github.com/bchainhub/blockbook@v0.3.2/static/test-websocket.html (about)

     1  <!doctype html>
     2  <html lang="en">
     3  <head>
     4      <meta charset="utf-8">
     5      <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
     6      <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
     7      <style>
     8          .row {
     9              margin-top: 1%;
    10          }
    11      </style>
    12      <title>Blockbook Websocket Test Page</title>
    13      <script>
    14          var ws;
    15          var messageID;
    16          var pendingMessages;
    17          var subscriptions;
    18          function send(method, params, callback) {
    19              var id = messageID.toString();
    20              messageID++;
    21              pendingMessages[id] = callback;
    22              var req = {
    23                  id,
    24                  method,
    25                  params
    26              }
    27              ws.send(JSON.stringify(req));
    28              return id;
    29          }
    30          function subscribe(method, params, callback) {
    31              var id = messageID.toString();
    32              messageID++;
    33              subscriptions[id] = callback;
    34              var req = {
    35                  id,
    36                  method,
    37                  params
    38              }
    39              ws.send(JSON.stringify(req));
    40              return id;
    41          }
    42          function unsubscribe(method, id, params, callback) {
    43              delete subscriptions[id];
    44              pendingMessages[id] = callback;
    45              var req = {
    46                  id,
    47                  method,
    48                  params
    49              }
    50              ws.send(JSON.stringify(req));
    51              return id;
    52          }
    53          function connect(server) {
    54              messageID = 0;
    55              pendingMessages = {};
    56              subscriptions = {};
    57              subscribeNewBlockId = "";
    58              subscribeAddressesId = "";
    59              if (server.startsWith("http")) {
    60                  server = server.replace("http", "ws");
    61              }
    62              if (!server.endsWith("/websocket")) {
    63                  server += "/websocket";
    64              }
    65              ws = new WebSocket(server);
    66              ws.onopen = function (e) {
    67                  console.log('socket connected', e);
    68                  document.getElementById('connectionStatus').innerText = "connected";
    69              };
    70              ws.onclose = function (e) {
    71                  console.log('socket closed', e);
    72                  document.getElementById('connectionStatus').innerText = "disconnected";
    73              };
    74              ws.onerror = function (e) {
    75                  console.log('socket error ', e);
    76                  document.getElementById('connectionStatus').innerText = "error";
    77              };
    78              ws.onmessage = function (e) {
    79                  console.log('resp ' + e.data);
    80                  var resp = JSON.parse(e.data);
    81                  var f = pendingMessages[resp.id];
    82                  if (f != undefined) {
    83                      delete pendingMessages[resp.id];
    84                      f(resp.data);
    85                  } else {
    86                      f = subscriptions[resp.id];
    87                      if (f != undefined) {
    88                          f(resp.data);
    89                      }
    90                      else {
    91                          console.log("unkown response " + resp.id);
    92                      }
    93                  }
    94              };
    95          }
    96  
    97          function getInfo() {
    98              const method = 'getInfo';
    99              const params = {
   100              };
   101              send(method, params, function (result) {
   102                  document.getElementById('getInfoResult').innerText = JSON.stringify(result).replace(/,/g, ", ");
   103              });
   104          }
   105  
   106          function ping() {
   107              const method = 'ping';
   108              const params = {
   109              };
   110              send(method, params, function (result) {
   111                  document.getElementById('pingResult').innerText = JSON.stringify(result).replace(/,/g, ", ");
   112              });
   113          }
   114  
   115          function getBlockHash() {
   116              const method = 'getBlockHash';
   117              const height = parseInt(document.getElementById("getBlockHashHeight").value);
   118              const params = {
   119                  height
   120              };
   121              send(method, params, function (result) {
   122                  document.getElementById('getBlockHashResult').innerText = JSON.stringify(result).replace(/,/g, ", ");
   123              });
   124          }
   125  
   126          function getAccountInfo() {
   127              const descriptor = document.getElementById('getAccountInfoDescriptor').value.trim();
   128              const selectDetails = document.getElementById('getAccountInfoDetails');
   129              const details = selectDetails.options[selectDetails.selectedIndex].value;
   130              const page = parseInt(document.getElementById("getAccountInfoPage").value);
   131              const from = parseInt(document.getElementById("getAccountInfoFrom").value);
   132              const to = parseInt(document.getElementById("getAccountInfoTo").value);
   133              const contractFilter = document.getElementById("getAccountInfoContract").value.trim();
   134              const pageSize = 10;
   135              const method = 'getAccountInfo';
   136              const tokens = "derived"; // could be "nonzero", "used", default is "derived" i.e. all
   137              const params = {
   138                  descriptor,
   139                  details,
   140                  tokens,
   141                  page,
   142                  pageSize,
   143                  from,
   144                  to,
   145                  contractFilter
   146                  // default gap=20
   147              };
   148              send(method, params, function (result) {
   149                  document.getElementById('getAccountInfoResult').innerText = JSON.stringify(result).replace(/,/g, ", ");
   150              });
   151          }
   152  
   153          function getAccountUtxo() {
   154              const descriptor = document.getElementById('getAccountUtxoDescriptor').value.trim();
   155              const method = 'getAccountUtxo';
   156              const params = {
   157                  descriptor,
   158              };
   159              send(method, params, function (result) {
   160                  document.getElementById('getAccountUtxoResult').innerText = JSON.stringify(result).replace(/,/g, ", ");
   161              });
   162          }
   163  
   164          function getBalanceHistory() {
   165              const descriptor = document.getElementById('getBalanceHistoryDescriptor').value.trim();
   166              const from = parseInt(document.getElementById("getBalanceHistoryFrom").value.trim());
   167              const to = parseInt(document.getElementById("getBalanceHistoryTo").value.trim());
   168              const currencies = document.getElementById('getBalanceHistoryFiat').value.split(",");
   169              const groupBy = parseInt(document.getElementById("getBalanceHistoryGroupBy").value);
   170              const method = 'getBalanceHistory';
   171              const params = {
   172                  descriptor,
   173                  from,
   174                  to,
   175                  currencies,
   176                  groupBy
   177                  // default gap=20
   178              };
   179              send(method, params, function (result) {
   180                  document.getElementById('getBalanceHistoryResult').innerText = JSON.stringify(result).replace(/,/g, ", ");
   181              });
   182          }
   183  
   184  
   185          function getTransaction() {
   186              const txid = document.getElementById('getTransactionTxid').value.trim();
   187              const method = 'getTransaction';
   188              const params = {
   189                  txid,
   190              };
   191              send(method, params, function (result) {
   192                  document.getElementById('getTransactionResult').innerText = JSON.stringify(result).replace(/,/g, ", ");
   193              });
   194          }
   195  
   196          function getTransactionSpecific() {
   197              const txid = document.getElementById('getTransactionSpecificTxid').value.trim();
   198              const method = 'getTransactionSpecific';
   199              const params = {
   200                  txid,
   201              };
   202              send(method, params, function (result) {
   203                  document.getElementById('getTransactionSpecificResult').innerText = JSON.stringify(result).replace(/,/g, ", ");
   204              });
   205          }
   206  
   207          function estimateFee() {
   208              try {
   209                  var blocks = document.getElementById('estimateFeeBlocks').value.split(",");
   210                  var specific = document.getElementById('estimateFeeSpecific').value.trim();
   211                  if (specific) {
   212                      // example for bitcoin type: {"conservative": false,"txsize":1234}
   213                      // example for ethereum type: {"from":"0x65513ecd11fd3a5b1fefdcc6a500b025008405a2","to":"0x65513ecd11fd3a5b1fefdcc6a500b025008405a2","data":"0xabcd"}
   214                      specific = JSON.parse(specific)
   215                  }
   216                  else {
   217                      specific = undefined;
   218                  }
   219                  blocks = blocks.map(s => parseInt(s.trim()));
   220                  const method = 'estimateFee';
   221                  const params = {
   222                      blocks,
   223                      specific
   224                  };
   225                  send(method, params, function (result) {
   226                      document.getElementById('estimateFeeResult').innerText = JSON.stringify(result).replace(/,/g, ", ");
   227                  });
   228              }
   229              catch (e) {
   230                  document.getElementById('estimateFeeResult').innerText = e;
   231              }
   232          }
   233  
   234          function sendTransaction() {
   235              var hex = document.getElementById('sendTransactionHex').value.trim();
   236              const method = 'sendTransaction';
   237              const params = {
   238                  hex,
   239              };
   240              send(method, params, function (result) {
   241                  document.getElementById('sendTransactionResult').innerText = JSON.stringify(result).replace(/,/g, ", ");
   242              });
   243          }
   244  
   245          function subscribeNewBlock() {
   246              const method = 'subscribeNewBlock';
   247              const params = {
   248              };
   249              if (subscribeNewBlockId) {
   250                  delete subscriptions[subscribeNewBlockId];
   251                  subscribeNewBlockId = "";
   252              }
   253              subscribeNewBlockId = subscribe(method, params, function (result) {
   254                  document.getElementById('subscribeNewBlockResult').innerText += JSON.stringify(result).replace(/,/g, ", ") + "\n";
   255              });
   256              document.getElementById('subscribeNewBlockId').innerText = subscribeNewBlockId;
   257              document.getElementById('unsubscribeNewBlockButton').setAttribute("style", "display: inherit;");
   258          }
   259  
   260          function unsubscribeNewBlock() {
   261              const method = 'unsubscribeNewBlock';
   262              const params = {
   263              };
   264              unsubscribe(method, subscribeNewBlockId, params, function (result) {
   265                  subscribeNewBlockId = "";
   266                  document.getElementById('subscribeNewBlockResult').innerText += JSON.stringify(result).replace(/,/g, ", ") + "\n";
   267                  document.getElementById('subscribeNewBlockId').innerText = "";
   268                  document.getElementById('unsubscribeNewBlockButton').setAttribute("style", "display: none;");
   269              });
   270          }
   271  
   272          function subscribeAddresses() {
   273              const method = 'subscribeAddresses';
   274              var addresses = document.getElementById('subscribeAddressesName').value.split(",");
   275              addresses = addresses.map(s => s.trim());
   276              const params = {
   277                  addresses
   278              };
   279              if (subscribeAddressesId) {
   280                  delete subscriptions[subscribeAddressesId];
   281                  subscribeAddressesId = "";
   282              }
   283              subscribeAddressesId = subscribe(method, params, function (result) {
   284                  document.getElementById('subscribeAddressesResult').innerText += JSON.stringify(result).replace(/,/g, ", ") + "\n";
   285              });
   286              document.getElementById('subscribeAddressesIds').innerText = subscribeAddressesId;
   287              document.getElementById('unsubscribeAddressesButton').setAttribute("style", "display: inherit;");
   288          }
   289  
   290          function unsubscribeAddresses() {
   291              const method = 'unsubscribeAddresses';
   292              const params = {
   293              };
   294              unsubscribe(method, subscribeAddressesId, params, function (result) {
   295                  subscribeAddressesId = "";
   296                  document.getElementById('subscribeAddressesResult').innerText += JSON.stringify(result).replace(/,/g, ", ") + "\n";
   297                  document.getElementById('subscribeAddressesIds').innerText = "";
   298                  document.getElementById('unsubscribeAddressesButton').setAttribute("style", "display: none;");
   299              });
   300          }
   301  
   302          function getFiatRatesForTimestamps() {
   303              const method = 'getFiatRatesForTimestamps';
   304              var timestamps = document.getElementById('getFiatRatesForTimestampsList').value.split(",");
   305              var currencies = document.getElementById('getFiatRatesForTimestampsCurrency').value.split(",");
   306              timestamps = timestamps.map(Number);
   307              const params = {
   308                  timestamps,
   309                  'currencies': currencies
   310              };
   311              send(method, params, function (result) {
   312                  document.getElementById('getFiatRatesForTimestampsResult').innerText = JSON.stringify(result).replace(/,/g, ", ");
   313              });
   314          }
   315  
   316          function getCurrentFiatRates() {
   317              const method = 'getCurrentFiatRates';
   318              var currencies = document.getElementById('getCurrentFiatRatesCurrency').value.split(",");
   319              const params = {
   320                  "currencies": currencies
   321              };
   322              send(method, params, function (result) {
   323                  document.getElementById('getCurrentFiatRatesResult').innerText = JSON.stringify(result).replace(/,/g, ", ");
   324              });
   325          }
   326  
   327          function getFiatRatesTickersList() {
   328              const method = 'getFiatRatesTickersList';
   329              var timestamp = document.getElementById('getFiatRatesTickersListDate').value;
   330              timestamp = parseInt(timestamp);
   331              const params = {
   332                  timestamp,
   333              };
   334              send(method, params, function (result) {
   335                  document.getElementById('getFiatRatesTickersListResult').innerText = JSON.stringify(result).replace(/,/g, ", ");
   336              });
   337          }
   338  
   339          function subscribeNewFiatRatesTicker() {
   340              const method = 'subscribeFiatRates';
   341              var currency = document.getElementById('subscribeFiatRatesCurrency').value;
   342              const params = {
   343                  "currency": currency
   344              };
   345              if (subscribeNewFiatRatesTickerId) {
   346                  delete subscriptions[subscribeNewFiatRatesTickerId];
   347                  subscribeNewFiatRatesTickerId = "";
   348              }
   349              subscribeNewFiatRatesTickerId = subscribe(method, params, function (result) {
   350                  document.getElementById('subscribeNewFiatRatesTickerResult').innerText += JSON.stringify(result).replace(/,/g, ", ") + "\n";
   351              });
   352              document.getElementById('subscribeNewFiatRatesTickerId').innerText = subscribeNewFiatRatesTickerId;
   353              document.getElementById('unsubscribeNewFiatRatesTickerButton').setAttribute("style", "display: inherit;");
   354          }
   355  
   356          function unsubscribeNewFiatRatesTicker() {
   357              const method = 'unsubscribeFiatRates';
   358              const params = {
   359              };
   360              unsubscribe(method, subscribeNewFiatRatesTickerId, params, function (result) {
   361                  subscribeNewFiatRatesTickerId = "";
   362                  document.getElementById('subscribeNewFiatRatesTickerResult').innerText += JSON.stringify(result).replace(/,/g, ", ") + "\n";
   363                  document.getElementById('subscribeNewFiatRatesTickerId').innerText = "";
   364                  document.getElementById('unsubscribeNewFiatRatesTickerButton').setAttribute("style", "display: none;");
   365              });
   366          }
   367      </script>
   368  </head>
   369  
   370  <body>
   371      <div class="container">
   372          <div class="row justify-content-center">
   373              <h1>Blockbook Websocket Test Page</h1>
   374          </div>
   375          <div class="row">
   376              <div class="col">
   377                  <input class="btn btn-secondary" type="button" value="Login" onclick="connect(document.getElementById('serverAddress').value)">
   378              </div>
   379              <div class="col-8">
   380                  <input type="text" class="form-control" id="serverAddress" value="">
   381              </div>
   382              <div class="col form-inline">
   383                  <label id="connectionStatus">not connected</label>
   384              </div>
   385          </div>
   386          <div class="row">
   387              <div class="col">
   388                  <input class="btn btn-secondary" type="button" value="getInfo" onclick="getInfo()">
   389              </div>
   390              <div class="col-10" id="getInfoResult">
   391              </div>
   392          </div>
   393          <div class="row">
   394              <div class="col">
   395                  <input class="btn btn-secondary" type="button" value="ping" onclick="ping()">
   396              </div>
   397              <div class="col-10" id="pingResult">
   398              </div>
   399          </div>
   400          <div class="row">
   401              <div class="col">
   402                  <input class="btn btn-secondary" type="button" value="getBlockHash" onclick="getBlockHash()">
   403              </div>
   404              <div class="col-8">
   405                  <input type="text" class="form-control" placeholder="height" id="getBlockHashHeight" value="0">
   406              </div>
   407              <div class="col">
   408              </div>
   409          </div>
   410          <div class="row">
   411              <div class="col" id="getBlockHashResult"></div>
   412          </div>
   413          <div class="row">
   414              <div class="col">
   415                  <input class="btn btn-secondary" type="button" value="getAccountInfo" onclick="getAccountInfo()">
   416              </div>
   417              <div class="col-8">
   418                  <div class="row" style="margin: 0;">
   419                      <input type="text" placeholder="descriptor" style="width: 79%" class="form-control" id="getAccountInfoDescriptor" value="0xba98d6a5ac827632e3457de7512d211e4ff7e8bd">
   420                      <select id="getAccountInfoDetails" style="width: 20%; margin-left: 5px;">
   421                          <option value="basic">Basic</option>
   422                          <option value="tokens">Tokens</option>
   423                          <option value="tokenBalances">TokenBalances</option>
   424                          <option value="txids">Txids</option>
   425                          <option value="txs">Transactions</option>
   426                      </select>
   427                  </div>
   428                  <div class="row" style="margin: 0; margin-top: 5px;">
   429                      <input type="text" placeholder="page" style="width: 10%; margin-right: 5px;" class="form-control" id="getAccountInfoPage">
   430                      <input type="text" placeholder="from" style="width: 15%;margin-left: 5px;margin-right: 5px;" class="form-control" id="getAccountInfoFrom">
   431                      <input type="text" placeholder="to" style="width: 15%; margin-left: 5px; margin-right: 5px;" class="form-control" id="getAccountInfoTo">
   432                      <input type="text" placeholder="contract" style="width: 55%; margin-left: 5px; margin-right: 5px;" class="form-control" id="getAccountInfoContract">
   433                  </div>
   434              </div>
   435              <div class="col form-inline"></div>
   436          </div>
   437          <div class="row">
   438              <div class="col" id="getAccountInfoResult">
   439              </div>
   440          </div>
   441          <div class="row">
   442              <div class="col">
   443                  <input class="btn btn-secondary" type="button" value="getAccountUtxo" onclick="getAccountUtxo()">
   444              </div>
   445              <div class="col-8">
   446                  <div class="row" style="margin: 0;">
   447                      <input type="text" placeholder="descriptor" class="form-control" id="getAccountUtxoDescriptor" value="0xba98d6a5ac827632e3457de7512d211e4ff7e8bd">
   448                   </div>
   449              </div>
   450              <div class="col form-inline"></div>
   451          </div>
   452          <div class="row">
   453              <div class="col" id="getAccountUtxoResult">
   454              </div>
   455          </div>
   456          <div class="row">
   457              <div class="col">
   458                  <input class="btn btn-secondary" type="button" value="getBalanceHistory" onclick="getBalanceHistory()">
   459              </div>
   460              <div class="col-8">
   461                  <div class="row" style="margin: 0;">
   462                      <input type="text" placeholder="descriptor" class="form-control" id="getBalanceHistoryDescriptor" value="0xba98d6a5ac827632e3457de7512d211e4ff7e8bd">
   463                  </div>
   464                  <div class="row" style="margin: 0; margin-top: 5px;">
   465                      <input type="text" placeholder="from Unix TS" style="width: 20%;margin-left: 5px;margin-right: 5px;" class="form-control" id="getBalanceHistoryFrom">
   466                      <input type="text" placeholder="to Unix TS" style="width: 20%; margin-left: 5px; margin-right: 5px;" class="form-control" id="getBalanceHistoryTo">
   467                      <input type="text" placeholder="usd,eur" style="width: 20%; margin-left: 5px; margin-right: 5px;" class="form-control" id="getBalanceHistoryFiat">
   468                      <input type="text" placeholder="group by (sec)" style="width: 20%; margin-left: 5px; margin-right: 5px;" class="form-control" id="getBalanceHistoryGroupBy">
   469                  </div>
   470              </div>
   471              <div class="col form-inline"></div>
   472          </div>
   473          <div class="row">
   474              <div class="col" id="getBalanceHistoryResult">
   475              </div>
   476          </div>
   477          <div class="row">
   478              <div class="col">
   479                  <input class="btn btn-secondary" type="button" value="getTransaction" onclick="getTransaction()">
   480              </div>
   481              <div class="col-8">
   482                  <div class="row" style="margin: 0;">
   483                      <input type="text" placeholder="txid" class="form-control" id="getTransactionTxid" value="0xb266c89f9bfefa4aa2fca4e65b7d6c918d5407f464be781c2803f3546d34a574">
   484                   </div>
   485              </div>
   486              <div class="col form-inline"></div>
   487          </div>
   488          <div class="row">
   489              <div class="col" id="getTransactionResult">
   490              </div>
   491          </div>
   492          <div class="row">
   493              <div class="col">
   494                  <input class="btn btn-secondary" type="button" value="getTransactionSpecific" onclick="getTransactionSpecific()">
   495              </div>
   496              <div class="col-8">
   497                  <div class="row" style="margin: 0;">
   498                      <input type="text" placeholder="txid" class="form-control" id="getTransactionSpecificTxid" value="0xb266c89f9bfefa4aa2fca4e65b7d6c918d5407f464be781c2803f3546d34a574">
   499                   </div>
   500              </div>
   501              <div class="col form-inline"></div>
   502          </div>
   503          <div class="row">
   504              <div class="col" id="getTransactionSpecificResult">
   505              </div>
   506          </div>
   507          <div class="row">
   508              <div class="col">
   509                  <input class="btn btn-secondary" type="button" value="estimateFee" onclick="estimateFee()">
   510              </div>
   511              <div class="col-8">
   512                  <div class="row" style="margin: 0;">
   513                      <input type="text" placeholder="comma separated list of block targets" class="form-control" id="estimateFeeBlocks" value="2,5,10,20">
   514                  </div>
   515                  <div class="row" style="margin: 0; margin-top: 5px;">
   516                      <input type="text" placeholder="tx specific JSON" class="form-control" id="estimateFeeSpecific" value="">
   517                  </div>
   518              </div>
   519              <div class="col"></div>
   520          </div>
   521          <div class="row">
   522              <div class="col" id="estimateFeeResult">
   523              </div>
   524          </div>
   525          <div class="row">
   526              <div class="col">
   527                  <input class="btn btn-secondary" type="button" value="sendTransaction" onclick="sendTransaction()">
   528              </div>
   529              <div class="col-8">
   530                  <input type="text" class="form-control" id="sendTransactionHex" value="010000000001019d64f0c72a0d206001decbffaa722eb1044534c74eee7a5df8318e42a4323ec10000000017160014550da1f5d25a9dae2eafd6902b4194c4c6500af6ffffffff02809698000000000017a914cd668d781ece600efa4b2404dc91fd26b8b8aed8870553d7360000000017a914246655bdbd54c7e477d0ea2375e86e0db2b8f80a8702473044022076aba4ad559616905fa51d4ddd357fc1fdb428d40cb388e042cdd1da4a1b7357022011916f90c712ead9a66d5f058252efd280439ad8956a967e95d437d246710bc9012102a80a5964c5612bb769ef73147b2cf3c149bc0fd4ecb02f8097629c94ab013ffd00000000">
   531              </div>
   532              <div class="col">
   533              </div>
   534          </div>
   535          <div class="row">
   536              <div class="col" id="sendTransactionResult"></div>
   537          </div>
   538          <div class="row">
   539              <div class="col-2">
   540                  <input class="btn btn-secondary" type="button" value="get fiat rates for dates" onclick="getFiatRatesForTimestamps()">
   541              </div>
   542              <div class="col-1">
   543                  <input type="text" class="form-control" id="getFiatRatesForTimestampsCurrency" placeholder="usd,eur">
   544              </div>
   545              <div class="col-7">
   546                  <input type="text" class="form-control" id="getFiatRatesForTimestampsList" value="1575288000,1575550800">
   547              </div>
   548          </div>
   549          <div class="row">
   550              <div class="col" id="getFiatRatesForTimestampsResult"></div>
   551          </div>
   552          <div class="row">
   553              <div class="col-2">
   554                  <input class="btn btn-secondary" type="button" value="get current fiat rates" onclick="getCurrentFiatRates()">
   555              </div>
   556              <div class="col-1">
   557                  <input type="text" class="form-control" id="getCurrentFiatRatesCurrency" placeholder="usd">
   558              </div>
   559          </div>
   560          <div class="row">
   561              <div class="col" id="getCurrentFiatRatesResult"></div>
   562          </div>
   563          <div class="row">
   564              <div class="col-2">
   565                  <input class="btn btn-secondary" type="button" value="get fiat rates tickers" onclick="getFiatRatesTickersList()">
   566              </div>
   567              <div class="col-8">
   568                  <input type="text" class="form-control" id="getFiatRatesTickersListDate" value="1576591569" placeholder="Unix timestamp">
   569              </div>
   570          </div>
   571          <div class="row">
   572              <div class="col" id="getFiatRatesTickersListResult"></div>
   573          </div>
   574          <div class="row">
   575              <div class="col">
   576                  <input class="btn btn-secondary" type="button" value="subscribe new block" onclick="subscribeNewBlock()">
   577              </div>
   578              <div class="col-4">
   579                  <span id="subscribeNewBlockId"></span>
   580              </div>
   581              <div class="col">
   582                  <input class="btn btn-secondary" id="unsubscribeNewBlockButton" style="display: none;" type="button" value="unsubscribe" onclick="unsubscribeNewBlock()">
   583              </div>
   584          </div>
   585          <div class="row">
   586              <div class="col" id="subscribeNewBlockResult"></div>
   587          </div>
   588          <div class="row">
   589              <div class="col">
   590                  <input class="btn btn-secondary" type="button" value="subscribe address" onclick="subscribeAddresses()">
   591              </div>
   592              <div class="col-8">
   593                  <input type="text" class="form-control" id="subscribeAddressesName" value="0xba98d6a5ac827632e3457de7512d211e4ff7e8bd,0x73d0385f4d8e00c5e6504c6030f47bf6212736a8">
   594              </div>
   595              <div class="col">
   596                  <span id="subscribeAddressesIds"></span>
   597              </div>
   598              <div class="col">
   599                  <input class="btn btn-secondary" id="unsubscribeAddressesButton" style="display: none;" type="button" value="unsubscribe" onclick="unsubscribeAddresses()">
   600              </div>
   601          </div>
   602          <div class="row">
   603              <div class="col" id="subscribeAddressesResult"></div>
   604          </div>
   605          <div class="row">
   606              <div class="col-3">
   607                  <input class="btn btn-secondary" type="button" value="subscribe new fiat rates" onclick="subscribeNewFiatRatesTicker()">
   608              </div>
   609              <div class="col-1">
   610                  <span id="subscribeNewFiatRatesTickerId"></span>
   611              </div>
   612              <div class="col-1">
   613                  <input type="text" class="form-control" id="subscribeFiatRatesCurrency" value="usd">
   614              </div>
   615              <div class="col-5">
   616                  <input class="btn btn-secondary" id="unsubscribeNewFiatRatesTickerButton" style="display: none;" type="button" value="unsubscribe" onclick="unsubscribeNewFiatRatesTicker()">
   617              </div>
   618          </div>
   619          <div class="row">
   620              <div class="col" id="subscribeNewFiatRatesTickerResult"></div>
   621          </div>
   622      </div>
   623      <br><br>
   624  </body>
   625  <script>
   626      document.getElementById('serverAddress').value = window.location.protocol + "//" + window.location.host;
   627  </script>
   628  
   629  </html>