{"id":273795,"date":"2016-02-08T11:31:03","date_gmt":"2016-02-08T08:31:03","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=273795"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=273795","title":{"rendered":"\u041f\u0438\u0448\u0435\u043c \u0447\u0430\u0442 \u043d\u0430 Vert.x 3"},"content":{"rendered":"<p>       \u041d\u0430 \u0425\u0430\u0431\u0440\u0435 \u043d\u0435 \u0442\u0430\u043a \u0443\u0436 \u043c\u043d\u043e\u0433\u043e \u0441\u0442\u0430\u0442\u0435\u0439, \u043f\u043e\u0441\u0432\u044f\u0449\u0435\u043d\u043d\u044b\u0445 Vert.x, <a href=\"https:\/\/habrahabr.ru\/post\/218733\/\">\u0440\u0430\u0437<\/a>, <a href=\"https:\/\/habrahabr.ru\/post\/181686\/\">\u0434\u0432\u0430<\/a> \u0438 \u043e\u0431\u0447\u0451\u043b\u0441\u044f. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0440\u0435\u0448\u0438\u043b \u0432\u043d\u0435\u0441\u0442\u0438 \u0441\u0432\u043e\u0439 \u0432\u043a\u043b\u0430\u0434 \u0438 \u043e\u043f\u0443\u0431\u043b\u0438\u043a\u043e\u0432\u0430\u0442\u044c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0443\u0440\u043e\u043a, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u0430\u043d\u043e, \u043a\u0430\u043a \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u0447\u0430\u0442 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Vert.x 3.<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/files\/e8a\/0b2\/894\/e8a0b2894b6b415293cddd1f59c7ef87.png\"\/><br \/>  <a name=\"habracut\"><\/a>  <\/p>\n<h4>\u0421\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435<\/h4>\n<p>  <\/p>\n<ol>\n<li><a href=\"#whatIs\">\u0427\u0442\u043e \u0442\u0430\u043a\u043e\u0435 Vert.x?<\/a><\/li>\n<li><a href=\"#about\">\u041e \u0447\u0430\u0442\u0435<\/a><\/li>\n<li><a href=\"#structure\">\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/a><\/li>\n<li><a href=\"#server\">\u0421\u0435\u0440\u0432\u0435\u0440<\/a><\/li>\n<li><a href=\"#client\">\u041a\u043b\u0438\u0435\u043d\u0442<\/a><\/li>\n<li><a href=\"#testing\">\u0422\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435<\/a><\/li>\n<li><a href=\"#building\">\u0421\u0431\u043e\u0440\u043a\u0430 \u0438 \u0437\u0430\u043f\u0443\u0441\u043a \u0438\u0441\u043f\u043e\u043b\u043d\u044f\u0435\u043c\u043e\u0433\u043e \u043c\u043e\u0434\u0443\u043b\u044f<\/a><\/li>\n<li><a href=\"#source\">\u041f\u043e\u043b\u043d\u044b\u0439 \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434<\/a><\/li>\n<li><a href=\"#resources\">\u041f\u043e\u043b\u0435\u0437\u043d\u044b\u0435 \u0440\u0435\u0441\u0443\u0440\u0441\u044b<\/a><\/li>\n<\/ol>\n<p>  <a name=\"whatIs\"><\/a><\/p>\n<h4>\u0427\u0442\u043e \u0442\u0430\u043a\u043e\u0435 Vert.x?<\/h4>\n<p>  Vert.x \u044d\u0442\u043e \u0441\u043e\u0431\u044b\u0442\u0438\u0439\u043d\u043e-\u043e\u0440\u0438\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0438\u0439 \u043d\u0430 JVM. \u041d\u0430 \u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u044f\u044f \u0432\u0435\u0440\u0441\u0438\u044f \u044d\u0442\u043e\u0433\u043e \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430 3.2. Vert.x 3 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438:<\/p>\n<ul>\n<li><b>\u041c\u0443\u043b\u044c\u0442\u0438\u044f\u0437\u044b\u0447\u043d\u043e\u0441\u0442\u044c<\/b>. \u041a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u043d\u044b \u043d\u0430 Java, JavaScript, Scala, Python, Ruby, Groovy, \u0430 \u0442\u0430\u043a\u0436\u0435 Clojure;<\/li>\n<li><b>\u041f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u0438\u0437\u043c<\/b>. \u0414\u043e\u0432\u043e\u043b\u044c\u043d\u043e-\u0442\u0430\u043a\u0438 \u043f\u0440\u043e\u0441\u0442\u0430\u044f \u043c\u043e\u0434\u0435\u043b\u044c \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u0438\u0437\u043c\u0430, \u043e\u0441\u0432\u043e\u0431\u043e\u0436\u0434\u0430\u044e\u0449\u0430\u044f \u043e\u0442 \u0445\u043b\u043e\u043f\u043e\u0442 \u043c\u043d\u043e\u0433\u043e\u043f\u043e\u0442\u043e\u0447\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f;<\/li>\n<li><b>\u0410\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0441\u0442\u044c<\/b>. \u041f\u0440\u043e\u0441\u0442\u0430\u044f \u043c\u043e\u0434\u0435\u043b\u044c \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0433\u043e \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0431\u0435\u0437 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0438;<\/li>\n<li><b>\u0420\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u0430\u044f \u0448\u0438\u043d\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u0439<\/b>. \u0412\u043a\u043b\u044e\u0447\u0430\u044e\u0449\u0430\u044f \u043a\u0430\u043a \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u0443\u044e, \u0442\u0430\u043a \u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u0443\u044e \u0441\u0442\u043e\u0440\u043e\u043d\u044b. \u0418\u0433\u0440\u0430\u0435\u0442 \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0433\u043b\u0430\u0432\u043d\u0443\u044e \u0440\u043e\u043b\u044c \u0432 \u043d\u0430\u0448\u0435\u043c \u0447\u0430\u0442\u0435;<\/li>\n<li><b>Java 8<\/b>. Vert.x 3 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0432\u0435\u0440\u0441\u0438\u0438 Java \u043d\u0435 \u043d\u0438\u0436\u0435 8.<\/li>\n<\/ul>\n<p>  <a name=\"about\"><\/a><\/p>\n<h4>\u0411\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u043e \u0447\u0430\u0442\u0435<\/h4>\n<p>  \u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435, \u043f\u043e\u0441\u043b\u0435 \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f \u043f\u0443\u0431\u043b\u0438\u043a\u0443\u0435\u0442\u0441\u044f \u0430\u0434\u0440\u0435\u0441 \u0430\u043d\u043e\u043d\u0438\u043c\u043d\u043e\u0433\u043e \u0447\u0430\u0442\u0430, \u043a \u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443 \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u0438\u0441\u043e\u0435\u0434\u0438\u043d\u0438\u0442\u044c\u0441\u044f, \u0447\u0435\u0440\u0435\u0437 \u043b\u044e\u0431\u043e\u0439 \u0431\u0440\u0430\u0443\u0437\u0435\u0440. \u041f\u043e \u044d\u0442\u043e\u043c\u0443 \u0430\u0434\u0440\u0435\u0441\u0443 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0442\u0440\u0430\u043d\u0441\u043b\u0438\u0440\u0443\u0435\u0442 \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043e\u0442 \u0432\u0441\u0435\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439.<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/files\/7f7\/d71\/33b\/7f7d7133baff4cc2b4176aba39dab2bb.PNG\"\/><\/p>\n<h4>\u041f\u043e\u0435\u0445\u0430\u043b\u0438!<\/h4>\n<p>  \u0420\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u0431\u0443\u0434\u0435\u043c \u0432\u0435\u0441\u0442\u0438 \u0432 IntelliJ IDEA 15, \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e <a href=\"https:\/\/www.jetbrains.com\/idea\/download\/\">Community-\u0432\u0435\u0440\u0441\u0438\u0438<\/a>.<\/p>\n<p>  <a name=\"structure\"><\/a><\/p>\n<h4>\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/h4>\n<p>  \u0421\u043e\u0437\u0434\u0430\u0435\u043c maven-\u043f\u0440\u043e\u0435\u043a\u0442. \u041a \u0441\u043e\u0436\u0430\u043b\u0435\u043d\u0438\u044e \u0433\u043e\u0442\u043e\u0432\u043e\u0433\u043e \u0430\u0440\u0445\u0435\u0442\u0438\u043f\u0430, \u0434\u043b\u044f vert.x 3 \u043d\u0435\u0442 (\u0445\u043e\u0442\u044f \u0434\u043b\u044f 2 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442), \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0433\u0435\u043d\u0435\u0440\u0438\u043c \u043e\u0431\u044b\u0447\u043d\u044b\u0439 maven-\u043f\u0440\u043e\u0435\u043a\u0442. \u0415\u0433\u043e \u043a\u043e\u043d\u0435\u0447\u043d\u0430\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0431\u0443\u0434\u0435\u0442 \u0438\u043c\u0435\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0432\u0438\u0434:<\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"bash\">src +---main |   +---java |   |   |   Server.java |   |   |   VerticleLoader.java |   |   | |   |   \\---webroot |   |           date-format.js |   |           index.html |   |           vertx-eventbus.js |   | |   \\---resources \\---test     \\---java             ChatTest.java <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u0412 pom.xml \u0437\u0430\u0434\u0430\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438. \u0413\u0434\u0435 <i>vertx-core<\/i> \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0438 Verticles (\u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e, \u0447\u0442\u043e \u044d\u0442\u043e \u0442\u0430\u043a\u043e\u0435, \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0434\u0430\u043b\u044c\u0448\u0435), <i>vertx-web<\/i> \u2013 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0441\u043e\u0431\u044b\u0442\u0438\u0439 (\u0438 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e) \u0438 <i>vertx-unit<\/i> \u2013 \u0434\u043b\u044f \u043c\u043e\u0434\u0443\u043b\u044c\u043d\u043e\u0433\u043e \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f.<\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">pom.xml<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"xml\">&lt;dependencies&gt;     &lt;dependency&gt;         &lt;groupId&gt;io.vertx&lt;\/groupId&gt;         &lt;artifactId&gt;vertx-core&lt;\/artifactId&gt;         &lt;version&gt;3.0.0&lt;\/version&gt;     &lt;\/dependency&gt;      &lt;dependency&gt;         &lt;groupId&gt;io.vertx&lt;\/groupId&gt;         &lt;artifactId&gt;vertx-web&lt;\/artifactId&gt;         &lt;version&gt;3.0.0&lt;\/version&gt;     &lt;\/dependency&gt;      &lt;dependency&gt;         &lt;groupId&gt;io.vertx&lt;\/groupId&gt;         &lt;artifactId&gt;vertx-unit&lt;\/artifactId&gt;         &lt;version&gt;3.0.0&lt;\/version&gt;         &lt;scope&gt;test&lt;\/scope&gt;     &lt;\/dependency&gt; &lt;\/dependencies&gt; <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  <a name=\"server\"><\/a><\/p>\n<h4>\u0421\u0435\u0440\u0432\u0435\u0440<\/h4>\n<p>  \u041e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u044c\u044e \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0442\u043e, \u0447\u0442\u043e \u0432\u0441\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0431\u044b\u0442\u044c \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u044b \u0432 \u0432\u0438\u0434\u0435 Verticle.<\/p>\n<p>  Verticle \u2013 \u044d\u0442\u043e \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0430\u043d\u0430\u043b\u043e\u0433 \u0441\u0435\u0440\u0432\u043b\u0435\u0442\u0430, \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0430\u0442\u043e\u043c\u0430\u0440\u043d\u043e\u0439 \u0435\u0434\u0438\u043d\u0438\u0446\u0435\u0439 \u0440\u0430\u0437\u0432\u0451\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f. \u0421\u0430\u043c\u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u044e\u0442 Verticle, \u043a\u0430\u043a \u043d\u0435\u0447\u0442\u043e \u043f\u043e\u0445\u043e\u0436\u0435\u0435 \u043d\u0430 \u0430\u043a\u0442\u0435\u0440\u0430 \u0432 \u043c\u043e\u0434\u0435\u043b\u0438 <a href=\"https:\/\/ru.wikipedia.org\/wiki\/%D0%9C%D0%BE%D0%B4%D0%B5%D0%BB%D1%8C_%D0%B0%D0%BA%D1%82%D0%BE%D1%80%D0%BE%D0%B2\">\u0430\u043a\u0442\u043e\u0440\u043e\u0432<\/a>. \u0421\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u044d\u0442\u0430 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0432\u044b\u0441\u043e\u043a\u0443\u044e \u0441\u0442\u0435\u043f\u0435\u043d\u044c \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u0438\u0437\u043c\u0430 \u0438 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0441\u0442\u0438, \u0447\u0435\u043c \u0438 \u0441\u043b\u0430\u0432\u0438\u0442\u0441\u044f Vert.x. \u0412 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043d\u0430\u0448\u0435\u0433\u043e \u0441\u0435\u0440\u0432\u0435\u0440\u0430, \u043c\u044b \u043d\u0430\u0441\u043b\u0435\u0434\u0443\u0435\u043c \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0442\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 AbstractVerticle.<\/p>\n<p>  \u041f\u0435\u0440\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c\u044b\u0439 \u043d\u0430\u043c\u0438 \u043c\u0435\u0442\u043e\u0434 start() \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0442\u043e\u0447\u043a\u043e\u0439 \u0432\u0445\u043e\u0434\u0430 \u0432 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0443. \u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u2013 \u0444\u0443\u043d\u043a\u0446\u0438\u044f deploy(), \u0437\u0430\u0442\u0435\u043c \u0432\u0435\u0448\u0430\u0435\u0442\u0441\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u2013 \u043c\u0435\u0442\u043e\u0434 handle().<\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">Server.java<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"java\">public class Server extends AbstractVerticle {     private Logger log = LoggerFactory.getLogger(Server.class);     private SockJSHandler handler = null;     private AtomicInteger online = new AtomicInteger(0);      \/\/\u0442\u043e\u0447\u043a\u0430 \u0432\u0445\u043e\u0434\u0430.     @Override     public void start() throws Exception {          if (!deploy()) {             log.error(&quot;Failed to deploy the server.&quot;);             return;         }          handle();     }      \/\/... } <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u0414\u043b\u044f \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0441\u0432\u043e\u0431\u043e\u0434\u043d\u044b\u0439 \u043f\u043e\u0440\u0442, \u0432 \u0441\u043b\u0443\u0447\u0430\u0435, \u0435\u0441\u043b\u0438 \u043d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0435\u0433\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c, \u0432 hostPort \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u0440\u0438\u0446\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435. \u0414\u0430\u043b\u0435\u0435 \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u0440\u043e\u0443\u0442\u0435\u0440, \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u0434\u043b\u044f \u043d\u0435\u0433\u043e \u0430\u0434\u0440\u0435\u0441 \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u0435\u043b\u044f \u0438 \u0432\u0435\u0448\u0430\u0435\u043c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a. \u0418 \u043d\u0430\u043a\u043e\u043d\u0435\u0446, \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c HTTP-Server \u043d\u0430 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e\u043c \u043f\u043e\u0440\u0442\u0443.<\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">Server.java<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"java\">\/\/\u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. private boolean deploy() {     int hostPort = getFreePort();      if (hostPort &lt; 0)         return false;      Router router = Router.router(vertx);      \/\/\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0441\u043e\u0431\u044b\u0442\u0438\u0439.     handler = SockJSHandler.create(vertx);      router.route(&quot;\/eventbus\/*&quot;).handler(handler);     router.route().handler(StaticHandler.create());      \/\/\u0437\u0430\u043f\u0443\u0441\u043a \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0435\u0440\u0430.     vertx.createHttpServer().requestHandler(router::accept).listen(hostPort);      try {         String addr = InetAddress.getLocalHost().getHostAddress();         log.info(&quot;Access to \\&quot;CHAT\\&quot; at the following address: \\nhttp:\/\/&quot; + addr + &quot;:&quot; + hostPort);     } catch (UnknownHostException e) {         log.error(&quot;Failed to get the local address: [&quot; + e.toString() + &quot;]&quot;);         return false;     }      return true; } <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u041f\u0440\u043e\u0446\u0435\u0441\u0441 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0441\u0432\u043e\u0431\u043e\u0434\u043d\u043e\u0433\u043e \u043f\u043e\u0440\u0442\u0430 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d \u0432\u043e \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u0435 \u043a\u043e\u0434\u0430 \u043d\u0438\u0436\u0435. \u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442\u0441\u044f static-\u043f\u043e\u043b\u0435 PROCESS_ARGS \u043d\u0430 \u043d\u0430\u043b\u0438\u0447\u0438\u0435 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u043e\u0434\u043d\u0438\u043c \u0438\u0437 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043f\u043e\u0440\u0442 \u0440\u0430\u0437\u0432\u0451\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0437\u0430\u0434\u0430\u043d\u043d\u044b\u0439 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u043c. \u0412 \u0441\u043b\u0443\u0447\u0430\u0435, \u0435\u0441\u043b\u0438 \u043f\u043e\u0440\u0442 \u043d\u0435 \u0431\u044b\u043b \u0437\u0430\u0434\u0430\u043d, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043f\u043e\u0440\u0442 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e: 8080.<\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">Server.java<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"java\">\/\/\u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0441\u0432\u043e\u0431\u043e\u0434\u043d\u043e\u0433\u043e \u043f\u043e\u0440\u0442\u0430 \u0434\u043b\u044f \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. private int getFreePort() {     int hostPort = 8080;      \/\/\u0435\u0441\u043b\u0438 \u043f\u043e\u0440\u0442 \u0437\u0430\u0434\u0430\u043d \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0430,     \/\/ \u043f\u0440\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.     if (Starter.PROCESS_ARGS != null             && Starter.PROCESS_ARGS.size() &gt; 0) {         try {             hostPort = Integer.valueOf(Starter.PROCESS_ARGS.get(0));         } catch (NumberFormatException e) {             log.warn(&quot;Invalid port: [&quot; + Starter.PROCESS_ARGS.get(0) + &quot;]&quot;);         }     }      \/\/\u0435\u0441\u043b\u0438 \u043d\u0435\u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e \u0443\u043a\u0430\u0437\u0430\u043d \u043f\u043e\u0440\u0442.     if (hostPort &lt; 0 || hostPort &gt; 65535)         hostPort = 8080;      return getFreePort(hostPort); } <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u0415\u0441\u043b\u0438 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0430 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0430 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0441\u043e\u043a\u0435\u0442\u0430, \u0443\u043a\u0430\u0437\u0430\u043d \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u0441\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435\u043c 0, \u0442\u043e \u0432 \u0442\u0430\u043a\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0434\u0430\u043d \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u044b\u0439 \u0441\u0432\u043e\u0431\u043e\u0434\u043d\u044b\u0439 \u043f\u043e\u0440\u0442.<\/p>\n<p>  \u041a\u043e\u0433\u0434\u0430 \u043f\u043e\u0440\u0442 \u0443\u0436\u0435 \u0437\u0430\u043d\u044f\u0442 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043f\u043e\u0440\u0442 8080 \u0443\u0436\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0434\u0440\u0443\u0433\u0438\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c, \u043d\u043e \u043f\u0440\u0438 \u044d\u0442\u043e\u043c, \u043e\u043d \u0443\u043a\u0430\u0437\u0430\u043d \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0430 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f), \u0432\u044b\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 BindException, \u0432 \u0442\u0430\u043a\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u0430\u044f \u043f\u043e\u043f\u044b\u0442\u043a\u0430 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0441\u0432\u043e\u0431\u043e\u0434\u043d\u043e\u0433\u043e \u043f\u043e\u0440\u0442\u0430.<\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">Server.java<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"java\">private int getFreePort(int hostPort) {     try {         ServerSocket socket = new ServerSocket(hostPort);         int port = socket.getLocalPort();         socket.close();          return port;     } catch (BindException e) {         \/\/\u0441\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442, \u043a\u043e\u0433\u0434\u0430 \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u0439 \u043f\u043e\u0440\u0442 \u0443\u0436\u0435 \u0437\u0430\u043d\u044f\u0442.         if (hostPort != 0)             return getFreePort(0);          log.error(&quot;Failed to get the free port: [&quot; + e.toString() + &quot;]&quot;);         return -1;     } catch (IOException e) {         log.error(&quot;Failed to get the free port: [&quot; + e.toString() + &quot;]&quot;);         return -1;     } } <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u0412 \u0441\u043b\u0443\u0447\u0430\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0433\u043e \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f, \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442\u0441\u044f \u043f\u0440\u043e\u0441\u043b\u0443\u0448\u0438\u0432\u0430\u043d\u0438\u0435 \u0448\u0438\u043d\u044b \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u043f\u043e \u0430\u0434\u0440\u0435\u0441\u0430\u043c: chat.to.server (\u0432\u0445\u043e\u0434\u044f\u0449\u0438\u0435 \u0441\u043e\u0431\u044b\u0442\u0438\u044f) \u0438 chat.to.client (\u0438\u0441\u0445\u043e\u0434\u044f\u0449\u0438\u0435 \u0441\u043e\u0431\u044b\u0442\u0438\u044f).<\/p>\n<p>  \u041f\u043e\u0441\u043b\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043e\u0447\u0435\u0440\u0435\u0434\u043d\u043e\u0433\u043e \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u043d\u0430 \u0448\u0438\u043d\u0435, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0447\u0435\u043a\u043d\u0443\u0442\u044c \u044d\u0442\u043e \u0441\u043e\u0431\u044b\u0442\u0438\u0435.<\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">Server.java<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"java\">private void handle() {     BridgeOptions opts = new BridgeOptions()             .addInboundPermitted(new PermittedOptions().setAddress(&quot;chat.to.server&quot;))             .addOutboundPermitted(new PermittedOptions().setAddress(&quot;chat.to.client&quot;));      \/\/\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043f\u0440\u0438\u0445\u043e\u0434\u044f\u0449\u0438\u0445 \u0441\u043e\u0431\u044b\u0442\u0438\u0439.     handler.bridge(opts, event -&gt; {         if (event.type() == PUBLISH)             publishEvent(event);          if (event.type() == REGISTER)             registerEvent(event);          if (event.type() == SOCKET_CLOSED)             closeEvent(event);          \/\/\u043e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u043f\u043e\u0441\u043b\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u044f         \/\/ \u0434\u043e\u043b\u0436\u0435\u043d \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u0433\u043e\u0432\u043e\u0440\u044f\u0449\u0438\u0439 \u0441\u0430\u043c \u0437\u0430 \u0441\u0435\u0431\u044f \u043c\u0435\u0442\u043e\u0434.         event.complete(true);     }); } <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u041b\u044e\u0431\u044b\u0435 \u0441\u043e\u0431\u044b\u0442\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u044f\u0442 \u043d\u0430 \u0448\u0438\u043d\u0435, \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u044b 7 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c\u0438 \u0442\u0438\u043f\u0430\u043c\u0438:  <\/p>\n<table>\n<tr>\n<th>\u0422\u0438\u043f<\/th>\n<th>\u0421\u043e\u0431\u044b\u0442\u0438\u0435<\/th>\n<\/tr>\n<tr>\n<td>SOCKET_CREATED<\/td>\n<td>\u0432\u043e\u0437\u043d\u0438\u043a\u0430\u0435\u0442 \u043f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u0441\u043e\u043a\u0435\u0442\u0430<\/td>\n<\/tr>\n<tr>\n<td>SOCKET_CLOSED<\/td>\n<td>\u043f\u0440\u0438 \u0437\u0430\u043a\u0440\u044b\u0442\u0438\u0438 \u0441\u043e\u043a\u0435\u0442\u0430<\/td>\n<\/tr>\n<tr>\n<td>SEND<\/td>\n<td>\u043f\u043e\u043f\u044b\u0442\u043a\u0430 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043e\u0442 \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u043a \u0441\u0435\u0440\u0432\u0435\u0440\u0443<\/td>\n<\/tr>\n<tr>\n<td>PUBLISH<\/td>\n<td>\u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u044f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u043c \u0434\u043b\u044f \u0441\u0435\u0440\u0432\u0435\u0440\u0430<\/td>\n<\/tr>\n<tr>\n<td>RECEIVE<\/td>\n<td>\u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0435 \u043e\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430, \u043e \u0434\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043d\u043e\u043c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0438<\/td>\n<\/tr>\n<tr>\n<td>REGISTER<\/td>\n<td>\u043f\u043e\u043f\u044b\u0442\u043a\u0430 \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a<\/td>\n<\/tr>\n<tr>\n<td>UNREGISTER<\/td>\n<td>\u043f\u043e\u043f\u044b\u0442\u043a\u0430 \u043e\u0442\u043c\u0435\u043d\u0438\u0442\u044c \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a<\/td>\n<\/tr>\n<\/table>\n<p>  \u0412 \u043d\u0430\u0448\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u043d\u0430\u043c \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043b\u0438\u0448\u044c \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u0441 \u0442\u0438\u043f\u043e\u043c PUBLISH, REGISTER \u0438 SOCKET_CLOSED.<\/p>\n<p>  \u0421\u043e\u0431\u044b\u0442\u0438\u0435 \u0441 \u0442\u0438\u043f\u043e\u043c PUBLISH \u0441\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442, \u043a\u043e\u0433\u0434\u0430 \u043a\u0442\u043e-\u0442\u043e \u0438\u0437 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0432 \u0447\u0430\u0442. <br \/>  REGISTER \u2013 \u0441\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u0442\u043e\u0433\u0434\u0430, \u043a\u043e\u0433\u0434\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u0443\u0435\u0442 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a. \u041f\u043e\u0447\u0435\u043c\u0443 \u043d\u0435 SOCKET_CREATED? \u041f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e, \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u0441 \u0442\u0438\u043f\u043e\u043c SOCKET_CREATED \u043f\u0440\u0435\u0434\u0448\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u2013 REGISTER, \u0438, \u0435\u0441\u0442\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u043f\u043e\u043a\u0430 \u043a\u043b\u0438\u0435\u043d\u0442 \u043d\u0435 \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u0443\u0435\u0442 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a, \u043e\u043d \u043d\u0435 \u0441\u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0441\u043e\u0431\u044b\u0442\u0438\u044f.<br \/>  SOCKET_CLOSED \u2013 \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u0435\u0442, \u0432\u0441\u0435\u0433\u0434\u0430 \u043a\u043e\u0433\u0434\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043f\u043e\u043a\u0438\u0434\u0430\u0435\u0442 \u0447\u0430\u0442 \u0438\u043b\u0438 \u043a\u043e\u0433\u0434\u0430 \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u0435\u0442 \u043d\u0435\u043f\u0440\u0435\u0434\u0432\u0438\u0434\u0435\u043d\u043d\u0430\u044f \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u044f.<\/p>\n<p>  \u041f\u0440\u0438 \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f, \u0441\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0438 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 \u043c\u0435\u0442\u043e\u0434 publishEvent. \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442\u0441\u044f \u0430\u0434\u0440\u0435\u0441 \u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f, \u0432 \u0441\u043b\u0443\u0447\u0430\u0435, \u0435\u0441\u043b\u0438 \u043e\u043d \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u0435\u043d, \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0438\u0437\u0432\u043b\u0435\u043a\u0430\u0435\u0442\u0441\u044f, \u0437\u0430\u0442\u0435\u043c \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442\u0441\u044f \u0438 \u043f\u0443\u0431\u043b\u0438\u043a\u0443\u0435\u0442\u0441\u044f \u043d\u0430 \u0448\u0438\u043d\u0435 \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432 (\u0432 \u0442.\u0447. \u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u0435\u043b\u044f). <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">Server.java<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"java\">private boolean publishEvent(BridgeEvent event) {     if (event.rawMessage() != null             && event.rawMessage().getString(&quot;address&quot;).equals(&quot;chat.to.server&quot;)) {         String message = event.rawMessage().getString(&quot;body&quot;);         if (!verifyMessage(message))             return false;          String host = event.socket().remoteAddress().host();         int port = event.socket().remoteAddress().port();          Map&lt;String, Object&gt; publicNotice = createPublicNotice(host, port, message);         vertx.eventBus().publish(&quot;chat.to.client&quot;, new Gson().toJson(publicNotice));         return true;     } else         return false; } <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u0413\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f \u0434\u043b\u044f \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">Server.java<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"java\">\/\/\u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f \u043e \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f. private Map&lt;String, Object&gt; createPublicNotice(String host, int port, String message) {     Date time = Calendar.getInstance().getTime();      Map&lt;String, Object&gt; notice = new TreeMap&lt;&gt;();     notice.put(&quot;type&quot;, &quot;publish&quot;);     notice.put(&quot;time&quot;, time.toString());     notice.put(&quot;host&quot;, host);     notice.put(&quot;port&quot;, port);     notice.put(&quot;message&quot;, message);     return notice; } <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u0412\u0445\u043e\u0434 \u0438 \u0432\u044b\u0445\u043e\u0434 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0432 \u0447\u0430\u0442 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u043c:<\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">Server.java<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"java\">\/\/\u0442\u0438\u043f \u0441\u043e\u0431\u044b\u0442\u0438\u044f - \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430. private void registerEvent(BridgeEvent event) {     if (event.rawMessage() != null             && event.rawMessage().getString(&quot;address&quot;).equals(&quot;chat.to.client&quot;))         new Thread(() -&gt;         {             Map&lt;String, Object&gt; registerNotice = createRegisterNotice();             vertx.eventBus().publish(&quot;chat.to.client&quot;, new Gson().toJson(registerNotice));         }).start(); }  \/\/\u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f \u043e \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f. private Map&lt;String, Object&gt; createRegisterNotice() {     Map&lt;String, Object&gt; notice = new TreeMap&lt;&gt;();     notice.put(&quot;type&quot;, &quot;register&quot;);     notice.put(&quot;online&quot;, online.incrementAndGet());     return notice; }  \/\/\u0442\u0438\u043f \u0441\u043e\u0431\u044b\u0442\u0438\u044f - \u0437\u0430\u043a\u0440\u044b\u0442\u0438\u0435 \u0441\u043e\u043a\u0435\u0442\u0430. private void closeEvent(BridgeEvent event) {     new Thread(() -&gt;     {         Map&lt;String, Object&gt; closeNotice = createCloseNotice();         vertx.eventBus().publish(&quot;chat.to.client&quot;, new Gson().toJson(closeNotice));     }).start(); }  \/\/\u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f \u043e \u0432\u044b\u0445\u043e\u0434\u0435 \u043f\u043e\u043b\u044c\u0437\u0432\u0430\u0442\u0435\u043b\u044f \u0438\u0437 \u0447\u0430\u0442\u0430. private Map&lt;String, Object&gt; createCloseNotice() {     Map&lt;String, Object&gt; notice = new TreeMap&lt;&gt;();     notice.put(&quot;type&quot;, &quot;close&quot;);     notice.put(&quot;online&quot;, online.decrementAndGet());     return notice; } <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043f\u0443\u0431\u043b\u0438\u043a\u0443\u0435\u043c\u043e\u0433\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u0440\u0438\u043c\u0438\u0442\u0438\u0432\u043d\u0430\u044f, \u043d\u043e \u0434\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u0438 \u044d\u0442\u043e\u0433\u043e \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e, \u0442.\u0435. \u0432\u044b \u0435\u0451 \u043c\u043e\u0436\u0435\u0442\u0435 \u0441\u0430\u043c\u0438 \u0443\u0441\u043b\u043e\u0436\u043d\u0438\u0442\u044c \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u044f, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043d\u0430 \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0443 \u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0432 \u0432 \u0432\u0438\u0434\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0438 \u043f\u0440\u043e\u0447\u0438\u0445 \u0445\u0430\u043a\u043e\u0432.<\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">Server.java<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"java\">private boolean verifyMessage(String msg) {     return msg.length() &gt; 0             && msg.length() &lt;= 140; } <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u0414\u043b\u044f \u043e\u0431\u043c\u0435\u043d\u0430 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0444\u043e\u0440\u043c\u0430\u0442 JSON, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0444\u0430\u0439\u043b pom.xml \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043e\u0431\u043d\u043e\u0432\u0438\u0442\u044c, \u0434\u043e\u0431\u0430\u0432\u0438\u0432 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044c:<\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">pom.xml<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"xml\">&lt;dependency&gt;     &lt;groupId&gt;com.google.code.gson&lt;\/groupId&gt;     &lt;artifactId&gt;gson&lt;\/artifactId&gt;     &lt;version&gt;2.3.1&lt;\/version&gt; &lt;\/dependency&gt; <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u0422\u0430\u043a\u0436\u0435, \u0432 \u043d\u0430\u0448\u0435\u043c \u0447\u0430\u0442\u0435 \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c\u0441\u044f \u0441\u0447\u0435\u0442\u0447\u0438\u043a \u0447\u0438\u0441\u043b\u0430 \u043e\u043d\u043b\u0430\u0439\u043d-\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439, \u0442.\u043a. \u043d\u0430\u0448\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043c\u043d\u043e\u0433\u043e\u043f\u043e\u0442\u043e\u0447\u043d\u043e\u0435, \u043e\u043d\u043e \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043e \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c thread-safety, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u0441\u043f\u043e\u0441\u043e\u0431 \u043e\u0431\u044a\u044f\u0432\u0438\u0442\u044c \u043d\u0430\u0448 \u0441\u0447\u0451\u0442\u0447\u0438\u043a \u043a\u0430\u043a <a href=\"https:\/\/docs.oracle.com\/javase\/8\/docs\/api\/java\/util\/concurrent\/atomic\/AtomicInteger.html\">AtomicInteger<\/a>.<\/p>\n<p>  <a name=\"client\"><\/a><\/p>\n<h4>\u041a\u043b\u0438\u0435\u043d\u0442<\/h4>\n<p>  \u0421\u043e\u0437\u0434\u0430\u0435\u043c index.html \u0432 \u0440\u0430\u0437\u0434\u0435\u043b\u0435 webroot, \u043a\u0430\u043a \u044d\u0442\u043e \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043d\u043e\u0439 \u043d\u0430 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0435 \u0432 \u043d\u0430\u0447\u0430\u043b\u0435 \u0441\u0442\u0430\u0442\u044c\u0438. \u0414\u043b\u044f \u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c, \u0430 \u0442\u043e\u0447\u043d\u0435\u0435, \u0441 \u0448\u0438\u043d\u043e\u0439 \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 <a href=\"https:\/\/github.com\/vert-x3\/vertx-examples\/blob\/master\/web-examples\/src\/main\/java\/io\/vertx\/example\/web\/chat\/webroot\/vertx-eventbus.js\">vertx-eventbus.js<\/a>. <\/p>\n<p>  \u0414\u043b\u044f \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0434\u0430\u0442\u044b, \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 <a href=\"http:\/\/stevenlevithan.com\/assets\/misc\/date.format.js\">date-format.js<\/a>, \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e-\u0442\u0430\u043a\u0438 \u043f\u0440\u043e\u0441\u0442\u0430\u044f \u0438 \u0443\u0434\u043e\u0431\u043d\u0430\u044f. \u041f\u043e\u043c\u0438\u043c\u043e \u044d\u0442\u043e\u0433\u043e, \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 html \u043e\u0444\u043e\u0440\u043c\u043b\u0435\u043d\u0438\u044f \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c bootstrap \u0432\u0435\u0440\u0441\u0438\u0438 3.3.5, sockjs.js \u0432\u0435\u0440\u0441\u0438\u0438 0.3.4, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0439 \u0434\u043b\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 vertx-eventbus.js \u0438 jquery \u0432\u0435\u0440\u0441\u0438\u0438 1.11.3.<\/p>\n<p>  \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0448\u0438\u043d\u044b \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">index.html<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"javascript\">var online = 0; \/\/\u0441\u0447\u0435\u0442\u0447\u0438\u043a \u043e\u043d\u043b\u0430\u0439\u043d-\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439. var eb = new EventBus(&quot;\/eventbus\/&quot;); \/\/\u0448\u0438\u043d\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u0439.  eb.onopen = function() {     \/\/\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u0432 \u0447\u0430\u0442\u0435.     eb.registerHandler(&quot;chat.to.client&quot;, eventChatProcessing); };  \/\/\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u0432 \u0447\u0430\u0442\u0435. function eventChatProcessing(err, msg) {     var event = jQuery.parseJSON(msg.body);      if (event.type == 'publish') { \/\/\u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435.         var time = Date.parse(event.time);         var formattedTime = dateFormat(time, &quot;dd.mm.yy HH:MM:ss&quot;);          \/\/\u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435.         appendMsg(event.host, event.port, event.message, formattedTime);     } else { \/\/\u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0447\u0438\u0441\u043b\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439.         \/\/type: register \u0438\u043b\u0438 close.         online = event.online;         $('#online').text(online);     } }; <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u0412 \u0441\u043b\u0443\u0447\u0430\u0435, \u0435\u0441\u043b\u0438 \u0442\u0438\u043f \u0441\u043e\u0431\u044b\u0442\u0438\u044f publish (\u0442.\u0435. \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u044f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f), \u0442\u043e \u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u0437 \u0441\u043e\u0431\u044b\u0442\u0438\u044f (event) \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u044e\u0442\u0441\u044f \u0432 \u043a\u043e\u0440\u0442\u0435\u0436 \u0438 \u043f\u0440\u0438\u0441\u043e\u0435\u0434\u0438\u043d\u044f\u044e\u0442\u0441\u044f \u043a \u0442\u0430\u0431\u043b\u0438\u0446\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439. \u0418\u043d\u0430\u0447\u0435, \u043a\u043e\u0433\u0434\u0430 \u0442\u0438\u043f \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u043d\u043e\u0432\u043e\u043c\u0443 \u0438\u043b\u0438 \u0443\u0448\u0435\u0434\u0448\u0435\u043c\u0443 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e, \u043f\u0440\u043e\u0441\u0442\u043e \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0441\u0447\u0435\u0442\u0447\u0438\u043a \u043e\u043d\u043b\u0430\u0439\u043d \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439. \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e-\u0442\u0430\u043a\u0438 \u043f\u0440\u043e\u0441\u0442\u0430.<\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">index.html<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"javascript\">\/\/\u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043d\u043e\u0432\u043e\u0433\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f. function appendMsg(host, port, message, formattedTime) {     var $msg = $('&lt;tr bgcolor=&quot;#dff0d8&quot;&gt;&lt;td align=&quot;left&quot;&gt;' + formattedTime + '&lt;\/td&gt;&lt;td align=&quot;left&quot;&gt;' + host + ' [' + port + ']' + '&lt;\/td&gt;&lt;td&gt;' + message + '&lt;\/td&gt;&lt;\/tr&gt;');      var countMsg = $('#messages tr').length;     if (countMsg == 0)         $('#messages').append($msg);     else         $('#messages &gt; tbody &gt; tr:first').before($msg); } <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u0412\u043e \u0432\u0440\u0435\u043c\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f, \u043e\u043d\u043e \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u043f\u0443\u0431\u043b\u0438\u043a\u0443\u0435\u0442\u0441\u044f \u043f\u043e \u0430\u0434\u0440\u0435\u0441\u0443 \u201cchat.to.server\u201d, \u0433\u0434\u0435 \u0435\u0433\u043e \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u0441\u0435\u0440\u0432\u0435\u0440, \u0432 \u0441\u043b\u0443\u0447\u0430\u0435, \u0435\u0441\u043b\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u0442 \u0432\u0435\u0440\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044e, \u043e\u043d\u043e \u0440\u0430\u0441\u0441\u044b\u043b\u0430\u0435\u0442\u0441\u044f \u0432\u0441\u0435\u043c \u043a\u043b\u0438\u0435\u043d\u0442\u0430\u043c, \u0432 \u0442.\u0447. \u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u0435\u043b\u044e.<\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">index.html<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"javascript\">$(document).ready(function() {     \/\/\u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f.     $('#chatForm').submit(function(evt) {         evt.preventDefault();         var message = $('#message').val();         if (message.length &gt; 0) {             \/\/\u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043d\u0430 \u0448\u0438\u043d\u0443 \u0441\u043e\u0431\u044b\u0442\u0438\u0439.             eb.publish(&quot;chat.to.server&quot;, message);             $('#message').val(&quot;&quot;).focus();             countChar();         }     }); }); <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u041d\u0443 \u0438 \u043d\u0430\u043a\u043e\u043d\u0435\u0446 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u043c\u0435\u0442\u043e\u0434, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0432\u0432\u0435\u0434\u0435\u043d\u043d\u044b\u0445 \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432, \u043f\u043e \u0443\u0441\u043b\u043e\u0432\u0438\u044e, \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u0432\u0432\u0435\u0441\u0442\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0434\u043b\u0438\u043d\u043e\u0439 \u0431\u043e\u043b\u0435\u0435 140 \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432.<\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">index.html<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"javascript\">\/\/\u0441\u0447\u0435\u0442\u0447\u0438\u043a \u0432\u0432\u0435\u0434\u0435\u043d\u043d\u044b\u0445 \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432. function countChar() {     var len = $('#message').val().length;     if (len &gt; 140) {         var msg = $('#message').val().substring(0, 140);         $('#message').val(msg);     } else {         $('#charNum').text(140 - len);         var per = 100 \/ 140 * len;         $('#charNumProgressBar').css('width', per + '%').attr('aria-valuenow', per);     } }; <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u041f\u043e\u043b\u043d\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f index.html, \u0432\u043a\u043b\u044e\u0447\u0430\u044f \u0440\u0430\u0437\u043c\u0435\u0442\u043a\u0443, \u0440\u0430\u0437\u043c\u0435\u0449\u0435\u043d\u0430 \u0432 \u043a\u043e\u043d\u0446\u0435 \u0441\u0442\u0430\u0442\u044c\u0438.<\/p>\n<p>  \u041f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e, \u043a\u0430\u043a \u043c\u044b \u043d\u0430\u043f\u0438\u0441\u0430\u043b\u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u0443\u044e \u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u0443\u044e \u0447\u0430\u0441\u0442\u0438, \u043d\u0430\u0441\u0442\u0443\u043f\u0438\u043b\u0430 \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0414\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0438 \u0443\u0434\u043e\u0431\u043d\u043e\u0439 \u043e\u0442\u043b\u0430\u0434\u043a\u0438, \u044f \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u044e \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0437\u0430\u0433\u0440\u0443\u0437\u0447\u0438\u043a Verticle, \u0445\u043e\u0442\u044f \u0438 \u0435\u0441\u0442\u044c \u0431\u043e\u043b\u0435\u0435 \u043f\u0440\u043e\u0441\u0442\u0430\u044f \u0430\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u0430, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u044f \u043f\u0440\u0438\u0432\u0435\u0434\u0443 \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u043f\u043e\u0437\u0436\u0435.<\/p>\n<p>  \u0415\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u0442 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e dir \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e, \u0442.\u0435. \u0432 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u0434\u043e\u043b\u0436\u0435\u043d \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0442\u0430\u043a\u043e\u0439 \u043f\u0443\u0442\u044c. \u0410 \u0442\u0430\u043a\u0436\u0435, \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f verticleID \u0434\u043e\u043b\u0436\u043d\u0430 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0438\u043c\u0435\u043d\u0435\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c\u043e\u0433\u043e verticle-\u043a\u043b\u0430\u0441\u0441\u0430, \u0432\u0435\u0441\u044c \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u043e\u0439 \u043a\u043e\u0434 \u043d\u0435 \u043f\u043e\u0434\u043b\u0435\u0436\u0438\u0442 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044e.<\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">VerticleLoader.java<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"java\">public class VerticleLoader {     private static Vertx vertx;      public static Vertx getVertx() {         return vertx;     }      public static void load() {         load(null);     }      public static void load(Handler&lt;AsyncResult&lt;String&gt;&gt; completionHandler) {         VertxOptions options = new VertxOptions().setClustered(false);         \/\/\u043f\u0443\u0442\u044c \u0434\u043e verticle-\u043a\u043b\u0430\u0441\u0441\u0430.         String dir = &quot;chat\/src\/main\/java\/&quot;;          try {             File current = new File(&quot;.&quot;).getCanonicalFile();             if (dir.startsWith(current.getName()) && !dir.equals(current.getName())) {                 dir = dir.substring(current.getName().length() + 1);             }         } catch (IOException e) {         }          System.setProperty(&quot;vertx.cwd&quot;, dir);         String verticleID = Server.class.getName();          Consumer&lt;Vertx&gt; runner = vertx -&gt;         {             try {                 if (completionHandler == null)                     vertx.deployVerticle(verticleID);                 else                     vertx.deployVerticle(verticleID, completionHandler);             } catch (Throwable t) {                 t.printStackTrace();             }         };          if (options.isClustered()) {             Vertx.clusteredVertx(options, res -&gt;             {                 if (res.succeeded()) {                     vertx = res.result();                     runner.accept(vertx);                 } else {                     res.cause().printStackTrace();                 }             });         } else {             vertx = Vertx.vertx(options);             runner.accept(vertx);         }     }      public static void main(String[] args) {         load();     } } <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c, \u043a\u043e\u0433\u0434\u0430 \u0437\u0430\u0433\u0440\u0443\u0437\u0447\u0438\u043a \u0433\u043e\u0442\u043e\u0432, \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e \u0437\u0430\u043f\u0443\u0441\u043a\u0430: Run \u2013 Edit Configuration\u2026 \u2013 Add New Configuration (Alt + Insert) \u2013 Application. \u0423\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c Main Class \u043a\u0430\u043a VerticleLoader, \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e \u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c.<\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u0418\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438<\/b><\/p>\n<div class=\"spoiler_text\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/files\/6e9\/e66\/8d0\/6e9e668d01974530afa49a7e2d7c2f05.png\"\/>  <\/div>\n<\/div>\n<p>  <b>PROFIT!<\/b><\/p>\n<p>  \u041e\u0431\u0435\u0449\u0430\u043d\u043d\u0430\u044f \u0430\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u0430. <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u0410\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u043d\u0430\u044f \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f<\/b><\/p>\n<div class=\"spoiler_text\">\u041d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e \u0437\u0430\u043f\u0443\u0441\u043a\u0430, \u043a\u0430\u043a \u044d\u0442\u043e \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043e \u043d\u0430 \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0435. \u041d\u0430 \u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435, \u043a\u043b\u0430\u0441\u0441 Starter \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0433\u043b\u0430\u0432\u043d\u044b\u043c \u043a\u043b\u0430\u0441\u0441\u043e\u043c, \u043e\u043d \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u043c\u0435\u0442\u043e\u0434 main, \u043a\u043e\u0442\u043e\u0440\u044b\u0439-\u0442\u043e \u0438 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0442\u043e\u0447\u043a\u043e\u0439 \u0432\u0445\u043e\u0434\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/files\/772\/32a\/d6d\/77232ad6dad74a71b87034e6510a7344.png\"\/>  <\/div>\n<\/div>\n<p>  <a name=\"testing\"><\/a>  <\/p>\n<h4>\u0422\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435<\/h4>\n<p>  \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u0440\u043e\u0442\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u043c \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u043d\u043d\u043e\u0435 \u043d\u0430\u043c\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435. \u0414\u0435\u043b\u0430\u0442\u044c \u043c\u044b \u044d\u0442\u043e \u0431\u0443\u0434\u0435\u043c \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c JUnit, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u043d\u043e\u0432\u0430 \u043e\u0442\u043a\u0440\u044b\u0442\u044c pom.xml \u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044c:<\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">pom.xml<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"xml\">&lt;dependency&gt;     &lt;groupId&gt;junit&lt;\/groupId&gt;     &lt;artifactId&gt;junit&lt;\/artifactId&gt;     &lt;version&gt;4.12&lt;\/version&gt;     &lt;scope&gt;test&lt;\/scope&gt; &lt;\/dependency&gt; <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u0412 setUp \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 Vertx \u0438 \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u0435\u043c \u043d\u0430 \u043d\u0435\u0433\u043e \u043d\u0430\u0448\u0443 Verticle. \u0412 \u043e\u0442\u043b\u0438\u0447\u0438\u0438 \u043e\u0442 \u0442\u0440\u0430\u0434\u0438\u0446\u0438\u043e\u043d\u043d\u043e\u0433\u043e JUnit \u043c\u0435\u0442\u043e\u0434\u043e\u0432, \u0432\u0441\u0435 \u0442\u0435\u043a\u0443\u0449\u0438\u0435 \u043c\u0435\u0442\u043e\u0434\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u044e\u0442 \u0435\u0449\u0435 TestContext. \u0417\u0430\u0434\u0430\u0447\u0430 \u044d\u0442\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0441\u043e\u0431\u043b\u044e\u0434\u0430\u0442\u044c \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0441\u0442\u044c \u043d\u0430\u0448\u0438\u0445 \u0442\u0435\u0441\u0442\u043e\u0432.<\/p>\n<p>  \u0412 \u043c\u0435\u0442\u043e\u0434\u0435 tearDown() \u0434\u043b\u044f \u043e\u0431\u044a\u0435\u043a\u0442\u0430 TestContext \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f asyncAssertSuccess(), \u043e\u043d \u0442\u0435\u0440\u043f\u0438\u0442 \u043d\u0435\u0443\u0434\u0430\u0447\u0443, \u0435\u0441\u043b\u0438 \u043f\u0440\u0438 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u0438 \u0440\u0430\u0431\u043e\u0442\u044b Verticle \u0432\u043e\u0437\u043d\u0438\u043a\u043b\u0438 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b.<\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">ChatTest.java<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"java\">@RunWith(VertxUnitRunner.class) public class ChatTest {     private Vertx vertx;     private int port = 8080;     private Logger log = LoggerFactory.getLogger(ChatTest.class);      \/\/@Ignore     @Before     public void setUp(TestContext context) throws IOException {         VerticleLoader.load(context.asyncAssertSuccess());         vertx = VerticleLoader.getVertx();     }      \/\/@Ignore     @After     public void tearDown(TestContext context) {         vertx.close(context.asyncAssertSuccess());     }      \/\/... } <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u0412 \u043c\u0435\u0442\u043e\u0434\u0435 loadVerticleTest \u043c\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0443 \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0421\u043e\u0437\u0434\u0430\u0435\u043c \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u0438 \u043f\u044b\u0442\u0430\u0435\u043c\u0441\u044f \u0443\u0434\u043e\u0441\u0442\u043e\u0432\u0435\u0440\u0438\u0442\u044c\u0441\u044f, \u0447\u0442\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0442\u043e\u0435 \u043f\u043e \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u043c\u0443 \u043d\u0430\u043c\u0438 \u0430\u0434\u0440\u0435\u0441\u0443 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e. \u0412 \u0441\u043b\u0443\u0447\u0430\u0435 \u0443\u0441\u043f\u0435\u0445\u0430, \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043a\u043e\u0434 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f 200. <\/p>\n<p>  \u0417\u0430\u0442\u0435\u043c, \u043f\u044b\u0442\u0430\u0435\u043c\u0441\u044f \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b, \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0434\u043e\u043b\u0436\u0435\u043d \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0442\u0435\u043a\u0441\u0442 \u201cChat\u201d.<\/p>\n<p>  \u0422\u0430\u043a \u043a\u0430\u043a \u0437\u0430\u043f\u0440\u043e\u0441 \u0438 \u043e\u0442\u0432\u0435\u0442 \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u043c\u0438 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u044f\u043c\u0438, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u044d\u0442\u043e \u043a\u0430\u043a-\u0442\u043e \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438 \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f, \u043a\u043e\u0433\u0434\u0430 \u0442\u0435\u0441\u0442 \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u043b\u0441\u044f \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043e\u0431\u044a\u0435\u043a\u0442 Async, \u0432\u044b\u0437\u044b\u0432\u0430\u044e\u0449\u0438\u0439 \u0432\u0441\u0435\u0433\u0434\u0430 \u043c\u0435\u0442\u043e\u0434 complete() \u043f\u043e \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044e \u0442\u0435\u0441\u0442\u0430.<\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">ChatTest.java<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"java\">@Test public void loadVerticleTest(TestContext context) {     log.info(&quot;*** loadVerticleTest ***&quot;);      Async async = context.async();     vertx.createHttpClient().getNow(port, &quot;localhost&quot;, &quot;\/&quot;, response -&gt;     {         context.assertEquals(response.statusCode(), 200);         context.assertEquals(response.headers().get(&quot;content-type&quot;), &quot;text\/html&quot;);         response.bodyHandler(body -&gt;         {             context.assertTrue(body.toString().contains(&quot;&lt;title&gt;Chat&lt;\/title&gt;&quot;));             async.complete();         });     }); } <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u0412 \u043c\u0435\u0442\u043e\u0434\u0435 eventBusTest \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f \u043a\u043b\u0438\u0435\u043d\u0442 \u0448\u0438\u043d\u044b \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u0438 \u0432\u0435\u0448\u0430\u0435\u0442\u0441\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a. \u0412 \u0442\u043e \u0432\u0440\u0435\u043c\u044f, \u043f\u043e\u043a\u0430 \u043a\u043b\u0438\u0435\u043d\u0442 \u0436\u0434\u0435\u0442 \u043a\u0430\u043a\u0438\u0435-\u043b\u0438\u0431\u043e \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u043d\u0430 \u0448\u0438\u043d\u0435, \u043f\u0443\u0431\u043b\u0438\u043a\u0443\u0435\u0442\u0441\u044f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435. \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0440\u0435\u0430\u0433\u0438\u0440\u0443\u0435\u0442 \u043d\u0430 \u044d\u0442\u043e \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0442\u0435\u043b\u043e \u0432\u0445\u043e\u0434\u044f\u0449\u0435\u0433\u043e \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u043d\u0430 \u044d\u043a\u0432\u0438\u0432\u0430\u043b\u0435\u043d\u0442\u043d\u043e\u0441\u0442\u044c, \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0439 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0442\u0435\u0441\u0442 \u0437\u0430\u0432\u0435\u0440\u0448\u0430\u0435\u0442\u0441\u044f \u0432\u044b\u0437\u043e\u0432\u043e\u043c async.complete().<\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">ChatTest.java<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"java\">@Test public void eventBusTest(TestContext context) {     log.info(&quot;*** eventBusTest ***&quot;);      Async async = context.async();     EventBus eb = vertx.eventBus();     eb.consumer(&quot;chat.to.server&quot;).handler(message -&gt;     {         String getMsg = message.body().toString();         context.assertEquals(getMsg, &quot;hello&quot;);         async.complete();     });      eb.publish(&quot;chat.to.server&quot;, &quot;hello&quot;); } <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u0442\u0435\u0441\u0442\u044b.<\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u041f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043a\u0430\u043a&#8230;<\/b><\/p>\n<div class=\"spoiler_text\">\u0412\u043a\u043b\u0430\u0434\u043a\u0430 Maven Projects \u2013 Lifecycle \u2013 test \u2013 Run [test].<br \/>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/files\/e99\/0ae\/c2d\/e990aec2d47b441c803069535b5c55a6.png\"\/>  <\/div>\n<\/div>\n<p>  <a name=\"building\"><\/a><\/p>\n<h4>\u0421\u0431\u043e\u0440\u043a\u0430 \u0438 \u0437\u0430\u043f\u0443\u0441\u043a \u0438\u0441\u043f\u043e\u043b\u043d\u044f\u0435\u043c\u043e\u0433\u043e \u043c\u043e\u0434\u0443\u043b\u044f<\/h4>\n<p>  \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0432 pom.xml \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043f\u043b\u0430\u0433\u0438\u043d <i>maven-shade-plugin<\/i>. \u0413\u0434\u0435 Main-Verticle \u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0434\u043e\u043b\u0436\u0435\u043d \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043d\u0430 \u043a\u043b\u0430\u0441\u0441 <i>Server<\/i>.<\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">pom.xml<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"xml\">&lt;plugin&gt;     &lt;groupId&gt;org.apache.maven.plugins&lt;\/groupId&gt;     &lt;artifactId&gt;maven-shade-plugin&lt;\/artifactId&gt;     &lt;version&gt;2.3&lt;\/version&gt;     &lt;executions&gt;         &lt;execution&gt;             &lt;phase&gt;package&lt;\/phase&gt;             &lt;goals&gt;                 &lt;goal&gt;shade&lt;\/goal&gt;             &lt;\/goals&gt;             &lt;configuration&gt;                 &lt;transformers&gt;                     &lt;transformer                             implementation=&quot;org.apache.maven.plugins.shade.resource.ManifestResourceTransformer&quot;&gt;                         &lt;manifestEntries&gt;                             &lt;Main-Class&gt;io.vertx.core.Starter&lt;\/Main-Class&gt;                             &lt;Main-Verticle&gt;Server&lt;\/Main-Verticle&gt;                         &lt;\/manifestEntries&gt;                     &lt;\/transformer&gt;                 &lt;\/transformers&gt;                 &lt;artifactSet\/&gt;                 &lt;outputFile&gt;${project.build.directory}\/${project.artifactId}-${project.version}-fat.jar&lt;\/outputFile&gt;             &lt;\/configuration&gt;         &lt;\/execution&gt;     &lt;\/executions&gt; &lt;\/plugin&gt; <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u0412\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u043c \u043a\u043e\u043c\u0430\u043d\u0434\u0443 Run Maven Build, \u043f\u043e\u0441\u043b\u0435 \u0447\u0435\u0433\u043e \u0432 \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0435 target \u043f\u043e\u044f\u0432\u0438\u0442\u0441\u044f chat-1.0-fat.jar. \u0414\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438\u0441\u043f\u043e\u043b\u043d\u044f\u0435\u043c\u044b\u0439 \u043c\u043e\u0434\u0443\u043b\u044c \u0438 \u043f\u0430\u043f\u043a\u0430 webroot \u0434\u043e\u043b\u0436\u043d\u044b \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u044c\u0441\u044f \u0432 \u043e\u0434\u043d\u043e\u043c \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0435. \u0427\u0442\u043e\u0431\u044b \u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0442\u044c \u043d\u0430\u0448\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043d\u0430 \u043f\u043e\u0440\u0442\u0443 12345 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u043a\u043e\u043c\u0430\u043d\u0434\u0443:<br \/>  <code>java -jar chat-1.0-fat.jar 12345<br \/>  <\/code><\/p>\n<p>  \u041d\u0430 \u044d\u0442\u043e\u043c \u0432\u0441\u0451. \u0423\u0441\u043f\u0435\u0445\u043e\u0432!<\/p>\n<p>  <a name=\"source\"><\/a><\/p>\n<h4>\u041f\u043e\u043b\u043d\u044b\u0439 \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434<\/h4>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">Server.java<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"java\">import com.google.gson.Gson; import io.vertx.core.AbstractVerticle; import io.vertx.core.Starter; import io.vertx.core.logging.Logger; import io.vertx.core.logging.LoggerFactory; import io.vertx.ext.web.Router; import io.vertx.ext.web.handler.StaticHandler; import io.vertx.ext.web.handler.sockjs.BridgeEvent; import io.vertx.ext.web.handler.sockjs.BridgeOptions; import io.vertx.ext.web.handler.sockjs.PermittedOptions; import io.vertx.ext.web.handler.sockjs.SockJSHandler;  import java.io.IOException; import java.net.BindException; import java.net.InetAddress; import java.net.ServerSocket; import java.net.UnknownHostException; import java.util.*; import java.util.concurrent.atomic.AtomicInteger;  import static io.vertx.ext.web.handler.sockjs.BridgeEvent.Type.*;  public class Server extends AbstractVerticle {     private Logger log = LoggerFactory.getLogger(Server.class);     private SockJSHandler handler = null;     private AtomicInteger online = new AtomicInteger(0);      \/\/\u0442\u043e\u0447\u043a\u0430 \u0432\u0445\u043e\u0434\u0430.     @Override     public void start() throws Exception {          if (!deploy()) {             log.error(&quot;Failed to deploy the server.&quot;);             return;         }          handle();     }      \/\/\u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.     private boolean deploy() {         int hostPort = getFreePort();          if (hostPort &lt; 0)             return false;          Router router = Router.router(vertx);          \/\/\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0441\u043e\u0431\u044b\u0442\u0438\u0439.         handler = SockJSHandler.create(vertx);          router.route(&quot;\/eventbus\/*&quot;).handler(handler);         router.route().handler(StaticHandler.create());          \/\/\u0437\u0430\u043f\u0443\u0441\u043a \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0435\u0440\u0430.         vertx.createHttpServer().requestHandler(router::accept).listen(hostPort);          try {             String addr = InetAddress.getLocalHost().getHostAddress();             log.info(&quot;Access to \\&quot;CHAT\\&quot; at the following address: \\nhttp:\/\/&quot; + addr + &quot;:&quot; + hostPort);         } catch (UnknownHostException e) {             log.error(&quot;Failed to get the local address: [&quot; + e.toString() + &quot;]&quot;);             return false;         }          return true;     }      \/\/\u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0441\u0432\u043e\u0431\u043e\u0434\u043d\u043e\u0433\u043e \u043f\u043e\u0440\u0442\u0430 \u0434\u043b\u044f \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.     private int getFreePort() {         int hostPort = 8080;          \/\/\u0435\u0441\u043b\u0438 \u043f\u043e\u0440\u0442 \u0437\u0430\u0434\u0430\u043d \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0430,         \/\/ \u043f\u0440\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.         if (Starter.PROCESS_ARGS != null                 && Starter.PROCESS_ARGS.size() &gt; 0) {             try {                 hostPort = Integer.valueOf(Starter.PROCESS_ARGS.get(0));             } catch (NumberFormatException e) {                 log.warn(&quot;Invalid port: [&quot; + Starter.PROCESS_ARGS.get(0) + &quot;]&quot;);             }         }          \/\/\u0435\u0441\u043b\u0438 \u043d\u0435\u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e \u0443\u043a\u0430\u0437\u0430\u043d \u043f\u043e\u0440\u0442.         if (hostPort &lt; 0 || hostPort &gt; 65535)             hostPort = 8080;          return getFreePort(hostPort);     }      \/\/\u0435\u0441\u043b\u0438 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043f\u043e\u0440\u0442\u0430 \u0443\u043a\u0430\u0437\u0430\u043d\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 0,     \/\/ \u0442\u043e \u0432\u044b\u0434\u0430\u0435\u0442\u0441\u044f \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u044b\u0439 \u0441\u0432\u043e\u0431\u043e\u0434\u043d\u044b\u0439 \u043f\u043e\u0440\u0442.     private int getFreePort(int hostPort) {         try {             ServerSocket socket = new ServerSocket(hostPort);             int port = socket.getLocalPort();             socket.close();              return port;         } catch (BindException e) {             \/\/\u0441\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442, \u043a\u043e\u0433\u0434\u0430 \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u0439 \u043f\u043e\u0440\u0442 \u0443\u0436\u0435 \u0437\u0430\u043d\u044f\u0442.             if (hostPort != 0)                 return getFreePort(0);              log.error(&quot;Failed to get the free port: [&quot; + e.toString() + &quot;]&quot;);             return -1;         } catch (IOException e) {             log.error(&quot;Failed to get the free port: [&quot; + e.toString() + &quot;]&quot;);             return -1;         }     }      private void handle() {         BridgeOptions opts = new BridgeOptions()                 .addInboundPermitted(new PermittedOptions().setAddress(&quot;chat.to.server&quot;))                 .addOutboundPermitted(new PermittedOptions().setAddress(&quot;chat.to.client&quot;));          \/\/\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043f\u0440\u0438\u0445\u043e\u0434\u044f\u0449\u0438\u0445 \u0441\u043e\u0431\u044b\u0442\u0438\u0439.         handler.bridge(opts, event -&gt; {             if (event.type() == PUBLISH)                 publishEvent(event);              if (event.type() == REGISTER)                 registerEvent(event);              if (event.type() == SOCKET_CLOSED)                 closeEvent(event);              \/\/\u043e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u043f\u043e\u0441\u043b\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u044f             \/\/ \u0434\u043e\u043b\u0436\u0435\u043d \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u0433\u043e\u0432\u043e\u0440\u044f\u0449\u0438\u0439 \u0441\u0430\u043c \u0437\u0430 \u0441\u0435\u0431\u044f \u043c\u0435\u0442\u043e\u0434.             event.complete(true);         });     }      \/\/\u0442\u0438\u043f \u0441\u043e\u0431\u044b\u0442\u0438\u044f - \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u044f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f.     private boolean publishEvent(BridgeEvent event) {         if (event.rawMessage() != null                 && event.rawMessage().getString(&quot;address&quot;).equals(&quot;chat.to.server&quot;)) {             String message = event.rawMessage().getString(&quot;body&quot;);             if (!verifyMessage(message))                 return false;              String host = event.socket().remoteAddress().host();             int port = event.socket().remoteAddress().port();              Map&lt;String, Object&gt; publicNotice = createPublicNotice(host, port, message);             vertx.eventBus().publish(&quot;chat.to.client&quot;, new Gson().toJson(publicNotice));             return true;         } else             return false;     }      \/\/\u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f \u043e \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f.     private Map&lt;String, Object&gt; createPublicNotice(String host, int port, String message) {         Date time = Calendar.getInstance().getTime();          Map&lt;String, Object&gt; notice = new TreeMap&lt;&gt;();         notice.put(&quot;type&quot;, &quot;publish&quot;);         notice.put(&quot;time&quot;, time.toString());         notice.put(&quot;host&quot;, host);         notice.put(&quot;port&quot;, port);         notice.put(&quot;message&quot;, message);         return notice;     }      \/\/\u0442\u0438\u043f \u0441\u043e\u0431\u044b\u0442\u0438\u044f - \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430.     private void registerEvent(BridgeEvent event) {         if (event.rawMessage() != null                 && event.rawMessage().getString(&quot;address&quot;).equals(&quot;chat.to.client&quot;))             new Thread(() -&gt;             {                 Map&lt;String, Object&gt; registerNotice = createRegisterNotice();                 vertx.eventBus().publish(&quot;chat.to.client&quot;, new Gson().toJson(registerNotice));             }).start();     }      \/\/\u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f \u043e \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f.     private Map&lt;String, Object&gt; createRegisterNotice() {         Map&lt;String, Object&gt; notice = new TreeMap&lt;&gt;();         notice.put(&quot;type&quot;, &quot;register&quot;);         notice.put(&quot;online&quot;, online.incrementAndGet());         return notice;     }      \/\/\u0442\u0438\u043f \u0441\u043e\u0431\u044b\u0442\u0438\u044f - \u0437\u0430\u043a\u0440\u044b\u0442\u0438\u0435 \u0441\u043e\u043a\u0435\u0442\u0430.     private void closeEvent(BridgeEvent event) {         new Thread(() -&gt;         {             Map&lt;String, Object&gt; closeNotice = createCloseNotice();             vertx.eventBus().publish(&quot;chat.to.client&quot;, new Gson().toJson(closeNotice));         }).start();     }      \/\/\u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f \u043e \u0432\u044b\u0445\u043e\u0434\u0435 \u043f\u043e\u043b\u044c\u0437\u0432\u0430\u0442\u0435\u043b\u044f \u0438\u0437 \u0447\u0430\u0442\u0430.     private Map&lt;String, Object&gt; createCloseNotice() {         Map&lt;String, Object&gt; notice = new TreeMap&lt;&gt;();         notice.put(&quot;type&quot;, &quot;close&quot;);         notice.put(&quot;online&quot;, online.decrementAndGet());         return notice;     }      \/\/\u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u0430\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f,     \/\/ \u043a\u043e\u043d\u0435\u0447\u043d\u043e \u0435\u0451 \u043c\u043e\u0436\u043d\u043e \u0443\u0441\u043b\u043e\u0436\u043d\u0438\u0442\u044c,     \/\/ \u043d\u043e \u0434\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u0440 \u0438 \u044d\u0442\u043e\u0433\u043e \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e ;)     private boolean verifyMessage(String msg) {         return msg.length() &gt; 0                 && msg.length() &lt;= 140;     } } <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">VerticleLoader.java<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"java\">import io.vertx.core.AsyncResult; import io.vertx.core.Handler; import io.vertx.core.Vertx; import io.vertx.core.VertxOptions; import io.vertx.core.impl.StringEscapeUtils;  import java.io.File; import java.io.IOException; import java.util.function.Consumer;  public class VerticleLoader {     private static Vertx vertx;      public static Vertx getVertx() {         return vertx;     }      public static void load() {         load(null);     }      public static void load(Handler&lt;AsyncResult&lt;String&gt;&gt; completionHandler) {         VertxOptions options = new VertxOptions().setClustered(false);         \/\/\u043f\u0443\u0442\u044c \u0434\u043e verticle-\u043a\u043b\u0430\u0441\u0441\u0430.         String dir = &quot;chat\/src\/main\/java\/&quot;;          try {             File current = new File(&quot;.&quot;).getCanonicalFile();             if (dir.startsWith(current.getName()) && !dir.equals(current.getName())) {                 dir = dir.substring(current.getName().length() + 1);             }         } catch (IOException e) {         }          System.setProperty(&quot;vertx.cwd&quot;, dir);         String verticleID = Server.class.getName();          Consumer&lt;Vertx&gt; runner = vertx -&gt;         {             try {                 if (completionHandler == null)                     vertx.deployVerticle(verticleID);                 else                     vertx.deployVerticle(verticleID, completionHandler);             } catch (Throwable t) {                 t.printStackTrace();             }         };          if (options.isClustered()) {             Vertx.clusteredVertx(options, res -&gt;             {                 if (res.succeeded()) {                     vertx = res.result();                     runner.accept(vertx);                 } else {                     res.cause().printStackTrace();                 }             });         } else {             vertx = Vertx.vertx(options);             runner.accept(vertx);         }     }      public static void main(String[] args) {         load();     } } <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">ChatTest.java<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"java\">import io.vertx.core.Vertx; import io.vertx.core.eventbus.EventBus; import io.vertx.core.logging.Logger; import io.vertx.core.logging.LoggerFactory; import io.vertx.ext.unit.Async; import io.vertx.ext.unit.TestContext; import io.vertx.ext.unit.junit.VertxUnitRunner; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith;  import java.io.IOException;  @RunWith(VertxUnitRunner.class) public class ChatTest {     private Vertx vertx;     private int port = 8080;     private Logger log = LoggerFactory.getLogger(ChatTest.class);      \/\/@Ignore     @Before     public void setUp(TestContext context) throws IOException {         \/\/\u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u0435 \u043d\u0430\u0448\u0435\u0439 Verticle.         VerticleLoader.load(context.asyncAssertSuccess());         vertx = VerticleLoader.getVertx();     }      \/\/@Ignore     @After     public void tearDown(TestContext context) {         vertx.close(context.asyncAssertSuccess());     }      \/\/@Ignore     @Test     public void loadVerticleTest(TestContext context) {         log.info(&quot;*** loadVerticleTest ***&quot;);          Async async = context.async();         vertx.createHttpClient().getNow(port, &quot;localhost&quot;, &quot;\/&quot;, response -&gt;         {             \/\/\u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e\u0441\u0442\u0438 \u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0442\u043e\u0433\u043e \u043d\u0430\u043c\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.             context.assertEquals(response.statusCode(), 200);             context.assertEquals(response.headers().get(&quot;content-type&quot;), &quot;text\/html&quot;);              \/\/\u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0433\u043e \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b.             response.bodyHandler(body -&gt;             {                 context.assertTrue(body.toString().contains(&quot;&lt;title&gt;Chat&lt;\/title&gt;&quot;));                 async.complete();             });         });     }      \/\/@Ignore     @Test     public void eventBusTest(TestContext context) {         log.info(&quot;*** eventBusTest ***&quot;);          Async async = context.async();         EventBus eb = vertx.eventBus();         \/\/\u043e\u0436\u0438\u0434\u0430\u043d\u0438\u0435 \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u043d\u0430 \u0448\u0438\u043d\u0435.         eb.consumer(&quot;chat.to.server&quot;).handler(message -&gt;         {             String getMsg = message.body().toString();             context.assertEquals(getMsg, &quot;hello&quot;);             async.complete();         });          \/\/\u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0430 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043d\u0430 \u0448\u0438\u043d\u0443.         eb.publish(&quot;chat.to.server&quot;, &quot;hello&quot;);     } } <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">index.html<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"html\">&lt;!DOCTYPE html&gt; &lt;html lang=&quot;en&quot;&gt; &lt;head&gt;     &lt;meta charset=&quot;UTF-8&quot;&gt;     &lt;title&gt;Chat&lt;\/title&gt;     &lt;meta charset=&quot;windows-1251&quot;&gt;     &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt;     &lt;script src=&quot;\/\/cdn.jsdelivr.net\/sockjs\/0.3.4\/sockjs.min.js&quot;&gt;&lt;\/script&gt;     &lt;link rel=&quot;stylesheet&quot; href=&quot;http:\/\/maxcdn.bootstrapcdn.com\/bootstrap\/3.3.5\/css\/bootstrap.min.css&quot;&gt;     &lt;script src=&quot;https:\/\/ajax.googleapis.com\/ajax\/libs\/jquery\/1.11.3\/jquery.min.js&quot;&gt;&lt;\/script&gt;     &lt;script src=&quot;http:\/\/maxcdn.bootstrapcdn.com\/bootstrap\/3.3.5\/js\/bootstrap.min.js&quot;&gt;&lt;\/script&gt;     &lt;script src=&quot;date-format.js&quot;&gt;&lt;\/script&gt;     &lt;script src=&quot;vertx-eventbus.js&quot;&gt;&lt;\/script&gt;      &lt;style type=&quot;text\/css&quot;&gt;         body {             padding-top: 40px;             padding-bottom: 40px;             background-color: #f5f5f5;         }          .received{             width: 160px;             font-size: 10px;         }          input[type=text]:focus, textarea:focus{             box-shadow: 0 0 5px #4cae4c;             border: 1px solid #4cae4c;         }          .tab-content{             padding:5px         }     &lt;\/style&gt;      &lt;script&gt;         var online = 0; \/\/\u0441\u0447\u0435\u0442\u0447\u0438\u043a \u043e\u043d\u043b\u0430\u0439\u043d-\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439.         var eb = new EventBus(&quot;\/eventbus\/&quot;); \/\/\u0448\u0438\u043d\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u0439.          eb.onopen = function() {             \/\/\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u0432 \u0447\u0430\u0442\u0435.             eb.registerHandler(&quot;chat.to.client&quot;, eventChatProcessing);         };          \/\/\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u0432 \u0447\u0430\u0442\u0435.         function eventChatProcessing(err, msg) {             var event = jQuery.parseJSON(msg.body);  \t\t\tif (event.type == 'publish') {\/\/\u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435. \t\t\t\tvar time = Date.parse(event.time); \t\t\t\tvar formattedTime = dateFormat(time, &quot;dd.mm.yy HH:MM:ss&quot;);  \t\t\t\t\/\/\u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435. \t\t\t\tappendMsg(event.host, event.port, event.message, formattedTime); \t\t\t} else { \/\/\u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0447\u0438\u0441\u043b\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439. \t\t\t    \/\/type: register \u0438\u043b\u0438 close. \t\t\t    online = event.online; \t\t\t\t$('#online').text(online); \t\t\t}         };          \/\/\u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043d\u043e\u0432\u043e\u0433\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f. \t\tfunction appendMsg(host, port, message, formattedTime){ \t\t\tvar $msg = $('&lt;tr bgcolor=&quot;#dff0d8&quot;&gt;&lt;td align=&quot;left&quot;&gt;' + formattedTime \t\t\t\t\t+ '&lt;\/td&gt;&lt;td align=&quot;left&quot;&gt;' + host + ' [' + port + ']' \t\t\t\t\t+ '&lt;\/td&gt;&lt;td&gt;' + message \t\t\t\t\t+ '&lt;\/td&gt;&lt;\/tr&gt;');              var countMsg = $('#messages tr').length; \t\t\tif (countMsg == 0) \t\t\t\t$('#messages').append($msg); \t\t\telse \t\t\t    $('#messages &gt; tbody &gt; tr:first').before($msg); \t\t}          $(document).ready(function() {             \/\/\u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f.             $('#chatForm').submit(function(evt) {                 evt.preventDefault();                 var message = $('#message').val();                 if (message.length &gt; 0) {                     \/\/\u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043d\u0430 \u0448\u0438\u043d\u0443 \u0441\u043e\u0431\u044b\u0442\u0438\u0439.                     eb.publish(&quot;chat.to.server&quot;, message);                     $('#message').val(&quot;&quot;).focus();                     countChar();                 }             });         });          \/\/\u0441\u0447\u0435\u0442\u0447\u0438\u043a \u0432\u0432\u0435\u0434\u0435\u043d\u043d\u044b\u0445 \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432.         function countChar() {             var len = $('#message').val().length;             if (len &gt; 140) {                 var msg = $('#message').val().substring(0, 140);                 $('#message').val(msg);             } else {                 $('#charNum').text(140 - len);                 var per = 100 \/ 140 * len;                 $('#charNumProgressBar').css('width', per+'%').attr('aria-valuenow', per);             }         };     &lt;\/script&gt; &lt;\/head&gt; &lt;body&gt;     &lt;div class=&quot;container chat-wrapper&quot;&gt;         &lt;form id=&quot;chatForm&quot;&gt;             &lt;h2 align=&quot;center&quot; class=&quot;alert alert-success&quot;&gt;CHAT ROOM&lt;\/h2&gt;             &lt;fieldset&gt;                 &lt;div class=&quot;input-group input-group-lg&quot;&gt;                     &lt;span class=&quot;input-group-addon&quot; id=&quot;onlineIco&quot;&gt;                         &lt;span class=&quot;glyphicon glyphicon-eye-open&quot;&gt;&lt;\/span&gt;                     &lt;\/span&gt;                     &lt;span class=&quot;input-group-addon&quot; id=&quot;online&quot;&gt;                         &lt;span class=&quot;glyphicon glyphicon-option-horizontal&quot;&gt;&lt;\/span&gt;                     &lt;\/span&gt;                     &lt;input type=&quot;text&quot; maxlength=&quot;141&quot; autocomplete=&quot;off&quot; class=&quot;form-control&quot;                         placeholder=&quot;What's new?&quot; id=&quot;message&quot; aria-describedby=&quot;sizing-addon1&quot;                         onkeyup=&quot;countChar()&quot;\/&gt;                     &lt;span class=&quot;input-group-btn&quot;&gt;                         &lt;button class=&quot;btn btn-success&quot; type=&quot;submit&quot;&gt;                             &lt;span class=&quot;glyphicon glyphicon-send&quot;&gt;&lt;\/span&gt;                         &lt;\/button&gt;                     &lt;\/span&gt;                 &lt;\/div&gt;             &lt;\/fieldset&gt;              &lt;h3 id=&quot;charNum&quot;&gt;140&lt;\/h3&gt;              &lt;div class=&quot;progress&quot;&gt;                 &lt;div id=&quot;charNumProgressBar&quot; class=&quot;progress-bar progress-bar-success active&quot; role=&quot;progressbar&quot;                      aria-valuenow=&quot;0&quot; aria-valuemin=&quot;0&quot; aria-valuemax=&quot;100&quot; style=&quot;width: 0%&quot;&gt;                     &lt;span class=&quot;sr-only&quot;&gt;100% Complete&lt;\/span&gt;                 &lt;\/div&gt;             &lt;\/div&gt;              &lt;div class=&quot;panel panel-success&quot;&gt;                 &lt;div class=&quot;panel-heading&quot;&gt;&lt;h3&gt;New messages&lt;\/h3&gt;&lt;\/div&gt;                     &lt;table id=&quot;messages&quot; class=&quot;table table-hover&quot; width=&quot;100%&quot;&gt;                         &lt;colgroup&gt;                             &lt;col style=&quot;width:10%&quot;&gt;                             &lt;col style=&quot;width:10%&quot;&gt;                             &lt;col style=&quot;width:10%&quot;&gt;                         &lt;\/colgroup&gt;                     &lt;\/table&gt;             &lt;\/div&gt;         &lt;\/form&gt;     &lt;\/div&gt; &lt;\/body&gt; &lt;\/html&gt; <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  <a name=\"resources\"><\/a>  <\/p>\n<h4>\u041f\u043e\u043b\u0435\u0437\u043d\u044b\u0435 \u0440\u0435\u0441\u0443\u0440\u0441\u044b<\/h4>\n<p>  <\/p>\n<ul>\n<li><a href=\"https:\/\/github.com\/oxaoo\/chat\">\u042d\u0442\u043e\u0442 \u043f\u0440\u043e\u0435\u043a\u0442 \u043d\u0430 GitHub<\/a>;<\/li>\n<li><a href=\"http:\/\/vertx.io\/docs\/\">Vert.x Documentation<\/a>;<\/li>\n<li><a href=\"http:\/\/vertx.io\/docs\/vertx-web\/java\/\">Vert.x-Web Documentation<\/a>;<\/li>\n<li><a href=\"http:\/\/vertx.io\/blog\/my-first-vert-x-3-application\/\">My first Vert.x 3 Application<\/a>;<\/li>\n<li><a href=\"https:\/\/github.com\/vert-x3\/vertx-examples\">Vert.x examples on GitHub<\/a>;<\/li>\n<li><a href=\"http:\/\/tutorials.jenkov.com\/vert.x\/index.html\">Vert.x Tutorial by Jakob Jenkov<\/a>.<\/li>\n<\/ul>\n<div class=\"clear\"><\/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=\"https:\/\/habrahabr.ru\/post\/276771\/\"> https:\/\/habrahabr.ru\/post\/276771\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>       \u041d\u0430 \u0425\u0430\u0431\u0440\u0435 \u043d\u0435 \u0442\u0430\u043a \u0443\u0436 \u043c\u043d\u043e\u0433\u043e \u0441\u0442\u0430\u0442\u0435\u0439, \u043f\u043e\u0441\u0432\u044f\u0449\u0435\u043d\u043d\u044b\u0445 Vert.x, <a href=\"https:\/\/habrahabr.ru\/post\/218733\/\">\u0440\u0430\u0437<\/a>, <a href=\"https:\/\/habrahabr.ru\/post\/181686\/\">\u0434\u0432\u0430<\/a> \u0438 \u043e\u0431\u0447\u0451\u043b\u0441\u044f. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0440\u0435\u0448\u0438\u043b \u0432\u043d\u0435\u0441\u0442\u0438 \u0441\u0432\u043e\u0439 \u0432\u043a\u043b\u0430\u0434 \u0438 \u043e\u043f\u0443\u0431\u043b\u0438\u043a\u043e\u0432\u0430\u0442\u044c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0443\u0440\u043e\u043a, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u0430\u043d\u043e, \u043a\u0430\u043a \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u0447\u0430\u0442 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Vert.x 3.<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/files\/e8a\/0b2\/894\/e8a0b2894b6b415293cddd1f59c7ef87.png\"\/>  <\/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-273795","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/273795","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=273795"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/273795\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=273795"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=273795"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=273795"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}