Completed
Push — v2 ( b3c0e1...e198fb )
by Joschi
08:19
created

ItemTest::testItemExport()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 7
nc 2
nop 0
dl 0
loc 11
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * micrometa
5
 *
6
 * @category Jkphl
7
 * @package Jkphl\Micrometa
8
 * @subpackage Infrastructure
9
 * @author Joschi Kuphal <[email protected]> / @jkphl
10
 * @copyright Copyright © 2017 Joschi Kuphal <[email protected]> / @jkphl
11
 * @license http://opensource.org/licenses/MIT The MIT License (MIT)
12
 */
13
14
/***********************************************************************************
15
 *  The MIT License (MIT)
16
 *
17
 *  Copyright © 2017 Joschi Kuphal <[email protected]> / @jkphl
18
 *
19
 *  Permission is hereby granted, free of charge, to any person obtaining a copy of
20
 *  this software and associated documentation files (the "Software"), to deal in
21
 *  the Software without restriction, including without limitation the rights to
22
 *  use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
23
 *  the Software, and to permit persons to whom the Software is furnished to do so,
24
 *  subject to the following conditions:
25
 *
26
 *  The above copyright notice and this permission notice shall be included in all
27
 *  copies or substantial portions of the Software.
28
 *
29
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
31
 *  FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
32
 *  COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
33
 *  IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
34
 *  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35
 ***********************************************************************************/
36
37
namespace Jkphl\Micrometa\Tests\Ports;
38
39
use Jkphl\Micrometa\Application\Factory\PropertyListFactory;
40
use Jkphl\Micrometa\Application\Item\Item as ApplicationItem;
41
use Jkphl\Micrometa\Application\Value\StringValue;
42
use Jkphl\Micrometa\Infrastructure\Factory\AlternateFactory;
43
use Jkphl\Micrometa\Infrastructure\Factory\MicroformatsFactory;
44
use Jkphl\Micrometa\Infrastructure\Factory\RelFactory;
45
use Jkphl\Micrometa\Infrastructure\Parser\Microformats;
46
use Jkphl\Micrometa\Ports\Item\Item;
47
use Jkphl\Micrometa\Ports\Item\ItemInterface;
48
use Jkphl\Micrometa\Ports\Item\ItemList;
49
use Jkphl\Micrometa\Ports\Item\ItemObjectModel;
50
use Jkphl\Micrometa\Ports\Rel\Alternate;
51
use Jkphl\Micrometa\Ports\Rel\Rel;
52
53
/**
54
 * Parser factory tests
55
 *
56
 * @package Jkphl\Micrometa
57
 * @subpackage Jkphl\Micrometa\Tests
58
 */
59
class ItemTest extends \PHPUnit_Framework_TestCase
60
{
61
    /**
62
     * Test an item
63
     */
64
    public function testItemTypes()
65
    {
66
        $feedItem = $this->getFeedItem();
67
        $this->assertInstanceOf(Item::class, $feedItem);
68
69
        // Test the item type
70
        $this->assertTrue($feedItem->isOfType('h-feed'));
71
        $this->assertTrue($feedItem->isOfType('h-feed', MicroformatsFactory::MF2_PROFILE_URI));
72
        $this->assertFalse($feedItem->isOfType('invalid', MicroformatsFactory::MF2_PROFILE_URI));
73
    }
74
75
    /**
76
     * Create and return an h-feed Microformats item
77
     *
78
     * @return Item h-feed item
79
     */
80
    protected function getFeedItem()
81
    {
82
        $authorItem = new ApplicationItem(
83
            Microformats::FORMAT,
84
            new PropertyListFactory(),
85
            (object)['profile' => MicroformatsFactory::MF2_PROFILE_URI, 'name' => 'h-card'],
86
            [
87
                (object)[
88
                    'profile' => MicroformatsFactory::MF2_PROFILE_URI,
89
                    'name' => 'name',
90
                    'values' => [
91
                        new StringValue('John Doe')
92
                    ]
93
                ],
94
                (object)[
95
                    'profile' => MicroformatsFactory::MF2_PROFILE_URI,
96
                    'name' => 'email',
97
                    'values' => [
98
                        new StringValue('[email protected]')
99
                    ]
100
                ]
101
            ]
102
        );
103
104
105
        $entryItem = new ApplicationItem(
106
            Microformats::FORMAT,
107
            new PropertyListFactory(),
108
            (object)['profile' => MicroformatsFactory::MF2_PROFILE_URI, 'name' => 'h-entry'],
109
            [
110
                (object)[
111
                    'profile' => MicroformatsFactory::MF2_PROFILE_URI,
112
                    'name' => 'name',
113
                    'values' => [
114
                        new StringValue('Famous blog post')
115
                    ]
116
                ],
117
                (object)[
118
                    'profile' => MicroformatsFactory::MF2_PROFILE_URI,
119
                    'name' => 'author',
120
                    'values' => [
121
                        $authorItem
122
                    ]
123
                ]
124
            ]
125
        );
126
127
128
        $feedItem = new ApplicationItem(
129
            Microformats::FORMAT,
130
            new PropertyListFactory(),
131
            (object)['profile' => MicroformatsFactory::MF2_PROFILE_URI, 'name' => 'h-feed'],
132
            [
133
                (object)[
134
                    'profile' => MicroformatsFactory::MF2_PROFILE_URI,
135
                    'name' => 'name',
136
                    'values' => [
137
                        new StringValue('John Doe\'s Blog')
138
                    ]
139
                ],
140
                (object)[
141
                    'profile' => MicroformatsFactory::MF2_PROFILE_URI,
142
                    'name' => 'author',
143
                    'values' => [
144
                        $authorItem
145
                    ]
146
                ],
147
                (object)[
148
                    'profile' => MicroformatsFactory::MF2_PROFILE_URI,
149
                    'name' => 'custom-property',
150
                    'values' => [
151
                        new StringValue('Property for alias testing')
152
                    ]
153
                ],
154
            ],
155
            [$entryItem, $entryItem]
156
        );
157
158
        return new Item($feedItem);
159
    }
160
161
    /**
162
     * Test the item properties
163
     *
164
     * @expectedException \Jkphl\Micrometa\Ports\Exceptions\OutOfBoundsException
165
     * @expectedExceptionCode 1491672553
166
     */
167
    public function testItemProperties()
168
    {
169
        $feedItem = $this->getFeedItem();
170
        $this->assertInstanceOf(Item::class, $feedItem);
171
172
        $properties = $feedItem->getProperties();
173
        $this->assertTrue(is_array($properties));
174
        $this->assertEquals(3, count($properties));
175
176
        // Get an unknown property
177
        $feedItem->getProperty('name', null, 2);
178
    }
179
180
    /**
181
     * Test the item export
182
     */
183
    public function testItemExport()
184
    {
185
        $feedItem = $this->getFeedItem();
186
        $this->assertInstanceOf(Item::class, $feedItem);
187
188
        $export = $feedItem->toObject();
189
        $this->assertInstanceOf(\stdClass::class, $export);
190
        foreach (['format', 'types', 'properties', 'items'] as $property) {
191
            $this->assertTrue(isset($export->$property));
192
        }
193
    }
194
195
    /**
196
     * Test an unprofiled property
197
     *
198
     * @expectedException \Jkphl\Micrometa\Ports\Exceptions\OutOfBoundsException
199
     * @expectedExceptionCode 1488315604
200
     */
201
    public function testUnprofiledProperty()
202
    {
203
        $feedItem = $this->getFeedItem();
204
        $this->assertInstanceOf(Item::class, $feedItem);
205
206
        // Test the item name as an unprofiled property value list
207
        $feedNameList = $feedItem->getProperty('name');
208
        $this->assertTrue(is_array($feedNameList));
209
        $this->assertEquals(1, count($feedNameList));
210
        $this->assertTrue(is_string($feedNameList[0]));
211
        $this->assertEquals('John Doe\'s Blog', $feedNameList[0]);
212
213
        // Test the item name as an unprofiled single property value
214
        $feedName = $feedItem->getProperty('name', null, 0);
215
        $this->assertTrue(is_string($feedName));
216
        $this->assertEquals('John Doe\'s Blog', $feedName);
217
218
        // Test an invalid unprofiled property
219
        $feedItem->getProperty('invalid');
220
    }
221
222
    /**
223
     * Test a profiled property
224
     *
225
     * @expectedException \Jkphl\Micrometa\Ports\Exceptions\OutOfBoundsException
226
     * @expectedExceptionCode 1488315604
227
     */
228
    public function testProfiledProperty()
229
    {
230
        $feedItem = $this->getFeedItem();
231
        $this->assertInstanceOf(Item::class, $feedItem);
232
233
        // Test the item name as an unprofiled property value list
234
        $feedNameList = $feedItem->getProperty('name', MicroformatsFactory::MF2_PROFILE_URI);
235
        $this->assertTrue(is_array($feedNameList));
236
        $this->assertEquals(1, count($feedNameList));
237
        $this->assertTrue(is_string($feedNameList[0]));
238
        $this->assertEquals('John Doe\'s Blog', $feedNameList[0]);
239
240
        // Test the item name as an unprofiled single property value
241
        $feedName = $feedItem->getProperty('name', MicroformatsFactory::MF2_PROFILE_URI, 0);
242
        $this->assertTrue(is_string($feedName));
243
        $this->assertEquals('John Doe\'s Blog', $feedName);
244
245
        // Test an invalid unprofiled property
246
        $feedItem->getProperty('invalid', MicroformatsFactory::MF2_PROFILE_URI);
247
    }
248
249
    /**
250
     * Test an unprofiled property
251
     *
252
     * @expectedException \Jkphl\Micrometa\Ports\Exceptions\OutOfBoundsException
253
     * @expectedExceptionCode 1488315604
254
     */
255
    public function testAliasedProperty()
256
    {
257
        $feedItem = $this->getFeedItem();
258
        $this->assertInstanceOf(Item::class, $feedItem);
259
260
        // Test the custom item property as an unprofiled property value list
261
        $feedCustomPropList = $feedItem->getProperty('custom-property');
262
        $this->assertTrue(is_array($feedCustomPropList));
263
        $this->assertEquals(1, count($feedCustomPropList));
264
        $this->assertTrue(is_string($feedCustomPropList[0]));
265
        $this->assertEquals('Property for alias testing', $feedCustomPropList[0]);
266
267
        // Test the custom item property as an unprofiled single property value
268
        $feedCustomProp = $feedItem->getProperty('custom-property', null, 0);
269
        $this->assertTrue(is_string($feedCustomProp));
270
        $this->assertEquals('Property for alias testing', $feedCustomProp);
271
272
        // Test the custom item property via the convenience getter
273
        $feedCustomProp = $feedItem->customProperty;
1 ignored issue
show
Bug introduced by
The property customProperty does not seem to exist in Jkphl\Micrometa\Ports\Item\Item.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
274
        $this->assertTrue(is_string($feedCustomProp));
275
        $this->assertEquals('Property for alias testing', $feedCustomProp);
276
277
        // Test an invalid property
278
        $feedItem->invalidProperty;
1 ignored issue
show
Documentation introduced by
The property invalidProperty does not exist on object<Jkphl\Micrometa\Ports\Item\Item>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
279
    }
280
281
    /**
282
     * Test a property stack
283
     *
284
     * @expectedException \Jkphl\Micrometa\Ports\Exceptions\OutOfBoundsException
285
     * @expectedExceptionCode 1488315604
286
     */
287
    public function testPropertyStack()
288
    {
289
        $feedItem = $this->getFeedItem();
290
        $this->assertInstanceOf(Item::class, $feedItem);
291
292
        // Request a valid property stack
293
        $propertyValues = $feedItem->getFirstProperty('photo', MicroformatsFactory::MF2_PROFILE_URI, 'name');
294
        $this->assertEquals(['John Doe\'s Blog'], $propertyValues);
295
296
        // Request unknown properties only
297
        $feedItem->getFirstProperty('photo', MicroformatsFactory::MF2_PROFILE_URI, 'invalid');
298
    }
299
300
    /**
301
     * Test a property item
302
     */
303
    public function testPropertyItem()
304
    {
305
        $feedItem = $this->getFeedItem();
306
        $this->assertInstanceOf(Item::class, $feedItem);
307
308
        // Request a valid property stack
309
        /** @var ItemInterface[] $authors */
310
        $authors = $feedItem->getFirstProperty('author');
311
        $this->assertTrue(is_array($authors));
312
        $this->assertInstanceOf(ItemInterface::class, $authors[0]);
313
314
        // Test the author name as an unprofiled single property value
315
        $authorName = $authors[0]->getProperty('name', MicroformatsFactory::MF2_PROFILE_URI, 0);
316
        $this->assertTrue(is_string($authorName));
317
        $this->assertEquals('John Doe', $authorName);
318
    }
319
320
    /**
321
     * Test nested items
322
     *
323
     * @expectedException \Jkphl\Micrometa\Ports\Exceptions\InvalidArgumentException
324
     * @expectedExceptionCode 1492418709
325
     */
326
    public function testNestedItems()
327
    {
328
        $feedItem = $this->getFeedItem();
329
        $this->assertInstanceOf(Item::class, $feedItem);
330
331
        // Test the number of nested items
332
        $this->assertEquals(2, count($feedItem));
333
        $this->assertEquals(2, count($feedItem->getItems()));
334
        foreach ($feedItem as $itemIndex => $entryItem) {
335
            $this->assertInstanceOf(ItemInterface::class, $entryItem);
336
            $this->assertTrue(is_int($itemIndex));
337
        }
338
        $this->assertInstanceOf(ItemInterface::class, $feedItem->getFirstItem('h-entry'));
339
        $this->assertInstanceOf(
340
            ItemInterface::class, $feedItem->getFirstItem('h-entry', MicroformatsFactory::MF2_PROFILE_URI)
341
        );
342
343
        // Test the second entry item
344
        /** @var Item $entryItem */
345
        $entryItem = $feedItem->getItems('h-entry')[1];
346
        $this->assertInstanceOf(ItemInterface::class, $entryItem);
347
348
        // Test the magic item getter / item type aliases
349
        /** @noinspection PhpUndefinedMethodInspection */
350
        $entryItem = $feedItem->hEntry(0);
1 ignored issue
show
Documentation Bug introduced by
The method hEntry does not exist on object<Jkphl\Micrometa\Ports\Item\Item>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
351
        $this->assertInstanceOf(ItemInterface::class, $entryItem);
352
        /** @noinspection PhpUndefinedMethodInspection */
353
        $feedItem->hEntry(-1);
1 ignored issue
show
Documentation Bug introduced by
The method hEntry does not exist on object<Jkphl\Micrometa\Ports\Item\Item>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
354
    }
355
356
    /**
357
     * Test non-existent nested item
358
     *
359
     * @expectedException \Jkphl\Micrometa\Ports\Exceptions\OutOfBoundsException
360
     * @expectedExceptionCode 1492418999
361
     */
362
    public function testNonExistentNestedItems()
363
    {
364
        $feedItem = $this->getFeedItem();
365
        /** @noinspection PhpUndefinedMethodInspection */
366
        $this->assertEquals('John Doe', $feedItem->hEntry()->author->name);
1 ignored issue
show
Documentation Bug introduced by
The method hEntry does not exist on object<Jkphl\Micrometa\Ports\Item\Item>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
367
        /** @noinspection PhpUndefinedMethodInspection */
368
        $feedItem->hEntry(2);
1 ignored issue
show
Documentation Bug introduced by
The method hEntry does not exist on object<Jkphl\Micrometa\Ports\Item\Item>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
369
    }
370
371
    /**
372
     * Test the item list export
373
     *
374
     * @expectedException \Jkphl\Micrometa\Ports\Exceptions\OutOfBoundsException
375
     * @expectedExceptionCode 1492030227
376
     */
377
    public function testItemListExport()
378
    {
379
        $feedItem = $this->getFeedItem();
380
        $itemList = new ItemList([$feedItem]);
381
        $this->assertInstanceOf(ItemList::class, $itemList);
382
383
        $export = $itemList->toObject();
384
        $this->assertInstanceOf(\stdClass::class, $export);
385
        $this->assertTrue(isset($export->items));
386
        $this->assertTrue(is_array($export->items));
387
        $this->assertEquals($feedItem->toObject(), current($export->items));
388
389
        $itemList->getFirstItem('invalid');
390
    }
391
392
    /**
393
     * Test the item object model rels
394
     *
395
     * @expectedException \Jkphl\Micrometa\Ports\Exceptions\OutOfBoundsException
396
     * @expectedExceptionCode 1489269267
397
     */
398
    public function testItemObjectModelRels()
399
    {
400
        $itemObjectModel = $this->getItemObjectModel();
401
        $this->assertInstanceOf(ItemObjectModel::class, $itemObjectModel);
402
403
        // Get the list of all rels
404
        $rels = $itemObjectModel->rels();
405
        $this->assertTrue(is_array($rels));
406
        $this->assertEquals(2, count($rels));
407
408
        // Get the list of all rel=me
409
        $relMes = $itemObjectModel->rel('me');
410
        $this->assertTrue(is_array($relMes));
411
        $this->assertEquals(2, count($relMes));
412
413
        // Get the first rel=me
414
        $this->assertInstanceOf(Rel::class, $itemObjectModel->rel('me', 0));
415
        $this->assertEquals('https://twitter.com/example', strval($itemObjectModel->rel('me', 0)));
416
417
        $itemObjectModel->rel('invalid');
418
    }
419
420
    /**
421
     * Test an invalid item rel index
422
     *
423
     * @expectedException \Jkphl\Micrometa\Ports\Exceptions\OutOfBoundsException
424
     * @expectedExceptionCode 1489268571
425
     */
426
    public function testItemObjectModelInvalidRelIndex()
427
    {
428
        $itemObjectModel = $this->getItemObjectModel();
429
        $this->assertInstanceOf(ItemObjectModel::class, $itemObjectModel);
430
        $itemObjectModel->rel('me', 2);
431
    }
432
433
    /**
434
     * Test the item object model alternates
435
     */
436
    public function testItemObjectModelAlternates()
437
    {
438
        $itemObjectModel = $this->getItemObjectModel();
439
        $this->assertInstanceOf(ItemObjectModel::class, $itemObjectModel);
440
441
        // Get the list of all rels
442
        $alternates = $itemObjectModel->alternates();
443
        $this->assertTrue(is_array($alternates));
444
        $this->assertEquals(2, count($alternates));
445
        $this->assertInstanceOf(Alternate::class, $alternates[0]);
446
        $this->assertEquals('http://example.com/blog.atom', strval($alternates[0]));
447
        $this->assertEquals('application/atom+xml', $alternates[0]->getType());
448
        $this->assertEquals('Atom feed', $alternates[0]->getTitle());
449
    }
450
451
    /**
452
     * Instantiate an item object model
453
     *
454
     * @return ItemObjectModel Item object model
455
     */
456
    protected function getItemObjectModel()
457
    {
458
        $alternates = AlternateFactory::createFromParserResult(
459
            [
460
                ['value' => 'http://example.com/blog.atom', 'type' => 'application/atom+xml', 'title' => 'Atom feed'],
461
                ['value' => 'http://example.com/blog.rss', 'type' => 'application/rss+xml', 'title' => 'RSS feed'],
462
            ]
463
        );
464
        $rels = RelFactory::createFromParserResult(
465
            [
466
                'me' => ['https://twitter.com/example', 'https://github.com/example'],
467
                'webmention' => ['https://example.com/webmention'],
468
            ]
469
        );
470
        return new ItemObjectModel([$this->getFeedItem()], $rels, $alternates);
0 ignored issues
show
Documentation introduced by
$rels is of type array<integer,array>, but the function expects a array<integer,object<Jkp...orts\Rel\RelInterface>>.

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...
471
    }
472
}
473