text: 'use strict';
  
  const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_$";
  const unsafeChars = /[<>\b\f\n\r\t\0\u2028\u2029]/g;
  const reserved = /^(?:do|if|in|for|int|let|new|try|var|byte|case|char|else|enum|goto|long|this|void|with|await|break|catch|class|const|final|float|short|super|throw|while|yield|delete|double|export|import|native|return|switch|throws|typeof|boolean|default|extends|finally|package|private|abstract|continue|debugger|function|volatile|interface|protected|transient|implements|instanceof|synchronized)$/;
  const escaped = {
    "<": "\\u003C",
    ">": "\\u003E",
    "/": "\\u002F",
    "\\": "\\\\",
    "\b": "\\b",
    "\f": "\\f",
    "\n": "\\n",
    "\r": "\\r",
    "	": "\\t",
    "\0": "\\0",
    "\u2028": "\\u2028",
    "\u2029": "\\u2029"
  };
  const objectProtoOwnPropertyNames = Object.getOwnPropertyNames(Object.prototype).sort().join("\0");
  function devalue(value) {
    const counts = new Map();
    let logNum = 0;
    function log(message) {
      if (logNum < 100) {
        console.warn(message);
        logNum += 1;
      }
    }
    function walk(thing) {
      if (typeof thing === "function") {
        log(`Cannot stringify a function ${thing.name}`);
        return;
      }
      if (counts.has(thing)) {
        counts.set(thing, counts.get(thing) + 1);
        return;
      }
      counts.set(thing, 1);
      if (!isPrimitive(thing)) {
        const type = getType(thing);
        switch (type) {
          case "Number":
          case "String":
          case "Boolean":
          case "Date":
          case "RegExp":
            return;
          case "Array":
            thing.forEach(walk);
            break;
          case "Set":
          case "Map":
            Array.from(thing).forEach(walk);
            break;
          default:
            const proto = Object.getPrototypeOf(thing);
            if (proto !== Object.prototype && proto !== null && Object.getOwnPropertyNames(proto).sort().join("\0") !== objectProtoOwnPropertyNames) {
              if (typeof thing.toJSON !== "function") {
                log(`Cannot stringify arbitrary non-POJOs ${thing.constructor.name}`);
              }
            } else if (Object.getOwnPropertySymbols(thing).length > 0) {
              log(`Cannot stringify POJOs with symbolic keys ${Object.getOwnPropertySymbols(thing).map((symbol) => symbol.toString())}`);
            } else {
              Object.keys(thing).forEach((key) => walk(thing[key]));
            }
        }
      }
    }
    walk(value);
    const names = new Map();
    Array.from(counts).filter((entry) => entry[1] > 1).sort((a, b) => b[1] - a[1]).forEach((entry, i) => {
      names.set(entry[0], getName(i));
    });
    function stringify(thing) {
      if (names.has(thing)) {
        return names.get(thing);
      }
      if (isPrimitive(thing)) {
        return stringifyPrimitive(thing);
      }
      const type = getType(thing);
      switch (type) {
        case "Number":
        case "String":
        case "Boolean":
          return `Object(${stringify(thing.valueOf())})`;
        case "RegExp":
          return thing.toString();
        case "Date":
          return `new Date(${thing.getTime()})`;
        case "Array":
          const members = thing.map((v, i) => i in thing ? stringify(v) : "");
          const tail = thing.length === 0 || thing.length - 1 in thing ? "" : ",";
          return `[${members.join(",")}${tail}]`;
        case "Set":
        case "Map":
          return `new ${type}([${Array.from(thing).map(stringify).join(",")}])`;
        default:
          if (thing.toJSON) {
            let json = thing.toJSON();
            if (getType(json) === "String") {
              try {
                json = JSON.parse(json);
              } catch (e) {
              }
            }
            return stringify(json);
          }
          if (Object.getPrototypeOf(thing) === null) {
            if (Object.keys(thing).length === 0) {
              return "Object.create(null)";
            }
            return `Object.create(null,{${Object.keys(thing).map((key) => `${safeKey(key)}:{writable:true,enumerable:true,value:${stringify(thing[key])}}`).join(",")}})`;
          }
          return `{${Object.keys(thing).map((key) => `${safeKey(key)}:${stringify(thing[key])}`).join(",")}}`;
      }
    }
    const str = stringify(value);
    if (names.size) {
      const params = [];
      const statements = [];
      const values = [];
      names.forEach((name, thing) => {
        params.push(name);
        if (isPrimitive(thing)) {
          values.push(stringifyPrimitive(thing));
          return;
        }
        const type = getType(thing);
        switch (type) {
          case "Number":
          case "String":
          case "Boolean":
            values.push(`Object(${stringify(thing.valueOf())})`);
            break;
          case "RegExp":
            values.push(thing.toString());
            break;
          case "Date":
            values.push(`new Date(${thing.getTime()})`);
            break;
          case "Array":
            values.push(`Array(${thing.length})`);
            thing.forEach((v, i) => {
              statements.push(`${name}[${i}]=${stringify(v)}`);
            });
            break;
          case "Set":
            values.push("new Set");
            statements.push(`${name}.${Array.from(thing).map((v) => `add(${stringify(v)})`).join(".")}`);
            break;
          case "Map":
            values.push("new Map");
            statements.push(`${name}.${Array.from(thing).map(([k, v]) => `set(${stringify(k)}, ${stringify(v)})`).join(".")}`);
            break;
          default:
            values.push(Object.getPrototypeOf(thing) === null ? "Object.create(null)" : "{}");
            Object.keys(thing).forEach((key) => {
              statements.push(`${name}${safeProp(key)}=${stringify(thing[key])}`);
            });
        }
      });
      statements.push(`return ${str}`);
      return `(function(${params.join(",")}){${statements.join(";")}}(${values.join(",")}))`;
    } else {
      return str;
    }
  }
  function getName(num) {
    let name = "";
    do {
      name = chars[num % chars.length] + name;
      num = ~~(num / chars.length) - 1;
    } while (num >= 0);
    return reserved.test(name) ? `${name}0` : name;
  }
  function isPrimitive(thing) {
    return Object(thing) !== thing;
  }
  function stringifyPrimitive(thing) {
    if (typeof thing === "string") {
      return stringifyString(thing);
    }
    if (thing === void 0) {
      return "void 0";
    }
    if (thing === 0 && 1 / thing < 0) {
      return "-0";
    }
    const str = String(thing);
    if (typeof thing === "number") {
      return str.replace(/^(-)?0\./, "$1.");
    }
    return str;
  }
  function getType(thing) {
    return Object.prototype.toString.call(thing).slice(8, -1);
  }
  function escapeUnsafeChar(c) {
    return escaped[c] || c;
  }
  function escapeUnsafeChars(str) {
    return str.replace(unsafeChars, escapeUnsafeChar);
  }
  function safeKey(key) {
    return /^[_$a-zA-Z][_$a-zA-Z0-9]*$/.test(key) ? key : escapeUnsafeChars(JSON.stringify(key));
  }
  function safeProp(key) {
    return /^[_$a-zA-Z][_$a-zA-Z0-9]*$/.test(key) ? `.${key}` : `[${escapeUnsafeChars(JSON.stringify(key))}]`;
  }
  function stringifyString(str) {
    let result = '"';
    for (let i = 0; i < str.length; i += 1) {
      const char = str.charAt(i);
      const code = char.charCodeAt(0);
      if (char === '"') {
        result += '\\"';
      } else if (char in escaped) {
        result += escaped[char];
      } else if (code >= 55296 && code <= 57343) {
        const next = str.charCodeAt(i + 1);
        if (code <= 56319 && (next >= 56320 && next <= 57343)) {
          result += char + str[++i];
        } else {
          result += `\\u${code.toString(16).toUpperCase()}`;
        }
      } else {
        result += char;
      }
    }
    result += '"';
    return result;
  }
  
  module.exports = devalue;
  