Repository: incubator-weex
Updated Branches:
  refs/heads/master 00a4cd654 -> 4747acc95


[WEEX-109][android] support scroll start scroll end event on scroller list  
template list


Project: http://git-wip-us.apache.org/repos/asf/incubator-weex/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-weex/commit/40de9402
Tree: http://git-wip-us.apache.org/repos/asf/incubator-weex/tree/40de9402
Diff: http://git-wip-us.apache.org/repos/asf/incubator-weex/diff/40de9402

Branch: refs/heads/master
Commit: 40de94021c0d5e139f8c8696d19ce493f252b772
Parents: 8a19b9b
Author: jianbai.gbj <jianbai....@alibaba-inc.com>
Authored: Mon Nov 13 18:09:08 2017 +0800
Committer: jianbai.gbj <jianbai....@alibaba-inc.com>
Committed: Mon Nov 13 18:09:08 2017 +0800

----------------------------------------------------------------------
 .../java/com/taobao/weex/common/Constants.java  |   2 +
 .../taobao/weex/ui/component/WXScroller.java    |  43 ++++++-
 .../component/helper/ScrollStartEndHelper.java  | 116 +++++++++++++++++++
 .../ui/component/list/BasicListComponent.java   |  35 +++++-
 .../list/template/WXRecyclerTemplateList.java   |  39 +++++--
 5 files changed, 219 insertions(+), 16 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/40de9402/android/sdk/src/main/java/com/taobao/weex/common/Constants.java
----------------------------------------------------------------------
diff --git a/android/sdk/src/main/java/com/taobao/weex/common/Constants.java 
b/android/sdk/src/main/java/com/taobao/weex/common/Constants.java
index 32c91ba..5145f9e 100644
--- a/android/sdk/src/main/java/com/taobao/weex/common/Constants.java
+++ b/android/sdk/src/main/java/com/taobao/weex/common/Constants.java
@@ -278,6 +278,8 @@ public class Constants {
     String ONPULLING_DOWN = "pullingdown";
     String ONPULLING_UP = "pullingup";
     String SCROLL = "scroll";
+    String SCROLL_START = "scrollstart";
+    String SCROLL_END = "scrollend";
     String CLICKBACKITEM = "clickbackitem";
     String RESUME_EVENT = "WXApplicationDidBecomeActiveEvent";
     String PAUSE_EVENT = "WXApplicationWillResignActiveEvent";

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/40de9402/android/sdk/src/main/java/com/taobao/weex/ui/component/WXScroller.java
----------------------------------------------------------------------
diff --git 
a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXScroller.java 
b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXScroller.java
index 9e56259..9885d62 100644
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXScroller.java
+++ b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXScroller.java
@@ -42,6 +42,7 @@ import com.taobao.weex.common.OnWXScrollListener;
 import com.taobao.weex.common.WXThread;
 import com.taobao.weex.dom.WXDomObject;
 import com.taobao.weex.ui.ComponentCreator;
+import com.taobao.weex.ui.component.helper.ScrollStartEndHelper;
 import com.taobao.weex.ui.component.helper.WXStickyHelper;
 import com.taobao.weex.ui.view.IWXScroller;
 import com.taobao.weex.ui.view.WXBaseRefreshLayout;
@@ -78,6 +79,14 @@ public class WXScroller extends WXVContainer<ViewGroup> 
implements WXScrollViewL
   private boolean mForceLoadmoreNextTime = false;
   private int mOffsetAccuracy = 10;
   private Point mLastReport = new Point(-1, -1);
+  private boolean mHasAddScrollEvent = false;
+
+  /**
+   * scroll start and scroll end event
+   * */
+  private ScrollStartEndHelper mScrollStartEndHelper;
+
+
 
   public static class Creator implements ComponentCreator {
     public WXComponent createInstance(WXSDKInstance instance, WXDomObject 
node, WXVContainer parent) throws IllegalAccessException, 
InvocationTargetException, InstantiationException {
@@ -102,6 +111,7 @@ public class WXScroller extends WXVContainer<ViewGroup> 
implements WXScrollViewL
 
   private boolean isScrollable = true;
 
+
   @Deprecated
   public WXScroller(WXSDKInstance instance, WXDomObject dom, WXVContainer 
parent, String instanceId, boolean isLazy) {
     this(instance,dom,parent);
@@ -148,11 +158,17 @@ public class WXScroller extends WXVContainer<ViewGroup> 
implements WXScrollViewL
   @Override
   public void addEvent(String type) {
     super.addEvent(type);
-    if (Constants.Event.SCROLL.equals(type) && getInnerView() != null) {
+    if (ScrollStartEndHelper.isScrollEvent(type)
+            && getInnerView() != null && !mHasAddScrollEvent) {
+      mHasAddScrollEvent = true;
       if (getInnerView() instanceof WXScrollView) {
         ((WXScrollView) getInnerView()).addScrollViewListener(new 
WXScrollViewListener() {
           @Override
           public void onScrollChanged(WXScrollView scrollView, int x, int y, 
int oldx, int oldy) {
+            getScrollStartEndHelper().onScrolled(x, y);
+            if(!getDomObject().getEvents().contains(Constants.Event.SCROLL)){
+              return;
+            }
             if (shouldReport(x, y)) {
               fireScrollEvent(scrollView.getContentFrame(), x, y, oldx, oldy);
             }
@@ -177,6 +193,10 @@ public class WXScroller extends WXVContainer<ViewGroup> 
implements WXScrollViewL
         ((WXHorizontalScrollView) getInnerView()).addScrollViewListener(new 
WXHorizontalScrollView.ScrollViewListener() {
           @Override
           public void onScrollChanged(WXHorizontalScrollView scrollView, int 
x, int y, int oldx, int oldy) {
+            getScrollStartEndHelper().onScrolled(x, y);
+            if(!getDomObject().getEvents().contains(Constants.Event.SCROLL)){
+              return;
+            }
             if (shouldReport(x, y)) {
               fireScrollEvent(scrollView.getContentFrame(), x, y, oldx, oldy);
             }
@@ -187,6 +207,16 @@ public class WXScroller extends WXVContainer<ViewGroup> 
implements WXScrollViewL
   }
 
   private void fireScrollEvent(Rect contentFrame, int x, int y, int oldx, int 
oldy) {
+    fireEvent(Constants.Event.SCROLL, getScrollEvent(x, y));
+  }
+
+  public Map<String, Object> getScrollEvent(int x, int y){
+    Rect contentFrame =  new Rect();
+    if (getInnerView() instanceof WXScrollView) {
+       contentFrame = ((WXScrollView) getInnerView()).getContentFrame();
+    }else if (getInnerView() instanceof WXHorizontalScrollView) {
+      contentFrame = ((WXHorizontalScrollView) 
getInnerView()).getContentFrame();
+    }
     Map<String, Object> event = new HashMap<>(2);
     Map<String, Object> contentSize = new HashMap<>(2);
     Map<String, Object> contentOffset = new HashMap<>(2);
@@ -201,8 +231,7 @@ public class WXScroller extends WXVContainer<ViewGroup> 
implements WXScrollViewL
 
     event.put(Constants.Name.CONTENT_SIZE, contentSize);
     event.put(Constants.Name.CONTENT_OFFSET, contentOffset);
-
-    fireEvent(Constants.Event.SCROLL, event);
+    return  event;
   }
 
   private boolean shouldReport(int x, int y) {
@@ -719,4 +748,12 @@ public class WXScroller extends WXVContainer<ViewGroup> 
implements WXScrollViewL
   public void resetLoadmore() {
     mForceLoadmoreNextTime = true;
   }
+
+
+  public ScrollStartEndHelper getScrollStartEndHelper() {
+    if(mScrollStartEndHelper == null){
+      mScrollStartEndHelper = new ScrollStartEndHelper(this);
+    }
+    return mScrollStartEndHelper;
+  }
 }

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/40de9402/android/sdk/src/main/java/com/taobao/weex/ui/component/helper/ScrollStartEndHelper.java
----------------------------------------------------------------------
diff --git 
a/android/sdk/src/main/java/com/taobao/weex/ui/component/helper/ScrollStartEndHelper.java
 
b/android/sdk/src/main/java/com/taobao/weex/ui/component/helper/ScrollStartEndHelper.java
new file mode 100644
index 0000000..15163e1
--- /dev/null
+++ 
b/android/sdk/src/main/java/com/taobao/weex/ui/component/helper/ScrollStartEndHelper.java
@@ -0,0 +1,116 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package com.taobao.weex.ui.component.helper;
+
+import android.os.Handler;
+import android.os.Looper;
+import com.taobao.weex.common.Constants;
+import com.taobao.weex.ui.component.WXComponent;
+import com.taobao.weex.ui.component.WXScroller;
+import com.taobao.weex.ui.component.list.BasicListComponent;
+import com.taobao.weex.ui.component.list.ListComponentView;
+import com.taobao.weex.ui.component.list.template.WXRecyclerTemplateList;
+import com.taobao.weex.utils.WXUtils;
+
+import java.util.Map;
+
+
+/**
+ * Created by furture on 2017/11/13.
+ */
+
+public class ScrollStartEndHelper  implements Runnable{
+
+    private Handler handler;
+    private WXComponent component;
+    private boolean  hasStart;
+    private long  minInterval;
+
+    private int x;
+    private int y;
+
+    public ScrollStartEndHelper(WXComponent component) {
+        this.component = component;
+        this.handler = new Handler(Looper.getMainLooper());
+        this.minInterval = 
WXUtils.getNumberInt(component.getDomObject().getAttrs().get("minscrolldelayinterval"),
 32);
+    }
+
+    /**
+     * @param  x scroll offset or dx, which is not accurate
+     * @param  y scroll offset or dy, which is not accurate
+     * */
+    public void  onScrolled(int x, int y){
+        
if((component.getDomObject().getEvents().contains(Constants.Event.SCROLL_START)
+                || 
component.getDomObject().getEvents().contains(Constants.Event.SCROLL_END))){
+            this.x = x;
+            this.y = y;
+            if(!hasStart){
+                
if(component.getDomObject().getEvents().contains(Constants.Event.SCROLL_START)){
+                    component.fireEvent(Constants.Event.SCROLL_START, 
getScrollEvent(x, y));
+                }
+                hasStart = true;
+            }
+            handler.removeCallbacks(this);
+            handler.postDelayed(this, minInterval);
+        }
+    }
+
+
+    @Override
+    public void run() {
+        if(component.isDestoryed()){
+            return;
+        }
+        
if(component.getDomObject().getEvents().contains(Constants.Event.SCROLL_END)){
+            component.fireEvent(Constants.Event.SCROLL_END, 
getScrollEvent(this.x, this.y));
+        }
+        hasStart = false;
+    }
+
+    private Map<String, Object> getScrollEvent(int offsetX, int offsetY){
+        if(component instanceof BasicListComponent){
+            BasicListComponent basicListComponent = (BasicListComponent) 
component;
+            if(basicListComponent.getHostView() instanceof  ListComponentView){
+                ListComponentView componentView = (ListComponentView) 
basicListComponent.getHostView();
+                if(componentView != null){
+                    return 
basicListComponent.getScrollEvent(componentView.getInnerView(), offsetX, 
offsetY);
+                }
+            }
+        }else if(component instanceof WXRecyclerTemplateList){
+            WXRecyclerTemplateList templateList = (WXRecyclerTemplateList) 
component;
+            return 
templateList.getScrollEvent(templateList.getHostView().getInnerView(), offsetX, 
offsetY);
+        }else if(component instanceof WXScroller){
+            WXScroller scroller = (WXScroller) component;
+            return scroller.getScrollEvent(offsetX, offsetY);
+        }
+        return null;
+    }
+
+
+    public static boolean isScrollEvent(String type){
+        if(Constants.Event.SCROLL.equals(type)){
+            return  true;
+        }else if(Constants.Event.SCROLL_START.equals(type)){
+            return  true;
+        }else if(Constants.Event.SCROLL_END.equals(type)){
+            return  true;
+        }
+        return  false;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/40de9402/android/sdk/src/main/java/com/taobao/weex/ui/component/list/BasicListComponent.java
----------------------------------------------------------------------
diff --git 
a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/BasicListComponent.java
 
b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/BasicListComponent.java
index bf51870..e8920d3 100644
--- 
a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/BasicListComponent.java
+++ 
b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/BasicListComponent.java
@@ -58,13 +58,13 @@ import com.taobao.weex.ui.component.WXComponentProp;
 import com.taobao.weex.ui.component.WXLoading;
 import com.taobao.weex.ui.component.WXRefresh;
 import com.taobao.weex.ui.component.WXVContainer;
+import com.taobao.weex.ui.component.helper.ScrollStartEndHelper;
 import com.taobao.weex.ui.component.helper.WXStickyHelper;
 import com.taobao.weex.ui.view.listview.WXRecyclerView;
 import com.taobao.weex.ui.view.listview.adapter.IOnLoadMoreListener;
 import com.taobao.weex.ui.view.listview.adapter.IRecyclerAdapterListener;
 import com.taobao.weex.ui.view.listview.adapter.ListBaseViewHolder;
 import com.taobao.weex.ui.view.listview.adapter.RecyclerViewBaseAdapter;
-import com.taobao.weex.ui.view.listview.adapter.TransformItemDecoration;
 import com.taobao.weex.ui.view.listview.adapter.WXRecyclerViewOnScrollListener;
 import com.taobao.weex.utils.WXLogUtils;
 import com.taobao.weex.utils.WXResourceUtils;
@@ -78,7 +78,6 @@ import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
 /**
@@ -113,6 +112,7 @@ public abstract class BasicListComponent<T extends 
ViewGroup & ListComponentView
 
   private int mOffsetAccuracy = 10;
   private Point mLastReport = new Point(-1, -1);
+  private boolean mHasAddScrollEvent = false;
 
   private RecyclerView.ItemAnimator mItemAnimator;
 
@@ -150,6 +150,12 @@ public abstract class BasicListComponent<T extends 
ViewGroup & ListComponentView
   private WXStickyHelper stickyHelper;
 
 
+  /**
+   * scroll start and scroll end event
+   * */
+  private ScrollStartEndHelper mScrollStartEndHelper;
+
+
 
   /**
    * keep positon
@@ -1204,7 +1210,11 @@ public abstract class BasicListComponent<T extends 
ViewGroup & ListComponentView
   @Override
   public void addEvent(String type) {
     super.addEvent(type);
-    if (Constants.Event.SCROLL.equals(type) && getHostView() != null && 
getHostView().getInnerView() != null) {
+    if (ScrollStartEndHelper.isScrollEvent(type)
+            && getHostView() != null
+            && getHostView().getInnerView() != null
+            && !mHasAddScrollEvent) {
+      mHasAddScrollEvent = true;
       WXRecyclerView innerView = getHostView().getInnerView();
       innerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
         private int offsetXCorrection, offsetYCorrection;
@@ -1230,7 +1240,10 @@ public abstract class BasicListComponent<T extends 
ViewGroup & ListComponentView
             offsetX = offsetX - offsetXCorrection;
             offsetY = offsetY - offsetYCorrection;
           }
-
+          getScrollStartEndHelper().onScrolled(offsetX, offsetY);
+          if(!getDomObject().getEvents().contains(Constants.Event.SCROLL)){
+            return;
+          }
           if (mFirstEvent) {
             //skip first event
             mFirstEvent = false;
@@ -1251,6 +1264,10 @@ public abstract class BasicListComponent<T extends 
ViewGroup & ListComponentView
   }
 
   private void fireScrollEvent(RecyclerView recyclerView, int offsetX, int 
offsetY) {
+    fireEvent(Constants.Event.SCROLL, getScrollEvent(recyclerView, offsetX, 
offsetY));
+  }
+
+  public Map<String, Object> getScrollEvent(RecyclerView recyclerView, int 
offsetX, int offsetY){
     if(getOrientation() == Constants.Orientation.VERTICAL){
       offsetY = - calcContentOffset(recyclerView);
     }
@@ -1274,8 +1291,7 @@ public abstract class BasicListComponent<T extends 
ViewGroup & ListComponentView
     contentOffset.put(Constants.Name.Y, - WXViewUtils.getWebPxByWidth(offsetY, 
getInstance().getInstanceViewPortWidth()));
     event.put(Constants.Name.CONTENT_SIZE, contentSize);
     event.put(Constants.Name.CONTENT_OFFSET, contentOffset);
-
-    fireEvent(Constants.Event.SCROLL, event);
+    return event;
   }
 
   private boolean shouldReport(int offsetX, int offsetY) {
@@ -1356,4 +1372,11 @@ public abstract class BasicListComponent<T extends 
ViewGroup & ListComponentView
     //Unhandled LayoutManager type
     return -1;
   }
+
+  public ScrollStartEndHelper getScrollStartEndHelper() {
+    if(mScrollStartEndHelper == null){
+       mScrollStartEndHelper = new ScrollStartEndHelper(this);
+    }
+    return mScrollStartEndHelper;
+  }
 }

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/40de9402/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/WXRecyclerTemplateList.java
----------------------------------------------------------------------
diff --git 
a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/WXRecyclerTemplateList.java
 
b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/WXRecyclerTemplateList.java
index 76bcce0..2e2992f 100644
--- 
a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/WXRecyclerTemplateList.java
+++ 
b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/WXRecyclerTemplateList.java
@@ -44,16 +44,13 @@ import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.taobao.weex.WXEnvironment;
 import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.WXSDKManager;
 import com.taobao.weex.annotation.Component;
 import com.taobao.weex.annotation.JSMethod;
-import com.taobao.weex.bridge.WXBridgeManager;
 import com.taobao.weex.common.Constants;
 import com.taobao.weex.common.ICheckBindingScroller;
 import com.taobao.weex.common.OnWXScrollListener;
 import com.taobao.weex.dom.WXAttr;
 import com.taobao.weex.dom.WXCellDomObject;
-import com.taobao.weex.dom.WXDomHandler;
 import com.taobao.weex.dom.WXDomObject;
 import com.taobao.weex.dom.WXEvent;
 import com.taobao.weex.dom.WXRecyclerDomObject;
@@ -70,6 +67,7 @@ import com.taobao.weex.ui.component.WXRefresh;
 import com.taobao.weex.ui.component.WXVContainer;
 import com.taobao.weex.ui.component.binding.Layouts;
 import com.taobao.weex.ui.component.binding.Statements;
+import com.taobao.weex.ui.component.helper.ScrollStartEndHelper;
 import com.taobao.weex.ui.component.list.RecyclerTransform;
 import com.taobao.weex.ui.component.list.WXCell;
 import com.taobao.weex.ui.view.listview.WXRecyclerView;
@@ -132,6 +130,7 @@ public class WXRecyclerTemplateList extends 
WXVContainer<BounceRecyclerView> imp
     private boolean isScrollable = true;
     private int mOffsetAccuracy = 10;
     private Point mLastReport = new Point(-1, -1);
+    private boolean mHasAddScrollEvent = false;
 
     private JSONArray listData;
     private String listDataKey = Constants.Name.Recycler.LIST_DATA;
@@ -149,6 +148,13 @@ public class WXRecyclerTemplateList extends 
WXVContainer<BounceRecyclerView> imp
 
 
     /**
+     * scroll start and scroll end event
+     * */
+    private ScrollStartEndHelper mScrollStartEndHelper;
+
+
+
+    /**
      * sticky helper
      * */
     private TemplateStickyHelper mStickyHelper;
@@ -827,7 +833,11 @@ public class WXRecyclerTemplateList extends 
WXVContainer<BounceRecyclerView> imp
     @Override
     public void addEvent(String type) {
         super.addEvent(type);
-        if (Constants.Event.SCROLL.equals(type) && getHostView() != null && 
getHostView().getInnerView() != null) {
+        if (ScrollStartEndHelper.isScrollEvent(type)
+                && getHostView() != null
+                && getHostView().getInnerView() != null
+                && !mHasAddScrollEvent) {
+            mHasAddScrollEvent = true;
             WXRecyclerView innerView = getHostView().getInnerView();
             innerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
                 private int offsetXCorrection, offsetYCorrection;
@@ -852,7 +862,10 @@ public class WXRecyclerTemplateList extends 
WXVContainer<BounceRecyclerView> imp
                         offsetX = offsetX - offsetXCorrection;
                         offsetY = offsetY - offsetYCorrection;
                     }
-
+                    getScrollStartEndHelper().onScrolled(offsetX, offsetY);
+                    
if(!getDomObject().getEvents().contains(Constants.Event.SCROLL)){
+                        return;
+                    }
                     if (mFirstEvent) {
                         //skip first event
                         mFirstEvent = false;
@@ -868,6 +881,10 @@ public class WXRecyclerTemplateList extends 
WXVContainer<BounceRecyclerView> imp
     }
 
     private void fireScrollEvent(RecyclerView recyclerView, int offsetX, int 
offsetY) {
+        fireEvent(Constants.Event.SCROLL, getScrollEvent(recyclerView, 
offsetX, offsetY));
+    }
+
+    public Map<String, Object> getScrollEvent(RecyclerView recyclerView, int 
offsetX, int offsetY){
         offsetY = -calcContentOffset(recyclerView);
         int contentWidth = recyclerView.getMeasuredWidth() + 
recyclerView.computeHorizontalScrollRange();
         int contentHeight = calcContentSize();
@@ -883,10 +900,11 @@ public class WXRecyclerTemplateList extends 
WXVContainer<BounceRecyclerView> imp
         contentOffset.put(Constants.Name.Y, - 
WXViewUtils.getWebPxByWidth(offsetY, getInstance().getInstanceViewPortWidth()));
         event.put(Constants.Name.CONTENT_SIZE, contentSize);
         event.put(Constants.Name.CONTENT_OFFSET, contentOffset);
-
-        fireEvent(Constants.Event.SCROLL, event);
+        return event;
     }
 
+
+
     private boolean shouldReport(int offsetX, int offsetY) {
         if (mLastReport.x == -1 && mLastReport.y == -1) {
             mLastReport.x = offsetX;
@@ -1639,4 +1657,11 @@ public class WXRecyclerTemplateList extends 
WXVContainer<BounceRecyclerView> imp
             }
         }
     }
+
+    public ScrollStartEndHelper getScrollStartEndHelper() {
+        if(mScrollStartEndHelper == null){
+            mScrollStartEndHelper = new ScrollStartEndHelper(this);
+        }
+        return mScrollStartEndHelper;
+    }
 }

Reply via email to