|
|
@@ -3,7 +3,6 @@ package kr.co.zumo.app.lifeplus.view.screen.main;
|
|
|
import android.graphics.PointF;
|
|
|
import android.support.annotation.NonNull;
|
|
|
import android.support.annotation.Nullable;
|
|
|
-import android.support.v7.widget.LinearLayoutManager;
|
|
|
import android.support.v7.widget.LinearSmoothScroller;
|
|
|
import android.support.v7.widget.OrientationHelper;
|
|
|
import android.support.v7.widget.RecyclerView;
|
|
|
@@ -14,12 +13,10 @@ import android.support.v7.widget.SnapHelper;
|
|
|
import android.util.DisplayMetrics;
|
|
|
import android.util.Log;
|
|
|
import android.view.View;
|
|
|
-import android.view.ViewConfiguration;
|
|
|
import android.view.animation.DecelerateInterpolator;
|
|
|
+import android.view.animation.Interpolator;
|
|
|
import android.widget.Scroller;
|
|
|
|
|
|
-import kr.co.zumo.app.lifeplus.util.ResourceUtil;
|
|
|
-
|
|
|
/**
|
|
|
* MainContentsSnapper
|
|
|
* <pre>
|
|
|
@@ -33,24 +30,26 @@ import kr.co.zumo.app.lifeplus.util.ResourceUtil;
|
|
|
public class MainContentsSnapper extends RecyclerView.OnFlingListener {
|
|
|
|
|
|
private final int snapOffset;
|
|
|
- private int minVelocity = 200;
|
|
|
- private int maxVelocity = 5000;
|
|
|
+ private int minVelocity;
|
|
|
|
|
|
private static final int TIME_MAX = 990;
|
|
|
private static final int TIME_MIN = 250;
|
|
|
|
|
|
- static final float MILLISECONDS_PER_INCH = 100f;
|
|
|
+ private static final float MILLISECONDS_PER_INCH = 500f; // fling 속도
|
|
|
+ private static final float MILLISECONDS_PER_INCH_SCROLL = 200f; // smoothScrollToPosition() 을 이용할 때 스크롤 속도
|
|
|
+ private static final float SCROLL_FRICTION = 5f; //1.5f // 마찰계수를 늘려 준다. 최대 이동 거리가 줄어듬.
|
|
|
|
|
|
- RecyclerView mRecyclerView;
|
|
|
+ private RecyclerView mRecyclerView;
|
|
|
private Scroller mGravityScroller;
|
|
|
|
|
|
private static final float INVALID_DISTANCE = 1f;
|
|
|
|
|
|
+ private static final float INTERPOLATOR_FACTOR = 1.5f; // 1.5f
|
|
|
+
|
|
|
+ protected Interpolator interpolator = new DecelerateInterpolator(INTERPOLATOR_FACTOR);
|
|
|
// Orientation helpers are lazily created per LayoutManager.
|
|
|
@Nullable
|
|
|
private OrientationHelper mVerticalHelper;
|
|
|
- @Nullable
|
|
|
- private OrientationHelper mHorizontalHelper;
|
|
|
|
|
|
// Handles the snap on scroll case.
|
|
|
private final RecyclerView.OnScrollListener mScrollListener =
|
|
|
@@ -68,7 +67,6 @@ public class MainContentsSnapper extends RecyclerView.OnFlingListener {
|
|
|
|
|
|
@Override
|
|
|
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
|
|
|
-// Log.i("APP# MainContentsSnapper | onScrolledVertical", "|" + "dx: " + dx);
|
|
|
if (dx != 0 || dy != 0) {
|
|
|
mScrolled = true;
|
|
|
}
|
|
|
@@ -83,25 +81,12 @@ public class MainContentsSnapper extends RecyclerView.OnFlingListener {
|
|
|
* @param snapOffset snap 지점의 offset, - (음수) 이면 화면의 위쪽으로 이동.
|
|
|
*/
|
|
|
public MainContentsSnapper(int minVelocity, int snapOffset) {
|
|
|
- this.minVelocity = minVelocity;
|
|
|
+ this.minVelocity = modifyVelocity(minVelocity);
|
|
|
this.snapOffset = snapOffset;
|
|
|
}
|
|
|
|
|
|
- @Override
|
|
|
- public boolean onFling(int velocityX, int velocityY) {
|
|
|
- Log.w("APP# MainContentsSnapper | onFling", "|" + "velocityY: " + velocityY);
|
|
|
-
|
|
|
- LayoutManager layoutManager = mRecyclerView.getLayoutManager();
|
|
|
- if (layoutManager == null) {
|
|
|
- return false;
|
|
|
- }
|
|
|
- RecyclerView.Adapter adapter = mRecyclerView.getAdapter();
|
|
|
- if (adapter == null) {
|
|
|
- return false;
|
|
|
- }
|
|
|
- int minFlingVelocity = 0; //mRecyclerView.getMinFlingVelocity();
|
|
|
- return (Math.abs(velocityY) > minFlingVelocity || Math.abs(velocityX) > minFlingVelocity)
|
|
|
- && snapFromFling(layoutManager, velocityX, velocityY);
|
|
|
+ private int modifyVelocity(int velocity) {
|
|
|
+ return velocity; // >> 2;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -125,8 +110,8 @@ public class MainContentsSnapper extends RecyclerView.OnFlingListener {
|
|
|
mRecyclerView = recyclerView;
|
|
|
if (mRecyclerView != null) {
|
|
|
setupCallbacks();
|
|
|
- mGravityScroller = new Scroller(mRecyclerView.getContext(), new DecelerateInterpolator(20f));
|
|
|
- mGravityScroller.setFriction(ViewConfiguration.getScrollFriction() * 10); // 마찰계수를 늘려 줌
|
|
|
+ mGravityScroller = new Scroller(mRecyclerView.getContext(), new DecelerateInterpolator());
|
|
|
+ mGravityScroller.setFriction(SCROLL_FRICTION);
|
|
|
snapToTargetExistingView();
|
|
|
}
|
|
|
}
|
|
|
@@ -150,6 +135,23 @@ public class MainContentsSnapper extends RecyclerView.OnFlingListener {
|
|
|
mRecyclerView.setOnFlingListener(null);
|
|
|
}
|
|
|
|
|
|
+ @Override
|
|
|
+ public boolean onFling(int velocityX, int velocityY) {
|
|
|
+// Log.w("APP# MainContentsSnapper | onFling", "|" + "velocityY: ==============================> " + velocityY);
|
|
|
+ velocityY = modifyVelocity(velocityY);
|
|
|
+
|
|
|
+ LayoutManager layoutManager = mRecyclerView.getLayoutManager();
|
|
|
+ if (layoutManager == null) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ RecyclerView.Adapter adapter = mRecyclerView.getAdapter();
|
|
|
+ if (adapter == null) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ int minFlingVelocity = 0; //mRecyclerView.getMinFlingVelocity();
|
|
|
+ return Math.abs(velocityY) > minFlingVelocity && snapFromFling(layoutManager, velocityX, velocityY);
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* Calculated the estimated scroll distance in each direction given velocities on both axes.
|
|
|
*
|
|
|
@@ -186,7 +188,7 @@ public class MainContentsSnapper extends RecyclerView.OnFlingListener {
|
|
|
}
|
|
|
|
|
|
int targetPosition = findTargetSnapPosition(layoutManager, velocityX, velocityY);
|
|
|
-// Log.w("APP# MainContentsSnapper | snapFromFling2", "|" + "targetPosition: " + targetPosition);
|
|
|
+// Log.w("APP# MainContentsSnapper | snapFromFling2", "|" + "targetPosition: ----------------------------------> " + targetPosition);
|
|
|
if (targetPosition == RecyclerView.NO_POSITION) {
|
|
|
return false;
|
|
|
}
|
|
|
@@ -244,7 +246,7 @@ public class MainContentsSnapper extends RecyclerView.OnFlingListener {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- SmoothScroller smoothScroller = createScroller(layoutManager, 200f);
|
|
|
+ SmoothScroller smoothScroller = createScroller(layoutManager, MILLISECONDS_PER_INCH_SCROLL);
|
|
|
if (smoothScroller == null) {
|
|
|
return;
|
|
|
}
|
|
|
@@ -290,7 +292,7 @@ public class MainContentsSnapper extends RecyclerView.OnFlingListener {
|
|
|
// The associated RecyclerView has been removed so there is no action to take.
|
|
|
return;
|
|
|
}
|
|
|
- int offset = snapOffset;
|
|
|
+ int offset = 0; //snapOffset;
|
|
|
int viewIndex = mRecyclerView.getChildAdapterPosition(targetView);
|
|
|
if (viewIndex == (mRecyclerView.getAdapter().getItemCount() - 1)) {
|
|
|
/**
|
|
|
@@ -308,6 +310,7 @@ public class MainContentsSnapper extends RecyclerView.OnFlingListener {
|
|
|
// Log.e("APP# MainCategorySnapper | onTargetFound", "|" + "helper.getDecoratedMeasurement(targetView): " + helper.getDecoratedMeasurement(targetView));
|
|
|
// Log.e("APP# MainCategorySnapper | onTargetFound", "|" + "offset: " + offset);
|
|
|
}
|
|
|
+
|
|
|
int[] snapDistances = calculateDistanceToFinalSnap(mRecyclerView.getLayoutManager(), targetView);
|
|
|
final int dx;
|
|
|
final int dy;
|
|
|
@@ -315,28 +318,15 @@ public class MainContentsSnapper extends RecyclerView.OnFlingListener {
|
|
|
/**
|
|
|
* 방향을 고려해서 offset 적용한다. 항상 적용하면 긴쪽을 기준으로 time 이 계산되어서 이동 거리가 0일 경우 느리게 움직일 수 있다.
|
|
|
*/
|
|
|
- LinearLayoutManager linearLayoutManager = (LinearLayoutManager) layoutManager;
|
|
|
- if (null != linearLayoutManager) {
|
|
|
- if (linearLayoutManager.getOrientation() == LinearLayoutManager.HORIZONTAL) {
|
|
|
- dx = snapDistances[0] - offset;
|
|
|
- dy = snapDistances[1];
|
|
|
- }
|
|
|
- else {
|
|
|
- dx = snapDistances[0];
|
|
|
- dy = snapDistances[1] - offset;
|
|
|
- }
|
|
|
- }
|
|
|
- else {
|
|
|
- dx = snapDistances[0];
|
|
|
- dy = snapDistances[1];
|
|
|
- }
|
|
|
+ dx = snapDistances[0];
|
|
|
+ dy = snapDistances[1]; // - offset;
|
|
|
|
|
|
final int time = calculateTimeForDeceleration(Math.max(Math.abs(dx), Math.abs(dy)));
|
|
|
Log.i("APP# MainContentsSnapper | onTargetFound", "|" + "time: ---> " + time);
|
|
|
Log.i("APP# MainContentsSnapper | onTargetFound", "|" + "dy: ---> " + dy);
|
|
|
if (time > 0) {
|
|
|
int newTime = Math.min(TIME_MAX, Math.max(time, TIME_MIN));
|
|
|
- action.update(dx, dy, newTime, mDecelerateInterpolator);
|
|
|
+ action.update(dx, dy, newTime, interpolator);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -348,13 +338,7 @@ public class MainContentsSnapper extends RecyclerView.OnFlingListener {
|
|
|
}
|
|
|
|
|
|
private OrientationHelper getOrientationHelper(LayoutManager layoutManager) {
|
|
|
- if (layoutManager.canScrollVertically()) {
|
|
|
- return getVerticalHelper(layoutManager);
|
|
|
- }
|
|
|
- else if (layoutManager.canScrollHorizontally()) {
|
|
|
- return getHorizontalHelper(layoutManager);
|
|
|
- }
|
|
|
- return null;
|
|
|
+ return getVerticalHelper(layoutManager);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -374,20 +358,21 @@ public class MainContentsSnapper extends RecyclerView.OnFlingListener {
|
|
|
@Nullable
|
|
|
public int[] calculateDistanceToFinalSnap(@NonNull LayoutManager layoutManager, @NonNull View targetView) {
|
|
|
int[] out = new int[2];
|
|
|
- if (layoutManager.canScrollHorizontally()) {
|
|
|
- out[0] = distanceToTop(layoutManager, targetView, getHorizontalHelper(layoutManager));
|
|
|
- }
|
|
|
- else {
|
|
|
- out[0] = 0;
|
|
|
- }
|
|
|
+ out[0] = 0;
|
|
|
+ out[1] = distanceToCenter(layoutManager, targetView, getVerticalHelper(layoutManager));
|
|
|
+ return out;
|
|
|
+ }
|
|
|
|
|
|
- if (layoutManager.canScrollVertically()) {
|
|
|
- out[1] = distanceToTop(layoutManager, targetView, getVerticalHelper(layoutManager));
|
|
|
+ private int distanceToCenter(@NonNull RecyclerView.LayoutManager layoutManager, @NonNull View targetView, OrientationHelper helper) {
|
|
|
+ final int childCenter = helper.getDecoratedStart(targetView) + (helper.getDecoratedMeasurement(targetView) / 2);
|
|
|
+ final int containerCenter;
|
|
|
+ if (layoutManager.getClipToPadding()) {
|
|
|
+ containerCenter = helper.getStartAfterPadding() + helper.getTotalSpace() / 2;
|
|
|
}
|
|
|
else {
|
|
|
- out[1] = 0;
|
|
|
+ containerCenter = helper.getEnd() / 2;
|
|
|
}
|
|
|
- return out;
|
|
|
+ return childCenter - containerCenter;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -409,86 +394,52 @@ public class MainContentsSnapper extends RecyclerView.OnFlingListener {
|
|
|
public View findSnapView(LayoutManager layoutManager) {
|
|
|
OrientationHelper helper = getOrientationHelper(layoutManager);
|
|
|
if (null != helper) {
|
|
|
- return findTopView(layoutManager, helper);
|
|
|
+ return findCenterView(layoutManager, getVerticalHelper(layoutManager));
|
|
|
}
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Return the child view that is currently closest to the top of this parent.
|
|
|
+ * Return the child view that is currently closest to the center of this parent.
|
|
|
*
|
|
|
- * @param layoutManager The {@link LayoutManager} associated with the attached
|
|
|
+ * @param layoutManager The {@link RecyclerView.LayoutManager} associated with the attached
|
|
|
* {@link RecyclerView}.
|
|
|
* @param helper The relevant {@link OrientationHelper} for the attached {@link RecyclerView}.
|
|
|
- * @return the child view that is currently closest to the top of this parent.
|
|
|
+ * @return the child view that is currently closest to the center of this parent.
|
|
|
*/
|
|
|
@Nullable
|
|
|
- private View findTopView(LayoutManager layoutManager, OrientationHelper helper) {
|
|
|
+ private View findCenterView(RecyclerView.LayoutManager layoutManager,
|
|
|
+ OrientationHelper helper) {
|
|
|
int childCount = layoutManager.getChildCount();
|
|
|
if (childCount == 0) {
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
View closestChild = null;
|
|
|
- final int top;
|
|
|
+ final int center;
|
|
|
if (layoutManager.getClipToPadding()) {
|
|
|
- top = helper.getStartAfterPadding();
|
|
|
+ center = helper.getStartAfterPadding() + helper.getTotalSpace() / 2;
|
|
|
}
|
|
|
else {
|
|
|
- top = 0;
|
|
|
+ center = helper.getEnd() / 2;
|
|
|
}
|
|
|
int absClosest = Integer.MAX_VALUE;
|
|
|
- int dp100 = ResourceUtil.dpToPx(100);
|
|
|
- int lastIndex = mRecyclerView.getAdapter().getItemCount() - 1;
|
|
|
-
|
|
|
- int secondItemPositionMax = 0;
|
|
|
|
|
|
- for (int i = 0; i < childCount; ++i) {
|
|
|
+ for (int i = 0; i < childCount; i++) {
|
|
|
final View child = layoutManager.getChildAt(i);
|
|
|
- int childStart = helper.getDecoratedStart(child);
|
|
|
- int childEnd = helper.getDecoratedEnd(child);
|
|
|
- int childSize = Math.abs(childEnd - childStart);
|
|
|
- int secondItemPosition = childSize + snapOffset;
|
|
|
- int childCenter = childStart + (helper.getDecoratedMeasurement(child) >> 2);
|
|
|
- int absDistance = Math.abs(childCenter - (top + (childSize >> 2)));
|
|
|
-
|
|
|
- /** if child top is closer than previous closest, set it as closest **/
|
|
|
+ int childCenter = helper.getDecoratedStart(child)
|
|
|
+ + (helper.getDecoratedMeasurement(child) / 2);
|
|
|
+ int absDistance = Math.abs(childCenter - center);
|
|
|
+
|
|
|
+ /** if child center is closer than previous closest, set it as closest **/
|
|
|
if (absDistance < absClosest) {
|
|
|
absClosest = absDistance;
|
|
|
closestChild = child;
|
|
|
}
|
|
|
-
|
|
|
- if (secondItemPositionMax < secondItemPosition) {
|
|
|
- secondItemPositionMax = secondItemPosition;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * todo 화면에 2 개 이상 표시될 수 있을 경우 처리 필요
|
|
|
- */
|
|
|
-
|
|
|
- /**
|
|
|
- * 마지막이 -100dp 이상 보여질 경우 타겟으로 설정
|
|
|
- */
|
|
|
- if (mRecyclerView.getChildAdapterPosition(child) == lastIndex) {
|
|
|
-// Log.w("APP# MainContentsSnapper | findTopView", "|" + "secondItemPositionMax: " + secondItemPositionMax);
|
|
|
-// Log.w("APP# MainContentsSnapper | findTopView", "|" + "secondItemPosition: " + secondItemPosition);
|
|
|
-// Log.w("APP# MainContentsSnapper | findTopView", "|" + "snapOffset: " + snapOffset);
|
|
|
-// Log.w("APP# MainContentsSnapper | findTopView", "|" + "child.y: " + child.getY());
|
|
|
- if (helper.getEnd() - (childSize - dp100) > child.getY()) {
|
|
|
- closestChild = child;
|
|
|
- }
|
|
|
- }
|
|
|
}
|
|
|
return closestChild;
|
|
|
}
|
|
|
|
|
|
- private int distanceToTop(@NonNull LayoutManager layoutManager, @NonNull View targetView, OrientationHelper helper) {
|
|
|
- /**
|
|
|
- * targetView 의 시작 위치(Top)를 반환한다.
|
|
|
- */
|
|
|
- return helper.getDecoratedStart(targetView);
|
|
|
- }
|
|
|
-
|
|
|
/**
|
|
|
* Estimates a position to which SnapHelper will try to scroll to in response to a fling.
|
|
|
*
|
|
|
@@ -503,15 +454,13 @@ public class MainContentsSnapper extends RecyclerView.OnFlingListener {
|
|
|
int[] distances = calculateScrollDistance(velocityX, velocityY);
|
|
|
float distancePerChild = computeDistancePerChild(layoutManager, helper);
|
|
|
if (distancePerChild <= 0) {
|
|
|
- return 0;
|
|
|
+ return 1;
|
|
|
}
|
|
|
- int distance =
|
|
|
- Math.abs(distances[0]) > Math.abs(distances[1]) ? distances[0] : distances[1];
|
|
|
-// return (int) Math.round(distance / distancePerChild);
|
|
|
+ int distance = Math.abs(distances[0]) > Math.abs(distances[1]) ? distances[0] : distances[1];
|
|
|
|
|
|
- int min = 0;
|
|
|
+ int min = 1;
|
|
|
// 속도가 minVelocity 보다 크면 기본 1칸 이동
|
|
|
- if (Math.abs(velocityX) > minVelocity || Math.abs(velocityY) > minVelocity) {
|
|
|
+ if (Math.abs(velocityY) > minVelocity) {
|
|
|
min = 1;
|
|
|
}
|
|
|
int result = Math.round(distance / distancePerChild);
|
|
|
@@ -532,8 +481,7 @@ public class MainContentsSnapper extends RecyclerView.OnFlingListener {
|
|
|
* @return the target adapter position to you want to snap or {@link RecyclerView#NO_POSITION}
|
|
|
* if no snapping should happen
|
|
|
*/
|
|
|
- public int findTargetSnapPosition(LayoutManager layoutManager, int velocityX,
|
|
|
- int velocityY) {
|
|
|
+ public int findTargetSnapPosition(LayoutManager layoutManager, int velocityX, int velocityY) {
|
|
|
if (!(layoutManager instanceof ScrollVectorProvider)) {
|
|
|
return RecyclerView.NO_POSITION;
|
|
|
}
|
|
|
@@ -563,29 +511,14 @@ public class MainContentsSnapper extends RecyclerView.OnFlingListener {
|
|
|
return RecyclerView.NO_POSITION;
|
|
|
}
|
|
|
|
|
|
- int vDeltaJump, hDeltaJump;
|
|
|
- if (layoutManager.canScrollHorizontally()) {
|
|
|
- hDeltaJump = estimateNextPositionDiffForFling(layoutManager,
|
|
|
- getHorizontalHelper(layoutManager), velocityX, 0);
|
|
|
- if (vectorForEnd.x < 0) {
|
|
|
- hDeltaJump = -hDeltaJump;
|
|
|
- }
|
|
|
- }
|
|
|
- else {
|
|
|
- hDeltaJump = 0;
|
|
|
- }
|
|
|
- if (layoutManager.canScrollVertically()) {
|
|
|
- vDeltaJump = estimateNextPositionDiffForFling(layoutManager,
|
|
|
- getVerticalHelper(layoutManager), 0, velocityY);
|
|
|
- if (vectorForEnd.y < 0) {
|
|
|
- vDeltaJump = -vDeltaJump;
|
|
|
- }
|
|
|
- }
|
|
|
- else {
|
|
|
- vDeltaJump = 0;
|
|
|
+ int vDeltaJump;
|
|
|
+
|
|
|
+ vDeltaJump = estimateNextPositionDiffForFling(layoutManager, getVerticalHelper(layoutManager), 0, velocityY);
|
|
|
+ if (vectorForEnd.y < 0) {
|
|
|
+ vDeltaJump = -vDeltaJump;
|
|
|
}
|
|
|
|
|
|
- int deltaJump = layoutManager.canScrollVertically() ? vDeltaJump : hDeltaJump;
|
|
|
+ int deltaJump = vDeltaJump;
|
|
|
if (deltaJump == 0) {
|
|
|
return RecyclerView.NO_POSITION;
|
|
|
}
|
|
|
@@ -640,10 +573,8 @@ public class MainContentsSnapper extends RecyclerView.OnFlingListener {
|
|
|
if (minPosView == null || maxPosView == null) {
|
|
|
return INVALID_DISTANCE;
|
|
|
}
|
|
|
- int start = Math.min(helper.getDecoratedStart(minPosView),
|
|
|
- helper.getDecoratedStart(maxPosView));
|
|
|
- int end = Math.max(helper.getDecoratedEnd(minPosView),
|
|
|
- helper.getDecoratedEnd(maxPosView));
|
|
|
+ int start = Math.min(helper.getDecoratedStart(minPosView), helper.getDecoratedStart(maxPosView));
|
|
|
+ int end = Math.max(helper.getDecoratedEnd(minPosView), helper.getDecoratedEnd(maxPosView));
|
|
|
int distance = end - start;
|
|
|
if (distance == 0) {
|
|
|
return INVALID_DISTANCE;
|
|
|
@@ -658,13 +589,4 @@ public class MainContentsSnapper extends RecyclerView.OnFlingListener {
|
|
|
}
|
|
|
return mVerticalHelper;
|
|
|
}
|
|
|
-
|
|
|
- @NonNull
|
|
|
- private OrientationHelper getHorizontalHelper(
|
|
|
- @NonNull LayoutManager layoutManager) {
|
|
|
- if (mHorizontalHelper == null || mHorizontalHelper.getLayoutManager() != layoutManager) {
|
|
|
- mHorizontalHelper = OrientationHelper.createHorizontalHelper(layoutManager);
|
|
|
- }
|
|
|
- return mHorizontalHelper;
|
|
|
- }
|
|
|
}
|