2018-09-25 23:52:27 +02:00
|
|
|
<?php
|
|
|
|
namespace Psalm\Tests;
|
|
|
|
|
|
|
|
class FileDiffTest extends TestCase
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* @dataProvider getChanges
|
|
|
|
*
|
|
|
|
* @param string $a
|
|
|
|
* @param string $b
|
|
|
|
* @param string[] $same_methods
|
|
|
|
*
|
|
|
|
* @return void
|
|
|
|
*/
|
2018-09-26 22:33:59 +02:00
|
|
|
public function testCode(string $a, string $b, array $same_methods, array $same_signatures, array $diff_map_offsets)
|
2018-09-25 23:52:27 +02:00
|
|
|
{
|
|
|
|
if (strpos($this->getTestName(), 'SKIPPED-') !== false) {
|
|
|
|
$this->markTestSkipped();
|
|
|
|
}
|
|
|
|
|
|
|
|
$a_stmts = \Psalm\Provider\StatementsProvider::parseStatements($a);
|
|
|
|
$b_stmts = \Psalm\Provider\StatementsProvider::parseStatements($b);
|
|
|
|
|
|
|
|
$diff = \Psalm\Diff\FileStatementsDiffer::diff($a_stmts, $b_stmts, $a, $b);
|
|
|
|
|
|
|
|
$this->assertSame(
|
|
|
|
$same_methods,
|
|
|
|
$diff[0]
|
|
|
|
);
|
|
|
|
|
|
|
|
$this->assertSame(
|
|
|
|
$same_signatures,
|
|
|
|
$diff[1]
|
|
|
|
);
|
2018-09-26 22:33:59 +02:00
|
|
|
|
|
|
|
$this->assertSame(count($diff_map_offsets), count($diff[2]));
|
|
|
|
|
|
|
|
$found_offsets = array_map(
|
|
|
|
/**
|
|
|
|
* @param array{0: int, 1: int, 2: int, 3: int} $arr
|
|
|
|
*
|
|
|
|
* @return array{0: int, 1: int}
|
|
|
|
*/
|
|
|
|
function (array $arr) {
|
|
|
|
return [$arr[2], $arr[3]];
|
|
|
|
},
|
|
|
|
$diff[2]
|
|
|
|
);
|
|
|
|
|
|
|
|
$this->assertSame($diff_map_offsets, $found_offsets);
|
2018-09-25 23:52:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return array
|
|
|
|
*/
|
|
|
|
public function getChanges()
|
|
|
|
{
|
|
|
|
return [
|
|
|
|
'sameFile' => [
|
|
|
|
'<?php
|
|
|
|
namespace Foo;
|
|
|
|
|
|
|
|
class A {
|
|
|
|
public $aB = 5;
|
|
|
|
|
|
|
|
const F = 1;
|
|
|
|
|
|
|
|
public function foo() {
|
|
|
|
$a = 1;
|
|
|
|
}
|
|
|
|
public function bar() {
|
|
|
|
$b = 1;
|
|
|
|
}
|
|
|
|
}',
|
|
|
|
'<?php
|
|
|
|
namespace Foo;
|
|
|
|
|
|
|
|
class A {
|
|
|
|
public $aB = 5;
|
|
|
|
|
|
|
|
const F = 1;
|
|
|
|
|
|
|
|
public function foo() {
|
|
|
|
$a = 1;
|
|
|
|
}
|
|
|
|
public function bar() {
|
|
|
|
$b = 1;
|
|
|
|
}
|
|
|
|
}',
|
2018-09-26 22:33:59 +02:00
|
|
|
['foo\a::$aB', 'foo\a::F', 'foo\a::foo', 'foo\a::bar'],
|
|
|
|
[],
|
|
|
|
[[0, 0], [0, 0], [0, 0], [0, 0]]
|
2018-09-25 23:52:27 +02:00
|
|
|
],
|
2018-09-26 22:33:59 +02:00
|
|
|
'lineChanges' => [
|
2018-09-25 23:52:27 +02:00
|
|
|
'<?php
|
|
|
|
namespace Foo;
|
|
|
|
|
|
|
|
class A {
|
2018-09-26 22:33:59 +02:00
|
|
|
public $aB = 5;
|
|
|
|
|
|
|
|
const F = 1;
|
|
|
|
|
2018-09-25 23:52:27 +02:00
|
|
|
public function foo() {
|
|
|
|
$a = 1;
|
|
|
|
}
|
|
|
|
public function bar() {
|
|
|
|
$b = 1;
|
|
|
|
}
|
|
|
|
}',
|
|
|
|
'<?php
|
|
|
|
namespace Foo;
|
|
|
|
|
|
|
|
class A {
|
2018-09-26 22:33:59 +02:00
|
|
|
|
|
|
|
public $aB = 5;
|
|
|
|
|
|
|
|
|
|
|
|
const F = 1;
|
|
|
|
|
2018-09-25 23:52:27 +02:00
|
|
|
public function foo() {
|
|
|
|
$a = 1;
|
|
|
|
}
|
2018-09-26 22:33:59 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
2018-09-25 23:52:27 +02:00
|
|
|
public function bar() {
|
2018-09-26 22:33:59 +02:00
|
|
|
$b = 1;
|
|
|
|
}
|
|
|
|
}',
|
|
|
|
['foo\a::$aB', 'foo\a::F', 'foo\a::foo', 'foo\a::bar'],
|
|
|
|
[],
|
|
|
|
[[1, 1], [2, 2], [2, 2], [5, 5]]
|
|
|
|
],
|
|
|
|
'simpleBodyChange' => [
|
|
|
|
'<?php
|
|
|
|
namespace Foo;
|
|
|
|
|
|
|
|
class A {
|
|
|
|
public function foo() {
|
|
|
|
$a = 1;
|
|
|
|
}
|
|
|
|
public function bar() {
|
|
|
|
$b = 1;
|
2018-09-25 23:52:27 +02:00
|
|
|
}
|
|
|
|
}',
|
2018-09-26 22:33:59 +02:00
|
|
|
'<?php
|
|
|
|
namespace Foo;
|
|
|
|
|
|
|
|
class A {
|
|
|
|
public function foo() {
|
|
|
|
$a = 12;
|
|
|
|
}
|
|
|
|
public function bar() {
|
|
|
|
$b = 1;
|
|
|
|
}
|
|
|
|
}',
|
|
|
|
['foo\a::bar'],
|
2018-09-25 23:52:27 +02:00
|
|
|
['foo\a::foo'],
|
2018-09-26 22:33:59 +02:00
|
|
|
[[1, 0]]
|
2018-09-25 23:52:27 +02:00
|
|
|
],
|
|
|
|
'simpleBodyChangeWithSignatureChange' => [
|
|
|
|
'<?php
|
|
|
|
namespace Foo;
|
|
|
|
|
|
|
|
class A {
|
|
|
|
public function foo() {
|
|
|
|
$a = 1;
|
|
|
|
}
|
|
|
|
public function bar() {
|
|
|
|
$b = 1;
|
|
|
|
}
|
|
|
|
}',
|
|
|
|
'<?php
|
|
|
|
namespace Foo;
|
|
|
|
|
|
|
|
class A {
|
|
|
|
public function foo() {
|
|
|
|
$a = 1;
|
|
|
|
}
|
|
|
|
public function bar(string $a) {
|
|
|
|
$b = 1;
|
|
|
|
}
|
|
|
|
}',
|
|
|
|
['foo\a::foo'],
|
2018-09-26 22:33:59 +02:00
|
|
|
[],
|
|
|
|
[[0, 0]]
|
2018-09-25 23:52:27 +02:00
|
|
|
],
|
|
|
|
'propertyChange' => [
|
|
|
|
'<?php
|
|
|
|
namespace Foo;
|
|
|
|
|
|
|
|
class A {
|
|
|
|
public $a;
|
|
|
|
}',
|
|
|
|
'<?php
|
|
|
|
namespace Foo;
|
|
|
|
|
|
|
|
class A {
|
|
|
|
public $b;
|
|
|
|
}',
|
2018-09-26 22:33:59 +02:00
|
|
|
[],
|
|
|
|
[],
|
2018-09-25 23:52:27 +02:00
|
|
|
[]
|
|
|
|
],
|
|
|
|
'propertyDefaultChange' => [
|
|
|
|
'<?php
|
|
|
|
namespace Foo;
|
|
|
|
|
|
|
|
class A {
|
|
|
|
public $a = 1;
|
|
|
|
}',
|
|
|
|
'<?php
|
|
|
|
namespace Foo;
|
|
|
|
|
|
|
|
class A {
|
|
|
|
public $a = 2;
|
|
|
|
}',
|
2018-09-26 22:33:59 +02:00
|
|
|
[],
|
|
|
|
[],
|
2018-09-25 23:52:27 +02:00
|
|
|
[]
|
|
|
|
],
|
|
|
|
'propertyDefaultAddition' => [
|
|
|
|
'<?php
|
|
|
|
namespace Foo;
|
|
|
|
|
|
|
|
class A {
|
|
|
|
public $a;
|
|
|
|
}',
|
|
|
|
'<?php
|
|
|
|
namespace Foo;
|
|
|
|
|
|
|
|
class A {
|
|
|
|
public $a = 2;
|
|
|
|
}',
|
2018-09-26 22:33:59 +02:00
|
|
|
[],
|
|
|
|
[],
|
2018-09-25 23:52:27 +02:00
|
|
|
[]
|
|
|
|
],
|
|
|
|
'propertySignatureChange' => [
|
|
|
|
'<?php
|
|
|
|
namespace Foo;
|
|
|
|
|
|
|
|
class A {
|
|
|
|
/** @var ?string */
|
|
|
|
public $a;
|
|
|
|
}',
|
|
|
|
'<?php
|
|
|
|
namespace Foo;
|
|
|
|
|
|
|
|
class A {
|
|
|
|
/** @var ?int */
|
|
|
|
public $a;
|
|
|
|
}',
|
2018-09-26 22:33:59 +02:00
|
|
|
[],
|
|
|
|
[],
|
2018-09-25 23:52:27 +02:00
|
|
|
[]
|
|
|
|
],
|
2018-09-26 22:33:59 +02:00
|
|
|
'addDocblockToFirst' => [
|
|
|
|
'<?php
|
|
|
|
namespace Foo;
|
|
|
|
|
|
|
|
class A {
|
|
|
|
public function foo() {
|
|
|
|
$a = 1;
|
|
|
|
}
|
|
|
|
public function bar() {
|
|
|
|
$b = 2;
|
|
|
|
}
|
|
|
|
}',
|
|
|
|
'<?php
|
|
|
|
namespace Foo;
|
|
|
|
|
|
|
|
class A {
|
|
|
|
/**
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
public function foo() {
|
|
|
|
$a = 1;
|
|
|
|
}
|
|
|
|
public function bar() {
|
|
|
|
$b = 2;
|
|
|
|
}
|
|
|
|
}',
|
|
|
|
['foo\a::bar'],
|
|
|
|
[],
|
|
|
|
[[84, 3]]
|
|
|
|
],
|
|
|
|
'addDocblockToSecond' => [
|
2018-09-25 23:52:27 +02:00
|
|
|
'<?php
|
|
|
|
namespace Foo;
|
|
|
|
|
|
|
|
class A {
|
|
|
|
public function foo() {
|
|
|
|
$a = 1;
|
|
|
|
}
|
|
|
|
public function bar() {
|
|
|
|
$b = 2;
|
|
|
|
}
|
|
|
|
}',
|
|
|
|
'<?php
|
|
|
|
namespace Foo;
|
|
|
|
|
|
|
|
class A {
|
|
|
|
public function foo() {
|
|
|
|
$a = 1;
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
public function bar() {
|
|
|
|
$b = 2;
|
|
|
|
}
|
|
|
|
}',
|
2018-09-26 22:33:59 +02:00
|
|
|
['foo\a::foo'],
|
|
|
|
[],
|
|
|
|
[[0, 0]]
|
2018-09-25 23:52:27 +02:00
|
|
|
],
|
|
|
|
'removeDocblock' => [
|
|
|
|
'<?php
|
|
|
|
namespace Foo;
|
|
|
|
|
|
|
|
class A {
|
|
|
|
public function foo() {
|
|
|
|
$a = 1;
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
public function bar() {
|
|
|
|
$b = 2;
|
|
|
|
}
|
|
|
|
}',
|
|
|
|
'<?php
|
|
|
|
namespace Foo;
|
|
|
|
|
|
|
|
class A {
|
|
|
|
public function foo() {
|
|
|
|
$a = 1;
|
|
|
|
}
|
|
|
|
public function bar() {
|
|
|
|
$b = 2;
|
|
|
|
}
|
|
|
|
}',
|
2018-09-26 22:33:59 +02:00
|
|
|
['foo\a::foo'],
|
|
|
|
[],
|
|
|
|
[[0, 0]]
|
2018-09-25 23:52:27 +02:00
|
|
|
],
|
|
|
|
'changeDocblock' => [
|
|
|
|
'<?php
|
|
|
|
namespace Foo;
|
|
|
|
|
|
|
|
class A {
|
|
|
|
public function foo() {
|
|
|
|
$a = 1;
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
public function bar() {
|
|
|
|
$b = 2;
|
|
|
|
}
|
|
|
|
}',
|
|
|
|
'<?php
|
|
|
|
namespace Foo;
|
|
|
|
|
|
|
|
class A {
|
|
|
|
public function foo() {
|
|
|
|
$a = 1;
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
public function bar() {
|
|
|
|
$b = 2;
|
|
|
|
}
|
|
|
|
}',
|
2018-09-26 22:33:59 +02:00
|
|
|
['foo\a::foo'],
|
|
|
|
[],
|
|
|
|
[[0, 0]]
|
2018-09-25 23:52:27 +02:00
|
|
|
],
|
|
|
|
'removeFunctionAtEnd' => [
|
|
|
|
'<?php
|
|
|
|
namespace Foo;
|
|
|
|
|
|
|
|
class A {
|
|
|
|
public function foo() {
|
|
|
|
$a = 1;
|
|
|
|
}
|
|
|
|
public function bar() {
|
|
|
|
$b = 1;
|
|
|
|
}
|
|
|
|
public function bat() {
|
|
|
|
$c = 1;
|
|
|
|
}
|
|
|
|
}',
|
|
|
|
'<?php
|
|
|
|
namespace Foo;
|
|
|
|
|
|
|
|
class A {
|
|
|
|
public function foo() {
|
|
|
|
$a = 1;
|
|
|
|
}
|
|
|
|
public function bar() {
|
|
|
|
$b = 1;
|
|
|
|
}
|
|
|
|
}',
|
2018-09-26 22:33:59 +02:00
|
|
|
['foo\a::foo', 'foo\a::bar'],
|
|
|
|
[],
|
|
|
|
[[0, 0], [0, 0]]
|
2018-09-25 23:52:27 +02:00
|
|
|
],
|
|
|
|
'removeFunctionAtBeginning' => [
|
|
|
|
'<?php
|
|
|
|
namespace Foo;
|
|
|
|
|
|
|
|
class A {
|
|
|
|
public function foo() {
|
|
|
|
$a = 1;
|
|
|
|
}
|
|
|
|
public function bar() {
|
|
|
|
$b = 1;
|
|
|
|
}
|
|
|
|
public function bat() {
|
|
|
|
$c = 1;
|
|
|
|
}
|
|
|
|
}',
|
|
|
|
'<?php
|
|
|
|
namespace Foo;
|
|
|
|
|
|
|
|
class A {
|
|
|
|
public function bar() {
|
|
|
|
$b = 1;
|
|
|
|
}
|
|
|
|
public function bat() {
|
|
|
|
$c = 1;
|
|
|
|
}
|
|
|
|
}',
|
2018-09-26 22:33:59 +02:00
|
|
|
['foo\a::bar', 'foo\a::bat'],
|
|
|
|
[],
|
|
|
|
[[-98, -3], [-98, -3]]
|
2018-09-25 23:52:27 +02:00
|
|
|
],
|
|
|
|
'removeFunctionInMiddle' => [
|
|
|
|
'<?php
|
|
|
|
namespace Foo;
|
|
|
|
|
|
|
|
class A {
|
|
|
|
public function foo() {
|
|
|
|
$a = 1;
|
|
|
|
}
|
|
|
|
public function bar() {
|
|
|
|
$b = 1;
|
|
|
|
}
|
|
|
|
public function bat() {
|
|
|
|
$c = 1;
|
|
|
|
}
|
|
|
|
}',
|
|
|
|
'<?php
|
|
|
|
namespace Foo;
|
|
|
|
|
|
|
|
class A {
|
|
|
|
public function foo() {
|
|
|
|
$a = 1;
|
|
|
|
}
|
|
|
|
public function bat() {
|
|
|
|
$c = 1;
|
|
|
|
}
|
|
|
|
}',
|
2018-09-26 22:33:59 +02:00
|
|
|
['foo\a::foo', 'foo\a::bat'],
|
|
|
|
[],
|
|
|
|
[[0, 0], [-98, -3]],
|
2018-09-25 23:52:27 +02:00
|
|
|
],
|
|
|
|
'changeNamespace' => [
|
|
|
|
'<?php
|
|
|
|
namespace Bar;
|
|
|
|
|
|
|
|
class A {
|
|
|
|
public function foo() {
|
|
|
|
$a = 1;
|
|
|
|
}
|
|
|
|
public function bar() {
|
|
|
|
$b = 1;
|
|
|
|
}
|
|
|
|
}',
|
|
|
|
'<?php
|
|
|
|
namespace Foo;
|
|
|
|
|
|
|
|
class A {
|
|
|
|
public function bar() {
|
|
|
|
$b = 2;
|
|
|
|
}
|
|
|
|
}',
|
2018-09-26 22:33:59 +02:00
|
|
|
[],
|
|
|
|
[],
|
2018-09-25 23:52:27 +02:00
|
|
|
[]
|
|
|
|
],
|
|
|
|
'removeNamespace' => [
|
|
|
|
'<?php
|
|
|
|
namespace Bar;
|
|
|
|
|
|
|
|
class A {
|
|
|
|
public function foo() {
|
|
|
|
$a = 1;
|
|
|
|
}
|
|
|
|
public function bar() {
|
|
|
|
$b = 1;
|
|
|
|
}
|
|
|
|
}',
|
|
|
|
'<?php
|
|
|
|
class A {
|
|
|
|
public function bar() {
|
|
|
|
$b = 2;
|
|
|
|
}
|
|
|
|
}',
|
|
|
|
[],
|
2018-09-26 22:33:59 +02:00
|
|
|
[],
|
|
|
|
[]
|
2018-09-25 23:52:27 +02:00
|
|
|
],
|
|
|
|
'newFunctionAtEnd' => [
|
|
|
|
'<?php
|
|
|
|
namespace Foo;
|
|
|
|
|
|
|
|
class A {
|
|
|
|
public function foo() {
|
|
|
|
$a = 1;
|
|
|
|
}
|
|
|
|
public function bar() {
|
|
|
|
$b = 1;
|
|
|
|
}
|
|
|
|
}',
|
|
|
|
'<?php
|
|
|
|
namespace Foo;
|
|
|
|
|
|
|
|
class A {
|
|
|
|
public function foo() {
|
|
|
|
$a = 1;
|
|
|
|
}
|
|
|
|
public function bar() {
|
|
|
|
$b = 1;
|
|
|
|
}
|
|
|
|
public function bat() {
|
|
|
|
$c = 1;
|
|
|
|
}
|
|
|
|
}',
|
2018-09-26 22:33:59 +02:00
|
|
|
['foo\a::foo', 'foo\a::bar'],
|
|
|
|
[],
|
|
|
|
[[0, 0], [0, 0]]
|
2018-09-25 23:52:27 +02:00
|
|
|
],
|
|
|
|
'newFunctionAtBeginning' => [
|
|
|
|
'<?php
|
|
|
|
namespace Foo;
|
|
|
|
|
|
|
|
class A {
|
|
|
|
public function foo() {
|
|
|
|
$a = 1;
|
|
|
|
}
|
|
|
|
public function bar() {
|
|
|
|
$b = 1;
|
|
|
|
}
|
|
|
|
}',
|
|
|
|
'<?php
|
|
|
|
namespace Foo;
|
|
|
|
|
|
|
|
class A {
|
|
|
|
public function bat() {
|
|
|
|
$c = 1;
|
|
|
|
}
|
|
|
|
public function foo() {
|
|
|
|
$a = 1;
|
|
|
|
}
|
|
|
|
public function bar() {
|
|
|
|
$b = 1;
|
|
|
|
}
|
|
|
|
}',
|
2018-09-26 22:33:59 +02:00
|
|
|
['foo\a::foo', 'foo\a::bar'],
|
|
|
|
[],
|
|
|
|
[[98, 3], [98, 3]]
|
2018-09-25 23:52:27 +02:00
|
|
|
],
|
|
|
|
'newFunctionInMiddle' => [
|
|
|
|
'<?php
|
|
|
|
namespace Foo;
|
|
|
|
|
|
|
|
class A {
|
|
|
|
public function foo() {
|
|
|
|
$a = 1;
|
|
|
|
}
|
|
|
|
public function bar() {
|
|
|
|
$b = 1;
|
|
|
|
}
|
|
|
|
}',
|
|
|
|
'<?php
|
|
|
|
namespace Foo;
|
|
|
|
|
|
|
|
class A {
|
|
|
|
public function foo() {
|
|
|
|
$a = 1;
|
|
|
|
}
|
|
|
|
public function bat() {
|
|
|
|
$c = 1;
|
|
|
|
}
|
|
|
|
public function bar() {
|
|
|
|
$b = 1;
|
|
|
|
}
|
|
|
|
}',
|
2018-09-26 22:33:59 +02:00
|
|
|
['foo\a::foo', 'foo\a::bar'],
|
|
|
|
[],
|
|
|
|
[[0, 0], [98, 3]]
|
2018-09-25 23:52:27 +02:00
|
|
|
],
|
2018-09-26 22:33:59 +02:00
|
|
|
'SKIPPED-whiteSpaceOnly' => [
|
2018-09-25 23:52:27 +02:00
|
|
|
'<?php
|
|
|
|
namespace Foo;
|
|
|
|
|
|
|
|
class A {
|
|
|
|
public function foo() {
|
|
|
|
$a = 1;
|
|
|
|
}
|
|
|
|
public function bar() {
|
|
|
|
$b = 1;
|
|
|
|
}
|
|
|
|
}',
|
|
|
|
'<?php
|
|
|
|
namespace Foo;
|
|
|
|
class A {
|
|
|
|
public function foo() {
|
|
|
|
|
|
|
|
$a = 1 ;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function bar() {
|
|
|
|
$b = 1;
|
|
|
|
|
|
|
|
}
|
|
|
|
}',
|
2018-09-26 22:33:59 +02:00
|
|
|
['foo\a::foo', 'foo\a::bar'],
|
|
|
|
[],
|
|
|
|
[]
|
2018-09-25 23:52:27 +02:00
|
|
|
],
|
|
|
|
'changeDeclaredMethodId' => [
|
|
|
|
'<?php
|
|
|
|
namespace Foo;
|
|
|
|
|
|
|
|
class A {
|
|
|
|
public function __construct() {}
|
|
|
|
public static function bar() : void {}
|
|
|
|
}
|
|
|
|
|
|
|
|
class B extends A {
|
|
|
|
public static function bat() : void {}
|
|
|
|
}
|
|
|
|
|
|
|
|
class C extends B { }',
|
|
|
|
'<?php
|
|
|
|
namespace Foo;
|
|
|
|
|
|
|
|
class A {
|
|
|
|
public function __construct() {}
|
|
|
|
public static function bar() : void {}
|
|
|
|
}
|
|
|
|
|
|
|
|
class B extends A {
|
|
|
|
public function __construct() {}
|
|
|
|
public static function bar() : void {}
|
|
|
|
public static function bat() : void {}
|
|
|
|
}
|
|
|
|
|
|
|
|
class C extends B { }',
|
2018-09-26 22:33:59 +02:00
|
|
|
['foo\a::__construct', 'foo\a::bar', 'foo\b::bat'],
|
|
|
|
[],
|
|
|
|
[[0, 0], [0, 0], [120, 2]]
|
2018-09-25 23:52:27 +02:00
|
|
|
],
|
|
|
|
];
|
|
|
|
}
|
|
|
|
}
|