text: //! moment-timezone.js
  //! version : 0.5.10
  //! Copyright (c) JS Foundation and other contributors
  //! license : MIT
  //! github.com/moment/moment-timezone
  
  (function (root, factory) {
      "use strict";
  
      /*global define*/
      if (typeof define === 'function' && define.amd) {
          define(['moment'], factory);                 // AMD
      } else if (typeof module === 'object' && module.exports) {
          module.exports = factory(require('moment')); // Node
      } else {
          factory(root.moment);                        // Browser
      }
  }(this, function (moment) {
      "use strict";
  
      // Do not load moment-timezone a second time.
      if (moment.tz !== undefined) {
          logError('Moment Timezone ' + moment.tz.version + ' was already loaded ' + (moment.tz.dataVersion ? 'with data from ' : 'without any data') + moment.tz.dataVersion);
          return moment;
      }
  
      var VERSION = "0.5.10",
          zones = {},
          links = {},
          names = {},
          guesses = {},
          cachedGuess,
  
          momentVersion = moment.version.split('.'),
          major = +momentVersion[0],
          minor = +momentVersion[1];
  
      // Moment.js version check
      if (major < 2 || (major === 2 && minor < 6)) {
          logError('Moment Timezone requires Moment.js >= 2.6.0. You are using Moment.js ' + moment.version + '. See momentjs.com');
      }
  
      /************************************
          Unpacking
      ************************************/
  
      function charCodeToInt(charCode) {
          if (charCode > 96) {
              return charCode - 87;
          } else if (charCode > 64) {
              return charCode - 29;
          }
          return charCode - 48;
      }
  
      function unpackBase60(string) {
          var i = 0,
              parts = string.split('.'),
              whole = parts[0],
              fractional = parts[1] || '',
              multiplier = 1,
              num,
              out = 0,
              sign = 1;
  
          // handle negative numbers
          if (string.charCodeAt(0) === 45) {
              i = 1;
              sign = -1;
          }
  
          // handle digits before the decimal
          for (i; i < whole.length; i++) {
              num = charCodeToInt(whole.charCodeAt(i));
              out = 60 * out + num;
          }
  
          // handle digits after the decimal
          for (i = 0; i < fractional.length; i++) {
              multiplier = multiplier / 60;
              num = charCodeToInt(fractional.charCodeAt(i));
              out += num * multiplier;
          }
  
          return out * sign;
      }
  
      function arrayToInt (array) {
          for (var i = 0; i < array.length; i++) {
              array[i] = unpackBase60(array[i]);
          }
      }
  
      function intToUntil (array, length) {
          for (var i = 0; i < length; i++) {
              array[i] = Math.round((array[i - 1] || 0) + (array[i] * 60000)); // minutes to milliseconds
          }
  
          array[length - 1] = Infinity;
      }
  
      function mapIndices (source, indices) {
          var out = [], i;
  
          for (i = 0; i < indices.length; i++) {
              out[i] = source[indices[i]];
          }
  
          return out;
      }
  
      function unpack (string) {
          var data = string.split('|'),
              offsets = data[2].split(' '),
              indices = data[3].split(''),
              untils  = data[4].split(' ');
  
          arrayToInt(offsets);
          arrayToInt(indices);
          arrayToInt(untils);
  
          intToUntil(untils, indices.length);
  
          return {
              name       : data[0],
              abbrs      : mapIndices(data[1].split(' '), indices),
              offsets    : mapIndices(offsets, indices),
              untils     : untils,
              population : data[5] | 0
          };
      }
  
      /************************************
          Zone object
      ************************************/
  
      function Zone (packedString) {
          if (packedString) {
              this._set(unpack(packedString));
          }
      }
  
      Zone.prototype = {
          _set : function (unpacked) {
              this.name       = unpacked.name;
              this.abbrs      = unpacked.abbrs;
              this.untils     = unpacked.untils;
              this.offsets    = unpacked.offsets;
              this.population = unpacked.population;
          },
  
          _index : function (timestamp) {
              var target = +timestamp,
                  untils = this.untils,
                  i;
  
              for (i = 0; i < untils.length; i++) {
                  if (target < untils[i]) {
                      return i;
                  }
              }
          },
  
          parse : function (timestamp) {
              var target  = +timestamp,
                  offsets = this.offsets,
                  untils  = this.untils,
                  max     = untils.length - 1,
                  offset, offsetNext, offsetPrev, i;
  
              for (i = 0; i < max; i++) {
                  offset     = offsets[i];
                  offsetNext = offsets[i + 1];
                  offsetPrev = offsets[i ? i - 1 : i];
  
                  if (offset < offsetNext && tz.moveAmbiguousForward) {
                      offset = offsetNext;
                  } else if (offset > offsetPrev && tz.moveInvalidForward) {
                      offset = offsetPrev;
                  }
  
                  if (target < untils[i] - (offset * 60000)) {
                      return offsets[i];
                  }
              }
  
              return offsets[max];
          },
  
          abbr : function (mom) {
              return this.abbrs[this._index(mom)];
          },
  
          offset : function (mom) {
              return this.offsets[this._index(mom)];
          }
      };
  
      /************************************
          Current Timezone
      ************************************/
  
      function OffsetAt(at) {
          var timeString = at.toTimeString();
          var abbr = timeString.match(/\([a-z ]+\)/i);
          if (abbr && abbr[0]) {
              // 17:56:31 GMT-0600 (CST)
              // 17:56:31 GMT-0600 (Central Standard Time)
              abbr = abbr[0].match(/[A-Z]/g);
              abbr = abbr ? abbr.join('') : undefined;
          } else {
              // 17:56:31 CST
              // 17:56:31 GMT+0800 (台北標準時間)
              abbr = timeString.match(/[A-Z]{3,5}/g);
              abbr = abbr ? abbr[0] : undefined;
          }
  
          if (abbr === 'GMT') {
              abbr = undefined;
          }
  
          this.at = +at;
          this.abbr = abbr;
          this.offset = at.getTimezoneOffset();
      }
  
      function ZoneScore(zone) {
          this.zone = zone;
          this.offsetScore = 0;
          this.abbrScore = 0;
      }
  
      ZoneScore.prototype.scoreOffsetAt = function (offsetAt) {
          this.offsetScore += Math.abs(this.zone.offset(offsetAt.at) - offsetAt.offset);
          if (this.zone.abbr(offsetAt.at).replace(/[^A-Z]/g, '') !== offsetAt.abbr) {
              this.abbrScore++;
          }
      };
  
      function findChange(low, high) {
          var mid, diff;
  
          while ((diff = ((high.at - low.at) / 12e4 | 0) * 6e4)) {
              mid = new OffsetAt(new Date(low.at + diff));
              if (mid.offset === low.offset) {
                  low = mid;
              } else {
                  high = mid;
              }
          }
  
          return low;
      }
  
      function userOffsets() {
          var startYear = new Date().getFullYear() - 2,
              last = new OffsetAt(new Date(startYear, 0, 1)),
              offsets = [last],
              change, next, i;
  
          for (i = 1; i < 48; i++) {
              next = new OffsetAt(new Date(startYear, i, 1));
              if (next.offset !== last.offset) {
                  change = findChange(last, next);
                  offsets.push(change);
                  offsets.push(new OffsetAt(new Date(change.at + 6e4)));
              }
              last = next;
          }
  
          for (i = 0; i < 4; i++) {
              offsets.push(new OffsetAt(new Date(startYear + i, 0, 1)));
              offsets.push(new OffsetAt(new Date(startYear + i, 6, 1)));
          }
  
          return offsets;
      }
  
      function sortZoneScores (a, b) {
          if (a.offsetScore !== b.offsetScore) {
              return a.offsetScore - b.offsetScore;
          }
          if (a.abbrScore !== b.abbrScore) {
              return a.abbrScore - b.abbrScore;
          }
          return b.zone.population - a.zone.population;
      }
  
      function addToGuesses (name, offsets) {
          var i, offset;
          arrayToInt(offsets);
          for (i = 0; i < offsets.length; i++) {
              offset = offsets[i];
              guesses[offset] = guesses[offset] || {};
              guesses[offset][name] = true;
          }
      }
  
      function guessesForUserOffsets (offsets) {
          var offsetsLength = offsets.length,
              filteredGuesses = {},
              out = [],
              i, j, guessesOffset;
  
          for (i = 0; i < offsetsLength; i++) {
              guessesOffset = guesses[offsets[i].offset] || {};
              for (j in guessesOffset) {
                  if (guessesOffset.hasOwnProperty(j)) {
                      filteredGuesses[j] = true;
                  }
              }
          }
  
          for (i in filteredGuesses) {
              if (filteredGuesses.hasOwnProperty(i)) {
                  out.push(names[i]);
              }
          }
  
          return out;
      }
  
      function rebuildGuess () {
  
          // use Intl API when available and returning valid time zone
          try {
              var intlName = Intl.DateTimeFormat().resolvedOptions().timeZone;
              if (intlName){
                  var name = names[normalizeName(intlName)];
                  if (name) {
                      return name;
                  }
                  logError("Moment Timezone found " + intlName + " from the Intl api, but did not have that data loaded.");
              }
          } catch (e) {
              // Intl unavailable, fall back to manual guessing.
          }
  
          var offsets = userOffsets(),
              offsetsLength = offsets.length,
              guesses = guessesForUserOffsets(offsets),
              zoneScores = [],
              zoneScore, i, j;
  
          for (i = 0; i < guesses.length; i++) {
              zoneScore = new ZoneScore(getZone(guesses[i]), offsetsLength);
              for (j = 0; j < offsetsLength; j++) {
                  zoneScore.scoreOffsetAt(offsets[j]);
              }
              zoneScores.push(zoneScore);
          }
  
          zoneScores.sort(sortZoneScores);
  
          return zoneScores.length > 0 ? zoneScores[0].zone.name : undefined;
      }
  
      function guess (ignoreCache) {
          if (!cachedGuess || ignoreCache) {
              cachedGuess = rebuildGuess();
          }
          return cachedGuess;
      }
  
      /************************************
          Global Methods
      ************************************/
  
      function normalizeName (name) {
          return (name || '').toLowerCase().replace(/\//g, '_');
      }
  
      function addZone (packed) {
          var i, name, split, normalized;
  
          if (typeof packed === "string") {
              packed = [packed];
          }
  
          for (i = 0; i < packed.length; i++) {
              split = packed[i].split('|');
              name = split[0];
              normalized = normalizeName(name);
              zones[normalized] = packed[i];
              names[normalized] = name;
              if (split[5]) {
                  addToGuesses(normalized, split[2].split(' '));
              }
          }
      }
  
      function getZone (name, caller) {
          name = normalizeName(name);
  
          var zone = zones[name];
          var link;
  
          if (zone instanceof Zone) {
              return zone;
          }
  
          if (typeof zone === 'string') {
              zone = new Zone(zone);
              zones[name] = zone;
              return zone;
          }
  
          // Pass getZone to prevent recursion more than 1 level deep
          if (links[name] && caller !== getZone && (link = getZone(links[name], getZone))) {
              zone = zones[name] = new Zone();
              zone._set(link);
              zone.name = names[name];
              return zone;
          }
  
          return null;
      }
  
      function getNames () {
          var i, out = [];
  
          for (i in names) {
              if (names.hasOwnProperty(i) && (zones[i] || zones[links[i]]) && names[i]) {
                  out.push(names[i]);
              }
          }
  
          return out.sort();
      }
  
      function addLink (aliases) {
          var i, alias, normal0, normal1;
  
          if (typeof aliases === "string") {
              aliases = [aliases];
          }
  
          for (i = 0; i < aliases.length; i++) {
              alias = aliases[i].split('|');
  
              normal0 = normalizeName(alias[0]);
              normal1 = normalizeName(alias[1]);
  
              links[normal0] = normal1;
              names[normal0] = alias[0];
  
              links[normal1] = normal0;
              names[normal1] = alias[1];
          }
      }
  
      function loadData (data) {
          addZone(data.zones);
          addLink(data.links);
          tz.dataVersion = data.version;
      }
  
      function zoneExists (name) {
          if (!zoneExists.didShowError) {
              zoneExists.didShowError = true;
                  logError("moment.tz.zoneExists('" + name + "') has been deprecated in favor of !moment.tz.zone('" + name + "')");
          }
          return !!getZone(name);
      }
  
      function needsOffset (m) {
          return !!(m._a && (m._tzm === undefined));
      }
  
      function logError (message) {
          if (typeof console !== 'undefined' && typeof console.error === 'function') {
              console.error(message);
          }
      }
  
      /************************************
          moment.tz namespace
      ************************************/
  
      function tz (input) {
          var args = Array.prototype.slice.call(arguments, 0, -1),
              name = arguments[arguments.length - 1],
              zone = getZone(name),
              out  = moment.utc.apply(null, args);
  
          if (zone && !moment.isMoment(input) && needsOffset(out)) {
              out.add(zone.parse(out), 'minutes');
          }
  
          out.tz(name);
  
          return out;
      }
  
      tz.version      = VERSION;
      tz.dataVersion  = '';
      tz._zones       = zones;
      tz._links       = links;
      tz._names       = names;
      tz.add          = addZone;
      tz.link         = addLink;
      tz.load         = loadData;
      tz.zone         = getZone;
      tz.zoneExists   = zoneExists; // deprecated in 0.1.0
      tz.guess        = guess;
      tz.names        = getNames;
      tz.Zone         = Zone;
      tz.unpack       = unpack;
      tz.unpackBase60 = unpackBase60;
      tz.needsOffset  = needsOffset;
      tz.moveInvalidForward   = true;
      tz.moveAmbiguousForward = false;
  
      /************************************
          Interface with Moment.js
      ************************************/
  
      var fn = moment.fn;
  
      moment.tz = tz;
  
      moment.defaultZone = null;
  
      moment.updateOffset = function (mom, keepTime) {
          var zone = moment.defaultZone,
              offset;
  
          if (mom._z === undefined) {
              if (zone && needsOffset(mom) && !mom._isUTC) {
                  mom._d = moment.utc(mom._a)._d;
                  mom.utc().add(zone.parse(mom), 'minutes');
              }
              mom._z = zone;
          }
          if (mom._z) {
              offset = mom._z.offset(mom);
              if (Math.abs(offset) < 16) {
                  offset = offset / 60;
              }
              if (mom.utcOffset !== undefined) {
                  mom.utcOffset(-offset, keepTime);
              } else {
                  mom.zone(offset, keepTime);
              }
          }
      };
  
      fn.tz = function (name) {
          if (name) {
              this._z = getZone(name);
              if (this._z) {
                  moment.updateOffset(this);
              } else {
                  logError("Moment Timezone has no data for " + name + ". See http://momentjs.com/timezone/docs/#/data-loading/.");
              }
              return this;
          }
          if (this._z) { return this._z.name; }
      };
  
      function abbrWrap (old) {
          return function () {
              if (this._z) { return this._z.abbr(this); }
              return old.call(this);
          };
      }
  
      function resetZoneWrap (old) {
          return function () {
              this._z = null;
              return old.apply(this, arguments);
          };
      }
  
      fn.zoneName = abbrWrap(fn.zoneName);
      fn.zoneAbbr = abbrWrap(fn.zoneAbbr);
      fn.utc      = resetZoneWrap(fn.utc);
  
      moment.tz.setDefault = function(name) {
          if (major < 2 || (major === 2 && minor < 9)) {
              logError('Moment Timezone setDefault() requires Moment.js >= 2.9.0. You are using Moment.js ' + moment.version + '.');
          }
          moment.defaultZone = name ? getZone(name) : null;
          return moment;
      };
  
      // Cloning a moment should include the _z property.
      var momentProperties = moment.momentProperties;
      if (Object.prototype.toString.call(momentProperties) === '[object Array]') {
          // moment 2.8.1+
          momentProperties.push('_z');
          momentProperties.push('_a');
      } else if (momentProperties) {
          // moment 2.7.0
          momentProperties._z = null;
      }
  
      // INJECT DATA
  
      return moment;
  }));