├── .classpath
├── .gitignore
├── .project
├── AndroidManifest.xml
├── README.md
├── ic_launcher-web.png
├── libs
├── android-support-v4.jar
└── nineoldandroids-2.4.0.jar
├── proguard-project.txt
├── project.properties
├── res
├── drawable-hdpi
│ └── ic_launcher.png
├── drawable-mdpi
│ └── ic_launcher.png
├── drawable-xhdpi
│ ├── clip.png
│ ├── clip2.png
│ ├── eye.png
│ ├── ic_launcher.png
│ ├── weather_bg_rain.png
│ ├── weather_drizzle.png
│ └── weather_mostly_cloudy.png
├── drawable-xxhdpi
│ └── ic_launcher.png
├── drawable
│ └── selector_bg.xml
├── layout
│ └── activity_main.xml
├── menu
│ └── main.xml
├── values-sw600dp
│ └── dimens.xml
├── values-sw720dp-land
│ └── dimens.xml
├── values-v11
│ └── styles.xml
├── values-v14
│ └── styles.xml
└── values
│ ├── colors.xml
│ ├── dimens.xml
│ ├── strings.xml
│ └── styles.xml
├── screenshoot
└── 123.gif
└── src
└── com
└── bluemor
└── pulllayout
├── EyeView.java
├── MainActivity.java
└── PullLayout.java
/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | *.apk
3 | *.ap_
4 |
5 | # Files for the Dalvik VM
6 | *.dex
7 |
8 | # Java class files
9 | *.class
10 |
11 | # Generated files
12 | bin/
13 | gen/
14 |
15 | # Gradle files
16 | .gradle/
17 | build/
18 |
19 | # Local configuration file (sdk path, etc)
20 | local.properties
21 |
22 | # Proguard folder generated by Eclipse
23 | proguard/
24 |
25 | # Log Files
26 | *.log
27 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | PullLayout
4 |
5 |
6 |
7 |
8 |
9 | com.android.ide.eclipse.adt.ResourceManagerBuilder
10 |
11 |
12 |
13 |
14 | com.android.ide.eclipse.adt.PreCompilerBuilder
15 |
16 |
17 |
18 |
19 | org.eclipse.jdt.core.javabuilder
20 |
21 |
22 |
23 |
24 | com.android.ide.eclipse.adt.ApkBuilder
25 |
26 |
27 |
28 |
29 |
30 | com.android.ide.eclipse.adt.AndroidNature
31 | org.eclipse.jdt.core.javanature
32 |
33 |
34 |
--------------------------------------------------------------------------------
/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
10 |
11 |
16 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Android-PullLayout
2 | ==================
3 |
4 | 仿UC天气下拉和微信下拉眼睛
5 |
6 |
7 | ##Screenshots
8 | 
9 |
--------------------------------------------------------------------------------
/ic_launcher-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BlueMor/Android-PullLayout/dd2f4b51f99a1d6427a71fbbc9dcdffc2c128d39/ic_launcher-web.png
--------------------------------------------------------------------------------
/libs/android-support-v4.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BlueMor/Android-PullLayout/dd2f4b51f99a1d6427a71fbbc9dcdffc2c128d39/libs/android-support-v4.jar
--------------------------------------------------------------------------------
/libs/nineoldandroids-2.4.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BlueMor/Android-PullLayout/dd2f4b51f99a1d6427a71fbbc9dcdffc2c128d39/libs/nineoldandroids-2.4.0.jar
--------------------------------------------------------------------------------
/proguard-project.txt:
--------------------------------------------------------------------------------
1 | # To enable ProGuard in your project, edit project.properties
2 | # to define the proguard.config property as described in that file.
3 | #
4 | # Add project specific ProGuard rules here.
5 | # By default, the flags in this file are appended to flags specified
6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt
7 | # You can edit the include path and order by changing the ProGuard
8 | # include property in project.properties.
9 | #
10 | # For more details, see
11 | # http://developer.android.com/guide/developing/tools/proguard.html
12 |
13 | # Add any project specific keep options here:
14 |
15 | # If your project uses WebView with JS, uncomment the following
16 | # and specify the fully qualified class name to the JavaScript interface
17 | # class:
18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
19 | # public *;
20 | #}
21 |
--------------------------------------------------------------------------------
/project.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system edit
7 | # "ant.properties", and override values to adapt the script to your
8 | # project structure.
9 | #
10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
12 |
13 | # Project target.
14 | target=android-19
15 |
--------------------------------------------------------------------------------
/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BlueMor/Android-PullLayout/dd2f4b51f99a1d6427a71fbbc9dcdffc2c128d39/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BlueMor/Android-PullLayout/dd2f4b51f99a1d6427a71fbbc9dcdffc2c128d39/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/clip.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BlueMor/Android-PullLayout/dd2f4b51f99a1d6427a71fbbc9dcdffc2c128d39/res/drawable-xhdpi/clip.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/clip2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BlueMor/Android-PullLayout/dd2f4b51f99a1d6427a71fbbc9dcdffc2c128d39/res/drawable-xhdpi/clip2.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/eye.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BlueMor/Android-PullLayout/dd2f4b51f99a1d6427a71fbbc9dcdffc2c128d39/res/drawable-xhdpi/eye.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BlueMor/Android-PullLayout/dd2f4b51f99a1d6427a71fbbc9dcdffc2c128d39/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/weather_bg_rain.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BlueMor/Android-PullLayout/dd2f4b51f99a1d6427a71fbbc9dcdffc2c128d39/res/drawable-xhdpi/weather_bg_rain.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/weather_drizzle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BlueMor/Android-PullLayout/dd2f4b51f99a1d6427a71fbbc9dcdffc2c128d39/res/drawable-xhdpi/weather_drizzle.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/weather_mostly_cloudy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BlueMor/Android-PullLayout/dd2f4b51f99a1d6427a71fbbc9dcdffc2c128d39/res/drawable-xhdpi/weather_mostly_cloudy.png
--------------------------------------------------------------------------------
/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BlueMor/Android-PullLayout/dd2f4b51f99a1d6427a71fbbc9dcdffc2c128d39/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/res/drawable/selector_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
8 |
9 |
13 |
14 |
20 |
21 |
29 |
30 |
35 |
36 |
37 |
45 |
46 |
54 |
55 |
64 |
65 |
66 |
67 |
73 |
74 |
81 |
82 |
86 |
87 |
91 |
92 |
96 |
97 |
98 |
99 |
112 |
113 |
114 |
--------------------------------------------------------------------------------
/res/menu/main.xml:
--------------------------------------------------------------------------------
1 |
10 |
--------------------------------------------------------------------------------
/res/values-sw600dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/res/values-sw720dp-land/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 | 128dp
8 |
9 |
10 |
--------------------------------------------------------------------------------
/res/values-v11/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/res/values-v14/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | #33555555
5 |
6 |
--------------------------------------------------------------------------------
/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 16dp
5 | 16dp
6 |
7 |
8 |
--------------------------------------------------------------------------------
/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | PullLayout
5 | Settings
6 | Hello world!
7 |
8 |
9 |
--------------------------------------------------------------------------------
/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
14 |
15 |
16 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/screenshoot/123.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BlueMor/Android-PullLayout/dd2f4b51f99a1d6427a71fbbc9dcdffc2c128d39/screenshoot/123.gif
--------------------------------------------------------------------------------
/src/com/bluemor/pulllayout/EyeView.java:
--------------------------------------------------------------------------------
1 | package com.bluemor.pulllayout;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.content.Context;
5 | import android.graphics.Bitmap;
6 | import android.graphics.Canvas;
7 | import android.graphics.Paint;
8 | import android.graphics.PorterDuff;
9 | import android.graphics.PorterDuffXfermode;
10 | import android.os.Build;
11 | import android.util.AttributeSet;
12 | import android.widget.FrameLayout;
13 |
14 | public class EyeView extends FrameLayout {
15 |
16 | private Paint paint;
17 | private Bitmap bitmap;
18 |
19 | public EyeView(Context context) {
20 | super(context);
21 | init();
22 | }
23 |
24 | public EyeView(Context context, AttributeSet attrs) {
25 | super(context, attrs);
26 | init();
27 | }
28 |
29 | public EyeView(Context context, AttributeSet attrs, int defStyle) {
30 | super(context, attrs, defStyle);
31 | init();
32 | }
33 |
34 | @SuppressLint("NewApi")
35 | private void init() {
36 | setDrawingCacheEnabled(true);
37 | if (Build.VERSION.SDK_INT >= 11) {
38 | setLayerType(LAYER_TYPE_SOFTWARE, null);
39 | }
40 | paint = new Paint(Paint.ANTI_ALIAS_FLAG);
41 | }
42 |
43 | @Override
44 | protected void dispatchDraw(Canvas canvas) {
45 | super.dispatchDraw(canvas);
46 | if (bitmap != null) {
47 | paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
48 | canvas.drawBitmap(bitmap, 0, 0, paint);
49 | paint.setXfermode(null);
50 | }
51 | }
52 |
53 | public void setRadius(int radius) {
54 | if (bitmap != null && !bitmap.isRecycled()) {
55 | bitmap.recycle();
56 | }
57 | bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
58 | Canvas canvas = new Canvas(bitmap);
59 | canvas.drawCircle(getWidth() / 2f, getHeight() / 2f, radius, paint);
60 | invalidate();
61 | }
62 |
63 | }
64 |
--------------------------------------------------------------------------------
/src/com/bluemor/pulllayout/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.bluemor.pulllayout;
2 |
3 | import android.app.Activity;
4 | import android.os.Bundle;
5 |
6 | public class MainActivity extends Activity {
7 |
8 | @Override
9 | protected void onCreate(Bundle savedInstanceState) {
10 | super.onCreate(savedInstanceState);
11 | setContentView(R.layout.activity_main);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/com/bluemor/pulllayout/PullLayout.java:
--------------------------------------------------------------------------------
1 | package com.bluemor.pulllayout;
2 |
3 | import android.content.Context;
4 | import android.graphics.Color;
5 | import android.util.AttributeSet;
6 | import android.view.MotionEvent;
7 | import android.view.View;
8 | import android.view.ViewTreeObserver.OnGlobalLayoutListener;
9 | import android.view.animation.DecelerateInterpolator;
10 | import android.widget.ScrollView;
11 | import android.widget.TextView;
12 |
13 | import com.nineoldandroids.animation.Animator;
14 | import com.nineoldandroids.animation.Animator.AnimatorListener;
15 | import com.nineoldandroids.animation.ObjectAnimator;
16 | import com.nineoldandroids.view.ViewHelper;
17 |
18 | public class PullLayout extends ScrollView {
19 |
20 | private View rl_top;
21 | private View ll_weather;
22 | private View ll_content;
23 | private TextView tv;
24 | private EyeView ev;
25 | private ObjectAnimator oa;
26 | private float lastY = -1;
27 | private float detalY = -1;
28 | private int range;
29 | private int tvHeight;
30 | private int tvWidth;
31 | private boolean isTouchOrRunning;
32 | private boolean isActionCancel;
33 |
34 | public PullLayout(Context context) {
35 | super(context);
36 | }
37 |
38 | public PullLayout(Context context, AttributeSet attrs) {
39 | super(context, attrs);
40 | }
41 |
42 | public PullLayout(Context context, AttributeSet attrs, int defStyle) {
43 | super(context, attrs, defStyle);
44 | }
45 |
46 | @Override
47 | protected void onFinishInflate() {
48 | super.onFinishInflate();
49 | setVerticalScrollBarEnabled(false);
50 | rl_top = findViewById(R.id.rl_top);
51 | ll_content = findViewById(R.id.ll_content);
52 | tv = (TextView) findViewById(R.id.tv);
53 | ev = (EyeView) findViewById(R.id.ev);
54 | ll_weather = findViewById(R.id.ll_weather);
55 |
56 | rl_top.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
57 | @SuppressWarnings("deprecation")
58 | @Override
59 | public void onGlobalLayout() {
60 | rl_top.getViewTreeObserver().removeGlobalOnLayoutListener(this);
61 | range = rl_top.getHeight();
62 | scrollTo(0, range);
63 | rl_top.getLayoutParams().height = range;
64 | }
65 | });
66 | tv.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
67 | @SuppressWarnings("deprecation")
68 | @Override
69 | public void onGlobalLayout() {
70 | tv.getViewTreeObserver().removeGlobalOnLayoutListener(this);
71 | tvHeight = tv.getHeight();
72 | tvWidth = tv.getWidth();
73 | ViewHelper.setTranslationY(ll_content, tvHeight);
74 | }
75 | });
76 |
77 | ev.setOnClickListener(new OnClickListener() {
78 | @Override
79 | public void onClick(View v) {
80 | close();
81 | }
82 | });
83 |
84 | tv.setOnClickListener(new OnClickListener() {
85 | @Override
86 | public void onClick(View v) {
87 | open();
88 | }
89 | });
90 |
91 | }
92 |
93 | @Override
94 | public boolean onInterceptTouchEvent(MotionEvent ev) {
95 | switch (ev.getAction()) {
96 | case MotionEvent.ACTION_DOWN:
97 | isActionCancel = false;
98 | isTouchOrRunning = true;
99 | lastY = ev.getY();
100 | break;
101 | }
102 | return super.onInterceptTouchEvent(ev);
103 | }
104 |
105 | @Override
106 | public boolean onTouchEvent(MotionEvent ev) {
107 | if (oa != null && oa.isRunning()) {
108 | ev.setAction(MotionEvent.ACTION_UP);
109 | isActionCancel = true;
110 | }
111 | if (isActionCancel && ev.getAction() != MotionEvent.ACTION_DOWN) {
112 | return false;
113 | }
114 | if (ev.getActionIndex() != 0 && getScrollY() < range) {
115 | ev.setAction(MotionEvent.ACTION_UP);
116 | isActionCancel = true;
117 | }
118 |
119 | switch (ev.getAction()) {
120 | case MotionEvent.ACTION_MOVE:
121 | isTouchOrRunning = true;
122 | if (getScrollY() != 0) {
123 | detalY = 0;
124 | lastY = ev.getY();
125 | } else {
126 | detalY = ev.getY() - lastY;
127 | if (detalY > 0) {
128 | setT((int) -detalY / 5);
129 | return true;
130 | }
131 | }
132 | break;
133 | case MotionEvent.ACTION_UP:
134 | isTouchOrRunning = false;
135 | if (getScrollY() < range) {
136 | if (detalY != 0) {
137 | reset();
138 | } else {
139 | toggle();
140 | }
141 | return true;
142 | }
143 | break;
144 | }
145 | return super.onTouchEvent(ev);
146 | }
147 |
148 | @Override
149 | protected void onScrollChanged(int l, int t, int oldl, int oldt) {
150 | super.onScrollChanged(l, t, oldl, oldt);
151 | if (t > range) {
152 | return;
153 | } else if (!isTouchOrRunning && t != range) {
154 | scrollTo(0, range);
155 | } else {
156 | animateScroll(t);
157 | }
158 | }
159 |
160 | public void setT(int t) {
161 | scrollTo(0, t);
162 | if (t < 0) {
163 | animatePull(t);
164 | }
165 | }
166 |
167 | private void animateScroll(int t) {
168 | float percent = (float) t / range;
169 | ViewHelper.setTranslationY(rl_top, t);
170 | ViewHelper.setTranslationY(ll_content, tvHeight * percent);
171 | ViewHelper.setScaleX(tv, 2 - percent);
172 | ViewHelper.setScaleY(tv, 2 - percent);
173 | ViewHelper.setTranslationX(tv, tvWidth * (1 - percent) / 2f);
174 | ViewHelper.setTranslationY(tv, t + tvHeight * (1 - percent) / 2f);
175 | ViewHelper.setTranslationY(ev, -t / 2);
176 | ViewHelper.setTranslationY(ll_weather, -t / 2);
177 | ev.setRadius((int) (range * 0.25f * (1 - percent)));
178 | tv.setTextColor(evaluate(percent, Color.WHITE, Color.BLACK));
179 | }
180 |
181 | private void animatePull(int t) {
182 | rl_top.getLayoutParams().height = range - t;
183 | rl_top.requestLayout();
184 | float percent = (float) t / range;
185 | ViewHelper.setScaleX(ev, 1 - percent);
186 | ViewHelper.setScaleY(ev, 1 - percent);
187 | ViewHelper.setScaleX(tv, 2 - percent);
188 | ViewHelper.setScaleY(tv, 2 - percent);
189 | ViewHelper.setTranslationX(tv, tvWidth * (1 - percent) / 2f);
190 | ViewHelper.setTranslationY(ll_weather, t / 2);
191 | }
192 |
193 | private Integer evaluate(float fraction, Object startValue, Integer endValue) {
194 | int startInt = (Integer) startValue;
195 | int startA = (startInt >> 24) & 0xff;
196 | int startR = (startInt >> 16) & 0xff;
197 | int startG = (startInt >> 8) & 0xff;
198 | int startB = startInt & 0xff;
199 | int endInt = (Integer) endValue;
200 | int endA = (endInt >> 24) & 0xff;
201 | int endR = (endInt >> 16) & 0xff;
202 | int endG = (endInt >> 8) & 0xff;
203 | int endB = endInt & 0xff;
204 | return (int) ((startA + (int) (fraction * (endA - startA))) << 24)
205 | | (int) ((startR + (int) (fraction * (endR - startR))) << 16)
206 | | (int) ((startG + (int) (fraction * (endG - startG))) << 8)
207 | | (int) ((startB + (int) (fraction * (endB - startB))));
208 | }
209 |
210 | public void toggle() {
211 | if (isOpen()) {
212 | close();
213 | } else {
214 | open();
215 | }
216 | }
217 |
218 | private Status status;
219 |
220 | public enum Status {
221 | Open, Close;
222 | }
223 |
224 | public boolean isOpen() {
225 | return status == Status.Open;
226 | }
227 |
228 | private void reset() {
229 | if (oa != null && oa.isRunning()) {
230 | return;
231 | }
232 | oa = ObjectAnimator.ofInt(this, "t", (int) -detalY / 5, 0);
233 | oa.setDuration(150);
234 | oa.start();
235 | }
236 |
237 | public void close() {
238 | if (oa != null && oa.isRunning()) {
239 | return;
240 | }
241 | oa = ObjectAnimator.ofInt(this, "t", getScrollY(), range);
242 | oa.setInterpolator(new DecelerateInterpolator());
243 | oa.addListener(new AnimatorListener() {
244 | @Override
245 | public void onAnimationStart(Animator arg0) {
246 | isTouchOrRunning = true;
247 | }
248 |
249 | @Override
250 | public void onAnimationRepeat(Animator arg0) {
251 | }
252 |
253 | @Override
254 | public void onAnimationEnd(Animator arg0) {
255 | isTouchOrRunning = false;
256 | status = Status.Close;
257 | }
258 |
259 | @Override
260 | public void onAnimationCancel(Animator arg0) {
261 |
262 | }
263 | });
264 | oa.setDuration(250);
265 | oa.start();
266 | }
267 |
268 | public void open() {
269 | if (oa != null && oa.isRunning()) {
270 | return;
271 | }
272 | oa = ObjectAnimator.ofInt(this, "t", getScrollY(), (int) (-getScrollY() / 2.2f), 0);
273 | oa.setInterpolator(new DecelerateInterpolator());
274 | oa.addListener(new AnimatorListener() {
275 | @Override
276 | public void onAnimationStart(Animator arg0) {
277 | isTouchOrRunning = true;
278 | }
279 |
280 | @Override
281 | public void onAnimationRepeat(Animator arg0) {
282 | }
283 |
284 | @Override
285 | public void onAnimationEnd(Animator arg0) {
286 | isTouchOrRunning = false;
287 | status = Status.Open;
288 | }
289 |
290 | @Override
291 | public void onAnimationCancel(Animator arg0) {
292 |
293 | }
294 | });
295 | oa.setDuration(400);
296 | oa.start();
297 | }
298 |
299 | }
300 |
--------------------------------------------------------------------------------