• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/**
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16/**
17 * @file: Mobile Network Home page
18 */
19import { addAirPlaneModeListener, removeAirPlaneModeListener, queryAirPlaneMode } from '../common/utils/AirplaneMode';
20import publiccontent from '../common/components/publiccontent';
21import item from '../common/components/listItem/listItem';
22import call from '@ohos.telephony.call';
23import { registerSimStateChange, getMaxSimCount } from '../model/registerSimStateApi';
24import { getSimStateCardOne, getSimStateCardTwo } from '../common/model/getSimStateApi';
25import { getSimCardOnePhoneNumber, getSimCardTwoPhoneNumber } from '../common/model/getSimTelephoneNumberApi';
26import {
27  isCellularDataRoamingEnabledCardOne,
28  isCellularDataRoamingEnabledCardTwo,
29  getSupportNetwork
30} from '../common/model/getCellularDataRoamingEnabledApi';
31import { setPreferredNetwork } from '../common/model/setPreferredNetworkApi';
32import { getPreferredNetwork } from '../common/model/getPreferredNetworkModeApi';
33import {
34  isCellularDataEnabled,
35  enableCellularData,
36  disableCellularData,
37  getOperatorName
38} from '../model/mobileDataStatus';
39import HeadComponent from '../common/components/headComponent';
40import { SubHeader } from '../common/components/subHeader';
41import LogUtils from '../common/utils/LogUtils';
42import router from '@ohos.router';
43
44const TAG = 'Index';
45
46@Entry
47@Component
48struct Index {
49  scroller: Scroller = new Scroller();
50  @State byValueWLMS: Resource = publiccontent.strings.fourAuto;
51  @State publicheader: Resource = publiccontent.strings.mobileData;
52  @State isLoading: boolean = true;
53  @State moisBtn: boolean = true;
54  @State isBtn: boolean = true;
55  @State gqBtn: boolean = true;
56  @State moislastone: boolean = true;
57  @State isSupport: boolean = true;
58  @State mobileDataDisabled: boolean = false;
59  @State mobileDataDisabled2: boolean = false;
60  // Mobile data switch
61  @State isDataEnable: boolean = true;
62  // Mobile AirPlane Mode
63  @State isAirPlaneMode: boolean = false;
64  // Data roaming switch
65  @State dataRoamSwitchCardOne: boolean = false;
66  @State dataRoamSwitchCardTwo: boolean = false;
67  // HD call switch
68  @State volteSwitch: boolean = false;
69  // Card I status
70  @State simStateStatusCardOne: boolean = true;
71  // Card 2 status
72  @State simStateStatusCardTwo: boolean = false;
73  @State controlSwitchWLMS: boolean = false;
74  @State slotId: number = 0;
75  @State dialogTitle: Resource = publiccontent.strings.preferredNetworkMode;
76  @State enable5g: boolean = false;
77  @StorageLink('imsOne')enableISM: boolean = false;
78  @State enableISM2: boolean = false;
79  @State mTelephoneNumber: string = '';
80  @State mTelephoneNumber2?: string = '';
81  @State ceshi: boolean = false;
82  @State cardOne: number = 0;
83  @State cardTwo: number = 1;
84
85
86  childComponentTitle: Resource = $r('app.string.mobile_data')
87
88  /**
89   * Get network mode
90   *
91   * @param {Object} slotId - call slotId
92   */
93  async getPreferredNetwork(slotId) {
94    const res = await getPreferredNetwork(this.slotId);
95    if (res == 0) {
96      this.byValueWLMS = $r('app.string.mobile_data_5g');
97    } else if (res == 5) {
98      this.byValueWLMS = $r('app.string.mobile_data_4g');
99    } else if (res == 6) {
100      this.byValueWLMS = $r('app.string.mobile_data_3g');
101    } else if (res == 1) {
102      this.byValueWLMS = $r('app.string.mobile_data_2g');
103    }
104  }
105
106  /**
107   * This interface is used to obtain sim cardOne status
108   */
109  getSimStateDataCardOne() {
110    getSimStateCardOne().then((res: number) => {
111      LogUtils.i(TAG, 'getSimStateData Card1 :success ' + JSON.stringify(res))
112      const simState = {
113        SIM_STATE_UNKNOWN: 0,
114        SIM_STATE_NOT_PRESENT: 1,
115        SIM_STATE_LOCKED: 2,
116        SIM_STATE_NOT_READY: 3,
117        SIM_STATE_READY: 4,
118        SIM_STATE_LOADED: 5
119      };
120      if (res == simState.SIM_STATE_LOADED || res == simState.SIM_STATE_READY) {
121        this.simStateStatusCardOne = true;
122      } else {
123        this.simStateStatusCardOne = false;
124      }
125    }).catch((err) => {
126      this.simStateStatusCardOne = false;
127      LogUtils.i(TAG, 'getSimStateData Card1 :console.error() ' + JSON.stringify(err.message));
128    });
129  }
130
131  /**
132   * This interface is used to obtain sim cardTwo status
133   */
134  getSimStateDataCardTwo() {
135    getSimStateCardTwo().then((res: number) => {
136      LogUtils.i(TAG, 'getSimState Card2 :success then' + JSON.stringify(res));
137      const simState = {
138        SIM_STATE_UNKNOWN: 0,
139        SIM_STATE_NOT_PRESENT: 1,
140        SIM_STATE_LOCKED: 2,
141        SIM_STATE_NOT_READY: 3,
142        SIM_STATE_READY: 4,
143        SIM_STATE_LOADED: 5
144      };
145      if (res == simState.SIM_STATE_LOADED || res == simState.SIM_STATE_READY) {
146        this.simStateStatusCardTwo = true;
147      } else {
148        this.simStateStatusCardTwo = false;
149      }
150    }).catch((err) => {
151      this.simStateStatusCardTwo = false;
152      LogUtils.i(TAG, 'getSimState Card2 :console.error() ' + JSON.stringify(err.message));
153    });
154  }
155
156  getSupportNetwork(slotId) {
157    getSupportNetwork(slotId).then((res) => {
158      if (res) {
159        this.isSupport = true;
160      } else {
161        this.isSupport = false;
162      }
163    }).catch((err) => {
164    });
165  }
166
167  /**
168   * Get mobile phone number
169   */
170  getSimCardOnePhoneNumber() {
171    getSimCardOnePhoneNumber().then((res) => {
172      LogUtils.i(TAG, 'getSimTelephoneNumber card1 other success' + JSON.stringify(res));
173      this.mTelephoneNumber = res;
174    }).catch((err) => {
175      LogUtils.i(TAG, 'getSimTelephoneNumber card1 other catch' + JSON.stringify(err));
176    });
177  }
178
179  /**
180   * Get mobile phone number
181   */
182  getSimCardTwoPhoneNumber() {
183    getSimCardTwoPhoneNumber().then((res) => {
184      LogUtils.i(TAG, 'getSimTelephoneNumber card2 other success' + JSON.stringify(res));
185      this.mTelephoneNumber2 = res;
186    }).catch((err) => {
187      LogUtils.i(TAG, 'getSimTelephoneNumber card2 other catch' + JSON.stringify(err));
188    });
189  }
190
191  /**
192   * Get mobile data on or off
193   */
194  getCellularDataState() {
195    isCellularDataEnabled().then((data) => {
196      LogUtils.i(TAG, 'isCellularDataEnabled success: isON:' + JSON.stringify(data));
197      this.isDataEnable = data;
198    }).catch((error) => {
199      LogUtils.i(TAG, 'isCellularDataEnabled error catch' + JSON.stringify(error));
200    });
201  }
202
203  // init AirPlane Mode
204  initAirPlaneMode() {
205    LogUtils.i(TAG, 'initAirPlaneMode');
206    try {
207      addAirPlaneModeListener((data) => {
208        LogUtils.i(TAG, 'initAirPlaneMode callback');
209        this.isAirPlaneMode = data == 1 ? true : false;
210      });
211    } catch (err) {
212      LogUtils.e(TAG, `initAirPlaneMode err = ${JSON.stringify(err)}`);
213    }
214  }
215
216  // query AirPlane Mode
217  getAirPlaneMode() {
218    LogUtils.i(TAG, 'getAirPlaneMode');
219    try {
220      queryAirPlaneMode((data) => {
221        LogUtils.i(TAG, 'getAirPlaneMode callback');
222        this.isAirPlaneMode = data == 1 ? true : false;
223      });
224    } catch (err) {
225      LogUtils.e(TAG, `getAirPlaneMode err = ${JSON.stringify(err)}`);
226    }
227  }
228
229  addRegisterSimStateChange(slotId) {
230    registerSimStateChange(slotId, async () => {
231      this.getCellularDataRoamingEnabled();
232      this.getSimStateDataCardOne();
233      this.getSimStateDataCardTwo();
234      this.getPreferredNetwork(slotId);
235      this.getSupportNetwork(slotId);
236      this.getSimCardOnePhoneNumber();
237      this.getSimCardTwoPhoneNumber();
238      this.getCellularDataState();
239      this.isImsSwitchEnabled(0);
240      if (getMaxSimCount() === 2) {
241        this.isImsSwitchEnabled(1);
242      }
243    })
244  }
245
246  isImsSwitchEnabled(slotId) {
247    call.isImsSwitchEnabled(slotId).then((res: boolean) => {
248      if (slotId) {
249        this.enableISM2 = res;
250        LogUtils.i(TAG, 'isImsSwitchEnable enable 1:' + JSON.stringify(this.enableISM2));
251      } else {
252        this.enableISM = res;
253        LogUtils.i(TAG, 'isImsSwitchEnable enable 0:' + JSON.stringify(this.enableISM));
254      }
255    }).catch((err) => {
256      if (slotId) {
257        this.enableISM2 = true;
258        LogUtils.i(TAG, 'isImsSwitchEnable err 1:' + JSON.stringify(this.enableISM2));
259      } else {
260        this.enableISM = true;
261        LogUtils.i(TAG, 'isImsSwitchEnable err 0:' + JSON.stringify(this.enableISM));
262      }
263      LogUtils.i(TAG, 'isImsSwitchEnabled card catch:' + JSON.stringify(err));
264    });
265  }
266
267  aboutToAppear() {
268    LogUtils.i(TAG, 'aboutToAppear')
269    this.initAirPlaneMode();
270    if (getMaxSimCount() === 2) {
271      this.addRegisterSimStateChange(1);
272      this.isImsSwitchEnabled(1);
273      this.getSimStateDataCardTwo();
274    }
275    this.addRegisterSimStateChange(0);
276    //Get data roaming status
277    this.getCellularDataRoamingEnabled();
278    //Get HD call status
279    this.isImsSwitchEnabled(0);
280    this.getSimStateDataCardOne();
281    //Get network mode
282    this.getPreferredNetwork(this.slotId);
283    getOperatorName().then((res) => {
284    })
285    this.getSupportNetwork(this.slotId);
286    //card number acquire
287    this.getSimCardOnePhoneNumber();
288    this.getSimCardTwoPhoneNumber();
289    this.getCellularDataState();
290  }
291
292  onPageShow() {
293    this.isImsSwitchEnabled(0);
294    this.getAirPlaneMode();
295  }
296
297  onPageHide() {
298    removeAirPlaneModeListener();
299  }
300
301  /**
302   * Set network mode
303   */
304  radioChange(slotId, v) {
305    const res = setPreferredNetwork(slotId, v);
306    LogUtils.i(TAG, 'radioChange res:' + JSON.stringify(res));
307  }
308
309  getCellularDataRoamingEnabled() {
310    isCellularDataRoamingEnabledCardOne().then((res) => {
311      LogUtils.i(TAG, 'getCellularDataRoamingEnabled card one success then:' + JSON.stringify(res));
312      this.dataRoamSwitchCardOne = res;
313    }).catch((err) => {
314      this.dataRoamSwitchCardOne = false;
315      LogUtils.i(TAG, 'enableCellularDataRoaming card one catch:' + JSON.stringify(err));
316    });
317    if (getMaxSimCount() === 2) {
318      isCellularDataRoamingEnabledCardTwo().then((res) => {
319        LogUtils.i(TAG, 'getCellularDataRoamingEnabled card two success then:' + JSON.stringify(res));
320        this.dataRoamSwitchCardTwo = res;
321      }).catch((err) => {
322        this.dataRoamSwitchCardTwo = false;
323        LogUtils.i(TAG, 'enableCellularDataRoaming card two catch:' + JSON.stringify(err));
324      });
325    }
326  }
327
328  clickHandle(click: number) {
329    switch (click) {
330      case 0:
331        router.pushUrl({
332          url: 'pages/networkStand'
333        })
334        break
335      case 1:
336        router.pushUrl({
337          url: 'pages/apnList'
338        })
339        break
340    }
341  }
342
343  build() {
344    GridRow({ columns: { sm: 4, md: 8, lg: 12 }, gutter: { x: 12 } }) {
345      GridCol({ span: { sm: 4, md: 8, lg: 8 }, offset: { sm: 0, md: 1, lg: 2 } }) {
346        Column() {
347          Column() {
348
349            HeadComponent({ isTouch: true, title: this.childComponentTitle });
350
351            Stack({ alignContent: Alignment.TopStart }) {
352              Scroll(this.scroller) {
353                Column() {
354                  SubHeader({ titleContent: $r('app.string.mobile_data_general'), subTitleContent: '' });
355
356                  Flex({
357                    direction: FlexDirection.Row,
358                    justifyContent: FlexAlign.SpaceBetween,
359                    alignItems: ItemAlign.Center
360                  }) {
361                    Column() {
362                      Row() {
363                        Text($r('app.string.mobile_data'))
364                          .fontSize(16)
365                          .fontWeight(FontWeight.Medium)
366                          .fontFamily('HarmonyHeiTi')
367                          .lineHeight(22)
368                          .fontColor($r('app.color.font_color_182431'))
369                      }
370
371                      Row() {
372                        Text($r('app.string.mobile_data_charges'))
373                          .fontSize(14)
374                          .fontWeight(FontWeight.Regular)
375                          .fontFamily('HarmonyHeiTi')
376                          .fontColor('#555')
377                          .opacity(0.6)
378                          .lineHeight(19)
379                          .maxLines(2)
380                      }
381                      .margin({ top: 2, right: 26 })
382                    }
383                    .alignItems(HorizontalAlign.Start)
384
385                    Toggle({ type: ToggleType.Switch, isOn: this.isDataEnable })
386                      .width(36)
387                      .height(20)
388                      .enabled((this.simStateStatusCardOne || this.simStateStatusCardTwo) && !this.isAirPlaneMode)
389                      .onChange((isOn: boolean) => {
390                        this.isDataEnable = !this.isDataEnable;
391                        LogUtils.i(TAG, 'mobile data switch changes enable:' + JSON.stringify(this.isDataEnable));
392                        if (this.isDataEnable == false) {
393                          disableCellularData().then((data) => {
394                            LogUtils.i(TAG, 'disableCellularData: success then' + JSON.stringify(data));
395                          }).catch((error) => {
396                            LogUtils.i(TAG, 'disableCellularData: error catch' + JSON.stringify(error));
397                          });
398                        } else {
399                          enableCellularData().then((data) => {
400                            LogUtils.i(TAG, 'enableCellularData: success then' + JSON.stringify(data));
401                          }).catch((error) => {
402                            LogUtils.i(TAG, 'enableCellularData: error catch' + JSON.stringify(error));
403                          });
404                        }
405                      })
406                  }
407                  .padding({
408                    left: 12,
409                    right: 12,
410                    top: 4,
411                    bottom: 4
412                  })
413                  .height(90)
414                  .width('100%')
415                  .borderRadius(16)
416                  .backgroundColor($r('sys.color.ohos_id_color_foreground_contrary'))
417                  .opacity((this.simStateStatusCardOne || this.simStateStatusCardTwo) && !this.isAirPlaneMode ? 1 : 0.4)
418
419                  SubHeader({
420                    titleContent: $r('app.string.mobile_data_card1'),
421                    subTitleContent: this.mTelephoneNumber
422                  });
423
424                  Column() {
425                    item({
426                      isBtn: this.moisBtn,
427                      cardType: this.cardOne,
428                      controlSwitch: $dataRoamSwitchCardOne,
429                      title: $r('app.string.mobile_data_dataRoaming'),
430                      describe: $r('app.string.mobile_data_enableDataWhileRoaming'),
431                      isDisabled: this.simStateStatusCardOne && !this.isAirPlaneMode,
432                      isCard: true,
433                      isSupport: false,
434                      isCon: 0,
435                    })
436
437                    Divider()
438                      .strokeWidth(0.5)
439                      .color('#E3E3E3')
440                      .lineCap(LineCapStyle.Round)
441                      .margin({ right: '2%' })
442
443                    item({
444                      isBtn: this.gqBtn,
445                      cardType: this.cardOne,
446                      controlSwitch: $enableISM,
447                      title: $r('app.string.mobile_data_volte'),
448                      describe: $r('app.string.mobile_data_confirmation_function'),
449                      isDisabled: this.simStateStatusCardOne && !this.isAirPlaneMode,
450                      isSupport: false,
451                      isCard: true,
452                      isCon: 22,
453                    })
454
455
456                    Divider()
457                      .strokeWidth(0.5)
458                      .color('#E3E3E3')
459                      .lineCap(LineCapStyle.Round)
460                      .margin({ right: '2%' })
461
462                    Flex({ justifyContent: FlexAlign.SpaceBetween, alignItems: ItemAlign.Center }) {
463                      Column() {
464                        Text($r('app.string.network_standard'))
465                          .fontFamily('HarmonyHeiTi')
466                          .fontSize($r('sys.float.ohos_id_text_size_body1'))
467                          .fontWeight(FontWeight.Medium)
468                          .fontColor($r('sys.color.ohos_id_color_text_primary'))
469                          .opacity((this.simStateStatusCardOne && !this.isAirPlaneMode) ? 0.9 : 0.6)
470                          .letterSpacing(1)
471                          .lineHeight(22)
472                          .textAlign(TextAlign.Start)
473                        Text($r('app.string.network_standard_select'))
474                          .margin({ top: 2 })
475                          .fontFamily('HarmonyHeiTi')
476                          .fontWeight(FontWeight.Regular)
477                          .fontSize($r('sys.float.ohos_id_text_size_body2'))
478                          .fontColor($r('sys.color.ohos_id_color_text_secondary'))
479                          .opacity(0.6)
480                          .lineHeight(19)
481                          .letterSpacing(1)
482                      }
483                      .width('100%')
484                      .alignItems(HorizontalAlign.Start)
485                      .margin({ right: 26 })
486
487                      Image($r('app.media.next_icon'))
488                        .width(10)
489                        .height(15)
490                        .margin({ right: 10 })
491                        .enabled(this.simStateStatusCardOne && !this.isAirPlaneMode)
492
493                    }.backgroundColor($r('sys.color.ohos_id_color_foreground_contrary'))
494                    .opacity((this.simStateStatusCardOne && !this.isAirPlaneMode) ? 1 : 0.4)
495                    .margin({ top: 8, bottom: this.isSupport ? 5 : 11 })
496                    .onClick(() => {
497                      if (this.simStateStatusCardOne && !this.isAirPlaneMode) {
498                        this.clickHandle(0)
499                      }
500                    })
501                    Divider()
502                      .strokeWidth(0.5)
503                      .color('#E3E3E3')
504                      .lineCap(LineCapStyle.Round)
505                      .margin({ right: '2%' })
506
507                    Flex({ justifyContent: FlexAlign.SpaceBetween, alignItems: ItemAlign.Center }) {
508                      Column() {
509                        Text($r('app.string.access_point_name'))
510                          .fontFamily('HarmonyHeiTi')
511                          .fontSize($r('sys.float.ohos_id_text_size_body1'))
512                          .fontWeight(FontWeight.Medium)
513                          .fontColor($r('sys.color.ohos_id_color_text_primary'))
514                          .opacity((this.simStateStatusCardOne && !this.isAirPlaneMode) ? 0.9 : 0.6)
515                          .letterSpacing(1)
516                          .lineHeight(22)
517                          .textAlign(TextAlign.Start)
518                        Text($r('app.string.apn_stttings'))
519                          .margin({ top: 2 })
520                          .fontFamily('HarmonyHeiTi')
521                          .fontWeight(FontWeight.Regular)
522                          .fontSize($r('sys.float.ohos_id_text_size_body2'))
523                          .fontColor($r('sys.color.ohos_id_color_text_secondary'))
524                          .opacity(0.6)
525                          .lineHeight(19)
526                          .letterSpacing(1)
527                      }.justifyContent(FlexAlign.Center)
528                      .width('100%')
529                      .alignItems(HorizontalAlign.Start)
530                      .margin({ right: 26 })
531
532                      Image($r('app.media.next_icon'))
533                        .width(10)
534                        .height(15)
535                        .margin({ right: 10 })
536                        .enabled(this.simStateStatusCardOne && !this.isAirPlaneMode)
537
538                    }.backgroundColor($r('sys.color.ohos_id_color_foreground_contrary'))
539                    .opacity((this.simStateStatusCardOne && !this.isAirPlaneMode) ? 1 : 0.4)
540                    .margin({ top: 8, bottom: this.isSupport ? 5 : 11 })
541                    .onClick(() => {
542                      if ((this.simStateStatusCardOne && !this.isAirPlaneMode)) {
543                        this.clickHandle(1)
544                      }
545                    })
546                  }
547                  .padding({
548                    left: 12,
549                    right: 12,
550                    top: 4,
551                    bottom: 4
552                  })
553                  .width('100%')
554                  .borderRadius(16)
555                  .backgroundColor($r('sys.color.ohos_id_color_foreground_contrary'))
556                  .opacity(this.simStateStatusCardOne && !this.isAirPlaneMode ? 1 : 0.4)
557
558                  SubHeader({
559                    titleContent: $r('app.string.mobile_data_card2'),
560                    subTitleContent: this.mTelephoneNumber2
561                  })
562                  .visibility(getMaxSimCount() === 2 ? Visibility.Visible : Visibility.Hidden)
563
564                  Column() {
565                    item({
566                      isBtn: this.moisBtn,
567                      cardType: this.cardTwo,
568                      controlSwitch: $mobileDataDisabled2,
569                      title: $r('app.string.mobile_data_dataRoaming'),
570                      describe: $r('app.string.mobile_data_enableDataWhileRoaming'),
571                      isDisabled: this.simStateStatusCardTwo && !this.isAirPlaneMode,
572                      isSupport: false,
573                      isCard: true,
574                      isCon: 0,
575                    })
576                    Divider()
577                      .strokeWidth(0.5)
578                      .color('#E3E3E3')
579                      .lineCap(LineCapStyle.Round)
580                      .margin({ right: '2%' })
581                    item({
582                      isBtn: this.gqBtn,
583                      cardType: this.cardTwo,
584                      controlSwitch: $enableISM2,
585                      title: $r('app.string.mobile_data_volte'),
586                      describe: $r('app.string.mobile_data_confirmation_function'),
587                      isDisabled: this.simStateStatusCardTwo && !this.isAirPlaneMode,
588                      isSupport: false,
589                      isCard: true,
590                      isCon: 22,
591                    })
592                  }
593                  .padding({
594                    left: 12,
595                    right: 12,
596                    top: 4,
597                    bottom: 4
598                  })
599                  .padding({
600                    left: 12,
601                    right: 12,
602                    top: 4,
603                    bottom: 4
604                  })
605                  .width('100%')
606                  .borderRadius(16)
607                  .backgroundColor($r('sys.color.ohos_id_color_foreground_contrary'))
608                  .opacity(this.simStateStatusCardTwo && !this.isAirPlaneMode ? 1 : 0.4)
609                  .visibility(getMaxSimCount() === 2 ? Visibility.Visible : Visibility.Hidden)
610                }
611                .alignItems(HorizontalAlign.Start)
612              }
613            }
614          }
615          .useSizeType({
616            sm: { span: 4, offset: 0 },
617            md: { span: 6, offset: 1 },
618            lg: { span: 8, offset: 2 }
619          })
620        }
621        .visibility(this.isLoading ? Visibility.Visible : Visibility.Hidden)
622      }
623    }
624    .padding({ left: 12, right: 12 })
625    .width('100%')
626    .height('100%')
627    .backgroundColor($r('sys.color.ohos_id_color_sub_background'))
628  }
629}