Completed
Push — master ( 96a5d6...44e1f1 )
by Kamil
22s
created

iShouldSeeThatTheyHavePlacedOrdersAcrossAllChannels()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
1
<?php
2
3
/*
4
 * This file is part of the Sylius package.
5
 *
6
 * (c) Paweł Jędrzejewski
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Sylius\Behat\Context\Ui\Admin;
13
14
use Behat\Behat\Context\Context;
15
use Sylius\Behat\Page\Admin\Crud\IndexPageInterface;
16
use Sylius\Behat\Page\Admin\Customer\CreatePageInterface;
17
use Sylius\Behat\Page\Admin\Customer\ShowPageInterface;
18
use Sylius\Behat\Page\Admin\Customer\UpdatePageInterface;
19
use Sylius\Behat\Service\Resolver\CurrentPageResolverInterface;
20
use Sylius\Component\Core\Model\CustomerInterface;
21
use Webmozart\Assert\Assert;
22
23
/**
24
 * @author Anna Walasek <[email protected]>
25
 */
26
final class ManagingCustomersContext implements Context
27
{
28
    /**
29
     * @var IndexPageInterface
30
     */
31
    private $indexPage;
32
33
    /**
34
     * @var CreatePageInterface
35
     */
36
    private $createPage;
37
38
    /**
39
     * @var UpdatePageInterface
40
     */
41
    private $updatePage;
42
43
    /**
44
     * @var ShowPageInterface
45
     */
46
    private $showPage;
47
48
    /**
49
     * @var IndexPageInterface
50
     */
51
    private $ordersIndexPage;
52
53
    /**
54
     * @var CurrentPageResolverInterface
55
     */
56
    private $currentPageResolver;
57
58
    /**
59
     * @param CreatePageInterface $createPage
60
     * @param IndexPageInterface $indexPage
61
     * @param UpdatePageInterface $updatePage
62
     * @param ShowPageInterface $showPage
63
     * @param IndexPageInterface $ordersIndexPage
64
     * @param CurrentPageResolverInterface $currentPageResolver
65
     */
66
    public function __construct(
67
        CreatePageInterface $createPage,
68
        IndexPageInterface $indexPage,
69
        UpdatePageInterface $updatePage,
70
        ShowPageInterface $showPage,
71
        IndexPageInterface $ordersIndexPage,
72
        CurrentPageResolverInterface $currentPageResolver
73
    ) {
74
        $this->createPage = $createPage;
75
        $this->indexPage = $indexPage;
76
        $this->updatePage = $updatePage;
77
        $this->showPage = $showPage;
78
        $this->ordersIndexPage = $ordersIndexPage;
79
        $this->currentPageResolver = $currentPageResolver;
80
    }
81
82
    /**
83
     * @Given I want to create a new customer
84
     * @Given I want to create a new customer account
85
     */
86
    public function iWantToCreateANewCustomer()
87
    {
88
        $this->createPage->open();
89
    }
90
91
    /**
92
     * @When /^I specify (?:their|his) first name as "([^"]*)"$/
93
     */
94
    public function iSpecifyItsFirstNameAs($name)
95
    {
96
        $this->createPage->specifyFirstName($name);
97
    }
98
99
    /**
100
     * @When /^I specify (?:their|his) last name as "([^"]*)"$/
101
     */
102
    public function iSpecifyItsLastNameAs($name)
103
    {
104
        $this->createPage->specifyLastName($name);
105
    }
106
107
    /**
108
     * @When I specify their email as :name
109
     * @When I do not specify their email
110
     */
111
    public function iSpecifyItsEmailAs($email = null)
112
    {
113
        $this->createPage->specifyEmail($email);
114
    }
115
116
    /**
117
     * @When I add them
118
     * @When I try to add them
119
     */
120
    public function iAddIt()
121
    {
122
        $this->createPage->create();
123
    }
124
125
    /**
126
     * @Then the customer :customer should appear in the store
127
     * @Then the customer :customer should still have this email
128
     */
129
    public function theCustomerShould(CustomerInterface $customer)
130
    {
131
        $this->indexPage->open();
132
133
        Assert::true($this->indexPage->isSingleResourceOnPage(['email' => $customer->getEmail()]));
134
    }
135
136
    /**
137
     * @When I select :gender as its gender
138
     */
139
    public function iSelectGender($gender)
140
    {
141
        $this->createPage->chooseGender($gender);
142
    }
143
144
    /**
145
     * @When I select :group as their group
146
     */
147
    public function iSelectGroup($group)
148
    {
149
        $this->createPage->chooseGroup($group);
150
    }
151
152
    /**
153
     * @When I specify its birthday as :birthday
154
     */
155
    public function iSpecifyItsBirthdayAs($birthday)
156
    {
157
        $this->createPage->specifyBirthday($birthday);
158
    }
159
160
    /**
161
     * @Given /^I want to edit (this customer)$/
162
     */
163
    public function iWantToEditThisCustomer(CustomerInterface $customer)
164
    {
165
        $this->updatePage->open(['id' => $customer->getId()]);
166
    }
167
168
    /**
169
     * @When I save my changes
170
     * @When I try to save my changes
171
     */
172
    public function iSaveMyChanges()
173
    {
174
        $this->updatePage->saveChanges();
175
    }
176
177
    /**
178
     * @Then /^(this customer) with name "([^"]*)" should appear in the store$/
179
     */
180
    public function theCustomerWithNameShouldAppearInTheRegistry(CustomerInterface $customer, $name)
181
    {
182
        $this->updatePage->open(['id' => $customer->getId()]);
183
184
        Assert::same($this->updatePage->getFullName(), $name);
185
    }
186
187
    /**
188
     * @When I want to see all customers in store
189
     */
190
    public function iWantToSeeAllCustomersInStore()
191
    {
192
        $this->indexPage->open();
193
    }
194
195
    /**
196
     * @Then /^I should see (\d+) customers in the list$/
197
     */
198
    public function iShouldSeeCustomersInTheList($amountOfCustomers)
199
    {
200
        Assert::same($this->indexPage->countItems(), (int) $amountOfCustomers);
201
    }
202
203
    /**
204
     * @Then I should see the customer :email in the list
205
     */
206
    public function iShouldSeeTheCustomerInTheList($email)
207
    {
208
        Assert::true($this->indexPage->isSingleResourceOnPage(['email' => $email]));
209
    }
210
211
    /**
212
     * @Then /^I should be notified that ([^"]+) is required$/
213
     */
214
    public function iShouldBeNotifiedThatFirstNameIsRequired($elementName)
215
    {
216
        Assert::same(
217
            $this->createPage->getValidationMessage($elementName),
218
            sprintf('Please enter your %s.', $elementName)
219
        );
220
    }
221
222
    /**
223
     * @Then /^I should be notified that ([^"]+) should be ([^"]+)$/
224
     */
225
    public function iShouldBeNotifiedThatTheElementShouldBe($elementName, $validationMessage)
226
    {
227
        Assert::same(
228
            $this->updatePage->getValidationMessage($elementName),
229
            sprintf('%s must be %s.', ucfirst($elementName), $validationMessage)
230
        );
231
    }
232
233
    /**
234
     * @Then the customer with email :email should not appear in the store
235
     */
236
    public function theCustomerShouldNotAppearInTheStore($email)
237
    {
238
        $this->indexPage->open();
239
240
        Assert::false($this->indexPage->isSingleResourceOnPage(['email' => $email]));
241
    }
242
243
    /**
244
     * @When I remove its first name
245
     */
246
    public function iRemoveItsFirstName()
247
    {
248
        $this->updatePage->changeFirstName('');
249
    }
250
251
    /**
252
     * @Then /^(this customer) should have an empty first name$/
253
     * @Then the customer :customer should still have an empty first name
254
     */
255
    public function theCustomerShouldStillHaveAnEmptyFirstName(CustomerInterface $customer)
256
    {
257
        $this->updatePage->open(['id' => $customer->getId()]);
258
259
        Assert::eq($this->updatePage->getFirstName(), '');
260
    }
261
262
    /**
263
     * @When I remove its last name
264
     */
265
    public function iRemoveItsLastName()
266
    {
267
        $this->updatePage->changeLastName('');
268
    }
269
270
    /**
271
     * @Then /^(this customer) should have an empty last name$/
272
     * @Then the customer :customer should still have an empty last name
273
     */
274
    public function theCustomerShouldStillHaveAnEmptyLastName(CustomerInterface $customer)
275
    {
276
        $this->updatePage->open(['id' => $customer->getId()]);
277
278
        Assert::eq($this->updatePage->getLastName(), '');
279
    }
280
281
    /**
282
     * @When I remove its email
283
     */
284
    public function iRemoveItsEmail()
285
    {
286
        $this->updatePage->changeEmail('');
287
    }
288
289
    /**
290
     * @Then I should be notified that email is not valid
291
     */
292
    public function iShouldBeNotifiedThatEmailIsNotValid()
293
    {
294
        Assert::same($this->createPage->getValidationMessage('email'), 'This email is invalid.');
295
    }
296
297
    /**
298
     * @Then I should be notified that email must be unique
299
     */
300
    public function iShouldBeNotifiedThatEmailMustBeUnique()
301
    {
302
        Assert::same($this->createPage->getValidationMessage('email'), 'This email is already used.');
303
    }
304
305
    /**
306
     * @Then there should still be only one customer with email :email
307
     */
308
    public function thereShouldStillBeOnlyOneCustomerWithEmail($email)
309
    {
310
        $this->indexPage->open();
311
312
        Assert::true($this->indexPage->isSingleResourceOnPage(['email' => $email]));
313
    }
314
315
    /**
316
     * @Given I want to enable :customer
317
     * @Given I want to disable :customer
318
     */
319
    public function iWantToChangeStatusOf(CustomerInterface $customer)
320
    {
321
        $this->updatePage->open(['id' => $customer->getId()]);
322
    }
323
324
    /**
325
     * @When I enable their account
326
     */
327
    public function iEnableIt()
328
    {
329
        $this->updatePage->enable();
330
    }
331
332
    /**
333
     * @When I disable their account
334
     */
335
    public function iDisableIt()
336
    {
337
        $this->updatePage->disable();
338
    }
339
340
    /**
341
     * @Then /^(this customer) should be enabled$/
342
     */
343
    public function thisCustomerShouldBeEnabled(CustomerInterface $customer)
344
    {
345
        $this->indexPage->open();
346
347
        Assert::eq($this->indexPage->getCustomerAccountStatus($customer), 'Enabled');
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Sylius\Behat\Page\Admin\Crud\IndexPageInterface as the method getCustomerAccountStatus() does only exist in the following implementations of said interface: Sylius\Behat\Page\Admin\Customer\IndexPage.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
348
    }
349
350
    /**
351
     * @Then /^(this customer) should be disabled$/
352
     */
353
    public function thisCustomerShouldBeDisabled(CustomerInterface $customer)
354
    {
355
        $this->indexPage->open();
356
357
        Assert::eq($this->indexPage->getCustomerAccountStatus($customer), 'Disabled');
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Sylius\Behat\Page\Admin\Crud\IndexPageInterface as the method getCustomerAccountStatus() does only exist in the following implementations of said interface: Sylius\Behat\Page\Admin\Customer\IndexPage.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
358
    }
359
360
    /**
361
     * @When I specify their password as :password
362
     */
363
    public function iSpecifyItsPasswordAs($password)
364
    {
365
        $this->createPage->specifyPassword($password);
366
    }
367
368
    /**
369
     * @When I choose create account option
370
     */
371
    public function iChooseCreateAccountOption()
372
    {
373
        $this->createPage->selectCreateAccount();
374
    }
375
376
    /**
377
     * @When I browse orders of a customer :customer
378
     */
379
    public function iBrowseOrdersOfACustomer(CustomerInterface $customer)
380
    {
381
        $this->ordersIndexPage->open(['id' => $customer->getId()]);
382
    }
383
384
    /**
385
     * @Then the customer :customer should have an account created
386
     * @Then /^(this customer) should have an account created$/
387
     */
388
    public function theyShouldHaveAnAccountCreated(CustomerInterface $customer)
389
    {
390
        Assert::notNull(
391
            $customer->getUser()->getPassword(),
392
            'Customer should have an account, but they do not.'
393
        );
394
    }
395
396
    /**
397
     * @When I view details of the customer :customer
398
     * @When /^I view (their) details$/
399
     */
400
    public function iViewDetailsOfTheCustomer(CustomerInterface $customer)
401
    {
402
        $this->showPage->open(['id' => $customer->getId()]);
403
    }
404
405
    /**
406
     * @Then his name should be :name
407
     */
408
    public function hisNameShouldBe($name)
409
    {
410
        Assert::same($this->showPage->getCustomerName(), $name);
411
    }
412
413
    /**
414
     * @Then he should be registered since :registrationDate
415
     */
416
    public function hisRegistrationDateShouldBe($registrationDate)
417
    {
418
        Assert::eq($this->showPage->getRegistrationDate(), new \DateTime($registrationDate));
419
    }
420
421
    /**
422
     * @Then his email should be :email
423
     */
424
    public function hisEmailShouldBe($email)
425
    {
426
        Assert::same($this->showPage->getCustomerEmail(), $email);
427
    }
428
429
    /**
430
     * @Then his phone number should be :phoneNumber
431
     */
432
    public function hisPhoneNumberShouldBe($phoneNumber)
433
    {
434
        Assert::same($this->showPage->getCustomerPhoneNumber(), $phoneNumber);
435
    }
436
437
    /**
438
     * @Then his default address should be :defaultAddress
439
     */
440
    public function hisShippingAddressShouldBe($defaultAddress)
441
    {
442
        Assert::same($this->showPage->getDefaultAddress(), str_replace(',', '', $defaultAddress));
443
    }
444
445
    /**
446
     * @Then I should see information about no existing account for this customer
447
     */
448
    public function iShouldSeeInformationAboutNoExistingAccountForThisCustomer()
449
    {
450
        Assert::true($this->showPage->hasAccount());
451
    }
452
453
    /**
454
     * @Then I should see that this customer is subscribed to the newsletter
455
     */
456
    public function iShouldSeeThatThisCustomerIsSubscribedToTheNewsletter()
457
    {
458
        Assert::true($this->showPage->isSubscribedToNewsletter());
459
    }
460
461
    /**
462
     * @Then I should not see information about email verification
463
     */
464
    public function iShouldSeeInformationAboutEmailVerification()
465
    {
466
        Assert::true($this->showPage->hasEmailVerificationInformation());
467
    }
468
469
    /**
470
     * @When I make them subscribed to the newsletter
471
     */
472
    public function iMakeThemSubscribedToTheNewsletter()
473
    {
474
        $this->updatePage->subscribeToTheNewsletter();
475
    }
476
477
    /**
478
     * @When I change the password of user :customer to :newPassword
479
     */
480
    public function iChangeThePasswordOfUserTo(CustomerInterface $customer, $newPassword)
481
    {
482
        $this->updatePage->open(['id' => $customer->getId()]);
483
        $this->updatePage->changePassword($newPassword);
484
        $this->updatePage->saveChanges();
485
    }
486
487
    /**
488
     * @Then this customer should be subscribed to the newsletter
489
     */
490
    public function thisCustomerShouldBeSubscribedToTheNewsletter()
491
    {
492
        Assert::true($this->updatePage->isSubscribedToTheNewsletter());
493
    }
494
495
    /**
496
     * @Then the province in the default address should be :provinceName
497
     */
498
    public function theProvinceInTheDefaultAddressShouldBe($provinceName)
499
    {
500
        Assert::true($this->showPage->hasDefaultAddressProvinceName($provinceName));
501
    }
502
503
    /**
504
     * @Then this customer should have :groupName as their group
505
     */
506
    public function thisCustomerShouldHaveAsTheirGroup($groupName)
507
    {
508
        /** @var UpdatePageInterface|ShowPageInterface $currentPage */
509
        $currentPage = $this->currentPageResolver->getCurrentPageWithForm([$this->updatePage, $this->showPage]);
0 ignored issues
show
Documentation introduced by
array($this->updatePage, $this->showPage) is of type array<integer,object<Syl...\\ShowPageInterface>"}>, but the function expects a array<integer,object<Syl...\SymfonyPageInterface>>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
510
511
        Assert::same($currentPage->getGroupName(), $groupName);
512
    }
513
514
    /**
515
     * @Then I should see that this customer has verified the email
516
     */
517
    public function iShouldSeeThatThisCustomerHasVerifiedTheEmail()
518
    {
519
        Assert::true($this->showPage->hasVerifiedEmail());
520
    }
521
522
    /**
523
     * @Then I should see a single order in the list
524
     */
525
    public function iShouldSeeASingleOrderInTheList()
526
    {
527
        Assert::same($this->ordersIndexPage->countItems(), 1);
528
    }
529
530
    /**
531
     * @Then I should see the order with number :orderNumber in the list
532
     */
533
    public function iShouldSeeASingleOrderFromCustomer($orderNumber)
534
    {
535
        Assert::true($this->indexPage->isSingleResourceOnPage(['number' => $orderNumber]));
536
    }
537
538
    /**
539
     * @Then I should not see the order with number :orderNumber in the list
540
     */
541
    public function iShouldNotSeeASingleOrderFromCustomer($orderNumber)
542
    {
543
        Assert::false($this->indexPage->isSingleResourceOnPage(['number' => $orderNumber]));
544
    }
545
546
    /**
547
     * @When I do not specify any information
548
     */
549
    public function iDoNotSpecifyAnyInformation()
550
    {
551
        // Intentionally left blank.
552
    }
553
554
    /**
555
     * @Then I should not be able to specify their password
556
     */
557
    public function iShouldNotBeAbleToSpecifyItPassword()
558
    {
559
        Assert::true($this->createPage->isUserFormHidden());
560
    }
561
562
    /**
563
     * @Then I should still be on the customer creation page
564
     */
565
    public function iShouldBeOnTheCustomerCreationPage()
566
    {
567
        Assert::true($this->createPage->isOpen());
568
    }
569
570
    /**
571
     * @Then I should be able to select create account option
572
     */
573
    public function iShouldBeAbleToSelectCreateAccountOption()
574
    {
575
        Assert::false($this->createPage->hasCheckedCreateOption());
576
    }
577
578
    /**
579
     * @Then I should be able to specify their password
580
     */
581
    public function iShouldBeAbleToSpecifyItPassword()
582
    {
583
        Assert::true($this->createPage->hasPasswordField());
584
    }
585
586
    /**
587
     * @Then I should not be able to select create account option
588
     */
589
    public function iShouldNotBeAbleToSelectCreateAccountOption()
590
    {
591
        Assert::true($this->createPage->hasCheckedCreateOption());
592
    }
593
594
    /**
595
     * @When I do not choose create account option
596
     */
597
    public function iDoNotChooseCreateAccountOption()
598
    {
599
        // Intentionally left blank.
600
    }
601
602
    /**
603
     * @Then I should not see create account option
604
     */
605
    public function iShouldNotSeeCreateAccountOption()
606
    {
607
        Assert::false($this->createPage->hasCreateOption());
0 ignored issues
show
Bug introduced by
The method hasCreateOption() does not exist on Sylius\Behat\Page\Admin\...mer\CreatePageInterface. Did you maybe mean create()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
608
    }
609
610
    /**
611
     * @Then /^I should be notified that the password must be at least (\d+) characters long$/
612
     */
613
    public function iShouldBeNotifiedThatThePasswordMustBeAtLeastCharactersLong($amountOfCharacters)
614
    {
615
        Assert::same(
616
            $this->createPage->getValidationMessage('password'),
617
            sprintf('Password must be at least %d characters long.', $amountOfCharacters)
618
        );
619
    }
620
621
    /**
622
     * @Then I should see the customer has not placed any orders yet
623
     */
624
    public function iShouldSeeTheCustomerHasNotYetPlacedAnyOrders()
625
    {
626
        Assert::false($this->showPage->hasCustomerPlacedAnyOrders());
627
    }
628
629
    /**
630
     * @Then /^I should see that they have placed (\d+) orders? in the "([^"]+)" channel$/
631
     */
632
    public function iShouldSeeThatTheyHavePlacedOrdersInTheChannel($ordersCount, $channelName)
633
    {
634
        Assert::same($this->showPage->getOrdersCountInChannel($channelName), (int) $ordersCount);
635
    }
636
637
    /**
638
     * @Then /^I should see that the overall total value of all their orders in the "([^"]+)" channel is "([^"]+)"$/
639
     */
640
    public function iShouldSeeThatTheOverallTotalValueOfAllTheirOrdersInTheChannelIs($channelName, $ordersValue)
641
    {
642
        Assert::same($this->showPage->getOrdersTotalInChannel($channelName), $ordersValue);
643
    }
644
645
    /**
646
     * @Then /^I should see that the average total value of their order in the "([^"]+)" channel is "([^"]+)"$/
647
     */
648
    public function iShouldSeeThatTheAverageTotalValueOfTheirOrderInTheChannelIs($channelName, $ordersValue)
649
    {
650
        Assert::same($this->showPage->getOrdersTotalInChannel($channelName), $ordersValue);
651
    }
652
}
653