{"id":205934,"date":"2013-12-13T16:39:03","date_gmt":"2013-12-13T12:39:03","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=205934"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=205934","title":{"rendered":"<span class=\"post_title\">WebSocket \u0447\u0430\u0442 \u043d\u0430 symfony2 \u0432 100 \u0441\u0442\u0440\u043e\u043a<\/span>"},"content":{"rendered":"<div class=\"content html_format\">   \t\u041f\u0440\u0438\u0432\u0435\u0442 \u0425\u0430\u0431\u0440!<br \/>  \u041d\u0435\u0434\u0430\u0432\u043d\u043e \u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u043b \u0447\u0430\u0442 \u043d\u0430 \u0432\u0435\u0431\u0441\u043e\u043a\u0435\u0442\u0430\u0445 \u0434\u043b\u044f \u0441\u0432\u043e\u0435\u0433\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u0430 <a href=\"http:\/\/internetsms.org\/chat\">http:\/\/internetsms.org\/chat<\/a>.<br \/>  \u041f\u0440\u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438, \u044f \u0441\u0442\u043e\u043b\u043a\u043d\u0443\u043b\u0441\u044f \u0441 \u0442\u0435\u043c, \u0447\u0442\u043e \u0432 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0435 \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u043e \u0447\u0430\u0442\u043e\u0432 \u0441\u0434\u0435\u043b\u0430\u043d\u044b \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u043f\u043e\u0432\u0442\u043e\u0440\u044f\u044e\u0449\u0438\u0445\u0441\u044f ajax \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u044e\u0442 \u043d\u043e\u0432\u044b\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043f\u043e \u0437\u0430\u0434\u0430\u043d\u043d\u043e\u043c\u0443 \u043f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043a\u0443 \u0432\u0440\u0435\u043c\u0435\u043d\u0438. \u0422\u0430\u043a\u043e\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u0434\u043b\u044f \u043c\u0435\u043d\u044f \u0431\u044b\u043b \u043d\u0435\u043f\u0440\u0438\u0435\u043c\u043b\u0435\u043c, \u0442.\u043a \u043f\u0440\u0438 \u043d\u0430\u043f\u043b\u044b\u0432\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439, \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440 \u0432\u044b\u0440\u0430\u0441\u0442\u0435\u0442 \u044d\u043a\u0441\u043f\u043e\u043d\u0435\u043d\u0446\u0438\u0430\u043b\u044c\u043d\u043e. \u041d\u0430 \u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435, \u0435\u0441\u0442\u044c \u0431\u043e\u043b\u0435\u0435 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0435 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438:<br \/>  <b>Long polling<\/b><br \/>  \u041a\u043b\u0438\u0435\u043d\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440 \u00ab\u0434\u043e\u043b\u0433\u0438\u0439\u00bb \u0437\u0430\u043f\u0440\u043e\u0441, \u0438 \u043f\u0440\u0438 \u043d\u0430\u043b\u0438\u0447\u0438\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439, \u0441\u0435\u0440\u0432\u0435\u0440 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u043e\u0442\u0432\u0435\u0442. \u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u0447\u0438\u0441\u043b\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0441\u043d\u0438\u0436\u0430\u0435\u0442\u0441\u044f. \u041a\u0441\u0442\u0430\u0442\u0438, \u044d\u0442\u0430 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0432 Gmail.<br \/>  <b>Web sockets<\/b><br \/>  \u0412 html5 \u043f\u043e\u044f\u0432\u0438\u043b\u0430\u0441\u044c \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u0430\u044f \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c WebSocket \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f. \u041f\u0430\u0440\u0430\u0434\u0438\u0433\u043c\u0430 \u0437\u0430\u043f\u0440\u043e\u0441-\u043e\u0442\u0432\u0435\u0442 \u0437\u0434\u0435\u0441\u044c \u0432\u043e\u043e\u0431\u0449\u0435 \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f. \u041c\u0435\u0436\u0434\u0443 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u043c \u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c \u043e\u0434\u0438\u043d \u0440\u0430\u0437 \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043a\u0430\u043d\u0430\u043b \u0441\u0432\u044f\u0437\u0438. \u041d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043e\u0434\u0438\u043d \u0434\u0435\u043c\u043e\u043d, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u0432\u0445\u043e\u0434\u044f\u0449\u0438\u0435 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f. \u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440 \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043d\u0435\u0442 \u0434\u0430\u0436\u0435 \u043f\u0440\u0438 \u0431\u043e\u043b\u044c\u0448\u043e\u043c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u043e\u043d\u043b\u0430\u0439\u043d.<br \/>  <a name=\"habracut\"><\/a>  <\/p>\n<h4>\u0421\u0435\u0440\u0432\u0435\u0440\u043d\u0430\u044f \u0447\u0430\u0441\u0442\u044c<\/h4>\n<p>  \u0421\u0435\u0439\u0447\u0430\u0441 \u044f \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u043e\u0431\u044a\u044f\u0441\u043d\u044e, \u043a\u0430\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u044d\u0442\u043e\u0442 \u0447\u0430\u0442. \u042f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b <a href=\"https:\/\/github.com\/cboden\/Ratchet\">Ratchet<\/a> \u2014 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0449\u0443\u044e \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u0441\u043e\u043a\u0435\u0442\u0430\u043c\u0438 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435. \u0412 \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u0445\u0440\u0430\u043d\u044f\u0442\u0441\u044f \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438 \u0442\u0435\u043a\u0443\u0449\u0438\u0435 \u0447\u0430\u0442\u044b (Chat) \u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438 (ChatUser).  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">Chat Entity<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"php\">&lt;?php namespace ISMS\\ChatBundle\\Entity;  use Doctrine\\Common\\Collections\\ArrayCollection; use Doctrine\\ORM\\Mapping as ORM;  \/**  * @ORM\\Entity  * @ORM\\Table  *\/ class Chat {     \/**      * @ORM\\Id      * @ORM\\Column(type=&quot;bigint&quot;)      * @ORM\\GeneratedValue(strategy=&quot;AUTO&quot;)      *      * @var int      *\/     private $id;      \/**      * @var bool      *      * @ORM\\Column(type=&quot;boolean&quot;)      *\/     protected $isCompleted = false;      \/**      * @ORM\\OneToMany(targetEntity=&quot;ChatUser&quot;, mappedBy=&quot;Chat&quot;)      * @var ArrayCollection      *\/     private $users;      \/**      * Constructor      *\/     public function __construct()     {         $this-&gt;users = new ArrayCollection();     }          \/**      * Get id      *      * @return integer       *\/     public function getId()     {         return $this-&gt;id;     }      \/**      * Add users      *      * @param ChatUser $user      * @return Chat      *\/     public function addUser(ChatUser $user)     {         $this-&gt;users[] = $user;          return $this;     }      \/**      * Remove users      *      * @param ChatUser $user      *\/     public function removeUser(ChatUser $user)     {         $this-&gt;users-&gt;removeElement($user);     }      \/**      * Get users      *      * @return ArrayCollection|ChatUser[]      *\/     public function getUsers()     {         return $this-&gt;users;     }      \/**      * @param boolean $isCompleted      *\/     public function setIsCompleted($isCompleted)     {         $this-&gt;isCompleted = $isCompleted;     }      \/**      * @return boolean      *\/     public function getIsCompleted()     {         return $this-&gt;isCompleted;     } } <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">ChatUser Entity<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"php\">&lt;?php namespace ISMS\\ChatBundle\\Entity;  use Doctrine\\ORM\\Mapping as ORM;  \/**  * @ORM\\Entity  * @ORM\\Table  *\/ class ChatUser {     \/**      * @ORM\\Id      * @ORM\\Column(type=&quot;bigint&quot;)      * @ORM\\GeneratedValue(strategy=&quot;AUTO&quot;)      *      * @var int      *\/     private $id;      \/**      * @ORM\\Column(type=&quot;integer&quot;, unique=true)      *      * @var int      *\/     private $rid;      \/**      * @ORM\\ManyToOne(targetEntity=&quot;Chat&quot;, inversedBy=&quot;users&quot;)      * @ORM\\JoinColumn(name=&quot;chat_id&quot;, referencedColumnName=&quot;id&quot;)      * @var Chat      *\/     private $Chat;       \/**      * Get id      *      * @return integer       *\/     public function getId()     {         return $this-&gt;id;     }      \/**      * Set rid      *      * @param integer $rid      * @return ChatUser      *\/     public function setRid($rid)     {         $this-&gt;rid = $rid;              return $this;     }      \/**      * Get rid      *      * @return string       *\/     public function getRid()     {         return $this-&gt;rid;     }      \/**      * Set Chat      *      * @param Chat $chat      * @return ChatUser      *\/     public function setChat(Chat $chat = null)     {         $this-&gt;Chat = $chat;         $chat-&gt;addUser($this);          return $this;     }      \/**      * Get Chat      *      * @return Chat      *\/     public function getChat()     {         return $this-&gt;Chat;     } } <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u0422\u0440\u0438\u0432\u0438\u0430\u043b\u044c\u043d\u044b\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u0441 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u044f\u043c\u0438 \u0432\u044b\u043d\u0435\u0441\u0435\u043d\u044b \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440  <\/p>\n<pre><code class=\"bash\">parameters:     isms_chat.manager.class: ISMS\\ChatBundle\\Manager\\ChatManager  services:     isms_chat.manager:         class: %isms_chat.manager.class%         arguments: [ @doctrine.orm.entity_manager ] <\/code><\/pre>\n<div class=\"spoiler\"><b class=\"spoiler_title\">ChatManager<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"php\">&lt;?php namespace ISMS\\ChatBundle\\Manager;  use Doctrine\\Common\\Persistence\\ObjectManager; use ISMS\\ChatBundle\\Entity\\Chat; use ISMS\\ChatBundle\\Entity\\ChatUser;  class ChatManager {     \/** @var ObjectManager *\/     private $em;      public function __construct(ObjectManager $em)     {         $this-&gt;em = $em;     }      public function removeUserFromChat(ChatUser $user, Chat $chat)     {         if ($chat-&gt;getIsCompleted()) {             $chat-&gt;removeUser($user);             $chat-&gt;setIsCompleted(false);         } else {             $this-&gt;em-&gt;remove($chat);         }         $this-&gt;em-&gt;remove($user);         $this-&gt;em-&gt;flush();     }      public function findOrCreateChatForUser($rid)     {         $chat_user = new ChatUser();         $chat_user-&gt;setRid($rid);         $chat = $this-&gt;getUncompletedChat();         if ($chat) {             $chat-&gt;setIsCompleted(true);         } else {             $chat = new Chat();         }         $chat_user-&gt;setChat($chat);         $this-&gt;em-&gt;persist($chat);         $this-&gt;em-&gt;persist($chat_user);         $this-&gt;em-&gt;flush();         return $chat;     }      public function getChatByUser($rid)     {         $chat_user = $this-&gt;getUserByRid($rid);         return $chat_user ? $chat_user-&gt;getChat() : null;     }      public function getUserByRid($rid)     {         return $this-&gt;em-&gt;getRepository('ISMSChatBundle:ChatUser')-&gt;findOneBy(['rid' =&gt; $rid]);     }      public function getUncompletedChat()     {         return $this-&gt;em-&gt;getRepository('ISMSChatBundle:Chat')-&gt;findOneBy(['isCompleted' =&gt; false]);     }      public function truncateChats()     {         \/** @var \\Doctrine\\DBAL\\Connection $conn *\/         $conn = $this-&gt;em-&gt;getConnection();         $platform = $conn-&gt;getDatabasePlatform();         $conn-&gt;query('SET FOREIGN_KEY_CHECKS=0');         $conn-&gt;executeUpdate($platform-&gt;getTruncateTableSQL('chat_user'));         $conn-&gt;executeUpdate($platform-&gt;getTruncateTableSQL('chat'));         $conn-&gt;query('SET FOREIGN_KEY_CHECKS=1');     } }  <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u0412\u0441\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0432\u0445\u043e\u0434\u044f\u0449\u0438\u0445 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0439 \u0438 \u043f\u0435\u0440\u0435\u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u043c\u0435\u0436\u0434\u0443 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u043c\u0438 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0432 \u043a\u043b\u0430\u0441\u0441\u0435 Chat.  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">Chat<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"php\">&lt;?php namespace ISMS\\ChatBundle\\Chat;  use ISMS\\ChatBundle\\Manager\\ChatManager; use Ratchet\\ConnectionInterface; use Ratchet\\MessageComponentInterface; use Ratchet\\WebSocket\\Version\\RFC6455\\Connection;  class Chat implements MessageComponentInterface {     \/** @var ConnectionInterface[] *\/     protected $clients = [];      \/** @var ChatManager *\/     protected $chm;      public function __construct(ChatManager $chm) {         $this-&gt;chm = $chm;         $this-&gt;chm-&gt;truncateChats();     }      \/**      * @param ConnectionInterface|Connection $conn      * @return string      *\/     private function getRid(ConnectionInterface $conn)     {         return $conn-&gt;resourceId;     }      \/**      * @param ConnectionInterface|Connection $conn      *\/     function onOpen(ConnectionInterface $conn)     {         $this-&gt;clients[$this-&gt;getRid($conn)] = $conn;     }      function onClose(ConnectionInterface $conn)     {         $rid = array_search($conn, $this-&gt;clients);         if ($user = $this-&gt;chm-&gt;getUserByRid($rid)) {             $chat = $user-&gt;getChat();             $this-&gt;chm-&gt;removeUserFromChat($user, $chat);             foreach ($chat-&gt;getUsers() as $user) {                 $this-&gt;clients[$user-&gt;getRid()]-&gt;close();             }         }         unset($this-&gt;clients[$rid]);     }      function onError(ConnectionInterface $conn, \\Exception $e)     {         $conn-&gt;close();     }      function onMessage(ConnectionInterface $from, $msg)     {         $msg = json_decode($msg, true);         $rid = array_search($from, $this-&gt;clients);         switch ($msg['type']) {             case 'request':                 $chat = $this-&gt;chm-&gt;findOrCreateChatForUser($rid);                 if ($chat-&gt;getIsCompleted()) {                     $msg = json_encode(['type' =&gt; 'response']);                     foreach ($chat-&gt;getUsers() as $user) {                         $conn = $this-&gt;clients[$user-&gt;getRid()];                         $conn-&gt;send($msg);                     }                 }                 break;             case 'message':                 if ($chat = $this-&gt;chm-&gt;getChatByUser($rid)) {                     foreach ($chat-&gt;getUsers() as $user) {                         $conn = $this-&gt;clients[$user-&gt;getRid()];                         $msg['from'] = $conn === $from ? 'me' : 'guest';                         $conn-&gt;send(json_encode($msg));                     }                 }                 break;         }     } } <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u0414\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0431\u044b\u043b\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0430 <a href=\"https:\/\/github.com\/mac-cain13\/daemonizable-command\">\u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430<\/a> \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0434\u0435\u043c\u043e\u043d-\u043a\u043e\u043c\u0430\u043d\u0434. \u041a\u0441\u0442\u0430\u0442\u0438, \u0442\u0430\u043c \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043a\u0430\u043a <a href=\"https:\/\/github.com\/mac-cain13\/daemonizable-command#how-to-daemonize\">\u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c<\/a> \u0434\u0435\u043c\u043e\u043d, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 Upstart. \u042d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0447\u0430\u0442\u0430 \u0438 \u0441\u043b\u0435\u0434\u0438\u0442\u044c, \u0447\u0442\u043e\u0431\u044b \u043e\u043d \u043d\u0435 \u0443\u043f\u0430\u043b.<\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">DaemonCommand<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"php\">&lt;?php namespace ISMS\\ChatBundle\\Command;  use ISMS\\ChatBundle\\Chat\\Chat; use Ratchet\\Http\\HttpServer; use Ratchet\\Server\\IoServer; use Ratchet\\WebSocket\\WsServer; use Symfony\\Component\\Console\\Input\\InputInterface; use Symfony\\Component\\Console\\Output\\OutputInterface; use Symfony\\Component\\DependencyInjection\\ContainerAwareInterface; use Symfony\\Component\\DependencyInjection\\ContainerInterface; use Wrep\\Daemonizable\\Command\\EndlessCommand;  class DaemonCommand extends EndlessCommand implements ContainerAwareInterface {     \/** @var ContainerInterface *\/     private $container;      public function setContainer(ContainerInterface $container = null)     {         $this-&gt;container = $container;     }      protected function configure()     {         $this-&gt;setName('isms:chat:daemon');     }      protected function execute(InputInterface $input, OutputInterface $output)     {         $chm = $this-&gt;container-&gt;get('isms_chat.manager');         $server = IoServer::factory(             new HttpServer(                 new WsServer(                     new Chat($chm)                 )             ),             8080         );         $server-&gt;run();     } } <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<h4>\u041a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u0430\u044f \u0447\u0430\u0441\u0442\u044c<\/h4>\n<p>  \u0414\u0432\u0438\u0436\u043e\u043a \u0447\u0430\u0442\u0430 \u043e\u0444\u043e\u0440\u043c\u043b\u0435\u043d \u0432 \u0432\u0438\u0434\u0435 \u043a\u043e\u043d\u0435\u0447\u043d\u043e\u0433\u043e \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0430, \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u043c \u043d\u0430\u0431\u043e\u0440\u043e\u043c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439 \u0438 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u043e\u0432. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0431\u044b\u043b\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0430 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 <a href=\"https:\/\/github.com\/jakesgordon\/javascript-state-machine\">Javascript Finite State Machine<\/a>. \u041d\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u043b\u044e\u0431\u043e\u0433\u043e \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0430 \u043c\u043e\u0436\u043d\u043e \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a. \u041d\u0430 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043c\u043e\u0436\u043d\u043e \u0432\u0435\u0448\u0430\u0442\u044c \u0431\u0438\u0437\u043d\u0435\u0441 \u043b\u043e\u0433\u0438\u043a\u0443.<\/p>\n<p>  \u0421\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0438 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u044b \u043a\u043e\u043d\u0435\u0447\u043d\u043e\u0433\u043e \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0430<br \/>  <img decoding=\"async\" src=\"http:\/\/habr.habrastorage.org\/post_images\/db5\/8c4\/e85\/db58c4e853060a318d8ef14012b8802d.png\"\/><\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">HTML<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"html\">    &lt;div id=&quot;chat_wrapper&quot;&gt;         &lt;div id=&quot;template_idle&quot; class=&quot;template&quot;&gt;             &lt;div class=&quot;row text-center&quot;&gt;                 &lt;div&gt;                     &lt;h3&gt;\u0414\u043e\u0431\u0440\u043e \u043f\u043e\u0436\u0430\u043b\u043e\u0432\u0430\u0442\u044c \u0432 \u043d\u0430\u0448 \u0447\u0430\u0442!&lt;\/h3&gt;                     &lt;p&gt;\u0427\u0442\u043e\u0431\u044b \u043d\u0430\u0439\u0442\u0438 \u0441\u043e\u0431\u0435\u0441\u0435\u0434\u043d\u0438\u043a\u0430, \u043d\u0430\u0436\u043c\u0438\u0442\u0435 \u043a\u043d\u043e\u043f\u043a\u0443 &quot;\u041d\u0430\u0447\u0430\u0442\u044c \u0447\u0430\u0442&quot; \u0438 \u043f\u043e\u0434\u043e\u0436\u0434\u0438\u0442\u0435, \u043f\u043e\u043a\u0430 \u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u043e\u0434\u0431\u0435\u0440\u0435\u0442 \u0441\u043e\u0431\u0435\u0441\u0435\u0434\u043d\u0438\u043a\u0430&lt;\/p&gt;                     &lt;p&gt;\u0427\u0442\u043e\u0431\u044b \u043d\u0430\u0439\u0442\u0438 \u043d\u043e\u0432\u043e\u0433\u043e \u0441\u043e\u0431\u0435\u0441\u0435\u0434\u043d\u0438\u043a\u0430, \u043d\u0430\u0436\u043c\u0438\u0442\u0435 \u043a\u043d\u043e\u043f\u043a\u0443 &quot;\u0417\u0430\u043a\u043e\u043d\u0447\u0438\u0442\u044c \u0440\u0430\u0437\u0433\u043e\u0432\u043e\u0440&quot; \u0438 \u0441\u043d\u043e\u0432\u0430 \u043d\u0430\u0436\u043c\u0438\u0442\u0435 &quot;\u041d\u0430\u0447\u0430\u0442\u044c \u0447\u0430\u0442&quot;.&lt;\/p&gt;                     &lt;p&gt;\u0418\u0441\u0442\u043e\u0440\u0438\u044f \u0447\u0430\u0442\u0430 \u043d\u0435 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442\u0441\u044f. \u0420\u0430\u0437\u0432\u043b\u0435\u043a\u0430\u0439\u0442\u0435\u0441\u044c!&lt;\/p&gt;                 &lt;\/div&gt;                 &lt;a class=&quot;btn btn-large btn-primary begin-chat&quot;&gt;\u041d\u0430\u0447\u0430\u0442\u044c \u0447\u0430\u0442&lt;\/a&gt;             &lt;\/div&gt;         &lt;\/div&gt;         &lt;div id=&quot;template_wait&quot; class=&quot;template&quot;&gt;             &lt;div class=&quot;row text-center&quot;&gt;                 &lt;h3&gt;&lt;i class=&quot;fa fa-spin fa-refresh&quot;&gt;&lt;\/i&gt; \u041f\u043e\u0434\u043e\u0436\u0434\u0438\u0442\u0435&lt;\/h3&gt;                 &lt;span class=&quot;state&quot;&gt;&lt;\/span&gt;             &lt;\/div&gt;         &lt;\/div&gt;         &lt;div id=&quot;template_chat&quot; class=&quot;template&quot;&gt;             &lt;div class=&quot;row&quot;&gt;                 &lt;div class=&quot;message_box&quot; id=&quot;message_box&quot;&gt;&lt;\/div&gt;             &lt;\/div&gt;             &lt;div class=&quot;row well&quot;&gt;                 &lt;form id=&quot;send-msg-form&quot;&gt;                     &lt;div class=&quot;input-append&quot;&gt;                         &lt;textarea id=&quot;message&quot; rows=&quot;2&quot; placeholder=&quot;\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 (\u041e\u0442\u043f\u0440\u0430\u0432\u043a\u0430 \u043f\u043e Ctrl + Enter)&quot; required=&quot;required&quot; class=&quot;span6&quot;&gt;&lt;\/textarea&gt;                         &lt;button id=&quot;send-btn&quot; type=&quot;submit&quot; class=&quot;btn btn-primary btn-large has-spinner&quot;&gt;&lt;span class=&quot;spinner&quot;&gt;&lt;i class=&quot;fa fa-spin fa-refresh&quot;&gt;&lt;\/i&gt;&lt;\/span&gt;\u041e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c&lt;\/button&gt;                     &lt;\/div&gt;                     &lt;div class=&quot;text-center&quot;&gt;                         &lt;div class=&quot;show-chat&quot;&gt;&lt;a href=&quot;#&quot; class=&quot;btn btn-danger close-chat&quot;&gt;\u0417\u0430\u043a\u043e\u043d\u0447\u0438\u0442\u044c \u0440\u0430\u0437\u0433\u043e\u0432\u043e\u0440&lt;\/a&gt;&lt;\/div&gt;                         &lt;div class=&quot;show-closed&quot;&gt;\u0420\u0430\u0437\u0433\u043e\u0432\u043e\u0440 \u0437\u0430\u043a\u043e\u043d\u0447\u0435\u043d. &lt;a href=&quot;#&quot; class=&quot;btn btn-primary begin-chat&quot;&gt;\u041d\u0430\u0447\u0430\u0442\u044c \u0437\u0430\u043d\u043e\u0432\u043e&lt;\/a&gt;&lt;\/div&gt;                     &lt;\/div&gt;                 &lt;\/form&gt;             &lt;\/div&gt;         &lt;\/div&gt;     &lt;\/div&gt;     &lt;script type=&quot;text\/javascript&quot; src=&quot;{{ asset('bundles\/ismschat\/js\/chat-widget.js') }}&quot;&gt;&lt;\/script&gt;     &lt;script type=&quot;text\/javascript&quot;&gt;         $(document).ready(function(){             $('#chat_wrapper').chatWidget();         });     &lt;\/script&gt; <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<div class=\"spoiler\"><b class=\"spoiler_title\">chat-widget.js<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"javascript\">(function($) {     $.fn.extend({chatWidget: function(options){         var o = jQuery.extend({             wsUri: 'ws:\/\/'+location.host+':8080',             tmplClass: '.template',             tmplIdle: '#template_idle',             tmplWait: '#template_wait',             tmplChat: '#template_chat',             btnBeginChat: '.begin-chat',             labelWaitState: '.state',             messageBox: '#message_box',             formSend: '#send-msg-form',             textMessage: '#message',             btnCloseChat: '.close-chat'         },options);          var websocket, fsm;          var windowNotifier = function(){             var                 window_active = true,                 new_message = false;              $(window).blur(function(){                 window_active = false;             });             $(window).focus(function(){                 window_active = true;                 new_message = false;             });              var original = document.title;             window.setInterval(function() {                 if (new_message && window_active == false) {                     document.title = '***\u0421\u041e\u041e\u0411\u0429\u0415\u041d\u0418\u0415***';                     setTimeout(function(){                         document.title = original;                     }, 750);                 }             }, 1500);              return {                 setNewMessage: function() {                     new_message = true;                 }             };         } ();          var initSocket = function() {             websocket = new WebSocket(o.wsUri);             websocket.onopen = function(e) {                 fsm.request();             };             websocket.onclose \t= function(e){                 fsm.close();             };             websocket.onerror\t= function(e){                 console.log(e);                 if (websocket.readyState == 1) {                     websocket.close();                 }             };             websocket.onmessage = function(e) {                 var msg = JSON.parse(e.data);                 switch (msg.type) {                     case 'response':                         fsm.response();                         windowNotifier.setNewMessage();                         break;                     case 'message':                         chatController.addMessage(msg);                         if (msg.from == 'me') {                             chatController.unspinChat();                         } else {                             windowNotifier.setNewMessage();                         }                         $(o.textMessage).focus();                         break;                 }             }         };          var setView = function(tmpl) {             $(o.tmplClass).removeClass('active');             $(tmpl).addClass('active');         };          var idleController = function() {             $(o.btnBeginChat).click(function() {                 fsm.open();             });              return {                 show: function() {                     setView(o.tmplIdle);                 }             };         } ();          var waitController = function() {             return {                 show: function(label) {                     $(o.labelWaitState).text(label);                     setView(o.tmplWait);                 }             };         } ();          var chatController = function() {             $(o.textMessage).keydown(function (e) {                 if (e.ctrlKey && e.keyCode == 13) {                     $(o.formSend).trigger('submit');                 }             });              $(document).on('submit', o.formSend, function(e) {                 e.preventDefault();                 var text = $(o.textMessage).val();                 text = $.trim(text);                 if (!text) {                     return;                 }                 var msg = {                     type: 'message',                     message: text                 };                 websocket.send(JSON.stringify(msg));                 $(o.textMessage).val('');                 chatController.spinChat();             });              $(o.btnCloseChat).click(function(e) {                 websocket.close();             });              var htmlForTextWithEmbeddedNewlines = function(text) {                 var htmls = [];                 var lines = text.split(\/\\n\/);                 var tmpDiv = jQuery(document.createElement('div'));                 for (var i = 0 ; i &lt; lines.length ; i++) {                     htmls.push(tmpDiv.text(lines[i]).html());                 }                 return htmls.join(&quot;&lt;br&gt;&quot;);             };              return {                 clear: function() {                     $(o.messageBox).empty();                 },                 lockChat: function() {                     $(o.formSend).find(':input').attr('disabled', 'disabled');                 },                 unlockChat: function() {                     $(o.formSend).find(':input').removeAttr('disabled');                 },                 spinChat: function() {                     chatController.lockChat();                     $(o.formSend).find('.btn').addClass('active');                 },                 unspinChat: function() {                     $(o.formSend).find('.btn').removeClass('active');                     chatController.unlockChat();                 },                 showChat: function() {                     chatController.unlockChat();                     $('.show-closed').hide();                     $('.show-chat').show();                     setView(o.tmplChat);                 },                 showClosed: function() {                     chatController.lockChat();                     $('.show-chat').hide();                     $('.show-closed').show();                     setView(o.tmplChat);                 },                 addMessage: function(msg) {                     var d = new Date();                     var text = htmlForTextWithEmbeddedNewlines(msg.message);                     $(o.messageBox).append(                         '&lt;div&gt;' +                             '&lt;span class=&quot;user_name&quot;&gt;'+msg.from+'&lt;\/span&gt; : &lt;span class=&quot;user_message&quot;&gt;'+text + '&lt;\/span&gt;' +                             '&lt;span class=&quot;pull-right&quot;&gt;'+d.toLocaleTimeString()+'&lt;\/span&gt;' +                             '&lt;\/div&gt;'                     );                      $(o.messageBox).scrollTop($(o.messageBox)[0].scrollHeight);                 },                 addSystemMessage: function(msg) {                     $(o.messageBox).append('&lt;div class=&quot;system_msg&quot;&gt;'+msg+'&lt;\/div&gt;');                  }             };         } ();          fsm = StateMachine.create({             initial: 'idle',             events: [                 { name: 'open',  from: ['idle', 'closed'],  to: 'connecting' },                 { name: 'request',  from: 'connecting',  to: 'waiting' },                 { name: 'response',  from: 'waiting',  to: 'chat' },                 { name: 'close',  from: ['connecting', 'waiting'],  to: 'idle' },                 { name: 'close',  from: 'chat',  to: 'closed' }             ],             callbacks: {                 onidle: function(event, from, to) { idleController.show(); },                 onconnecting: function(event, from, to) { waitController.show('\u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043a \u0441\u0435\u0440\u0432\u0435\u0440\u0443'); },                 onwaiting: function(event, from, to) { waitController.show('\u041e\u0436\u0438\u0434\u0430\u043d\u0438\u0435 \u0441\u043e\u0431\u0435\u0441\u0435\u0434\u043d\u0438\u043a\u0430'); },                 onchat: function(event, from, to) { chatController.showChat(); },                 onclosed: function(event, from, to) { chatController.showClosed(); },                 onopen:  function(event, from, to) { initSocket(); },                 onrequest: function (event, from, to) {                     var msg = {                         type: 'request'                     };                     websocket.send(JSON.stringify(msg));                 },                 onresponse: function (event, from, to) {                     chatController.clear();                     chatController.addSystemMessage('\u0421\u043e\u0431\u0435\u0441\u0435\u0434\u043d\u0438\u043a \u043d\u0430\u0439\u0434\u0435\u043d - \u043e\u0431\u0449\u0430\u0439\u0442\u0435\u0441\u044c');                 },                 onclose: function (event, from, to) {                     chatController.addSystemMessage('\u0427\u0430\u0442 \u0437\u0430\u043a\u0440\u044b\u0442');                 }             }         });     }}) })(jQuery); <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<h4>\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442<\/h4>\n<p>  \u0427\u0430\u0442 \u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043e\u043a\u043e\u043b\u043e \u0434\u0432\u0443\u0445 \u043d\u0435\u0434\u0435\u043b\u044c. \u0414\u0435\u043c\u043e\u043d \u0440\u0430\u0441\u0445\u043e\u0434\u0443\u0435\u0442 50\u041c\u0411 \u043f\u0430\u043c\u044f\u0442\u044c \u0438 0,2% \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440\u0430.<br \/>  \u041b\u044e\u0434\u0438 \u0434\u043e\u043b\u044c\u0448\u0435 \u043e\u0441\u0442\u0430\u044e\u0442\u0441\u044f \u043d\u0430 \u0441\u0430\u0439\u0442\u0435, \u043e\u0431\u0449\u0430\u044e\u0442\u0441\u044f \u0438 \u0441\u0442\u0430\u0432\u044f\u0442 \u043b\u0430\u0439\u043a\u0438. \u041f\u0440\u0438\u0433\u043b\u0430\u0448\u0430\u044e \u0438 \u0432\u0430\u0441 <a href=\"http:\/\/internetsms.org\/chat\">\u043f\u043e\u043e\u0431\u0449\u0430\u0442\u044c\u0441\u044f<\/a>!<\/p>\n<p>  \u0421\u043f\u0430\u0441\u0438\u0431\u043e \u0437\u0430 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435!    \t<\/p>\n<div class=\"clear\"><\/div>\n<\/p><\/div>\n<p> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"http:\/\/habrahabr.ru\/post\/205934\/\"> http:\/\/habrahabr.ru\/post\/205934\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div class=\"content html_format\">   \t\u041f\u0440\u0438\u0432\u0435\u0442 \u0425\u0430\u0431\u0440!<br \/>  \u041d\u0435\u0434\u0430\u0432\u043d\u043e \u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u043b \u0447\u0430\u0442 \u043d\u0430 \u0432\u0435\u0431\u0441\u043e\u043a\u0435\u0442\u0430\u0445 \u0434\u043b\u044f \u0441\u0432\u043e\u0435\u0433\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u0430 <a href=\"http:\/\/internetsms.org\/chat\">http:\/\/internetsms.org\/chat<\/a>.<br \/>  \u041f\u0440\u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438, \u044f \u0441\u0442\u043e\u043b\u043a\u043d\u0443\u043b\u0441\u044f \u0441 \u0442\u0435\u043c, \u0447\u0442\u043e \u0432 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0435 \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u043e \u0447\u0430\u0442\u043e\u0432 \u0441\u0434\u0435\u043b\u0430\u043d\u044b \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u043f\u043e\u0432\u0442\u043e\u0440\u044f\u044e\u0449\u0438\u0445\u0441\u044f ajax \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u044e\u0442 \u043d\u043e\u0432\u044b\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043f\u043e \u0437\u0430\u0434\u0430\u043d\u043d\u043e\u043c\u0443 \u043f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043a\u0443 \u0432\u0440\u0435\u043c\u0435\u043d\u0438. \u0422\u0430\u043a\u043e\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u0434\u043b\u044f \u043c\u0435\u043d\u044f \u0431\u044b\u043b \u043d\u0435\u043f\u0440\u0438\u0435\u043c\u043b\u0435\u043c, \u0442.\u043a \u043f\u0440\u0438 \u043d\u0430\u043f\u043b\u044b\u0432\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439, \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440 \u0432\u044b\u0440\u0430\u0441\u0442\u0435\u0442 \u044d\u043a\u0441\u043f\u043e\u043d\u0435\u043d\u0446\u0438\u0430\u043b\u044c\u043d\u043e. \u041d\u0430 \u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435, \u0435\u0441\u0442\u044c \u0431\u043e\u043b\u0435\u0435 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0435 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438:<br \/>  <b>Long polling<\/b><br \/>  \u041a\u043b\u0438\u0435\u043d\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440 \u00ab\u0434\u043e\u043b\u0433\u0438\u0439\u00bb \u0437\u0430\u043f\u0440\u043e\u0441, \u0438 \u043f\u0440\u0438 \u043d\u0430\u043b\u0438\u0447\u0438\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439, \u0441\u0435\u0440\u0432\u0435\u0440 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u043e\u0442\u0432\u0435\u0442. \u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u0447\u0438\u0441\u043b\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0441\u043d\u0438\u0436\u0430\u0435\u0442\u0441\u044f. \u041a\u0441\u0442\u0430\u0442\u0438, \u044d\u0442\u0430 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0432 Gmail.<br \/>  <b>Web sockets<\/b><br \/>  \u0412 html5 \u043f\u043e\u044f\u0432\u0438\u043b\u0430\u0441\u044c \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u0430\u044f \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c WebSocket \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f. \u041f\u0430\u0440\u0430\u0434\u0438\u0433\u043c\u0430 \u0437\u0430\u043f\u0440\u043e\u0441-\u043e\u0442\u0432\u0435\u0442 \u0437\u0434\u0435\u0441\u044c \u0432\u043e\u043e\u0431\u0449\u0435 \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f. \u041c\u0435\u0436\u0434\u0443 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u043c \u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c \u043e\u0434\u0438\u043d \u0440\u0430\u0437 \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043a\u0430\u043d\u0430\u043b \u0441\u0432\u044f\u0437\u0438. \u041d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043e\u0434\u0438\u043d \u0434\u0435\u043c\u043e\u043d, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u0432\u0445\u043e\u0434\u044f\u0449\u0438\u0435 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f. \u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440 \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043d\u0435\u0442 \u0434\u0430\u0436\u0435 \u043f\u0440\u0438 \u0431\u043e\u043b\u044c\u0448\u043e\u043c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u043e\u043d\u043b\u0430\u0439\u043d.  <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-205934","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/205934","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=205934"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/205934\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=205934"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=205934"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=205934"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}