code: function Type(attrs, opts) {
    var type = LOGICAL_TYPE || this;
    LOGICAL_TYPE = null;
  
    // Lazily instantiated hash string. It will be generated the first time the
    // type's default fingerprint is computed (for example when using `equals`).
    this._hs = undefined;
    this._name = undefined;
    this._aliases = undefined;
  
    if (attrs) {
      // This is a complex (i.e. non-primitive) type.
      var name = attrs.name;
      var namespace = attrs.namespace === undefined ?
        opts && opts.namespace :
        attrs.namespace;
      if (name !== undefined) {
        // This isn't an anonymous type.
        name = qualify(name, namespace);
        if (isPrimitive(name)) {
          // Avro doesn't allow redefining primitive names.
          throw new Error(f('cannot rename primitive type: %j', name));
        }
        var registry = opts && opts.registry;
        if (registry) {
          if (registry[name] !== undefined) {
            throw new Error(f('duplicate type name: %s', name));
          }
          registry[name] = type;
        }
      } else if (opts && opts.noAnonymousTypes) {
        throw new Error(f('missing name property in schema: %j', attrs));
      }
      this._name = name;
      this._aliases = attrs.aliases ?
        attrs.aliases.map(function (s) { return qualify(s, namespace); }) :
        [];
    }
  }
docs: "Abstract" base Avro type.
  
  This class' constructor will register any named types to support recursive
  schemas. All type values are represented in memory similarly to their JSON
  representation, except for:
  
  + `bytes` and `fixed` which are represented as `Buffer`s.
  + `union`s which will be "unwrapped" unless the `wrapUnions` option is set.
  
  See individual subclasses for details.