Hi Minh,
        Ack.

Thanks
-Nagu


> -----Original Message-----
> From: minh chau [mailto:[email protected]]
> Sent: 05 July 2017 06:24
> To: Nagendra Kumar; [email protected];
> [email protected]; Praveen Malviya
> Cc: [email protected]
> Subject: Re: [PATCH 1/1] amfd: Avoid to create duplicated 2N ACTIVE SUSI
> for absent assignment V2 [#2477]
> 
> Hi Nagu,
> 
> Plesae find my comments with [Minh]
> 
> Thanks,
> Minh
> On 04/07/17 22:53, Nagendra Kumar wrote:
> > Hi Minh,
> >             Thanks for clarification.
> > 1. But, I didn't get the logic of (tail == tail). What will happen if the 
> > message
> is last i.e. tail, then will it go into loop?
> [Minh]: The if condition is (tail == cb->dnd_list.tail), the @tail is to
> memorize the last item in queue before any change.
> When we pop a susi message for example, change msg_id, push it back, now
> the dnd_list.tail is changed. So the if (tail == cb->dnd_list.tail) is
> to know if we reach all items of the queue
> > 2. So, after this patch what is the outcome of scenario listed in the 
> > ticket. Is
> it able to do a failover ?
> We now don't create an absent active susi so we will not do any
> absent_failover(). With only one active susi, sg fsm will continue to
> create another standby susi. The outcome is:
> safSISU=safSu=SU4\,safSg=AmfDemoTwon\,safApp=AmfDemoTwon,safSi=A
> mfDemoTwonDep1,safApp=AmfDemoTwon
>      saAmfSISUHAState=ACTIVE(1)
>      saAmfSISUHAReadinessState=READY_FOR_ASSIGNMENT(1)
> \--
> safSISU=safSu=SU4\,safSg=AmfDemoTwon\,safApp=AmfDemoTwon,safSi=A
> mfDemoTwonDep2,safApp=AmfDemoTwon
>      saAmfSISUHAState=ACTIVE(1)
>      saAmfSISUHAReadinessState=READY_FOR_ASSIGNMENT(1)
> safSISU=safSu=SU4\,safSg=AmfDemoTwon\,safApp=AmfDemoTwon,safSi=A
> mfDemoTwon,safApp=AmfDemoTwon
>      saAmfSISUHAState=ACTIVE(1)
>      saAmfSISUHAReadinessState=READY_FOR_ASSIGNMENT(1)
> --
> safSISU=safSu=SU1\,safSg=AmfDemoTwon\,safApp=AmfDemoTwon,safSi=A
> mfDemoTwon,safApp=AmfDemoTwon
>      saAmfSISUHAState=STANDBY(2)
>      saAmfSISUHAReadinessState=READY_FOR_ASSIGNMENT(1)
> --
> safSISU=safSu=SU1\,safSg=AmfDemoTwon\,safApp=AmfDemoTwon,safSi=A
> mfDemoTwonDep2,safApp=AmfDemoTwon
>      saAmfSISUHAState=STANDBY(2)
>      saAmfSISUHAReadinessState=READY_FOR_ASSIGNMENT(1)
> safSISU=safSu=SU1\,safSg=AmfDemoTwon\,safApp=AmfDemoTwon,safSi=A
> mfDemoTwonDep1,safApp=AmfDemoTwon
>      saAmfSISUHAState=STANDBY(2)
>      saAmfSISUHAReadinessState=READY_FOR_ASSIGNMENT(1)
> 
> SU4 has active assignment which was assigned from failover during both
> SC were going down. SU1 has newly standby assignments
> 
> 
> >
> > Thanks
> > -Nagu
> >
> >> -----Original Message-----
> >> From: minh chau [mailto:[email protected]]
> >> Sent: 02 July 2017 03:28
> >> To: Nagendra Kumar; [email protected];
> >> [email protected]; Praveen Malviya
> >> Cc: [email protected]
> >> Subject: Re: [PATCH 1/1] amfd: Avoid to create duplicated 2N ACTIVE
> SUSI
> >> for absent assignment V2 [#2477]
> >>
> >> Hi Nagu,
> >>
> >> Please find my replies with [Minh]
> >>
> >> Thanks,
> >> Minh
> >>
> >> On 01/07/17 00:33, Nagendra Kumar wrote:
> >>> Hi Minh,
> >>>   Please find comment inlined with [Nagu].
> >>>
> >>> Thanks
> >>> -Nagu
> >>>
> >>>> -----Original Message-----
> >>>> From: Minh Chau [mailto:[email protected]]
> >>>> Sent: 20 June 2017 07:11
> >>>> To:[email protected];[email protected];
> >>>> [email protected];[email protected]
> >>>> Cc:[email protected]; Minh Chau
> >>>> Subject: [PATCH 1/1] amfd: Avoid to create duplicated 2N ACTIVE SUSI
> for
> >>>> absent assignment V2 [#2477]
> >>>>
> >>>> In large cluster, the IMM sync calls mostly take no effect  when both
> SCs
> >>>> abruptly go down, thus amfd may leaves the susi assignments in amfnd
> >> and
> >>>> IMM in unexpected states.
> >>>>
> >>>> The scenario is same as #2416, but in #2477 amfd can also see 2
> ACTIVE
> >>>> assignments of 2 SUs for the same 2N SI. That leads to osafassert(),
> >> causes
> >>>> node reboot, and the same osafassert() repeatedly happens after node
> >>>> comes up.
> >>>>
> >>>> Patch refactors the creation of absent assignment by adding new
> function
> >>>> avd_susi_validate_absent_assignment(), and adds a check to avoid
> >> creating 2
> >>>> ACTIVE assignments for one SI. Also, a fix
> >>>> avnd_diq_rec_check_buffered_msg() is needed in this scenario
> >>>> ---
> >>>>    src/amf/amfd/siass.cc | 127 ++++++++++++++++++++++++++++++++--
> ---
> >> -----
> >>>> --------
> >>>>    src/amf/amfd/susi.h   |   4 +-
> >>>>    src/amf/amfnd/di.cc   |   6 ++-
> >>>>    3 files changed, 89 insertions(+), 48 deletions(-)
> >>>>
> >>>> diff --git a/src/amf/amfd/siass.cc b/src/amf/amfd/siass.cc index
> >>>> 6a13836f9..d14d279dc 100644
> >>>> --- a/src/amf/amfd/siass.cc
> >>>> +++ b/src/amf/amfd/siass.cc
> >>>> @@ -218,13 +218,20 @@ void
> >>>> avd_susi_read_headless_cached_rta(AVD_CL_CB *cb) {
> >>>>            std::string(strstr(osaf_extended_name_borrow(&dn), "safSi"));
> >>>>        assert(si_name.empty() == false);
> >>>>        AVD_SI *si = si_db->find(si_name);
> >>>> -    osafassert(si);
> >>>> +    if (si == nullptr) {
> >>>> +      LOG_ER("SI:'%s' does not exist in AMF's sidb", si_name.c_str());
> >>>> +      continue;
> >>>> +    }
> >>> [Nagu]: If we have SUSI in Imm DB, then SI should exist. Did you get any
> >> scenario which hits this.
> >>>>        SaNameT su_name;
> >>>>        avsv_sanamet_init_from_association_dn(&dn, &su_name, "safSu",
> >>>>                                              si->name.c_str());
> >>>>        AVD_SU *su = su_db->find(Amf::to_string(&su_name));
> >>>> +    if (su == nullptr) {
> >>>> +      LOG_ER("SU:'%s' does not exist in AMF's sudb",
> >>>> +          Amf::to_string(&su_name).c_str());
> >>>> +      continue;
> >>>> +    }
> >>>>        osaf_extended_name_free(&su_name);
> >>>> -    osafassert(su);
> >>> [Nagu]: If we have SUSI in Imm DB, then SU should exist. Did you get any
> >> scenario which hits this.
> >> [Minh]: We have failed into this assert in cluster with many "real"
> >> applications. It is basically not AMF problem, it appeared to be a link
> >> problem. But this osafassert() was causing the cyclic reboot and it's
> >> hard to collect the log. It didn't help to recover, and replace it by
> >> LOG_ER might leave SG unstable but it's way better of cyclic reboot. I
> >> think we need to look at this kind of asserts elsewhere and need to
> >> enable/disable it in debug/production build.
> >>>>        susi = avd_su_susi_find(cb, su, si->name);
> >>>>        rc = immutil_getAttr("osafAmfSISUFsmState", attributes, 0,
> >>>> &imm_susi_fsm);
> >>>>        osafassert(rc == SA_AIS_OK);
> >>>> @@ -232,10 +239,11 @@ void
> >>>> avd_susi_read_headless_cached_rta(AVD_CL_CB *cb) {
> >>>>        osafassert(rc == SA_AIS_OK);
> >>>>
> >>>>        if (susi) {  // FOR PRESENT SUSI found in AMFND(s)
> >>>> -      TRACE("SISU:'%s', old(imm) fsm state: %d, new(sync) fsm state:
> %d",
> >>>> -            Amf::to_string(&dn).c_str(), imm_susi_fsm, susi->fsm);
> >>>> +      TRACE("Check present SUSI:'%s', old(imm) fsm state: %d,"
> >>>> +          "new(sync) fsm state: %d", Amf::to_string(&dn).c_str(),
> >>>> +          imm_susi_fsm, susi->fsm);
> >>>>
> >>>> -      if (avd_susi_validate_headless_cached_rta(susi, imm_ha_state,
> >>>> +      if (avd_susi_validate_present_assignment(susi, imm_ha_state,
> >>>>                                                    imm_susi_fsm) == 
> >>>> false) {
> >>>>            continue;
> >>>>          }
> >>>> @@ -279,38 +287,29 @@ void
> >>>> avd_susi_read_headless_cached_rta(AVD_CL_CB *cb) {
> >>>>          if (susi->su->su_on_node->admin_ng == nullptr)
> >>>>            avd_ng_restore_headless_states(cb, susi);
> >>>>        } else {  // For ABSENT SUSI
> >>>> -      if (su->sg_of_su->sg_ncs_spec == false &&
> >>>> -          su->sg_of_su->sg_redundancy_model !=
> >>>> SA_AMF_NO_REDUNDANCY_MODEL &&
> >>>> -          su->sg_of_su->sg_redundancy_model !=
> >>>> -              SA_AMF_N_WAY_ACTIVE_REDUNDANCY_MODEL &&
> >>>> -          (su->sg_of_su->any_assignment_in_progress() == true ||
> >>>> -           su->sg_of_su->any_assignment_assigned() == true)) {
> >>>> -        TRACE("Absent SUSI, ha_state:'%u', fsm_state:'%u'",
> imm_ha_state,
> >>>> -              imm_susi_fsm);
> >>>> -        if (imm_susi_fsm != AVD_SU_SI_STATE_UNASGN) {
> >>>> -          absent_susi = avd_susi_create(avd_cb, si, su, imm_ha_state,
> false,
> >>>> -                                        AVSV_SUSI_ACT_BASE);
> >>>> -          // Restore the fsm of this absent SUSI, which is used to
> determine
> >>>> -          // whether a SU should be added in SG's SUOperationList
> >>>> -          // Memorize it in temporary var @absent
> >>>> -          // The fsm of this SUSI will be changed to
> >> AVD_SU_SI_STATE_ABSENT
> >>>> -          // after restoring SUOperationList
> >>>> -          absent_susi->fsm = imm_susi_fsm;
> >>>> -          absent_susi->absent = true;
> >>>> -          if (absent_susi->si->saAmfSIAdminState ==
> >> SA_AMF_ADMIN_LOCKED
> >>>> ||
> >>>> -              absent_susi->si->saAmfSIAdminState ==
> >>>> -                  SA_AMF_ADMIN_SHUTTING_DOWN) {
> >>>> -            if (absent_susi->fsm == AVD_SU_SI_STATE_MODIFY &&
> >>>> -                (absent_susi->state == SA_AMF_HA_QUIESCED ||
> >>>> -                 absent_susi->state == SA_AMF_HA_QUIESCING)) {
> >>>> -              m_AVD_SET_SG_ADMIN_SI(cb, si);
> >>>> -            }
> >>>> -          }
> >>>> -        } else {
> >>>> -          avd_saImmOiRtObjectDelete(Amf::to_string(&dn));
> >>>> -        }
> >>>> -      } else {
> >>>> +      TRACE("Check absent SUSI, ha_state:'%u', fsm_state:'%u'",
> >>>> imm_ha_state,
> >>>> +            imm_susi_fsm);
> >>>> +      if (avd_susi_validate_absent_assignment(su, si,
> >>>> +          imm_ha_state, imm_susi_fsm) == false) {
> >>>>            avd_saImmOiRtObjectDelete(Amf::to_string(&dn));
> >>>> +        continue;
> >>>> +      }
> >>>> +      absent_susi = avd_susi_create(avd_cb, si, su, imm_ha_state, false,
> >>>> +          AVSV_SUSI_ACT_BASE);
> >>>> +      // Restore the fsm of this absent SUSI, which is used to determine
> >>>> +      // whether a SU should be added in SG's SUOperationList
> >>>> +      // Memorize it in temporary var @absent
> >>>> +      // The fsm of this SUSI will be changed to
> AVD_SU_SI_STATE_ABSENT
> >>>> +      // after restoring SUOperationList
> >>>> +      absent_susi->fsm = imm_susi_fsm;
> >>>> +      absent_susi->absent = true;
> >>>> +      if (absent_susi->si->saAmfSIAdminState ==
> SA_AMF_ADMIN_LOCKED
> >> ||
> >>>> +          absent_susi->si->saAmfSIAdminState ==
> >>>> SA_AMF_ADMIN_SHUTTING_DOWN) {
> >>>> +        if (absent_susi->fsm == AVD_SU_SI_STATE_MODIFY &&
> >>>> +            (absent_susi->state == SA_AMF_HA_QUIESCED ||
> >>>> +                absent_susi->state == SA_AMF_HA_QUIESCING)) {
> >>>> +          m_AVD_SET_SG_ADMIN_SI(cb, si);
> >>>> +        }
> >>>>          }
> >>>>        }
> >>>>      }
> >>>> @@ -321,13 +320,58 @@ done:
> >>>>      TRACE_LEAVE();
> >>>>    }
> >>> [Nagu]: I find below function and above changes are just refactoring. It
> is
> >> not making any logic change, please confirm?
> >> [Minh]: The main change is at check of 2N SG where the old code doesn't.
> >> It avoids to create an absent ACTIVE SUSI read from IMM while AMFD is
> >> having another present ACTIVE SUSI for the same SI.
> >>>>    /**
> >>>> + * Validate the creation of absent assignment
> >>>> + * @param su: The SU associated with absent assignment
> >>>> + * @param si: The SI associated with absent assignment
> >>>> + * @return: true of valid, false otherwise  */ bool
> >>>> +avd_susi_validate_absent_assignment(AVD_SU *su, AVD_SI *si,
> >>>> +    SaAmfHAStateT imm_ha_state, AVD_SU_SI_STATE imm_fsm_state)
> {
> >>>> +  bool valid = false;
> >>>> +  TRACE_ENTER();
> >>>> +  // Must be application sg
> >>>> +  if (su->sg_of_su->sg_ncs_spec == true) goto done;
> >>>> +  // skip for removing SUSI assignment
> >>>> +  if (imm_fsm_state == AVD_SU_SI_STATE_UNASGN) goto done;
> >>>> +  // Must have present SUSI assignment
> >>>> +  if (su->sg_of_su->any_assignment_in_progress() == false &&
> >>>> +      su->sg_of_su->any_assignment_assigned() == false) {
> >>>> +    goto done;
> >>>> +  }
> >>>> +  // Support: 2N, NoRed, NwayActive. Not support: NpM, Nway
> >>>> +  if (su->sg_of_su->sg_redundancy_model ==
> >>>> SA_AMF_NPM_REDUNDANCY_MODEL ||
> >>>> +      su->sg_of_su->sg_redundancy_model ==
> >>>> SA_AMF_N_WAY_REDUNDANCY_MODEL) {
> >>>> +    LOG_WA("Unsupported SG Redundancy model(%d) for SC Absence",
> >>>> +        su->sg_of_su->sg_redundancy_model);
> >>>> +  }
> >>>> +  // Skip for NoRed and NWayActive
> >>>> +  if (su->sg_of_su->sg_redundancy_model ==
> >>>> SA_AMF_NO_REDUNDANCY_MODEL ||
> >>>> +        su->sg_of_su->sg_redundancy_model ==
> >>>> +            SA_AMF_N_WAY_ACTIVE_REDUNDANCY_MODEL) {
> >>>> +      goto done;
> >>>> +  }
> >>>> +  // No need to create absent SUSI assignment for the 2N SI that
> >>>> +already has
> >>>> +  // ACTIVE SUSI
> >>>> +  if (su->sg_of_su->sg_redundancy_model ==
> >>>> SA_AMF_2N_REDUNDANCY_MODEL) {
> >>>> +    if (si->list_of_sisu != nullptr &&
> >>>> +        si->list_of_sisu->state == SA_AMF_HA_ACTIVE &&
> >>>> +        imm_ha_state == SA_AMF_HA_ACTIVE)
> >>>> +      goto done;
> >>>> +  }
> >>>> +
> >>>> +  valid = true;
> >>>> +done:
> >>>> +  TRACE_LEAVE();
> >>>> +  return valid;
> >>>> +}
> >>>> +/**
> >>>>     * Validate cached RTA read from IMM
> >>>>     * @param present_susi
> >>>>     * @param ha_fr_imm: Ha state of @present_susi read from IMM
> >>>>     * @param fsm_fr_imm: Fsm state of @present susi read from IMM
> >>>>     * @return: true of valid, false otherwise
> >>>>     */
> >>>> -bool avd_susi_validate_headless_cached_rta(AVD_SU_SI_REL
> >>>> *present_susi,
> >>>> +bool avd_susi_validate_present_assignment(AVD_SU_SI_REL
> >> *present_susi,
> >>>>                                               SaAmfHAStateT ha_fr_imm,
> >>>>                                               AVD_SU_SI_STATE 
> >>>> fsm_fr_imm) {
> >>>>      std::string dn = present_susi->si->name + "," + present_susi->su-
> >name;
> >>>> @@ -335,15 +379,8 @@ bool
> >>>> avd_susi_validate_headless_cached_rta(AVD_SU_SI_REL
> *present_susi,
> >>>>      bool valid = true;
> >>>>      // rule 1: valid ha state
> >>>>      if (ha_fr_imm != present_susi->state) {
> >>>> -    if (ha_fr_imm == SA_AMF_HA_QUIESCING || ha_fr_imm ==
> >>>> SA_AMF_HA_QUIESCED) {
> >>>> -      // That's fine
> >>>> -      ;
> >>>> -    } else {
> >>>> -      LOG_ER("SISU:'%s', old(imm) ha state: %d, new(sync) ha state: %d",
> >>>> +      LOG_WA("SISU:'%s', old(imm) ha state: %d, new(sync) ha state:
> >>>> + %d",
> >>>>                 dn.c_str(), ha_fr_imm, present_susi->state);
> >>>> -      valid = false;
> >>>> -      goto done;
> >>>> -    }
> >>>>      }
> >>> [Nagu]: This change will allow the present susi to go ahead in function
> and
> >> will not mark valid as false.
> >>>                   This means that avd_susi_validate_present_assignment 
> >>> will
> return
> >> true. So, how this change is helping
> >>>                   In solving the problem, please explain.
> >> [Minh]: This change needs to return true to update the assignment
> >> counter of active present susi, since we will not let the 2nd active
> >> absent susi to be created (as in previous comment). In V1 patch, we
> >> allowed to create the 2nd absent susi, then failover it by node_fail()
> >> and from there the assignment counter will be updated.
> >>>>      // rule 2: if ha_fr_imm is QUIESCING, one of relevant entities must
> >>>>      // have adminState is SHUTTINGDOWN, otherwise re-adjust if
> possible
> >> diff
> >>>> --git a/src/amf/amfd/susi.h b/src/amf/amfd/susi.h index
> >>>> 94bd04033..5d925baae 100644
> >>>> --- a/src/amf/amfd/susi.h
> >>>> +++ b/src/amf/amfd/susi.h
> >>>> @@ -143,9 +143,11 @@ AVD_SU_SI_REL *avd_susi_create(
> >>>> AVD_SU_SI_REL *avd_susi_find(AVD_CL_CB *cb, const std::string
> >>>> &su_name,
> >>>>                                 const std::string &si_name);  void
> >>>> avd_susi_update_fsm(AVD_SU_SI_REL *susi, AVD_SU_SI_STATE
> >>>> new_fsm_state); -bool
> >>>> avd_susi_validate_headless_cached_rta(AVD_SU_SI_REL
> *present_susi,
> >>>> +bool avd_susi_validate_present_assignment(AVD_SU_SI_REL
> >> *present_susi,
> >>>>                                               SaAmfHAStateT ha_fr_imm,
> >>>>                                               AVD_SU_SI_STATE 
> >>>> fsm_fr_imm);
> >>>> +bool avd_susi_validate_absent_assignment(AVD_SU *su, AVD_SI *si,
> >>>> +    SaAmfHAStateT imm_ha_state, AVD_SU_SI_STATE imm_fsm_state);
> >>>>    void avd_susi_read_headless_cached_rta(AVD_CL_CB *cb);  extern
> void
> >>>> avd_susi_update(AVD_SU_SI_REL *susi, SaAmfHAStateT ha_state);
> >>>>
> >>> [Nagu]: Below logic change has no comment, not sure how this is
> related
> >> to the issue.
> >> [Minh]: The below change came from a test of double cyclic reboot of SC
> >> in the scenario of this issue.
> >> - after SC asbence stage, SC1 restarts, all msg_id of buffered msgs are
> >> corrected, plus amfnd has one node_up msg and it's waiting for ack
> >> - Now SC1 reboot, when we get mdsncs_down, we don't clean all
> buffered
> >> anymore, thus the previous node_up msg is still in queue, this node_up
> >> msg (or maybe some other msgs was around 1st reboot) should be
> removed.
> >>
> >> The "break" (before this patch) has made the loop quit at just the first
> >> time that amfnd found the SUSI_ASSIGN/OPER_STATE being *already*
> >> corrected, then amfnd hasn't gone through all the buffered list. amfnd
> >> will go through all the list for this first time of uncorrected buffered
> >> msg, but it doesn't go for the next time. So this patch is for this
> >> scenario.
> >>>> diff --git a/src/amf/amfnd/di.cc b/src/amf/amfnd/di.cc index
> >>>> 6f0a76cda..0da907566 100644
> >>>> --- a/src/amf/amfnd/di.cc
> >>>> +++ b/src/amf/amfnd/di.cc
> >>>> @@ -1290,6 +1290,7 @@ void avnd_di_msg_ack_process(AVND_CB
> *cb,
> >>>> uint32_t mid) {  void avnd_diq_rec_check_buffered_msg(AVND_CB *cb)
> {
> >>>>      if ((cb->dnd_list.head != nullptr)) {
> >>>>        AVND_DND_MSG_LIST *rec = 0;
> >>>> +    AVND_DND_MSG_LIST *tail = cb->dnd_list.tail;
> >>>>        bool found = true;
> >>>>        while (found) {
> >>>>          found = false;
> >>>> @@ -1318,7 +1319,7 @@ void
> >>>> avnd_diq_rec_check_buffered_msg(AVND_CB *cb) {
> >>>>                    rec->msg.info.avd->msg_info.n2d_su_si_assign.msg_id);
> >>>>              }
> >>>>              m_AVND_DIQ_REC_PUSH(cb, rec);
> >>>> -          break;
> >>>> +          if (tail == cb->dnd_list.tail) break;
> >>>>            } else if (rec->msg.info.avd->msg_type ==
> >>>>                  AVSV_N2D_OPERATION_STATE_MSG) {
> >>>>              if (rec->msg.info.avd->msg_info.n2d_opr_state.msg_id != 0) {
> @@
> >> -
> >>>> 1337,11 +1338,12 @@ void
> >> avnd_diq_rec_check_buffered_msg(AVND_CB
> >>>> *cb) {
> >>>>                        .raw);
> >>>>              }
> >>>>              m_AVND_DIQ_REC_PUSH(cb, rec);
> >>>> -          break;
> >>>> +          if (tail == cb->dnd_list.tail) break;
> >>>>            } else {
> >>>>              // delete other messages for now
> >>>>              avnd_diq_rec_del(cb, rec);
> >>>>              rec = cb->dnd_list.head;
> >>>> +          tail = cb->dnd_list.tail;
> >>>>            }
> >>>>          }
> >>>>        }
> >>>> --
> >>>> 2.11.0
> 

------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
Opensaf-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/opensaf-devel

Reply via email to