text: /*! @name mpd-parser @version 0.16.0 @license Apache-2.0 */
  (function (global, factory) {
    typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('global/window'), require('xmldom')) :
    typeof define === 'function' && define.amd ? define(['exports', 'global/window', 'xmldom'], factory) :
    (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.mpdParser = {}, global.window, global.window));
  }(this, (function (exports, window, xmldom) { 'use strict';
  
    function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
  
    var window__default = /*#__PURE__*/_interopDefaultLegacy(window);
  
    var version = "0.16.0";
  
    var isObject = function isObject(obj) {
      return !!obj && typeof obj === 'object';
    };
  
    var merge = function merge() {
      for (var _len = arguments.length, objects = new Array(_len), _key = 0; _key < _len; _key++) {
        objects[_key] = arguments[_key];
      }
  
      return objects.reduce(function (result, source) {
        if (typeof source !== 'object') {
          return result;
        }
  
        Object.keys(source).forEach(function (key) {
          if (Array.isArray(result[key]) && Array.isArray(source[key])) {
            result[key] = result[key].concat(source[key]);
          } else if (isObject(result[key]) && isObject(source[key])) {
            result[key] = merge(result[key], source[key]);
          } else {
            result[key] = source[key];
          }
        });
        return result;
      }, {});
    };
    var values = function values(o) {
      return Object.keys(o).map(function (k) {
        return o[k];
      });
    };
  
    var range = function range(start, end) {
      var result = [];
  
      for (var i = start; i < end; i++) {
        result.push(i);
      }
  
      return result;
    };
    var flatten = function flatten(lists) {
      return lists.reduce(function (x, y) {
        return x.concat(y);
      }, []);
    };
    var from = function from(list) {
      if (!list.length) {
        return [];
      }
  
      var result = [];
  
      for (var i = 0; i < list.length; i++) {
        result.push(list[i]);
      }
  
      return result;
    };
    var findIndexes = function findIndexes(l, key) {
      return l.reduce(function (a, e, i) {
        if (e[key]) {
          a.push(i);
        }
  
        return a;
      }, []);
    };
  
    var errors = {
      INVALID_NUMBER_OF_PERIOD: 'INVALID_NUMBER_OF_PERIOD',
      DASH_EMPTY_MANIFEST: 'DASH_EMPTY_MANIFEST',
      DASH_INVALID_XML: 'DASH_INVALID_XML',
      NO_BASE_URL: 'NO_BASE_URL',
      MISSING_SEGMENT_INFORMATION: 'MISSING_SEGMENT_INFORMATION',
      SEGMENT_TIME_UNSPECIFIED: 'SEGMENT_TIME_UNSPECIFIED',
      UNSUPPORTED_UTC_TIMING_SCHEME: 'UNSUPPORTED_UTC_TIMING_SCHEME'
    };
  
    function createCommonjsModule(fn, basedir, module) {
    	return module = {
    	  path: basedir,
    	  exports: {},
    	  require: function (path, base) {
          return commonjsRequire(path, (base === undefined || base === null) ? module.path : base);
        }
    	}, fn(module, module.exports), module.exports;
    }
  
    function commonjsRequire () {
    	throw new Error('Dynamic requires are not currently supported by @rollup/plugin-commonjs');
    }
  
    var urlToolkit = createCommonjsModule(function (module, exports) {
      // see https://tools.ietf.org/html/rfc1808
      (function (root) {
        var URL_REGEX = /^((?:[a-zA-Z0-9+\-.]+:)?)(\/\/[^\/?#]*)?((?:[^\/?#]*\/)*[^;?#]*)?(;[^?#]*)?(\?[^#]*)?(#.*)?$/;
        var FIRST_SEGMENT_REGEX = /^([^\/?#]*)(.*)$/;
        var SLASH_DOT_REGEX = /(?:\/|^)\.(?=\/)/g;
        var SLASH_DOT_DOT_REGEX = /(?:\/|^)\.\.\/(?!\.\.\/)[^\/]*(?=\/)/g;
        var URLToolkit = {
          // If opts.alwaysNormalize is true then the path will always be normalized even when it starts with / or //
          // E.g
          // With opts.alwaysNormalize = false (default, spec compliant)
          // http://a.com/b/cd + /e/f/../g => http://a.com/e/f/../g
          // With opts.alwaysNormalize = true (not spec compliant)
          // http://a.com/b/cd + /e/f/../g => http://a.com/e/g
          buildAbsoluteURL: function buildAbsoluteURL(baseURL, relativeURL, opts) {
            opts = opts || {}; // remove any remaining space and CRLF
  
            baseURL = baseURL.trim();
            relativeURL = relativeURL.trim();
  
            if (!relativeURL) {
              // 2a) If the embedded URL is entirely empty, it inherits the
              // entire base URL (i.e., is set equal to the base URL)
              // and we are done.
              if (!opts.alwaysNormalize) {
                return baseURL;
              }
  
              var basePartsForNormalise = URLToolkit.parseURL(baseURL);
  
              if (!basePartsForNormalise) {
                throw new Error('Error trying to parse base URL.');
              }
  
              basePartsForNormalise.path = URLToolkit.normalizePath(basePartsForNormalise.path);
              return URLToolkit.buildURLFromParts(basePartsForNormalise);
            }
  
            var relativeParts = URLToolkit.parseURL(relativeURL);
  
            if (!relativeParts) {
              throw new Error('Error trying to parse relative URL.');
            }
  
            if (relativeParts.scheme) {
              // 2b) If the embedded URL starts with a scheme name, it is
              // interpreted as an absolute URL and we are done.
              if (!opts.alwaysNormalize) {
                return relativeURL;
              }
  
              relativeParts.path = URLToolkit.normalizePath(relativeParts.path);
              return URLToolkit.buildURLFromParts(relativeParts);
            }
  
            var baseParts = URLToolkit.parseURL(baseURL);
  
            if (!baseParts) {
              throw new Error('Error trying to parse base URL.');
            }
  
            if (!baseParts.netLoc && baseParts.path && baseParts.path[0] !== '/') {
              // If netLoc missing and path doesn't start with '/', assume everthing before the first '/' is the netLoc
              // This causes 'example.com/a' to be handled as '//example.com/a' instead of '/example.com/a'
              var pathParts = FIRST_SEGMENT_REGEX.exec(baseParts.path);
              baseParts.netLoc = pathParts[1];
              baseParts.path = pathParts[2];
            }
  
            if (baseParts.netLoc && !baseParts.path) {
              baseParts.path = '/';
            }
  
            var builtParts = {
              // 2c) Otherwise, the embedded URL inherits the scheme of
              // the base URL.
              scheme: baseParts.scheme,
              netLoc: relativeParts.netLoc,
              path: null,
              params: relativeParts.params,
              query: relativeParts.query,
              fragment: relativeParts.fragment
            };
  
            if (!relativeParts.netLoc) {
              // 3) If the embedded URL's <net_loc> is non-empty, we skip to
              // Step 7.  Otherwise, the embedded URL inherits the <net_loc>
              // (if any) of the base URL.
              builtParts.netLoc = baseParts.netLoc; // 4) If the embedded URL path is preceded by a slash "/", the
              // path is not relative and we skip to Step 7.
  
              if (relativeParts.path[0] !== '/') {
                if (!relativeParts.path) {
                  // 5) If the embedded URL path is empty (and not preceded by a
                  // slash), then the embedded URL inherits the base URL path
                  builtParts.path = baseParts.path; // 5a) if the embedded URL's <params> is non-empty, we skip to
                  // step 7; otherwise, it inherits the <params> of the base
                  // URL (if any) and
  
                  if (!relativeParts.params) {
                    builtParts.params = baseParts.params; // 5b) if the embedded URL's <query> is non-empty, we skip to
                    // step 7; otherwise, it inherits the <query> of the base
                    // URL (if any) and we skip to step 7.
  
                    if (!relativeParts.query) {
                      builtParts.query = baseParts.query;
                    }
                  }
                } else {
                  // 6) The last segment of the base URL's path (anything
                  // following the rightmost slash "/", or the entire path if no
                  // slash is present) is removed and the embedded URL's path is
                  // appended in its place.
                  var baseURLPath = baseParts.path;
                  var newPath = baseURLPath.substring(0, baseURLPath.lastIndexOf('/') + 1) + relativeParts.path;
                  builtParts.path = URLToolkit.normalizePath(newPath);
                }
              }
            }
  
            if (builtParts.path === null) {
              builtParts.path = opts.alwaysNormalize ? URLToolkit.normalizePath(relativeParts.path) : relativeParts.path;
            }
  
            return URLToolkit.buildURLFromParts(builtParts);
          },
          parseURL: function parseURL(url) {
            var parts = URL_REGEX.exec(url);
  
            if (!parts) {
              return null;
            }
  
            return {
              scheme: parts[1] || '',
              netLoc: parts[2] || '',
              path: parts[3] || '',
              params: parts[4] || '',
              query: parts[5] || '',
              fragment: parts[6] || ''
            };
          },
          normalizePath: function normalizePath(path) {
            // The following operations are
            // then applied, in order, to the new path:
            // 6a) All occurrences of "./", where "." is a complete path
            // segment, are removed.
            // 6b) If the path ends with "." as a complete path segment,
            // that "." is removed.
            path = path.split('').reverse().join('').replace(SLASH_DOT_REGEX, ''); // 6c) All occurrences of "<segment>/../", where <segment> is a
            // complete path segment not equal to "..", are removed.
            // Removal of these path segments is performed iteratively,
            // removing the leftmost matching pattern on each iteration,
            // until no matching pattern remains.
            // 6d) If the path ends with "<segment>/..", where <segment> is a
            // complete path segment not equal to "..", that
            // "<segment>/.." is removed.
  
            while (path.length !== (path = path.replace(SLASH_DOT_DOT_REGEX, '')).length) {}
  
            return path.split('').reverse().join('');
          },
          buildURLFromParts: function buildURLFromParts(parts) {
            return parts.scheme + parts.netLoc + parts.path + parts.params + parts.query + parts.fragment;
          }
        };
        module.exports = URLToolkit;
      })();
    });
  
    var resolveUrl = function resolveUrl(baseUrl, relativeUrl) {
      // return early if we don't need to resolve
      if (/^[a-z]+:/i.test(relativeUrl)) {
        return relativeUrl;
      } // if the base URL is relative then combine with the current location
  
  
      if (!/\/\//i.test(baseUrl)) {
        baseUrl = urlToolkit.buildAbsoluteURL(window__default['default'].location && window__default['default'].location.href || '', baseUrl);
      }
  
      return urlToolkit.buildAbsoluteURL(baseUrl, relativeUrl);
    };
  
    /**
     * @typedef {Object} SingleUri
     * @property {string} uri - relative location of segment
     * @property {string} resolvedUri - resolved location of segment
     * @property {Object} byterange - Object containing information on how to make byte range
     *   requests following byte-range-spec per RFC2616.
     * @property {String} byterange.length - length of range request
     * @property {String} byterange.offset - byte offset of range request
     *
     * @see https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35.1
     */
  
    /**
     * Converts a URLType node (5.3.9.2.3 Table 13) to a segment object
     * that conforms to how m3u8-parser is structured
     *
     * @see https://github.com/videojs/m3u8-parser
     *
     * @param {string} baseUrl - baseUrl provided by <BaseUrl> nodes
     * @param {string} source - source url for segment
     * @param {string} range - optional range used for range calls,
     *   follows  RFC 2616, Clause 14.35.1
     * @return {SingleUri} full segment information transformed into a format similar
     *   to m3u8-parser
     */
  
    var urlTypeToSegment = function urlTypeToSegment(_ref) {
      var _ref$baseUrl = _ref.baseUrl,
          baseUrl = _ref$baseUrl === void 0 ? '' : _ref$baseUrl,
          _ref$source = _ref.source,
          source = _ref$source === void 0 ? '' : _ref$source,
          _ref$range = _ref.range,
          range = _ref$range === void 0 ? '' : _ref$range,
          _ref$indexRange = _ref.indexRange,
          indexRange = _ref$indexRange === void 0 ? '' : _ref$indexRange;
      var segment = {
        uri: source,
        resolvedUri: resolveUrl(baseUrl || '', source)
      };
  
      if (range || indexRange) {
        var rangeStr = range ? range : indexRange;
        var ranges = rangeStr.split('-');
        var startRange = parseInt(ranges[0], 10);
        var endRange = parseInt(ranges[1], 10); // byterange should be inclusive according to
        // RFC 2616, Clause 14.35.1
  
        segment.byterange = {
          length: endRange - startRange + 1,
          offset: startRange
        };
      }
  
      return segment;
    };
    var byteRangeToString = function byteRangeToString(byterange) {
      // `endRange` is one less than `offset + length` because the HTTP range
      // header uses inclusive ranges
      var endRange = byterange.offset + byterange.length - 1;
      return byterange.offset + "-" + endRange;
    };
  
    /**
     * parse the end number attribue that can be a string
     * number, or undefined.
     *
     * @param {string|number|undefined} endNumber
     *        The end number attribute.
     *
     * @return {number|null}
     *          The result of parsing the end number.
     */
  
    var parseEndNumber = function parseEndNumber(endNumber) {
      if (endNumber && typeof endNumber !== 'number') {
        endNumber = parseInt(endNumber, 10);
      }
  
      if (isNaN(endNumber)) {
        return null;
      }
  
      return endNumber;
    };
    /**
     * Functions for calculating the range of available segments in static and dynamic
     * manifests.
     */
  
  
    var segmentRange = {
      /**
       * Returns the entire range of available segments for a static MPD
       *
       * @param {Object} attributes
       *        Inheritied MPD attributes
       * @return {{ start: number, end: number }}
       *         The start and end numbers for available segments
       */
      static: function _static(attributes) {
        var duration = attributes.duration,
            _attributes$timescale = attributes.timescale,
            timescale = _attributes$timescale === void 0 ? 1 : _attributes$timescale,
            sourceDuration = attributes.sourceDuration;
        var endNumber = parseEndNumber(attributes.endNumber);
        return {
          start: 0,
          end: typeof endNumber === 'number' ? endNumber : Math.ceil(sourceDuration / (duration / timescale))
        };
      },
  
      /**
       * Returns the current live window range of available segments for a dynamic MPD
       *
       * @param {Object} attributes
       *        Inheritied MPD attributes
       * @return {{ start: number, end: number }}
       *         The start and end numbers for available segments
       */
      dynamic: function dynamic(attributes) {
        var NOW = attributes.NOW,
            clientOffset = attributes.clientOffset,
            availabilityStartTime = attributes.availabilityStartTime,
            _attributes$timescale2 = attributes.timescale,
            timescale = _attributes$timescale2 === void 0 ? 1 : _attributes$timescale2,
            duration = attributes.duration,
            _attributes$start = attributes.start,
            start = _attributes$start === void 0 ? 0 : _attributes$start,
            _attributes$minimumUp = attributes.minimumUpdatePeriod,
            minimumUpdatePeriod = _attributes$minimumUp === void 0 ? 0 : _attributes$minimumUp,
            _attributes$timeShift = attributes.timeShiftBufferDepth,
            timeShiftBufferDepth = _attributes$timeShift === void 0 ? Infinity : _attributes$timeShift;
        var endNumber = parseEndNumber(attributes.endNumber);
        var now = (NOW + clientOffset) / 1000;
        var periodStartWC = availabilityStartTime + start;
        var periodEndWC = now + minimumUpdatePeriod;
        var periodDuration = periodEndWC - periodStartWC;
        var segmentCount = Math.ceil(periodDuration * timescale / duration);
        var availableStart = Math.floor((now - periodStartWC - timeShiftBufferDepth) * timescale / duration);
        var availableEnd = Math.floor((now - periodStartWC) * timescale / duration);
        return {
          start: Math.max(0, availableStart),
          end: typeof endNumber === 'number' ? endNumber : Math.min(segmentCount, availableEnd)
        };
      }
    };
    /**
     * Maps a range of numbers to objects with information needed to build the corresponding
     * segment list
     *
     * @name toSegmentsCallback
     * @function
     * @param {number} number
     *        Number of the segment
     * @param {number} index
     *        Index of the number in the range list
     * @return {{ number: Number, duration: Number, timeline: Number, time: Number }}
     *         Object with segment timing and duration info
     */
  
    /**
     * Returns a callback for Array.prototype.map for mapping a range of numbers to
     * information needed to build the segment list.
     *
     * @param {Object} attributes
     *        Inherited MPD attributes
     * @return {toSegmentsCallback}
     *         Callback map function
     */
  
    var toSegments = function toSegments(attributes) {
      return function (number, index) {
        var duration = attributes.duration,
            _attributes$timescale3 = attributes.timescale,
            timescale = _attributes$timescale3 === void 0 ? 1 : _attributes$timescale3,
            periodIndex = attributes.periodIndex,
            _attributes$startNumb = attributes.startNumber,
            startNumber = _attributes$startNumb === void 0 ? 1 : _attributes$startNumb;
        return {
          number: startNumber + number,
          duration: duration / timescale,
          timeline: periodIndex,
          time: index * duration
        };
      };
    };
    /**
     * Returns a list of objects containing segment timing and duration info used for
     * building the list of segments. This uses the @duration attribute specified
     * in the MPD manifest to derive the range of segments.
     *
     * @param {Object} attributes
     *        Inherited MPD attributes
     * @return {{number: number, duration: number, time: number, timeline: number}[]}
     *         List of Objects with segment timing and duration info
     */
  
    var parseByDuration = function parseByDuration(attributes) {
      var _attributes$type = attributes.type,
          type = _attributes$type === void 0 ? 'static' : _attributes$type,
          duration = attributes.duration,
          _attributes$timescale4 = attributes.timescale,
          timescale = _attributes$timescale4 === void 0 ? 1 : _attributes$timescale4,
          sourceDuration = attributes.sourceDuration;
  
      var _segmentRange$type = segmentRange[type](attributes),
          start = _segmentRange$type.start,
          end = _segmentRange$type.end;
  
      var segments = range(start, end).map(toSegments(attributes));
  
      if (type === 'static') {
        var index = segments.length - 1; // final segment may be less than full segment duration
  
        segments[index].duration = sourceDuration - duration / timescale * index;
      }
  
      return segments;
    };
  
    /**
     * Translates SegmentBase into a set of segments.
     * (DASH SPEC Section 5.3.9.3.2) contains a set of <SegmentURL> nodes.  Each
     * node should be translated into segment.
     *
     * @param {Object} attributes
     *   Object containing all inherited attributes from parent elements with attribute
     *   names as keys
     * @return {Object.<Array>} list of segments
     */
  
    var segmentsFromBase = function segmentsFromBase(attributes) {
      var baseUrl = attributes.baseUrl,
          _attributes$initializ = attributes.initialization,
          initialization = _attributes$initializ === void 0 ? {} : _attributes$initializ,
          sourceDuration = attributes.sourceDuration,
          _attributes$indexRang = attributes.indexRange,
          indexRange = _attributes$indexRang === void 0 ? '' : _attributes$indexRang,
          duration = attributes.duration; // base url is required for SegmentBase to work, per spec (Section 5.3.9.2.1)
  
      if (!baseUrl) {
        throw new Error(errors.NO_BASE_URL);
      }
  
      var initSegment = urlTypeToSegment({
        baseUrl: baseUrl,
        source: initialization.sourceURL,
        range: initialization.range
      });
      var segment = urlTypeToSegment({
        baseUrl: baseUrl,
        source: baseUrl,
        indexRange: indexRange
      });
      segment.map = initSegment; // If there is a duration, use it, otherwise use the given duration of the source
      // (since SegmentBase is only for one total segment)
  
      if (duration) {
        var segmentTimeInfo = parseByDuration(attributes);
  
        if (segmentTimeInfo.length) {
          segment.duration = segmentTimeInfo[0].duration;
          segment.timeline = segmentTimeInfo[0].timeline;
        }
      } else if (sourceDuration) {
        segment.duration = sourceDuration;
        segment.timeline = 0;
      } // This is used for mediaSequence
  
  
      segment.number = 0;
      return [segment];
    };
    /**
     * Given a playlist, a sidx box, and a baseUrl, update the segment list of the playlist
     * according to the sidx information given.
     *
     * playlist.sidx has metadadata about the sidx where-as the sidx param
     * is the parsed sidx box itself.
     *
     * @param {Object} playlist the playlist to update the sidx information for
     * @param {Object} sidx the parsed sidx box
     * @return {Object} the playlist object with the updated sidx information
     */
  
    var addSidxSegmentsToPlaylist = function addSidxSegmentsToPlaylist(playlist, sidx, baseUrl) {
      // Retain init segment information
      var initSegment = playlist.sidx.map ? playlist.sidx.map : null; // Retain source duration from initial master manifest parsing
  
      var sourceDuration = playlist.sidx.duration; // Retain source timeline
  
      var timeline = playlist.timeline || 0;
      var sidxByteRange = playlist.sidx.byterange;
      var sidxEnd = sidxByteRange.offset + sidxByteRange.length; // Retain timescale of the parsed sidx
  
      var timescale = sidx.timescale; // referenceType 1 refers to other sidx boxes
  
      var mediaReferences = sidx.references.filter(function (r) {
        return r.referenceType !== 1;
      });
      var segments = []; // firstOffset is the offset from the end of the sidx box
  
      var startIndex = sidxEnd + sidx.firstOffset;
  
      for (var i = 0; i < mediaReferences.length; i++) {
        var reference = sidx.references[i]; // size of the referenced (sub)segment
  
        var size = reference.referencedSize; // duration of the referenced (sub)segment, in  the  timescale
        // this will be converted to seconds when generating segments
  
        var duration = reference.subsegmentDuration; // should be an inclusive range
  
        var endIndex = startIndex + size - 1;
        var indexRange = startIndex + "-" + endIndex;
        var attributes = {
          baseUrl: baseUrl,
          timescale: timescale,
          timeline: timeline,
          // this is used in parseByDuration
          periodIndex: timeline,
          duration: duration,
          sourceDuration: sourceDuration,
          indexRange: indexRange
        };
        var segment = segmentsFromBase(attributes)[0];
  
        if (initSegment) {
          segment.map = initSegment;
        }
  
        segments.push(segment);
        startIndex += size;
      }
  
      playlist.segments = segments;
      return playlist;
    };
  
    var generateSidxKey = function generateSidxKey(sidx) {
      return sidx && sidx.uri + '-' + byteRangeToString(sidx.byterange);
    };
  
    var mergeDiscontiguousPlaylists = function mergeDiscontiguousPlaylists(playlists) {
      var mergedPlaylists = values(playlists.reduce(function (acc, playlist) {
        // assuming playlist IDs are the same across periods
        // TODO: handle multiperiod where representation sets are not the same
        // across periods
        var name = playlist.attributes.id + (playlist.attributes.lang || ''); // Periods after first
  
        if (acc[name]) {
          var _acc$name$segments;
  
          // first segment of subsequent periods signal a discontinuity
          if (playlist.segments[0]) {
            playlist.segments[0].discontinuity = true;
          }
  
          (_acc$name$segments = acc[name].segments).push.apply(_acc$name$segments, playlist.segments); // bubble up contentProtection, this assumes all DRM content
          // has the same contentProtection
  
  
          if (playlist.attributes.contentProtection) {
            acc[name].attributes.contentProtection = playlist.attributes.contentProtection;
          }
        } else {
          // first Period
          acc[name] = playlist;
        }
  
        return acc;
      }, {}));
      return mergedPlaylists.map(function (playlist) {
        playlist.discontinuityStarts = findIndexes(playlist.segments, 'discontinuity');
        return playlist;
      });
    };
  
    var addSidxSegmentsToPlaylist$1 = function addSidxSegmentsToPlaylist$1(playlist, sidxMapping) {
      var sidxKey = generateSidxKey(playlist.sidx);
      var sidxMatch = sidxKey && sidxMapping[sidxKey] && sidxMapping[sidxKey].sidx;
  
      if (sidxMatch) {
        addSidxSegmentsToPlaylist(playlist, sidxMatch, playlist.sidx.resolvedUri);
      }
  
      return playlist;
    };
    var addSidxSegmentsToPlaylists = function addSidxSegmentsToPlaylists(playlists, sidxMapping) {
      if (sidxMapping === void 0) {
        sidxMapping = {};
      }
  
      if (!Object.keys(sidxMapping).length) {
        return playlists;
      }
  
      for (var i in playlists) {
        playlists[i] = addSidxSegmentsToPlaylist$1(playlists[i], sidxMapping);
      }
  
      return playlists;
    };
    var formatAudioPlaylist = function formatAudioPlaylist(_ref, isAudioOnly) {
      var _attributes;
  
      var attributes = _ref.attributes,
          segments = _ref.segments,
          sidx = _ref.sidx;
      var playlist = {
        attributes: (_attributes = {
          NAME: attributes.id,
          BANDWIDTH: attributes.bandwidth,
          CODECS: attributes.codecs
        }, _attributes['PROGRAM-ID'] = 1, _attributes),
        uri: '',
        endList: (attributes.type || 'static') === 'static',
        timeline: attributes.periodIndex,
        resolvedUri: '',
        targetDuration: attributes.duration,
        segments: segments,
        mediaSequence: segments.length ? segments[0].number : 1
      };
  
      if (attributes.contentProtection) {
        playlist.contentProtection = attributes.contentProtection;
      }
  
      if (sidx) {
        playlist.sidx = sidx;
      }
  
      if (isAudioOnly) {
        playlist.attributes.AUDIO = 'audio';
        playlist.attributes.SUBTITLES = 'subs';
      }
  
      return playlist;
    };
    var formatVttPlaylist = function formatVttPlaylist(_ref2) {
      var _m3u8Attributes;
  
      var attributes = _ref2.attributes,
          segments = _ref2.segments;
  
      if (typeof segments === 'undefined') {
        // vtt tracks may use single file in BaseURL
        segments = [{
          uri: attributes.baseUrl,
          timeline: attributes.periodIndex,
          resolvedUri: attributes.baseUrl || '',
          duration: attributes.sourceDuration,
          number: 0
        }]; // targetDuration should be the same duration as the only segment
  
        attributes.duration = attributes.sourceDuration;
      }
  
      var m3u8Attributes = (_m3u8Attributes = {
        NAME: attributes.id,
        BANDWIDTH: attributes.bandwidth
      }, _m3u8Attributes['PROGRAM-ID'] = 1, _m3u8Attributes);
  
      if (attributes.codecs) {
        m3u8Attributes.CODECS = attributes.codecs;
      }
  
      return {
        attributes: m3u8Attributes,
        uri: '',
        endList: (attributes.type || 'static') === 'static',
        timeline: attributes.periodIndex,
        resolvedUri: attributes.baseUrl || '',
        targetDuration: attributes.duration,
        segments: segments,
        mediaSequence: segments.length ? segments[0].number : 1
      };
    };
    var organizeAudioPlaylists = function organizeAudioPlaylists(playlists, sidxMapping, isAudioOnly) {
      if (sidxMapping === void 0) {
        sidxMapping = {};
      }
  
      if (isAudioOnly === void 0) {
        isAudioOnly = false;
      }
  
      var mainPlaylist;
      var formattedPlaylists = playlists.reduce(function (a, playlist) {
        var role = playlist.attributes.role && playlist.attributes.role.value || '';
        var language = playlist.attributes.lang || '';
        var label = playlist.attributes.label || 'main';
  
        if (language && !playlist.attributes.label) {
          var roleLabel = role ? " (" + role + ")" : '';
          label = "" + playlist.attributes.lang + roleLabel;
        }
  
        if (!a[label]) {
          a[label] = {
            language: language,
            autoselect: true,
            default: role === 'main',
            playlists: [],
            uri: ''
          };
        }
  
        var formatted = addSidxSegmentsToPlaylist$1(formatAudioPlaylist(playlist, isAudioOnly), sidxMapping);
        a[label].playlists.push(formatted);
  
        if (typeof mainPlaylist === 'undefined' && role === 'main') {
          mainPlaylist = playlist;
          mainPlaylist.default = true;
        }
  
        return a;
      }, {}); // if no playlists have role "main", mark the first as main
  
      if (!mainPlaylist) {
        var firstLabel = Object.keys(formattedPlaylists)[0];
        formattedPlaylists[firstLabel].default = true;
      }
  
      return formattedPlaylists;
    };
    var organizeVttPlaylists = function organizeVttPlaylists(playlists, sidxMapping) {
      if (sidxMapping === void 0) {
        sidxMapping = {};
      }
  
      return playlists.reduce(function (a, playlist) {
        var label = playlist.attributes.lang || 'text';
  
        if (!a[label]) {
          a[label] = {
            language: label,
            default: false,
            autoselect: false,
            playlists: [],
            uri: ''
          };
        }
  
        a[label].playlists.push(addSidxSegmentsToPlaylist$1(formatVttPlaylist(playlist), sidxMapping));
        return a;
      }, {});
    };
    var formatVideoPlaylist = function formatVideoPlaylist(_ref3) {
      var _attributes2;
  
      var attributes = _ref3.attributes,
          segments = _ref3.segments,
          sidx = _ref3.sidx;
      var playlist = {
        attributes: (_attributes2 = {
          NAME: attributes.id,
          AUDIO: 'audio',
          SUBTITLES: 'subs',
          RESOLUTION: {
            width: attributes.width,
            height: attributes.height
          },
          CODECS: attributes.codecs,
          BANDWIDTH: attributes.bandwidth
        }, _attributes2['PROGRAM-ID'] = 1, _attributes2),
        uri: '',
        endList: (attributes.type || 'static') === 'static',
        timeline: attributes.periodIndex,
        resolvedUri: '',
        targetDuration: attributes.duration,
        segments: segments,
        mediaSequence: segments.length ? segments[0].number : 1
      };
  
      if (attributes.contentProtection) {
        playlist.contentProtection = attributes.contentProtection;
      }
  
      if (sidx) {
        playlist.sidx = sidx;
      }
  
      return playlist;
    };
  
    var videoOnly = function videoOnly(_ref4) {
      var attributes = _ref4.attributes;
      return attributes.mimeType === 'video/mp4' || attributes.mimeType === 'video/webm' || attributes.contentType === 'video';
    };
  
    var audioOnly = function audioOnly(_ref5) {
      var attributes = _ref5.attributes;
      return attributes.mimeType === 'audio/mp4' || attributes.mimeType === 'audio/webm' || attributes.contentType === 'audio';
    };
  
    var vttOnly = function vttOnly(_ref6) {
      var attributes = _ref6.attributes;
      return attributes.mimeType === 'text/vtt' || attributes.contentType === 'text';
    };
  
    var toM3u8 = function toM3u8(dashPlaylists, locations, sidxMapping) {
      var _mediaGroups;
  
      if (sidxMapping === void 0) {
        sidxMapping = {};
      }
  
      if (!dashPlaylists.length) {
        return {};
      } // grab all master attributes
  
  
      var _dashPlaylists$0$attr = dashPlaylists[0].attributes,
          duration = _dashPlaylists$0$attr.sourceDuration,
          _dashPlaylists$0$attr2 = _dashPlaylists$0$attr.type,
          type = _dashPlaylists$0$attr2 === void 0 ? 'static' : _dashPlaylists$0$attr2,
          suggestedPresentationDelay = _dashPlaylists$0$attr.suggestedPresentationDelay,
          minimumUpdatePeriod = _dashPlaylists$0$attr.minimumUpdatePeriod;
      var videoPlaylists = mergeDiscontiguousPlaylists(dashPlaylists.filter(videoOnly)).map(formatVideoPlaylist);
      var audioPlaylists = mergeDiscontiguousPlaylists(dashPlaylists.filter(audioOnly));
      var vttPlaylists = dashPlaylists.filter(vttOnly);
      var master = {
        allowCache: true,
        discontinuityStarts: [],
        segments: [],
        endList: true,
        mediaGroups: (_mediaGroups = {
          AUDIO: {},
          VIDEO: {}
        }, _mediaGroups['CLOSED-CAPTIONS'] = {}, _mediaGroups.SUBTITLES = {}, _mediaGroups),
        uri: '',
        duration: duration,
        playlists: addSidxSegmentsToPlaylists(videoPlaylists, sidxMapping)
      };
  
      if (minimumUpdatePeriod >= 0) {
        master.minimumUpdatePeriod = minimumUpdatePeriod * 1000;
      }
  
      if (locations) {
        master.locations = locations;
      }
  
      if (type === 'dynamic') {
        master.suggestedPresentationDelay = suggestedPresentationDelay;
      }
  
      var isAudioOnly = master.playlists.length === 0;
  
      if (audioPlaylists.length) {
        master.mediaGroups.AUDIO.audio = organizeAudioPlaylists(audioPlaylists, sidxMapping, isAudioOnly);
      }
  
      if (vttPlaylists.length) {
        master.mediaGroups.SUBTITLES.subs = organizeVttPlaylists(vttPlaylists, sidxMapping);
      }
  
      return master;
    };
  
    /**
     * Calculates the R (repetition) value for a live stream (for the final segment
     * in a manifest where the r value is negative 1)
     *
     * @param {Object} attributes
     *        Object containing all inherited attributes from parent elements with attribute
     *        names as keys
     * @param {number} time
     *        current time (typically the total time up until the final segment)
     * @param {number} duration
     *        duration property for the given <S />
     *
     * @return {number}
     *        R value to reach the end of the given period
     */
    var getLiveRValue = function getLiveRValue(attributes, time, duration) {
      var NOW = attributes.NOW,
          clientOffset = attributes.clientOffset,
          availabilityStartTime = attributes.availabilityStartTime,
          _attributes$timescale = attributes.timescale,
          timescale = _attributes$timescale === void 0 ? 1 : _attributes$timescale,
          _attributes$start = attributes.start,
          start = _attributes$start === void 0 ? 0 : _attributes$start,
          _attributes$minimumUp = attributes.minimumUpdatePeriod,
          minimumUpdatePeriod = _attributes$minimumUp === void 0 ? 0 : _attributes$minimumUp;
      var now = (NOW + clientOffset) / 1000;
      var periodStartWC = availabilityStartTime + start;
      var periodEndWC = now + minimumUpdatePeriod;
      var periodDuration = periodEndWC - periodStartWC;
      return Math.ceil((periodDuration * timescale - time) / duration);
    };
    /**
     * Uses information provided by SegmentTemplate.SegmentTimeline to determine segment
     * timing and duration
     *
     * @param {Object} attributes
     *        Object containing all inherited attributes from parent elements with attribute
     *        names as keys
     * @param {Object[]} segmentTimeline
     *        List of objects representing the attributes of each S element contained within
     *
     * @return {{number: number, duration: number, time: number, timeline: number}[]}
     *         List of Objects with segment timing and duration info
     */
  
  
    var parseByTimeline = function parseByTimeline(attributes, segmentTimeline) {
      var _attributes$type = attributes.type,
          type = _attributes$type === void 0 ? 'static' : _attributes$type,
          _attributes$minimumUp2 = attributes.minimumUpdatePeriod,
          minimumUpdatePeriod = _attributes$minimumUp2 === void 0 ? 0 : _attributes$minimumUp2,
          _attributes$media = attributes.media,
          media = _attributes$media === void 0 ? '' : _attributes$media,
          sourceDuration = attributes.sourceDuration,
          _attributes$timescale2 = attributes.timescale,
          timescale = _attributes$timescale2 === void 0 ? 1 : _attributes$timescale2,
          _attributes$startNumb = attributes.startNumber,
          startNumber = _attributes$startNumb === void 0 ? 1 : _attributes$startNumb,
          timeline = attributes.periodIndex;
      var segments = [];
      var time = -1;
  
      for (var sIndex = 0; sIndex < segmentTimeline.length; sIndex++) {
        var S = segmentTimeline[sIndex];
        var duration = S.d;
        var repeat = S.r || 0;
        var segmentTime = S.t || 0;
  
        if (time < 0) {
          // first segment
          time = segmentTime;
        }
  
        if (segmentTime && segmentTime > time) {
          // discontinuity
          // TODO: How to handle this type of discontinuity
          // timeline++ here would treat it like HLS discontuity and content would
          // get appended without gap
          // E.G.
          //  <S t="0" d="1" />
          //  <S d="1" />
          //  <S d="1" />
          //  <S t="5" d="1" />
          // would have $Time$ values of [0, 1, 2, 5]
          // should this be appened at time positions [0, 1, 2, 3],(#EXT-X-DISCONTINUITY)
          // or [0, 1, 2, gap, gap, 5]? (#EXT-X-GAP)
          // does the value of sourceDuration consider this when calculating arbitrary
          // negative @r repeat value?
          // E.G. Same elements as above with this added at the end
          //  <S d="1" r="-1" />
          //  with a sourceDuration of 10
          // Would the 2 gaps be included in the time duration calculations resulting in
          // 8 segments with $Time$ values of [0, 1, 2, 5, 6, 7, 8, 9] or 10 segments
          // with $Time$ values of [0, 1, 2, 5, 6, 7, 8, 9, 10, 11] ?
          time = segmentTime;
        }
  
        var count = void 0;
  
        if (repeat < 0) {
          var nextS = sIndex + 1;
  
          if (nextS === segmentTimeline.length) {
            // last segment
            if (type === 'dynamic' && minimumUpdatePeriod > 0 && media.indexOf('$Number$') > 0) {
              count = getLiveRValue(attributes, time, duration);
            } else {
              // TODO: This may be incorrect depending on conclusion of TODO above
              count = (sourceDuration * timescale - time) / duration;
            }
          } else {
            count = (segmentTimeline[nextS].t - time) / duration;
          }
        } else {
          count = repeat + 1;
        }
  
        var end = startNumber + segments.length + count;
        var number = startNumber + segments.length;
  
        while (number < end) {
          segments.push({
            number: number,
            duration: duration / timescale,
            time: time,
            timeline: timeline
          });
          time += duration;
          number++;
        }
      }
  
      return segments;
    };
  
    var identifierPattern = /\$([A-z]*)(?:(%0)([0-9]+)d)?\$/g;
    /**
     * Replaces template identifiers with corresponding values. To be used as the callback
     * for String.prototype.replace
     *
     * @name replaceCallback
     * @function
     * @param {string} match
     *        Entire match of identifier
     * @param {string} identifier
     *        Name of matched identifier
     * @param {string} format
     *        Format tag string. Its presence indicates that padding is expected
     * @param {string} width
     *        Desired length of the replaced value. Values less than this width shall be left
     *        zero padded
     * @return {string}
     *         Replacement for the matched identifier
     */
  
    /**
     * Returns a function to be used as a callback for String.prototype.replace to replace
     * template identifiers
     *
     * @param {Obect} values
     *        Object containing values that shall be used to replace known identifiers
     * @param {number} values.RepresentationID
     *        Value of the Representation@id attribute
     * @param {number} values.Number
     *        Number of the corresponding segment
     * @param {number} values.Bandwidth
     *        Value of the Representation@bandwidth attribute.
     * @param {number} values.Time
     *        Timestamp value of the corresponding segment
     * @return {replaceCallback}
     *         Callback to be used with String.prototype.replace to replace identifiers
     */
  
    var identifierReplacement = function identifierReplacement(values) {
      return function (match, identifier, format, width) {
        if (match === '$$') {
          // escape sequence
          return '$';
        }
  
        if (typeof values[identifier] === 'undefined') {
          return match;
        }
  
        var value = '' + values[identifier];
  
        if (identifier === 'RepresentationID') {
          // Format tag shall not be present with RepresentationID
          return value;
        }
  
        if (!format) {
          width = 1;
        } else {
          width = parseInt(width, 10);
        }
  
        if (value.length >= width) {
          return value;
        }
  
        return "" + new Array(width - value.length + 1).join('0') + value;
      };
    };
    /**
     * Constructs a segment url from a template string
     *
     * @param {string} url
     *        Template string to construct url from
     * @param {Obect} values
     *        Object containing values that shall be used to replace known identifiers
     * @param {number} values.RepresentationID
     *        Value of the Representation@id attribute
     * @param {number} values.Number
     *        Number of the corresponding segment
     * @param {number} values.Bandwidth
     *        Value of the Representation@bandwidth attribute.
     * @param {number} values.Time
     *        Timestamp value of the corresponding segment
     * @return {string}
     *         Segment url with identifiers replaced
     */
  
    var constructTemplateUrl = function constructTemplateUrl(url, values) {
      return url.replace(identifierPattern, identifierReplacement(values));
    };
    /**
     * Generates a list of objects containing timing and duration information about each
     * segment needed to generate segment uris and the complete segment object
     *
     * @param {Object} attributes
     *        Object containing all inherited attributes from parent elements with attribute
     *        names as keys
     * @param {Object[]|undefined} segmentTimeline
     *        List of objects representing the attributes of each S element contained within
     *        the SegmentTimeline element
     * @return {{number: number, duration: number, time: number, timeline: number}[]}
     *         List of Objects with segment timing and duration info
     */
  
    var parseTemplateInfo = function parseTemplateInfo(attributes, segmentTimeline) {
      if (!attributes.duration && !segmentTimeline) {
        // if neither @duration or SegmentTimeline are present, then there shall be exactly
        // one media segment
        return [{
          number: attributes.startNumber || 1,
          duration: attributes.sourceDuration,
          time: 0,
          timeline: attributes.periodIndex
        }];
      }
  
      if (attributes.duration) {
        return parseByDuration(attributes);
      }
  
      return parseByTimeline(attributes, segmentTimeline);
    };
    /**
     * Generates a list of segments using information provided by the SegmentTemplate element
     *
     * @param {Object} attributes
     *        Object containing all inherited attributes from parent elements with attribute
     *        names as keys
     * @param {Object[]|undefined} segmentTimeline
     *        List of objects representing the attributes of each S element contained within
     *        the SegmentTimeline element
     * @return {Object[]}
     *         List of segment objects
     */
  
    var segmentsFromTemplate = function segmentsFromTemplate(attributes, segmentTimeline) {
      var templateValues = {
        RepresentationID: attributes.id,
        Bandwidth: attributes.bandwidth || 0
      };
      var _attributes$initializ = attributes.initialization,
          initialization = _attributes$initializ === void 0 ? {
        sourceURL: '',
        range: ''
      } : _attributes$initializ;
      var mapSegment = urlTypeToSegment({
        baseUrl: attributes.baseUrl,
        source: constructTemplateUrl(initialization.sourceURL, templateValues),
        range: initialization.range
      });
      var segments = parseTemplateInfo(attributes, segmentTimeline);
      return segments.map(function (segment) {
        templateValues.Number = segment.number;
        templateValues.Time = segment.time;
        var uri = constructTemplateUrl(attributes.media || '', templateValues);
        var map = {
          uri: uri,
          timeline: segment.timeline,
          duration: segment.duration,
          resolvedUri: resolveUrl(attributes.baseUrl || '', uri),
          map: mapSegment,
          number: segment.number
        };
  
        if (attributes.presentationTimeOffset) {
          map.presentationTimeOffset = attributes.presentationTimeOffset;
        }
  
        return map;
      });
    };
  
    /**
     * Converts a <SegmentUrl> (of type URLType from the DASH spec 5.3.9.2 Table 14)
     * to an object that matches the output of a segment in videojs/mpd-parser
     *
     * @param {Object} attributes
     *   Object containing all inherited attributes from parent elements with attribute
     *   names as keys
     * @param {Object} segmentUrl
     *   <SegmentURL> node to translate into a segment object
     * @return {Object} translated segment object
     */
  
    var SegmentURLToSegmentObject = function SegmentURLToSegmentObject(attributes, segmentUrl) {
      var baseUrl = attributes.baseUrl,
          _attributes$initializ = attributes.initialization,
          initialization = _attributes$initializ === void 0 ? {} : _attributes$initializ;
      var initSegment = urlTypeToSegment({
        baseUrl: baseUrl,
        source: initialization.sourceURL,
        range: initialization.range
      });
      var segment = urlTypeToSegment({
        baseUrl: baseUrl,
        source: segmentUrl.media,
        range: segmentUrl.mediaRange
      });
      segment.map = initSegment;
      return segment;
    };
    /**
     * Generates a list of segments using information provided by the SegmentList element
     * SegmentList (DASH SPEC Section 5.3.9.3.2) contains a set of <SegmentURL> nodes.  Each
     * node should be translated into segment.
     *
     * @param {Object} attributes
     *   Object containing all inherited attributes from parent elements with attribute
     *   names as keys
     * @param {Object[]|undefined} segmentTimeline
     *        List of objects representing the attributes of each S element contained within
     *        the SegmentTimeline element
     * @return {Object.<Array>} list of segments
     */
  
  
    var segmentsFromList = function segmentsFromList(attributes, segmentTimeline) {
      var duration = attributes.duration,
          _attributes$segmentUr = attributes.segmentUrls,
          segmentUrls = _attributes$segmentUr === void 0 ? [] : _attributes$segmentUr; // Per spec (5.3.9.2.1) no way to determine segment duration OR
      // if both SegmentTimeline and @duration are defined, it is outside of spec.
  
      if (!duration && !segmentTimeline || duration && segmentTimeline) {
        throw new Error(errors.SEGMENT_TIME_UNSPECIFIED);
      }
  
      var segmentUrlMap = segmentUrls.map(function (segmentUrlObject) {
        return SegmentURLToSegmentObject(attributes, segmentUrlObject);
      });
      var segmentTimeInfo;
  
      if (duration) {
        segmentTimeInfo = parseByDuration(attributes);
      }
  
      if (segmentTimeline) {
        segmentTimeInfo = parseByTimeline(attributes, segmentTimeline);
      }
  
      var segments = segmentTimeInfo.map(function (segmentTime, index) {
        if (segmentUrlMap[index]) {
          var segment = segmentUrlMap[index];
          segment.timeline = segmentTime.timeline;
          segment.duration = segmentTime.duration;
          segment.number = segmentTime.number;
          return segment;
        } // Since we're mapping we should get rid of any blank segments (in case
        // the given SegmentTimeline is handling for more elements than we have
        // SegmentURLs for).
  
      }).filter(function (segment) {
        return segment;
      });
      return segments;
    };
  
    var generateSegments = function generateSegments(_ref) {
      var attributes = _ref.attributes,
          segmentInfo = _ref.segmentInfo;
      var segmentAttributes;
      var segmentsFn;
  
      if (segmentInfo.template) {
        segmentsFn = segmentsFromTemplate;
        segmentAttributes = merge(attributes, segmentInfo.template);
  
        if (segmentInfo.template.presentationTimeOffset) {
          segmentAttributes.presentationTimeOffset = segmentInfo.template.presentationTimeOffset / segmentInfo.template.timescale;
        }
      } else if (segmentInfo.base) {
        segmentsFn = segmentsFromBase;
        segmentAttributes = merge(attributes, segmentInfo.base);
      } else if (segmentInfo.list) {
        segmentsFn = segmentsFromList;
        segmentAttributes = merge(attributes, segmentInfo.list);
      }
  
      var segmentsInfo = {
        attributes: attributes
      };
  
      if (!segmentsFn) {
        return segmentsInfo;
      }
  
      var segments = segmentsFn(segmentAttributes, segmentInfo.timeline); // The @duration attribute will be used to determin the playlist's targetDuration which
      // must be in seconds. Since we've generated the segment list, we no longer need
      // @duration to be in @timescale units, so we can convert it here.
  
      if (segmentAttributes.duration) {
        var _segmentAttributes = segmentAttributes,
            duration = _segmentAttributes.duration,
            _segmentAttributes$ti = _segmentAttributes.timescale,
            timescale = _segmentAttributes$ti === void 0 ? 1 : _segmentAttributes$ti;
        segmentAttributes.duration = duration / timescale;
      } else if (segments.length) {
        // if there is no @duration attribute, use the largest segment duration as
        // as target duration
        segmentAttributes.duration = segments.reduce(function (max, segment) {
          return Math.max(max, Math.ceil(segment.duration));
        }, 0);
      } else {
        segmentAttributes.duration = 0;
      }
  
      segmentsInfo.attributes = segmentAttributes;
      segmentsInfo.segments = segments; // This is a sidx box without actual segment information
  
      if (segmentInfo.base && segmentAttributes.indexRange) {
        segmentsInfo.sidx = segments[0];
        segmentsInfo.segments = [];
      }
  
      return segmentsInfo;
    };
    var toPlaylists = function toPlaylists(representations) {
      return representations.map(generateSegments);
    };
  
    var findChildren = function findChildren(element, name) {
      return from(element.childNodes).filter(function (_ref) {
        var tagName = _ref.tagName;
        return tagName === name;
      });
    };
    var getContent = function getContent(element) {
      return element.textContent.trim();
    };
  
    var parseDuration = function parseDuration(str) {
      var SECONDS_IN_YEAR = 365 * 24 * 60 * 60;
      var SECONDS_IN_MONTH = 30 * 24 * 60 * 60;
      var SECONDS_IN_DAY = 24 * 60 * 60;
      var SECONDS_IN_HOUR = 60 * 60;
      var SECONDS_IN_MIN = 60; // P10Y10M10DT10H10M10.1S
  
      var durationRegex = /P(?:(\d*)Y)?(?:(\d*)M)?(?:(\d*)D)?(?:T(?:(\d*)H)?(?:(\d*)M)?(?:([\d.]*)S)?)?/;
      var match = durationRegex.exec(str);
  
      if (!match) {
        return 0;
      }
  
      var _match$slice = match.slice(1),
          year = _match$slice[0],
          month = _match$slice[1],
          day = _match$slice[2],
          hour = _match$slice[3],
          minute = _match$slice[4],
          second = _match$slice[5];
  
      return parseFloat(year || 0) * SECONDS_IN_YEAR + parseFloat(month || 0) * SECONDS_IN_MONTH + parseFloat(day || 0) * SECONDS_IN_DAY + parseFloat(hour || 0) * SECONDS_IN_HOUR + parseFloat(minute || 0) * SECONDS_IN_MIN + parseFloat(second || 0);
    };
    var parseDate = function parseDate(str) {
      // Date format without timezone according to ISO 8601
      // YYY-MM-DDThh:mm:ss.ssssss
      var dateRegex = /^\d+-\d+-\d+T\d+:\d+:\d+(\.\d+)?$/; // If the date string does not specifiy a timezone, we must specifiy UTC. This is
      // expressed by ending with 'Z'
  
      if (dateRegex.test(str)) {
        str += 'Z';
      }
  
      return Date.parse(str);
    };
  
    var parsers = {
      /**
       * Specifies the duration of the entire Media Presentation. Format is a duration string
       * as specified in ISO 8601
       *
       * @param {string} value
       *        value of attribute as a string
       * @return {number}
       *         The duration in seconds
       */
      mediaPresentationDuration: function mediaPresentationDuration(value) {
        return parseDuration(value);
      },
  
      /**
       * Specifies the Segment availability start time for all Segments referred to in this
       * MPD. For a dynamic manifest, it specifies the anchor for the earliest availability
       * time. Format is a date string as specified in ISO 8601
       *
       * @param {string} value
       *        value of attribute as a string
       * @return {number}
       *         The date as seconds from unix epoch
       */
      availabilityStartTime: function availabilityStartTime(value) {
        return parseDate(value) / 1000;
      },
  
      /**
       * Specifies the smallest period between potential changes to the MPD. Format is a
       * duration string as specified in ISO 8601
       *
       * @param {string} value
       *        value of attribute as a string
       * @return {number}
       *         The duration in seconds
       */
      minimumUpdatePeriod: function minimumUpdatePeriod(value) {
        return parseDuration(value);
      },
  
      /**
       * Specifies the suggested presentation delay. Format is a
       * duration string as specified in ISO 8601
       *
       * @param {string} value
       *        value of attribute as a string
       * @return {number}
       *         The duration in seconds
       */
      suggestedPresentationDelay: function suggestedPresentationDelay(value) {
        return parseDuration(value);
      },
  
      /**
       * specifices the type of mpd. Can be either "static" or "dynamic"
       *
       * @param {string} value
       *        value of attribute as a string
       *
       * @return {string}
       *         The type as a string
       */
      type: function type(value) {
        return value;
      },
  
      /**
       * Specifies the duration of the smallest time shifting buffer for any Representation
       * in the MPD. Format is a duration string as specified in ISO 8601
       *
       * @param {string} value
       *        value of attribute as a string
       * @return {number}
       *         The duration in seconds
       */
      timeShiftBufferDepth: function timeShiftBufferDepth(value) {
        return parseDuration(value);
      },
  
      /**
       * Specifies the PeriodStart time of the Period relative to the availabilityStarttime.
       * Format is a duration string as specified in ISO 8601
       *
       * @param {string} value
       *        value of attribute as a string
       * @return {number}
       *         The duration in seconds
       */
      start: function start(value) {
        return parseDuration(value);
      },
  
      /**
       * Specifies the width of the visual presentation
       *
       * @param {string} value
       *        value of attribute as a string
       * @return {number}
       *         The parsed width
       */
      width: function width(value) {
        return parseInt(value, 10);
      },
  
      /**
       * Specifies the height of the visual presentation
       *
       * @param {string} value
       *        value of attribute as a string
       * @return {number}
       *         The parsed height
       */
      height: function height(value) {
        return parseInt(value, 10);
      },
  
      /**
       * Specifies the bitrate of the representation
       *
       * @param {string} value
       *        value of attribute as a string
       * @return {number}
       *         The parsed bandwidth
       */
      bandwidth: function bandwidth(value) {
        return parseInt(value, 10);
      },
  
      /**
       * Specifies the number of the first Media Segment in this Representation in the Period
       *
       * @param {string} value
       *        value of attribute as a string
       * @return {number}
       *         The parsed number
       */
      startNumber: function startNumber(value) {
        return parseInt(value, 10);
      },
  
      /**
       * Specifies the timescale in units per seconds
       *
       * @param {string} value
       *        value of attribute as a string
       * @return {number}
       *         The parsed timescale
       */
      timescale: function timescale(value) {
        return parseInt(value, 10);
      },
  
      /**
       * Specifies the presentationTimeOffset.
       *
       * @param {string} value
       *        value of the attribute as a string
       *
       * @return {number}
       *         The parsed presentationTimeOffset
       */
      presentationTimeOffset: function presentationTimeOffset(value) {
        return parseInt(value, 10);
      },
  
      /**
       * Specifies the constant approximate Segment duration
       * NOTE: The <Period> element also contains an @duration attribute. This duration
       *       specifies the duration of the Period. This attribute is currently not
       *       supported by the rest of the parser, however we still check for it to prevent
       *       errors.
       *
       * @param {string} value
       *        value of attribute as a string
       * @return {number}
       *         The parsed duration
       */
      duration: function duration(value) {
        var parsedValue = parseInt(value, 10);
  
        if (isNaN(parsedValue)) {
          return parseDuration(value);
        }
  
        return parsedValue;
      },
  
      /**
       * Specifies the Segment duration, in units of the value of the @timescale.
       *
       * @param {string} value
       *        value of attribute as a string
       * @return {number}
       *         The parsed duration
       */
      d: function d(value) {
        return parseInt(value, 10);
      },
  
      /**
       * Specifies the MPD start time, in @timescale units, the first Segment in the series
       * starts relative to the beginning of the Period
       *
       * @param {string} value
       *        value of attribute as a string
       * @return {number}
       *         The parsed time
       */
      t: function t(value) {
        return parseInt(value, 10);
      },
  
      /**
       * Specifies the repeat count of the number of following contiguous Segments with the
       * same duration expressed by the value of @d
       *
       * @param {string} value
       *        value of attribute as a string
       * @return {number}
       *         The parsed number
       */
      r: function r(value) {
        return parseInt(value, 10);
      },
  
      /**
       * Default parser for all other attributes. Acts as a no-op and just returns the value
       * as a string
       *
       * @param {string} value
       *        value of attribute as a string
       * @return {string}
       *         Unparsed value
       */
      DEFAULT: function DEFAULT(value) {
        return value;
      }
    };
    /**
     * Gets all the attributes and values of the provided node, parses attributes with known
     * types, and returns an object with attribute names mapped to values.
     *
     * @param {Node} el
     *        The node to parse attributes from
     * @return {Object}
     *         Object with all attributes of el parsed
     */
  
    var parseAttributes = function parseAttributes(el) {
      if (!(el && el.attributes)) {
        return {};
      }
  
      return from(el.attributes).reduce(function (a, e) {
        var parseFn = parsers[e.name] || parsers.DEFAULT;
        a[e.name] = parseFn(e.value);
        return a;
      }, {});
    };
  
    var atob = function atob(s) {
      return window__default['default'].atob ? window__default['default'].atob(s) : Buffer.from(s, 'base64').toString('binary');
    };
  
    function decodeB64ToUint8Array(b64Text) {
      var decodedString = atob(b64Text);
      var array = new Uint8Array(decodedString.length);
  
      for (var i = 0; i < decodedString.length; i++) {
        array[i] = decodedString.charCodeAt(i);
      }
  
      return array;
    }
  
    var keySystemsMap = {
      'urn:uuid:1077efec-c0b2-4d02-ace3-3c1e52e2fb4b': 'org.w3.clearkey',
      'urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed': 'com.widevine.alpha',
      'urn:uuid:9a04f079-9840-4286-ab92-e65be0885f95': 'com.microsoft.playready',
      'urn:uuid:f239e769-efa3-4850-9c16-a903c6932efb': 'com.adobe.primetime'
    };
    /**
     * Builds a list of urls that is the product of the reference urls and BaseURL values
     *
     * @param {string[]} referenceUrls
     *        List of reference urls to resolve to
     * @param {Node[]} baseUrlElements
     *        List of BaseURL nodes from the mpd
     * @return {string[]}
     *         List of resolved urls
     */
  
    var buildBaseUrls = function buildBaseUrls(referenceUrls, baseUrlElements) {
      if (!baseUrlElements.length) {
        return referenceUrls;
      }
  
      return flatten(referenceUrls.map(function (reference) {
        return baseUrlElements.map(function (baseUrlElement) {
          return resolveUrl(reference, getContent(baseUrlElement));
        });
      }));
    };
    /**
     * Contains all Segment information for its containing AdaptationSet
     *
     * @typedef {Object} SegmentInformation
     * @property {Object|undefined} template
     *           Contains the attributes for the SegmentTemplate node
     * @property {Object[]|undefined} timeline
     *           Contains a list of atrributes for each S node within the SegmentTimeline node
     * @property {Object|undefined} list
     *           Contains the attributes for the SegmentList node
     * @property {Object|undefined} base
     *           Contains the attributes for the SegmentBase node
     */
  
    /**
     * Returns all available Segment information contained within the AdaptationSet node
     *
     * @param {Node} adaptationSet
     *        The AdaptationSet node to get Segment information from
     * @return {SegmentInformation}
     *         The Segment information contained within the provided AdaptationSet
     */
  
    var getSegmentInformation = function getSegmentInformation(adaptationSet) {
      var segmentTemplate = findChildren(adaptationSet, 'SegmentTemplate')[0];
      var segmentList = findChildren(adaptationSet, 'SegmentList')[0];
      var segmentUrls = segmentList && findChildren(segmentList, 'SegmentURL').map(function (s) {
        return merge({
          tag: 'SegmentURL'
        }, parseAttributes(s));
      });
      var segmentBase = findChildren(adaptationSet, 'SegmentBase')[0];
      var segmentTimelineParentNode = segmentList || segmentTemplate;
      var segmentTimeline = segmentTimelineParentNode && findChildren(segmentTimelineParentNode, 'SegmentTimeline')[0];
      var segmentInitializationParentNode = segmentList || segmentBase || segmentTemplate;
      var segmentInitialization = segmentInitializationParentNode && findChildren(segmentInitializationParentNode, 'Initialization')[0]; // SegmentTemplate is handled slightly differently, since it can have both
      // @initialization and an <Initialization> node.  @initialization can be templated,
      // while the node can have a url and range specified.  If the <SegmentTemplate> has
      // both @initialization and an <Initialization> subelement we opt to override with
      // the node, as this interaction is not defined in the spec.
  
      var template = segmentTemplate && parseAttributes(segmentTemplate);
  
      if (template && segmentInitialization) {
        template.initialization = segmentInitialization && parseAttributes(segmentInitialization);
      } else if (template && template.initialization) {
        // If it is @initialization we convert it to an object since this is the format that
        // later functions will rely on for the initialization segment.  This is only valid
        // for <SegmentTemplate>
        template.initialization = {
          sourceURL: template.initialization
        };
      }
  
      var segmentInfo = {
        template: template,
        timeline: segmentTimeline && findChildren(segmentTimeline, 'S').map(function (s) {
          return parseAttributes(s);
        }),
        list: segmentList && merge(parseAttributes(segmentList), {
          segmentUrls: segmentUrls,
          initialization: parseAttributes(segmentInitialization)
        }),
        base: segmentBase && merge(parseAttributes(segmentBase), {
          initialization: parseAttributes(segmentInitialization)
        })
      };
      Object.keys(segmentInfo).forEach(function (key) {
        if (!segmentInfo[key]) {
          delete segmentInfo[key];
        }
      });
      return segmentInfo;
    };
    /**
     * Contains Segment information and attributes needed to construct a Playlist object
     * from a Representation
     *
     * @typedef {Object} RepresentationInformation
     * @property {SegmentInformation} segmentInfo
     *           Segment information for this Representation
     * @property {Object} attributes
     *           Inherited attributes for this Representation
     */
  
    /**
     * Maps a Representation node to an object containing Segment information and attributes
     *
     * @name inheritBaseUrlsCallback
     * @function
     * @param {Node} representation
     *        Representation node from the mpd
     * @return {RepresentationInformation}
     *         Representation information needed to construct a Playlist object
     */
  
    /**
     * Returns a callback for Array.prototype.map for mapping Representation nodes to
     * Segment information and attributes using inherited BaseURL nodes.
     *
     * @param {Object} adaptationSetAttributes
     *        Contains attributes inherited by the AdaptationSet
     * @param {string[]} adaptationSetBaseUrls
     *        Contains list of resolved base urls inherited by the AdaptationSet
     * @param {SegmentInformation} adaptationSetSegmentInfo
     *        Contains Segment information for the AdaptationSet
     * @return {inheritBaseUrlsCallback}
     *         Callback map function
     */
  
    var inheritBaseUrls = function inheritBaseUrls(adaptationSetAttributes, adaptationSetBaseUrls, adaptationSetSegmentInfo) {
      return function (representation) {
        var repBaseUrlElements = findChildren(representation, 'BaseURL');
        var repBaseUrls = buildBaseUrls(adaptationSetBaseUrls, repBaseUrlElements);
        var attributes = merge(adaptationSetAttributes, parseAttributes(representation));
        var representationSegmentInfo = getSegmentInformation(representation);
        return repBaseUrls.map(function (baseUrl) {
          return {
            segmentInfo: merge(adaptationSetSegmentInfo, representationSegmentInfo),
            attributes: merge(attributes, {
              baseUrl: baseUrl
            })
          };
        });
      };
    };
    /**
     * Tranforms a series of content protection nodes to
     * an object containing pssh data by key system
     *
     * @param {Node[]} contentProtectionNodes
     *        Content protection nodes
     * @return {Object}
     *        Object containing pssh data by key system
     */
  
    var generateKeySystemInformation = function generateKeySystemInformation(contentProtectionNodes) {
      return contentProtectionNodes.reduce(function (acc, node) {
        var attributes = parseAttributes(node);
        var keySystem = keySystemsMap[attributes.schemeIdUri];
  
        if (keySystem) {
          acc[keySystem] = {
            attributes: attributes
          };
          var psshNode = findChildren(node, 'cenc:pssh')[0];
  
          if (psshNode) {
            var pssh = getContent(psshNode);
            var psshBuffer = pssh && decodeB64ToUint8Array(pssh);
            acc[keySystem].pssh = psshBuffer;
          }
        }
  
        return acc;
      }, {});
    };
    /**
     * Maps an AdaptationSet node to a list of Representation information objects
     *
     * @name toRepresentationsCallback
     * @function
     * @param {Node} adaptationSet
     *        AdaptationSet node from the mpd
     * @return {RepresentationInformation[]}
     *         List of objects containing Representaion information
     */
  
    /**
     * Returns a callback for Array.prototype.map for mapping AdaptationSet nodes to a list of
     * Representation information objects
     *
     * @param {Object} periodAttributes
     *        Contains attributes inherited by the Period
     * @param {string[]} periodBaseUrls
     *        Contains list of resolved base urls inherited by the Period
     * @param {string[]} periodSegmentInfo
     *        Contains Segment Information at the period level
     * @return {toRepresentationsCallback}
     *         Callback map function
     */
  
  
    var toRepresentations = function toRepresentations(periodAttributes, periodBaseUrls, periodSegmentInfo) {
      return function (adaptationSet) {
        var adaptationSetAttributes = parseAttributes(adaptationSet);
        var adaptationSetBaseUrls = buildBaseUrls(periodBaseUrls, findChildren(adaptationSet, 'BaseURL'));
        var role = findChildren(adaptationSet, 'Role')[0];
        var roleAttributes = {
          role: parseAttributes(role)
        };
        var attrs = merge(periodAttributes, adaptationSetAttributes, roleAttributes);
        var label = findChildren(adaptationSet, 'Label')[0];
  
        if (label && label.childNodes.length) {
          var labelVal = label.childNodes[0].nodeValue.trim();
          attrs = merge(attrs, {
            label: labelVal
          });
        }
  
        var contentProtection = generateKeySystemInformation(findChildren(adaptationSet, 'ContentProtection'));
  
        if (Object.keys(contentProtection).length) {
          attrs = merge(attrs, {
            contentProtection: contentProtection
          });
        }
  
        var segmentInfo = getSegmentInformation(adaptationSet);
        var representations = findChildren(adaptationSet, 'Representation');
        var adaptationSetSegmentInfo = merge(periodSegmentInfo, segmentInfo);
        return flatten(representations.map(inheritBaseUrls(attrs, adaptationSetBaseUrls, adaptationSetSegmentInfo)));
      };
    };
    /**
     * Maps an Period node to a list of Representation inforamtion objects for all
     * AdaptationSet nodes contained within the Period
     *
     * @name toAdaptationSetsCallback
     * @function
     * @param {Node} period
     *        Period node from the mpd
     * @param {number} periodIndex
     *        Index of the Period within the mpd
     * @return {RepresentationInformation[]}
     *         List of objects containing Representaion information
     */
  
    /**
     * Returns a callback for Array.prototype.map for mapping Period nodes to a list of
     * Representation information objects
     *
     * @param {Object} mpdAttributes
     *        Contains attributes inherited by the mpd
     * @param {string[]} mpdBaseUrls
     *        Contains list of resolved base urls inherited by the mpd
     * @return {toAdaptationSetsCallback}
     *         Callback map function
     */
  
    var toAdaptationSets = function toAdaptationSets(mpdAttributes, mpdBaseUrls) {
      return function (period, index) {
        var periodBaseUrls = buildBaseUrls(mpdBaseUrls, findChildren(period, 'BaseURL'));
        var periodAtt = parseAttributes(period);
        var parsedPeriodId = parseInt(periodAtt.id, 10); // fallback to mapping index if Period@id is not a number
  
        var periodIndex = window__default['default'].isNaN(parsedPeriodId) ? index : parsedPeriodId;
        var periodAttributes = merge(mpdAttributes, {
          periodIndex: periodIndex
        });
        var adaptationSets = findChildren(period, 'AdaptationSet');
        var periodSegmentInfo = getSegmentInformation(period);
        return flatten(adaptationSets.map(toRepresentations(periodAttributes, periodBaseUrls, periodSegmentInfo)));
      };
    };
    /**
     * Traverses the mpd xml tree to generate a list of Representation information objects
     * that have inherited attributes from parent nodes
     *
     * @param {Node} mpd
     *        The root node of the mpd
     * @param {Object} options
     *        Available options for inheritAttributes
     * @param {string} options.manifestUri
     *        The uri source of the mpd
     * @param {number} options.NOW
     *        Current time per DASH IOP.  Default is current time in ms since epoch
     * @param {number} options.clientOffset
     *        Client time difference from NOW (in milliseconds)
     * @return {RepresentationInformation[]}
     *         List of objects containing Representation information
     */
  
    var inheritAttributes = function inheritAttributes(mpd, options) {
      if (options === void 0) {
        options = {};
      }
  
      var _options = options,
          _options$manifestUri = _options.manifestUri,
          manifestUri = _options$manifestUri === void 0 ? '' : _options$manifestUri,
          _options$NOW = _options.NOW,
          NOW = _options$NOW === void 0 ? Date.now() : _options$NOW,
          _options$clientOffset = _options.clientOffset,
          clientOffset = _options$clientOffset === void 0 ? 0 : _options$clientOffset;
      var periods = findChildren(mpd, 'Period');
  
      if (!periods.length) {
        throw new Error(errors.INVALID_NUMBER_OF_PERIOD);
      }
  
      var locations = findChildren(mpd, 'Location');
      var mpdAttributes = parseAttributes(mpd);
      var mpdBaseUrls = buildBaseUrls([manifestUri], findChildren(mpd, 'BaseURL'));
      mpdAttributes.sourceDuration = mpdAttributes.mediaPresentationDuration || 0;
      mpdAttributes.NOW = NOW;
      mpdAttributes.clientOffset = clientOffset;
  
      if (locations.length) {
        mpdAttributes.locations = locations.map(getContent);
      }
  
      return {
        locations: mpdAttributes.locations,
        representationInfo: flatten(periods.map(toAdaptationSets(mpdAttributes, mpdBaseUrls)))
      };
    };
  
    var stringToMpdXml = function stringToMpdXml(manifestString) {
      if (manifestString === '') {
        throw new Error(errors.DASH_EMPTY_MANIFEST);
      }
  
      var parser = new xmldom.DOMParser();
      var xml;
      var mpd;
  
      try {
        xml = parser.parseFromString(manifestString, 'application/xml');
        mpd = xml && xml.documentElement.tagName === 'MPD' ? xml.documentElement : null;
      } catch (e) {// ie 11 throwsw on invalid xml
      }
  
      if (!mpd || mpd && mpd.getElementsByTagName('parsererror').length > 0) {
        throw new Error(errors.DASH_INVALID_XML);
      }
  
      return mpd;
    };
  
    /**
     * Parses the manifest for a UTCTiming node, returning the nodes attributes if found
     *
     * @param {string} mpd
     *        XML string of the MPD manifest
     * @return {Object|null}
     *         Attributes of UTCTiming node specified in the manifest. Null if none found
     */
  
    var parseUTCTimingScheme = function parseUTCTimingScheme(mpd) {
      var UTCTimingNode = findChildren(mpd, 'UTCTiming')[0];
  
      if (!UTCTimingNode) {
        return null;
      }
  
      var attributes = parseAttributes(UTCTimingNode);
  
      switch (attributes.schemeIdUri) {
        case 'urn:mpeg:dash:utc:http-head:2014':
        case 'urn:mpeg:dash:utc:http-head:2012':
          attributes.method = 'HEAD';
          break;
  
        case 'urn:mpeg:dash:utc:http-xsdate:2014':
        case 'urn:mpeg:dash:utc:http-iso:2014':
        case 'urn:mpeg:dash:utc:http-xsdate:2012':
        case 'urn:mpeg:dash:utc:http-iso:2012':
          attributes.method = 'GET';
          break;
  
        case 'urn:mpeg:dash:utc:direct:2014':
        case 'urn:mpeg:dash:utc:direct:2012':
          attributes.method = 'DIRECT';
          attributes.value = Date.parse(attributes.value);
          break;
  
        case 'urn:mpeg:dash:utc:http-ntp:2014':
        case 'urn:mpeg:dash:utc:ntp:2014':
        case 'urn:mpeg:dash:utc:sntp:2014':
        default:
          throw new Error(errors.UNSUPPORTED_UTC_TIMING_SCHEME);
      }
  
      return attributes;
    };
  
    var VERSION = version;
  
    var parse = function parse(manifestString, options) {
      if (options === void 0) {
        options = {};
      }
  
      var parsedManifestInfo = inheritAttributes(stringToMpdXml(manifestString), options);
      var playlists = toPlaylists(parsedManifestInfo.representationInfo);
      return toM3u8(playlists, parsedManifestInfo.locations, options.sidxMapping);
    };
    /**
     * Parses the manifest for a UTCTiming node, returning the nodes attributes if found
     *
     * @param {string} manifestString
     *        XML string of the MPD manifest
     * @return {Object|null}
     *         Attributes of UTCTiming node specified in the manifest. Null if none found
     */
  
  
    var parseUTCTiming = function parseUTCTiming(manifestString) {
      return parseUTCTimingScheme(stringToMpdXml(manifestString));
    };
  
    exports.VERSION = VERSION;
    exports.addSidxSegmentsToPlaylist = addSidxSegmentsToPlaylist;
    exports.generateSidxKey = generateSidxKey;
    exports.inheritAttributes = inheritAttributes;
    exports.parse = parse;
    exports.parseUTCTiming = parseUTCTiming;
    exports.stringToMpdXml = stringToMpdXml;
    exports.toM3u8 = toM3u8;
    exports.toPlaylists = toPlaylists;
  
    Object.defineProperty(exports, '__esModule', { value: true });
  
  })));
  