1816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko/* 2816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * Copyright (C) 2015 The Android Open Source Project 3816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * 4816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * Licensed under the Apache License, Version 2.0 (the "License"); 5816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * you may not use this file except in compliance with the License. 6816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * You may obtain a copy of the License at 7816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * 8816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * http://www.apache.org/licenses/LICENSE-2.0 9816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * 10816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * Unless required by applicable law or agreed to in writing, software 11816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * distributed under the License is distributed on an "AS IS" BASIS, 12816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * See the License for the specific language governing permissions and 14816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * limitations under the License. 15816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko */ 16816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 17816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkopackage com.android.tv.menu; 18816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 19816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.content.Context; 20816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.support.v17.leanback.widget.HorizontalGridView; 21816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.support.v17.leanback.widget.OnChildSelectedListener; 22816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.support.v7.widget.RecyclerView; 23816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.util.AttributeSet; 24816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.util.Log; 25816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.view.LayoutInflater; 26816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.view.View; 27816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.view.ViewGroup; 28816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 29816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport com.android.tv.MainActivity; 30816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport com.android.tv.R; 31816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 32816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport java.util.Collections; 33816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport java.util.List; 34816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 35816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko/** 36816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * A view that shows a title and list view. 37816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko */ 38816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkopublic class ItemListRowView extends MenuRowView implements OnChildSelectedListener { 39816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private static final String TAG = MenuView.TAG; 40816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private static final boolean DEBUG = MenuView.DEBUG; 41816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 42816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public interface CardView<T> { 43816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko void onBind(T row, boolean selected); 442e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko void onRecycled(); 45816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko void onSelected(); 46816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko void onDeselected(); 47816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 48816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 49816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private HorizontalGridView mListView; 50816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private CardView<?> mSelectedCard; 51816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 52816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public ItemListRowView(Context context) { 53816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko this(context, null); 54816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 55816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 56816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public ItemListRowView(Context context, AttributeSet attrs) { 57816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko this(context, attrs, 0); 58816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 59816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 60816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public ItemListRowView(Context context, AttributeSet attrs, int defStyle) { 61816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko this(context, attrs, defStyle, 0); 62816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 63816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 64816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public ItemListRowView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 65816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko super(context, attrs, defStyleAttr, defStyleRes); 66816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 67816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 68816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko @Override 69816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko protected void onFinishInflate() { 70816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko super.onFinishInflate(); 71816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mListView = (HorizontalGridView) getContentsView(); 72816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 73816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 74816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko @Override 75816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko protected int getContentsViewId() { 76816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko return R.id.list_view; 77816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 78816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 79816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko @Override 80816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public void onBind(MenuRow row) { 81816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko super.onBind(row); 82816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko ItemListAdapter<?> adapter = ((ItemListRow) row).getAdapter(); 83816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko adapter.mItemListView = this; 84816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 85816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mListView.setOnChildSelectedListener(this); 86816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mListView.setAdapter(adapter); 87816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 88816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 89816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko @Override 90816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public void initialize(int reason) { 91816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko super.initialize(reason); 92816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko setInitialFocusView(mListView); 93816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mListView.setSelectedPosition(getAdapter().getInitialPosition()); 94816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 95816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 96816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private ItemListAdapter<?> getAdapter() { 97816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko return (ItemListAdapter<?>) mListView.getAdapter(); 98816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 99816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 100816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko @Override 101816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public void onChildSelected(ViewGroup parent, View child, int position, long id) { 102816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (DEBUG) Log.d(TAG, "onChildSelected: child=" + child); 103816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (mSelectedCard == child) { 104816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko return; 105816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 106816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (mSelectedCard != null) { 107816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mSelectedCard.onDeselected(); 108816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 109816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mSelectedCard = (CardView<?>) child; 110816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (mSelectedCard != null) { 111816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mSelectedCard.onSelected(); 112816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 113816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 114816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 115816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public static abstract class ItemListAdapter<T> 116816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko extends RecyclerView.Adapter<ItemListAdapter.MyViewHolder> { 117816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private final MainActivity mMainActivity; 118816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private final LayoutInflater mLayoutInflater; 119816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private List<T> mItemList = Collections.emptyList(); 120816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private ItemListRowView mItemListView; 121816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 122816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public ItemListAdapter(Context context) { 123816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko // Only MainActivity can use the main menu. 124816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mMainActivity = (MainActivity) context; 125816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mLayoutInflater = LayoutInflater.from(context); 126816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 127816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 128816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko /** 129816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * In most cases, implementation should call {@link #setItemList(java.util.List)} with 130816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * newly update item list. 131816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko */ 132816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public abstract void update(); 133816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 134816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko /** 135816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * Gets layout resource ID. It'll be used in {@link #onCreateViewHolder}. 136816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko */ 137816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko protected abstract int getLayoutResId(int viewType); 138816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 139816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko /** 140816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * Releases all the resources which need to be released. 141816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko */ 142816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public void release() { 143816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 144816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 145816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko /** 146816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * The initial position of list that will be selected when the main menu appears. 147816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * By default, the first item is initially selected. 148816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko */ 149816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public int getInitialPosition() { 150816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko return 0; 151816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 152816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 153816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko /** The MainActivity that the corresponding ItemListView belongs to. */ 154816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko protected MainActivity getMainActivity() { 155816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko return mMainActivity; 156816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 157816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 158816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko /** The item list. */ 159816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko protected List<T> getItemList() { 160816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko return mItemList; 161816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 162816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 163816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko /** 164816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * Sets the item list. 165816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * 166816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * <p>This sends an item change event, not a structural change event. The items of the same 167816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * positions retain the same identity. 168816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * 169816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * <p>If there's any structural change and relayout and rebind is needed, call 170816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * {@link #notifyDataSetChanged} explicitly. 171816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko */ 172816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko protected void setItemList(List<T> itemList) { 173816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko int oldSize = mItemList.size(); 174816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko int newSize = itemList.size(); 175816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mItemList = itemList; 176816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (oldSize > newSize) { 177816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko notifyItemRangeChanged(0, newSize); 178816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko notifyItemRangeRemoved(newSize, oldSize - newSize); 179816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } else if (oldSize < newSize) { 180816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko notifyItemRangeChanged(0, oldSize); 181816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko notifyItemRangeInserted(oldSize, newSize - oldSize); 182816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } else { 183816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko notifyItemRangeChanged(0, oldSize); 184816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 185816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 186816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 187816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko @Override 188816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public int getItemViewType(int position) { 189816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko return 0; 190816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 191816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 192816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko @Override 193816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public int getItemCount() { 194816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko return mItemList.size(); 195816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 196816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 197816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko @Override 198816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 199816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko View view = mLayoutInflater.inflate(getLayoutResId(viewType), parent, false); 200816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko return new MyViewHolder(view); 201816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 202816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 203816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko @Override 204816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public void onBindViewHolder(MyViewHolder viewHolder, int position) { 205816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko @SuppressWarnings("unchecked") 206816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko CardView<T> cardView = (CardView<T>) viewHolder.itemView; 207816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko cardView.onBind(mItemList.get(position), cardView.equals(mItemListView.mSelectedCard)); 208816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 209816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 2102e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko @Override 2112e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko public void onViewRecycled(MyViewHolder viewHolder) { 2122e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko super.onViewRecycled(viewHolder); 2132e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko CardView<T> cardView = (CardView<T>) viewHolder.itemView; 2142e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko cardView.onRecycled(); 2152e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko } 2162e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko 217816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public static class MyViewHolder extends RecyclerView.ViewHolder { 218816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko public MyViewHolder(View view) { 219816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko super(view); 220816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 221816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 222816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 223816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko} 224