Completed
Pull Request — master (#447)
by Alexandru
01:27
created

WebSocketHandler::onOpen()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 8
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
1
<?php
2
3
namespace BeyondCode\LaravelWebSockets\WebSockets;
4
5
use BeyondCode\LaravelWebSockets\Apps\App;
6
use BeyondCode\LaravelWebSockets\Dashboard\DashboardLogger;
7
use BeyondCode\LaravelWebSockets\Facades\StatisticsLogger;
8
use BeyondCode\LaravelWebSockets\PubSub\ReplicationInterface;
9
use BeyondCode\LaravelWebSockets\QueryParameters;
10
use BeyondCode\LaravelWebSockets\WebSockets\Channels\ChannelManager;
11
use BeyondCode\LaravelWebSockets\WebSockets\Exceptions\ConnectionsOverCapacity;
12
use BeyondCode\LaravelWebSockets\WebSockets\Exceptions\OriginNotAllowed;
13
use BeyondCode\LaravelWebSockets\WebSockets\Exceptions\UnknownAppKey;
14
use BeyondCode\LaravelWebSockets\WebSockets\Exceptions\WebSocketException;
15
use BeyondCode\LaravelWebSockets\WebSockets\Messages\PusherMessageFactory;
16
use Exception;
17
use Ratchet\ConnectionInterface;
18
use Ratchet\RFC6455\Messaging\MessageInterface;
19
use Ratchet\WebSocket\MessageComponentInterface;
20
use React\Promise\PromiseInterface;
21
22
class WebSocketHandler implements MessageComponentInterface
23
{
24
    /**
25
     * The channel manager.
26
     *
27
     * @var \BeyondCode\LaravelWebSockets\WebSockets\Channels\ChannelManager
28
     */
29
    protected $channelManager;
30
31
    /**
32
     * The replicator client.
33
     *
34
     * @var ReplicationInterface
35
     */
36
    protected $replicator;
37
38
    /**
39
     * Initialize a new handler.
40
     *
41
     * @param  \BeyondCode\LaravelWebSockets\WebSockets\Channels\ChannelManager  $channelManager
42
     * @return void
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
43
     */
44
    public function __construct(ChannelManager $channelManager)
45
    {
46
        $this->channelManager = $channelManager;
47
        $this->replicator = app(ReplicationInterface::class);
48
    }
49
50
    /**
51
     * Handle the socket opening.
52
     *
53
     * @param  \Ratchet\ConnectionInterface  $connection
54
     * @return void
55
     */
56
    public function onOpen(ConnectionInterface $connection)
57
    {
58
        $this->verifyAppKey($connection)
59
            ->verifyOrigin($connection)
60
            ->limitConcurrentConnections($connection)
61
            ->generateSocketId($connection)
62
            ->establishConnection($connection);
63
    }
64
65
    /**
66
     * Handle the incoming message.
67
     *
68
     * @param  \Ratchet\ConnectionInterface  $connection
69
     * @param  \Ratchet\RFC6455\Messaging\MessageInterface  $message
70
     * @return void
71
     */
72
    public function onMessage(ConnectionInterface $connection, MessageInterface $message)
73
    {
74
        $message = PusherMessageFactory::createForMessage($message, $connection, $this->channelManager);
75
76
        $message->respond();
77
78
        StatisticsLogger::webSocketMessage($connection->app->id);
0 ignored issues
show
Bug introduced by
Accessing app on the interface Ratchet\ConnectionInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
79
    }
80
81
    /**
82
     * Handle the websocket close.
83
     *
84
     * @param  \Ratchet\ConnectionInterface  $connection
85
     * @return void
86
     */
87
    public function onClose(ConnectionInterface $connection)
88
    {
89
        $this->channelManager->removeFromAllChannels($connection);
90
91
        DashboardLogger::log($connection->app->id, DashboardLogger::TYPE_DISCONNECTED, [
0 ignored issues
show
Bug introduced by
Accessing app on the interface Ratchet\ConnectionInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
92
            'socketId' => $connection->socketId,
0 ignored issues
show
Bug introduced by
Accessing socketId on the interface Ratchet\ConnectionInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
93
        ]);
94
95
        StatisticsLogger::disconnection($connection->app->id);
0 ignored issues
show
Bug introduced by
Accessing app on the interface Ratchet\ConnectionInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
96
97
        $this->replicator->unsubscribeFromApp($connection->app->id);
0 ignored issues
show
Bug introduced by
Accessing app on the interface Ratchet\ConnectionInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
98
    }
99
100
    /**
101
     * Handle the websocket errors.
102
     *
103
     * @param  \Ratchet\ConnectionInterface  $connection
104
     * @param  WebSocketException  $exception
105
     * @return void
106
     */
107
    public function onError(ConnectionInterface $connection, Exception $exception)
108
    {
109
        if ($exception instanceof WebSocketException) {
110
            $connection->send(json_encode(
111
                $exception->getPayload()
112
            ));
113
        }
114
115
        $this->replicator->unsubscribeFromApp($connection->app->id);
0 ignored issues
show
Bug introduced by
Accessing app on the interface Ratchet\ConnectionInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
116
    }
117
118
    /**
119
     * Verify the app key validity.
120
     *
121
     * @param  \Ratchet\ConnectionInterface  $connection
122
     * @return $this
123
     */
124
    protected function verifyAppKey(ConnectionInterface $connection)
125
    {
126
        $appKey = QueryParameters::create($connection->httpRequest)->get('appKey');
0 ignored issues
show
Bug introduced by
Accessing httpRequest on the interface Ratchet\ConnectionInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
127
128
        if (! $app = App::findByKey($appKey)) {
129
            throw new UnknownAppKey($appKey);
130
        }
131
132
        $connection->app = $app;
0 ignored issues
show
Bug introduced by
Accessing app on the interface Ratchet\ConnectionInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
133
134
        return $this;
135
    }
136
137
    /**
138
     * Verify the origin.
139
     *
140
     * @param  \Ratchet\ConnectionInterface  $connection
141
     * @return $this
142
     */
143
    protected function verifyOrigin(ConnectionInterface $connection)
144
    {
145
        if (! $connection->app->allowedOrigins) {
0 ignored issues
show
Bug introduced by
Accessing app on the interface Ratchet\ConnectionInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
146
            return $this;
147
        }
148
149
        $header = (string) ($connection->httpRequest->getHeader('Origin')[0] ?? null);
0 ignored issues
show
Bug introduced by
Accessing httpRequest on the interface Ratchet\ConnectionInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
150
151
        $origin = parse_url($header, PHP_URL_HOST) ?: $header;
152
153
        if (! $header || ! in_array($origin, $connection->app->allowedOrigins)) {
0 ignored issues
show
Bug introduced by
Accessing app on the interface Ratchet\ConnectionInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
154
            throw new OriginNotAllowed($connection->app->key);
0 ignored issues
show
Bug introduced by
Accessing app on the interface Ratchet\ConnectionInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
155
        }
156
157
        return $this;
158
    }
159
160
    /**
161
     * Limit the connections count by the app.
162
     *
163
     * @param  \Ratchet\ConnectionInterface  $connection
164
     * @return $this
165
     */
166
    protected function limitConcurrentConnections(ConnectionInterface $connection)
167
    {
168
        if (! is_null($capacity = $connection->app->capacity)) {
0 ignored issues
show
Bug introduced by
Accessing app on the interface Ratchet\ConnectionInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
169
            $connectionsCount = $this->channelManager->getGlobalConnectionsCount($connection->app->id);
0 ignored issues
show
Bug introduced by
Accessing app on the interface Ratchet\ConnectionInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
170
171
            if ($connectionsCount instanceof PromiseInterface) {
172
                $connectionsCount->then(function ($connectionsCount) use ($capacity, $connection) {
173
                    $this->sendExceptionIfOverCapacity($connectionsCount, $capacity, $connection);
174
                });
175
            } else {
176
                $this->throwExceptionIfOverCapacity($connectionsCount, $capacity);
177
            }
178
        }
179
180
        return $this;
181
    }
182
183
    /**
184
     * Create a socket id.
185
     *
186
     * @param  \Ratchet\ConnectionInterface  $connection
187
     * @return $this
188
     */
189
    protected function generateSocketId(ConnectionInterface $connection)
190
    {
191
        $socketId = sprintf('%d.%d', random_int(1, 1000000000), random_int(1, 1000000000));
192
193
        $connection->socketId = $socketId;
0 ignored issues
show
Bug introduced by
Accessing socketId on the interface Ratchet\ConnectionInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
194
195
        return $this;
196
    }
197
198
    /**
199
     * Establish connection with the client.
200
     *
201
     * @param  \Ratchet\ConnectionInterface  $connection
202
     * @return $this
203
     */
204
    protected function establishConnection(ConnectionInterface $connection)
205
    {
206
        $connection->send(json_encode([
207
            'event' => 'pusher:connection_established',
208
            'data' => json_encode([
209
                'socket_id' => $connection->socketId,
0 ignored issues
show
Bug introduced by
Accessing socketId on the interface Ratchet\ConnectionInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
210
                'activity_timeout' => 30,
211
            ]),
212
        ]));
213
214
        /** @var \GuzzleHttp\Psr7\Request $request */
215
        $request = $connection->httpRequest;
0 ignored issues
show
Bug introduced by
Accessing httpRequest on the interface Ratchet\ConnectionInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
216
217
        DashboardLogger::log($connection->app->id, DashboardLogger::TYPE_CONNECTED, [
0 ignored issues
show
Bug introduced by
Accessing app on the interface Ratchet\ConnectionInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
218
            'origin' => "{$request->getUri()->getScheme()}://{$request->getUri()->getHost()}",
219
            'socketId' => $connection->socketId,
0 ignored issues
show
Bug introduced by
Accessing socketId on the interface Ratchet\ConnectionInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
220
        ]);
221
222
        StatisticsLogger::connection($connection->app->id);
0 ignored issues
show
Bug introduced by
Accessing app on the interface Ratchet\ConnectionInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
223
224
        $this->replicator->subscribeToApp($connection->app->id);
0 ignored issues
show
Bug introduced by
Accessing app on the interface Ratchet\ConnectionInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
225
226
        return $this;
227
    }
228
229
    /**
230
     * Throw a ConnectionsOverCapacity exception.
231
     *
232
     * @param  int  $connectionsCount
233
     * @param  int  $capacity
234
     * @return void
235
     * @throws ConnectionsOverCapacity
236
     */
237
    protected function throwExceptionIfOverCapacity(int $connectionsCount, int $capacity)
238
    {
239
        if ($connectionsCount >= $capacity) {
240
            throw new ConnectionsOverCapacity;
241
        }
242
    }
243
244
    /**
245
     * Send the ConnectionsOverCapacity exception through
246
     * the connection and close the channel.
247
     *
248
     * @param  int  $connectionsCount
249
     * @param  int  $capacity
250
     * @param  ConnectionInterface  $connection
251
     * @return void
252
     */
253
    protected function sendExceptionIfOverCapacity(int $connectionsCount, int $capacity, ConnectionInterface $connection)
254
    {
255
        if ($connectionsCount >= $capacity) {
256
            $payload = json_encode((new ConnectionsOverCapacity)->getPayload());
257
258
            tap($connection)->send($payload)->close();
259
        }
260
    }
261
}
262