text: var ASSERT = require('assert');
  var ASN1 = require('../../lib/asn1');
  var UTIL = require('../../lib/util');
  
  (function() {
    describe('asn1', function() {
      // TODO: add more ASN.1 coverage
  
      it('should convert an OID to DER', function() {
        ASSERT.equal(ASN1.oidToDer('1.2.840.113549').toHex(), '2a864886f70d');
      });
  
      it('should convert an OID from DER', function() {
        var der = UTIL.hexToBytes('2a864886f70d');
        ASSERT.equal(ASN1.derToOid(der), '1.2.840.113549');
      });
  
      it('should convert INTEGER 0 to DER', function() {
        ASSERT.equal(ASN1.integerToDer(0).toHex(), '00');
      });
  
      it('should convert INTEGER 1 to DER', function() {
        ASSERT.equal(ASN1.integerToDer(1).toHex(), '01');
      });
  
      it('should convert INTEGER 127 to DER', function() {
        ASSERT.equal(ASN1.integerToDer(127).toHex(), '7f');
      });
  
      it('should convert INTEGER 128 to DER', function() {
        ASSERT.equal(ASN1.integerToDer(128).toHex(), '0080');
      });
  
      it('should convert INTEGER 256 to DER', function() {
        ASSERT.equal(ASN1.integerToDer(256).toHex(), '0100');
      });
  
      it('should convert INTEGER -128 to DER', function() {
        ASSERT.equal(ASN1.integerToDer(-128).toHex(), '80');
      });
  
      it('should convert INTEGER -129 to DER', function() {
        ASSERT.equal(ASN1.integerToDer(-129).toHex(), 'ff7f');
      });
  
      it('should convert INTEGER 32768 to DER', function() {
        ASSERT.equal(ASN1.integerToDer(32768).toHex(), '008000');
      });
  
      it('should convert INTEGER -32768 to DER', function() {
        ASSERT.equal(ASN1.integerToDer(-32768).toHex(), '8000');
      });
  
      it('should convert INTEGER -32769 to DER', function() {
        ASSERT.equal(ASN1.integerToDer(-32769).toHex(), 'ff7fff');
      });
  
      it('should convert INTEGER 8388608 to DER', function() {
        ASSERT.equal(ASN1.integerToDer(8388608).toHex(), '00800000');
      });
  
      it('should convert INTEGER -8388608 to DER', function() {
        ASSERT.equal(ASN1.integerToDer(-8388608).toHex(), '800000');
      });
  
      it('should convert INTEGER -8388609 to DER', function() {
        ASSERT.equal(ASN1.integerToDer(-8388609).toHex(), 'ff7fffff');
      });
  
      it('should convert INTEGER 2147483647 to DER', function() {
        ASSERT.equal(ASN1.integerToDer(2147483647).toHex(), '7fffffff');
      });
  
      it('should convert INTEGER -2147483648 to DER', function() {
        ASSERT.equal(ASN1.integerToDer(-2147483648).toHex(), '80000000');
      });
  
      it('should convert INTEGER 0 from DER', function() {
        var der = UTIL.hexToBytes('00');
        ASSERT.equal(ASN1.derToInteger(der), 0);
      });
  
      it('should convert INTEGER 1 from DER', function() {
        var der = UTIL.hexToBytes('01');
        ASSERT.equal(ASN1.derToInteger(der), 1);
      });
  
      it('should convert INTEGER 127 from DER', function() {
        var der = UTIL.hexToBytes('7f');
        ASSERT.equal(ASN1.derToInteger(der), 127);
      });
  
      it('should convert INTEGER 128 from DER', function() {
        var der = UTIL.hexToBytes('0080');
        ASSERT.equal(ASN1.derToInteger(der), 128);
      });
  
      it('should convert INTEGER 256 from DER', function() {
        var der = UTIL.hexToBytes('0100');
        ASSERT.equal(ASN1.derToInteger(der), 256);
      });
  
      it('should convert INTEGER -128 from DER', function() {
        var der = UTIL.hexToBytes('80');
        ASSERT.equal(ASN1.derToInteger(der), -128);
      });
  
      it('should convert INTEGER -129 from DER', function() {
        var der = UTIL.hexToBytes('ff7f');
        ASSERT.equal(ASN1.derToInteger(der), -129);
      });
  
      it('should convert INTEGER 32768 from DER', function() {
        var der = UTIL.hexToBytes('008000');
        ASSERT.equal(ASN1.derToInteger(der), 32768);
      });
  
      it('should convert INTEGER -32768 from DER', function() {
        var der = UTIL.hexToBytes('8000');
        ASSERT.equal(ASN1.derToInteger(der), -32768);
      });
  
      it('should convert INTEGER -32769 from DER', function() {
        var der = UTIL.hexToBytes('ff7fff');
        ASSERT.equal(ASN1.derToInteger(der), -32769);
      });
  
      it('should convert INTEGER 8388608 from DER', function() {
        var der = UTIL.hexToBytes('00800000');
        ASSERT.equal(ASN1.derToInteger(der), 8388608);
      });
  
      it('should convert INTEGER -8388608 from DER', function() {
        var der = UTIL.hexToBytes('800000');
        ASSERT.equal(ASN1.derToInteger(der), -8388608);
      });
  
      it('should convert INTEGER -8388609 from DER', function() {
        var der = UTIL.hexToBytes('ff7fffff');
        ASSERT.equal(ASN1.derToInteger(der), -8388609);
      });
  
      it('should convert INTEGER 2147483647 from DER', function() {
        var der = UTIL.hexToBytes('7fffffff');
        ASSERT.equal(ASN1.derToInteger(der), 2147483647);
      });
  
      it('should convert INTEGER -2147483648 from DER', function() {
        var der = UTIL.hexToBytes('80000000');
        ASSERT.equal(ASN1.derToInteger(der), -2147483648);
      });
  
      (function() {
        var tests = [{
          in: '20110223123400',
          out: 1298464440000
        }, {
          in: '20110223123400.1',
          out: 1298464440100
        }, {
          in: '20110223123400.123',
          out: 1298464440123
        }];
        tests.forEach(function(test) {
          it('should convert local generalized time "' + test.in + '" to a Date', function() {
            var d = ASN1.generalizedTimeToDate(test.in);
            var localOffset = d.getTimezoneOffset() * 60000;
            ASSERT.equal(d.getTime(), test.out + localOffset);
          });
        });
      })();
  
      (function() {
        var tests = [{
          in: '20110223123400Z', // Wed Feb 23 12:34:00.000 UTC 2011
          out: 1298464440000
        }, {
          in: '20110223123400.1Z', // Wed Feb 23 12:34:00.100 UTC 2011
          out: 1298464440100
        }, {
          in: '20110223123400.123Z', // Wed Feb 23 12:34:00.123 UTC 2011
          out: 1298464440123
        }, {
          in: '20110223123400+0200', // Wed Feb 23 10:34:00.000 UTC 2011
          out: 1298457240000
        }, {
          in: '20110223123400.1+0200', // Wed Feb 23 10:34:00.100 UTC 2011
          out: 1298457240100
        }, {
          in: '20110223123400.123+0200', // Wed Feb 23 10:34:00.123 UTC 2011
          out: 1298457240123
        }, {
          in: '20110223123400-0200', // Wed Feb 23 14:34:00.000 UTC 2011
          out: 1298471640000
        }, {
          in: '20110223123400.1-0200', // Wed Feb 23 14:34:00.100 UTC 2011
          out: 1298471640100
        }, {
          in: '20110223123400.123-0200', // Wed Feb 23 14:34:00.123 UTC 2011
          out: 1298471640123
        }];
        tests.forEach(function(test) {
          it('should convert utc generalized time "' + test.in + '" to a Date', function() {
            var d = ASN1.generalizedTimeToDate(test.in);
            ASSERT.equal(d.getTime(), test.out);
          });
        });
      })();
  
      (function() {
        var tests = [{
          in: 'Jan 1 1949 00:00:00 GMT',
          out: '19490101000000Z'
        }, {
          in: 'Jan 1 2000 00:00:00 GMT',
          out: '20000101000000Z'
        }, {
          in: 'Jan 1 2050 00:00:00 GMT',
          out: '20500101000000Z'
        }, {
          in: 'Mar 1 2100 00:00:00 GMT',
          out: '21000301000000Z'
        }];
        tests.forEach(function(test) {
          it('should convert date "' + test.in + '" to generalized time', function() {
            var d = ASN1.dateToGeneralizedTime(new Date(test.in));
            ASSERT.equal(d, test.out);
          });
        });
      })();
  
      (function() {
        var tests = [{
          in: '1102231234Z', // Wed Feb 23 12:34:00 UTC 2011
          out: 1298464440000
        }, {
          in: '1102231234+0200', // Wed Feb 23 10:34:00 UTC 2011
          out: 1298457240000
        }, {
          in: '1102231234-0200', // Wed Feb 23 14:34:00 UTC 2011
          out: 1298471640000
        }, {
          in: '110223123456Z', // Wed Feb 23 12:34:56 UTC 2011
          out: 1298464496000
        }, {
          in: '110223123456+0200', // Wed Feb 23 10:34:56 UTC 2011
          out: 1298457296000
        }, {
          in: '110223123456-0200', // Wed Feb 23 14:34:56 UTC 2011
          out: 1298471696000
        }, {
          in: '500101000000Z',
          out: -631152000000
        }];
        tests.forEach(function(test) {
          it('should convert utc time "' + test.in + '" to a Date', function() {
            var d = ASN1.utcTimeToDate(test.in);
            ASSERT.equal(d.getTime(), test.out);
          });
        });
      })();
  
      (function() {
        var tests = [{
          in: 'Sat Dec 31 1949 19:00:00 GMT-0500',
          out: '500101000000Z'
        }];
        tests.forEach(function(test) {
          it('should convert date "' + test.in + '" to utc time', function() {
            var d = ASN1.dateToUtcTime(new Date(test.in));
            ASSERT.equal(d, test.out);
          });
        });
      })();
  
      (function() {
        // use function to avoid calling apis during setup
        function _asn1(str) {
          return function() {
            return ASN1.fromDer(UTIL.hexToBytes(str.replace(/ /g, '')));
          };
        }
        var tests = [{
          name: 'empty strings',
          obj1: '',
          obj2: '',
          equal: true
        }, {
          name: 'simple strings',
          obj1: '\u0001',
          obj2: '\u0001',
          equal: true
        }, {
          name: 'simple strings',
          obj1: '\u0000',
          obj2: '\u0001',
          equal: false
        }, {
          name: 'simple arrays',
          obj1: ['', ''],
          obj2: ['', ''],
          equal: true
        }, {
          name: 'simple arrays',
          obj1: ['', ''],
          obj2: [''],
          equal: false
        }, {
          name: 'INTEGERs',
          obj1: _asn1('02 01 00'),
          obj2: _asn1('02 01 00'),
          equal: true
        }, {
          name: 'BER INTEGERs',
          obj1: _asn1('02 01 01'),
          obj2: _asn1('02 02 00 01'),
          equal: false
        }, {
          name: 'BIT STRINGs',
          obj1: _asn1('03 02 00 01'),
          obj2: _asn1('03 02 00 01'),
          equal: true
        }, {
          name: 'BIT STRINGs',
          obj1: _asn1('03 02 00 01'),
          obj2: _asn1('03 02 00 02'),
          equal: false
        }, {
          name: 'BIT STRINGs sub INTEGER',
          obj1: _asn1('03 04 00 02 01 01'),
          obj2: _asn1('03 04 00 02 01 01'),
          equal: true
        }, {
          name: 'mutated BIT STRINGs',
          obj1: _asn1('03 04 00 02 01 01'),
          obj2: _asn1('03 04 00 02 01 01'),
          mutate: function(obj1, obj2) {
            obj2.value[0].value = '\u0002';
          },
          equal: false
        }];
        tests.forEach(function(test, index) {
          var name = 'should check ASN.1 ' +
            (test.equal ? '' : 'not ') + 'equal: ' +
            (test.name || '#' + index);
          it(name, function() {
            var obj1 = typeof test.obj1 === 'function' ? test.obj1() : test.obj1;
            var obj2 = typeof test.obj2 === 'function' ? test.obj2() : test.obj2;
            if(test.mutate) {
              test.mutate(obj1, obj2);
            }
            ASSERT.equal(ASN1.equals(obj1, obj2), test.equal);
          });
        });
      })();
  
      (function() {
        // use function to avoid calling apis during setup
        function _asn1(str) {
          return function() {
            return ASN1.fromDer(UTIL.hexToBytes(str.replace(/ /g, '')));
          };
        }
        var tests = [{
          name: 'empty string',
          obj: ''
        }, {
          name: 'simple string',
          obj: '\u0001'
        }, {
          name: 'simple array',
          obj: ['', '']
        }, {
          name: 'INTEGER',
          obj: _asn1('02 01 00')
        }, {
          name: 'BER INTEGER',
          obj: _asn1('02 01 01')
        }, {
          name: 'BIT STRING',
          obj: _asn1('03 02 00 01')
        }, {
          name: 'BIT STRING sub INTEGER',
          obj: _asn1('03 04 00 02 01 01')
        }];
        tests.forEach(function(test, index) {
          var name = 'should check ASN.1 copy: ' + (test.name || '#' + index);
          it(name, function() {
            var obj = typeof test.obj === 'function' ? test.obj() : test.obj;
            ASSERT.equal(ASN1.equals(ASN1.copy(obj), obj), true);
          });
        });
      })();
  
      (function() {
        function _h2b(str) {
          return UTIL.hexToBytes(str.replace(/ /g, ''));
        }
        function _add(b, str) {
          b.putBytes(_h2b(str));
        }
        function _asn1dump(asn1) {
          console.log(ASN1.prettyPrint(asn1));
          console.log(JSON.stringify(asn1, null, 2));
        }
        function _asn1TestOne(strict, throws, options) {
          options = options || {};
          if(!('decodeBitStrings' in options)) {
            options.decodeBitStrings = true;
          }
          // buffer strict test
          var b = UTIL.createBuffer();
          // init
          options.init(b);
          // bytes for round-trip comparison
          var bytes = b.copy().bytes();
          // copy for non-strict test
          var bns = b.copy();
          // create strict and non-strict asn1
          var asn1assert = throws ? ASSERT.throws : function(f) { f(); };
          var asn1;
          var der;
          asn1assert(function() {
            asn1 = ASN1.fromDer(b, {
              strict: strict,
              decodeBitStrings: options.decodeBitStrings
            });
          });
          // debug
          if(options.dump && asn1) {
            console.log('=== ' + (strict ? 'Strict' : 'Non Strict') + ' ===');
            _asn1dump(asn1);
          }
          // basic check
          if(!throws) {
            ASSERT.ok(asn1);
          }
  
          // round-trip(ish) check
          if(!throws) {
            der = ASN1.toDer(asn1);
            if(options.roundtrip) {
              // byte comparisons for round-trip testing can fail due to
              // symantically safe changes such as changing the length encoding.
              // test a roundtrip for data where it makes sense.
              ASSERT.equal(
                UTIL.bytesToHex(bytes),
                UTIL.bytesToHex(der.bytes()));
            }
          }
  
          // validator check
          if(!throws && options.v) {
            var capture = {};
            var errors = [];
            var asn1ok = ASN1.validate(asn1, options.v, capture, errors);
            ASSERT.deepEqual(errors, []);
            if(options.captured) {
              ASSERT.deepEqual(capture, options.captured);
            } else {
              ASSERT.deepEqual(capture, {});
            }
            ASSERT.ok(asn1ok);
          }
  
          return {
            asn1: asn1,
            der: der
          };
        }
        function _asn1Test(options) {
          var s = _asn1TestOne(true, options.strictThrows, options);
          var ns = _asn1TestOne(false, options.nonStrictThrows, options);
  
          // check asn1 equality
          if(s.asn1 && ns.asn1) {
            ASSERT.deepEqual(s.asn1, ns.asn1);
          }
  
          // check der equality
          if(s.der && ns.der) {
            ASSERT.equal(
              UTIL.bytesToHex(s.der.bytes()),
              UTIL.bytesToHex(ns.der.bytes()));
          }
  
          if(options.done) {
            options.done({
              strict: s,
              nonStrict: ns
            });
          }
        }
  
        it('should convert BIT STRING from DER (short,empty)', function() {
          _asn1Test({
            init: function(b) {
              // BIT STRING value=none
              _add(b, '03 00');
            },
            dump: false,
            roundtrip: true,
            v: {
              tagClass: ASN1.Class.UNIVERSAL,
              type: ASN1.Type.BITSTRING,
              constructed: false,
              captureBitStringContents: 'bits'
            },
            captured: {
              bits: ''
            }
          });
        });
  
        it('should convert BIT STRING from DER (short,empty2)', function() {
          _asn1Test({
            init: function(b) {
              // BIT STRING value=none
              _add(b, '03 01 00');
            },
            dump: false,
            roundtrip: true,
            v: {
              tagClass: ASN1.Class.UNIVERSAL,
              type: ASN1.Type.BITSTRING,
              constructed: false,
              captureBitStringContents: 'bitsC',
              captureBitStringValue: 'bitsV'
            },
            captured: {
              bitsC: _h2b('00'),
              bitsV: ''
            }
          });
        });
  
        it('should convert BIT STRING from BER (short,invalid)', function() {
          _asn1Test({
            init: function(b) {
              // BIT STRING value=partial
              // invalid in strict mode, non-strict will read 1 of 2 bytes
              _add(b, '03 02 00');
            },
            dump: false,
            roundtrip: false,
            strictThrows: true,
            nonStrictThrows: false,
            v: {
              tagClass: ASN1.Class.UNIVERSAL,
              type: ASN1.Type.BITSTRING,
              constructed: false,
              captureBitStringContents: 'bits'
            },
            captured: {
              // only for non-strict mode, truncated value
              bits: _h2b('00')
            }
          });
        });
  
        it('should convert BIT STRING from DER (short)', function() {
          _asn1Test({
            init: function(b) {
              // BIT STRING value=0110111001011101
              _add(b, '03 03 00 6e 5d');
            },
            dump: false,
            roundtrip: true,
            v: {
              tagClass: ASN1.Class.UNIVERSAL,
              type: ASN1.Type.BITSTRING,
              constructed: false,
              captureBitStringContents: 'bits'
            },
            captured: {
              bits: _h2b('00 6e 5d')
            }
          });
        });
  
        it('should convert BIT STRING from DER (short2)', function() {
          _asn1Test({
            init: function(b) {
              // BIT STRING value=0110111001011101
              // contains an INTEGER=0x12
              _add(b, '03 04 00 02 01 12');
            },
            dump: false,
            roundtrip: true,
            v: {
              tagClass: ASN1.Class.UNIVERSAL,
              type: ASN1.Type.BITSTRING,
              constructed: false,
              // note captureBitStringContents used to get all bytes
              // 'capture' would get the value structure
              // 'captureAsn1' would get the value and sub-value structures
              captureBitStringContents: 'bits',
              value: [{
                tagClass: ASN1.Class.UNIVERSAL,
                type: ASN1.Type.INTEGER,
                constructed: false,
                capture: 'int0'
              }]
            },
            captured: {
              bits: _h2b('00 02 01 12'),
              int0: _h2b('12')
            }
          });
        });
  
        it('should convert BIT STRING from DER (short,unused1z)', function() {
          _asn1Test({
            init: function(b) {
              // BIT STRING value=01101110010111011010111, unused=0
              _add(b, '03 04 01 6e 5d ae');
            },
            dump: false,
            roundtrip: true,
            v: {
              tagClass: ASN1.Class.UNIVERSAL,
              type: ASN1.Type.BITSTRING,
              constructed: false,
              captureBitStringContents: 'bits'
            },
            captured: {
              bits: _h2b('01 6e 5d ae')
            }
          });
        });
  
        it('should convert BIT STRING from DER (short,unused6z)', function() {
          _asn1Test({
            init: function(b) {
              // BIT STRING short len, value=011011100101110111, unused=000000
              _add(b, '03 04 06 6e 5d c0');
            },
            dump: false,
            roundtrip: true,
            v: {
              tagClass: ASN1.Class.UNIVERSAL,
              type: ASN1.Type.BITSTRING,
              constructed: false,
              captureBitStringContents: 'bits'
            },
            captured: {
              bits: _h2b('06 6e 5d c0')
            }
          });
        });
  
        it('should convert BIT STRING from BER (short,unused6d)', function() {
          _asn1Test({
            init: function(b) {
              // BIT STRING short len, value=011011100101110111, unused=100000
              _add(b, '03 04 06 6e 5d e0');
            },
            dump: false,
            roundtrip: true,
            v: {
              tagClass: ASN1.Class.UNIVERSAL,
              type: ASN1.Type.BITSTRING,
              constructed: false,
              captureBitStringContents: 'bits'
            },
            captured: {
              bits: _h2b('06 6e 5d e0')
            }
          });
        });
  
        it('should convert BIT STRING from BER (long,unused6z)', function() {
          _asn1Test({
            init: function(b) {
              // BIT STRING long len, value=011011100101110111, unused=000000
              _add(b, '03 81 04 06 6e 5d c0');
            },
            dump: false,
            // length is compressed
            roundtrip: false,
            v: {
              tagClass: ASN1.Class.UNIVERSAL,
              type: ASN1.Type.BITSTRING,
              constructed: false,
              captureBitStringContents: 'bits'
            },
            captured: {
              bits: _h2b('06 6e 5d c0')
            }
          });
        });
  
        it('should convert BIT STRING from BER (unused6z)', function() {
          _asn1Test({
            init: function(b) {
              // BIT STRING constructed, value=0110111001011101+11, unused=000000
              _add(b, '23 09');
              _add(b, '03 03 00 6e 5d');
              _add(b, '03 02 06 c0');
            },
            dump: false,
            roundtrip: true,
            v: {
              tagClass: ASN1.Class.UNIVERSAL,
              type: ASN1.Type.BITSTRING,
              constructed: true,
              value: [{
                tagClass: ASN1.Class.UNIVERSAL,
                type: ASN1.Type.BITSTRING,
                constructed: false,
                capture: 'bits0'
              }, {
                tagClass: ASN1.Class.UNIVERSAL,
                type: ASN1.Type.BITSTRING,
                constructed: false,
                capture: 'bits1'
              }]
            },
            captured: {
              bits0: _h2b('00 6e 5d'),
              bits1: _h2b('06 c0')
            }
          });
        });
  
        it('should convert BIT STRING from BER (decode)', function() {
          _asn1Test({
            init: function(b) {
              // create crafted DER BIT STRING data that includes encapsulated
              // data.  often used to store SEQUENCE of INTEGERs.
              // add bit stream of bytes using long length
              _add(b, '03 82 00 10');
              // no padding
              _add(b, '00');
              // sequence of two ints
              _add(b, '30 0D');
              // add test int, long len
              _add(b, '02 81 04 12 34 56 78');
              // add test int, short len
              _add(b, '02 04 87 65 43 21');
            },
            dump: false,
            decodeBitStrings: true,
            // long len will compress to short len
            roundtrip: false,
            v: {
              tagClass: ASN1.Class.UNIVERSAL,
              type: ASN1.Type.BITSTRING,
              constructed: false,
              captureBitStringContents: 'bits',
              value: [{
                tagClass: ASN1.Class.UNIVERSAL,
                type: ASN1.Type.SEQUENCE,
                constructed: true,
                value: [{
                  tagClass: ASN1.Class.UNIVERSAL,
                  type: ASN1.Type.INTEGER,
                  constructed: false,
                  capture: 'int0'
                }, {
                  tagClass: ASN1.Class.UNIVERSAL,
                  type: ASN1.Type.INTEGER,
                  constructed: false,
                  capture: 'int1'
                }]
              }]
            },
            captured: {
              bits: _h2b(
                '00' +
                '30 0D' +
                '02 81 04 12 34 56 78' +
                '02 04 87 65 43 21'),
              int0: _h2b('12 34 56 78'),
              int1: _h2b('87 65 43 21')
            }
          });
        });
  
        it('should convert BIT STRING from BER (no decode)', function() {
          _asn1Test({
            init: function(b) {
              // create crafted DER BIT STRING data that includes encapsulated
              // data.  often used to store SEQUENCE of INTEGERs.
              // add bit stream
              _add(b, '03 82 00 10');
              // no padding
              _add(b, '00');
              // sequence of two ints
              _add(b, '30 0D');
              // add test int, long len
              _add(b, '02 81 04 12 34 56 78');
              // add test int, short len
              _add(b, '02 04 87 65 43 21');
            },
            dump: false,
            decodeBitStrings: false,
            // long length is compressed
            roundtrip: false,
            v: {
              tagClass: ASN1.Class.UNIVERSAL,
              type: ASN1.Type.BITSTRING,
              constructed: false,
              captureBitStringContents: 'bits'
            },
            captured: {
              bits: _h2b(
                '00' +
                '30 0D' +
                '02 81 04 12 34 56 78' +
                '02 04 87 65 43 21')
            }
          });
        });
  
        it('should convert BIT STRING from DER (decode2)', function() {
          _asn1Test({
            init: function(b) {
              // create crafted DER BIT STRING data that includes encapsulated
              // data.  often used to store SEQUENCE of INTEGERs.
              // bit stream
              _add(b, '03 81 8D');
              // no padding
              _add(b, '00');
              // sequence
              _add(b, '30 81 89');
              // int header and leading 0
              _add(b, '02 81 81 00');
              // 1024 bit int
              _add(b, 'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F0');
              _add(b, 'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F1');
              _add(b, 'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F2');
              _add(b, 'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F3');
              _add(b, 'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F4');
              _add(b, 'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F5');
              _add(b, 'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F6');
              _add(b, 'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F7');
              // int header and 3 byte int
              _add(b, '02 03 01 00 01');
            },
            dump: false,
            decodeBitStrings: true,
            roundtrip: true,
            v: {
              tagClass: ASN1.Class.UNIVERSAL,
              type: ASN1.Type.BITSTRING,
              constructed: false,
              value: [{
                tagClass: ASN1.Class.UNIVERSAL,
                type: ASN1.Type.SEQUENCE,
                constructed: true,
                value: [{
                  tagClass: ASN1.Class.UNIVERSAL,
                  type: ASN1.Type.INTEGER,
                  constructed: false,
                  capture: 'int0'
                }, {
                  tagClass: ASN1.Class.UNIVERSAL,
                  type: ASN1.Type.INTEGER,
                  constructed: false,
                  capture: 'int1'
                }]
              }]
            },
            captured: {
              int0: _h2b('00' +
                'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F0' +
                'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F1' +
                'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F2' +
                'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F3' +
                'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F4' +
                'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F5' +
                'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F6' +
                'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F7'),
              int1: _h2b('01 00 01')
            }
          });
        });
  
        it('should convert BIT STRING from DER (sig)', function() {
          _asn1Test({
            init: function(b) {
              // create crafted DER BIT STRING data similar to a signature that
              // could be interpreted incorrectly as encapsulated data.
              // add bit stream of 257 bytes
              _add(b, '03 82 01 01');
              // no unused
              _add(b, '00');
              // signature bits
              _add(b, '25 81 FD 6E D3 AB 34 45 DE AE F1 5B EC 6A FB 79');
              _add(b, '14 CD 7B B2 8E 48 59 AE 89 B1 55 60 11 AB BC 7F');
              _add(b, '6D 6D FE 16 22 42 AC 57 CC E9 C0 3A 8D 1E F3 C3');
              _add(b, '97 C8 23 53 DE E0 34 C3 A9 43 8B 2B D9 C0 24 FF');
              _add(b, 'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F4');
              _add(b, 'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F5');
              _add(b, 'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F6');
              _add(b, 'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F7');
              _add(b, 'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F8');
              _add(b, 'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F9');
              _add(b, 'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FA');
              _add(b, 'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FB');
              _add(b, 'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FC');
              _add(b, 'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FD');
              _add(b, 'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FE');
              _add(b, 'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF');
            },
            dump: false,
            roundtrip: true,
            v: {
              tagClass: ASN1.Class.UNIVERSAL,
              type: ASN1.Type.BITSTRING,
              constructed: false,
              // captureBitStringContents not used to check if valude decoded
              capture: 'sig'
            },
            captured: {
              sig: _h2b(
                '00' +
                '25 81 FD 6E D3 AB 34 45 DE AE F1 5B EC 6A FB 79' +
                '14 CD 7B B2 8E 48 59 AE 89 B1 55 60 11 AB BC 7F' +
                '6D 6D FE 16 22 42 AC 57 CC E9 C0 3A 8D 1E F3 C3' +
                '97 C8 23 53 DE E0 34 C3 A9 43 8B 2B D9 C0 24 FF' +
                'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F4' +
                'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F5' +
                'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F6' +
                'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F7' +
                'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F8' +
                'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F9' +
                'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FA' +
                'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FB' +
                'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FC' +
                'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FD' +
                'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FE' +
                'FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF')
            }
          });
        });
  
        it('should convert BIT STRING from DER (sig2)', function() {
          _asn1Test({
            init: function(b) {
              // create crafted DER BIT STRING data similar to a signature that
              // could be interpreted incorrectly as encapsulated data.
              // add bit stream of 257 bytes
              _add(b, '03 82 01 01');
              // no unused
              _add(b, '00');
              // signature bits
              _add(b, '2B 05 9D 81 FB 07 2C CE 15 0A 39 CD D3 89 A7 83');
              _add(b, '5C 99 5E B2 0D A4 E0 26 81 20 EF 5A 0F 23 46 E0');
              _add(b, '46 4A 5D 7B 6A C9 4F B1 38 D5 FC 71 6A 32 06 6C');
              _add(b, '68 15 9E F2 13 DB 2A 36 41 93 51 4C 98 EB 9F 32');
              _add(b, '28 54 07 CE B2 05 92 A7 C8 DF 2F A1 E3 C9 9C 0A');
              _add(b, 'E4 BE B3 88 17 CF 62 70 80 CD 10 B8 9B 08 E0 47');
              _add(b, '61 24 12 16 C0 FC 70 D9 0A 4A 39 09 F4 51 F1 62');
              _add(b, '0A 56 6B 46 C1 E2 0B FF 92 3E F5 A5 06 EE 55 0A');
              _add(b, '6D FD DA 18 B9 C1 30 6E 98 CD 38 4D 9C C5 B5 6B');
              _add(b, '81 19 B7 B1 19 52 5C F8 99 9D C2 EC A1 F5 96 A7');
              _add(b, '66 79 A6 53 F8 17 67 64 52 F6 32 37 F4 CD 74 5A');
              _add(b, '2F 59 35 06 90 6B CC F7 E6 7D 67 C4 FA 0C 7B 10');
              _add(b, '05 85 E8 4F E2 0E EF A0 D4 F8 57 EB BF 2F 14 42');
              _add(b, '62 01 09 08 35 5C 24 8C 0D 5D FD FA 52 58 D8 C9');
              _add(b, '10 45 4F AE 15 B0 9A 82 B9 FB 17 CC E6 A0 BD BA');
              _add(b, '76 BD 05 F1 70 69 43 9D 60 31 F9 F4 13 7A 8C 71');
            },
            dump: false,
            roundtrip: true,
            v: {
              tagClass: ASN1.Class.UNIVERSAL,
              type: ASN1.Type.BITSTRING,
              constructed: false,
              // captureBitStringContents not used to check if valude decoded
              captureBitStringValue: 'bits'
            },
            captured: {
              bits: _h2b(
                '2B 05 9D 81 FB 07 2C CE 15 0A 39 CD D3 89 A7 83' +
                '5C 99 5E B2 0D A4 E0 26 81 20 EF 5A 0F 23 46 E0' +
                '46 4A 5D 7B 6A C9 4F B1 38 D5 FC 71 6A 32 06 6C' +
                '68 15 9E F2 13 DB 2A 36 41 93 51 4C 98 EB 9F 32' +
                '28 54 07 CE B2 05 92 A7 C8 DF 2F A1 E3 C9 9C 0A' +
                'E4 BE B3 88 17 CF 62 70 80 CD 10 B8 9B 08 E0 47' +
                '61 24 12 16 C0 FC 70 D9 0A 4A 39 09 F4 51 F1 62' +
                '0A 56 6B 46 C1 E2 0B FF 92 3E F5 A5 06 EE 55 0A' +
                '6D FD DA 18 B9 C1 30 6E 98 CD 38 4D 9C C5 B5 6B' +
                '81 19 B7 B1 19 52 5C F8 99 9D C2 EC A1 F5 96 A7' +
                '66 79 A6 53 F8 17 67 64 52 F6 32 37 F4 CD 74 5A' +
                '2F 59 35 06 90 6B CC F7 E6 7D 67 C4 FA 0C 7B 10' +
                '05 85 E8 4F E2 0E EF A0 D4 F8 57 EB BF 2F 14 42' +
                '62 01 09 08 35 5C 24 8C 0D 5D FD FA 52 58 D8 C9' +
                '10 45 4F AE 15 B0 9A 82 B9 FB 17 CC E6 A0 BD BA' +
                '76 BD 05 F1 70 69 43 9D 60 31 F9 F4 13 7A 8C 71')
            }
          });
        });
  
        it('should convert BIT STRING from DER (sig3)', function() {
          _asn1Test({
            init: function(b) {
              // create crafted DER BIT STRING data similar to a signature that
              // could be interpreted incorrectly as encapsulated data.
              _add(b, '03 0B');
              // no unused
              _add(b, '00');
              // signature bits with structure with bad type and length
              _add(b, '2B 05 9D 05 F0 F1 F2 F3 F4 F5');
            },
            dump: false,
            roundtrip: true,
            v: {
              tagClass: ASN1.Class.UNIVERSAL,
              type: ASN1.Type.BITSTRING,
              constructed: false,
              // captureBitStringContents not used to check if value decoded
              capture: 'sig'
            },
            captured: {
              sig: _h2b(
                '00' +
                '2B 05 9D 05 F0 F1 F2 F3 F4 F5')
            }
          });
        });
  
        it('should convert BIT STRING from BER (decodable sig)', function() {
          _asn1Test({
            init: function(b) {
              // create crafted DER BIT STRING data similar to a signature that
              // could be interpreted as encapsulated data. data is such that
              // a round trip process could change the data due to INTEGER
              // optimization (removal of leading bytes) or length structure
              // compression (long to short).
              // add a basic bit stream "signature" with test data
              _add(b, '03 22');
              // no unused
              _add(b, '00');
              // everything after this point might be important bits, not ASN.1
              // SEQUENCE of tests
              _add(b, '30 1E');
              // signature bits
              // '02 02' prefix will be cause parsing as an integer
              // toDer will try to remove the extra 00.
              // tests the BIT STRING content/value saving feature
              _add(b, '02 02 00 7F');
              // similar example for -1:
              _add(b, '02 02 FF FF');
              // could extend out to any structure size:
              _add(b, '02 06 FF FF FF FF FF FF');
              // the roundtrip issue can exist for long lengths that could
              // compress to short lenghts, this could be output as '02 02 01 23':
              _add(b, '02 81 02 01 23');
              // also an issue for indefinite length structures that will
              // have a known length later:
              _add(b, '30 80');
              // a few INTEGERs
              _add(b, '02 01 00');
              _add(b, '02 01 01');
              // done
              _add(b, '00 00');
              // other examples may exist
            },
            dump: false,
            // NOTE: arbitrary data can be recompacted, check saved data worked
            roundtrip: true,
            v: {
              tagClass: ASN1.Class.UNIVERSAL,
              type: ASN1.Type.BITSTRING,
              constructed: false,
              captureBitStringValue: 'sig'
            },
            captured: {
              sig: _h2b(
                '30 1E' +
                '02 02 00 7F' +
                '02 02 FF FF' +
                '02 06 FF FF FF FF FF FF' +
                '02 81 02 01 23' +
                '30 80' +
                '02 01 00' +
                '02 01 01' +
                '00 00')
            }
          });
        });
  
        it('should convert BIT STRING from strict DER', function() {
          _asn1Test({
            init: function(b) {
              // create crafted DER BIT STRING data that includes encapsulated
              // data.  include valid data that would only parse in strict
              // mode.
              _add(b, '03 06');
              // no padding
              _add(b, '00');
              // sub-BIT STRING with valid length
              _add(b, '03 03 00 01 02');
            },
            dump: false,
            decodeBitStrings: true,
            roundtrip: true,
            v: {
              tagClass: ASN1.Class.UNIVERSAL,
              type: ASN1.Type.BITSTRING,
              constructed: false,
              // default capture value has structural data
              // check contents and value
              captureBitStringContents: 'bitsC',
              captureBitStringValue: 'bitsV'
            },
            captured: {
              bitsC: _h2b('00 03 03 00 01 02'),
              bitsV: _h2b('03 03 00 01 02')
            }
          });
        });
        it('should convert BIT STRING from non-strict DER', function() {
          _asn1Test({
            init: function(b) {
              // create crafted DER BIT STRING data that includes encapsulated
              // data.  include invalid data that would only parse in non-strict
              // mode.  ensure it is never parsed.
              _add(b, '03 05');
              // no padding
              _add(b, '00');
              // sub-BIT STRING with invalid length, missing a byte
              _add(b, '03 03 00 01');
            },
            dump: false,
            decodeBitStrings: true,
            roundtrip: true,
            v: {
              tagClass: ASN1.Class.UNIVERSAL,
              type: ASN1.Type.BITSTRING,
              constructed: false,
              // ensure default captures contents vs decoded structure
              capture: 'bits0',
              // check contents and value
              captureBitStringContents: 'bitsC',
              captureBitStringValue: 'bitsV'
            },
            captured: {
              bits0: _h2b('00 03 03 00 01'),
              bitsC: _h2b('00 03 03 00 01'),
              bitsV: _h2b('03 03 00 01')
            }
          });
        });
  
        it('should convert indefinite length seq from BER', function() {
          _asn1Test({
            init: function(b) {
              // SEQUENCE
              _add(b, '30 80');
              // a few INTEGERs
              _add(b, '02 01 00');
              _add(b, '02 01 01');
              _add(b, '02 01 02');
              // done
              _add(b, '00 00');
            },
            dump: false,
            // roundtrip will know the sequence length
            roundtrip: false,
            v: {
              tagClass: ASN1.Class.UNIVERSAL,
              type: ASN1.Type.SEQUENCE,
              constructed: true,
              value: [{
                tagClass: ASN1.Class.UNIVERSAL,
                type: ASN1.Type.INTEGER,
                constructed: false,
                capture: 'int0'
              }, {
                tagClass: ASN1.Class.UNIVERSAL,
                type: ASN1.Type.INTEGER,
                constructed: false,
                capture: 'int1'
              }, {
                tagClass: ASN1.Class.UNIVERSAL,
                type: ASN1.Type.INTEGER,
                constructed: false,
                capture: 'int2'
              }]
            },
            captured: {
              int0: _h2b('00'),
              int1: _h2b('01'),
              int2: _h2b('02')
            }
          });
        });
  
        it('should handle ASN.1 mutations', function() {
          _asn1Test({
            init: function(b) {
              // BIT STRING
              _add(b, '03 09 00');
              // SEQUENCE
              _add(b, '30 06');
              // a few INTEGERs
              _add(b, '02 01 00');
              _add(b, '02 01 01');
            },
            dump: false,
            // roundtrip will know the sequence length
            roundtrip: true,
            v: {
              tagClass: ASN1.Class.UNIVERSAL,
              type: ASN1.Type.BITSTRING,
              constructed: false,
              captureBitStringContents: 'bits',
              value: [{
                tagClass: ASN1.Class.UNIVERSAL,
                type: ASN1.Type.SEQUENCE,
                constructed: true,
                value: [{
                  tagClass: ASN1.Class.UNIVERSAL,
                  type: ASN1.Type.INTEGER,
                  constructed: false,
                  capture: 'int0'
                }, {
                  tagClass: ASN1.Class.UNIVERSAL,
                  type: ASN1.Type.INTEGER,
                  constructed: false,
                  capture: 'int1'
                }]
              }]
            },
            captured: {
              bits: _h2b('00 30 06 02 01 00 02 01 01'),
              int0: _h2b('00'),
              int1: _h2b('01')
            },
            done: function(data) {
              var asn1 = data.strict.asn1;
              // mutate
              asn1.value[0].value[0].value = _h2b('02');
              asn1.value[0].value[1].value = _h2b('03');
              // convert
              // must use new data vs saved BIT STRING data
              var der = ASN1.toDer(asn1);
              var expect = _h2b('03 09 00 30 06 02 01 02 02 01 03');
              // compare
              ASSERT.equal(UTIL.bytesToHex(der), UTIL.bytesToHex(expect));
            }
          });
        });
  
        it('should convert BMP STRING from DER', function() {
          _asn1Test({
            init: function(b) {
              // BPMSTRING
              _add(b, '1e 08');
              _add(b, '01 02 03 04 05 06 07 08');
            },
            dump: false,
            roundtrip: true,
            v: {
              tagClass: ASN1.Class.UNIVERSAL,
              type: ASN1.Type.BPMSTRING,
              constructed: false,
              capture: 'bits'
            },
            captured: {
              bits: '\u0102\u0304\u0506\u0708'
            }
          });
        });
  
        // TODO: how minimal should INTEGERs be encoded?
        // .. fromDer will create the full integer
        // .. toDer will remove only first byte if possible
        it('should minimally encode INTEGERs', function() {
          function _test(hin, hout) {
            var derIn = _h2b(hin);
            var derOut = ASN1.toDer(ASN1.fromDer(derIn));
            ASSERT.equal(
              UTIL.bytesToHex(derOut),
              UTIL.bytesToHex(_h2b(hout)));
          }
          // optimial
          _test('02 01 01', '02 01 01');
          _test('02 01 FF', '02 01 FF');
          _test('02 02 00 FF', '02 02 00 FF');
  
          // remove leading 00s before a 0b0xxxxxxx
          _test('02 04 00 00 00 01', '02 03 00 00 01');
          // this would be more optimal
          //_test('02 04 00 00 00 01', '02 01 01');
  
          // remove leading FFs before a 0b1xxxxxxx
          _test('02 04 FF FF FF FF', '02 03 FF FF FF');
          // this would be more optimal
          //_test('02 04 FF FF FF FF', '02 01 FF');
        });
        it('basic asn1 from DER', function() {
          function _test(hin) {
            var derIn = _h2b(hin);
            var asn1Out = ASN1.fromDer(derIn);
            //_asn1dump(asn1Out);
            // eslint-disable-next-line max-len
            let v = {tagClass: 0, type: 16, constructed: true, composed: false, value: [{tagClass: 0, type: 12, constructed: false, optional: true, capture: 'string1'}, {tagClass: 0, type: 2, constructed: false, optional: true, capture: 'int1'}, {tagClass: 0, type: 12, constructed: false, optional: true, capture: 'string2'}]};
            var cap = {};
            var errors = [];
            //_asn1dump(ASN1.fromDer(asn1Out.value[1].value));
            var options = {parseSupportedTypes: true};
            // eslint-disable-next-line max-len
            ASN1.validate(ASN1.fromDer(asn1Out.value[1].value), v, cap, errors, options);
            console.log(cap['string1' + ' ' + cap['string2']]);
            ASSERT.equal(cap.int1, 25);
            ASSERT.equal(cap.string1, 'EAA_DEMO');
            ASSERT.equal(cap.string2, 'ZTCORE');
          }
          // optimial
          /*_test('30 30 80 11 00 FF FF FF  FF FF FF FF FF FF FF FF'+
          'FF FF FF FF FF 81 06 46  61 6C 63 6F 6E 83 01 02' +
          'A4 04 80 02 46 51 A5 0A  0C 03 43 61 72 0C 03 47' +
          '50 53');
          console.log('NO AUTOTAGS');
          _test('30 2E 02 11 00 FF FF FF  FF FF FF FF FF FF FF FF' +
          'FF FF FF FF FF 0C 06 46  61 6C 63 6F 6E 0A 01 00' +
          '02 02 46 50 30 0A 0C 03  43 61 72 0C 03 47 50 53');
          */
          // eslint-disable-next-line max-len
          _test('30' +
           '22 06 07 2A 03 04 05 06  07 09 04 17 30 15 0C 08' +
           '45 41 41 5F 44 45 4D 4F  02 01 19 0C 06 5A 54 43' +
           '4F 52 45');
          // eslint-disable-next-line max-len
          // _test('308203f0308202d8a0030201020214464daba63872dace22bfe2e97cd1bd5e5c4ba4bd300d06092a864886f70d01010b050030583112301006035504030c09646e7373616d706c65310b300906035504061302494e3113301106035504080c0a54616d696c204e6164753110300e06035504070c074368656e6e6169310e300c060355040a0c0564756d6d79301e170d3230303832373039343831355a170d3231303832373039343831355a30583112301006035504030c09646e7373616d706c65310b300906035504061302494e3113301106035504080c0a54616d696c204e6164753110300e06035504070c074368656e6e6169310e300c060355040a0c0564756d6d7930820122300d06092a864886f70d01010105000382010f003082010a0282010100a5af81d93bb41ab9060a0b221e4f7a75a5c8da31411993816ca73e66d03bcc01f27a70a443a114029025c85492a7cf36e2f1a918b59234ed4ba53ebd7230935136a7564d2bbd836f98f5981939f1113aa9e2dca9ac94e5422ce5c08c12ec311809322ea8148af39e3e2a20381050d88dcdc90c0ce67784ff9eb890d805353d931e6e15c6605a1b48a5526a9a78078406c39a8a12dd1ec09c2d203288cb6af6edf3e1b311f3a3c2511c1ea752be992e08ffef903236876b5cf95734ad46729dba136ca46a1dd771bf188fbdcb820efb750e20507d8df737e7da71a323f3df9956e8ebf21f63c239ea0ff25d3fe5c8ba09a46fa121556cccd1500266870c51748f0203010001a381b13081ae301d0603551d0e04160414f9c95b4aa30fe4e13cd8873fdf7a668371092fce301f0603551d23041830168014f9c95b4aa30fe4e13cd8873fdf7a668371092fce300e0603551d0f0101ff0404030202ac30200603551d250101ff0416301406082b0601050507030106082b06010505070302300c0603551d130101ff04023000302c0603551d1104253023820f7777772e646e736e616d652e636f6d81107669636b40646e736e616d652e636f6d300d06092a864886f70d01010b050003820101002527776ca07374459a86143f0832efaa9382a14f7318732f8ce41b63f32b6c34da7e927a4ff8b08e2628104cf0d34238e0117c06c8c358f2e1df57f03c3dfb8c7a1d3294504acfb1fae6cc486bb5113eacf463b5ad0370facb2945d8789d5efb2e232f2f3ef1b16c50b365e070c303a69c23d2fff42b217cc27261dfde9d32e42e41e3ae76488784be2927743dfaead69c6f52686da5fb315650bd19a5c049f6fa163e898bd4534c00060dfbe2a4982d6d4dfe36401bdc1dfe7087f6de4159df2c173d49fa47543fba6d1b97eb20be631f5fb5e1d1a3367ecc0d29e481eca61e3fd496699bd4163a1faf1dcbbf742b52ee19773a14bc1e61f9882bd8c9cfa92e');
        });
      })();
    });
  })();
  