Changes of Revision 37

libosmocore.spec Changed
x
 
1
@@ -14,13 +14,13 @@
2
 
3
 Name:           libosmocore
4
 Requires: osmocom-master
5
-Version: 1.7.0.86.23a7
6
+Version: 1.7.0.87.7a79
7
 Release:        0
8
 Summary:        The Open Source Mobile Communications Core Library
9
 License:        GPL-2.0-only AND GPL-2.0-or-later AND LGPL-2.1-or-later AND AGPL-3.0-or-later
10
 Group:          Productivity/Telephony/Utilities
11
 Url:            https://osmocom.org/projects/libosmocore/wiki/Libosmocore
12
-Source: libosmocore_1.7.0.86.23a7.tar.xz
13
+Source: libosmocore_1.7.0.87.7a79.tar.xz
14
 Source1: rpmlintrc
15
 BuildRequires:  automake >= 1.6
16
 BuildRequires:  libtool >= 2
17
commit_23a7d0740c7879b5c6d1f883b6a999359932547b.txt Deleted
commit_7a79dd3dab4986ce159a42907cb074c6d25b856b.txt Added
libosmocore_1.7.0.86.23a7.dsc -> libosmocore_1.7.0.87.7a79.dsc Changed
22
 
1
@@ -2,7 +2,7 @@
2
 Source: libosmocore
3
 Binary: libosmocore, libosmocodec0, libosmocodec-doc, libosmocoding0, libosmocoding-doc, libosmocore19, libosmocore-doc, libosmogb14, libosmogb-doc, libosmogsm18, libosmogsm-doc, libosmovty9, libosmovty-doc, libosmoctrl0, libosmoctrl-doc, libosmosim2, libosmousb0, libosmocore-dev, libosmocore-utils, libosmocore-dbg
4
 Architecture: any all
5
-Version: 1.7.0.86.23a7
6
+Version: 1.7.0.87.7a79
7
 Maintainer: Osmocom team <openbsc@lists.osmocom.org>
8
 Homepage: https://projects.osmocom.org/projects/libosmocore
9
 Standards-Version: 3.9.8
10
@@ -31,8 +31,8 @@
11
  libosmovty-doc deb doc optional arch=all
12
  libosmovty9 deb libs optional arch=any
13
 Checksums-Sha1:
14
- a294756db8836d168e15e6e39b215307802cc282 1002800 libosmocore_1.7.0.86.23a7.tar.xz
15
+ 22168c3abadbf3d5dd17e3bcb7c98abb754b1df9 1004348 libosmocore_1.7.0.87.7a79.tar.xz
16
 Checksums-Sha256:
17
- 86f10b05fdcaf9b5288736064f77a89397ef94c83fe796bd608ea626f8392b6f 1002800 libosmocore_1.7.0.86.23a7.tar.xz
18
+ 0780cf24c5c40cd063a2a28a8d1be7c2eb8fcc2dc26bd5cebc38321a5a084f03 1004348 libosmocore_1.7.0.87.7a79.tar.xz
19
 Files:
20
- 128a570198b7040fa84ac778e4fde632 1002800 libosmocore_1.7.0.86.23a7.tar.xz
21
+ 519c08f1872847a54338c04150b1f39b 1004348 libosmocore_1.7.0.87.7a79.tar.xz
22
libosmocore_1.7.0.86.23a7.tar.xz/.tarball-version -> libosmocore_1.7.0.87.7a79.tar.xz/.tarball-version Changed
4
 
1
@@ -1 +1 @@
2
-1.7.0.86-23a7
3
+1.7.0.87-7a79
4
libosmocore_1.7.0.86.23a7.tar.xz/configure.ac -> libosmocore_1.7.0.87.7a79.tar.xz/configure.ac Changed
9
 
1
@@ -599,6 +599,7 @@
2
    tests/Makefile
3
    tests/atlocal
4
    utils/Makefile
5
+   utils/osmo-stat-dummy/Makefile
6
    Doxyfile.core
7
    Doxyfile.gsm
8
    Doxyfile.vty
9
libosmocore_1.7.0.86.23a7.tar.xz/debian/changelog -> libosmocore_1.7.0.87.7a79.tar.xz/debian/changelog Changed
12
 
1
@@ -1,8 +1,8 @@
2
-libosmocore (1.7.0.86.23a7) unstable; urgency=medium
3
+libosmocore (1.7.0.87.7a79) unstable; urgency=medium
4
 
5
   * Automatically generated changelog entry for building the Osmocom master feed
6
 
7
- -- Osmocom OBS scripts <info@osmocom.org>  Mon, 19 Dec 2022 15:57:37 +0000
8
+ -- Osmocom OBS scripts <info@osmocom.org>  Tue, 20 Dec 2022 11:32:37 +0000
9
 
10
 libosmocore (1.7.0) unstable; urgency=medium
11
 
12
libosmocore_1.7.0.86.23a7.tar.xz/utils/Makefile.am -> libosmocore_1.7.0.87.7a79.tar.xz/utils/Makefile.am Changed
12
 
1
@@ -29,6 +29,10 @@
2
 endif
3
 
4
 if ENABLE_EXT_TESTS
5
+SUBDIRS = \
6
+   osmo-stat-dummy \
7
+   $(NULL)
8
+
9
 if ENABLE_GB
10
 noinst_PROGRAMS += osmo-ns-dummy
11
 osmo_ns_dummy_SOURCES = osmo-ns-dummy.c osmo-ns-dummy-vty.c
12
libosmocore_1.7.0.87.7a79.tar.xz/utils/osmo-stat-dummy Added
2
 
1
+(directory)
2
libosmocore_1.7.0.87.7a79.tar.xz/utils/osmo-stat-dummy/Makefile.am Added
10
 
1
@@ -0,0 +1,8 @@
2
+noinst_PROGRAMS = osmo-stat-dummy
3
+osmo_stat_dummy_SOURCES = osmo-stat-dummy.c
4
+osmo_stat_dummy_LDADD = $(LDADD) $(TALLOC_LIBS) \
5
+           $(top_builddir)/src/vty/libosmovty.la \
6
+           $(top_builddir)/src/ctrl/libosmoctrl.la \
7
+           $(top_builddir)/src/libosmocore.la
8
+osmo_stat_dummy_CFLAGS = -Wall $(TALLOC_CFLAGS) $(LIBOSMOCORE_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(LIBOSMOCTRL_CFLAGS)
9
+osmo_stat_dummy_CPPFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/include
10
libosmocore_1.7.0.87.7a79.tar.xz/utils/osmo-stat-dummy/README.md Added
14
 
1
@@ -0,0 +1,12 @@
2
+# Osmocom utilities
3
+
4
+* osmo-stat-dummy: utility for rate counter and statsd testing
5
+
6
+It has 2 rate counters: one ticks twice a seconds, another one can be manually updated with 'update-rate-ctr' command via vty.
7
+
8
+The raw value is sent via statsd protocol. If you install "netdata" monitoring tool than you can open http://localhost:19999 in browser
9
+and observe live counters monitoring under "StatsD dummy" without any additional setup.
10
+
11
+Opening osmo-stat-dummy.html in browser while both netdata and osmo-stat-dummy are running will show dimensioned (per min/hour/day) rate counters as well as raw data.
12
+
13
+The latter is handy for troubleshooting and comparing libosmocore's internal rate counter computation.
14
libosmocore_1.7.0.87.7a79.tar.xz/utils/osmo-stat-dummy/osmo-stat-dummy.c Added
337
 
1
@@ -0,0 +1,335 @@
2
+/* Rate counter and statsd test application */
3
+/* (C) 2022 by by sysmocom - s.f.m.c. GmbH
4
+ * All Rights Reserved
5
+ *
6
+ * This program is free software; you can redistribute it and/or modify
7
+ * it under the terms of the GNU General Public License as published by
8
+ * the Free Software Foundation; either version 3 of the License, or
9
+ * (at your option) any later version.
10
+ *
11
+ * This program is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
+ * GNU General Public License for more details.
15
+ *
16
+ */
17
+
18
+#include <errno.h>
19
+#include <stdlib.h>
20
+#include <stdio.h>
21
+#include <getopt.h>
22
+#include <signal.h>
23
+#include <unistd.h>
24
+#include <inttypes.h>
25
+
26
+#include <osmocom/core/select.h>
27
+#include <osmocom/core/application.h>
28
+#include <osmocom/core/stats.h>
29
+#include <osmocom/ctrl/control_if.h>
30
+#include <osmocom/ctrl/control_vty.h>
31
+#include <osmocom/vty/vty.h>
32
+#include <osmocom/vty/telnet_interface.h>
33
+#include <osmocom/vty/command.h>
34
+#include <osmocom/vty/ports.h>
35
+#include <osmocom/vty/tdef_vty.h>
36
+#include <osmocom/vty/logging.h>
37
+#include <osmocom/vty/stats.h>
38
+#include <osmocom/vty/misc.h>
39
+
40
+#include "../../config.h"
41
+
42
+void *tall_statdummy_ctx  = NULL;
43
+static bool quit = false;
44
+static bool config_given = false;
45
+struct rate_ctr_group *g_ctrg;
46
+
47
+enum dummy_rate_ctr_idx {
48
+   DUMMY_VTY = 0,
49
+   DUMMY_AUTO,
50
+};
51
+
52
+static void print_help(void)
53
+{
54
+   printf("Some useful options:\n"
55
+       "  -h   --help          This text\n"
56
+       "  -c   --config-file       Specify the filename of the config file\n"
57
+       "  -V   --version       Print version\n"
58
+       "\nVTY reference generation:\n"
59
+       "   --vty-ref-mode MODE VTY reference generation mode (e.g. 'expert').\n"
60
+       "   --vty-ref-xml       Generate the VTY reference XML output and exit.\n"
61
+       );
62
+}
63
+
64
+static void handle_long_options(const char *prog_name, const int long_option)
65
+{
66
+   static int vty_ref_mode = VTY_REF_GEN_MODE_DEFAULT;
67
+
68
+   switch (long_option) {
69
+   case 1:
70
+       vty_ref_mode = get_string_value(vty_ref_gen_mode_names, optarg);
71
+       if (vty_ref_mode < 0) {
72
+           fprintf(stderr, "%s: Unknown VTY reference generation mode '%s'\n", prog_name, optarg);
73
+           exit(2);
74
+       }
75
+       break;
76
+   case 2:
77
+       fprintf(stderr, "Generating the VTY reference in mode '%s' (%s)\n",
78
+           get_value_string(vty_ref_gen_mode_names, vty_ref_mode),
79
+           get_value_string(vty_ref_gen_mode_desc, vty_ref_mode));
80
+       vty_dump_xml_ref_mode(stdout, (enum vty_ref_gen_mode) vty_ref_mode);
81
+       exit(0);
82
+   default:
83
+       fprintf(stderr, "%s: error parsing cmdline options\n", prog_name);
84
+       exit(2);
85
+   }
86
+}
87
+
88
+static char *handle_options(int argc, char **argv)
89
+{
90
+   char *config_file = NULL;
91
+
92
+   while (1) {
93
+       int option_idx = 0, c;
94
+       static int long_option = 0;
95
+       static const struct option long_options = {
96
+           { "help", 0, 0, 'h' },
97
+           { "config-file", 1, 0, 'c' },
98
+           { "version", 0, 0, 'V' },
99
+           { "vty-ref-mode", 1, &long_option, 1 },
100
+           { "vty-ref-xml", 0, &long_option, 2 },
101
+           { 0, 0, 0, 0 }
102
+       };
103
+
104
+       c = getopt_long(argc, argv, "hc:V", long_options, &option_idx);
105
+       if (c == -1)
106
+           break;
107
+
108
+       switch (c) {
109
+       case 'h':
110
+           print_help();
111
+           exit(0);
112
+           break;
113
+       case 0:
114
+           handle_long_options(argv0, long_option);
115
+           break;
116
+       case 'c':
117
+           if (config_file)
118
+               free(config_file);
119
+           config_file = optarg;
120
+           config_given = true;
121
+           break;
122
+       case 'V':
123
+           print_version(1);
124
+           exit(0);
125
+           break;
126
+       default:
127
+           fprintf(stderr, "Unknown option '%c'\n", c);
128
+           exit(0);
129
+           break;
130
+       }
131
+   }
132
+
133
+   if (!config_file)
134
+       return "osmo-stat-dummy.cfg";
135
+
136
+   return config_file;
137
+}
138
+
139
+void sighandler(int sigset)
140
+{
141
+   if (sigset == SIGPIPE)
142
+       return;
143
+
144
+   fprintf(stderr, "Signal %d received.\n", sigset);
145
+
146
+   switch (sigset) {
147
+   case SIGINT:
148
+   case SIGTERM:
149
+       /* If another signal is received afterwards, the program
150
+        * is terminated without finishing shutdown process.
151
+        */
152
+       signal(SIGINT, SIG_DFL);
153
+       signal(SIGTERM, SIG_DFL);
154
+       signal(SIGPIPE, SIG_DFL);
155
+       signal(SIGABRT, SIG_DFL);
156
+       signal(SIGUSR1, SIG_DFL);
157
+       signal(SIGUSR2, SIG_DFL);
158
+
159
+       quit = 1;
160
+       break;
161
+   case SIGABRT:
162
+       /* in case of abort, we want to obtain a talloc report and
163
+        * then run default SIGABRT handler, who will generate coredump
164
+        * and abort the process. abort() should do this for us after we
165
+        * return, but program wouldn't exit if an external SIGABRT is
166
+        * received.
167
+        */
168
+       talloc_report_full(tall_statdummy_ctx, stderr);
169
+       signal(SIGABRT, SIG_DFL);
170
+       raise(SIGABRT);
171
+       break;
172
+   case SIGUSR1:
173
+   case SIGUSR2:
174
+       talloc_report_full(tall_statdummy_ctx, stderr);
175
+       break;
176
+   }
177
+}
178
+
179
+static int rate_ctr_timer_cb(struct osmo_fd *ofd, unsigned int what)
180
+{
181
+   uint64_t expire_count;
182
+   int rc;
183
+
184
+   /* check that the timer has actually expired */
185
+   if (!(what & OSMO_FD_READ))
186
+       return 0;
187
+
188
+   /* read from timerfd: number of expirations of periodic timer */
189
+   rc = read(ofd->fd, (void *) &expire_count, sizeof(expire_count));
190
+   if (rc < 0 && errno == EAGAIN)
191
+       return 0;
192
+
193
+   OSMO_ASSERT(rc == sizeof(expire_count));
194
+
195
+   if (expire_count > 1)
196
+       LOGP(DLGLOBAL, LOGL_NOTICE, "Stats timer expire_count=%" PRIu64 ": We missed %" PRIu64 " timers\n",
197
+           expire_count, expire_count-1);
198
+
199
+   /* Increment the counter value */
200
+   rate_ctr_inc(rate_ctr_group_get_ctr(g_ctrg, DUMMY_AUTO));
201
+
202
+   return 0;
203
+}
204
+
205
+DEFUN(update_rate_ctr, update_rate_ctr_cmd,
206
+      "update-rate-ctr <0-100000>",
207
+      "Update dummy rate counter\n"
208
+      "Value to add to rate counter\n")
209
+{
210
+   rate_ctr_add(rate_ctr_group_get_ctr(g_ctrg, DUMMY_VTY), atoi(argv0));
211
+
212
+   return CMD_SUCCESS;
213
+}
214
+
215
+static int statdummy_vty_init(void)
216
+{
217
+   install_element_ve(&update_rate_ctr_cmd);
218
+
219
+   return 0;
220
+}
221
+
222
+int main(int argc, char *argv)
223
+{
224
+   struct log_info log_info = {};
225
+   char *config_file;
226
+   void *ctx = tall_statdummy_ctx = talloc_named_const(NULL, 0, "osmo-stat-dummy");
227
+   struct ctrl_handle *ctrl;
228
+   struct osmo_fd rate_ctr_timer = { .fd = -1 };
229
+   struct timespec ts_interval = { .tv_sec = 0, .tv_nsec = 500000000 }; /* 0.5 seconds */
230
+   int rc = 0;
231
+
232
+   const char vty_copyright =
233
+   "Copyright (C) 2022 by by sysmocom - s.f.m.c. GmbH\r\n"
234
+   "Author: Max Suraev <msuraev@sysmocom.de>\r\n"
235
+   "License GNU GPL version 3 or later\r\n"
236
+   "This is free software: you are free to change and redistribute it.\r\n"
237
+   "There is NO WARRANTY, to the extent permitted by law.\r\n";
238
+
239
+   struct vty_app_info vty_info = {
240
+       .name       = "OsmoSTATdummy",
241
+       .version    = PACKAGE_VERSION,
242
+       .copyright  = vty_copyright,
243
+       .tall_ctx   = ctx
244
+   };
245
+
246
+   const struct rate_ctr_desc dummy_ctr_desc = {
247
+       DUMMY_VTY = { "dummy:vty", "Dummy counter updated via VTY" },
248
+       DUMMY_AUTO =    { "dummy:auto", "Dummy counter autoupdated via timer" },
249
+   };
250
+
251
+   const struct rate_ctr_group_desc dummy_ctrg_desc = {
252
+       "dummy",
253
+       "dummy stat tester",
254
+       OSMO_STATS_CLASS_GLOBAL,
255
+       ARRAY_SIZE(dummy_ctr_desc),
256
+       dummy_ctr_desc,
257
+   };
258
+
259
+   osmo_init_logging2(ctx, &log_info);
260
+   log_set_use_color(osmo_stderr_target, 0);
261
+   log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_NONE);
262
+   log_set_log_level(osmo_stderr_target, LOGL_INFO);
263
+
264
+   msgb_talloc_ctx_init(ctx, 0);
265
+
266
+   vty_init(&vty_info);
267
+   ctrl_vty_init(ctx);
268
+   logging_vty_add_cmds();
269
+   osmo_stats_vty_add_cmds();
270
+   osmo_talloc_vty_add_cmds();
271
+
272
+   config_file = handle_options(argc, argv);
273
+
274
+   statdummy_vty_init();
275
+   rc = vty_read_config_file(config_file, NULL);
276
+   if (rc < 0) {
277
+       if (config_given) {
278
+           fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file);
279
+           exit(1);
280
+       }
281
+       fprintf(stderr, "No config file: '%s' Using default config.\n", config_file);
282
+   }
283
+
284
+   rc = telnet_init_default(ctx, NULL, -1);
285
+   if (rc < 0) {
286
+       fprintf(stderr, "Error initializing telnet\n");
287
+       exit(1);
288
+   }
289
+
290
+   ctrl = ctrl_interface_setup(NULL, 1234, NULL);
291
+   if (!ctrl) {
292
+       fprintf(stderr, "Failed to initialize control interface. Exiting.\n");
293
+       exit(1);
294
+   }
295
+
296
+   g_ctrg = rate_ctr_group_alloc(ctx, &dummy_ctrg_desc, 0);
297
+   if (!g_ctrg) {
298
+       fprintf(stderr, "Failed to initialize rate counters. Exiting.\n");
299
+       return -1;
300
+   }
301
+
302
+   osmo_stats_init(ctx);
303
+   rate_ctr_init(ctx);
304
+
305
+   rc = osmo_timerfd_setup(&rate_ctr_timer, rate_ctr_timer_cb, NULL);
306
+   if (rc < 0) {
307
+       LOGP(DLGLOBAL, LOGL_ERROR, "Failed to setup the timer with error code %d (fd=%d)\n",
308
+            rc, rate_ctr_timer.fd);
309
+       return rc;
310
+   }
311
+
312
+   rc = osmo_timerfd_schedule(&rate_ctr_timer, NULL, &ts_interval);
313
+   if (rc < 0) {
314
+       LOGP(DLGLOBAL, LOGL_ERROR, "Failed to schedule the timer with error code %d (fd=%d)\n",
315
+            rc, rate_ctr_timer.fd);
316
+   }
317
+
318
+   signal(SIGINT, sighandler);
319
+   signal(SIGTERM, sighandler);
320
+   signal(SIGPIPE, sighandler);
321
+   signal(SIGABRT, sighandler);
322
+   signal(SIGUSR1, sighandler);
323
+   signal(SIGUSR2, sighandler);
324
+   osmo_init_ignore_signals();
325
+
326
+   while (!quit) {
327
+       osmo_select_main(0);
328
+   }
329
+
330
+   telnet_exit();
331
+
332
+   talloc_report_full(tall_statdummy_ctx, stderr);
333
+   talloc_free(tall_statdummy_ctx);
334
+
335
+   return 0;
336
+}
337
libosmocore_1.7.0.87.7a79.tar.xz/utils/osmo-stat-dummy/osmo-stat-dummy.cfg Added
42
 
1
@@ -0,0 +1,40 @@
2
+log stderr
3
+ logging filter all 1
4
+ logging color 0
5
+ logging timestamp 0
6
+ logging print extended-timestamp 0
7
+ logging print category-hex 0
8
+ logging print category 1
9
+ !logging print file basename
10
+ ! log-levels defined by libosmocore and hence available everywhere, can be overridden by inidividual per-app configs below
11
+ logging level lstats notice
12
+ logging level lglobal notice
13
+ logging level llapd notice
14
+ logging level linp notice
15
+ logging level lmux notice
16
+ logging level lmi notice
17
+ logging level lmib notice
18
+ logging level lsms notice
19
+ logging level lctrl notice
20
+ logging level lgtp notice
21
+ logging level lgsup notice
22
+ logging level loap notice
23
+ logging level lss7 error
24
+ logging level lsccp notice
25
+ logging level lsua notice
26
+ logging level lm3ua notice
27
+ logging level lmgcp notice
28
+ logging level ljibuf notice
29
+ logging level lrspro notice
30
+stats reporter statsd
31
+ !use default https://learn.netdata.cloud/ statsd plugin:
32
+ remote-ip 127.0.0.1
33
+ remote-port 8125
34
+ level global
35
+ no prefix
36
+ enable
37
+stats interval 1
38
+line vty
39
+ bind 127.0.0.2 6969
40
+ctrl
41
+ bind 127.0.0.11 1234
42
libosmocore_1.7.0.87.7a79.tar.xz/utils/osmo-stat-dummy/osmo-stat-dummy.html Added
61
 
1
@@ -0,0 +1,59 @@
2
+<!DOCTYPE html>
3
+<html lang="en">
4
+<head>
5
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
6
+    <meta charset="utf-8">
7
+    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
8
+    <meta name="viewport" content="width=device-width, initial-scale=1">
9
+    <meta name="apple-mobile-web-app-capable" content="yes">
10
+    <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
11
+</head>
12
+<body>
13
+  <div data-netdata="statsd_dummy.0.dummy.auto_counter"
14
+       data-chart-library="dygraph"
15
+       data-title="raw data (timerfd ticks twice per second)"
16
+       data-width="600"
17
+       data-height="200"
18
+       data-after="-600"
19
+       ></div>
20
+  <div data-netdata="statsd_dummy.0.dummy.auto_counter"
21
+       data-chart-library="dygraph"
22
+       data-title="aggregated per minute (timerfd ticks twice per second)"
23
+       data-width="600"
24
+       data-height="200"
25
+       data-after="-600"
26
+       data-method="average"
27
+       data-gtime="60"
28
+       data-units="events/min"
29
+       ></div>
30
+  <div data-netdata="statsd_dummy.0.dummy.auto_counter"
31
+       data-chart-library="dygraph"
32
+       data-title="aggregated per hour (timerfd ticks twice per second)"
33
+       data-width="600"
34
+       data-height="200"
35
+       data-after="-600"
36
+       data-method="average"
37
+       data-gtime="3600"
38
+       data-units="events/hour"
39
+       ></div>
40
+  <div data-netdata="statsd_dummy.0.dummy.auto_counter"
41
+       data-chart-library="dygraph"
42
+       data-title="aggregated per day (timerfd ticks twice per second)"
43
+       data-width="600"
44
+       data-height="200"
45
+       data-after="-600"
46
+       data-method="average"
47
+       data-gtime="86400"
48
+       data-units="events/day"
49
+       ></div>
50
+
51
+  <div data-netdata="statsd_dummy.0.dummy.vty_counter"
52
+       data-chart-library="dygraph"
53
+       data-title="raw data (updated manually via vty command)"
54
+       data-width="600"
55
+       data-height="200"
56
+       data-after="-600"
57
+       ></div>
58
+</body>
59
+<script type="text/javascript" src="http://localhost:19999/dashboard.js"></script>
60
+</html>
61