]> arthur.barton.de Git - netdata.git/commitdiff
Merge pull request #138 from clickthisnick/chore-remove-trailing-spaces
authorCosta Tsaousis <costa@tsaousis.gr>
Sat, 2 Apr 2016 15:43:46 +0000 (18:43 +0300)
committerCosta Tsaousis <costa@tsaousis.gr>
Sat, 2 Apr 2016 15:43:46 +0000 (18:43 +0300)
CHORE - remove trailing spaces

13 files changed:
LICENSE.md
Makefile.am
README.md
conf.d/apps_groups.conf
configure.ac
node.d/Makefile.am
node.d/node_modules/netdata.js
node.d/node_modules/node-int64.js [new file with mode: 0644]
src/apps_plugin.c
src/plugins_d.c
src/proc_interrupts.c
src/proc_softirqs.c
web/index.html

index 9666af975ddc8380b97f1edcba8f12e9eb05f954..3221f223105b9bf1772b40aeb0414b67edafe73a 100644 (file)
@@ -138,3 +138,8 @@ connectivity is not available.
     Copyright 2015, Joseph Huckaby
     [MIT License](https://github.com/jhuckaby/pixl-xml)
     
+- [node-int64](https://github.com/broofa/node-int64)
+
+    Copyright 2014, Robert Kieffer
+    [MIT License](https://github.com/broofa/node-int64/blob/master/LICENSE)
+    
index 72f0502cd5e097551717c5bb8dc4a9ffb3f77b30..6dcdfc1d1983682d64675f05233483b6da12921a 100644 (file)
@@ -19,7 +19,7 @@ MAINTAINERCLEANFILES= \
 EXTRA_DIST = \
        .gitignore \
        autogen.sh \
-       README.md \
+       README \
        LICENSE.md \
        autogen.sh \
        netdata-9999.ebuild \
@@ -37,6 +37,15 @@ SUBDIRS = \
        web \
        $(NULL)
 
+if GIT_TREE
+
+all-local: README
+
+README: README.md
+       sed -e '/^## Features$$/p' -e '/^## Git/,/^## Features$$/d' $< > $@
+
+endif
+
 dist_noinst_DATA = netdata.spec
 
 # until integrated within build
index 6f479e2294c38cd7debbad307540d60e20fef042..6eb79caaf2f4c902bca5745be9683653fb07c029 100755 (executable)
--- a/README.md
+++ b/README.md
@@ -6,6 +6,15 @@
 
 ---
 
+## Git sources
+
+You are looking at a version of the sources extracted directly from git.
+If you want a version of the source package where `configure` and any
+documentation has been built for you, please get an official
+[netdata package download](https://firehol.org/download/netdata/).
+The `unsigned/master` folder tracks the head of the git tree and
+released packages are also available.
+
 ## Features
 
 **netdata** is a highly optimized Linux daemon providing **real-time performance monitoring for Linux systems, Applications, SNMP devices, over the web**!
index 6e954fb0e915b33140d27570e59fdedcdfaad2b2..ae75edf9648e9ad89f660b0367256004154ced6d 100644 (file)
@@ -23,7 +23,7 @@
 compile: cc1 cc1plus as gcc ld make automake autoconf git
 rsync: rsync
 media: mplayer vlc xine mediatomb omxplayer omxplayer.bin kodi kodi.bin xbmc xbmc.bin mediacenter eventlircd
-squid: squid squid2 squid3
+squid: squid squid2 squid3 c-icap
 apache: apache apache2
 mysql: mysqld mysql
 asterisk: asterisk
index 5bdb01401ea91e8b20fd7d1bdf9fbb52dde6b594..8d6f441e8780c8fef512aef3486177e05a7399f3 100644 (file)
@@ -14,6 +14,8 @@ PACKAGE_RPM_RELEASE="0.0.$(echo VERSION_SUFFIX | sed 's/^_//')"
 
 AC_INIT([netdata], VERSION_NUMBER[]VERSION_SUFFIX)
 
+AM_CONDITIONAL([GIT_TREE], [test -f README.md])
+
 AM_MAINTAINER_MODE([disable])
 if test x"$USE_MAINTAINER_MODE" = xyes; then
 AC_MSG_NOTICE(***************** MAINTAINER MODE *****************)
index ae7eeac52293ed70ebfb9ade89e9352f422d8982..6edd64f31982a16dd4c95e53772eb00715303f80 100644 (file)
@@ -14,6 +14,7 @@ dist_nodemodules_DATA = \
        node_modules/pixl-xml.js \
        node_modules/net-snmp.js \
        node_modules/asn1.js \
+       node_modules/node-int64.js \
        $(NULL)
 
 nodemodulesberdir=$(nodedir)/node_modules/ber
index 9834534eef4d4759ba2728c07da7d061719b39ac..f36a97b695d80136d7f928ae4533a5f6a27d00f0 100755 (executable)
@@ -3,6 +3,7 @@
 var url = require('url');
 var http = require('http');
 var util = require('util');
+var Int64 = require('node-int64');
 
 /*
 var netdata = require('netdata');
@@ -339,8 +340,14 @@ var netdata = {
                        if(typeof value === 'undefined' || value === null)
                                return false;
 
-                       if(this._current_chart._dimensions_count !== 0)
-                               this.queue('SET ' + dimension + ' = ' + value);
+                       if(this._current_chart._dimensions_count !== 0) {
+                               if (value instanceof Buffer) {
+                                       var value64 = new Int64(value);
+                                       this.queue('SET ' + dimension + ' = ' + value64.toString(10));
+                               }
+                               else
+                                       this.queue('SET ' + dimension + ' = ' + value.toString());
+                       }
 
                        return true;
                };
diff --git a/node.d/node_modules/node-int64.js b/node.d/node_modules/node-int64.js
new file mode 100644 (file)
index 0000000..f870a2a
--- /dev/null
@@ -0,0 +1,268 @@
+//     Int64.js
+//
+//     Copyright (c) 2012 Robert Kieffer
+//     MIT License - http://opensource.org/licenses/mit-license.php
+
+/**
+ * Support for handling 64-bit int numbers in Javascript (node.js)
+ *
+ * JS Numbers are IEEE-754 binary double-precision floats, which limits the
+ * range of values that can be represented with integer precision to:
+ *
+ * 2^^53 <= N <= 2^53
+ *
+ * Int64 objects wrap a node Buffer that holds the 8-bytes of int64 data.  These
+ * objects operate directly on the buffer which means that if they are created
+ * using an existing buffer then setting the value will modify the Buffer, and
+ * vice-versa.
+ *
+ * Internal Representation
+ *
+ * The internal buffer format is Big Endian.  I.e. the most-significant byte is
+ * at buffer[0], the least-significant at buffer[7].  For the purposes of
+ * converting to/from JS native numbers, the value is assumed to be a signed
+ * integer stored in 2's complement form.
+ *
+ * For details about IEEE-754 see:
+ * http://en.wikipedia.org/wiki/Double_precision_floating-point_format
+ */
+
+// Useful masks and values for bit twiddling
+var MASK31 =  0x7fffffff, VAL31 = 0x80000000;
+var MASK32 =  0xffffffff, VAL32 = 0x100000000;
+
+// Map for converting hex octets to strings
+var _HEX = [];
+for (var i = 0; i < 256; i++) {
+  _HEX[i] = (i > 0xF ? '' : '0') + i.toString(16);
+}
+
+//
+// Int64
+//
+
+/**
+ * Constructor accepts any of the following argument types:
+ *
+ * new Int64(buffer[, offset=0]) - Existing Buffer with byte offset
+ * new Int64(Uint8Array[, offset=0]) - Existing Uint8Array with a byte offset
+ * new Int64(string)             - Hex string (throws if n is outside int64 range)
+ * new Int64(number)             - Number (throws if n is outside int64 range)
+ * new Int64(hi, lo)             - Raw bits as two 32-bit values
+ */
+var Int64 = module.exports = function(a1, a2) {
+  if (a1 instanceof Buffer) {
+    this.buffer = a1;
+    this.offset = a2 || 0;
+  } else if (Object.prototype.toString.call(a1) == '[object Uint8Array]') {
+    // Under Browserify, Buffers can extend Uint8Arrays rather than an
+    // instance of Buffer. We could assume the passed in Uint8Array is actually
+    // a buffer but that won't handle the case where a raw Uint8Array is passed
+    // in. We construct a new Buffer just in case.
+    this.buffer = new Buffer(a1);
+    this.offset = a2 || 0;
+  } else {
+    this.buffer = this.buffer || new Buffer(8);
+    this.offset = 0;
+    this.setValue.apply(this, arguments);
+  }
+};
+
+
+// Max integer value that JS can accurately represent
+Int64.MAX_INT = Math.pow(2, 53);
+
+// Min integer value that JS can accurately represent
+Int64.MIN_INT = -Math.pow(2, 53);
+
+Int64.prototype = {
+
+  constructor: Int64,
+
+  /**
+   * Do in-place 2's compliment.  See
+   * http://en.wikipedia.org/wiki/Two's_complement
+   */
+  _2scomp: function() {
+    var b = this.buffer, o = this.offset, carry = 1;
+    for (var i = o + 7; i >= o; i--) {
+      var v = (b[i] ^ 0xff) + carry;
+      b[i] = v & 0xff;
+      carry = v >> 8;
+    }
+  },
+
+  /**
+   * Set the value. Takes any of the following arguments:
+   *
+   * setValue(string) - A hexidecimal string
+   * setValue(number) - Number (throws if n is outside int64 range)
+   * setValue(hi, lo) - Raw bits as two 32-bit values
+   */
+  setValue: function(hi, lo) {
+    var negate = false;
+    if (arguments.length == 1) {
+      if (typeof(hi) == 'number') {
+        // Simplify bitfield retrieval by using abs() value.  We restore sign
+        // later
+        negate = hi < 0;
+        hi = Math.abs(hi);
+        lo = hi % VAL32;
+        hi = hi / VAL32;
+        if (hi > VAL32) throw new RangeError(hi  + ' is outside Int64 range');
+        hi = hi | 0;
+      } else if (typeof(hi) == 'string') {
+        hi = (hi + '').replace(/^0x/, '');
+        lo = hi.substr(-8);
+        hi = hi.length > 8 ? hi.substr(0, hi.length - 8) : '';
+        hi = parseInt(hi, 16);
+        lo = parseInt(lo, 16);
+      } else {
+        throw new Error(hi + ' must be a Number or String');
+      }
+    }
+
+    // Technically we should throw if hi or lo is outside int32 range here, but
+    // it's not worth the effort. Anything past the 32'nd bit is ignored.
+
+    // Copy bytes to buffer
+    var b = this.buffer, o = this.offset;
+    for (var i = 7; i >= 0; i--) {
+      b[o+i] = lo & 0xff;
+      lo = i == 4 ? hi : lo >>> 8;
+    }
+
+    // Restore sign of passed argument
+    if (negate) this._2scomp();
+  },
+
+  /**
+   * Convert to a native JS number.
+   *
+   * WARNING: Do not expect this value to be accurate to integer precision for
+   * large (positive or negative) numbers!
+   *
+   * @param allowImprecise If true, no check is performed to verify the
+   * returned value is accurate to integer precision.  If false, imprecise
+   * numbers (very large positive or negative numbers) will be forced to +/-
+   * Infinity.
+   */
+  toNumber: function(allowImprecise) {
+    var b = this.buffer, o = this.offset;
+
+    // Running sum of octets, doing a 2's complement
+    var negate = b[o] & 0x80, x = 0, carry = 1;
+    for (var i = 7, m = 1; i >= 0; i--, m *= 256) {
+      var v = b[o+i];
+
+      // 2's complement for negative numbers
+      if (negate) {
+        v = (v ^ 0xff) + carry;
+        carry = v >> 8;
+        v = v & 0xff;
+      }
+
+      x += v * m;
+    }
+
+    // Return Infinity if we've lost integer precision
+    if (!allowImprecise && x >= Int64.MAX_INT) {
+      return negate ? -Infinity : Infinity;
+    }
+
+    return negate ? -x : x;
+  },
+
+  /**
+   * Convert to a JS Number. Returns +/-Infinity for values that can't be
+   * represented to integer precision.
+   */
+  valueOf: function() {
+    return this.toNumber(false);
+  },
+
+  /**
+   * Return string value
+   *
+   * @param radix Just like Number#toString()'s radix
+   */
+  toString: function(radix) {
+    return this.valueOf().toString(radix || 10);
+  },
+
+  /**
+   * Return a string showing the buffer octets, with MSB on the left.
+   *
+   * @param sep separator string. default is '' (empty string)
+   */
+  toOctetString: function(sep) {
+    var out = new Array(8);
+    var b = this.buffer, o = this.offset;
+    for (var i = 0; i < 8; i++) {
+      out[i] = _HEX[b[o+i]];
+    }
+    return out.join(sep || '');
+  },
+
+  /**
+   * Returns the int64's 8 bytes in a buffer.
+   *
+   * @param {bool} [rawBuffer=false]  If no offset and this is true, return the internal buffer.  Should only be used if
+   *                                  you're discarding the Int64 afterwards, as it breaks encapsulation.
+   */
+  toBuffer: function(rawBuffer) {
+    if (rawBuffer && this.offset === 0) return this.buffer;
+
+    var out = new Buffer(8);
+    this.buffer.copy(out, 0, this.offset, this.offset + 8);
+    return out;
+  },
+
+  /**
+   * Copy 8 bytes of int64 into target buffer at target offset.
+   *
+   * @param {Buffer} targetBuffer       Buffer to copy into.
+   * @param {number} [targetOffset=0]   Offset into target buffer.
+   */
+  copy: function(targetBuffer, targetOffset) {
+    this.buffer.copy(targetBuffer, targetOffset || 0, this.offset, this.offset + 8);
+  },
+
+  /**
+   * Returns a number indicating whether this comes before or after or is the
+   * same as the other in sort order.
+   *
+   * @param {Int64} other  Other Int64 to compare.
+   */
+  compare: function(other) {
+
+    // If sign bits differ ...
+    if ((this.buffer[this.offset] & 0x80) != (other.buffer[other.offset] & 0x80)) {
+      return other.buffer[other.offset] - this.buffer[this.offset];
+    }
+
+    // otherwise, compare bytes lexicographically
+    for (var i = 0; i < 8; i++) {
+      if (this.buffer[this.offset+i] !== other.buffer[other.offset+i]) {
+        return this.buffer[this.offset+i] - other.buffer[other.offset+i];
+      }
+    }
+    return 0;
+  },
+
+  /**
+   * Returns a boolean indicating if this integer is equal to other.
+   *
+   * @param {Int64} other  Other Int64 to compare.
+   */
+  equals: function(other) {
+    return this.compare(other) === 0;
+  },
+
+  /**
+   * Pretty output in console.log
+   */
+  inspect: function() {
+    return '[Int64 value:' + this + ' octets:' + this.toOctetString(' ') + ']';
+  }
+};
index 199dacd6d053f7d412da2005b0ac759d09c4a8f9..df76cf53cd96509e0585930e7f46051f7678d398 100755 (executable)
@@ -575,7 +575,7 @@ struct pid_stat {
        int *fds;                                       // array of fds it uses
        int fds_size;                           // the size of the fds array
 
-       int childs;                                     // number of processes directly referencing this
+       int children_count;                     // number of processes directly referencing this
        int updated;                            // 1 when update
        int merged;                                     // 1 when it has been merged to its parent
        int new_entry;
@@ -804,7 +804,7 @@ int walk_down(pid_t pid, int level) {
        if(p) {
                if(!p->updated) ret += 1;
                if(ret) fprintf(stderr, "%s %s %d [%s, %s] c=%d u=%llu+%llu, s=%llu+%llu, cu=%llu+%llu, cs=%llu+%llu, n=%llu+%llu, j=%llu+%llu, cn=%llu+%llu, cj=%llu+%llu\n"
-                       , b, p->comm, p->pid, p->updated?"OK":"KILLED", p->target->name, p->childs
+                       , b, p->comm, p->pid, p->updated?"OK":"KILLED", p->target->name, p->children_count
                        , p->utime, p->utime - p->old_utime
                        , p->stime, p->stime - p->old_stime
                        , p->cutime, p->cutime - p->old_cutime
@@ -1062,7 +1062,7 @@ int update_from_proc(void)
                all_pids_count++;
                p->parent = NULL;
                p->updated = 0;
-               p->childs = 0;
+               p->children_count = 0;
                p->merged = 0;
                p->new_entry = 0;
        }
@@ -1236,57 +1236,104 @@ void update_statistics(void)
        int c;
        struct pid_stat *p = NULL;
 
-       // link all parents and update childs count
+
+       // link all children to their parents
+       // and update children count on parents
        for(p = root_of_pids; p ; p = p->next) {
-               if(p->ppid > 0 && p->ppid <= pid_max && all_pids[p->ppid]) {
-                       if(debug || (p->target && p->target->debug)) fprintf(stderr, "apps.plugin: \tparent of %d %s is %d %s\n", p->pid, p->comm, p->ppid, all_pids[p->ppid]->comm);
+               // for each process found running
+
+               if(p->ppid > 0
+                               && p->ppid <= pid_max
+                               && all_pids[p->ppid]
+                       ) {
+                       // for valid processes
+
+                       if(debug || (p->target && p->target->debug))
+                               fprintf(stderr, "apps.plugin: \tparent of %d (%s) is %d (%s)\n", p->pid, p->comm, p->ppid, all_pids[p->ppid]->comm);
 
                        p->parent = all_pids[p->ppid];
-                       p->parent->childs++;
+                       p->parent->children_count++;
                }
-               else if(p->ppid != 0) error("pid %d %s states parent %d, but the later does not exist.", p->pid, p->comm, p->ppid);
+               else if(p->ppid != 0)
+                       error("pid %d %s states parent %d, but the later does not exist.", p->pid, p->comm, p->ppid);
        }
 
+
+       // children that do not have a target
+       // inherit their target from their parent
+       int found = 1;
+       while(found) {
+               found = 0;
+               for(p = root_of_pids; p ; p = p->next) {
+                       // if this process does not have a target
+                       // and it has a parent
+                       // and its parent has a target
+                       // then, set the parent's target to this process
+                       if(unlikely(!p->target && p->parent && p->parent->target)) {
+                               p->target = p->parent->target;
+                               found++;
+
+                               if(debug || (p->target && p->target->debug))
+                                       fprintf(stderr, "apps.plugin: \t\tTARGET INHERITANCE: %s is inherited by %d (%s) from its parent %d (%s).\n", p->target->name, p->pid, p->comm, p->parent->pid, p->parent->comm);
+                       }
+               }
+       }
+
+
        // find all the procs with 0 childs and merge them to their parents
        // repeat, until nothing more can be done.
-       int found = 1;
+       found = 1;
        while(found) {
                found = 0;
                for(p = root_of_pids; p ; p = p->next) {
-                       // if this process does not have any childs, and
-                       // is not already merged, and
-                       // its parent has childs waiting to be merged, and
-                       // the target of this process and its parent is the same, or the parent does not have a target, or this process does not have a parent
+                       // if this process does not have any children
+                       // and is not already merged
+                       // and has a parent
+                       // and its parent has children
+                       // and the target of this process and its parent is the same, or the parent does not have a target
                        // and its parent is not init
-                       // then... merge them!
-                       if(!p->childs && !p->merged && p->parent && p->parent->childs && (p->target == p->parent->target || !p->parent->target || !p->target) && p->ppid != 1) {
-                               p->parent->childs--;
+                       // then, mark them as merged.
+                       if(unlikely(
+                                       !p->children_count
+                                       && !p->merged
+                                       && p->parent
+                                       && p->parent->children_count
+                                       && (p->target == p->parent->target || !p->parent->target)
+                                       && p->ppid != 1
+                               )) {
+                               p->parent->children_count--;
                                p->merged = 1;
 
                                // the parent inherits the child's target, if it does not have a target itself
-                               if(p->target && !p->parent->target) {
+                               if(unlikely(p->target && !p->parent->target)) {
                                        p->parent->target = p->target;
-                                       if(debug || (p->target && p->target->debug)) fprintf(stderr, "apps.plugin: \t\ttarget %s is inherited by %d %s from its child %d %s.\n", p->target->name, p->parent->pid, p->parent->comm, p->pid, p->comm);
+
+                                       if(debug || (p->target && p->target->debug))
+                                               fprintf(stderr, "apps.plugin: \t\tTARGET INHERITANCE: %s is inherited by %d (%s) from its child %d (%s).\n", p->target->name, p->parent->pid, p->parent->comm, p->pid, p->comm);
                                }
 
                                found++;
                        }
                }
-               if(debug) fprintf(stderr, "apps.plugin: merged %d processes\n", found);
+
+               if(debug)
+                       fprintf(stderr, "apps.plugin: merged %d processes\n", found);
        }
 
-       // give a default target on all top level processes
        // init goes always to default target
-       if(all_pids[1]) all_pids[1]->target = default_target;
+       if(all_pids[1])
+               all_pids[1]->target = default_target;
 
+       // give a default target on all top level processes
        for(p = root_of_pids; p ; p = p->next) {
                // if the process is not merged itself
                // then is is a top level process
-               if(!p->merged && !p->target) p->target = default_target;
+               if(!p->merged && !p->target)
+                       p->target = default_target;
 
 #ifdef INCLUDE_CHILDS
                // by the way, update the diffs
-               // will be used later for substracting killed process times
+               // will be used later for subtracting killed process times
                p->diff_cutime = p->utime - p->cutime;
                p->diff_cstime = p->stime - p->cstime;
                p->diff_cminflt = p->minflt - p->cminflt;
@@ -1299,9 +1346,12 @@ void update_statistics(void)
        while(found) {
                found = 0;
                for(p = root_of_pids; p ; p = p->next) {
-                       if(!p->target && p->merged && p->parent && p->parent->target) {
+                       if(unlikely(!p->target && p->merged && p->parent && p->parent->target)) {
                                p->target = p->parent->target;
                                found++;
+
+                               if(debug || (p->target && p->target->debug))
+                                       fprintf(stderr, "apps.plugin: \t\tTARGET INHERITANCE: %s is inherited by %d (%s) from its parent %d (%s) at phase 2.\n", p->target->name, p->pid, p->comm, p->parent->pid, p->parent->comm);
                        }
                }
        }
index eb8f141b89a545c9c90fdce770f3055b0ecc400b..09295fb49196937e6a4ec7cc17edd8db6bc675ec 100755 (executable)
@@ -218,7 +218,7 @@ void *pluginsd_worker_thread(void *arg)
                                        break;
                                }
 
-                               if(unlikely(st->debug)) debug(D_PLUGINSD, "PLUGINSD: '%s' is requesting a END on chart %s", cd->fullfilename, st->id);
+                               if(unlikely(st->debug)) debug(D_PLUGINSD, "PLUGINSD: '%s' is requesting an END on chart %s", cd->fullfilename, st->id);
 
                                rrdset_done(st);
                                st = NULL;
@@ -528,5 +528,3 @@ void *pluginsd_main(void *ptr)
        pthread_exit(NULL);
        return NULL;
 }
-
-
index 25482dfa7eddb93e3626ad869a5eef79df98c946..8ebbd1c2caffc8d90ffb2b3921c60557b4b55b0c 100755 (executable)
@@ -46,6 +46,11 @@ int do_proc_interrupts(int update_every, unsigned long long dt) {
        uint32_t lines = procfile_lines(ff), l;
        uint32_t words = procfile_linewords(ff, 0), w;
 
+       if(!lines) {
+               error("Cannot read /proc/interrupts, zero lines reported.");
+               return 1;
+       }
+
        // find how many CPUs are there
        if(cpus == -1) {
                cpus = 0;
index 9373baaecae5f33da22a76bc54fab747dd013c4b..a601c7e350afd389bbd594e1ee8958017c6e6046 100755 (executable)
@@ -46,6 +46,11 @@ int do_proc_softirqs(int update_every, unsigned long long dt) {
        uint32_t lines = procfile_lines(ff), l;
        uint32_t words = procfile_linewords(ff, 0), w;
 
+       if(!lines) {
+               error("Cannot read /proc/softirqs, zero lines reported.");
+               return 1;
+       }
+
        // find how many CPUs are there
        if(cpus == -1) {
                cpus = 0;
index 6b927f4fde7f0d8d353404a2886002e3a71b9d1c..3c308ee61dfdcb6682070f137e0bcb6171b641e4 100755 (executable)
                                                <i class="fa fa-circle"></i> <a href="http://D3js.org/" target="_blank">D3</a>,
                                                <i class="fa fa-copyright"></i> Copyright 2015, Mike Bostock, <a href="http://opensource.org/licenses/BSD-3-Clause" target="_blank">BSD License</a>
 
+                                               <i class="fa fa-circle"></i> <a href="https://github.com/broofa/node-int64" target="_blank">node-int64</a>,
+                                               <i class="fa fa-copyright"></i> Copyright 2014, Robert Kieffer, <a href="https://github.com/broofa/node-int64/blob/master/LICENSE" target="_blank">MIT License</a>
+
                                        </small>
                                </div>
                        </div>