@sentry/node 11.0.0-beta.0 → 11.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,7 +6,7 @@ const core = require('@sentry/core');
6
6
  const debug = require('../../utils/debug.js');
7
7
 
8
8
  const { isPromise } = util.types;
9
- const base64WorkerScript = "LyohIEBzZW50cnkvbm9kZSAxMS4wLjAtYmV0YS4wICg1NGJiYWU5KSB8IGh0dHBzOi8vZ2l0aHViLmNvbS9nZXRzZW50cnkvc2VudHJ5LWphdmFzY3JpcHQgKi8KaW1wb3J0e1Nlc3Npb24gYXMgdH1mcm9tIm5vZGU6aW5zcGVjdG9yIjtpbXBvcnR7d29ya2VyRGF0YSBhcyBlLHBhcmVudFBvcnQgYXMgbn1mcm9tIm5vZGU6d29ya2VyX3RocmVhZHMiO2ltcG9ydHtwb3NpeCBhcyByLHNlcCBhcyBvfWZyb20ibm9kZTpwYXRoIjtpbXBvcnQqYXMgcyBmcm9tIm5vZGU6aHR0cCI7aW1wb3J0KmFzIGkgZnJvbSJub2RlOmh0dHBzIjtpbXBvcnR7UmVhZGFibGUgYXMgY31mcm9tIm5vZGU6c3RyZWFtIjtpbXBvcnR7Y3JlYXRlR3ppcCBhcyB1fWZyb20ibm9kZTp6bGliIjtpbXBvcnQqYXMgYSBmcm9tIm5vZGU6bmV0IjtpbXBvcnQqYXMgZiBmcm9tIm5vZGU6dGxzIjtjb25zdCBoPSJ1bmRlZmluZWQiPT10eXBlb2YgX19TRU5UUllfREVCVUdfX3x8X19TRU5UUllfREVCVUdfXyxwPWdsb2JhbFRoaXMsbD0iMTEuMC4wLWJldGEuMCI7ZnVuY3Rpb24gZCgpe3JldHVybiBnKHApLHB9ZnVuY3Rpb24gZyh0KXtjb25zdCBlPXQuX19TRU5UUllfXz10Ll9fU0VOVFJZX198fHt9O3JldHVybiBlLnZlcnNpb249ZS52ZXJzaW9ufHxsLGVbbF09ZVtsXXx8e319ZnVuY3Rpb24gbSh0LGUsbj1wKXtjb25zdCByPW4uX19TRU5UUllfXz1uLl9fU0VOVFJZX198fHt9LG89cltsXT1yW2xdfHx7fTtyZXR1cm4gb1t0XXx8KG9bdF09ZSgpKX1jb25zdCB5PXt9O2Z1bmN0aW9uIGIodCl7aWYoISgiY29uc29sZSJpbiBwKSlyZXR1cm4gdCgpO2NvbnN0IGU9cC5jb25zb2xlLG49e30scj1PYmplY3Qua2V5cyh5KTtyLmZvckVhY2godD0+e2NvbnN0IHI9eVt0XTtuW3RdPWVbdF0sZVt0XT1yfSk7dHJ5e3JldHVybiB0KCl9ZmluYWxseXtyLmZvckVhY2godD0+e2VbdF09blt0XX0pfX1mdW5jdGlvbiB2KCl7cmV0dXJuIFMoKS5lbmFibGVkfWZ1bmN0aW9uIHcodCwuLi5lKXtoJiZ2KCkmJmIoKCk9PntwLmNvbnNvbGVbdF0oYFNlbnRyeSBMb2dnZXIgWyR7dH1dOmAsLi4uZSl9KX1mdW5jdGlvbiBTKCl7cmV0dXJuIGg/bSgibG9nZ2VyU2V0dGluZ3MiLCgpPT4oe2VuYWJsZWQ6ITF9KSk6e2VuYWJsZWQ6ITF9fWNvbnN0IF89e2VuYWJsZTpmdW5jdGlvbigpe1MoKS5lbmFibGVkPSEwfSxkaXNhYmxlOmZ1bmN0aW9uKCl7UygpLmVuYWJsZWQ9ITF9LGlzRW5hYmxlZDp2LGxvZzpmdW5jdGlvbiguLi50KXt3KCJsb2ciLC4uLnQpfSx3YXJuOmZ1bmN0aW9uKC4uLnQpe3coIndhcm4iLC4uLnQpfSxlcnJvcjpmdW5jdGlvbiguLi50KXt3KCJlcnJvciIsLi4udCl9fSwkPS9jYXB0dXJlTWVzc2FnZXxjYXB0dXJlRXhjZXB0aW9uLztmdW5jdGlvbiBFKHQpe3JldHVybiB0W3QubGVuZ3RoLTFdfHx7fX1jb25zdCB4PSI8YW5vbnltb3VzPiI7Y29uc3QgTj1PYmplY3QucHJvdG90eXBlLnRvU3RyaW5nO2Z1bmN0aW9uIEModCl7cmV0dXJuIGZ1bmN0aW9uKHQsZSl7cmV0dXJuIE4uY2FsbCh0KT09PWBbb2JqZWN0ICR7ZX1dYH0odCwiT2JqZWN0Iil9ZnVuY3Rpb24gaih0KXtyZXR1cm4gQm9vbGVhbih0Py50aGVuJiYiZnVuY3Rpb24iPT10eXBlb2YgdC50aGVuKX1mdW5jdGlvbiBPKHQsZSl7dHJ5e3JldHVybiB0IGluc3RhbmNlb2YgZX1jYXRjaHtyZXR1cm4hMX19ZnVuY3Rpb24gUCh0KXtpZihmdW5jdGlvbih0KXtzd2l0Y2goTi5jYWxsKHQpKXtjYXNlIltvYmplY3QgRXJyb3JdIjpjYXNlIltvYmplY3QgRXhjZXB0aW9uXSI6Y2FzZSJbb2JqZWN0IERPTUV4Y2VwdGlvbl0iOmNhc2UiW29iamVjdCBXZWJBc3NlbWJseS5FeGNlcHRpb25dIjpyZXR1cm4hMDtkZWZhdWx0OnJldHVybiBPKHQsRXJyb3IpfX0odCkpcmV0dXJue21lc3NhZ2U6dC5tZXNzYWdlLG5hbWU6dC5uYW1lLHN0YWNrOnQuc3RhY2ssLi4uQSh0KX07aWYoZT10LCJ1bmRlZmluZWQiIT10eXBlb2YgRXZlbnQmJk8oZSxFdmVudCkpe2NvbnN0e3R5cGU6ZSx0YXJnZXQ6bixjdXJyZW50VGFyZ2V0OnIsZGV0YWlsOm99PXQ7cmV0dXJue3R5cGU6ZSx0YXJnZXQ6bixjdXJyZW50VGFyZ2V0OnIsLi4ubz97ZGV0YWlsOm99Ont9LC4uLkEodCl9fXZhciBlO3JldHVybiB0fWZ1bmN0aW9uIEEodCl7cmV0dXJuIm9iamVjdCI9PXR5cGVvZihlPXQpJiZudWxsIT09ZT9PYmplY3QuZnJvbUVudHJpZXMoT2JqZWN0LmVudHJpZXModCkpOnt9O3ZhciBlfWxldCBUO2Z1bmN0aW9uIGsodCl7aWYodm9pZCAwIT09VClyZXR1cm4gVD9UKHQpOnQoKTtjb25zdCBlPVN5bWJvbC5mb3IoIl9fU0VOVFJZX1NBRkVfUkFORE9NX0lEX1dSQVBQRVJfXyIpLG49cDtyZXR1cm4gZSBpbiBuJiYiZnVuY3Rpb24iPT10eXBlb2YgbltlXT8oVD1uW2VdLFQodCkpOihUPW51bGwsdCgpKX1mdW5jdGlvbiBSKCl7cmV0dXJuIGsoKCk9Pk1hdGgucmFuZG9tKCkpfWZ1bmN0aW9uIEkoKXtyZXR1cm4gaygoKT0+RGF0ZS5ub3coKSl9Y29uc3QgRD1TeW1ib2wuZm9yKCJzZW50cnkuc2tpcE5vcm1hbGl6YXRpb24iKSxVPVN5bWJvbC5mb3IoInNlbnRyeS5vdmVycmlkZU5vcm1hbGl6YXRpb25EZXB0aCIpO2Z1bmN0aW9uIEIodCxlPTEwMCxuPTEvMCl7dHJ5e3JldHVybiBMKCIiLHQsZSxuKX1jYXRjaCh0KXtyZXR1cm57RVJST1I6YCoqbm9uLXNlcmlhbGl6YWJsZSoqICgke3R9KWB9fX1mdW5jdGlvbiBMKHQsZSxuPTEvMCxyPTEvMCxvPWZ1bmN0aW9uKCl7Y29uc3QgdD1uZXcgV2Vha1NldDtmdW5jdGlvbiBlKGUpe3JldHVybiEhdC5oYXMoZSl8fCh0LmFkZChlKSwhMSl9ZnVuY3Rpb24gbihlKXt0LmRlbGV0ZShlKX1yZXR1cm5bZSxuXX0oKSl7Y29uc3RbcyxpXT1vO2lmKG51bGw9PWV8fFsiYm9vbGVhbiIsInN0cmluZyJdLmluY2x1ZGVzKHR5cGVvZiBlKXx8Im51bWJlciI9PXR5cGVvZiBlJiZOdW1iZXIuaXNGaW5pdGUoZSkpcmV0dXJuIGU7Y29uc3QgYz1mdW5jdGlvbih0LGUpe3RyeXtpZigidW5kZWZpbmVkIiE9dHlwZW9mIGdsb2JhbCYmZT09PWdsb2JhbClyZXR1cm4iW0dsb2JhbF0iO2lmKCJudW1iZXIiPT10eXBlb2YgZSYmIU51bWJlci5pc0Zpbml0ZShlKSlyZXR1cm5gWyR7ZX1dYDtpZigiZnVuY3Rpb24iPT10eXBlb2YgZSlyZXR1cm5gW0Z1bmN0aW9uOiAke2Z1bmN0aW9uKHQpe3RyeXtyZXR1cm4gdCYmImZ1bmN0aW9uIj09dHlwZW9mIHQmJnQubmFtZXx8eH1jYXRjaHtyZXR1cm4geH19KGUpfV1gO2lmKCJzeW1ib2wiPT10eXBlb2YgZSlyZXR1cm5gWyR7U3RyaW5nKGUpfV1gO2lmKCJiaWdpbnQiPT10eXBlb2YgZSlyZXR1cm5gW0JpZ0ludDogJHtTdHJpbmcoZSl9XWA7Y29uc3QgdD1mdW5jdGlvbih0KXtjb25zdCBlPU9iamVjdC5nZXRQcm90b3R5cGVPZih0KTtyZXR1cm4gZT8uY29uc3RydWN0b3I/ZS5jb25zdHJ1Y3Rvci5uYW1lOiJudWxsIHByb3RvdHlwZSJ9KGUpO3JldHVybmBbb2JqZWN0ICR7dH1dYH1jYXRjaCh0KXtyZXR1cm5gKipub24tc2VyaWFsaXphYmxlKiogKCR7dH0pYH19KDAsZSk7aWYoIWMuc3RhcnRzV2l0aCgiW29iamVjdCAiKSlyZXR1cm4gYztpZihmdW5jdGlvbih0KXtyZXR1cm4gQm9vbGVhbih0W0RdKX0oZSkpcmV0dXJuIGU7Y29uc3QgdT1mdW5jdGlvbih0KXtjb25zdCBlPXRbVV07cmV0dXJuIm51bWJlciI9PXR5cGVvZiBlP2U6dm9pZCAwfShlKSxhPXZvaWQgMCE9PXU/dTpuO2lmKDA9PT1hKXJldHVybiBjLnJlcGxhY2UoIm9iamVjdCAiLCIiKTtpZihzKGUpKXJldHVybiJbQ2lyY3VsYXIgfl0iO2NvbnN0IGY9ZTtpZihmJiYiZnVuY3Rpb24iPT10eXBlb2YgZi50b0pTT04pdHJ5e3JldHVybiBMKCIiLGYudG9KU09OKCksYS0xLHIsbyl9Y2F0Y2h7fWNvbnN0IGg9QXJyYXkuaXNBcnJheShlKT9bXTp7fTtsZXQgcD0wO2NvbnN0IGw9UChlKTtmb3IoY29uc3QgdCBpbiBsKXtpZighT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKGwsdCkpY29udGludWU7aWYocD49cil7aFt0XT0iW01heFByb3BlcnRpZXMgfl0iO2JyZWFrfWNvbnN0IGU9bFt0XTtoW3RdPUwodCxlLGEtMSxyLG8pLHArK31yZXR1cm4gaShlKSxofWZ1bmN0aW9uIE0odCxlKXtjb25zdCBuPWUucmVwbGFjZSgvXFwvZywiLyIpLnJlcGxhY2UoL1t8XFx7fSgpW1xdXiQrKj8uXS9nLCJcXCQmIik7bGV0IHI9dDt0cnl7cj1kZWNvZGVVUkkodCl9Y2F0Y2h7fXJldHVybiByLnJlcGxhY2UoL1xcL2csIi8iKS5yZXBsYWNlKC93ZWJwYWNrOlwvPy9nLCIiKS5yZXBsYWNlKG5ldyBSZWdFeHAoYChmaWxlOi8vKT8vKiR7bn0vKmAsImlnIiksImFwcDovLy8iKX1mdW5jdGlvbiB6KHQsZT0wKXtyZXR1cm4ic3RyaW5nIiE9dHlwZW9mIHR8fDA9PT1lfHx0Lmxlbmd0aDw9ZT90OmAke3Quc2xpY2UoMCxlKX0uLi5gfWxldCBKO2Z1bmN0aW9uIFcodD1mdW5jdGlvbigpe2NvbnN0IHQ9cDtyZXR1cm4gdC5jcnlwdG98fHQubXNDcnlwdG99KCkpe3RyeXtpZih0Py5yYW5kb21VVUlEKXJldHVybiBrKCgpPT50LnJhbmRvbVVVSUQoKSkucmVwbGFjZSgvLS9nLCIiKX1jYXRjaHt9cmV0dXJuIEp8fChKPSIxMDAwMDAwMDEwMDA0MDAwODAwMDEwMDAwMDAwMDAwMCIpLEoucmVwbGFjZSgvWzAxOF0vZyx0PT4odF4oMTYqUigpJjE1KT4+dC80KS50b1N0cmluZygxNikpfWZ1bmN0aW9uIEYoKXtyZXR1cm4gSSgpLzFlM31sZXQgRztmdW5jdGlvbiBZKCl7cmV0dXJuKEc/PyhHPWZ1bmN0aW9uKCl7Y29uc3R7cGVyZm9ybWFuY2U6dH09cDtpZighdD8ubm93fHwhdC50aW1lT3JpZ2luKXJldHVybiBGO2NvbnN0IGU9dC50aW1lT3JpZ2luO3JldHVybigpPT4oZStrKCgpPT50Lm5vdygpKSkvMWUzfSgpKSkoKX1mdW5jdGlvbiBIKHQpe2NvbnN0IGU9WSgpLG49e3NpZDpXKCksaW5pdDohMCx0aW1lc3RhbXA6ZSxzdGFydGVkOmUsZHVyYXRpb246MCxzdGF0dXM6Im9rIixlcnJvcnM6MCxpZ25vcmVEdXJhdGlvbjohMSx0b0pTT046KCk9PmZ1bmN0aW9uKHQpe3JldHVybntzaWQ6YCR7dC5zaWR9YCxpbml0OnQuaW5pdCxzdGFydGVkOm5ldyBEYXRlKDFlMyp0LnN0YXJ0ZWQpLnRvSVNPU3RyaW5nKCksdGltZXN0YW1wOm5ldyBEYXRlKDFlMyp0LnRpbWVzdGFtcCkudG9JU09TdHJpbmcoKSxzdGF0dXM6dC5zdGF0dXMsZXJyb3JzOnQuZXJyb3JzLGRpZDoibnVtYmVyIj09dHlwZW9mIHQuZGlkfHwic3RyaW5nIj09dHlwZW9mIHQuZGlkP2Ake3QuZGlkfWA6dm9pZCAwLGR1cmF0aW9uOnQuZHVyYXRpb24sYWJub3JtYWxfbWVjaGFuaXNtOnQuYWJub3JtYWxfbWVjaGFuaXNtLGF0dHJzOntyZWxlYXNlOnQucmVsZWFzZSxlbnZpcm9ubWVudDp0LmVudmlyb25tZW50LGlwX2FkZHJlc3M6dC5pcEFkZHJlc3MsdXNlcl9hZ2VudDp0LnVzZXJBZ2VudH19fShuKX07cmV0dXJuIHQmJloobix0KSxufWZ1bmN0aW9uIFoodCxlPXt9KXtpZihlLnVzZXImJighdC5pcEFkZHJlc3MmJmUudXNlci5pcF9hZGRyZXNzJiYodC5pcEFkZHJlc3M9ZS51c2VyLmlwX2FkZHJlc3MpLHQuZGlkfHxlLmRpZHx8KHQuZGlkPWUudXNlci5pZHx8ZS51c2VyLmVtYWlsfHxlLnVzZXIudXNlcm5hbWUpKSx0LnRpbWVzdGFtcD1lLnRpbWVzdGFtcHx8WSgpLGUuYWJub3JtYWxfbWVjaGFuaXNtJiYodC5hYm5vcm1hbF9tZWNoYW5pc209ZS5hYm5vcm1hbF9tZWNoYW5pc20pLGUuaWdub3JlRHVyYXRpb24mJih0Lmlnbm9yZUR1cmF0aW9uPWUuaWdub3JlRHVyYXRpb24pLGUuc2lkJiYodC5zaWQ9MzI9PT1lLnNpZC5sZW5ndGg/ZS5zaWQ6VygpKSx2b2lkIDAhPT1lLmluaXQmJih0LmluaXQ9ZS5pbml0KSwhdC5kaWQmJmUuZGlkJiYodC5kaWQ9YCR7ZS5kaWR9YCksIm51bWJlciI9PXR5cGVvZiBlLnN0YXJ0ZWQmJih0LnN0YXJ0ZWQ9ZS5zdGFydGVkKSx0Lmlnbm9yZUR1cmF0aW9uKXQuZHVyYXRpb249dm9pZCAwO2Vsc2UgaWYoIm51bWJlciI9PXR5cGVvZiBlLmR1cmF0aW9uKXQuZHVyYXRpb249ZS5kdXJhdGlvbjtlbHNle2NvbnN0IGU9dC50aW1lc3RhbXAtdC5zdGFydGVkO3QuZHVyYXRpb249ZT49MD9lOjB9ZS5yZWxlYXNlJiYodC5yZWxlYXNlPWUucmVsZWFzZSksZS5lbnZpcm9ubWVudCYmKHQuZW52aXJvbm1lbnQ9ZS5lbnZpcm9ubWVudCksIXQuaXBBZGRyZXNzJiZlLmlwQWRkcmVzcyYmKHQuaXBBZGRyZXNzPWUuaXBBZGRyZXNzKSwhdC51c2VyQWdlbnQmJmUudXNlckFnZW50JiYodC51c2VyQWdlbnQ9ZS51c2VyQWdlbnQpLCJudW1iZXIiPT10eXBlb2YgZS5lcnJvcnMmJih0LmVycm9ycz1lLmVycm9ycyksZS5zdGF0dXMmJih0LnN0YXR1cz1lLnN0YXR1cyl9ZnVuY3Rpb24gcSh0LGUsbj0yKXtpZighZXx8Im9iamVjdCIhPXR5cGVvZiBlfHxuPD0wKXJldHVybiBlO2lmKHQmJjA9PT1PYmplY3Qua2V5cyhlKS5sZW5ndGgpcmV0dXJuIHQ7Y29uc3Qgcj17Li4udH07Zm9yKGNvbnN0IHQgaW4gZSlPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwoZSx0KSYmKHJbdF09cShyW3RdLGVbdF0sbi0xKSk7cmV0dXJuIHJ9Y2xhc3MgS3tjb25zdHJ1Y3Rvcigpe3RoaXMudD0hMSx0aGlzLm89W10sdGhpcy5pPVtdLHRoaXMudT1bXSx0aGlzLmg9W10sdGhpcy5wPXt9LHRoaXMubD17fSx0aGlzLm09e30sdGhpcy52PXt9LHRoaXMuUz17fSx0aGlzLl89e30sZnVuY3Rpb24odCxlLG4pe3RyeXtPYmplY3QuZGVmaW5lUHJvcGVydHkodCxlLHt2YWx1ZTpuLHdyaXRhYmxlOiEwLGNvbmZpZ3VyYWJsZTohMH0pfWNhdGNoe2gmJl8ubG9nKGBGYWlsZWQgdG8gYWRkIG5vbi1lbnVtZXJhYmxlIHByb3BlcnR5ICIke1N0cmluZyhlKX0iIHRvIG9iamVjdGAsdCl9fSh0aGlzLCJyZWZzIix7fSksdGhpcy5OPXt0cmFjZUlkOlcoKSxzYW1wbGVSYW5kOlIoKX19Y2xvbmUoKXtjb25zdCB0PW5ldyBLO3JldHVybiB0LnU9Wy4uLnRoaXMudV0sdC5sPXsuLi50aGlzLmx9LHQubT17Li4udGhpcy5tfSx0LnY9ey4uLnRoaXMudn0sdC5TPXsuLi50aGlzLlN9LHRoaXMuUy5mbGFncyYmKHQuUy5mbGFncz17dmFsdWVzOlsuLi50aGlzLlMuZmxhZ3MudmFsdWVzXX0pLHQucD10aGlzLnAsdC5DPXRoaXMuQyx0Lmo9dGhpcy5qLHQuTz10aGlzLk8sdC5QPXRoaXMuUCx0Lmk9Wy4uLnRoaXMuaV0sdC5oPVsuLi50aGlzLmhdLHQuXz17Li4udGhpcy5ffSx0Lk49ey4uLnRoaXMuTn0sdC5BPXRoaXMuQSx0LlQ9dGhpcy5ULHQuaz10aGlzLmssdC5yZWZzPXsuLi50aGlzLnJlZnN9LHR9c2V0Q2xpZW50KHQpe3RoaXMuQT10fXNldExhc3RFdmVudElkKHQpe3RoaXMuVD10fWdldENsaWVudCgpe3JldHVybiB0aGlzLkF9bGFzdEV2ZW50SWQoKXtyZXR1cm4gdGhpcy5UfWFkZFNjb3BlTGlzdGVuZXIodCl7dGhpcy5vLnB1c2godCl9YWRkRXZlbnRQcm9jZXNzb3IodCl7cmV0dXJuIHRoaXMuaS5wdXNoKHQpLHRoaXN9c2V0VXNlcih0KXtyZXR1cm4gdGhpcy5wPXR8fHtlbWFpbDp2b2lkIDAsaWQ6dm9pZCAwLGlwX2FkZHJlc3M6dm9pZCAwLHVzZXJuYW1lOnZvaWQgMH0sdGhpcy5qJiZaKHRoaXMuaix7dXNlcjp0fSksdGhpcy5SKCksdGhpc31nZXRVc2VyKCl7cmV0dXJuIHRoaXMucH1zZXRDb252ZXJzYXRpb25JZCh0KXtyZXR1cm4gdGhpcy5rPXR8fHZvaWQgMCx0aGlzLlIoKSx0aGlzfXNldFRhZ3ModCl7cmV0dXJuIHRoaXMubD17Li4udGhpcy5sLC4uLnR9LHRoaXMuUigpLHRoaXN9c2V0VGFnKHQsZSl7cmV0dXJuIHRoaXMuc2V0VGFncyh7W3RdOmV9KX1zZXRBdHRyaWJ1dGVzKHQpe3JldHVybiB0aGlzLm09ey4uLnRoaXMubSwuLi50fSx0aGlzLlIoKSx0aGlzfXNldEF0dHJpYnV0ZSh0LGUpe3JldHVybiB0aGlzLnNldEF0dHJpYnV0ZXMoe1t0XTplfSl9cmVtb3ZlQXR0cmlidXRlKHQpe3JldHVybiB0IGluIHRoaXMubSYmKGRlbGV0ZSB0aGlzLm1bdF0sdGhpcy5SKCkpLHRoaXN9c2V0RXh0cmFzKHQpe3JldHVybiB0aGlzLnY9ey4uLnRoaXMudiwuLi50fSx0aGlzLlIoKSx0aGlzfXNldEV4dHJhKHQsZSl7cmV0dXJuIHRoaXMudj17Li4udGhpcy52LFt0XTplfSx0aGlzLlIoKSx0aGlzfXNldEZpbmdlcnByaW50KHQpe3JldHVybiB0aGlzLlA9dCx0aGlzLlIoKSx0aGlzfXNldExldmVsKHQpe3JldHVybiB0aGlzLkM9dCx0aGlzLlIoKSx0aGlzfXNldFRyYW5zYWN0aW9uTmFtZSh0KXtyZXR1cm4gdGhpcy5PPXQsdGhpcy5SKCksdGhpc31zZXRDb250ZXh0KHQsZSl7cmV0dXJuIG51bGw9PT1lP2RlbGV0ZSB0aGlzLlNbdF06dGhpcy5TW3RdPWUsdGhpcy5SKCksdGhpc31zZXRTZXNzaW9uKHQpe3JldHVybiB0P3RoaXMuaj10OmRlbGV0ZSB0aGlzLmosdGhpcy5SKCksdGhpc31nZXRTZXNzaW9uKCl7cmV0dXJuIHRoaXMuan11cGRhdGUodCl7aWYoIXQpcmV0dXJuIHRoaXM7Y29uc3QgZT0iZnVuY3Rpb24iPT10eXBlb2YgdD90KHRoaXMpOnQsbj1lIGluc3RhbmNlb2YgSz9lLmdldFNjb3BlRGF0YSgpOkMoZSk/dDp2b2lkIDAse3RhZ3M6cixhdHRyaWJ1dGVzOm8sZXh0cmE6cyx1c2VyOmksY29udGV4dHM6YyxsZXZlbDp1LGZpbmdlcnByaW50OmE9W10scHJvcGFnYXRpb25Db250ZXh0OmYsY29udmVyc2F0aW9uSWQ6aH09bnx8e307cmV0dXJuIHRoaXMubD17Li4udGhpcy5sLC4uLnJ9LHRoaXMubT17Li4udGhpcy5tLC4uLm99LHRoaXMudj17Li4udGhpcy52LC4uLnN9LHRoaXMuUz17Li4udGhpcy5TLC4uLmN9LGkmJk9iamVjdC5rZXlzKGkpLmxlbmd0aCYmKHRoaXMucD1pKSx1JiYodGhpcy5DPXUpLGEubGVuZ3RoJiYodGhpcy5QPWEpLGYmJih0aGlzLk49ZiksaCYmKHRoaXMuaz1oKSx0aGlzfWFkZEJyZWFkY3J1bWIodCxlKXtjb25zdCBuPSJudW1iZXIiPT10eXBlb2YgZT9lOjEwMDtpZihuPD0wKXJldHVybiB0aGlzO2NvbnN0IHI9e3RpbWVzdGFtcDpGKCksLi4udCxtZXNzYWdlOnQubWVzc2FnZT96KHQubWVzc2FnZSwyMDQ4KTp0Lm1lc3NhZ2V9O3JldHVybiB0aGlzLnUucHVzaChyKSx0aGlzLnUubGVuZ3RoPm4mJih0aGlzLnU9dGhpcy51LnNsaWNlKC1uKSx0aGlzLkE/LnJlY29yZERyb3BwZWRFdmVudCgiYnVmZmVyX292ZXJmbG93IiwibG9nX2l0ZW0iKSksdGhpcy5SKCksdGhpc31nZXRMYXN0QnJlYWRjcnVtYigpe3JldHVybiB0aGlzLnVbdGhpcy51Lmxlbmd0aC0xXX1jbGVhckJyZWFkY3J1bWJzKCl7cmV0dXJuIHRoaXMudT1bXSx0aGlzLlIoKSx0aGlzfWFkZEF0dGFjaG1lbnQodCl7cmV0dXJuIHRoaXMuaC5wdXNoKHQpLHRoaXN9Y2xlYXJBdHRhY2htZW50cygpe3JldHVybiB0aGlzLmg9W10sdGhpc31nZXRTY29wZURhdGEoKXtyZXR1cm57YnJlYWRjcnVtYnM6dGhpcy51LGF0dGFjaG1lbnRzOnRoaXMuaCxjb250ZXh0czp0aGlzLlMsdGFnczp0aGlzLmwsYXR0cmlidXRlczp0aGlzLm0sZXh0cmE6dGhpcy52LHVzZXI6dGhpcy5wLGxldmVsOnRoaXMuQyxmaW5nZXJwcmludDp0aGlzLlB8fFtdLGV2ZW50UHJvY2Vzc29yczp0aGlzLmkscHJvcGFnYXRpb25Db250ZXh0OnRoaXMuTixzZGtQcm9jZXNzaW5nTWV0YWRhdGE6dGhpcy5fLHRyYW5zYWN0aW9uTmFtZTp0aGlzLk8sY29udmVyc2F0aW9uSWQ6dGhpcy5rfX1zZXRTREtQcm9jZXNzaW5nTWV0YWRhdGEodCl7cmV0dXJuIHRoaXMuXz1xKHRoaXMuXyx0LDIpLHRoaXN9c2V0UHJvcGFnYXRpb25Db250ZXh0KHQpe3JldHVybiB0aGlzLk49dCx0aGlzfWdldFByb3BhZ2F0aW9uQ29udGV4dCgpe3JldHVybiB0aGlzLk59Y2FwdHVyZUV4Y2VwdGlvbih0LGUpe2NvbnN0IG49ZT8uZXZlbnRfaWR8fFcoKTtpZighdGhpcy5BKXJldHVybiBoJiZfLndhcm4oIk5vIGNsaWVudCBjb25maWd1cmVkIG9uIHNjb3BlIC0gd2lsbCBub3QgY2FwdHVyZSBleGNlcHRpb24hIiksbjtjb25zdCByPW5ldyBFcnJvcigiU2VudHJ5IHN5bnRoZXRpY0V4Y2VwdGlvbiIpO3JldHVybiB0aGlzLkEuY2FwdHVyZUV4Y2VwdGlvbih0LHtvcmlnaW5hbEV4Y2VwdGlvbjp0LHN5bnRoZXRpY0V4Y2VwdGlvbjpyLC4uLmUsZXZlbnRfaWQ6bn0sdGhpcyksbn1jYXB0dXJlTWVzc2FnZSh0LGUsbil7Y29uc3Qgcj1uPy5ldmVudF9pZHx8VygpO2lmKCF0aGlzLkEpcmV0dXJuIGgmJl8ud2FybigiTm8gY2xpZW50IGNvbmZpZ3VyZWQgb24gc2NvcGUgLSB3aWxsIG5vdCBjYXB0dXJlIG1lc3NhZ2UhIikscjtjb25zdCBvPW4/LnN5bnRoZXRpY0V4Y2VwdGlvbj8/bmV3IEVycm9yKHQpO3JldHVybiB0aGlzLkEuY2FwdHVyZU1lc3NhZ2UodCxlLHtvcmlnaW5hbEV4Y2VwdGlvbjp0LHN5bnRoZXRpY0V4Y2VwdGlvbjpvLC4uLm4sZXZlbnRfaWQ6cn0sdGhpcykscn1jYXB0dXJlRXZlbnQodCxlKXtjb25zdCBuPXQuZXZlbnRfaWR8fGU/LmV2ZW50X2lkfHxXKCk7cmV0dXJuIHRoaXMuQT8odGhpcy5BLmNhcHR1cmVFdmVudCh0LHsuLi5lLGV2ZW50X2lkOm59LHRoaXMpLG4pOihoJiZfLndhcm4oIk5vIGNsaWVudCBjb25maWd1cmVkIG9uIHNjb3BlIC0gd2lsbCBub3QgY2FwdHVyZSBldmVudCEiKSxuKX1SKCl7dGhpcy50fHwodGhpcy50PSEwLHRoaXMuby5mb3JFYWNoKHQ9Pnt0KHRoaXMpfSksdGhpcy50PSExKX19Y29uc3QgVj0iX19TRU5UUllfU1VQUFJFU1NfVFJBQ0lOR19fIixRPXQ9PnQgaW5zdGFuY2VvZiBQcm9taXNlJiYhdFtYXSxYPVN5bWJvbCgiY2hhaW5lZCBQcm9taXNlTGlrZSIpLHR0PSh0LGUpPT57aWYoIWUpcmV0dXJuIHQ7bGV0IG49ITE7Zm9yKGNvbnN0IHIgaW4gdCl7aWYociBpbiBlKWNvbnRpbnVlO249ITA7Y29uc3Qgbz10W3JdOyJmdW5jdGlvbiI9PXR5cGVvZiBvP09iamVjdC5kZWZpbmVQcm9wZXJ0eShlLHIse3ZhbHVlOiguLi5lKT0+by5hcHBseSh0LGUpLGVudW1lcmFibGU6ITAsY29uZmlndXJhYmxlOiEwLHdyaXRhYmxlOiEwfSk6ZVtyXT1vfXJldHVybiBuJiZPYmplY3QuYXNzaWduKGUse1tYXTohMH0pLGV9O2NsYXNzIGV0e2NvbnN0cnVjdG9yKHQsZSl7bGV0IG4scjtuPXR8fG5ldyBLLHI9ZXx8bmV3IEssdGhpcy5JPVt7c2NvcGU6bn1dLHRoaXMuRD1yfXdpdGhTY29wZSh0KXtjb25zdCBlPXRoaXMuVSgpO2xldCBuO3RyeXtuPXQoZSl9Y2F0Y2godCl7dGhyb3cgdGhpcy5CKCksdH1yZXR1cm4gaihuKT8oKHQsZSxuKT0+e2NvbnN0IHI9dC50aGVuKHQ9PihlKHQpLHQpLHQ9Pnt0aHJvdyBuKHQpLHR9KTtyZXR1cm4gUShyKSYmUSh0KT9yOnR0KHQscil9KShuLCgpPT50aGlzLkIoKSwoKT0+dGhpcy5CKCkpOih0aGlzLkIoKSxuKX1nZXRDbGllbnQoKXtyZXR1cm4gdGhpcy5nZXRTdGFja1RvcCgpLmNsaWVudH1nZXRTY29wZSgpe3JldHVybiB0aGlzLmdldFN0YWNrVG9wKCkuc2NvcGV9Z2V0SXNvbGF0aW9uU2NvcGUoKXtyZXR1cm4gdGhpcy5EfWdldFN0YWNrVG9wKCl7cmV0dXJuIHRoaXMuSVt0aGlzLkkubGVuZ3RoLTFdfVUoKXtjb25zdCB0PXRoaXMuZ2V0U2NvcGUoKS5jbG9uZSgpO3JldHVybiB0aGlzLkkucHVzaCh7Y2xpZW50OnRoaXMuZ2V0Q2xpZW50KCksc2NvcGU6dH0pLHR9Qigpe3JldHVybiEodGhpcy5JLmxlbmd0aDw9MSkmJiEhdGhpcy5JLnBvcCgpfX1mdW5jdGlvbiBudCgpe2NvbnN0IHQ9ZyhkKCkpO3JldHVybiB0LnN0YWNrPXQuc3RhY2t8fG5ldyBldChtKCJkZWZhdWx0Q3VycmVudFNjb3BlIiwoKT0+bmV3IEspLG0oImRlZmF1bHRJc29sYXRpb25TY29wZSIsKCk9Pm5ldyBLKSl9ZnVuY3Rpb24gcnQodCl7cmV0dXJuIG50KCkud2l0aFNjb3BlKHQpfWZ1bmN0aW9uIG90KHQsZSl7Y29uc3Qgbj1udCgpO3JldHVybiBuLndpdGhTY29wZSgoKT0+KG4uZ2V0U3RhY2tUb3AoKS5zY29wZT10LGUodCkpKX1mdW5jdGlvbiBzdCh0KXtyZXR1cm4gbnQoKS53aXRoU2NvcGUoKCk9PnQobnQoKS5nZXRJc29sYXRpb25TY29wZSgpKSl9ZnVuY3Rpb24gaXQodCl7cmV0dXJuIHJ0KGU9PntlLnNldFNES1Byb2Nlc3NpbmdNZXRhZGF0YSh7W1ZdOiEwfSk7Y29uc3Qgbj10KCk7cmV0dXJuIGUuc2V0U0RLUHJvY2Vzc2luZ01ldGFkYXRhKHtbVl06dm9pZCAwfSksbn0pfWZ1bmN0aW9uIGN0KHQpe2NvbnN0IGU9Zyh0KTtyZXR1cm4gZS5hY3M/ZS5hY3M6e3N1cHByZXNzVHJhY2luZzppdCx3aXRoSXNvbGF0aW9uU2NvcGU6c3Qsd2l0aFNjb3BlOnJ0LHdpdGhTZXRTY29wZTpvdCx3aXRoU2V0SXNvbGF0aW9uU2NvcGU6KHQsZSk9PnN0KGUpLGdldEN1cnJlbnRTY29wZTooKT0+bnQoKS5nZXRTY29wZSgpLGdldElzb2xhdGlvblNjb3BlOigpPT5udCgpLmdldElzb2xhdGlvblNjb3BlKCl9fWZ1bmN0aW9uIHV0KHQsZT0hMSl7Y29uc3R7aG9zdDpuLHBhdGg6cixwYXNzOm8scG9ydDpzLHByb2plY3RJZDppLHByb3RvY29sOmMscHVibGljS2V5OnV9PXQ7cmV0dXJuYCR7Y306Ly8ke3V9JHtlJiZvP2A6JHtvfWA6IiJ9QCR7bn0ke3M/YDoke3N9YDoiIn0vJHtyP2Ake3J9L2A6cn0ke2l9YH1mdW5jdGlvbiBhdCh0LGUpe2NvbnN0e2ZpbmdlcnByaW50Om4sYnJlYWRjcnVtYnM6cixzZGtQcm9jZXNzaW5nTWV0YWRhdGE6b309ZTshZnVuY3Rpb24odCxlKXtjb25zdHtleHRyYTpuLHRhZ3M6cix1c2VyOm8sY29udGV4dHM6cyxsZXZlbDppLHRyYW5zYWN0aW9uTmFtZTpjfT1lO09iamVjdC5rZXlzKG4pLmxlbmd0aCYmKHQuZXh0cmE9ey4uLm4sLi4udC5leHRyYX0pO09iamVjdC5rZXlzKHIpLmxlbmd0aCYmKHQudGFncz17Li4uciwuLi50LnRhZ3N9KTtPYmplY3Qua2V5cyhvKS5sZW5ndGgmJih0LnVzZXI9ey4uLm8sLi4udC51c2VyfSk7T2JqZWN0LmtleXMocykubGVuZ3RoJiYodC5jb250ZXh0cz17Li4ucywuLi50LmNvbnRleHRzfSk7aSYmKHQubGV2ZWw9aSk7YyYmInRyYW5zYWN0aW9uIiE9PXQudHlwZSYmKHQudHJhbnNhY3Rpb249Yyl9KHQsZSksZnVuY3Rpb24odCxlKXt0LmZpbmdlcnByaW50PXQuZmluZ2VycHJpbnQ/QXJyYXkuaXNBcnJheSh0LmZpbmdlcnByaW50KT90LmZpbmdlcnByaW50Olt0LmZpbmdlcnByaW50XTpbXSxlJiYodC5maW5nZXJwcmludD10LmZpbmdlcnByaW50LmNvbmNhdChlKSk7dC5maW5nZXJwcmludC5sZW5ndGh8fGRlbGV0ZSB0LmZpbmdlcnByaW50fSh0LG4pLGZ1bmN0aW9uKHQsZSl7Y29uc3Qgbj1bLi4udC5icmVhZGNydW1ic3x8W10sLi4uZV07dC5icmVhZGNydW1icz1uLmxlbmd0aD9uOnZvaWQgMH0odCxyKSxmdW5jdGlvbih0LGUpe3Quc2RrUHJvY2Vzc2luZ01ldGFkYXRhPXsuLi50LnNka1Byb2Nlc3NpbmdNZXRhZGF0YSwuLi5lfX0odCxvKX1mdW5jdGlvbiBmdCh0LGU9W10pe3JldHVyblt0LGVdfWZ1bmN0aW9uIGh0KHQsZSl7Y29uc3Qgbj10WzFdO2Zvcihjb25zdCB0IG9mIG4pe2lmKGUodCx0WzBdLnR5cGUpKXJldHVybiEwfXJldHVybiExfWZ1bmN0aW9uIHB0KHQpe2NvbnN0IGU9ZyhwKTtyZXR1cm4gZS5lbmNvZGVQb2x5ZmlsbD9lLmVuY29kZVBvbHlmaWxsKHQpOihuZXcgVGV4dEVuY29kZXIpLmVuY29kZSh0KX1mdW5jdGlvbiBsdCh0KXtjb25zdFtlLG5dPXQ7bGV0IHI9SlNPTi5zdHJpbmdpZnkoZSk7ZnVuY3Rpb24gbyh0KXsic3RyaW5nIj09dHlwZW9mIHI/cj0ic3RyaW5nIj09dHlwZW9mIHQ/cit0OltwdChyKSx0XTpyLnB1c2goInN0cmluZyI9PXR5cGVvZiB0P3B0KHQpOnQpfWZvcihjb25zdCB0IG9mIG4pe2NvbnN0W2Usbl09dDtpZihvKGBcbiR7SlNPTi5zdHJpbmdpZnkoZSl9XG5gKSwic3RyaW5nIj09dHlwZW9mIG58fG4gaW5zdGFuY2VvZiBVaW50OEFycmF5KW8obik7ZWxzZXtsZXQgdDt0cnl7dD1KU09OLnN0cmluZ2lmeShuKX1jYXRjaHt0PUpTT04uc3RyaW5naWZ5KEIobikpfW8odCl9fXJldHVybiJzdHJpbmciPT10eXBlb2Ygcj9yOmZ1bmN0aW9uKHQpe2NvbnN0IGU9dC5yZWR1Y2UoKHQsZSk9PnQrZS5sZW5ndGgsMCksbj1uZXcgVWludDhBcnJheShlKTtsZXQgcj0wO2Zvcihjb25zdCBlIG9mIHQpbi5zZXQoZSxyKSxyKz1lLmxlbmd0aDtyZXR1cm4gbn0ocil9Y29uc3QgZHQ9e3Nlc3Npb25zOiJzZXNzaW9uIixldmVudDoiZXJyb3IiLGNsaWVudF9yZXBvcnQ6ImludGVybmFsIix1c2VyX3JlcG9ydDoiZGVmYXVsdCIscHJvZmlsZV9jaHVuazoicHJvZmlsZSIscmVwbGF5X2V2ZW50OiJyZXBsYXkiLHJlcGxheV9yZWNvcmRpbmc6InJlcGxheSIsY2hlY2tfaW46Im1vbml0b3IiLHJhd19zZWN1cml0eToic2VjdXJpdHkiLGxvZzoibG9nX2l0ZW0iLHRyYWNlX21ldHJpYzoibWV0cmljIn07ZnVuY3Rpb24gZ3QodCl7cmV0dXJuIGZ1bmN0aW9uKHQpe3JldHVybiB0IGluIGR0fSh0KT9kdFt0XTp0fWZ1bmN0aW9uIG10KHQpe2lmKCF0Py5zZGspcmV0dXJuO2NvbnN0e25hbWU6ZSx2ZXJzaW9uOm59PXQuc2RrO3JldHVybntuYW1lOmUsdmVyc2lvbjpufX1mdW5jdGlvbiB5dCh0KXtjb25zdCBlPWN0KGQoKSk7cmV0dXJuIGUuc3VwcHJlc3NUcmFjaW5nP2Uuc3VwcHJlc3NUcmFjaW5nKHQpOmZ1bmN0aW9uKC4uLnQpe2NvbnN0IGU9Y3QoZCgpKTtpZigyPT09dC5sZW5ndGgpe2NvbnN0W24scl09dDtyZXR1cm4gbj9lLndpdGhTZXRTY29wZShuLHIpOmUud2l0aFNjb3BlKHIpfXJldHVybiBlLndpdGhTY29wZSh0WzBdKX0oZT0+KGUuc2V0U0RLUHJvY2Vzc2luZ01ldGFkYXRhKHtbVl06ITB9KSx0KCkpKX1mdW5jdGlvbiBidCh0LGUsbixyKXtjb25zdCBvPW10KG4pLHM9dC50eXBlJiYicmVwbGF5X2V2ZW50IiE9PXQudHlwZT90LnR5cGU6ImV2ZW50IjshZnVuY3Rpb24odCxlKXtpZighZSlyZXR1cm4gdDtjb25zdCBuPXQuc2RrfHx7fTt0LnNkaz17Li4ubixuYW1lOm4ubmFtZXx8ZS5uYW1lLHZlcnNpb246bi52ZXJzaW9ufHxlLnZlcnNpb24saW50ZWdyYXRpb25zOlsuLi50LnNkaz8uaW50ZWdyYXRpb25zfHxbXSwuLi5lLmludGVncmF0aW9uc3x8W11dLHBhY2thZ2VzOlsuLi50LnNkaz8ucGFja2FnZXN8fFtdLC4uLmUucGFja2FnZXN8fFtdXSxzZXR0aW5nczp0LnNkaz8uc2V0dGluZ3N8fGUuc2V0dGluZ3M/ey4uLnQuc2RrPy5zZXR0aW5ncywuLi5lLnNldHRpbmdzfTp2b2lkIDB9fSh0LG4/LnNkayk7Y29uc3QgaT1mdW5jdGlvbih0LGUsbixyKXtjb25zdCBvPXQuc2RrUHJvY2Vzc2luZ01ldGFkYXRhPy5keW5hbWljU2FtcGxpbmdDb250ZXh0O3JldHVybntldmVudF9pZDp0LmV2ZW50X2lkLHNlbnRfYXQ6bmV3IERhdGUoSSgpKS50b0lTT1N0cmluZygpLC4uLmUmJntzZGs6ZX0sLi4uISFuJiZyJiZ7ZHNuOnV0KHIpfSwuLi5vJiZ7dHJhY2U6b319fSh0LG8scixlKTtkZWxldGUgdC5zZGtQcm9jZXNzaW5nTWV0YWRhdGE7cmV0dXJuIGZ0KGksW1t7dHlwZTpzfSx0XV0pfWNsYXNzIHZ0e2NvbnN0cnVjdG9yKHQpe3RoaXMuTD0wLHRoaXMuTT1bXSx0aGlzLkoodCl9dGhlbih0LGUpe3JldHVybiBuZXcgdnQoKG4scik9Pnt0aGlzLk0ucHVzaChbITEsZT0+e2lmKHQpdHJ5e24odChlKSl9Y2F0Y2godCl7cih0KX1lbHNlIG4oZSl9LHQ9PntpZihlKXRyeXtuKGUodCkpfWNhdGNoKHQpe3IodCl9ZWxzZSByKHQpfV0pLHRoaXMuVygpfSl9Y2F0Y2godCl7cmV0dXJuIHRoaXMudGhlbih0PT50LHQpfWZpbmFsbHkodCl7cmV0dXJuIG5ldyB2dCgoZSxuKT0+e2xldCByLG87cmV0dXJuIHRoaXMudGhlbihlPT57bz0hMSxyPWUsdCYmdCgpfSxlPT57bz0hMCxyPWUsdCYmdCgpfSkudGhlbigoKT0+e28/bihyKTplKHIpfSl9KX1XKCl7aWYoMD09PXRoaXMuTClyZXR1cm47Y29uc3QgdD10aGlzLk0uc2xpY2UoKTt0aGlzLk09W10sdC5mb3JFYWNoKHQ9Pnt0WzBdfHwoMT09PXRoaXMuTCYmdFsxXSh0aGlzLkYpLDI9PT10aGlzLkwmJnRbMl0odGhpcy5GKSx0WzBdPSEwKX0pfUoodCl7Y29uc3QgZT0odCxlKT0+ezA9PT10aGlzLkwmJihqKGUpP2UudGhlbihuLHIpOih0aGlzLkw9dCx0aGlzLkY9ZSx0aGlzLlcoKSkpfSxuPXQ9PntlKDEsdCl9LHI9dD0+e2UoMix0KX07dHJ5e3QobixyKX1jYXRjaCh0KXtyKHQpfX19Y29uc3Qgd3Q9U3ltYm9sLmZvcigiU2VudHJ5QnVmZmVyRnVsbEVycm9yIik7ZnVuY3Rpb24gU3QodD0xMDApe2NvbnN0IGU9bmV3IFNldDtmdW5jdGlvbiBuKHQpe2UuZGVsZXRlKHQpfXJldHVybntnZXQgJCgpe3JldHVybiBBcnJheS5mcm9tKGUpfSxhZGQ6ZnVuY3Rpb24ocil7aWYoIShlLnNpemU8dCkpcmV0dXJuIG89d3QsbmV3IHZ0KCh0LGUpPT57ZShvKX0pO3ZhciBvO2NvbnN0IHM9cigpO3JldHVybiBlLmFkZChzKSxzLnRoZW4oKCk9Pm4ocyksKCk9Pm4ocykpLHN9LGRyYWluOmZ1bmN0aW9uKHQpe2lmKCFlLnNpemUpcmV0dXJuIG49ITAsbmV3IHZ0KHQ9Pnt0KG4pfSk7dmFyIG47Y29uc3Qgcj1Qcm9taXNlLmFsbFNldHRsZWQoQXJyYXkuZnJvbShlKSkudGhlbigoKT0+ITApO2lmKCF0KXJldHVybiByO2NvbnN0IG89W3IsbmV3IFByb21pc2UoZT0+e3JldHVybiJvYmplY3QiPT10eXBlb2Yobj1zZXRUaW1lb3V0KCgpPT5lKCExKSx0KSkmJiJmdW5jdGlvbiI9PXR5cGVvZiBuLnVucmVmJiZuLnVucmVmKCksbjt2YXIgbn0pXTtyZXR1cm4gUHJvbWlzZS5yYWNlKG8pfX19ZnVuY3Rpb24gX3QodCx7c3RhdHVzQ29kZTplLGhlYWRlcnM6bn0scj1JKCkpe2NvbnN0IG89ey4uLnR9LHM9bj8uWyJ4LXNlbnRyeS1yYXRlLWxpbWl0cyJdLGk9bj8uWyJyZXRyeS1hZnRlciJdO2lmKHMpZm9yKGNvbnN0IHQgb2Ygcy50cmltKCkuc3BsaXQoIiwiKSl7Y29uc3RbZSxuLCwsc109dC5zcGxpdCgiOiIsNSksaT1wYXJzZUludChlLDEwKSxjPTFlMyooaXNOYU4oaSk/NjA6aSk7aWYobilmb3IoY29uc3QgdCBvZiBuLnNwbGl0KCI7IikpIm1ldHJpY19idWNrZXQiPT09dCYmcyYmIXMuc3BsaXQoIjsiKS5pbmNsdWRlcygiY3VzdG9tIil8fChvW3RdPXIrYyk7ZWxzZSBvLmFsbD1yK2N9ZWxzZSBpP28uYWxsPXIrZnVuY3Rpb24odCxlPUkoKSl7Y29uc3Qgbj1wYXJzZUludChgJHt0fWAsMTApO2lmKCFpc05hTihuKSlyZXR1cm4gMWUzKm47Y29uc3Qgcj1EYXRlLnBhcnNlKGAke3R9YCk7cmV0dXJuIGlzTmFOKHIpPzZlNDpyLWV9KGkscik6NDI5PT09ZSYmKG8uYWxsPXIrNmU0KTtyZXR1cm4gb31mdW5jdGlvbiAkdCh0LGUsbj1TdCh0LmJ1ZmZlclNpemV8fDY0KSl7bGV0IHI9e307cmV0dXJue3NlbmQ6ZnVuY3Rpb24odCl7Y29uc3Qgbz1bXTtpZihodCh0LCh0LGUpPT57Y29uc3Qgbj1ndChlKTsoZnVuY3Rpb24odCxlLG49SSgpKXtyZXR1cm4gZnVuY3Rpb24odCxlKXtyZXR1cm4gdFtlXXx8dC5hbGx8fDB9KHQsZSk+bn0pKHIsbil8fG8ucHVzaCh0KX0pLDA9PT1vLmxlbmd0aClyZXR1cm4gUHJvbWlzZS5yZXNvbHZlKHt9KTtjb25zdCBzPWZ0KHRbMF0sbyksaT10PT57IWZ1bmN0aW9uKHQsZSl7cmV0dXJuIGh0KHQsKHQsbik9PmUuaW5jbHVkZXMobikpfShzLFsiY2xpZW50X3JlcG9ydCJdKT9odChzLCh0LGUpPT57fSk6aCYmXy53YXJuKGBEcm9wcGluZyBjbGllbnQgcmVwb3J0LiBXaWxsIG5vdCBzZW5kIG91dGNvbWVzIChyZWFzb246ICR7dH0pLmApfTtyZXR1cm4gbi5hZGQoKCk9PmUoe2JvZHk6bHQocyl9KS50aGVuKHQ9PjQxMz09PXQuc3RhdHVzQ29kZT8oaCYmXy5lcnJvcigiU2VudHJ5IHJlc3BvbmRlZCB3aXRoIHN0YXR1cyBjb2RlIDQxMy4gRW52ZWxvcGUgd2FzIGRpc2NhcmRlZCBkdWUgdG8gZXhjZWVkaW5nIHNpemUgbGltaXRzLiIpLGkoInNlbmRfZXJyb3IiKSx0KTooaCYmdm9pZCAwIT09dC5zdGF0dXNDb2RlJiYodC5zdGF0dXNDb2RlPDIwMHx8dC5zdGF0dXNDb2RlPj0zMDApJiZfLndhcm4oYFNlbnRyeSByZXNwb25kZWQgd2l0aCBzdGF0dXMgY29kZSAke3Quc3RhdHVzQ29kZX0gdG8gc2VudCBldmVudC5gKSxyPV90KHIsdCksdCksdD0+e3Rocm93IGkoIm5ldHdvcmtfZXJyb3IiKSxoJiZfLmVycm9yKCJFbmNvdW50ZXJlZCBlcnJvciBydW5uaW5nIHRyYW5zcG9ydCByZXF1ZXN0OiIsdCksdH0pKS50aGVuKHQ9PnQsdD0+e2lmKHQ9PT13dClyZXR1cm4gaCYmXy5lcnJvcigiU2tpcHBlZCBzZW5kaW5nIGV2ZW50IGJlY2F1c2UgYnVmZmVyIGlzIGZ1bGwuIiksaSgicXVldWVfb3ZlcmZsb3ciKSxQcm9taXNlLnJlc29sdmUoe30pO3Rocm93IHR9KX0sZmx1c2g6dD0+bi5kcmFpbih0KX19Y29uc3QgRXQ9L14oXFMrOlxcfFwvPykoW1xzXFNdKj8pKCg/OlwuezEsMn18W14vXFxdKz98KShcLlteLi9cXF0qfCkpKD86Wy9cXF0qKSQvO2Z1bmN0aW9uIHh0KHQpe2NvbnN0IGU9ZnVuY3Rpb24odCl7Y29uc3QgZT10Lmxlbmd0aD4xMDI0P2A8dHJ1bmNhdGVkPiR7dC5zbGljZSgtMTAyNCl9YDp0LG49RXQuZXhlYyhlKTtyZXR1cm4gbj9uLnNsaWNlKDEpOltdfSh0KSxuPWVbMF18fCIiO2xldCByPWVbMV07cmV0dXJuIG58fHI/KHImJihyPXIuc2xpY2UoMCxyLmxlbmd0aC0xKSksbityKToiLiJ9ZnVuY3Rpb24gTnQodCxlPSExKXtyZXR1cm4hKGV8fHQmJiF0LnN0YXJ0c1dpdGgoIi8iKSYmIXQubWF0Y2goL15bQS1aXTovKSYmIXQuc3RhcnRzV2l0aCgiLiIpJiYhdC5tYXRjaCgvXlthLXpBLVpdKFthLXpBLVowLTkuXC0rXSkqOlwvXC8vKSkmJnZvaWQgMCE9PXQmJiF0LmluY2x1ZGVzKCJub2RlX21vZHVsZXMvIil9dmFyIEN0O2NvbnN0IGp0PVN5bWJvbCgiQWdlbnRCYXNlSW50ZXJuYWxTdGF0ZSIpO2NsYXNzIE90IGV4dGVuZHMoQ3Q9cy5BZ2VudCxDdCl7Y29uc3RydWN0b3IodCl7c3VwZXIodCksdGhpc1tqdF09e319aXNTZWN1cmVFbmRwb2ludCh0KXtpZih0KXtpZigiYm9vbGVhbiI9PXR5cGVvZiB0LnNlY3VyZUVuZHBvaW50KXJldHVybiB0LnNlY3VyZUVuZHBvaW50O2lmKCJzdHJpbmciPT10eXBlb2YgdC5wcm90b2NvbClyZXR1cm4iaHR0cHM6Ij09PXQucHJvdG9jb2x9Y29uc3R7c3RhY2s6ZX09bmV3IEVycm9yO3JldHVybiJzdHJpbmciPT10eXBlb2YgZSYmZS5zcGxpdCgiXG4iKS5zb21lKHQ9Pi0xIT09dC5pbmRleE9mKCIoaHR0cHMuanM6Iil8fC0xIT09dC5pbmRleE9mKCJub2RlOmh0dHBzOiIpKX1jcmVhdGVTb2NrZXQodCxlLG4pe2NvbnN0IHI9ey4uLmUsc2VjdXJlRW5kcG9pbnQ6dGhpcy5pc1NlY3VyZUVuZHBvaW50KGUpfTtQcm9taXNlLnJlc29sdmUoKS50aGVuKCgpPT50aGlzLmNvbm5lY3QodCxyKSkudGhlbihvPT57aWYobyBpbnN0YW5jZW9mIHMuQWdlbnQpcmV0dXJuIG8uYWRkUmVxdWVzdCh0LHIpO3RoaXNbanRdLmN1cnJlbnRTb2NrZXQ9byxzdXBlci5jcmVhdGVTb2NrZXQodCxlLG4pfSxuKX1jcmVhdGVDb25uZWN0aW9uKCl7Y29uc3QgdD10aGlzW2p0XS5jdXJyZW50U29ja2V0O2lmKHRoaXNbanRdLmN1cnJlbnRTb2NrZXQ9dm9pZCAwLCF0KXRocm93IG5ldyBFcnJvcigiTm8gc29ja2V0IHdhcyByZXR1cm5lZCBpbiB0aGUgYGNvbm5lY3QoKWAgZnVuY3Rpb24iKTtyZXR1cm4gdH1nZXQgZGVmYXVsdFBvcnQoKXtyZXR1cm4gdGhpc1tqdF0uZGVmYXVsdFBvcnQ/PygiaHR0cHM6Ij09PXRoaXMucHJvdG9jb2w/NDQzOjgwKX1zZXQgZGVmYXVsdFBvcnQodCl7dGhpc1tqdF0mJih0aGlzW2p0XS5kZWZhdWx0UG9ydD10KX1nZXQgcHJvdG9jb2woKXtyZXR1cm4gdGhpc1tqdF0ucHJvdG9jb2w/Pyh0aGlzLmlzU2VjdXJlRW5kcG9pbnQoKT8iaHR0cHM6IjoiaHR0cDoiKX1zZXQgcHJvdG9jb2wodCl7dGhpc1tqdF0mJih0aGlzW2p0XS5wcm90b2NvbD10KX19ZnVuY3Rpb24gUHQoLi4udCl7Xy5sb2coIltodHRwcy1wcm94eS1hZ2VudDpwYXJzZS1wcm94eS1yZXNwb25zZV0iLC4uLnQpfWZ1bmN0aW9uIEF0KHQpe3JldHVybiBuZXcgUHJvbWlzZSgoZSxuKT0+e2xldCByPTA7Y29uc3Qgbz1bXTtmdW5jdGlvbiBzKCl7Y29uc3QgYz10LnJlYWQoKTtjP2Z1bmN0aW9uKGMpe28ucHVzaChjKSxyKz1jLmxlbmd0aDtjb25zdCB1PUJ1ZmZlci5jb25jYXQobyxyKSxhPXUuaW5kZXhPZigiXHJcblxyXG4iKTtpZigtMT09PWEpcmV0dXJuIFB0KCJoYXZlIG5vdCByZWNlaXZlZCBlbmQgb2YgSFRUUCBoZWFkZXJzIHlldC4uLiIpLHZvaWQgcygpO2NvbnN0IGY9dS5zdWJhcnJheSgwLGEpLnRvU3RyaW5nKCJhc2NpaSIpLnNwbGl0KCJcclxuIiksaD1mLnNoaWZ0KCk7aWYoIWgpcmV0dXJuIHQuZGVzdHJveSgpLG4obmV3IEVycm9yKCJObyBoZWFkZXIgcmVjZWl2ZWQgZnJvbSBwcm94eSBDT05ORUNUIHJlc3BvbnNlIikpO2NvbnN0IHA9aC5zcGxpdCgiICIpLGw9KyhwWzFdfHwwKSxkPXAuc2xpY2UoMikuam9pbigiICIpLGc9e307Zm9yKGNvbnN0IGUgb2YgZil7aWYoIWUpY29udGludWU7Y29uc3Qgcj1lLmluZGV4T2YoIjoiKTtpZigtMT09PXIpcmV0dXJuIHQuZGVzdHJveSgpLG4obmV3IEVycm9yKGBJbnZhbGlkIGhlYWRlciBmcm9tIHByb3h5IENPTk5FQ1QgcmVzcG9uc2U6ICIke2V9ImApKTtjb25zdCBvPWUuc2xpY2UoMCxyKS50b0xvd2VyQ2FzZSgpLHM9ZS5zbGljZShyKzEpLnRyaW1TdGFydCgpLGk9Z1tvXTsic3RyaW5nIj09dHlwZW9mIGk/Z1tvXT1baSxzXTpBcnJheS5pc0FycmF5KGkpP2kucHVzaChzKTpnW29dPXN9UHQoImdvdCBwcm94eSBzZXJ2ZXIgcmVzcG9uc2U6ICVvICVvIixoLGcpLGkoKSxlKHtjb25uZWN0OntzdGF0dXNDb2RlOmwsc3RhdHVzVGV4dDpkLGhlYWRlcnM6Z30sYnVmZmVyZWQ6dX0pfShjKTp0Lm9uY2UoInJlYWRhYmxlIixzKX1mdW5jdGlvbiBpKCl7dC5yZW1vdmVMaXN0ZW5lcigiZW5kIixjKSx0LnJlbW92ZUxpc3RlbmVyKCJlcnJvciIsdSksdC5yZW1vdmVMaXN0ZW5lcigicmVhZGFibGUiLHMpfWZ1bmN0aW9uIGMoKXtpKCksUHQoIm9uZW5kIiksbihuZXcgRXJyb3IoIlByb3h5IGNvbm5lY3Rpb24gZW5kZWQgYmVmb3JlIHJlY2VpdmluZyBDT05ORUNUIHJlc3BvbnNlIikpfWZ1bmN0aW9uIHUodCl7aSgpLFB0KCJvbmVycm9yICVvIix0KSxuKHQpfXQub24oImVycm9yIix1KSx0Lm9uKCJlbmQiLGMpLHMoKX0pfWZ1bmN0aW9uIFR0KC4uLnQpe18ubG9nKCJbaHR0cHMtcHJveHktYWdlbnRdIiwuLi50KX1jbGFzcyBrdCBleHRlbmRzIE90e2NvbnN0cnVjdG9yKHQsZSl7c3VwZXIoZSksdGhpcy5vcHRpb25zPXt9LHRoaXMucHJveHk9InN0cmluZyI9PXR5cGVvZiB0P25ldyBVUkwodCk6dCx0aGlzLnByb3h5SGVhZGVycz1lPy5oZWFkZXJzPz97fSxUdCgiQ3JlYXRpbmcgbmV3IEh0dHBzUHJveHlBZ2VudCBpbnN0YW5jZTogJW8iLHRoaXMucHJveHkuaHJlZik7Y29uc3Qgbj0odGhpcy5wcm94eS5ob3N0bmFtZXx8dGhpcy5wcm94eS5ob3N0KS5yZXBsYWNlKC9eXFt8XF0kL2csIiIpLHI9dGhpcy5wcm94eS5wb3J0P3BhcnNlSW50KHRoaXMucHJveHkucG9ydCwxMCk6Imh0dHBzOiI9PT10aGlzLnByb3h5LnByb3RvY29sPzQ0Mzo4MDt0aGlzLmNvbm5lY3RPcHRzPXtBTFBOUHJvdG9jb2xzOlsiaHR0cC8xLjEiXSwuLi5lP0l0KGUsImhlYWRlcnMiKTpudWxsLGhvc3Q6bixwb3J0OnJ9fWFzeW5jIGNvbm5lY3QodCxlKXtjb25zdHtwcm94eTpufT10aGlzO2lmKCFlLmhvc3QpdGhyb3cgbmV3IFR5cGVFcnJvcignTm8gImhvc3QiIHByb3ZpZGVkJyk7bGV0IHI7aWYoImh0dHBzOiI9PT1uLnByb3RvY29sKXtUdCgiQ3JlYXRpbmcgYHRscy5Tb2NrZXRgOiAlbyIsdGhpcy5jb25uZWN0T3B0cyk7Y29uc3QgdD10aGlzLmNvbm5lY3RPcHRzLnNlcnZlcm5hbWV8fHRoaXMuY29ubmVjdE9wdHMuaG9zdDtyPWYuY29ubmVjdCh7Li4udGhpcy5jb25uZWN0T3B0cyxzZXJ2ZXJuYW1lOnQmJmEuaXNJUCh0KT92b2lkIDA6dH0pfWVsc2UgVHQoIkNyZWF0aW5nIGBuZXQuU29ja2V0YDogJW8iLHRoaXMuY29ubmVjdE9wdHMpLHI9YS5jb25uZWN0KHRoaXMuY29ubmVjdE9wdHMpO2NvbnN0IG89ImZ1bmN0aW9uIj09dHlwZW9mIHRoaXMucHJveHlIZWFkZXJzP3RoaXMucHJveHlIZWFkZXJzKCk6ey4uLnRoaXMucHJveHlIZWFkZXJzfSxzPWEuaXNJUHY2KGUuaG9zdCk/YFske2UuaG9zdH1dYDplLmhvc3Q7bGV0IGk9YENPTk5FQ1QgJHtzfToke2UucG9ydH0gSFRUUC8xLjFcclxuYDtpZihuLnVzZXJuYW1lfHxuLnBhc3N3b3JkKXtjb25zdCB0PWAke2RlY29kZVVSSUNvbXBvbmVudChuLnVzZXJuYW1lKX06JHtkZWNvZGVVUklDb21wb25lbnQobi5wYXNzd29yZCl9YDtvWyJQcm94eS1BdXRob3JpemF0aW9uIl09YEJhc2ljICR7QnVmZmVyLmZyb20odCkudG9TdHJpbmcoImJhc2U2NCIpfWB9by5Ib3N0PWAke3N9OiR7ZS5wb3J0fWAsb1siUHJveHktQ29ubmVjdGlvbiJdfHwob1siUHJveHktQ29ubmVjdGlvbiJdPXRoaXMua2VlcEFsaXZlPyJLZWVwLUFsaXZlIjoiY2xvc2UiKTtmb3IoY29uc3QgdCBvZiBPYmplY3Qua2V5cyhvKSlpKz1gJHt0fTogJHtvW3RdfVxyXG5gO2NvbnN0IGM9QXQocik7ci53cml0ZShgJHtpfVxyXG5gKTtjb25zdHtjb25uZWN0OnUsYnVmZmVyZWQ6aH09YXdhaXQgYztpZih0LmVtaXQoInByb3h5Q29ubmVjdCIsdSksdGhpcy5lbWl0KCJwcm94eUNvbm5lY3QiLHUsdCksMjAwPT09dS5zdGF0dXNDb2RlKXtpZih0Lm9uY2UoInNvY2tldCIsUnQpLGUuc2VjdXJlRW5kcG9pbnQpe1R0KCJVcGdyYWRpbmcgc29ja2V0IGNvbm5lY3Rpb24gdG8gVExTIik7Y29uc3QgdD1lLnNlcnZlcm5hbWV8fGUuaG9zdDtyZXR1cm4gZi5jb25uZWN0KHsuLi5JdChlLCJob3N0IiwicGF0aCIsInBvcnQiKSxzb2NrZXQ6cixzZXJ2ZXJuYW1lOmEuaXNJUCh0KT92b2lkIDA6dH0pfXJldHVybiByfXIuZGVzdHJveSgpO2NvbnN0IHA9bmV3IGEuU29ja2V0KHt3cml0YWJsZTohMX0pO3JldHVybiBwLnJlYWRhYmxlPSEwLHQub25jZSgic29ja2V0Iix0PT57VHQoIlJlcGxheWluZyBwcm94eSBidWZmZXIgZm9yIGZhaWxlZCByZXF1ZXN0IiksdC5wdXNoKGgpLHQucHVzaChudWxsKX0pLHB9fWZ1bmN0aW9uIFJ0KHQpe3QucmVzdW1lKCl9ZnVuY3Rpb24gSXQodCwuLi5lKXtjb25zdCBuPXt9O2xldCByO2ZvcihyIGluIHQpZS5pbmNsdWRlcyhyKXx8KG5bcl09dFtyXSk7cmV0dXJuIG59a3QucHJvdG9jb2xzPVsiaHR0cCIsImh0dHBzIl07ZnVuY3Rpb24gRHQodCl7cmV0dXJuIHQucmVwbGFjZSgvXltBLVpdOi8sIiIpLnJlcGxhY2UoL1xcL2csIi8iKX1jb25zdCBVdD1lO2xldCBCdCxMdD0wLE10PXt9O2Z1bmN0aW9uIHp0KHQpe1V0LmRlYnVnJiZjb25zb2xlLmxvZyhgW0FOUiBXb3JrZXJdICR7dH1gKX12YXIgSnQsV3QsRnQ7Y29uc3QgR3Q9ZnVuY3Rpb24odCl7bGV0IGU7dHJ5e2U9bmV3IFVSTCh0LnVybCl9Y2F0Y2h7cmV0dXJuIGIoKCk9Pntjb25zb2xlLndhcm4oIltAc2VudHJ5L25vZGVdOiBJbnZhbGlkIGRzbiBvciB0dW5uZWwgb3B0aW9uLCB3aWxsIG5vdCBzZW5kIGFueSBldmVudHMuIFRoZSB0dW5uZWwgb3B0aW9uIG11c3QgYmUgYSBmdWxsIFVSTCB3aGVuIHVzZWQuIil9KSwkdCh0LCgpPT5Qcm9taXNlLnJlc29sdmUoe30pKX1jb25zdCBuPSJodHRwczoiPT09ZS5wcm90b2NvbCxyPWZ1bmN0aW9uKHQsZSl7Y29uc3R7bm9fcHJveHk6bn09cHJvY2Vzcy5lbnYscj1uPy5zcGxpdCgiLCIpLnNvbWUoZT0+dC5ob3N0LmVuZHNXaXRoKGUpfHx0Lmhvc3RuYW1lLmVuZHNXaXRoKGUpKTtyZXR1cm4gcj92b2lkIDA6ZX0oZSx0LnByb3h5fHwobj9wcm9jZXNzLmVudi5odHRwc19wcm94eTp2b2lkIDApfHxwcm9jZXNzLmVudi5odHRwX3Byb3h5KSxvPW4/aTpzLGE9dC5rZWVwQWxpdmU/PyEwLGY9cj9uZXcga3Qocik6bmV3IG8uQWdlbnQoe2tlZXBBbGl2ZTphLG1heFNvY2tldHM6MzAsdGltZW91dDoyZTN9KSxoPWZ1bmN0aW9uKHQsZSxuKXtjb25zdHtob3N0bmFtZTpyLHBhdGhuYW1lOm8scG9ydDpzLHByb3RvY29sOmksc2VhcmNoOmF9PW5ldyBVUkwodC51cmwpO3JldHVybiBmdW5jdGlvbihmKXtjb25zdCBoPXA9Pm5ldyBQcm9taXNlKChsLGQpPT57eXQoKCk9PntsZXQgZz1mdW5jdGlvbih0KXtyZXR1cm4gbmV3IGMoe3JlYWQoKXt0aGlzLnB1c2godCksdGhpcy5wdXNoKG51bGwpfX0pfShmLmJvZHkpO2NvbnN0IG09ey4uLnQuaGVhZGVyc307Zi5ib2R5Lmxlbmd0aD4zMjc2OCYmKG1bImNvbnRlbnQtZW5jb2RpbmciXT0iZ3ppcCIsZz1nLnBpcGUodSgpKSk7Y29uc3QgeT1yLnN0YXJ0c1dpdGgoIlsiKSxiPWUucmVxdWVzdCh7bWV0aG9kOiJQT1NUIixhZ2VudDpuLGhlYWRlcnM6bSxob3N0bmFtZTp5P3Iuc2xpY2UoMSwtMSk6cixwYXRoOmAke299JHthfWAscG9ydDpzLHByb3RvY29sOmksY2E6dC5jYUNlcnRzfSx0PT57dC5vbigiZGF0YSIsKCk9Pnt9KSx0Lm9uKCJlbmQiLCgpPT57fSksdC5zZXRFbmNvZGluZygidXRmOCIpO2NvbnN0IGU9dC5oZWFkZXJzWyJyZXRyeS1hZnRlciJdPz9udWxsLG49dC5oZWFkZXJzWyJ4LXNlbnRyeS1yYXRlLWxpbWl0cyJdPz9udWxsO2woe3N0YXR1c0NvZGU6dC5zdGF0dXNDb2RlLGhlYWRlcnM6eyJyZXRyeS1hZnRlciI6ZSwieC1zZW50cnktcmF0ZS1saW1pdHMiOkFycmF5LmlzQXJyYXkobik/blswXXx8bnVsbDpufX0pfSk7Yi5vbigiZXJyb3IiLHQ9PntwJiZiLnJldXNlZFNvY2tldCYmIkVDT05OUkVTRVQiPT09dC5jb2RlP2woaCghMSkpOmQodCl9KSxnLnBpcGUoYil9KX0pO3JldHVybiBoKCEwKX19KHQsdC5odHRwTW9kdWxlPz9vLGYpO3JldHVybiAkdCh0LGgpfSh7dXJsOihKdD1VdC5kc24sV3Q9VXQudHVubmVsLEZ0PVV0LnNka01ldGFkYXRhLnNkayxXdHx8YCR7ZnVuY3Rpb24odCl7cmV0dXJuYCR7ZnVuY3Rpb24odCl7Y29uc3QgZT10LnByb3RvY29sP2Ake3QucHJvdG9jb2x9OmA6IiIsbj10LnBvcnQ/YDoke3QucG9ydH1gOiIiO3JldHVybmAke2V9Ly8ke3QuaG9zdH0ke259JHt0LnBhdGg/YC8ke3QucGF0aH1gOiIifS9hcGkvYH0odCl9JHt0LnByb2plY3RJZH0vZW52ZWxvcGUvYH0oSnQpfT8ke2Z1bmN0aW9uKHQsZSl7Y29uc3Qgbj17c2VudHJ5X3ZlcnNpb246IjcifTtyZXR1cm4gdC5wdWJsaWNLZXkmJihuLnNlbnRyeV9rZXk9dC5wdWJsaWNLZXkpLGUmJihuLnNlbnRyeV9jbGllbnQ9YCR7ZS5uYW1lfS8ke2UudmVyc2lvbn1gKSxuZXcgVVJMU2VhcmNoUGFyYW1zKG4pLnRvU3RyaW5nKCl9KEp0LEZ0KX1gKX0pO2FzeW5jIGZ1bmN0aW9uIFl0KCl7aWYoQnQpe3p0KCJTZW5kaW5nIGFibm9ybWFsIHNlc3Npb24iKSxaKEJ0LHtzdGF0dXM6ImFibm9ybWFsIixhYm5vcm1hbF9tZWNoYW5pc206ImFucl9mb3JlZ3JvdW5kIixyZWxlYXNlOlV0LnJlbGVhc2UsZW52aXJvbm1lbnQ6VXQuZW52aXJvbm1lbnR9KTtjb25zdCB0PWZ1bmN0aW9uKHQsZSxuLHIpe2NvbnN0IG89bXQobik7cmV0dXJuIGZ0KHtzZW50X2F0Om5ldyBEYXRlKEkoKSkudG9JU09TdHJpbmcoKSwuLi5vJiZ7c2RrOm99LC4uLiEhciYmZSYme2Rzbjp1dChlKX19LFsiYWdncmVnYXRlcyJpbiB0P1t7dHlwZToic2Vzc2lvbnMifSx0XTpbe3R5cGU6InNlc3Npb24ifSx0LnRvSlNPTigpXV0pfShCdCxVdC5kc24sVXQuc2RrTWV0YWRhdGEsVXQudHVubmVsKTt6dChKU09OLnN0cmluZ2lmeSh0KSksYXdhaXQgR3Quc2VuZCh0KTt0cnl7bj8ucG9zdE1lc3NhZ2UoInNlc3Npb24tZW5kZWQiKX1jYXRjaHt9fX1mdW5jdGlvbiBIdCh0KXtpZighdClyZXR1cm47Y29uc3QgZT1mdW5jdGlvbih0KXtpZighdC5sZW5ndGgpcmV0dXJuW107Y29uc3QgZT1BcnJheS5mcm9tKHQpO3JldHVybi9zZW50cnlXcmFwcGVkLy50ZXN0KEUoZSkuZnVuY3Rpb258fCIiKSYmZS5wb3AoKSxlLnJldmVyc2UoKSwkLnRlc3QoRShlKS5mdW5jdGlvbnx8IiIpJiYoZS5wb3AoKSwkLnRlc3QoRShlKS5mdW5jdGlvbnx8IiIpJiZlLnBvcCgpKSxlLnNsaWNlKDAsNTApLm1hcCh0PT4oey4uLnQsZmlsZW5hbWU6dC5maWxlbmFtZXx8RShlKS5maWxlbmFtZSxmdW5jdGlvbjp0LmZ1bmN0aW9ufHwiPyJ9KSl9KHQpO2lmKFV0LmFwcFJvb3RQYXRoKWZvcihjb25zdCB0IG9mIGUpdC5maWxlbmFtZSYmKHQuZmlsZW5hbWU9TSh0LmZpbGVuYW1lLFV0LmFwcFJvb3RQYXRoKSk7cmV0dXJuIGV9YXN5bmMgZnVuY3Rpb24gWnQodCxlKXtpZihMdD49VXQubWF4QW5yRXZlbnRzKXJldHVybjtMdCs9MSxhd2FpdCBZdCgpLHp0KCJTZW5kaW5nIGV2ZW50Iik7Y29uc3Qgbj17ZXZlbnRfaWQ6VygpLGNvbnRleHRzOlV0LmNvbnRleHRzLHJlbGVhc2U6VXQucmVsZWFzZSxlbnZpcm9ubWVudDpVdC5lbnZpcm9ubWVudCxkaXN0OlV0LmRpc3QscGxhdGZvcm06Im5vZGUiLGxldmVsOiJlcnJvciIsZXhjZXB0aW9uOnt2YWx1ZXM6W3t0eXBlOiJBcHBsaWNhdGlvbk5vdFJlc3BvbmRpbmciLHZhbHVlOmBBcHBsaWNhdGlvbiBOb3QgUmVzcG9uZGluZyBmb3IgYXQgbGVhc3QgJHtVdC5hbnJUaHJlc2hvbGR9IG1zYCxzdGFja3RyYWNlOntmcmFtZXM6SHQodCl9LG1lY2hhbmlzbTp7dHlwZToiQU5SIn19XX0sdGFnczpVdC5zdGF0aWNUYWdzfTtlJiZmdW5jdGlvbih0LGUpe2lmKGF0KHQsZSksIXQuY29udGV4dHM/LnRyYWNlKXtjb25zdHt0cmFjZUlkOm4scGFyZW50U3BhbklkOnIscHJvcGFnYXRpb25TcGFuSWQ6b309ZS5wcm9wYWdhdGlvbkNvbnRleHQ7dC5jb250ZXh0cz17dHJhY2U6e3RyYWNlX2lkOm4sc3Bhbl9pZDpvfHxXKCkuc3Vic3RyaW5nKDE2KSxwYXJlbnRfc3Bhbl9pZDpyfSwuLi50LmNvbnRleHRzfX19KG4sZSksZnVuY3Rpb24odCl7aWYoMD09PU9iamVjdC5rZXlzKE10KS5sZW5ndGgpcmV0dXJuO2NvbnN0IGU9VXQuYXBwUm9vdFBhdGg/e306TXQ7aWYoVXQuYXBwUm9vdFBhdGgpZm9yKGNvbnN0W3Qsbl1vZiBPYmplY3QuZW50cmllcyhNdCkpZVtNKHQsVXQuYXBwUm9vdFBhdGgpXT1uO2NvbnN0IG49bmV3IE1hcDtmb3IoY29uc3QgciBvZiB0LmV4Y2VwdGlvbj8udmFsdWVzfHxbXSlmb3IoY29uc3QgdCBvZiByLnN0YWNrdHJhY2U/LmZyYW1lc3x8W10pe2NvbnN0IHI9dC5hYnNfcGF0aHx8dC5maWxlbmFtZTtyJiZlW3JdJiZuLnNldChyLGVbcl0pfWlmKG4uc2l6ZT4wKXtjb25zdCBlPVtdO2Zvcihjb25zdFt0LHJdb2Ygbi5lbnRyaWVzKCkpZS5wdXNoKHt0eXBlOiJzb3VyY2VtYXAiLGNvZGVfZmlsZTp0LGRlYnVnX2lkOnJ9KTt0LmRlYnVnX21ldGE9e2ltYWdlczplfX19KG4pO2NvbnN0IHI9YnQobixVdC5kc24sVXQuc2RrTWV0YWRhdGEsVXQudHVubmVsKTt6dChKU09OLnN0cmluZ2lmeShyKSksYXdhaXQgR3Quc2VuZChyKSxhd2FpdCBHdC5mbHVzaCgyZTMpLEx0Pj1VdC5tYXhBbnJFdmVudHMmJnNldFRpbWVvdXQoKCk9Pntwcm9jZXNzLmV4aXQoMCl9LDVlMyl9bGV0IHF0O2lmKHp0KCJTdGFydGVkIiksVXQuY2FwdHVyZVN0YWNrVHJhY2Upe3p0KCJDb25uZWN0aW5nIHRvIGRlYnVnZ2VyIik7Y29uc3QgZT1uZXcgdDtlLmNvbm5lY3RUb01haW5UaHJlYWQoKSx6dCgiQ29ubmVjdGVkIHRvIGRlYnVnZ2VyIik7Y29uc3Qgbj1uZXcgTWFwO2Uub24oIkRlYnVnZ2VyLnNjcmlwdFBhcnNlZCIsdD0+e24uc2V0KHQucGFyYW1zLnNjcmlwdElkLHQucGFyYW1zLnVybCl9KSxlLm9uKCJEZWJ1Z2dlci5wYXVzZWQiLHQ9PntpZigib3RoZXIiPT09dC5wYXJhbXMucmVhc29uKXRyeXt6dCgiRGVidWdnZXIgcGF1c2VkIik7Y29uc3Qgcz1bLi4udC5wYXJhbXMuY2FsbEZyYW1lc10saT1VdC5hcHBSb290UGF0aD9mdW5jdGlvbih0PShwcm9jZXNzLmFyZ3ZbMV0/eHQocHJvY2Vzcy5hcmd2WzFdKTpwcm9jZXNzLmN3ZCgpKSxlPSJcXCI9PT1vKXtjb25zdCBuPWU/RHQodCk6dDtyZXR1cm4gdD0+e2lmKCF0KXJldHVybjtjb25zdCBvPWU/RHQodCk6dDtsZXR7ZGlyOnMsYmFzZTppLGV4dDpjfT1yLnBhcnNlKG8pOyIuanMiIT09YyYmIi5tanMiIT09YyYmIi5janMiIT09Y3x8KGk9aS5zbGljZSgwLC0xKmMubGVuZ3RoKSk7Y29uc3QgdT1kZWNvZGVVUklDb21wb25lbnQoaSk7c3x8KHM9Ii4iKTtjb25zdCBhPXMubGFzdEluZGV4T2YoIi9ub2RlX21vZHVsZXMiKTtpZihhPi0xKXJldHVybmAke3Muc2xpY2UoYSsxNCkucmVwbGFjZSgvXC8vZywiLiIpfToke3V9YDtpZihzLnN0YXJ0c1dpdGgobikpe2NvbnN0IHQ9cy5zbGljZShuLmxlbmd0aCsxKS5yZXBsYWNlKC9cLy9nLCIuIik7cmV0dXJuIHQ/YCR7dH06JHt1fWA6dX1yZXR1cm4gdX19KFV0LmFwcFJvb3RQYXRoKTooKT0+e30sYz1zLm1hcCh0PT5mdW5jdGlvbih0LGUsbil7Y29uc3Qgcj1lP2UucmVwbGFjZSgvXmZpbGU6XC9cLy8sIiIpOnZvaWQgMCxvPXQubG9jYXRpb24uY29sdW1uTnVtYmVyP3QubG9jYXRpb24uY29sdW1uTnVtYmVyKzE6dm9pZCAwLHM9dC5sb2NhdGlvbi5saW5lTnVtYmVyP3QubG9jYXRpb24ubGluZU51bWJlcisxOnZvaWQgMDtyZXR1cm57ZmlsZW5hbWU6cixtb2R1bGU6bihyKSxmdW5jdGlvbjp0LmZ1bmN0aW9uTmFtZXx8Ij8iLGNvbG5vOm8sbGluZW5vOnMsaW5fYXBwOnI/TnQocik6dm9pZCAwfX0odCxuLmdldCh0LmxvY2F0aW9uLnNjcmlwdElkKSxpKSksdT1zZXRUaW1lb3V0KCgpPT57WnQoYykudGhlbihudWxsLCgpPT57enQoIlNlbmRpbmcgQU5SIGV2ZW50IGZhaWxlZC4iKX0pfSw1ZTMpO2UucG9zdCgiUnVudGltZS5ldmFsdWF0ZSIse2V4cHJlc3Npb246Imdsb2JhbC5fX1NFTlRSWV9HRVRfU0NPUEVTX18oKTsiLHNpbGVudDohMCxyZXR1cm5CeVZhbHVlOiEwfSwodCxuKT0+e3QmJnp0KGBFcnJvciBleGVjdXRpbmcgc2NyaXB0OiAnJHt0Lm1lc3NhZ2V9J2ApLGNsZWFyVGltZW91dCh1KTtjb25zdCByPW4/LnJlc3VsdD9uLnJlc3VsdC52YWx1ZTp2b2lkIDA7ZS5wb3N0KCJEZWJ1Z2dlci5yZXN1bWUiKSxlLnBvc3QoIkRlYnVnZ2VyLmRpc2FibGUiKSxadChjLHIpLnRoZW4obnVsbCwoKT0+e3p0KCJTZW5kaW5nIEFOUiBldmVudCBmYWlsZWQuIil9KX0pfWNhdGNoKHQpe3Rocm93IGUucG9zdCgiRGVidWdnZXIucmVzdW1lIiksZS5wb3N0KCJEZWJ1Z2dlci5kaXNhYmxlIiksdH19KSxxdD0oKT0+e3RyeXtlLnBvc3QoIkRlYnVnZ2VyLmVuYWJsZSIsKCk9PntlLnBvc3QoIkRlYnVnZ2VyLnBhdXNlIil9KX1jYXRjaHt9fX1jb25zdHtwb2xsOkt0fT1mdW5jdGlvbih0LGUsbixyKXtjb25zdCBvPXQoKTtsZXQgcz0hMSxpPSEwO3JldHVybiBzZXRJbnRlcnZhbCgoKT0+e2NvbnN0IHQ9by5nZXRUaW1lTXMoKTshMT09PXMmJnQ+ZStuJiYocz0hMCxpJiZyKCkpLHQ8ZStuJiYocz0hMSl9LDIwKSx7cG9sbDooKT0+e28ucmVzZXQoKX0sZW5hYmxlZDp0PT57aT10fX19KGZ1bmN0aW9uKCl7bGV0IHQ9cHJvY2Vzcy5ocnRpbWUoKTtyZXR1cm57Z2V0VGltZU1zOigpPT57Y29uc3RbZSxuXT1wcm9jZXNzLmhydGltZSh0KTtyZXR1cm4gTWF0aC5mbG9vcigxZTMqZStuLzFlNil9LHJlc2V0OigpPT57dD1wcm9jZXNzLmhydGltZSgpfX19LFV0LnBvbGxJbnRlcnZhbCxVdC5hbnJUaHJlc2hvbGQsZnVuY3Rpb24oKXt6dCgiV2F0Y2hkb2cgdGltZW91dCIpLHF0Pyh6dCgiUGF1c2luZyBkZWJ1Z2dlciB0byBjYXB0dXJlIHN0YWNrIHRyYWNlIikscXQoKSk6KHp0KCJDYXB0dXJpbmcgZXZlbnQgd2l0aG91dCBhIHN0YWNrIHRyYWNlIiksWnQoKS50aGVuKG51bGwsKCk9Pnt6dCgiU2VuZGluZyBBTlIgZXZlbnQgZmFpbGVkIG9uIHdhdGNoZG9nIHRpbWVvdXQuIil9KSl9KTtuPy5vbigibWVzc2FnZSIsdD0+e3Quc2Vzc2lvbiYmKEJ0PUgodC5zZXNzaW9uKSksdC5kZWJ1Z0ltYWdlcyYmKE10PXQuZGVidWdJbWFnZXMpLEt0KCl9KTs=";
9
+ const base64WorkerScript = "LyohIEBzZW50cnkvbm9kZSAxMS4wLjAtYmV0YS4xIChjYjIzOWUwKSB8IGh0dHBzOi8vZ2l0aHViLmNvbS9nZXRzZW50cnkvc2VudHJ5LWphdmFzY3JpcHQgKi8KaW1wb3J0e1Nlc3Npb24gYXMgdH1mcm9tIm5vZGU6aW5zcGVjdG9yIjtpbXBvcnR7d29ya2VyRGF0YSBhcyBlLHBhcmVudFBvcnQgYXMgbn1mcm9tIm5vZGU6d29ya2VyX3RocmVhZHMiO2ltcG9ydHtwb3NpeCBhcyByLHNlcCBhcyBvfWZyb20ibm9kZTpwYXRoIjtpbXBvcnQqYXMgcyBmcm9tIm5vZGU6aHR0cCI7aW1wb3J0KmFzIGkgZnJvbSJub2RlOmh0dHBzIjtpbXBvcnR7UmVhZGFibGUgYXMgY31mcm9tIm5vZGU6c3RyZWFtIjtpbXBvcnR7Y3JlYXRlR3ppcCBhcyB1fWZyb20ibm9kZTp6bGliIjtpbXBvcnQqYXMgYSBmcm9tIm5vZGU6bmV0IjtpbXBvcnQqYXMgZiBmcm9tIm5vZGU6dGxzIjtjb25zdCBoPSJ1bmRlZmluZWQiPT10eXBlb2YgX19TRU5UUllfREVCVUdfX3x8X19TRU5UUllfREVCVUdfXyxwPWdsb2JhbFRoaXMsbD0iMTEuMC4wLWJldGEuMSI7ZnVuY3Rpb24gZCgpe3JldHVybiBnKHApLHB9ZnVuY3Rpb24gZyh0KXtjb25zdCBlPXQuX19TRU5UUllfXz10Ll9fU0VOVFJZX198fHt9O3JldHVybiBlLnZlcnNpb249ZS52ZXJzaW9ufHxsLGVbbF09ZVtsXXx8e319ZnVuY3Rpb24gbSh0LGUsbj1wKXtjb25zdCByPW4uX19TRU5UUllfXz1uLl9fU0VOVFJZX198fHt9LG89cltsXT1yW2xdfHx7fTtyZXR1cm4gb1t0XXx8KG9bdF09ZSgpKX1jb25zdCB5PXt9O2Z1bmN0aW9uIGIodCl7aWYoISgiY29uc29sZSJpbiBwKSlyZXR1cm4gdCgpO2NvbnN0IGU9cC5jb25zb2xlLG49e30scj1PYmplY3Qua2V5cyh5KTtyLmZvckVhY2godD0+e2NvbnN0IHI9eVt0XTtuW3RdPWVbdF0sZVt0XT1yfSk7dHJ5e3JldHVybiB0KCl9ZmluYWxseXtyLmZvckVhY2godD0+e2VbdF09blt0XX0pfX1mdW5jdGlvbiB2KCl7cmV0dXJuIFMoKS5lbmFibGVkfWZ1bmN0aW9uIHcodCwuLi5lKXtoJiZ2KCkmJmIoKCk9PntwLmNvbnNvbGVbdF0oYFNlbnRyeSBMb2dnZXIgWyR7dH1dOmAsLi4uZSl9KX1mdW5jdGlvbiBTKCl7cmV0dXJuIGg/bSgibG9nZ2VyU2V0dGluZ3MiLCgpPT4oe2VuYWJsZWQ6ITF9KSk6e2VuYWJsZWQ6ITF9fWNvbnN0IF89e2VuYWJsZTpmdW5jdGlvbigpe1MoKS5lbmFibGVkPSEwfSxkaXNhYmxlOmZ1bmN0aW9uKCl7UygpLmVuYWJsZWQ9ITF9LGlzRW5hYmxlZDp2LGxvZzpmdW5jdGlvbiguLi50KXt3KCJsb2ciLC4uLnQpfSx3YXJuOmZ1bmN0aW9uKC4uLnQpe3coIndhcm4iLC4uLnQpfSxlcnJvcjpmdW5jdGlvbiguLi50KXt3KCJlcnJvciIsLi4udCl9fSwkPS9jYXB0dXJlTWVzc2FnZXxjYXB0dXJlRXhjZXB0aW9uLztmdW5jdGlvbiBFKHQpe3JldHVybiB0W3QubGVuZ3RoLTFdfHx7fX1jb25zdCB4PSI8YW5vbnltb3VzPiI7Y29uc3QgTj1PYmplY3QucHJvdG90eXBlLnRvU3RyaW5nO2Z1bmN0aW9uIEModCl7cmV0dXJuIGZ1bmN0aW9uKHQsZSl7cmV0dXJuIE4uY2FsbCh0KT09PWBbb2JqZWN0ICR7ZX1dYH0odCwiT2JqZWN0Iil9ZnVuY3Rpb24gaih0KXtyZXR1cm4gQm9vbGVhbih0Py50aGVuJiYiZnVuY3Rpb24iPT10eXBlb2YgdC50aGVuKX1mdW5jdGlvbiBPKHQsZSl7dHJ5e3JldHVybiB0IGluc3RhbmNlb2YgZX1jYXRjaHtyZXR1cm4hMX19ZnVuY3Rpb24gUCh0KXtpZihmdW5jdGlvbih0KXtzd2l0Y2goTi5jYWxsKHQpKXtjYXNlIltvYmplY3QgRXJyb3JdIjpjYXNlIltvYmplY3QgRXhjZXB0aW9uXSI6Y2FzZSJbb2JqZWN0IERPTUV4Y2VwdGlvbl0iOmNhc2UiW29iamVjdCBXZWJBc3NlbWJseS5FeGNlcHRpb25dIjpyZXR1cm4hMDtkZWZhdWx0OnJldHVybiBPKHQsRXJyb3IpfX0odCkpcmV0dXJue21lc3NhZ2U6dC5tZXNzYWdlLG5hbWU6dC5uYW1lLHN0YWNrOnQuc3RhY2ssLi4uQSh0KX07aWYoZT10LCJ1bmRlZmluZWQiIT10eXBlb2YgRXZlbnQmJk8oZSxFdmVudCkpe2NvbnN0e3R5cGU6ZSx0YXJnZXQ6bixjdXJyZW50VGFyZ2V0OnIsZGV0YWlsOm99PXQ7cmV0dXJue3R5cGU6ZSx0YXJnZXQ6bixjdXJyZW50VGFyZ2V0OnIsLi4ubz97ZGV0YWlsOm99Ont9LC4uLkEodCl9fXZhciBlO3JldHVybiB0fWZ1bmN0aW9uIEEodCl7cmV0dXJuIm9iamVjdCI9PXR5cGVvZihlPXQpJiZudWxsIT09ZT9PYmplY3QuZnJvbUVudHJpZXMoT2JqZWN0LmVudHJpZXModCkpOnt9O3ZhciBlfWxldCBUO2Z1bmN0aW9uIGsodCl7aWYodm9pZCAwIT09VClyZXR1cm4gVD9UKHQpOnQoKTtjb25zdCBlPVN5bWJvbC5mb3IoIl9fU0VOVFJZX1NBRkVfUkFORE9NX0lEX1dSQVBQRVJfXyIpLG49cDtyZXR1cm4gZSBpbiBuJiYiZnVuY3Rpb24iPT10eXBlb2YgbltlXT8oVD1uW2VdLFQodCkpOihUPW51bGwsdCgpKX1mdW5jdGlvbiBSKCl7cmV0dXJuIGsoKCk9Pk1hdGgucmFuZG9tKCkpfWZ1bmN0aW9uIEkoKXtyZXR1cm4gaygoKT0+RGF0ZS5ub3coKSl9Y29uc3QgRD1TeW1ib2wuZm9yKCJzZW50cnkuc2tpcE5vcm1hbGl6YXRpb24iKSxVPVN5bWJvbC5mb3IoInNlbnRyeS5vdmVycmlkZU5vcm1hbGl6YXRpb25EZXB0aCIpO2Z1bmN0aW9uIEIodCxlPTEwMCxuPTEvMCl7dHJ5e3JldHVybiBMKCIiLHQsZSxuKX1jYXRjaCh0KXtyZXR1cm57RVJST1I6YCoqbm9uLXNlcmlhbGl6YWJsZSoqICgke3R9KWB9fX1mdW5jdGlvbiBMKHQsZSxuPTEvMCxyPTEvMCxvPWZ1bmN0aW9uKCl7Y29uc3QgdD1uZXcgV2Vha1NldDtmdW5jdGlvbiBlKGUpe3JldHVybiEhdC5oYXMoZSl8fCh0LmFkZChlKSwhMSl9ZnVuY3Rpb24gbihlKXt0LmRlbGV0ZShlKX1yZXR1cm5bZSxuXX0oKSl7Y29uc3RbcyxpXT1vO2lmKG51bGw9PWV8fFsiYm9vbGVhbiIsInN0cmluZyJdLmluY2x1ZGVzKHR5cGVvZiBlKXx8Im51bWJlciI9PXR5cGVvZiBlJiZOdW1iZXIuaXNGaW5pdGUoZSkpcmV0dXJuIGU7Y29uc3QgYz1mdW5jdGlvbih0LGUpe3RyeXtpZigidW5kZWZpbmVkIiE9dHlwZW9mIGdsb2JhbCYmZT09PWdsb2JhbClyZXR1cm4iW0dsb2JhbF0iO2lmKCJudW1iZXIiPT10eXBlb2YgZSYmIU51bWJlci5pc0Zpbml0ZShlKSlyZXR1cm5gWyR7ZX1dYDtpZigiZnVuY3Rpb24iPT10eXBlb2YgZSlyZXR1cm5gW0Z1bmN0aW9uOiAke2Z1bmN0aW9uKHQpe3RyeXtyZXR1cm4gdCYmImZ1bmN0aW9uIj09dHlwZW9mIHQmJnQubmFtZXx8eH1jYXRjaHtyZXR1cm4geH19KGUpfV1gO2lmKCJzeW1ib2wiPT10eXBlb2YgZSlyZXR1cm5gWyR7U3RyaW5nKGUpfV1gO2lmKCJiaWdpbnQiPT10eXBlb2YgZSlyZXR1cm5gW0JpZ0ludDogJHtTdHJpbmcoZSl9XWA7Y29uc3QgdD1mdW5jdGlvbih0KXtjb25zdCBlPU9iamVjdC5nZXRQcm90b3R5cGVPZih0KTtyZXR1cm4gZT8uY29uc3RydWN0b3I/ZS5jb25zdHJ1Y3Rvci5uYW1lOiJudWxsIHByb3RvdHlwZSJ9KGUpO3JldHVybmBbb2JqZWN0ICR7dH1dYH1jYXRjaCh0KXtyZXR1cm5gKipub24tc2VyaWFsaXphYmxlKiogKCR7dH0pYH19KDAsZSk7aWYoIWMuc3RhcnRzV2l0aCgiW29iamVjdCAiKSlyZXR1cm4gYztpZihmdW5jdGlvbih0KXtyZXR1cm4gQm9vbGVhbih0W0RdKX0oZSkpcmV0dXJuIGU7Y29uc3QgdT1mdW5jdGlvbih0KXtjb25zdCBlPXRbVV07cmV0dXJuIm51bWJlciI9PXR5cGVvZiBlP2U6dm9pZCAwfShlKSxhPXZvaWQgMCE9PXU/dTpuO2lmKDA9PT1hKXJldHVybiBjLnJlcGxhY2UoIm9iamVjdCAiLCIiKTtpZihzKGUpKXJldHVybiJbQ2lyY3VsYXIgfl0iO2NvbnN0IGY9ZTtpZihmJiYiZnVuY3Rpb24iPT10eXBlb2YgZi50b0pTT04pdHJ5e3JldHVybiBMKCIiLGYudG9KU09OKCksYS0xLHIsbyl9Y2F0Y2h7fWNvbnN0IGg9QXJyYXkuaXNBcnJheShlKT9bXTp7fTtsZXQgcD0wO2NvbnN0IGw9UChlKTtmb3IoY29uc3QgdCBpbiBsKXtpZighT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKGwsdCkpY29udGludWU7aWYocD49cil7aFt0XT0iW01heFByb3BlcnRpZXMgfl0iO2JyZWFrfWNvbnN0IGU9bFt0XTtoW3RdPUwodCxlLGEtMSxyLG8pLHArK31yZXR1cm4gaShlKSxofWZ1bmN0aW9uIE0odCxlKXtjb25zdCBuPWUucmVwbGFjZSgvXFwvZywiLyIpLnJlcGxhY2UoL1t8XFx7fSgpW1xdXiQrKj8uXS9nLCJcXCQmIik7bGV0IHI9dDt0cnl7cj1kZWNvZGVVUkkodCl9Y2F0Y2h7fXJldHVybiByLnJlcGxhY2UoL1xcL2csIi8iKS5yZXBsYWNlKC93ZWJwYWNrOlwvPy9nLCIiKS5yZXBsYWNlKG5ldyBSZWdFeHAoYChmaWxlOi8vKT8vKiR7bn0vKmAsImlnIiksImFwcDovLy8iKX1mdW5jdGlvbiB6KHQsZT0wKXtyZXR1cm4ic3RyaW5nIiE9dHlwZW9mIHR8fDA9PT1lfHx0Lmxlbmd0aDw9ZT90OmAke3Quc2xpY2UoMCxlKX0uLi5gfWxldCBKO2Z1bmN0aW9uIFcodD1mdW5jdGlvbigpe2NvbnN0IHQ9cDtyZXR1cm4gdC5jcnlwdG98fHQubXNDcnlwdG99KCkpe3RyeXtpZih0Py5yYW5kb21VVUlEKXJldHVybiBrKCgpPT50LnJhbmRvbVVVSUQoKSkucmVwbGFjZSgvLS9nLCIiKX1jYXRjaHt9cmV0dXJuIEp8fChKPSIxMDAwMDAwMDEwMDA0MDAwODAwMDEwMDAwMDAwMDAwMCIpLEoucmVwbGFjZSgvWzAxOF0vZyx0PT4odF4oMTYqUigpJjE1KT4+dC80KS50b1N0cmluZygxNikpfWZ1bmN0aW9uIEYoKXtyZXR1cm4gSSgpLzFlM31sZXQgRztmdW5jdGlvbiBZKCl7cmV0dXJuKEc/PyhHPWZ1bmN0aW9uKCl7Y29uc3R7cGVyZm9ybWFuY2U6dH09cDtpZighdD8ubm93fHwhdC50aW1lT3JpZ2luKXJldHVybiBGO2NvbnN0IGU9dC50aW1lT3JpZ2luO3JldHVybigpPT4oZStrKCgpPT50Lm5vdygpKSkvMWUzfSgpKSkoKX1mdW5jdGlvbiBIKHQpe2NvbnN0IGU9WSgpLG49e3NpZDpXKCksaW5pdDohMCx0aW1lc3RhbXA6ZSxzdGFydGVkOmUsZHVyYXRpb246MCxzdGF0dXM6Im9rIixlcnJvcnM6MCxpZ25vcmVEdXJhdGlvbjohMSx0b0pTT046KCk9PmZ1bmN0aW9uKHQpe3JldHVybntzaWQ6YCR7dC5zaWR9YCxpbml0OnQuaW5pdCxzdGFydGVkOm5ldyBEYXRlKDFlMyp0LnN0YXJ0ZWQpLnRvSVNPU3RyaW5nKCksdGltZXN0YW1wOm5ldyBEYXRlKDFlMyp0LnRpbWVzdGFtcCkudG9JU09TdHJpbmcoKSxzdGF0dXM6dC5zdGF0dXMsZXJyb3JzOnQuZXJyb3JzLGRpZDoibnVtYmVyIj09dHlwZW9mIHQuZGlkfHwic3RyaW5nIj09dHlwZW9mIHQuZGlkP2Ake3QuZGlkfWA6dm9pZCAwLGR1cmF0aW9uOnQuZHVyYXRpb24sYWJub3JtYWxfbWVjaGFuaXNtOnQuYWJub3JtYWxfbWVjaGFuaXNtLGF0dHJzOntyZWxlYXNlOnQucmVsZWFzZSxlbnZpcm9ubWVudDp0LmVudmlyb25tZW50LGlwX2FkZHJlc3M6dC5pcEFkZHJlc3MsdXNlcl9hZ2VudDp0LnVzZXJBZ2VudH19fShuKX07cmV0dXJuIHQmJloobix0KSxufWZ1bmN0aW9uIFoodCxlPXt9KXtpZihlLnVzZXImJighdC5pcEFkZHJlc3MmJmUudXNlci5pcF9hZGRyZXNzJiYodC5pcEFkZHJlc3M9ZS51c2VyLmlwX2FkZHJlc3MpLHQuZGlkfHxlLmRpZHx8KHQuZGlkPWUudXNlci5pZHx8ZS51c2VyLmVtYWlsfHxlLnVzZXIudXNlcm5hbWUpKSx0LnRpbWVzdGFtcD1lLnRpbWVzdGFtcHx8WSgpLGUuYWJub3JtYWxfbWVjaGFuaXNtJiYodC5hYm5vcm1hbF9tZWNoYW5pc209ZS5hYm5vcm1hbF9tZWNoYW5pc20pLGUuaWdub3JlRHVyYXRpb24mJih0Lmlnbm9yZUR1cmF0aW9uPWUuaWdub3JlRHVyYXRpb24pLGUuc2lkJiYodC5zaWQ9MzI9PT1lLnNpZC5sZW5ndGg/ZS5zaWQ6VygpKSx2b2lkIDAhPT1lLmluaXQmJih0LmluaXQ9ZS5pbml0KSwhdC5kaWQmJmUuZGlkJiYodC5kaWQ9YCR7ZS5kaWR9YCksIm51bWJlciI9PXR5cGVvZiBlLnN0YXJ0ZWQmJih0LnN0YXJ0ZWQ9ZS5zdGFydGVkKSx0Lmlnbm9yZUR1cmF0aW9uKXQuZHVyYXRpb249dm9pZCAwO2Vsc2UgaWYoIm51bWJlciI9PXR5cGVvZiBlLmR1cmF0aW9uKXQuZHVyYXRpb249ZS5kdXJhdGlvbjtlbHNle2NvbnN0IGU9dC50aW1lc3RhbXAtdC5zdGFydGVkO3QuZHVyYXRpb249ZT49MD9lOjB9ZS5yZWxlYXNlJiYodC5yZWxlYXNlPWUucmVsZWFzZSksZS5lbnZpcm9ubWVudCYmKHQuZW52aXJvbm1lbnQ9ZS5lbnZpcm9ubWVudCksIXQuaXBBZGRyZXNzJiZlLmlwQWRkcmVzcyYmKHQuaXBBZGRyZXNzPWUuaXBBZGRyZXNzKSwhdC51c2VyQWdlbnQmJmUudXNlckFnZW50JiYodC51c2VyQWdlbnQ9ZS51c2VyQWdlbnQpLCJudW1iZXIiPT10eXBlb2YgZS5lcnJvcnMmJih0LmVycm9ycz1lLmVycm9ycyksZS5zdGF0dXMmJih0LnN0YXR1cz1lLnN0YXR1cyl9ZnVuY3Rpb24gcSh0LGUsbj0yKXtpZighZXx8Im9iamVjdCIhPXR5cGVvZiBlfHxuPD0wKXJldHVybiBlO2lmKHQmJjA9PT1PYmplY3Qua2V5cyhlKS5sZW5ndGgpcmV0dXJuIHQ7Y29uc3Qgcj17Li4udH07Zm9yKGNvbnN0IHQgaW4gZSlPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwoZSx0KSYmKHJbdF09cShyW3RdLGVbdF0sbi0xKSk7cmV0dXJuIHJ9Y2xhc3MgS3tjb25zdHJ1Y3Rvcigpe3RoaXMudD0hMSx0aGlzLm89W10sdGhpcy5pPVtdLHRoaXMudT1bXSx0aGlzLmg9W10sdGhpcy5wPXt9LHRoaXMubD17fSx0aGlzLm09e30sdGhpcy52PXt9LHRoaXMuUz17fSx0aGlzLl89e30sZnVuY3Rpb24odCxlLG4pe3RyeXtPYmplY3QuZGVmaW5lUHJvcGVydHkodCxlLHt2YWx1ZTpuLHdyaXRhYmxlOiEwLGNvbmZpZ3VyYWJsZTohMH0pfWNhdGNoe2gmJl8ubG9nKGBGYWlsZWQgdG8gYWRkIG5vbi1lbnVtZXJhYmxlIHByb3BlcnR5ICIke1N0cmluZyhlKX0iIHRvIG9iamVjdGAsdCl9fSh0aGlzLCJyZWZzIix7fSksdGhpcy5OPXt0cmFjZUlkOlcoKSxzYW1wbGVSYW5kOlIoKX19Y2xvbmUoKXtjb25zdCB0PW5ldyBLO3JldHVybiB0LnU9Wy4uLnRoaXMudV0sdC5sPXsuLi50aGlzLmx9LHQubT17Li4udGhpcy5tfSx0LnY9ey4uLnRoaXMudn0sdC5TPXsuLi50aGlzLlN9LHRoaXMuUy5mbGFncyYmKHQuUy5mbGFncz17dmFsdWVzOlsuLi50aGlzLlMuZmxhZ3MudmFsdWVzXX0pLHQucD10aGlzLnAsdC5DPXRoaXMuQyx0Lmo9dGhpcy5qLHQuTz10aGlzLk8sdC5QPXRoaXMuUCx0Lmk9Wy4uLnRoaXMuaV0sdC5oPVsuLi50aGlzLmhdLHQuXz17Li4udGhpcy5ffSx0Lk49ey4uLnRoaXMuTn0sdC5BPXRoaXMuQSx0LlQ9dGhpcy5ULHQuaz10aGlzLmssdC5yZWZzPXsuLi50aGlzLnJlZnN9LHR9c2V0Q2xpZW50KHQpe3RoaXMuQT10fXNldExhc3RFdmVudElkKHQpe3RoaXMuVD10fWdldENsaWVudCgpe3JldHVybiB0aGlzLkF9bGFzdEV2ZW50SWQoKXtyZXR1cm4gdGhpcy5UfWFkZFNjb3BlTGlzdGVuZXIodCl7dGhpcy5vLnB1c2godCl9YWRkRXZlbnRQcm9jZXNzb3IodCl7cmV0dXJuIHRoaXMuaS5wdXNoKHQpLHRoaXN9c2V0VXNlcih0KXtyZXR1cm4gdGhpcy5wPXR8fHtlbWFpbDp2b2lkIDAsaWQ6dm9pZCAwLGlwX2FkZHJlc3M6dm9pZCAwLHVzZXJuYW1lOnZvaWQgMH0sdGhpcy5qJiZaKHRoaXMuaix7dXNlcjp0fSksdGhpcy5SKCksdGhpc31nZXRVc2VyKCl7cmV0dXJuIHRoaXMucH1zZXRDb252ZXJzYXRpb25JZCh0KXtyZXR1cm4gdGhpcy5rPXR8fHZvaWQgMCx0aGlzLlIoKSx0aGlzfXNldFRhZ3ModCl7cmV0dXJuIHRoaXMubD17Li4udGhpcy5sLC4uLnR9LHRoaXMuUigpLHRoaXN9c2V0VGFnKHQsZSl7cmV0dXJuIHRoaXMuc2V0VGFncyh7W3RdOmV9KX1zZXRBdHRyaWJ1dGVzKHQpe3JldHVybiB0aGlzLm09ey4uLnRoaXMubSwuLi50fSx0aGlzLlIoKSx0aGlzfXNldEF0dHJpYnV0ZSh0LGUpe3JldHVybiB0aGlzLnNldEF0dHJpYnV0ZXMoe1t0XTplfSl9cmVtb3ZlQXR0cmlidXRlKHQpe3JldHVybiB0IGluIHRoaXMubSYmKGRlbGV0ZSB0aGlzLm1bdF0sdGhpcy5SKCkpLHRoaXN9c2V0RXh0cmFzKHQpe3JldHVybiB0aGlzLnY9ey4uLnRoaXMudiwuLi50fSx0aGlzLlIoKSx0aGlzfXNldEV4dHJhKHQsZSl7cmV0dXJuIHRoaXMudj17Li4udGhpcy52LFt0XTplfSx0aGlzLlIoKSx0aGlzfXNldEZpbmdlcnByaW50KHQpe3JldHVybiB0aGlzLlA9dCx0aGlzLlIoKSx0aGlzfXNldExldmVsKHQpe3JldHVybiB0aGlzLkM9dCx0aGlzLlIoKSx0aGlzfXNldFRyYW5zYWN0aW9uTmFtZSh0KXtyZXR1cm4gdGhpcy5PPXQsdGhpcy5SKCksdGhpc31zZXRDb250ZXh0KHQsZSl7cmV0dXJuIG51bGw9PT1lP2RlbGV0ZSB0aGlzLlNbdF06dGhpcy5TW3RdPWUsdGhpcy5SKCksdGhpc31zZXRTZXNzaW9uKHQpe3JldHVybiB0P3RoaXMuaj10OmRlbGV0ZSB0aGlzLmosdGhpcy5SKCksdGhpc31nZXRTZXNzaW9uKCl7cmV0dXJuIHRoaXMuan11cGRhdGUodCl7aWYoIXQpcmV0dXJuIHRoaXM7Y29uc3QgZT0iZnVuY3Rpb24iPT10eXBlb2YgdD90KHRoaXMpOnQsbj1lIGluc3RhbmNlb2YgSz9lLmdldFNjb3BlRGF0YSgpOkMoZSk/dDp2b2lkIDAse3RhZ3M6cixhdHRyaWJ1dGVzOm8sZXh0cmE6cyx1c2VyOmksY29udGV4dHM6YyxsZXZlbDp1LGZpbmdlcnByaW50OmE9W10scHJvcGFnYXRpb25Db250ZXh0OmYsY29udmVyc2F0aW9uSWQ6aH09bnx8e307cmV0dXJuIHRoaXMubD17Li4udGhpcy5sLC4uLnJ9LHRoaXMubT17Li4udGhpcy5tLC4uLm99LHRoaXMudj17Li4udGhpcy52LC4uLnN9LHRoaXMuUz17Li4udGhpcy5TLC4uLmN9LGkmJk9iamVjdC5rZXlzKGkpLmxlbmd0aCYmKHRoaXMucD1pKSx1JiYodGhpcy5DPXUpLGEubGVuZ3RoJiYodGhpcy5QPWEpLGYmJih0aGlzLk49ZiksaCYmKHRoaXMuaz1oKSx0aGlzfWFkZEJyZWFkY3J1bWIodCxlKXtjb25zdCBuPSJudW1iZXIiPT10eXBlb2YgZT9lOjEwMDtpZihuPD0wKXJldHVybiB0aGlzO2NvbnN0IHI9e3RpbWVzdGFtcDpGKCksLi4udCxtZXNzYWdlOnQubWVzc2FnZT96KHQubWVzc2FnZSwyMDQ4KTp0Lm1lc3NhZ2V9O3JldHVybiB0aGlzLnUucHVzaChyKSx0aGlzLnUubGVuZ3RoPm4mJih0aGlzLnU9dGhpcy51LnNsaWNlKC1uKSx0aGlzLkE/LnJlY29yZERyb3BwZWRFdmVudCgiYnVmZmVyX292ZXJmbG93IiwibG9nX2l0ZW0iKSksdGhpcy5SKCksdGhpc31nZXRMYXN0QnJlYWRjcnVtYigpe3JldHVybiB0aGlzLnVbdGhpcy51Lmxlbmd0aC0xXX1jbGVhckJyZWFkY3J1bWJzKCl7cmV0dXJuIHRoaXMudT1bXSx0aGlzLlIoKSx0aGlzfWFkZEF0dGFjaG1lbnQodCl7cmV0dXJuIHRoaXMuaC5wdXNoKHQpLHRoaXN9Y2xlYXJBdHRhY2htZW50cygpe3JldHVybiB0aGlzLmg9W10sdGhpc31nZXRTY29wZURhdGEoKXtyZXR1cm57YnJlYWRjcnVtYnM6dGhpcy51LGF0dGFjaG1lbnRzOnRoaXMuaCxjb250ZXh0czp0aGlzLlMsdGFnczp0aGlzLmwsYXR0cmlidXRlczp0aGlzLm0sZXh0cmE6dGhpcy52LHVzZXI6dGhpcy5wLGxldmVsOnRoaXMuQyxmaW5nZXJwcmludDp0aGlzLlB8fFtdLGV2ZW50UHJvY2Vzc29yczp0aGlzLmkscHJvcGFnYXRpb25Db250ZXh0OnRoaXMuTixzZGtQcm9jZXNzaW5nTWV0YWRhdGE6dGhpcy5fLHRyYW5zYWN0aW9uTmFtZTp0aGlzLk8sY29udmVyc2F0aW9uSWQ6dGhpcy5rfX1zZXRTREtQcm9jZXNzaW5nTWV0YWRhdGEodCl7cmV0dXJuIHRoaXMuXz1xKHRoaXMuXyx0LDIpLHRoaXN9c2V0UHJvcGFnYXRpb25Db250ZXh0KHQpe3JldHVybiB0aGlzLk49dCx0aGlzfWdldFByb3BhZ2F0aW9uQ29udGV4dCgpe3JldHVybiB0aGlzLk59Y2FwdHVyZUV4Y2VwdGlvbih0LGUpe2NvbnN0IG49ZT8uZXZlbnRfaWR8fFcoKTtpZighdGhpcy5BKXJldHVybiBoJiZfLndhcm4oIk5vIGNsaWVudCBjb25maWd1cmVkIG9uIHNjb3BlIC0gd2lsbCBub3QgY2FwdHVyZSBleGNlcHRpb24hIiksbjtjb25zdCByPW5ldyBFcnJvcigiU2VudHJ5IHN5bnRoZXRpY0V4Y2VwdGlvbiIpO3JldHVybiB0aGlzLkEuY2FwdHVyZUV4Y2VwdGlvbih0LHtvcmlnaW5hbEV4Y2VwdGlvbjp0LHN5bnRoZXRpY0V4Y2VwdGlvbjpyLC4uLmUsZXZlbnRfaWQ6bn0sdGhpcyksbn1jYXB0dXJlTWVzc2FnZSh0LGUsbil7Y29uc3Qgcj1uPy5ldmVudF9pZHx8VygpO2lmKCF0aGlzLkEpcmV0dXJuIGgmJl8ud2FybigiTm8gY2xpZW50IGNvbmZpZ3VyZWQgb24gc2NvcGUgLSB3aWxsIG5vdCBjYXB0dXJlIG1lc3NhZ2UhIikscjtjb25zdCBvPW4/LnN5bnRoZXRpY0V4Y2VwdGlvbj8/bmV3IEVycm9yKHQpO3JldHVybiB0aGlzLkEuY2FwdHVyZU1lc3NhZ2UodCxlLHtvcmlnaW5hbEV4Y2VwdGlvbjp0LHN5bnRoZXRpY0V4Y2VwdGlvbjpvLC4uLm4sZXZlbnRfaWQ6cn0sdGhpcykscn1jYXB0dXJlRXZlbnQodCxlKXtjb25zdCBuPXQuZXZlbnRfaWR8fGU/LmV2ZW50X2lkfHxXKCk7cmV0dXJuIHRoaXMuQT8odGhpcy5BLmNhcHR1cmVFdmVudCh0LHsuLi5lLGV2ZW50X2lkOm59LHRoaXMpLG4pOihoJiZfLndhcm4oIk5vIGNsaWVudCBjb25maWd1cmVkIG9uIHNjb3BlIC0gd2lsbCBub3QgY2FwdHVyZSBldmVudCEiKSxuKX1SKCl7dGhpcy50fHwodGhpcy50PSEwLHRoaXMuby5mb3JFYWNoKHQ9Pnt0KHRoaXMpfSksdGhpcy50PSExKX19Y29uc3QgVj0iX19TRU5UUllfU1VQUFJFU1NfVFJBQ0lOR19fIixRPXQ9PnQgaW5zdGFuY2VvZiBQcm9taXNlJiYhdFtYXSxYPVN5bWJvbCgiY2hhaW5lZCBQcm9taXNlTGlrZSIpLHR0PSh0LGUpPT57aWYoIWUpcmV0dXJuIHQ7bGV0IG49ITE7Zm9yKGNvbnN0IHIgaW4gdCl7aWYociBpbiBlKWNvbnRpbnVlO249ITA7Y29uc3Qgbz10W3JdOyJmdW5jdGlvbiI9PXR5cGVvZiBvP09iamVjdC5kZWZpbmVQcm9wZXJ0eShlLHIse3ZhbHVlOiguLi5lKT0+by5hcHBseSh0LGUpLGVudW1lcmFibGU6ITAsY29uZmlndXJhYmxlOiEwLHdyaXRhYmxlOiEwfSk6ZVtyXT1vfXJldHVybiBuJiZPYmplY3QuYXNzaWduKGUse1tYXTohMH0pLGV9O2NsYXNzIGV0e2NvbnN0cnVjdG9yKHQsZSl7bGV0IG4scjtuPXR8fG5ldyBLLHI9ZXx8bmV3IEssdGhpcy5JPVt7c2NvcGU6bn1dLHRoaXMuRD1yfXdpdGhTY29wZSh0KXtjb25zdCBlPXRoaXMuVSgpO2xldCBuO3RyeXtuPXQoZSl9Y2F0Y2godCl7dGhyb3cgdGhpcy5CKCksdH1yZXR1cm4gaihuKT8oKHQsZSxuKT0+e2NvbnN0IHI9dC50aGVuKHQ9PihlKHQpLHQpLHQ9Pnt0aHJvdyBuKHQpLHR9KTtyZXR1cm4gUShyKSYmUSh0KT9yOnR0KHQscil9KShuLCgpPT50aGlzLkIoKSwoKT0+dGhpcy5CKCkpOih0aGlzLkIoKSxuKX1nZXRDbGllbnQoKXtyZXR1cm4gdGhpcy5nZXRTdGFja1RvcCgpLmNsaWVudH1nZXRTY29wZSgpe3JldHVybiB0aGlzLmdldFN0YWNrVG9wKCkuc2NvcGV9Z2V0SXNvbGF0aW9uU2NvcGUoKXtyZXR1cm4gdGhpcy5EfWdldFN0YWNrVG9wKCl7cmV0dXJuIHRoaXMuSVt0aGlzLkkubGVuZ3RoLTFdfVUoKXtjb25zdCB0PXRoaXMuZ2V0U2NvcGUoKS5jbG9uZSgpO3JldHVybiB0aGlzLkkucHVzaCh7Y2xpZW50OnRoaXMuZ2V0Q2xpZW50KCksc2NvcGU6dH0pLHR9Qigpe3JldHVybiEodGhpcy5JLmxlbmd0aDw9MSkmJiEhdGhpcy5JLnBvcCgpfX1mdW5jdGlvbiBudCgpe2NvbnN0IHQ9ZyhkKCkpO3JldHVybiB0LnN0YWNrPXQuc3RhY2t8fG5ldyBldChtKCJkZWZhdWx0Q3VycmVudFNjb3BlIiwoKT0+bmV3IEspLG0oImRlZmF1bHRJc29sYXRpb25TY29wZSIsKCk9Pm5ldyBLKSl9ZnVuY3Rpb24gcnQodCl7cmV0dXJuIG50KCkud2l0aFNjb3BlKHQpfWZ1bmN0aW9uIG90KHQsZSl7Y29uc3Qgbj1udCgpO3JldHVybiBuLndpdGhTY29wZSgoKT0+KG4uZ2V0U3RhY2tUb3AoKS5zY29wZT10LGUodCkpKX1mdW5jdGlvbiBzdCh0KXtyZXR1cm4gbnQoKS53aXRoU2NvcGUoKCk9PnQobnQoKS5nZXRJc29sYXRpb25TY29wZSgpKSl9ZnVuY3Rpb24gaXQodCl7cmV0dXJuIHJ0KGU9PntlLnNldFNES1Byb2Nlc3NpbmdNZXRhZGF0YSh7W1ZdOiEwfSk7Y29uc3Qgbj10KCk7cmV0dXJuIGUuc2V0U0RLUHJvY2Vzc2luZ01ldGFkYXRhKHtbVl06dm9pZCAwfSksbn0pfWZ1bmN0aW9uIGN0KHQpe2NvbnN0IGU9Zyh0KTtyZXR1cm4gZS5hY3M/ZS5hY3M6e3N1cHByZXNzVHJhY2luZzppdCx3aXRoSXNvbGF0aW9uU2NvcGU6c3Qsd2l0aFNjb3BlOnJ0LHdpdGhTZXRTY29wZTpvdCx3aXRoU2V0SXNvbGF0aW9uU2NvcGU6KHQsZSk9PnN0KGUpLGdldEN1cnJlbnRTY29wZTooKT0+bnQoKS5nZXRTY29wZSgpLGdldElzb2xhdGlvblNjb3BlOigpPT5udCgpLmdldElzb2xhdGlvblNjb3BlKCl9fWZ1bmN0aW9uIHV0KHQsZT0hMSl7Y29uc3R7aG9zdDpuLHBhdGg6cixwYXNzOm8scG9ydDpzLHByb2plY3RJZDppLHByb3RvY29sOmMscHVibGljS2V5OnV9PXQ7cmV0dXJuYCR7Y306Ly8ke3V9JHtlJiZvP2A6JHtvfWA6IiJ9QCR7bn0ke3M/YDoke3N9YDoiIn0vJHtyP2Ake3J9L2A6cn0ke2l9YH1mdW5jdGlvbiBhdCh0LGUpe2NvbnN0e2ZpbmdlcnByaW50Om4sYnJlYWRjcnVtYnM6cixzZGtQcm9jZXNzaW5nTWV0YWRhdGE6b309ZTshZnVuY3Rpb24odCxlKXtjb25zdHtleHRyYTpuLHRhZ3M6cix1c2VyOm8sY29udGV4dHM6cyxsZXZlbDppLHRyYW5zYWN0aW9uTmFtZTpjfT1lO09iamVjdC5rZXlzKG4pLmxlbmd0aCYmKHQuZXh0cmE9ey4uLm4sLi4udC5leHRyYX0pO09iamVjdC5rZXlzKHIpLmxlbmd0aCYmKHQudGFncz17Li4uciwuLi50LnRhZ3N9KTtPYmplY3Qua2V5cyhvKS5sZW5ndGgmJih0LnVzZXI9ey4uLm8sLi4udC51c2VyfSk7T2JqZWN0LmtleXMocykubGVuZ3RoJiYodC5jb250ZXh0cz17Li4ucywuLi50LmNvbnRleHRzfSk7aSYmKHQubGV2ZWw9aSk7YyYmInRyYW5zYWN0aW9uIiE9PXQudHlwZSYmKHQudHJhbnNhY3Rpb249Yyl9KHQsZSksZnVuY3Rpb24odCxlKXt0LmZpbmdlcnByaW50PXQuZmluZ2VycHJpbnQ/QXJyYXkuaXNBcnJheSh0LmZpbmdlcnByaW50KT90LmZpbmdlcnByaW50Olt0LmZpbmdlcnByaW50XTpbXSxlJiYodC5maW5nZXJwcmludD10LmZpbmdlcnByaW50LmNvbmNhdChlKSk7dC5maW5nZXJwcmludC5sZW5ndGh8fGRlbGV0ZSB0LmZpbmdlcnByaW50fSh0LG4pLGZ1bmN0aW9uKHQsZSl7Y29uc3Qgbj1bLi4udC5icmVhZGNydW1ic3x8W10sLi4uZV07dC5icmVhZGNydW1icz1uLmxlbmd0aD9uOnZvaWQgMH0odCxyKSxmdW5jdGlvbih0LGUpe3Quc2RrUHJvY2Vzc2luZ01ldGFkYXRhPXsuLi50LnNka1Byb2Nlc3NpbmdNZXRhZGF0YSwuLi5lfX0odCxvKX1mdW5jdGlvbiBmdCh0LGU9W10pe3JldHVyblt0LGVdfWZ1bmN0aW9uIGh0KHQsZSl7Y29uc3Qgbj10WzFdO2Zvcihjb25zdCB0IG9mIG4pe2lmKGUodCx0WzBdLnR5cGUpKXJldHVybiEwfXJldHVybiExfWZ1bmN0aW9uIHB0KHQpe2NvbnN0IGU9ZyhwKTtyZXR1cm4gZS5lbmNvZGVQb2x5ZmlsbD9lLmVuY29kZVBvbHlmaWxsKHQpOihuZXcgVGV4dEVuY29kZXIpLmVuY29kZSh0KX1mdW5jdGlvbiBsdCh0KXtjb25zdFtlLG5dPXQ7bGV0IHI9SlNPTi5zdHJpbmdpZnkoZSk7ZnVuY3Rpb24gbyh0KXsic3RyaW5nIj09dHlwZW9mIHI/cj0ic3RyaW5nIj09dHlwZW9mIHQ/cit0OltwdChyKSx0XTpyLnB1c2goInN0cmluZyI9PXR5cGVvZiB0P3B0KHQpOnQpfWZvcihjb25zdCB0IG9mIG4pe2NvbnN0W2Usbl09dDtpZihvKGBcbiR7SlNPTi5zdHJpbmdpZnkoZSl9XG5gKSwic3RyaW5nIj09dHlwZW9mIG58fG4gaW5zdGFuY2VvZiBVaW50OEFycmF5KW8obik7ZWxzZXtsZXQgdDt0cnl7dD1KU09OLnN0cmluZ2lmeShuKX1jYXRjaHt0PUpTT04uc3RyaW5naWZ5KEIobikpfW8odCl9fXJldHVybiJzdHJpbmciPT10eXBlb2Ygcj9yOmZ1bmN0aW9uKHQpe2NvbnN0IGU9dC5yZWR1Y2UoKHQsZSk9PnQrZS5sZW5ndGgsMCksbj1uZXcgVWludDhBcnJheShlKTtsZXQgcj0wO2Zvcihjb25zdCBlIG9mIHQpbi5zZXQoZSxyKSxyKz1lLmxlbmd0aDtyZXR1cm4gbn0ocil9Y29uc3QgZHQ9e3Nlc3Npb25zOiJzZXNzaW9uIixldmVudDoiZXJyb3IiLGNsaWVudF9yZXBvcnQ6ImludGVybmFsIix1c2VyX3JlcG9ydDoiZGVmYXVsdCIscHJvZmlsZV9jaHVuazoicHJvZmlsZSIscmVwbGF5X2V2ZW50OiJyZXBsYXkiLHJlcGxheV9yZWNvcmRpbmc6InJlcGxheSIsY2hlY2tfaW46Im1vbml0b3IiLHJhd19zZWN1cml0eToic2VjdXJpdHkiLGxvZzoibG9nX2l0ZW0iLHRyYWNlX21ldHJpYzoibWV0cmljIn07ZnVuY3Rpb24gZ3QodCl7cmV0dXJuIGZ1bmN0aW9uKHQpe3JldHVybiB0IGluIGR0fSh0KT9kdFt0XTp0fWZ1bmN0aW9uIG10KHQpe2lmKCF0Py5zZGspcmV0dXJuO2NvbnN0e25hbWU6ZSx2ZXJzaW9uOm59PXQuc2RrO3JldHVybntuYW1lOmUsdmVyc2lvbjpufX1mdW5jdGlvbiB5dCh0KXtjb25zdCBlPWN0KGQoKSk7cmV0dXJuIGUuc3VwcHJlc3NUcmFjaW5nP2Uuc3VwcHJlc3NUcmFjaW5nKHQpOmZ1bmN0aW9uKC4uLnQpe2NvbnN0IGU9Y3QoZCgpKTtpZigyPT09dC5sZW5ndGgpe2NvbnN0W24scl09dDtyZXR1cm4gbj9lLndpdGhTZXRTY29wZShuLHIpOmUud2l0aFNjb3BlKHIpfXJldHVybiBlLndpdGhTY29wZSh0WzBdKX0oZT0+KGUuc2V0U0RLUHJvY2Vzc2luZ01ldGFkYXRhKHtbVl06ITB9KSx0KCkpKX1mdW5jdGlvbiBidCh0LGUsbixyKXtjb25zdCBvPW10KG4pLHM9dC50eXBlJiYicmVwbGF5X2V2ZW50IiE9PXQudHlwZT90LnR5cGU6ImV2ZW50IjshZnVuY3Rpb24odCxlKXtpZighZSlyZXR1cm4gdDtjb25zdCBuPXQuc2RrfHx7fTt0LnNkaz17Li4ubixuYW1lOm4ubmFtZXx8ZS5uYW1lLHZlcnNpb246bi52ZXJzaW9ufHxlLnZlcnNpb24saW50ZWdyYXRpb25zOlsuLi50LnNkaz8uaW50ZWdyYXRpb25zfHxbXSwuLi5lLmludGVncmF0aW9uc3x8W11dLHBhY2thZ2VzOlsuLi50LnNkaz8ucGFja2FnZXN8fFtdLC4uLmUucGFja2FnZXN8fFtdXSxzZXR0aW5nczp0LnNkaz8uc2V0dGluZ3N8fGUuc2V0dGluZ3M/ey4uLnQuc2RrPy5zZXR0aW5ncywuLi5lLnNldHRpbmdzfTp2b2lkIDB9fSh0LG4/LnNkayk7Y29uc3QgaT1mdW5jdGlvbih0LGUsbixyKXtjb25zdCBvPXQuc2RrUHJvY2Vzc2luZ01ldGFkYXRhPy5keW5hbWljU2FtcGxpbmdDb250ZXh0O3JldHVybntldmVudF9pZDp0LmV2ZW50X2lkLHNlbnRfYXQ6bmV3IERhdGUoSSgpKS50b0lTT1N0cmluZygpLC4uLmUmJntzZGs6ZX0sLi4uISFuJiZyJiZ7ZHNuOnV0KHIpfSwuLi5vJiZ7dHJhY2U6b319fSh0LG8scixlKTtkZWxldGUgdC5zZGtQcm9jZXNzaW5nTWV0YWRhdGE7cmV0dXJuIGZ0KGksW1t7dHlwZTpzfSx0XV0pfWNsYXNzIHZ0e2NvbnN0cnVjdG9yKHQpe3RoaXMuTD0wLHRoaXMuTT1bXSx0aGlzLkoodCl9dGhlbih0LGUpe3JldHVybiBuZXcgdnQoKG4scik9Pnt0aGlzLk0ucHVzaChbITEsZT0+e2lmKHQpdHJ5e24odChlKSl9Y2F0Y2godCl7cih0KX1lbHNlIG4oZSl9LHQ9PntpZihlKXRyeXtuKGUodCkpfWNhdGNoKHQpe3IodCl9ZWxzZSByKHQpfV0pLHRoaXMuVygpfSl9Y2F0Y2godCl7cmV0dXJuIHRoaXMudGhlbih0PT50LHQpfWZpbmFsbHkodCl7cmV0dXJuIG5ldyB2dCgoZSxuKT0+e2xldCByLG87cmV0dXJuIHRoaXMudGhlbihlPT57bz0hMSxyPWUsdCYmdCgpfSxlPT57bz0hMCxyPWUsdCYmdCgpfSkudGhlbigoKT0+e28/bihyKTplKHIpfSl9KX1XKCl7aWYoMD09PXRoaXMuTClyZXR1cm47Y29uc3QgdD10aGlzLk0uc2xpY2UoKTt0aGlzLk09W10sdC5mb3JFYWNoKHQ9Pnt0WzBdfHwoMT09PXRoaXMuTCYmdFsxXSh0aGlzLkYpLDI9PT10aGlzLkwmJnRbMl0odGhpcy5GKSx0WzBdPSEwKX0pfUoodCl7Y29uc3QgZT0odCxlKT0+ezA9PT10aGlzLkwmJihqKGUpP2UudGhlbihuLHIpOih0aGlzLkw9dCx0aGlzLkY9ZSx0aGlzLlcoKSkpfSxuPXQ9PntlKDEsdCl9LHI9dD0+e2UoMix0KX07dHJ5e3QobixyKX1jYXRjaCh0KXtyKHQpfX19Y29uc3Qgd3Q9U3ltYm9sLmZvcigiU2VudHJ5QnVmZmVyRnVsbEVycm9yIik7ZnVuY3Rpb24gU3QodD0xMDApe2NvbnN0IGU9bmV3IFNldDtmdW5jdGlvbiBuKHQpe2UuZGVsZXRlKHQpfXJldHVybntnZXQgJCgpe3JldHVybiBBcnJheS5mcm9tKGUpfSxhZGQ6ZnVuY3Rpb24ocil7aWYoIShlLnNpemU8dCkpcmV0dXJuIG89d3QsbmV3IHZ0KCh0LGUpPT57ZShvKX0pO3ZhciBvO2NvbnN0IHM9cigpO3JldHVybiBlLmFkZChzKSxzLnRoZW4oKCk9Pm4ocyksKCk9Pm4ocykpLHN9LGRyYWluOmZ1bmN0aW9uKHQpe2lmKCFlLnNpemUpcmV0dXJuIG49ITAsbmV3IHZ0KHQ9Pnt0KG4pfSk7dmFyIG47Y29uc3Qgcj1Qcm9taXNlLmFsbFNldHRsZWQoQXJyYXkuZnJvbShlKSkudGhlbigoKT0+ITApO2lmKCF0KXJldHVybiByO2NvbnN0IG89W3IsbmV3IFByb21pc2UoZT0+e3JldHVybiJvYmplY3QiPT10eXBlb2Yobj1zZXRUaW1lb3V0KCgpPT5lKCExKSx0KSkmJiJmdW5jdGlvbiI9PXR5cGVvZiBuLnVucmVmJiZuLnVucmVmKCksbjt2YXIgbn0pXTtyZXR1cm4gUHJvbWlzZS5yYWNlKG8pfX19ZnVuY3Rpb24gX3QodCx7c3RhdHVzQ29kZTplLGhlYWRlcnM6bn0scj1JKCkpe2NvbnN0IG89ey4uLnR9LHM9bj8uWyJ4LXNlbnRyeS1yYXRlLWxpbWl0cyJdLGk9bj8uWyJyZXRyeS1hZnRlciJdO2lmKHMpZm9yKGNvbnN0IHQgb2Ygcy50cmltKCkuc3BsaXQoIiwiKSl7Y29uc3RbZSxuLCwsc109dC5zcGxpdCgiOiIsNSksaT1wYXJzZUludChlLDEwKSxjPTFlMyooaXNOYU4oaSk/NjA6aSk7aWYobilmb3IoY29uc3QgdCBvZiBuLnNwbGl0KCI7IikpIm1ldHJpY19idWNrZXQiPT09dCYmcyYmIXMuc3BsaXQoIjsiKS5pbmNsdWRlcygiY3VzdG9tIil8fChvW3RdPXIrYyk7ZWxzZSBvLmFsbD1yK2N9ZWxzZSBpP28uYWxsPXIrZnVuY3Rpb24odCxlPUkoKSl7Y29uc3Qgbj1wYXJzZUludChgJHt0fWAsMTApO2lmKCFpc05hTihuKSlyZXR1cm4gMWUzKm47Y29uc3Qgcj1EYXRlLnBhcnNlKGAke3R9YCk7cmV0dXJuIGlzTmFOKHIpPzZlNDpyLWV9KGkscik6NDI5PT09ZSYmKG8uYWxsPXIrNmU0KTtyZXR1cm4gb31mdW5jdGlvbiAkdCh0LGUsbj1TdCh0LmJ1ZmZlclNpemV8fDY0KSl7bGV0IHI9e307cmV0dXJue3NlbmQ6ZnVuY3Rpb24odCl7Y29uc3Qgbz1bXTtpZihodCh0LCh0LGUpPT57Y29uc3Qgbj1ndChlKTsoZnVuY3Rpb24odCxlLG49SSgpKXtyZXR1cm4gZnVuY3Rpb24odCxlKXtyZXR1cm4gdFtlXXx8dC5hbGx8fDB9KHQsZSk+bn0pKHIsbil8fG8ucHVzaCh0KX0pLDA9PT1vLmxlbmd0aClyZXR1cm4gUHJvbWlzZS5yZXNvbHZlKHt9KTtjb25zdCBzPWZ0KHRbMF0sbyksaT10PT57IWZ1bmN0aW9uKHQsZSl7cmV0dXJuIGh0KHQsKHQsbik9PmUuaW5jbHVkZXMobikpfShzLFsiY2xpZW50X3JlcG9ydCJdKT9odChzLCh0LGUpPT57fSk6aCYmXy53YXJuKGBEcm9wcGluZyBjbGllbnQgcmVwb3J0LiBXaWxsIG5vdCBzZW5kIG91dGNvbWVzIChyZWFzb246ICR7dH0pLmApfTtyZXR1cm4gbi5hZGQoKCk9PmUoe2JvZHk6bHQocyl9KS50aGVuKHQ9PjQxMz09PXQuc3RhdHVzQ29kZT8oaCYmXy5lcnJvcigiU2VudHJ5IHJlc3BvbmRlZCB3aXRoIHN0YXR1cyBjb2RlIDQxMy4gRW52ZWxvcGUgd2FzIGRpc2NhcmRlZCBkdWUgdG8gZXhjZWVkaW5nIHNpemUgbGltaXRzLiIpLGkoInNlbmRfZXJyb3IiKSx0KTooaCYmdm9pZCAwIT09dC5zdGF0dXNDb2RlJiYodC5zdGF0dXNDb2RlPDIwMHx8dC5zdGF0dXNDb2RlPj0zMDApJiZfLndhcm4oYFNlbnRyeSByZXNwb25kZWQgd2l0aCBzdGF0dXMgY29kZSAke3Quc3RhdHVzQ29kZX0gdG8gc2VudCBldmVudC5gKSxyPV90KHIsdCksdCksdD0+e3Rocm93IGkoIm5ldHdvcmtfZXJyb3IiKSxoJiZfLmVycm9yKCJFbmNvdW50ZXJlZCBlcnJvciBydW5uaW5nIHRyYW5zcG9ydCByZXF1ZXN0OiIsdCksdH0pKS50aGVuKHQ9PnQsdD0+e2lmKHQ9PT13dClyZXR1cm4gaCYmXy5lcnJvcigiU2tpcHBlZCBzZW5kaW5nIGV2ZW50IGJlY2F1c2UgYnVmZmVyIGlzIGZ1bGwuIiksaSgicXVldWVfb3ZlcmZsb3ciKSxQcm9taXNlLnJlc29sdmUoe30pO3Rocm93IHR9KX0sZmx1c2g6dD0+bi5kcmFpbih0KX19Y29uc3QgRXQ9L14oXFMrOlxcfFwvPykoW1xzXFNdKj8pKCg/OlwuezEsMn18W14vXFxdKz98KShcLlteLi9cXF0qfCkpKD86Wy9cXF0qKSQvO2Z1bmN0aW9uIHh0KHQpe2NvbnN0IGU9ZnVuY3Rpb24odCl7Y29uc3QgZT10Lmxlbmd0aD4xMDI0P2A8dHJ1bmNhdGVkPiR7dC5zbGljZSgtMTAyNCl9YDp0LG49RXQuZXhlYyhlKTtyZXR1cm4gbj9uLnNsaWNlKDEpOltdfSh0KSxuPWVbMF18fCIiO2xldCByPWVbMV07cmV0dXJuIG58fHI/KHImJihyPXIuc2xpY2UoMCxyLmxlbmd0aC0xKSksbityKToiLiJ9ZnVuY3Rpb24gTnQodCxlPSExKXtyZXR1cm4hKGV8fHQmJiF0LnN0YXJ0c1dpdGgoIi8iKSYmIXQubWF0Y2goL15bQS1aXTovKSYmIXQuc3RhcnRzV2l0aCgiLiIpJiYhdC5tYXRjaCgvXlthLXpBLVpdKFthLXpBLVowLTkuXC0rXSkqOlwvXC8vKSkmJnZvaWQgMCE9PXQmJiF0LmluY2x1ZGVzKCJub2RlX21vZHVsZXMvIil9dmFyIEN0O2NvbnN0IGp0PVN5bWJvbCgiQWdlbnRCYXNlSW50ZXJuYWxTdGF0ZSIpO2NsYXNzIE90IGV4dGVuZHMoQ3Q9cy5BZ2VudCxDdCl7Y29uc3RydWN0b3IodCl7c3VwZXIodCksdGhpc1tqdF09e319aXNTZWN1cmVFbmRwb2ludCh0KXtpZih0KXtpZigiYm9vbGVhbiI9PXR5cGVvZiB0LnNlY3VyZUVuZHBvaW50KXJldHVybiB0LnNlY3VyZUVuZHBvaW50O2lmKCJzdHJpbmciPT10eXBlb2YgdC5wcm90b2NvbClyZXR1cm4iaHR0cHM6Ij09PXQucHJvdG9jb2x9Y29uc3R7c3RhY2s6ZX09bmV3IEVycm9yO3JldHVybiJzdHJpbmciPT10eXBlb2YgZSYmZS5zcGxpdCgiXG4iKS5zb21lKHQ9Pi0xIT09dC5pbmRleE9mKCIoaHR0cHMuanM6Iil8fC0xIT09dC5pbmRleE9mKCJub2RlOmh0dHBzOiIpKX1jcmVhdGVTb2NrZXQodCxlLG4pe2NvbnN0IHI9ey4uLmUsc2VjdXJlRW5kcG9pbnQ6dGhpcy5pc1NlY3VyZUVuZHBvaW50KGUpfTtQcm9taXNlLnJlc29sdmUoKS50aGVuKCgpPT50aGlzLmNvbm5lY3QodCxyKSkudGhlbihvPT57aWYobyBpbnN0YW5jZW9mIHMuQWdlbnQpcmV0dXJuIG8uYWRkUmVxdWVzdCh0LHIpO3RoaXNbanRdLmN1cnJlbnRTb2NrZXQ9byxzdXBlci5jcmVhdGVTb2NrZXQodCxlLG4pfSxuKX1jcmVhdGVDb25uZWN0aW9uKCl7Y29uc3QgdD10aGlzW2p0XS5jdXJyZW50U29ja2V0O2lmKHRoaXNbanRdLmN1cnJlbnRTb2NrZXQ9dm9pZCAwLCF0KXRocm93IG5ldyBFcnJvcigiTm8gc29ja2V0IHdhcyByZXR1cm5lZCBpbiB0aGUgYGNvbm5lY3QoKWAgZnVuY3Rpb24iKTtyZXR1cm4gdH1nZXQgZGVmYXVsdFBvcnQoKXtyZXR1cm4gdGhpc1tqdF0uZGVmYXVsdFBvcnQ/PygiaHR0cHM6Ij09PXRoaXMucHJvdG9jb2w/NDQzOjgwKX1zZXQgZGVmYXVsdFBvcnQodCl7dGhpc1tqdF0mJih0aGlzW2p0XS5kZWZhdWx0UG9ydD10KX1nZXQgcHJvdG9jb2woKXtyZXR1cm4gdGhpc1tqdF0ucHJvdG9jb2w/Pyh0aGlzLmlzU2VjdXJlRW5kcG9pbnQoKT8iaHR0cHM6IjoiaHR0cDoiKX1zZXQgcHJvdG9jb2wodCl7dGhpc1tqdF0mJih0aGlzW2p0XS5wcm90b2NvbD10KX19ZnVuY3Rpb24gUHQoLi4udCl7Xy5sb2coIltodHRwcy1wcm94eS1hZ2VudDpwYXJzZS1wcm94eS1yZXNwb25zZV0iLC4uLnQpfWZ1bmN0aW9uIEF0KHQpe3JldHVybiBuZXcgUHJvbWlzZSgoZSxuKT0+e2xldCByPTA7Y29uc3Qgbz1bXTtmdW5jdGlvbiBzKCl7Y29uc3QgYz10LnJlYWQoKTtjP2Z1bmN0aW9uKGMpe28ucHVzaChjKSxyKz1jLmxlbmd0aDtjb25zdCB1PUJ1ZmZlci5jb25jYXQobyxyKSxhPXUuaW5kZXhPZigiXHJcblxyXG4iKTtpZigtMT09PWEpcmV0dXJuIFB0KCJoYXZlIG5vdCByZWNlaXZlZCBlbmQgb2YgSFRUUCBoZWFkZXJzIHlldC4uLiIpLHZvaWQgcygpO2NvbnN0IGY9dS5zdWJhcnJheSgwLGEpLnRvU3RyaW5nKCJhc2NpaSIpLnNwbGl0KCJcclxuIiksaD1mLnNoaWZ0KCk7aWYoIWgpcmV0dXJuIHQuZGVzdHJveSgpLG4obmV3IEVycm9yKCJObyBoZWFkZXIgcmVjZWl2ZWQgZnJvbSBwcm94eSBDT05ORUNUIHJlc3BvbnNlIikpO2NvbnN0IHA9aC5zcGxpdCgiICIpLGw9KyhwWzFdfHwwKSxkPXAuc2xpY2UoMikuam9pbigiICIpLGc9e307Zm9yKGNvbnN0IGUgb2YgZil7aWYoIWUpY29udGludWU7Y29uc3Qgcj1lLmluZGV4T2YoIjoiKTtpZigtMT09PXIpcmV0dXJuIHQuZGVzdHJveSgpLG4obmV3IEVycm9yKGBJbnZhbGlkIGhlYWRlciBmcm9tIHByb3h5IENPTk5FQ1QgcmVzcG9uc2U6ICIke2V9ImApKTtjb25zdCBvPWUuc2xpY2UoMCxyKS50b0xvd2VyQ2FzZSgpLHM9ZS5zbGljZShyKzEpLnRyaW1TdGFydCgpLGk9Z1tvXTsic3RyaW5nIj09dHlwZW9mIGk/Z1tvXT1baSxzXTpBcnJheS5pc0FycmF5KGkpP2kucHVzaChzKTpnW29dPXN9UHQoImdvdCBwcm94eSBzZXJ2ZXIgcmVzcG9uc2U6ICVvICVvIixoLGcpLGkoKSxlKHtjb25uZWN0OntzdGF0dXNDb2RlOmwsc3RhdHVzVGV4dDpkLGhlYWRlcnM6Z30sYnVmZmVyZWQ6dX0pfShjKTp0Lm9uY2UoInJlYWRhYmxlIixzKX1mdW5jdGlvbiBpKCl7dC5yZW1vdmVMaXN0ZW5lcigiZW5kIixjKSx0LnJlbW92ZUxpc3RlbmVyKCJlcnJvciIsdSksdC5yZW1vdmVMaXN0ZW5lcigicmVhZGFibGUiLHMpfWZ1bmN0aW9uIGMoKXtpKCksUHQoIm9uZW5kIiksbihuZXcgRXJyb3IoIlByb3h5IGNvbm5lY3Rpb24gZW5kZWQgYmVmb3JlIHJlY2VpdmluZyBDT05ORUNUIHJlc3BvbnNlIikpfWZ1bmN0aW9uIHUodCl7aSgpLFB0KCJvbmVycm9yICVvIix0KSxuKHQpfXQub24oImVycm9yIix1KSx0Lm9uKCJlbmQiLGMpLHMoKX0pfWZ1bmN0aW9uIFR0KC4uLnQpe18ubG9nKCJbaHR0cHMtcHJveHktYWdlbnRdIiwuLi50KX1jbGFzcyBrdCBleHRlbmRzIE90e2NvbnN0cnVjdG9yKHQsZSl7c3VwZXIoZSksdGhpcy5vcHRpb25zPXt9LHRoaXMucHJveHk9InN0cmluZyI9PXR5cGVvZiB0P25ldyBVUkwodCk6dCx0aGlzLnByb3h5SGVhZGVycz1lPy5oZWFkZXJzPz97fSxUdCgiQ3JlYXRpbmcgbmV3IEh0dHBzUHJveHlBZ2VudCBpbnN0YW5jZTogJW8iLHRoaXMucHJveHkuaHJlZik7Y29uc3Qgbj0odGhpcy5wcm94eS5ob3N0bmFtZXx8dGhpcy5wcm94eS5ob3N0KS5yZXBsYWNlKC9eXFt8XF0kL2csIiIpLHI9dGhpcy5wcm94eS5wb3J0P3BhcnNlSW50KHRoaXMucHJveHkucG9ydCwxMCk6Imh0dHBzOiI9PT10aGlzLnByb3h5LnByb3RvY29sPzQ0Mzo4MDt0aGlzLmNvbm5lY3RPcHRzPXtBTFBOUHJvdG9jb2xzOlsiaHR0cC8xLjEiXSwuLi5lP0l0KGUsImhlYWRlcnMiKTpudWxsLGhvc3Q6bixwb3J0OnJ9fWFzeW5jIGNvbm5lY3QodCxlKXtjb25zdHtwcm94eTpufT10aGlzO2lmKCFlLmhvc3QpdGhyb3cgbmV3IFR5cGVFcnJvcignTm8gImhvc3QiIHByb3ZpZGVkJyk7bGV0IHI7aWYoImh0dHBzOiI9PT1uLnByb3RvY29sKXtUdCgiQ3JlYXRpbmcgYHRscy5Tb2NrZXRgOiAlbyIsdGhpcy5jb25uZWN0T3B0cyk7Y29uc3QgdD10aGlzLmNvbm5lY3RPcHRzLnNlcnZlcm5hbWV8fHRoaXMuY29ubmVjdE9wdHMuaG9zdDtyPWYuY29ubmVjdCh7Li4udGhpcy5jb25uZWN0T3B0cyxzZXJ2ZXJuYW1lOnQmJmEuaXNJUCh0KT92b2lkIDA6dH0pfWVsc2UgVHQoIkNyZWF0aW5nIGBuZXQuU29ja2V0YDogJW8iLHRoaXMuY29ubmVjdE9wdHMpLHI9YS5jb25uZWN0KHRoaXMuY29ubmVjdE9wdHMpO2NvbnN0IG89ImZ1bmN0aW9uIj09dHlwZW9mIHRoaXMucHJveHlIZWFkZXJzP3RoaXMucHJveHlIZWFkZXJzKCk6ey4uLnRoaXMucHJveHlIZWFkZXJzfSxzPWEuaXNJUHY2KGUuaG9zdCk/YFske2UuaG9zdH1dYDplLmhvc3Q7bGV0IGk9YENPTk5FQ1QgJHtzfToke2UucG9ydH0gSFRUUC8xLjFcclxuYDtpZihuLnVzZXJuYW1lfHxuLnBhc3N3b3JkKXtjb25zdCB0PWAke2RlY29kZVVSSUNvbXBvbmVudChuLnVzZXJuYW1lKX06JHtkZWNvZGVVUklDb21wb25lbnQobi5wYXNzd29yZCl9YDtvWyJQcm94eS1BdXRob3JpemF0aW9uIl09YEJhc2ljICR7QnVmZmVyLmZyb20odCkudG9TdHJpbmcoImJhc2U2NCIpfWB9by5Ib3N0PWAke3N9OiR7ZS5wb3J0fWAsb1siUHJveHktQ29ubmVjdGlvbiJdfHwob1siUHJveHktQ29ubmVjdGlvbiJdPXRoaXMua2VlcEFsaXZlPyJLZWVwLUFsaXZlIjoiY2xvc2UiKTtmb3IoY29uc3QgdCBvZiBPYmplY3Qua2V5cyhvKSlpKz1gJHt0fTogJHtvW3RdfVxyXG5gO2NvbnN0IGM9QXQocik7ci53cml0ZShgJHtpfVxyXG5gKTtjb25zdHtjb25uZWN0OnUsYnVmZmVyZWQ6aH09YXdhaXQgYztpZih0LmVtaXQoInByb3h5Q29ubmVjdCIsdSksdGhpcy5lbWl0KCJwcm94eUNvbm5lY3QiLHUsdCksMjAwPT09dS5zdGF0dXNDb2RlKXtpZih0Lm9uY2UoInNvY2tldCIsUnQpLGUuc2VjdXJlRW5kcG9pbnQpe1R0KCJVcGdyYWRpbmcgc29ja2V0IGNvbm5lY3Rpb24gdG8gVExTIik7Y29uc3QgdD1lLnNlcnZlcm5hbWV8fGUuaG9zdDtyZXR1cm4gZi5jb25uZWN0KHsuLi5JdChlLCJob3N0IiwicGF0aCIsInBvcnQiKSxzb2NrZXQ6cixzZXJ2ZXJuYW1lOmEuaXNJUCh0KT92b2lkIDA6dH0pfXJldHVybiByfXIuZGVzdHJveSgpO2NvbnN0IHA9bmV3IGEuU29ja2V0KHt3cml0YWJsZTohMX0pO3JldHVybiBwLnJlYWRhYmxlPSEwLHQub25jZSgic29ja2V0Iix0PT57VHQoIlJlcGxheWluZyBwcm94eSBidWZmZXIgZm9yIGZhaWxlZCByZXF1ZXN0IiksdC5wdXNoKGgpLHQucHVzaChudWxsKX0pLHB9fWZ1bmN0aW9uIFJ0KHQpe3QucmVzdW1lKCl9ZnVuY3Rpb24gSXQodCwuLi5lKXtjb25zdCBuPXt9O2xldCByO2ZvcihyIGluIHQpZS5pbmNsdWRlcyhyKXx8KG5bcl09dFtyXSk7cmV0dXJuIG59a3QucHJvdG9jb2xzPVsiaHR0cCIsImh0dHBzIl07ZnVuY3Rpb24gRHQodCl7cmV0dXJuIHQucmVwbGFjZSgvXltBLVpdOi8sIiIpLnJlcGxhY2UoL1xcL2csIi8iKX1jb25zdCBVdD1lO2xldCBCdCxMdD0wLE10PXt9O2Z1bmN0aW9uIHp0KHQpe1V0LmRlYnVnJiZjb25zb2xlLmxvZyhgW0FOUiBXb3JrZXJdICR7dH1gKX12YXIgSnQsV3QsRnQ7Y29uc3QgR3Q9ZnVuY3Rpb24odCl7bGV0IGU7dHJ5e2U9bmV3IFVSTCh0LnVybCl9Y2F0Y2h7cmV0dXJuIGIoKCk9Pntjb25zb2xlLndhcm4oIltAc2VudHJ5L25vZGVdOiBJbnZhbGlkIGRzbiBvciB0dW5uZWwgb3B0aW9uLCB3aWxsIG5vdCBzZW5kIGFueSBldmVudHMuIFRoZSB0dW5uZWwgb3B0aW9uIG11c3QgYmUgYSBmdWxsIFVSTCB3aGVuIHVzZWQuIil9KSwkdCh0LCgpPT5Qcm9taXNlLnJlc29sdmUoe30pKX1jb25zdCBuPSJodHRwczoiPT09ZS5wcm90b2NvbCxyPWZ1bmN0aW9uKHQsZSl7Y29uc3R7bm9fcHJveHk6bn09cHJvY2Vzcy5lbnYscj1uPy5zcGxpdCgiLCIpLnNvbWUoZT0+dC5ob3N0LmVuZHNXaXRoKGUpfHx0Lmhvc3RuYW1lLmVuZHNXaXRoKGUpKTtyZXR1cm4gcj92b2lkIDA6ZX0oZSx0LnByb3h5fHwobj9wcm9jZXNzLmVudi5odHRwc19wcm94eTp2b2lkIDApfHxwcm9jZXNzLmVudi5odHRwX3Byb3h5KSxvPW4/aTpzLGE9dC5rZWVwQWxpdmU/PyEwLGY9cj9uZXcga3Qocik6bmV3IG8uQWdlbnQoe2tlZXBBbGl2ZTphLG1heFNvY2tldHM6MzAsdGltZW91dDoyZTN9KSxoPWZ1bmN0aW9uKHQsZSxuKXtjb25zdHtob3N0bmFtZTpyLHBhdGhuYW1lOm8scG9ydDpzLHByb3RvY29sOmksc2VhcmNoOmF9PW5ldyBVUkwodC51cmwpO3JldHVybiBmdW5jdGlvbihmKXtjb25zdCBoPXA9Pm5ldyBQcm9taXNlKChsLGQpPT57eXQoKCk9PntsZXQgZz1mdW5jdGlvbih0KXtyZXR1cm4gbmV3IGMoe3JlYWQoKXt0aGlzLnB1c2godCksdGhpcy5wdXNoKG51bGwpfX0pfShmLmJvZHkpO2NvbnN0IG09ey4uLnQuaGVhZGVyc307Zi5ib2R5Lmxlbmd0aD4zMjc2OCYmKG1bImNvbnRlbnQtZW5jb2RpbmciXT0iZ3ppcCIsZz1nLnBpcGUodSgpKSk7Y29uc3QgeT1yLnN0YXJ0c1dpdGgoIlsiKSxiPWUucmVxdWVzdCh7bWV0aG9kOiJQT1NUIixhZ2VudDpuLGhlYWRlcnM6bSxob3N0bmFtZTp5P3Iuc2xpY2UoMSwtMSk6cixwYXRoOmAke299JHthfWAscG9ydDpzLHByb3RvY29sOmksY2E6dC5jYUNlcnRzfSx0PT57dC5vbigiZGF0YSIsKCk9Pnt9KSx0Lm9uKCJlbmQiLCgpPT57fSksdC5zZXRFbmNvZGluZygidXRmOCIpO2NvbnN0IGU9dC5oZWFkZXJzWyJyZXRyeS1hZnRlciJdPz9udWxsLG49dC5oZWFkZXJzWyJ4LXNlbnRyeS1yYXRlLWxpbWl0cyJdPz9udWxsO2woe3N0YXR1c0NvZGU6dC5zdGF0dXNDb2RlLGhlYWRlcnM6eyJyZXRyeS1hZnRlciI6ZSwieC1zZW50cnktcmF0ZS1saW1pdHMiOkFycmF5LmlzQXJyYXkobik/blswXXx8bnVsbDpufX0pfSk7Yi5vbigiZXJyb3IiLHQ9PntwJiZiLnJldXNlZFNvY2tldCYmIkVDT05OUkVTRVQiPT09dC5jb2RlP2woaCghMSkpOmQodCl9KSxnLnBpcGUoYil9KX0pO3JldHVybiBoKCEwKX19KHQsdC5odHRwTW9kdWxlPz9vLGYpO3JldHVybiAkdCh0LGgpfSh7dXJsOihKdD1VdC5kc24sV3Q9VXQudHVubmVsLEZ0PVV0LnNka01ldGFkYXRhLnNkayxXdHx8YCR7ZnVuY3Rpb24odCl7cmV0dXJuYCR7ZnVuY3Rpb24odCl7Y29uc3QgZT10LnByb3RvY29sP2Ake3QucHJvdG9jb2x9OmA6IiIsbj10LnBvcnQ/YDoke3QucG9ydH1gOiIiO3JldHVybmAke2V9Ly8ke3QuaG9zdH0ke259JHt0LnBhdGg/YC8ke3QucGF0aH1gOiIifS9hcGkvYH0odCl9JHt0LnByb2plY3RJZH0vZW52ZWxvcGUvYH0oSnQpfT8ke2Z1bmN0aW9uKHQsZSl7Y29uc3Qgbj17c2VudHJ5X3ZlcnNpb246IjcifTtyZXR1cm4gdC5wdWJsaWNLZXkmJihuLnNlbnRyeV9rZXk9dC5wdWJsaWNLZXkpLGUmJihuLnNlbnRyeV9jbGllbnQ9YCR7ZS5uYW1lfS8ke2UudmVyc2lvbn1gKSxuZXcgVVJMU2VhcmNoUGFyYW1zKG4pLnRvU3RyaW5nKCl9KEp0LEZ0KX1gKX0pO2FzeW5jIGZ1bmN0aW9uIFl0KCl7aWYoQnQpe3p0KCJTZW5kaW5nIGFibm9ybWFsIHNlc3Npb24iKSxaKEJ0LHtzdGF0dXM6ImFibm9ybWFsIixhYm5vcm1hbF9tZWNoYW5pc206ImFucl9mb3JlZ3JvdW5kIixyZWxlYXNlOlV0LnJlbGVhc2UsZW52aXJvbm1lbnQ6VXQuZW52aXJvbm1lbnR9KTtjb25zdCB0PWZ1bmN0aW9uKHQsZSxuLHIpe2NvbnN0IG89bXQobik7cmV0dXJuIGZ0KHtzZW50X2F0Om5ldyBEYXRlKEkoKSkudG9JU09TdHJpbmcoKSwuLi5vJiZ7c2RrOm99LC4uLiEhciYmZSYme2Rzbjp1dChlKX19LFsiYWdncmVnYXRlcyJpbiB0P1t7dHlwZToic2Vzc2lvbnMifSx0XTpbe3R5cGU6InNlc3Npb24ifSx0LnRvSlNPTigpXV0pfShCdCxVdC5kc24sVXQuc2RrTWV0YWRhdGEsVXQudHVubmVsKTt6dChKU09OLnN0cmluZ2lmeSh0KSksYXdhaXQgR3Quc2VuZCh0KTt0cnl7bj8ucG9zdE1lc3NhZ2UoInNlc3Npb24tZW5kZWQiKX1jYXRjaHt9fX1mdW5jdGlvbiBIdCh0KXtpZighdClyZXR1cm47Y29uc3QgZT1mdW5jdGlvbih0KXtpZighdC5sZW5ndGgpcmV0dXJuW107Y29uc3QgZT1BcnJheS5mcm9tKHQpO3JldHVybi9zZW50cnlXcmFwcGVkLy50ZXN0KEUoZSkuZnVuY3Rpb258fCIiKSYmZS5wb3AoKSxlLnJldmVyc2UoKSwkLnRlc3QoRShlKS5mdW5jdGlvbnx8IiIpJiYoZS5wb3AoKSwkLnRlc3QoRShlKS5mdW5jdGlvbnx8IiIpJiZlLnBvcCgpKSxlLnNsaWNlKDAsNTApLm1hcCh0PT4oey4uLnQsZmlsZW5hbWU6dC5maWxlbmFtZXx8RShlKS5maWxlbmFtZSxmdW5jdGlvbjp0LmZ1bmN0aW9ufHwiPyJ9KSl9KHQpO2lmKFV0LmFwcFJvb3RQYXRoKWZvcihjb25zdCB0IG9mIGUpdC5maWxlbmFtZSYmKHQuZmlsZW5hbWU9TSh0LmZpbGVuYW1lLFV0LmFwcFJvb3RQYXRoKSk7cmV0dXJuIGV9YXN5bmMgZnVuY3Rpb24gWnQodCxlKXtpZihMdD49VXQubWF4QW5yRXZlbnRzKXJldHVybjtMdCs9MSxhd2FpdCBZdCgpLHp0KCJTZW5kaW5nIGV2ZW50Iik7Y29uc3Qgbj17ZXZlbnRfaWQ6VygpLGNvbnRleHRzOlV0LmNvbnRleHRzLHJlbGVhc2U6VXQucmVsZWFzZSxlbnZpcm9ubWVudDpVdC5lbnZpcm9ubWVudCxkaXN0OlV0LmRpc3QscGxhdGZvcm06Im5vZGUiLGxldmVsOiJlcnJvciIsZXhjZXB0aW9uOnt2YWx1ZXM6W3t0eXBlOiJBcHBsaWNhdGlvbk5vdFJlc3BvbmRpbmciLHZhbHVlOmBBcHBsaWNhdGlvbiBOb3QgUmVzcG9uZGluZyBmb3IgYXQgbGVhc3QgJHtVdC5hbnJUaHJlc2hvbGR9IG1zYCxzdGFja3RyYWNlOntmcmFtZXM6SHQodCl9LG1lY2hhbmlzbTp7dHlwZToiQU5SIn19XX0sdGFnczpVdC5zdGF0aWNUYWdzfTtlJiZmdW5jdGlvbih0LGUpe2lmKGF0KHQsZSksIXQuY29udGV4dHM/LnRyYWNlKXtjb25zdHt0cmFjZUlkOm4scGFyZW50U3BhbklkOnIscHJvcGFnYXRpb25TcGFuSWQ6b309ZS5wcm9wYWdhdGlvbkNvbnRleHQ7dC5jb250ZXh0cz17dHJhY2U6e3RyYWNlX2lkOm4sc3Bhbl9pZDpvfHxXKCkuc3Vic3RyaW5nKDE2KSxwYXJlbnRfc3Bhbl9pZDpyfSwuLi50LmNvbnRleHRzfX19KG4sZSksZnVuY3Rpb24odCl7aWYoMD09PU9iamVjdC5rZXlzKE10KS5sZW5ndGgpcmV0dXJuO2NvbnN0IGU9VXQuYXBwUm9vdFBhdGg/e306TXQ7aWYoVXQuYXBwUm9vdFBhdGgpZm9yKGNvbnN0W3Qsbl1vZiBPYmplY3QuZW50cmllcyhNdCkpZVtNKHQsVXQuYXBwUm9vdFBhdGgpXT1uO2NvbnN0IG49bmV3IE1hcDtmb3IoY29uc3QgciBvZiB0LmV4Y2VwdGlvbj8udmFsdWVzfHxbXSlmb3IoY29uc3QgdCBvZiByLnN0YWNrdHJhY2U/LmZyYW1lc3x8W10pe2NvbnN0IHI9dC5hYnNfcGF0aHx8dC5maWxlbmFtZTtyJiZlW3JdJiZuLnNldChyLGVbcl0pfWlmKG4uc2l6ZT4wKXtjb25zdCBlPVtdO2Zvcihjb25zdFt0LHJdb2Ygbi5lbnRyaWVzKCkpZS5wdXNoKHt0eXBlOiJzb3VyY2VtYXAiLGNvZGVfZmlsZTp0LGRlYnVnX2lkOnJ9KTt0LmRlYnVnX21ldGE9e2ltYWdlczplfX19KG4pO2NvbnN0IHI9YnQobixVdC5kc24sVXQuc2RrTWV0YWRhdGEsVXQudHVubmVsKTt6dChKU09OLnN0cmluZ2lmeShyKSksYXdhaXQgR3Quc2VuZChyKSxhd2FpdCBHdC5mbHVzaCgyZTMpLEx0Pj1VdC5tYXhBbnJFdmVudHMmJnNldFRpbWVvdXQoKCk9Pntwcm9jZXNzLmV4aXQoMCl9LDVlMyl9bGV0IHF0O2lmKHp0KCJTdGFydGVkIiksVXQuY2FwdHVyZVN0YWNrVHJhY2Upe3p0KCJDb25uZWN0aW5nIHRvIGRlYnVnZ2VyIik7Y29uc3QgZT1uZXcgdDtlLmNvbm5lY3RUb01haW5UaHJlYWQoKSx6dCgiQ29ubmVjdGVkIHRvIGRlYnVnZ2VyIik7Y29uc3Qgbj1uZXcgTWFwO2Uub24oIkRlYnVnZ2VyLnNjcmlwdFBhcnNlZCIsdD0+e24uc2V0KHQucGFyYW1zLnNjcmlwdElkLHQucGFyYW1zLnVybCl9KSxlLm9uKCJEZWJ1Z2dlci5wYXVzZWQiLHQ9PntpZigib3RoZXIiPT09dC5wYXJhbXMucmVhc29uKXRyeXt6dCgiRGVidWdnZXIgcGF1c2VkIik7Y29uc3Qgcz1bLi4udC5wYXJhbXMuY2FsbEZyYW1lc10saT1VdC5hcHBSb290UGF0aD9mdW5jdGlvbih0PShwcm9jZXNzLmFyZ3ZbMV0/eHQocHJvY2Vzcy5hcmd2WzFdKTpwcm9jZXNzLmN3ZCgpKSxlPSJcXCI9PT1vKXtjb25zdCBuPWU/RHQodCk6dDtyZXR1cm4gdD0+e2lmKCF0KXJldHVybjtjb25zdCBvPWU/RHQodCk6dDtsZXR7ZGlyOnMsYmFzZTppLGV4dDpjfT1yLnBhcnNlKG8pOyIuanMiIT09YyYmIi5tanMiIT09YyYmIi5janMiIT09Y3x8KGk9aS5zbGljZSgwLC0xKmMubGVuZ3RoKSk7Y29uc3QgdT1kZWNvZGVVUklDb21wb25lbnQoaSk7c3x8KHM9Ii4iKTtjb25zdCBhPXMubGFzdEluZGV4T2YoIi9ub2RlX21vZHVsZXMiKTtpZihhPi0xKXJldHVybmAke3Muc2xpY2UoYSsxNCkucmVwbGFjZSgvXC8vZywiLiIpfToke3V9YDtpZihzLnN0YXJ0c1dpdGgobikpe2NvbnN0IHQ9cy5zbGljZShuLmxlbmd0aCsxKS5yZXBsYWNlKC9cLy9nLCIuIik7cmV0dXJuIHQ/YCR7dH06JHt1fWA6dX1yZXR1cm4gdX19KFV0LmFwcFJvb3RQYXRoKTooKT0+e30sYz1zLm1hcCh0PT5mdW5jdGlvbih0LGUsbil7Y29uc3Qgcj1lP2UucmVwbGFjZSgvXmZpbGU6XC9cLy8sIiIpOnZvaWQgMCxvPXQubG9jYXRpb24uY29sdW1uTnVtYmVyP3QubG9jYXRpb24uY29sdW1uTnVtYmVyKzE6dm9pZCAwLHM9dC5sb2NhdGlvbi5saW5lTnVtYmVyP3QubG9jYXRpb24ubGluZU51bWJlcisxOnZvaWQgMDtyZXR1cm57ZmlsZW5hbWU6cixtb2R1bGU6bihyKSxmdW5jdGlvbjp0LmZ1bmN0aW9uTmFtZXx8Ij8iLGNvbG5vOm8sbGluZW5vOnMsaW5fYXBwOnI/TnQocik6dm9pZCAwfX0odCxuLmdldCh0LmxvY2F0aW9uLnNjcmlwdElkKSxpKSksdT1zZXRUaW1lb3V0KCgpPT57WnQoYykudGhlbihudWxsLCgpPT57enQoIlNlbmRpbmcgQU5SIGV2ZW50IGZhaWxlZC4iKX0pfSw1ZTMpO2UucG9zdCgiUnVudGltZS5ldmFsdWF0ZSIse2V4cHJlc3Npb246Imdsb2JhbC5fX1NFTlRSWV9HRVRfU0NPUEVTX18oKTsiLHNpbGVudDohMCxyZXR1cm5CeVZhbHVlOiEwfSwodCxuKT0+e3QmJnp0KGBFcnJvciBleGVjdXRpbmcgc2NyaXB0OiAnJHt0Lm1lc3NhZ2V9J2ApLGNsZWFyVGltZW91dCh1KTtjb25zdCByPW4/LnJlc3VsdD9uLnJlc3VsdC52YWx1ZTp2b2lkIDA7ZS5wb3N0KCJEZWJ1Z2dlci5yZXN1bWUiKSxlLnBvc3QoIkRlYnVnZ2VyLmRpc2FibGUiKSxadChjLHIpLnRoZW4obnVsbCwoKT0+e3p0KCJTZW5kaW5nIEFOUiBldmVudCBmYWlsZWQuIil9KX0pfWNhdGNoKHQpe3Rocm93IGUucG9zdCgiRGVidWdnZXIucmVzdW1lIiksZS5wb3N0KCJEZWJ1Z2dlci5kaXNhYmxlIiksdH19KSxxdD0oKT0+e3RyeXtlLnBvc3QoIkRlYnVnZ2VyLmVuYWJsZSIsKCk9PntlLnBvc3QoIkRlYnVnZ2VyLnBhdXNlIil9KX1jYXRjaHt9fX1jb25zdHtwb2xsOkt0fT1mdW5jdGlvbih0LGUsbixyKXtjb25zdCBvPXQoKTtsZXQgcz0hMSxpPSEwO3JldHVybiBzZXRJbnRlcnZhbCgoKT0+e2NvbnN0IHQ9by5nZXRUaW1lTXMoKTshMT09PXMmJnQ+ZStuJiYocz0hMCxpJiZyKCkpLHQ8ZStuJiYocz0hMSl9LDIwKSx7cG9sbDooKT0+e28ucmVzZXQoKX0sZW5hYmxlZDp0PT57aT10fX19KGZ1bmN0aW9uKCl7bGV0IHQ9cHJvY2Vzcy5ocnRpbWUoKTtyZXR1cm57Z2V0VGltZU1zOigpPT57Y29uc3RbZSxuXT1wcm9jZXNzLmhydGltZSh0KTtyZXR1cm4gTWF0aC5mbG9vcigxZTMqZStuLzFlNil9LHJlc2V0OigpPT57dD1wcm9jZXNzLmhydGltZSgpfX19LFV0LnBvbGxJbnRlcnZhbCxVdC5hbnJUaHJlc2hvbGQsZnVuY3Rpb24oKXt6dCgiV2F0Y2hkb2cgdGltZW91dCIpLHF0Pyh6dCgiUGF1c2luZyBkZWJ1Z2dlciB0byBjYXB0dXJlIHN0YWNrIHRyYWNlIikscXQoKSk6KHp0KCJDYXB0dXJpbmcgZXZlbnQgd2l0aG91dCBhIHN0YWNrIHRyYWNlIiksWnQoKS50aGVuKG51bGwsKCk9Pnt6dCgiU2VuZGluZyBBTlIgZXZlbnQgZmFpbGVkIG9uIHdhdGNoZG9nIHRpbWVvdXQuIil9KSl9KTtuPy5vbigibWVzc2FnZSIsdD0+e3Quc2Vzc2lvbiYmKEJ0PUgodC5zZXNzaW9uKSksdC5kZWJ1Z0ltYWdlcyYmKE10PXQuZGVidWdJbWFnZXMpLEt0KCl9KTs=";
10
10
  const DEFAULT_INTERVAL = 50;
11
11
  const DEFAULT_HANG_THRESHOLD = 5e3;
12
12
  function log(message, ...args) {
@@ -1 +1 @@
1
- {"version":3,"file":"httpServerSpansIntegration.js","sources":["../../../../src/integrations/http/httpServerSpansIntegration.ts"],"sourcesContent":["/* eslint-disable max-lines */\nimport { errorMonitor } from 'node:events';\nimport {\n CLIENT_ADDRESS,\n CLIENT_PORT,\n HTTP_REQUEST_METHOD,\n HTTP_RESPONSE_STATUS_CODE,\n NETWORK_LOCAL_ADDRESS,\n NETWORK_LOCAL_PORT,\n NETWORK_PEER_ADDRESS,\n NETWORK_PEER_PORT,\n NETWORK_PROTOCOL_NAME,\n NETWORK_PROTOCOL_VERSION,\n NETWORK_TRANSPORT,\n SENTRY_HTTP_PREFETCH,\n SENTRY_KIND,\n SENTRY_OP,\n SENTRY_SEGMENT_NAME_SOURCE,\n SERVER_ADDRESS,\n SERVER_PORT,\n URL_FRAGMENT,\n URL_FULL,\n URL_PATH,\n URL_QUERY,\n URL_SCHEME,\n USER_AGENT_ORIGINAL,\n} from '@sentry/conventions/attributes';\nimport { HTTP_SERVER } from '@sentry/conventions/op';\nimport type { Event, Integration, IntegrationFn, Span, SpanAttributes, SpanStatus } from '@sentry/core';\nimport type { HttpIncomingMessage, HttpServerResponse } from '@sentry/core/server';\nimport { DEFAULT_IGNORE_STATUS_CODES, processHttpServerTransactionEvent } from '@sentry/core/server';\nimport {\n debug,\n getSpanStatusFromHttpCode,\n httpHeadersToSpanAttributes,\n getContentLengthFromHeaders,\n parseStringToURLObject,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SPAN_STATUS_ERROR,\n stripUrlQueryAndFragment,\n isTracingSuppressed,\n bindScopeToEmitter,\n startInactiveSpan,\n withActiveSpan,\n getUrlFragment,\n getUrlQuery,\n filterCollectedUrl,\n filterCollectedUrlQuery,\n hasSpanStreamingEnabled,\n HTTP_SPAN_NAME_FALLBACK,\n} from '@sentry/core';\nimport { DEBUG_BUILD } from '../../debug-build';\nimport type { NodeClient } from '../../sdk/client';\nimport { addStartSpanCallback } from './httpServerIntegration';\n\nconst INTEGRATION_NAME = 'Http.ServerSpans' as const;\n\n// Tree-shakable guard to remove all code related to tracing\ndeclare const __SENTRY_TRACING__: boolean;\n\nexport interface HttpServerSpansIntegrationOptions {\n /**\n * Do not capture spans for incoming HTTP requests to URLs where the given callback returns `true`.\n * Spans will be non recording if tracing is disabled.\n *\n * The `urlPath` param consists of the URL path and query string (if any) of the incoming request.\n * For example: `'/users/details?id=123'`\n *\n * The `request` param contains the original {@type IncomingMessage} object of the incoming request.\n * You can use it to filter on additional properties like method, headers, etc.\n */\n ignoreIncomingRequests?: (urlPath: string, request: HttpIncomingMessage) => boolean;\n\n /**\n * Whether to automatically ignore common static asset requests like favicon.ico, robots.txt, etc.\n * This helps reduce noise in your transactions.\n *\n * @default `true`\n */\n ignoreStaticAssets?: boolean;\n\n /**\n * Do not capture spans for incoming HTTP requests with the given status codes.\n * By default, spans with some 3xx and 4xx status codes are ignored (see @default).\n * Expects an array of status codes or a range of status codes, e.g. [[300,399], 404] would ignore 3xx and 404 status codes.\n *\n * @default `[[401, 404], [301, 303], [305, 399]]`\n */\n ignoreStatusCodes?: (number | [number, number])[];\n\n /**\n * A hook that can be used to mutate the span for incoming requests.\n * This is triggered after the span is created, but before it is recorded.\n */\n onSpanCreated?: (span: Span, request: HttpIncomingMessage, response: HttpServerResponse) => void;\n}\n\nconst _httpServerSpansIntegration = ((options: HttpServerSpansIntegrationOptions = {}) => {\n const ignoreStaticAssets = options.ignoreStaticAssets ?? true;\n const ignoreIncomingRequests = options.ignoreIncomingRequests;\n const ignoreStatusCodes = options.ignoreStatusCodes ?? DEFAULT_IGNORE_STATUS_CODES;\n\n const { onSpanCreated } = options;\n\n return {\n name: INTEGRATION_NAME,\n setup(client: NodeClient) {\n // If no tracing, we can just skip everything here\n if (typeof __SENTRY_TRACING__ !== 'undefined' && !__SENTRY_TRACING__) {\n return;\n }\n\n client.on('httpServerRequest', (_request, _response, normalizedRequest) => {\n // Type-casting this here because we do not want to put the node types into core\n const request = _request as HttpIncomingMessage;\n const response = _response as HttpServerResponse;\n\n const startSpan = (next: () => boolean): boolean => {\n if (\n shouldIgnoreSpansForIncomingRequest(request, {\n ignoreStaticAssets,\n ignoreIncomingRequests,\n })\n ) {\n DEBUG_BUILD && debug.log(INTEGRATION_NAME, 'Skipping span creation for incoming request', request.url);\n return next();\n }\n\n const fullUrl = normalizedRequest.url || request.url || '/';\n const urlObj = parseStringToURLObject(fullUrl);\n\n const headers = request.headers;\n const userAgent = headers['user-agent'];\n const httpVersion = request.httpVersion;\n const host = headers.host as string | undefined;\n const hostname = host?.replace(/^(.*)(:[0-9]{1,5})/, '$1') || 'localhost';\n\n const scheme = fullUrl.startsWith('https') ? 'https' : 'http';\n\n const requestMethod = normalizedRequest.method || request.method?.toUpperCase();\n const method = requestMethod || 'GET';\n const httpTargetWithoutQueryFragment = urlObj ? urlObj.pathname : stripUrlQueryAndFragment(fullUrl);\n const bestEffortTransactionName = `${method} ${httpTargetWithoutQueryFragment}`;\n\n const query = getUrlQuery(urlObj?.search);\n const fragment = getUrlFragment(urlObj?.hash);\n\n const span = startInactiveSpan({\n // With span streaming, span names have to be low cardinality, so we can't fall back to the URL path.\n // Route instrumentations rename the span to `${method} ${route}` once a route is known.\n name: hasSpanStreamingEnabled(client)\n ? requestMethod || HTTP_SPAN_NAME_FALLBACK\n : bestEffortTransactionName,\n attributes: {\n // Sentry specific attributes\n [SENTRY_KIND]: 'server',\n [SENTRY_OP]: HTTP_SERVER,\n [SENTRY_SEGMENT_NAME_SOURCE]: 'url',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.http_server',\n [SENTRY_HTTP_PREFETCH]: isKnownPrefetchRequest(request) || undefined,\n [URL_FULL]: filterCollectedUrl(fullUrl, client),\n [URL_PATH]: urlObj?.pathname ?? httpTargetWithoutQueryFragment,\n [URL_QUERY]: filterCollectedUrlQuery(query, client),\n [URL_FRAGMENT]: fragment,\n [HTTP_REQUEST_METHOD]: normalizedRequest.method,\n [USER_AGENT_ORIGINAL]: userAgent,\n [URL_SCHEME]: scheme,\n [SERVER_ADDRESS]: hostname,\n [NETWORK_PROTOCOL_NAME]: 'http',\n [NETWORK_PROTOCOL_VERSION]: httpVersion,\n [NETWORK_TRANSPORT]: httpVersion?.toUpperCase() === 'QUIC' ? 'udp' : 'tcp',\n 'http.request.body.size': getContentLengthFromHeaders(request.headers),\n ...httpHeadersToSpanAttributes(normalizedRequest.headers || {}, client.getDataCollectionOptions()),\n },\n });\n\n onSpanCreated?.(span, request, response);\n\n return withActiveSpan(span, () => {\n bindScopeToEmitter(request);\n bindScopeToEmitter(response);\n\n // Ensure we only end the span once\n // E.g. error can be emitted before close is emitted\n let isEnded = false;\n function endSpan(status: SpanStatus): void {\n if (isEnded) {\n return;\n }\n\n isEnded = true;\n\n const newAttributes = getIncomingRequestAttributesOnResponse(\n request,\n response,\n client.getDataCollectionOptions().userInfo,\n );\n span.setAttributes(newAttributes);\n span.setStatus(status);\n span.end();\n }\n\n response.on('close', () => {\n endSpan(getSpanStatusFromHttpCode(response.statusCode));\n });\n response.on(errorMonitor, () => {\n const httpStatus = getSpanStatusFromHttpCode(response.statusCode);\n // Ensure we def. have an error status here\n endSpan(httpStatus.code === SPAN_STATUS_ERROR ? httpStatus : { code: SPAN_STATUS_ERROR });\n });\n\n return next();\n });\n };\n\n addStartSpanCallback(request, startSpan);\n });\n },\n processEvent(event) {\n return processHttpServerTransactionEvent(event, ignoreStatusCodes);\n },\n afterAllSetup(client) {\n if (!DEBUG_BUILD) {\n return;\n }\n\n if (client.getIntegrationByName('Http')) {\n debug.warn(\n 'It seems that you have manually added `httpServerSpansIntegration` while `httpIntegration` is also present. Make sure to remove `httpIntegration` when adding `httpServerSpansIntegration`.',\n );\n }\n\n if (!client.getIntegrationByName('Http.Server')) {\n debug.error(\n 'It seems that you have manually added `httpServerSpansIntegration` without adding `httpServerIntegration`. This is a requiement for spans to be created - please add the `httpServerIntegration` integration.',\n );\n }\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * This integration emits spans for incoming requests handled via the node `http` module.\n * It requires the `httpServerIntegration` to be present.\n */\nexport const httpServerSpansIntegration = _httpServerSpansIntegration as (\n options?: HttpServerSpansIntegrationOptions,\n) => Integration & {\n name: 'Http.ServerSpans';\n setup: (client: NodeClient) => void;\n processEvent: (event: Event) => Event | null;\n};\n\nfunction isKnownPrefetchRequest(req: HttpIncomingMessage): boolean {\n // Currently only handles Next.js prefetch requests but may check other frameworks in the future.\n return req.headers['next-router-prefetch'] === '1';\n}\n\n/**\n * Check if a request is for a common static asset that should be ignored by default.\n *\n * Only exported for tests.\n */\nexport function isStaticAssetRequest(urlPath: string): boolean {\n const path = stripUrlQueryAndFragment(urlPath);\n // Common static file extensions\n if (path.match(/\\.(ico|png|jpg|jpeg|gif|svg|css|js|woff|woff2|ttf|eot|webp|avif)$/)) {\n return true;\n }\n\n // Common metadata files\n if (path.match(/^\\/(robots\\.txt|sitemap\\.xml|manifest\\.json|browserconfig\\.xml)$/)) {\n return true;\n }\n\n return false;\n}\n\nfunction shouldIgnoreSpansForIncomingRequest(\n request: HttpIncomingMessage,\n {\n ignoreStaticAssets,\n ignoreIncomingRequests,\n }: {\n ignoreStaticAssets?: boolean;\n ignoreIncomingRequests?: (urlPath: string, request: HttpIncomingMessage) => boolean;\n },\n): boolean {\n if (isTracingSuppressed()) {\n return true;\n }\n\n // request.url is the only property that holds any information about the url\n // it only consists of the URL path and query string (if any)\n const urlPath = request.url;\n\n const method = request.method?.toUpperCase();\n // We do not capture OPTIONS/HEAD requests as spans\n if (method === 'OPTIONS' || method === 'HEAD' || !urlPath) {\n return true;\n }\n\n // Default static asset filtering\n if (ignoreStaticAssets && method === 'GET' && isStaticAssetRequest(urlPath)) {\n return true;\n }\n\n if (ignoreIncomingRequests?.(urlPath, request)) {\n return true;\n }\n\n return false;\n}\n\n/**\n * First entry of `X-Forwarded-For`: the client as seen by the outermost proxy.\n * https://opentelemetry.io/docs/specs/semconv/registry/attributes/client/#client-address\n */\nfunction getForwardedClientAddress(forwardedFor: string | string[] | undefined): string | undefined {\n return typeof forwardedFor === 'string' ? forwardedFor.split(',')[0]?.trim() || undefined : undefined;\n}\n\nfunction getIncomingRequestAttributesOnResponse(\n request: HttpIncomingMessage,\n response: HttpServerResponse,\n collectClientAddress: boolean,\n): SpanAttributes {\n // take socket from the request,\n // since it may be detached from the response object in keep-alive mode\n const { socket } = request;\n const { statusCode, statusMessage } = response;\n\n const newAttributes: SpanAttributes = {\n [HTTP_RESPONSE_STATUS_CODE]: statusCode,\n 'http.response.status_text': statusMessage?.toUpperCase(),\n };\n\n if (collectClientAddress) {\n // `client.address` is the originating client, so a forwarding header wins over the socket, which\n // behind a proxy holds the proxy's address. `network.peer.address` below keeps the socket value.\n newAttributes[CLIENT_ADDRESS] =\n getForwardedClientAddress(request.headers['x-forwarded-for']) ?? socket?.remoteAddress;\n }\n\n if (socket) {\n const { localAddress, localPort, remoteAddress, remotePort } = socket;\n newAttributes[SERVER_PORT] = localPort;\n newAttributes[NETWORK_LOCAL_ADDRESS] = localAddress;\n newAttributes[NETWORK_LOCAL_PORT] = localPort;\n newAttributes[CLIENT_PORT] = remotePort;\n newAttributes[NETWORK_PEER_ADDRESS] = collectClientAddress ? remoteAddress : undefined;\n newAttributes[NETWORK_PEER_PORT] = remotePort;\n }\n\n return newAttributes;\n}\n"],"names":["DEFAULT_IGNORE_STATUS_CODES","DEBUG_BUILD","debug","parseStringToURLObject","stripUrlQueryAndFragment","getUrlQuery","getUrlFragment","startInactiveSpan","hasSpanStreamingEnabled","HTTP_SPAN_NAME_FALLBACK","SENTRY_KIND","SENTRY_OP","HTTP_SERVER","SENTRY_SEGMENT_NAME_SOURCE","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","SENTRY_HTTP_PREFETCH","URL_FULL","filterCollectedUrl","URL_PATH","URL_QUERY","filterCollectedUrlQuery","URL_FRAGMENT","HTTP_REQUEST_METHOD","USER_AGENT_ORIGINAL","URL_SCHEME","SERVER_ADDRESS","NETWORK_PROTOCOL_NAME","NETWORK_PROTOCOL_VERSION","NETWORK_TRANSPORT","getContentLengthFromHeaders","httpHeadersToSpanAttributes","withActiveSpan","bindScopeToEmitter","getSpanStatusFromHttpCode","errorMonitor","SPAN_STATUS_ERROR","addStartSpanCallback","processHttpServerTransactionEvent","isTracingSuppressed","HTTP_RESPONSE_STATUS_CODE","CLIENT_ADDRESS","SERVER_PORT","NETWORK_LOCAL_ADDRESS","NETWORK_LOCAL_PORT","CLIENT_PORT","NETWORK_PEER_ADDRESS","NETWORK_PEER_PORT"],"mappings":"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"}
1
+ {"version":3,"file":"httpServerSpansIntegration.js","sources":["../../../../src/integrations/http/httpServerSpansIntegration.ts"],"sourcesContent":["/* eslint-disable max-lines */\nimport { errorMonitor } from 'node:events';\nimport {\n CLIENT_ADDRESS,\n CLIENT_PORT,\n HTTP_REQUEST_METHOD,\n HTTP_RESPONSE_STATUS_CODE,\n NETWORK_LOCAL_ADDRESS,\n NETWORK_LOCAL_PORT,\n NETWORK_PEER_ADDRESS,\n NETWORK_PEER_PORT,\n NETWORK_PROTOCOL_NAME,\n NETWORK_PROTOCOL_VERSION,\n NETWORK_TRANSPORT,\n SENTRY_HTTP_PREFETCH,\n SENTRY_KIND,\n SENTRY_OP,\n SENTRY_SEGMENT_NAME_SOURCE,\n SERVER_ADDRESS,\n SERVER_PORT,\n URL_FRAGMENT,\n URL_FULL,\n URL_PATH,\n URL_QUERY,\n URL_SCHEME,\n USER_AGENT_ORIGINAL,\n} from '@sentry/conventions/attributes';\nimport { HTTP_SERVER } from '@sentry/conventions/op';\nimport type { Event, Integration, IntegrationFn, Span, SpanAttributes, SpanStatus } from '@sentry/core';\nimport type { HttpIncomingMessage, HttpServerResponse } from '@sentry/core/server';\nimport { DEFAULT_IGNORE_STATUS_CODES, processHttpServerTransactionEvent } from '@sentry/core/server';\nimport {\n debug,\n getSpanStatusFromHttpCode,\n httpHeadersToSpanAttributes,\n getContentLengthFromHeaders,\n parseStringToURLObject,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SPAN_STATUS_ERROR,\n stripUrlQueryAndFragment,\n isTracingSuppressed,\n bindScopeToEmitter,\n startInactiveSpan,\n withActiveSpan,\n getUrlFragment,\n getUrlQuery,\n filterCollectedUrl,\n filterCollectedUrlQuery,\n hasSpanStreamingEnabled,\n HTTP_SPAN_NAME_FALLBACK,\n} from '@sentry/core';\nimport { DEBUG_BUILD } from '../../debug-build';\nimport type { NodeClient } from '../../sdk/client';\nimport { addStartSpanCallback } from './httpServerIntegration';\n\nconst INTEGRATION_NAME = 'Http.ServerSpans' as const;\n\n// Tree-shakable guard to remove all code related to tracing\ndeclare const __SENTRY_TRACING__: boolean;\n\nexport interface HttpServerSpansIntegrationOptions {\n /**\n * Do not capture spans for incoming HTTP requests to URLs where the given callback returns `true`.\n * Spans will be non recording if tracing is disabled.\n *\n * The `urlPath` param consists of the URL path and query string (if any) of the incoming request.\n * For example: `'/users/details?id=123'`\n *\n * The `request` param contains the original {@type IncomingMessage} object of the incoming request.\n * You can use it to filter on additional properties like method, headers, etc.\n */\n ignoreIncomingRequests?: (urlPath: string, request: HttpIncomingMessage) => boolean;\n\n /**\n * Whether to automatically ignore common static asset requests like favicon.ico, robots.txt, etc.\n * This helps reduce noise in your transactions.\n *\n * @default `true`\n */\n ignoreStaticAssets?: boolean;\n\n /**\n * Do not capture spans for incoming HTTP requests with the given status codes.\n * By default, spans with some 3xx and 4xx status codes are ignored (see @default).\n * Expects an array of status codes or a range of status codes, e.g. [[300,399], 404] would ignore 3xx and 404 status codes.\n *\n * Important: This option is ignored by default! It only has an effect if `traceLifecycle` is set to `'static'`.\n *\n * @default `[[401, 404], [301, 303], [305, 399]]`\n *\n * @deprecated This option only has an effect if `traceLifecycle` is set to `'static'`. With span streaming\n * (`traceLifecycle: 'stream'`, the default), the SDK ignores it: child spans are sent as they end, before the\n * response status code is known, so a request's spans cannot be dropped retroactively. `ignoreStatusCodes` will be\n * removed in v12 of the SDK, without replacement.\n */\n ignoreStatusCodes?: (number | [number, number])[];\n\n /**\n * A hook that can be used to mutate the span for incoming requests.\n * This is triggered after the span is created, but before it is recorded.\n */\n onSpanCreated?: (span: Span, request: HttpIncomingMessage, response: HttpServerResponse) => void;\n}\n\nconst _httpServerSpansIntegration = ((options: HttpServerSpansIntegrationOptions = {}) => {\n const ignoreStaticAssets = options.ignoreStaticAssets ?? true;\n const ignoreIncomingRequests = options.ignoreIncomingRequests;\n // oxlint-disable-next-line typescript/no-deprecated\n const ignoreStatusCodes = options.ignoreStatusCodes ?? DEFAULT_IGNORE_STATUS_CODES;\n\n const { onSpanCreated } = options;\n\n return {\n name: INTEGRATION_NAME,\n setup(client: NodeClient) {\n // If no tracing, we can just skip everything here\n if (typeof __SENTRY_TRACING__ !== 'undefined' && !__SENTRY_TRACING__) {\n return;\n }\n\n client.on('httpServerRequest', (_request, _response, normalizedRequest) => {\n // Type-casting this here because we do not want to put the node types into core\n const request = _request as HttpIncomingMessage;\n const response = _response as HttpServerResponse;\n\n const startSpan = (next: () => boolean): boolean => {\n if (\n shouldIgnoreSpansForIncomingRequest(request, {\n ignoreStaticAssets,\n ignoreIncomingRequests,\n })\n ) {\n DEBUG_BUILD && debug.log(INTEGRATION_NAME, 'Skipping span creation for incoming request', request.url);\n return next();\n }\n\n const fullUrl = normalizedRequest.url || request.url || '/';\n const urlObj = parseStringToURLObject(fullUrl);\n\n const headers = request.headers;\n const userAgent = headers['user-agent'];\n const httpVersion = request.httpVersion;\n const host = headers.host as string | undefined;\n const hostname = host?.replace(/^(.*)(:[0-9]{1,5})/, '$1') || 'localhost';\n\n const scheme = fullUrl.startsWith('https') ? 'https' : 'http';\n\n const requestMethod = normalizedRequest.method || request.method?.toUpperCase();\n const method = requestMethod || 'GET';\n const httpTargetWithoutQueryFragment = urlObj ? urlObj.pathname : stripUrlQueryAndFragment(fullUrl);\n const bestEffortTransactionName = `${method} ${httpTargetWithoutQueryFragment}`;\n\n const query = getUrlQuery(urlObj?.search);\n const fragment = getUrlFragment(urlObj?.hash);\n\n const span = startInactiveSpan({\n // With span streaming, span names have to be low cardinality, so we can't fall back to the URL path.\n // Route instrumentations rename the span to `${method} ${route}` once a route is known.\n name: hasSpanStreamingEnabled(client)\n ? requestMethod || HTTP_SPAN_NAME_FALLBACK\n : bestEffortTransactionName,\n attributes: {\n // Sentry specific attributes\n [SENTRY_KIND]: 'server',\n [SENTRY_OP]: HTTP_SERVER,\n [SENTRY_SEGMENT_NAME_SOURCE]: 'url',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.http_server',\n [SENTRY_HTTP_PREFETCH]: isKnownPrefetchRequest(request) || undefined,\n [URL_FULL]: filterCollectedUrl(fullUrl, client),\n [URL_PATH]: urlObj?.pathname ?? httpTargetWithoutQueryFragment,\n [URL_QUERY]: filterCollectedUrlQuery(query, client),\n [URL_FRAGMENT]: fragment,\n [HTTP_REQUEST_METHOD]: normalizedRequest.method,\n [USER_AGENT_ORIGINAL]: userAgent,\n [URL_SCHEME]: scheme,\n [SERVER_ADDRESS]: hostname,\n [NETWORK_PROTOCOL_NAME]: 'http',\n [NETWORK_PROTOCOL_VERSION]: httpVersion,\n [NETWORK_TRANSPORT]: httpVersion?.toUpperCase() === 'QUIC' ? 'udp' : 'tcp',\n 'http.request.body.size': getContentLengthFromHeaders(request.headers),\n ...httpHeadersToSpanAttributes(normalizedRequest.headers || {}, client.getDataCollectionOptions()),\n },\n });\n\n onSpanCreated?.(span, request, response);\n\n return withActiveSpan(span, () => {\n bindScopeToEmitter(request);\n bindScopeToEmitter(response);\n\n // Ensure we only end the span once\n // E.g. error can be emitted before close is emitted\n let isEnded = false;\n function endSpan(status: SpanStatus): void {\n if (isEnded) {\n return;\n }\n\n isEnded = true;\n\n const newAttributes = getIncomingRequestAttributesOnResponse(\n request,\n response,\n client.getDataCollectionOptions().userInfo,\n );\n span.setAttributes(newAttributes);\n span.setStatus(status);\n span.end();\n }\n\n response.on('close', () => {\n endSpan(getSpanStatusFromHttpCode(response.statusCode));\n });\n response.on(errorMonitor, () => {\n const httpStatus = getSpanStatusFromHttpCode(response.statusCode);\n // Ensure we def. have an error status here\n endSpan(httpStatus.code === SPAN_STATUS_ERROR ? httpStatus : { code: SPAN_STATUS_ERROR });\n });\n\n return next();\n });\n };\n\n addStartSpanCallback(request, startSpan);\n });\n },\n processEvent(event) {\n return processHttpServerTransactionEvent(event, ignoreStatusCodes);\n },\n afterAllSetup(client) {\n if (!DEBUG_BUILD) {\n return;\n }\n\n if (client.getIntegrationByName('Http')) {\n debug.warn(\n 'It seems that you have manually added `httpServerSpansIntegration` while `httpIntegration` is also present. Make sure to remove `httpIntegration` when adding `httpServerSpansIntegration`.',\n );\n }\n\n if (!client.getIntegrationByName('Http.Server')) {\n debug.error(\n 'It seems that you have manually added `httpServerSpansIntegration` without adding `httpServerIntegration`. This is a requiement for spans to be created - please add the `httpServerIntegration` integration.',\n );\n }\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * This integration emits spans for incoming requests handled via the node `http` module.\n * It requires the `httpServerIntegration` to be present.\n */\nexport const httpServerSpansIntegration = _httpServerSpansIntegration as (\n options?: HttpServerSpansIntegrationOptions,\n) => Integration & {\n name: 'Http.ServerSpans';\n setup: (client: NodeClient) => void;\n processEvent: (event: Event) => Event | null;\n};\n\nfunction isKnownPrefetchRequest(req: HttpIncomingMessage): boolean {\n // Currently only handles Next.js prefetch requests but may check other frameworks in the future.\n return req.headers['next-router-prefetch'] === '1';\n}\n\n/**\n * Check if a request is for a common static asset that should be ignored by default.\n *\n * Only exported for tests.\n */\nexport function isStaticAssetRequest(urlPath: string): boolean {\n const path = stripUrlQueryAndFragment(urlPath);\n // Common static file extensions\n if (path.match(/\\.(ico|png|jpg|jpeg|gif|svg|css|js|woff|woff2|ttf|eot|webp|avif)$/)) {\n return true;\n }\n\n // Common metadata files\n if (path.match(/^\\/(robots\\.txt|sitemap\\.xml|manifest\\.json|browserconfig\\.xml)$/)) {\n return true;\n }\n\n return false;\n}\n\nfunction shouldIgnoreSpansForIncomingRequest(\n request: HttpIncomingMessage,\n {\n ignoreStaticAssets,\n ignoreIncomingRequests,\n }: {\n ignoreStaticAssets?: boolean;\n ignoreIncomingRequests?: (urlPath: string, request: HttpIncomingMessage) => boolean;\n },\n): boolean {\n if (isTracingSuppressed()) {\n return true;\n }\n\n // request.url is the only property that holds any information about the url\n // it only consists of the URL path and query string (if any)\n const urlPath = request.url;\n\n const method = request.method?.toUpperCase();\n // We do not capture OPTIONS/HEAD requests as spans\n if (method === 'OPTIONS' || method === 'HEAD' || !urlPath) {\n return true;\n }\n\n // Default static asset filtering\n if (ignoreStaticAssets && method === 'GET' && isStaticAssetRequest(urlPath)) {\n return true;\n }\n\n if (ignoreIncomingRequests?.(urlPath, request)) {\n return true;\n }\n\n return false;\n}\n\n/**\n * First entry of `X-Forwarded-For`: the client as seen by the outermost proxy.\n * https://opentelemetry.io/docs/specs/semconv/registry/attributes/client/#client-address\n */\nfunction getForwardedClientAddress(forwardedFor: string | string[] | undefined): string | undefined {\n return typeof forwardedFor === 'string' ? forwardedFor.split(',')[0]?.trim() || undefined : undefined;\n}\n\nfunction getIncomingRequestAttributesOnResponse(\n request: HttpIncomingMessage,\n response: HttpServerResponse,\n collectClientAddress: boolean,\n): SpanAttributes {\n // take socket from the request,\n // since it may be detached from the response object in keep-alive mode\n const { socket } = request;\n const { statusCode, statusMessage } = response;\n\n const newAttributes: SpanAttributes = {\n [HTTP_RESPONSE_STATUS_CODE]: statusCode,\n 'http.response.status_text': statusMessage?.toUpperCase(),\n };\n\n if (collectClientAddress) {\n // `client.address` is the originating client, so a forwarding header wins over the socket, which\n // behind a proxy holds the proxy's address. `network.peer.address` below keeps the socket value.\n newAttributes[CLIENT_ADDRESS] =\n getForwardedClientAddress(request.headers['x-forwarded-for']) ?? socket?.remoteAddress;\n }\n\n if (socket) {\n const { localAddress, localPort, remoteAddress, remotePort } = socket;\n newAttributes[SERVER_PORT] = localPort;\n newAttributes[NETWORK_LOCAL_ADDRESS] = localAddress;\n newAttributes[NETWORK_LOCAL_PORT] = localPort;\n newAttributes[CLIENT_PORT] = remotePort;\n newAttributes[NETWORK_PEER_ADDRESS] = collectClientAddress ? remoteAddress : undefined;\n newAttributes[NETWORK_PEER_PORT] = remotePort;\n }\n\n return newAttributes;\n}\n"],"names":["DEFAULT_IGNORE_STATUS_CODES","DEBUG_BUILD","debug","parseStringToURLObject","stripUrlQueryAndFragment","getUrlQuery","getUrlFragment","startInactiveSpan","hasSpanStreamingEnabled","HTTP_SPAN_NAME_FALLBACK","SENTRY_KIND","SENTRY_OP","HTTP_SERVER","SENTRY_SEGMENT_NAME_SOURCE","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","SENTRY_HTTP_PREFETCH","URL_FULL","filterCollectedUrl","URL_PATH","URL_QUERY","filterCollectedUrlQuery","URL_FRAGMENT","HTTP_REQUEST_METHOD","USER_AGENT_ORIGINAL","URL_SCHEME","SERVER_ADDRESS","NETWORK_PROTOCOL_NAME","NETWORK_PROTOCOL_VERSION","NETWORK_TRANSPORT","getContentLengthFromHeaders","httpHeadersToSpanAttributes","withActiveSpan","bindScopeToEmitter","getSpanStatusFromHttpCode","errorMonitor","SPAN_STATUS_ERROR","addStartSpanCallback","processHttpServerTransactionEvent","isTracingSuppressed","HTTP_RESPONSE_STATUS_CODE","CLIENT_ADDRESS","SERVER_PORT","NETWORK_LOCAL_ADDRESS","NETWORK_LOCAL_PORT","CLIENT_PORT","NETWORK_PEER_ADDRESS","NETWORK_PEER_PORT"],"mappings":"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"}
@@ -5,7 +5,7 @@ const core = require('@sentry/core');
5
5
  const debug = require('../../utils/debug.js');
6
6
  const common = require('./common.js');
7
7
 
8
- const base64WorkerScript = "LyohIEBzZW50cnkvbm9kZSAxMS4wLjAtYmV0YS4wICg1NGJiYWU5KSB8IGh0dHBzOi8vZ2l0aHViLmNvbS9nZXRzZW50cnkvc2VudHJ5LWphdmFzY3JpcHQgKi8KaW1wb3J0e1Nlc3Npb24gYXMgZX1mcm9tIm5vZGU6aW5zcGVjdG9yL3Byb21pc2VzIjtpbXBvcnR7d29ya2VyRGF0YSBhcyB0fWZyb20ibm9kZTp3b3JrZXJfdGhyZWFkcyI7Y29uc3Qgbj1nbG9iYWxUaGlzLGk9e307Y29uc3Qgbz0iX19TRU5UUllfRVJST1JfTE9DQUxfVkFSSUFCTEVTX18iO2NvbnN0IGE9dDtmdW5jdGlvbiBzKC4uLmUpe2EuZGVidWcmJmZ1bmN0aW9uKGUpe2lmKCEoImNvbnNvbGUiaW4gbikpcmV0dXJuIGUoKTtjb25zdCB0PW4uY29uc29sZSxvPXt9LGE9T2JqZWN0LmtleXMoaSk7YS5mb3JFYWNoKGU9Pntjb25zdCBuPWlbZV07b1tlXT10W2VdLHRbZV09bn0pO3RyeXtyZXR1cm4gZSgpfWZpbmFsbHl7YS5mb3JFYWNoKGU9Pnt0W2VdPW9bZV19KX19KCgpPT5jb25zb2xlLmxvZygiW0xvY2FsVmFyaWFibGVzIFdvcmtlcl0iLC4uLmUpKX1hc3luYyBmdW5jdGlvbiBjKGUsdCxuLGkpe2NvbnN0IG89YXdhaXQgZS5wb3N0KCJSdW50aW1lLmdldFByb3BlcnRpZXMiLHtvYmplY3RJZDp0LG93blByb3BlcnRpZXM6ITB9KTtpW25dPW8ucmVzdWx0LmZpbHRlcihlPT4ibGVuZ3RoIiE9PWUubmFtZSYmIWlzTmFOKHBhcnNlSW50KGUubmFtZSwxMCkpKS5zb3J0KChlLHQpPT5wYXJzZUludChlLm5hbWUsMTApLXBhcnNlSW50KHQubmFtZSwxMCkpLm1hcChlPT5lLnZhbHVlPy52YWx1ZSl9YXN5bmMgZnVuY3Rpb24gcihlLHQsbixpKXtjb25zdCBvPWF3YWl0IGUucG9zdCgiUnVudGltZS5nZXRQcm9wZXJ0aWVzIix7b2JqZWN0SWQ6dCxvd25Qcm9wZXJ0aWVzOiEwfSk7aVtuXT1vLnJlc3VsdC5tYXAoZT0+W2UubmFtZSxlLnZhbHVlPy52YWx1ZV0pLnJlZHVjZSgoZSxbdCxuXSk9PihlW3RdPW4sZSkse30pfWZ1bmN0aW9uIHUoZSx0KXtlLnZhbHVlJiYoInZhbHVlImluIGUudmFsdWU/dm9pZCAwPT09ZS52YWx1ZS52YWx1ZXx8bnVsbD09PWUudmFsdWUudmFsdWU/dFtlLm5hbWVdPWA8JHtlLnZhbHVlLnZhbHVlfT5gOnRbZS5uYW1lXT1lLnZhbHVlLnZhbHVlOiJkZXNjcmlwdGlvbiJpbiBlLnZhbHVlJiYiZnVuY3Rpb24iIT09ZS52YWx1ZS50eXBlP3RbZS5uYW1lXT1gPCR7ZS52YWx1ZS5kZXNjcmlwdGlvbn0+YDoidW5kZWZpbmVkIj09PWUudmFsdWUudHlwZSYmKHRbZS5uYW1lXT0iPHVuZGVmaW5lZD4iKSl9YXN5bmMgZnVuY3Rpb24gbChlLHQpe2NvbnN0IG49YXdhaXQgZS5wb3N0KCJSdW50aW1lLmdldFByb3BlcnRpZXMiLHtvYmplY3RJZDp0LG93blByb3BlcnRpZXM6ITB9KSxpPXt9O2Zvcihjb25zdCB0IG9mIG4ucmVzdWx0KWlmKHQudmFsdWU/Lm9iamVjdElkJiYiQXJyYXkiPT09dC52YWx1ZS5jbGFzc05hbWUpe2NvbnN0IG49dC52YWx1ZS5vYmplY3RJZDthd2FpdCBjKGUsbix0Lm5hbWUsaSl9ZWxzZSBpZih0LnZhbHVlPy5vYmplY3RJZCYmIk9iamVjdCI9PT10LnZhbHVlLmNsYXNzTmFtZSl7Y29uc3Qgbj10LnZhbHVlLm9iamVjdElkO2F3YWl0IHIoZSxuLHQubmFtZSxpKX1lbHNlIHQudmFsdWUmJnUodCxpKTtyZXR1cm4gaX1sZXQgZjsoYXN5bmMgZnVuY3Rpb24oKXtjb25zdCB0PW5ldyBlO3QuY29ubmVjdFRvTWFpblRocmVhZCgpLHMoIkNvbm5lY3RlZCB0byBtYWluIHRocmVhZCIpO2xldCBuPSExO3Qub24oIkRlYnVnZ2VyLnJlc3VtZWQiLCgpPT57bj0hMX0pLHQub24oIkRlYnVnZ2VyLnBhdXNlZCIsZT0+e249ITAsYXN5bmMgZnVuY3Rpb24oZSx7cmVhc29uOnQsZGF0YTp7b2JqZWN0SWQ6bn0sY2FsbEZyYW1lczppfSl7aWYoImV4Y2VwdGlvbiIhPT10JiYicHJvbWlzZVJlamVjdGlvbiIhPT10KXJldHVybjtpZihmPy4oKSxudWxsPT1uKXJldHVybjtjb25zdCBhPVtdO2ZvcihsZXQgdD0wO3Q8aS5sZW5ndGg7dCsrKXtjb25zdHtzY29wZUNoYWluOm4sZnVuY3Rpb25OYW1lOm8sdGhpczpzfT1pW3RdLGM9bi5maW5kKGU9PiJsb2NhbCI9PT1lLnR5cGUpLHI9Imdsb2JhbCIhPT1zLmNsYXNzTmFtZSYmcy5jbGFzc05hbWU/YCR7cy5jbGFzc05hbWV9LiR7b31gOm87aWYodm9pZCAwPT09Yz8ub2JqZWN0Lm9iamVjdElkKWFbdF09e2Z1bmN0aW9uOnJ9O2Vsc2V7Y29uc3Qgbj1hd2FpdCBsKGUsYy5vYmplY3Qub2JqZWN0SWQpO2FbdF09e2Z1bmN0aW9uOnIsdmFyczpufX19YXdhaXQgZS5wb3N0KCJSdW50aW1lLmNhbGxGdW5jdGlvbk9uIix7ZnVuY3Rpb25EZWNsYXJhdGlvbjpgZnVuY3Rpb24oKSB7IHRoaXMuJHtvfSA9IHRoaXMuJHtvfSB8fCAke0pTT04uc3RyaW5naWZ5KGEpfTsgfWAsc2lsZW50OiEwLG9iamVjdElkOm59KSxhd2FpdCBlLnBvc3QoIlJ1bnRpbWUucmVsZWFzZU9iamVjdCIse29iamVjdElkOm59KX0odCxlLnBhcmFtcykudGhlbihhc3luYygpPT57biYmYXdhaXQgdC5wb3N0KCJEZWJ1Z2dlci5yZXN1bWUiKX0sYXN5bmMgZT0+e24mJmF3YWl0IHQucG9zdCgiRGVidWdnZXIucmVzdW1lIil9KX0pLGF3YWl0IHQucG9zdCgiRGVidWdnZXIuZW5hYmxlIik7Y29uc3QgaT0hMSE9PWEuY2FwdHVyZUFsbEV4Y2VwdGlvbnM7aWYoYXdhaXQgdC5wb3N0KCJEZWJ1Z2dlci5zZXRQYXVzZU9uRXhjZXB0aW9ucyIse3N0YXRlOmk/ImFsbCI6InVuY2F1Z2h0In0pLGkpe2NvbnN0IGU9YS5tYXhFeGNlcHRpb25zUGVyU2Vjb25kfHw1MDtmPWZ1bmN0aW9uKGUsdCxuKXtsZXQgaT0wLG89NSxhPTA7cmV0dXJuIHNldEludGVydmFsKCgpPT57MD09PWE/aT5lJiYobyo9MixuKG8pLG8+ODY0MDAmJihvPTg2NDAwKSxhPW8pOihhLT0xLDA9PT1hJiZ0KCkpLGk9MH0sMWUzKS51bnJlZigpLCgpPT57aSs9MX19KGUsYXN5bmMoKT0+e3MoIlJhdGUtbGltaXQgbGlmdGVkLiIpLGF3YWl0IHQucG9zdCgiRGVidWdnZXIuc2V0UGF1c2VPbkV4Y2VwdGlvbnMiLHtzdGF0ZToiYWxsIn0pfSxhc3luYyBlPT57cyhgUmF0ZS1saW1pdCBleGNlZWRlZC4gRGlzYWJsaW5nIGNhcHR1cmluZyBvZiBjYXVnaHQgZXhjZXB0aW9ucyBmb3IgJHtlfSBzZWNvbmRzLmApLGF3YWl0IHQucG9zdCgiRGVidWdnZXIuc2V0UGF1c2VPbkV4Y2VwdGlvbnMiLHtzdGF0ZToidW5jYXVnaHQifSl9KX19KSgpLmNhdGNoKGU9PntzKCJGYWlsZWQgdG8gc3RhcnQgZGVidWdnZXIiLGUpfSksc2V0SW50ZXJ2YWwoKCk9Pnt9LDFlNCk7";
8
+ const base64WorkerScript = "LyohIEBzZW50cnkvbm9kZSAxMS4wLjAtYmV0YS4xIChjYjIzOWUwKSB8IGh0dHBzOi8vZ2l0aHViLmNvbS9nZXRzZW50cnkvc2VudHJ5LWphdmFzY3JpcHQgKi8KaW1wb3J0e1Nlc3Npb24gYXMgZX1mcm9tIm5vZGU6aW5zcGVjdG9yL3Byb21pc2VzIjtpbXBvcnR7d29ya2VyRGF0YSBhcyB0fWZyb20ibm9kZTp3b3JrZXJfdGhyZWFkcyI7Y29uc3Qgbj1nbG9iYWxUaGlzLGk9e307Y29uc3Qgbz0iX19TRU5UUllfRVJST1JfTE9DQUxfVkFSSUFCTEVTX18iO2NvbnN0IGE9dDtmdW5jdGlvbiBzKC4uLmUpe2EuZGVidWcmJmZ1bmN0aW9uKGUpe2lmKCEoImNvbnNvbGUiaW4gbikpcmV0dXJuIGUoKTtjb25zdCB0PW4uY29uc29sZSxvPXt9LGE9T2JqZWN0LmtleXMoaSk7YS5mb3JFYWNoKGU9Pntjb25zdCBuPWlbZV07b1tlXT10W2VdLHRbZV09bn0pO3RyeXtyZXR1cm4gZSgpfWZpbmFsbHl7YS5mb3JFYWNoKGU9Pnt0W2VdPW9bZV19KX19KCgpPT5jb25zb2xlLmxvZygiW0xvY2FsVmFyaWFibGVzIFdvcmtlcl0iLC4uLmUpKX1hc3luYyBmdW5jdGlvbiBjKGUsdCxuLGkpe2NvbnN0IG89YXdhaXQgZS5wb3N0KCJSdW50aW1lLmdldFByb3BlcnRpZXMiLHtvYmplY3RJZDp0LG93blByb3BlcnRpZXM6ITB9KTtpW25dPW8ucmVzdWx0LmZpbHRlcihlPT4ibGVuZ3RoIiE9PWUubmFtZSYmIWlzTmFOKHBhcnNlSW50KGUubmFtZSwxMCkpKS5zb3J0KChlLHQpPT5wYXJzZUludChlLm5hbWUsMTApLXBhcnNlSW50KHQubmFtZSwxMCkpLm1hcChlPT5lLnZhbHVlPy52YWx1ZSl9YXN5bmMgZnVuY3Rpb24gcihlLHQsbixpKXtjb25zdCBvPWF3YWl0IGUucG9zdCgiUnVudGltZS5nZXRQcm9wZXJ0aWVzIix7b2JqZWN0SWQ6dCxvd25Qcm9wZXJ0aWVzOiEwfSk7aVtuXT1vLnJlc3VsdC5tYXAoZT0+W2UubmFtZSxlLnZhbHVlPy52YWx1ZV0pLnJlZHVjZSgoZSxbdCxuXSk9PihlW3RdPW4sZSkse30pfWZ1bmN0aW9uIHUoZSx0KXtlLnZhbHVlJiYoInZhbHVlImluIGUudmFsdWU/dm9pZCAwPT09ZS52YWx1ZS52YWx1ZXx8bnVsbD09PWUudmFsdWUudmFsdWU/dFtlLm5hbWVdPWA8JHtlLnZhbHVlLnZhbHVlfT5gOnRbZS5uYW1lXT1lLnZhbHVlLnZhbHVlOiJkZXNjcmlwdGlvbiJpbiBlLnZhbHVlJiYiZnVuY3Rpb24iIT09ZS52YWx1ZS50eXBlP3RbZS5uYW1lXT1gPCR7ZS52YWx1ZS5kZXNjcmlwdGlvbn0+YDoidW5kZWZpbmVkIj09PWUudmFsdWUudHlwZSYmKHRbZS5uYW1lXT0iPHVuZGVmaW5lZD4iKSl9YXN5bmMgZnVuY3Rpb24gbChlLHQpe2NvbnN0IG49YXdhaXQgZS5wb3N0KCJSdW50aW1lLmdldFByb3BlcnRpZXMiLHtvYmplY3RJZDp0LG93blByb3BlcnRpZXM6ITB9KSxpPXt9O2Zvcihjb25zdCB0IG9mIG4ucmVzdWx0KWlmKHQudmFsdWU/Lm9iamVjdElkJiYiQXJyYXkiPT09dC52YWx1ZS5jbGFzc05hbWUpe2NvbnN0IG49dC52YWx1ZS5vYmplY3RJZDthd2FpdCBjKGUsbix0Lm5hbWUsaSl9ZWxzZSBpZih0LnZhbHVlPy5vYmplY3RJZCYmIk9iamVjdCI9PT10LnZhbHVlLmNsYXNzTmFtZSl7Y29uc3Qgbj10LnZhbHVlLm9iamVjdElkO2F3YWl0IHIoZSxuLHQubmFtZSxpKX1lbHNlIHQudmFsdWUmJnUodCxpKTtyZXR1cm4gaX1sZXQgZjsoYXN5bmMgZnVuY3Rpb24oKXtjb25zdCB0PW5ldyBlO3QuY29ubmVjdFRvTWFpblRocmVhZCgpLHMoIkNvbm5lY3RlZCB0byBtYWluIHRocmVhZCIpO2xldCBuPSExO3Qub24oIkRlYnVnZ2VyLnJlc3VtZWQiLCgpPT57bj0hMX0pLHQub24oIkRlYnVnZ2VyLnBhdXNlZCIsZT0+e249ITAsYXN5bmMgZnVuY3Rpb24oZSx7cmVhc29uOnQsZGF0YTp7b2JqZWN0SWQ6bn0sY2FsbEZyYW1lczppfSl7aWYoImV4Y2VwdGlvbiIhPT10JiYicHJvbWlzZVJlamVjdGlvbiIhPT10KXJldHVybjtpZihmPy4oKSxudWxsPT1uKXJldHVybjtjb25zdCBhPVtdO2ZvcihsZXQgdD0wO3Q8aS5sZW5ndGg7dCsrKXtjb25zdHtzY29wZUNoYWluOm4sZnVuY3Rpb25OYW1lOm8sdGhpczpzfT1pW3RdLGM9bi5maW5kKGU9PiJsb2NhbCI9PT1lLnR5cGUpLHI9Imdsb2JhbCIhPT1zLmNsYXNzTmFtZSYmcy5jbGFzc05hbWU/YCR7cy5jbGFzc05hbWV9LiR7b31gOm87aWYodm9pZCAwPT09Yz8ub2JqZWN0Lm9iamVjdElkKWFbdF09e2Z1bmN0aW9uOnJ9O2Vsc2V7Y29uc3Qgbj1hd2FpdCBsKGUsYy5vYmplY3Qub2JqZWN0SWQpO2FbdF09e2Z1bmN0aW9uOnIsdmFyczpufX19YXdhaXQgZS5wb3N0KCJSdW50aW1lLmNhbGxGdW5jdGlvbk9uIix7ZnVuY3Rpb25EZWNsYXJhdGlvbjpgZnVuY3Rpb24oKSB7IHRoaXMuJHtvfSA9IHRoaXMuJHtvfSB8fCAke0pTT04uc3RyaW5naWZ5KGEpfTsgfWAsc2lsZW50OiEwLG9iamVjdElkOm59KSxhd2FpdCBlLnBvc3QoIlJ1bnRpbWUucmVsZWFzZU9iamVjdCIse29iamVjdElkOm59KX0odCxlLnBhcmFtcykudGhlbihhc3luYygpPT57biYmYXdhaXQgdC5wb3N0KCJEZWJ1Z2dlci5yZXN1bWUiKX0sYXN5bmMgZT0+e24mJmF3YWl0IHQucG9zdCgiRGVidWdnZXIucmVzdW1lIil9KX0pLGF3YWl0IHQucG9zdCgiRGVidWdnZXIuZW5hYmxlIik7Y29uc3QgaT0hMSE9PWEuY2FwdHVyZUFsbEV4Y2VwdGlvbnM7aWYoYXdhaXQgdC5wb3N0KCJEZWJ1Z2dlci5zZXRQYXVzZU9uRXhjZXB0aW9ucyIse3N0YXRlOmk/ImFsbCI6InVuY2F1Z2h0In0pLGkpe2NvbnN0IGU9YS5tYXhFeGNlcHRpb25zUGVyU2Vjb25kfHw1MDtmPWZ1bmN0aW9uKGUsdCxuKXtsZXQgaT0wLG89NSxhPTA7cmV0dXJuIHNldEludGVydmFsKCgpPT57MD09PWE/aT5lJiYobyo9MixuKG8pLG8+ODY0MDAmJihvPTg2NDAwKSxhPW8pOihhLT0xLDA9PT1hJiZ0KCkpLGk9MH0sMWUzKS51bnJlZigpLCgpPT57aSs9MX19KGUsYXN5bmMoKT0+e3MoIlJhdGUtbGltaXQgbGlmdGVkLiIpLGF3YWl0IHQucG9zdCgiRGVidWdnZXIuc2V0UGF1c2VPbkV4Y2VwdGlvbnMiLHtzdGF0ZToiYWxsIn0pfSxhc3luYyBlPT57cyhgUmF0ZS1saW1pdCBleGNlZWRlZC4gRGlzYWJsaW5nIGNhcHR1cmluZyBvZiBjYXVnaHQgZXhjZXB0aW9ucyBmb3IgJHtlfSBzZWNvbmRzLmApLGF3YWl0IHQucG9zdCgiRGVidWdnZXIuc2V0UGF1c2VPbkV4Y2VwdGlvbnMiLHtzdGF0ZToidW5jYXVnaHQifSl9KX19KSgpLmNhdGNoKGU9PntzKCJGYWlsZWQgdG8gc3RhcnQgZGVidWdnZXIiLGUpfSksc2V0SW50ZXJ2YWwoKCk9Pnt9LDFlNCk7";
9
9
  function log(...args) {
10
10
  core.debug.log("[LocalVariables]", ...args);
11
11
  }
@@ -26,14 +26,6 @@ function instrumentUndici(config = {}) {
26
26
  subscribeToChannel("undici:request:trailers", (message) => onDone(message));
27
27
  subscribeToChannel("undici:request:error", (message) => onError(message));
28
28
  }
29
- function safeExecute(fn, onError2) {
30
- try {
31
- return fn();
32
- } catch (error) {
33
- onError2(error);
34
- return void 0;
35
- }
36
- }
37
29
  function subscribeToChannel(diagnosticChannel, onMessage) {
38
30
  _channelSubs.push(diagch.subscribe?.(diagnosticChannel, onMessage));
39
31
  }
@@ -73,9 +65,10 @@ function parseRequestHeaders(request) {
73
65
  }
74
66
  function onRequestCreated(config, { request }) {
75
67
  const url$1 = getAbsoluteUrl(request.origin, request.path);
76
- const ignoredByCallback = safeExecute(
68
+ const ignoredByCallback = core.safeCallback(
69
+ debugBuild.DEBUG_BUILD ? "The `ignoreOutgoingRequests` callback threw an error, not ignoring the request:" : "",
77
70
  () => !!config.ignoreOutgoingRequests?.(url$1),
78
- (e) => e && debugBuild.DEBUG_BUILD && core.debug.error("caught ignoreOutgoingRequests error: ", e)
71
+ () => false
79
72
  );
80
73
  const ignoreForBreadcrumbs = core.isTracingSuppressed() || !!ignoredByCallback;
81
74
  ignoreRequestMap.set(request, ignoreForBreadcrumbs);
@@ -145,9 +138,10 @@ function onRequestCreated(config, { request }) {
145
138
  attributes: attributes$1,
146
139
  onlyIfParent: !client || !core.hasSpanStreamingEnabled(client)
147
140
  });
148
- safeExecute(
141
+ core.safeCallback(
142
+ debugBuild.DEBUG_BUILD ? "The `requestHook` callback threw an error:" : "",
149
143
  () => config.requestHook?.(span, request),
150
- (e) => e && debugBuild.DEBUG_BUILD && core.debug.error("caught requestHook error: ", e)
144
+ () => void 0
151
145
  );
152
146
  outgoingFetchRequest.addTracePropagationHeadersToFetchRequest(request, propagationDecisionMap, span);
153
147
  spanFromReq.set(request, span);
@@ -186,9 +180,10 @@ function onResponseHeaders(config, { request, response }) {
186
180
  const spanAttributes = {
187
181
  [attributes.HTTP_RESPONSE_STATUS_CODE]: response.statusCode
188
182
  };
189
- safeExecute(
183
+ core.safeCallback(
184
+ debugBuild.DEBUG_BUILD ? "The `responseHook` callback threw an error:" : "",
190
185
  () => config.responseHook?.(span, { request, response }),
191
- (e) => e && debugBuild.DEBUG_BUILD && core.debug.error("caught responseHook error: ", e)
186
+ () => void 0
192
187
  );
193
188
  if (config.headersToSpanAttributes?.responseHeaders) {
194
189
  const headersToAttribs = /* @__PURE__ */ new Set();
@@ -1 +1 @@
1
- {"version":3,"file":"undici-instrumentation.js","sources":["../../../../src/integrations/node-fetch/undici-instrumentation.ts"],"sourcesContent":["/*\n * Copyright The OpenTelemetry Authors\n * SPDX-License-Identifier: Apache-2.0\n *\n * NOTICE from the Sentry authors:\n * - Vendored from: https://github.com/open-telemetry/opentelemetry-js-contrib/tree/ed97091c9890dd18e52759f2ea98e9d7593b3ae4/packages/instrumentation-undici\n * - Upstream version: @opentelemetry/instrumentation-undici@0.24.0\n * - Tracking issue: https://github.com/getsentry/sentry-javascript/issues/20165\n * - Refactored to use Sentry's span APIs instead of OpenTelemetry tracing APIs\n * - Dropped the OTel metrics (no MeterProvider is wired up) and the dead\n * `requireParentforSpans` code path (the SDK always passes `false`)\n * - Dropped the `@opentelemetry/instrumentation` base (undici reports via `diagnostics_channel`,\n * so no module patching was needed) — exposed as a plain `instrumentUndici()` function that the\n * integration wires up directly\n */\n\n/* eslint-disable max-lines */\n\nimport * as diagch from 'diagnostics_channel';\nimport { URL } from 'url';\n\nimport type { Span, SpanAttributes } from '@sentry/core';\nimport {\n debug,\n getClient,\n getSanitizedUrlString,\n getSpanStatusFromHttpCode,\n hasSpanStreamingEnabled,\n HTTP_SPAN_NAME_FALLBACK,\n isTracingSuppressed,\n LRUMap,\n parseUrl,\n SEMANTIC_ATTRIBUTE_SENTRY_CUSTOM_SPAN_NAME,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SPAN_STATUS_ERROR,\n startInactiveSpan,\n stripDataUrlContent,\n getUrlFragment,\n getUrlQuery,\n filterCollectedUrl,\n filterCollectedUrlQuery,\n} from '@sentry/core';\nimport { addFetchRequestBreadcrumb, addTracePropagationHeadersToFetchRequest } from '../../utils/outgoingFetchRequest';\nimport {\n HTTP_REQUEST_METHOD,\n HTTP_RESPONSE_STATUS_CODE,\n NETWORK_PEER_ADDRESS,\n NETWORK_PEER_PORT,\n SENTRY_KIND,\n SENTRY_OP,\n SERVER_ADDRESS,\n SERVER_PORT,\n URL_DOMAIN,\n URL_FRAGMENT,\n URL_FULL,\n URL_PATH,\n URL_QUERY,\n URL_SCHEME,\n USER_AGENT_ORIGINAL,\n} from '@sentry/conventions/attributes';\nimport { HTTP_CLIENT } from '@sentry/conventions/op';\nimport { DEBUG_BUILD } from '../../debug-build';\nimport type {\n NodeFetchOptions,\n UndiciRequest,\n RequestErrorMessage,\n RequestHeadersMessage,\n RequestMessage,\n RequestTrailersMessage,\n ResponseHeadersMessage,\n} from './types';\n\n// `http.request.method_original` is not part of `@sentry/conventions`, so we keep it inline.\nconst ATTR_HTTP_REQUEST_METHOD_ORIGINAL = 'http.request.method_original';\n\n// Keep ref to avoid https://github.com/nodejs/node/issues/42170 bug\n// We can replace this with _isInstrumented once we drop support for Node.js 18.18.0\nconst _channelSubs: Array<unknown> = [];\nconst spanFromReq = new WeakMap<UndiciRequest, Span>();\n// Whether breadcrumbs (and span-less trace propagation) should be skipped for a given request.\n// We evaluate this at request-creation time because the active context is no longer correct by the\n// time the response-headers event fires.\nconst ignoreRequestMap = new WeakMap<UndiciRequest, boolean>();\n// Caches trace-propagation decisions per URL so we don't recompute the `tracePropagationTargets` regexes per request.\nconst propagationDecisionMap = new LRUMap<string, boolean>(100);\n\n/**\n * Instrument outgoing HTTP requests made through `undici` or the global `fetch` API: emit `http.client`\n * spans, record breadcrumbs, and propagate traces into the outgoing request headers.\n *\n * Span creation is gated by the `spans` option (defaults to `true`). When spans are disabled, breadcrumbs\n * are still recorded and trace propagation headers are still injected (gated by `tracePropagation`).\n *\n * undici reports its request lifecycle via `diagnostics_channel`, so rather than patching any module we\n * subscribe to those channels directly. This is idempotent — subsequent calls are no-ops once the\n * channels have been subscribed to, and the config of the first call wins.\n *\n * A combination of https://github.com/elastic/apm-agent-nodejs and\n * https://github.com/gadget-inc/opentelemetry-instrumentations/blob/main/packages/opentelemetry-instrumentation-undici/src/index.ts\n */\nexport function instrumentUndici(config: NodeFetchOptions = {}): void {\n // Avoid duplicate subscriptions\n if (_channelSubs.length) {\n return;\n }\n\n subscribeToChannel('undici:request:create', message => onRequestCreated(config, message as RequestMessage));\n subscribeToChannel('undici:client:sendHeaders', message =>\n onRequestHeaders(config, message as RequestHeadersMessage),\n );\n subscribeToChannel('undici:request:headers', message => onResponseHeaders(config, message as ResponseHeadersMessage));\n subscribeToChannel('undici:request:trailers', message => onDone(message as RequestTrailersMessage));\n subscribeToChannel('undici:request:error', message => onError(message as RequestErrorMessage));\n}\n\n/** Replaces OTel's `safeExecuteInTheMiddle`: run `fn`, route any error to `onError`, and swallow it. */\nfunction safeExecute<T>(fn: () => T, onError: (error: unknown) => void): T | undefined {\n try {\n return fn();\n } catch (error) {\n onError(error);\n return undefined;\n }\n}\n\nfunction subscribeToChannel(\n diagnosticChannel: string,\n onMessage: (message: unknown, name: string | symbol) => void,\n): void {\n _channelSubs.push(diagch.subscribe?.(diagnosticChannel, onMessage));\n}\n\nfunction parseRequestHeaders(request: UndiciRequest): Map<string, string | string[]> {\n const result = new Map<string, string | string[]>();\n\n if (Array.isArray(request.headers)) {\n // headers are an array [k1, v2, k2, v2] (undici v6+)\n // values could be string or a string[] for multiple values\n for (let i = 0; i < request.headers.length; i += 2) {\n const key = request.headers[i];\n const value = request.headers[i + 1];\n\n // Key should always be a string, but the types don't know that, and let's be safe\n if (typeof key === 'string' && value !== undefined) {\n result.set(key.toLowerCase(), value);\n }\n }\n } else if (typeof request.headers === 'string') {\n // headers are a raw string (undici v5)\n // headers could be repeated in several lines for multiple values\n const headers = request.headers.split('\\r\\n');\n for (const line of headers) {\n if (!line) {\n continue;\n }\n const colonIndex = line.indexOf(':');\n if (colonIndex === -1) {\n // Invalid header? Probably this can't happen, but again let's be safe.\n continue;\n }\n const key = line.substring(0, colonIndex).toLowerCase();\n const value = line.substring(colonIndex + 1).trim();\n const allValues = result.get(key);\n\n if (allValues && Array.isArray(allValues)) {\n allValues.push(value);\n } else if (allValues) {\n result.set(key, [allValues, value]);\n } else {\n result.set(key, value);\n }\n }\n }\n return result;\n}\n\n// This is the 1st message we receive for each request (fired after request creation). Here we will\n// create the span and populate some atttributes, then link the span to the request for further\n// span processing\nfunction onRequestCreated(config: NodeFetchOptions, { request }: RequestMessage): void {\n const url = getAbsoluteUrl(request.origin, request.path);\n\n const ignoredByCallback = safeExecute(\n () => !!config.ignoreOutgoingRequests?.(url),\n e => e && DEBUG_BUILD && debug.error('caught ignoreOutgoingRequests error: ', e),\n );\n\n // Breadcrumbs & span-less trace propagation are additionally skipped when tracing is suppressed.\n // We store this here because the active context is no longer correct in later channel events.\n const ignoreForBreadcrumbs = isTracingSuppressed() || !!ignoredByCallback;\n ignoreRequestMap.set(request, ignoreForBreadcrumbs);\n\n // When spans are disabled we do not create a span, but we still inject trace propagation headers\n // directly (unless disabled via `tracePropagation`).\n if (!config.spans) {\n if (config.tracePropagation !== false && !ignoreForBreadcrumbs) {\n addTracePropagationHeadersToFetchRequest(request, propagationDecisionMap);\n }\n return;\n }\n\n // Ignore span creation if:\n // - the outgoing request is ignored via config\n // - method is 'CONNECT'\n if (request.method === 'CONNECT' || ignoredByCallback) {\n return;\n }\n\n let requestUrl;\n try {\n requestUrl = new URL(request.path, request.origin);\n } catch (err) {\n DEBUG_BUILD && debug.warn('could not determine url.full:', err);\n // Skip instrumenting this request.\n return;\n }\n\n const urlScheme = requestUrl.protocol.replace(':', '');\n const requestMethod = getRequestMethod(request.method);\n const attributes: SpanAttributes = {\n [SENTRY_KIND]: 'client',\n [SENTRY_OP]: HTTP_CLIENT,\n [HTTP_REQUEST_METHOD]: requestMethod,\n [ATTR_HTTP_REQUEST_METHOD_ORIGINAL]: request.method,\n [URL_FULL]: filterCollectedUrl(requestUrl.toString()),\n [URL_DOMAIN]: requestUrl.hostname || undefined,\n [URL_PATH]: requestUrl.pathname,\n [URL_QUERY]: filterCollectedUrlQuery(getUrlQuery(requestUrl.search)),\n [URL_FRAGMENT]: getUrlFragment(requestUrl.hash),\n [URL_SCHEME]: urlScheme,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.node_fetch',\n };\n\n // Sanitize data URLs to prevent long base64 strings in span attributes\n if (url.startsWith('data:')) {\n const sanitizedUrl = stripDataUrlContent(url);\n attributes[URL_FULL] = sanitizedUrl;\n attributes[SEMANTIC_ATTRIBUTE_SENTRY_CUSTOM_SPAN_NAME] = `${request.method || 'GET'} ${sanitizedUrl}`;\n }\n\n const schemePorts: Record<string, string> = { https: '443', http: '80' };\n const serverAddress = requestUrl.hostname;\n const serverPort = requestUrl.port || schemePorts[urlScheme];\n\n attributes[SERVER_ADDRESS] = serverAddress;\n if (serverPort && !isNaN(Number(serverPort))) {\n attributes[SERVER_PORT] = Number(serverPort);\n }\n\n // Get user agent from headers\n const headersMap = parseRequestHeaders(request);\n const userAgentValues = headersMap.get('user-agent');\n\n if (userAgentValues) {\n // NOTE: having multiple user agents is not expected so\n // we're going to take last one like `curl` does\n // ref: https://curl.se/docs/manpage.html#-A\n const userAgent = Array.isArray(userAgentValues) ? userAgentValues[userAgentValues.length - 1] : userAgentValues;\n attributes[USER_AGENT_ORIGINAL] = userAgent;\n }\n\n // Outside of span streaming, only record an `http.client` span when it has a parent. An orphan\n // one (no local parent) is left to the server for the downstream sampling decision: `onlyIfParent`\n // still creates a non-recording span so trace propagation headers are injected, but it isn't\n // emitted as a standalone transaction. This rule also lives in `SentrySampler`, but that only runs\n // when an OpenTelemetry SDK tracer provider is set up, so we enforce it here too, which covers\n // SDKs that don't use an OpenTelemetry tracer provider at all.\n const isDataUrl = url.startsWith('data:');\n const client = getClient();\n\n let spanName: string;\n if (requestMethod === '_OTHER') {\n spanName = HTTP_SPAN_NAME_FALLBACK;\n } else if (!!client && hasSpanStreamingEnabled(client)) {\n // With span streaming, span names have to be low cardinality, so the URL path is dropped and only\n // the domain is kept. Outgoing requests have no route to parameterize, and data URLs have no domain.\n spanName = requestUrl.hostname ? `${requestMethod} ${requestUrl.hostname}` : requestMethod;\n } else if (isDataUrl) {\n spanName = `${request.method || 'GET'} ${stripDataUrlContent(url)}`;\n } else {\n spanName = `${requestMethod} ${getSanitizedUrlString(parseUrl(requestUrl.toString()))}`;\n }\n\n const span = startInactiveSpan({\n name: spanName,\n attributes,\n onlyIfParent: !client || !hasSpanStreamingEnabled(client),\n });\n\n // Execute the request hook if defined\n safeExecute(\n () => config.requestHook?.(span, request),\n e => e && DEBUG_BUILD && debug.error('caught requestHook error: ', e),\n );\n\n // Context propagation goes last so no hook can tamper the propagation headers.\n // We propagate the trace data of the freshly created client span (not the active parent span)\n // so downstream services are parented to the http.client span, matching the upstream behavior.\n // This also de-duplicates against any trace headers the user set manually (e.g. via `getTraceData()`).\n addTracePropagationHeadersToFetchRequest(request, propagationDecisionMap, span);\n\n spanFromReq.set(request, span);\n}\n\n// This is the 2nd message we receive for each request. It is fired when connection with\n// the remote is established and about to send the first byte. Here we do have info about the\n// remote address and port so we can populate some `network.*` attributes into the span\nfunction onRequestHeaders(config: NodeFetchOptions, { request, socket }: RequestHeadersMessage): void {\n const span = spanFromReq.get(request);\n\n if (!span) {\n return;\n }\n\n const { remoteAddress, remotePort } = socket;\n const spanAttributes: SpanAttributes = {\n [NETWORK_PEER_ADDRESS]: remoteAddress,\n [NETWORK_PEER_PORT]: remotePort,\n };\n\n // After hooks have been processed (which may modify request headers)\n // we can collect the headers based on the configuration\n if (config.headersToSpanAttributes?.requestHeaders) {\n const headersToAttribs = new Set(config.headersToSpanAttributes.requestHeaders.map(n => n.toLowerCase()));\n const headersMap = parseRequestHeaders(request);\n\n for (const [name, value] of headersMap.entries()) {\n if (headersToAttribs.has(name)) {\n const attrValue = Array.isArray(value) ? value : [value];\n spanAttributes[`http.request.header.${name}`] = attrValue;\n }\n }\n }\n\n span.setAttributes(spanAttributes);\n}\n\n// This is the 3rd message we get for each request and it's fired when the server\n// headers are received, body may not be accessible yet.\n// From the response headers we can set the status and content length\nfunction onResponseHeaders(config: NodeFetchOptions, { request, response }: ResponseHeadersMessage): void {\n // Breadcrumbs are recorded independently of spans, so this runs even when span creation is disabled.\n const breadcrumbsEnabled = config.breadcrumbs !== false;\n if (breadcrumbsEnabled && !ignoreRequestMap.get(request)) {\n addFetchRequestBreadcrumb(request, response);\n }\n\n const span = spanFromReq.get(request);\n\n if (!span) {\n return;\n }\n\n const spanAttributes: SpanAttributes = {\n [HTTP_RESPONSE_STATUS_CODE]: response.statusCode,\n };\n\n // Execute the response hook if defined\n safeExecute(\n () => config.responseHook?.(span, { request, response }),\n e => e && DEBUG_BUILD && debug.error('caught responseHook error: ', e),\n );\n\n if (config.headersToSpanAttributes?.responseHeaders) {\n const headersToAttribs = new Set<string>();\n config.headersToSpanAttributes?.responseHeaders.forEach(name => headersToAttribs.add(name.toLowerCase()));\n\n for (let idx = 0; idx < response.headers.length; idx = idx + 2) {\n const nameBuf = response.headers[idx];\n const valueBuf = response.headers[idx + 1];\n if (nameBuf === undefined || valueBuf === undefined) {\n continue;\n }\n const name = nameBuf.toString().toLowerCase();\n const value = valueBuf;\n\n if (headersToAttribs.has(name)) {\n const attrName = `http.response.header.${name}`;\n if (!Object.prototype.hasOwnProperty.call(spanAttributes, attrName)) {\n spanAttributes[attrName] = [value.toString()];\n } else {\n (spanAttributes[attrName] as string[]).push(value.toString());\n }\n }\n }\n }\n\n span.setAttributes(spanAttributes);\n\n // Resolve the HTTP status code to a Sentry span status here (like the raw http client/server\n // instrumentation does) instead of setting a bare error and deferring to downstream inference.\n // The SentryTracerProvider's status finalization reads the already-stringified span status, which\n // can no longer be inferred back to `not_found` etc. the way the OpenTelemetry SDK exporter's\n // `mapStatus` does from the raw `{ code, message }`.\n if (response.statusCode >= 400) {\n span.setStatus(getSpanStatusFromHttpCode(response.statusCode));\n }\n}\n\n// This is the last event we receive if the request went without any errors\nfunction onDone({ request }: RequestTrailersMessage): void {\n const span = spanFromReq.get(request);\n\n if (!span) {\n return;\n }\n\n span.end();\n spanFromReq.delete(request);\n}\n\n// This is the event we get when something is wrong in the request like\n// - invalid options when calling `fetch` global API or any undici method for request\n// - connectivity errors such as unreachable host\n// - requests aborted through an `AbortController.signal`\n// NOTE: server errors are considered valid responses and it's the lib consumer\n// who should deal with that.\nfunction onError({ request, error }: RequestErrorMessage): void {\n const span = spanFromReq.get(request);\n\n if (!span) {\n return;\n }\n\n // NOTE: in `undici@6.3.0` when request aborted the error type changes from\n // a custom error (`RequestAbortedError`) to a built-in `DOMException` carrying\n // some differences:\n // - `code` is from DOMEXception (ABORT_ERR: 20)\n // - `message` changes\n // - stacktrace is smaller and contains node internal frames\n span.setStatus({\n code: SPAN_STATUS_ERROR,\n message: error.message,\n });\n span.end();\n spanFromReq.delete(request);\n}\n\nfunction getRequestMethod(original: string): string {\n const knownMethods = {\n CONNECT: true,\n OPTIONS: true,\n HEAD: true,\n GET: true,\n POST: true,\n PUT: true,\n PATCH: true,\n DELETE: true,\n TRACE: true,\n // QUERY from https://datatracker.ietf.org/doc/rfc10008/\n QUERY: true,\n };\n\n if (original.toUpperCase() in knownMethods) {\n return original.toUpperCase();\n }\n\n return '_OTHER';\n}\n\n// Matching the behavior of the base instrumentation\nfunction getAbsoluteUrl(origin: string, path: string = '/'): string {\n const url = `${origin}`;\n\n if (url.endsWith('/') && path.startsWith('/')) {\n return `${url}${path.slice(1)}`;\n }\n\n if (!url.endsWith('/') && !path.startsWith('/')) {\n return `${url}/${path}`;\n }\n\n return `${url}${path}`;\n}\n"],"names":["LRUMap","onError","url","DEBUG_BUILD","debug","isTracingSuppressed","addTracePropagationHeadersToFetchRequest","URL","attributes","SENTRY_KIND","SENTRY_OP","HTTP_CLIENT","HTTP_REQUEST_METHOD","URL_FULL","filterCollectedUrl","URL_DOMAIN","URL_PATH","URL_QUERY","filterCollectedUrlQuery","getUrlQuery","URL_FRAGMENT","getUrlFragment","URL_SCHEME","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","stripDataUrlContent","SEMANTIC_ATTRIBUTE_SENTRY_CUSTOM_SPAN_NAME","SERVER_ADDRESS","SERVER_PORT","USER_AGENT_ORIGINAL","getClient","HTTP_SPAN_NAME_FALLBACK","hasSpanStreamingEnabled","getSanitizedUrlString","parseUrl","startInactiveSpan","NETWORK_PEER_ADDRESS","NETWORK_PEER_PORT","addFetchRequestBreadcrumb","HTTP_RESPONSE_STATUS_CODE","getSpanStatusFromHttpCode","SPAN_STATUS_ERROR"],"mappings":"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"}
1
+ {"version":3,"file":"undici-instrumentation.js","sources":["../../../../src/integrations/node-fetch/undici-instrumentation.ts"],"sourcesContent":["/*\n * Copyright The OpenTelemetry Authors\n * SPDX-License-Identifier: Apache-2.0\n *\n * NOTICE from the Sentry authors:\n * - Vendored from: https://github.com/open-telemetry/opentelemetry-js-contrib/tree/ed97091c9890dd18e52759f2ea98e9d7593b3ae4/packages/instrumentation-undici\n * - Upstream version: @opentelemetry/instrumentation-undici@0.24.0\n * - Tracking issue: https://github.com/getsentry/sentry-javascript/issues/20165\n * - Refactored to use Sentry's span APIs instead of OpenTelemetry tracing APIs\n * - Dropped the OTel metrics (no MeterProvider is wired up) and the dead\n * `requireParentforSpans` code path (the SDK always passes `false`)\n * - Dropped the `@opentelemetry/instrumentation` base (undici reports via `diagnostics_channel`,\n * so no module patching was needed) — exposed as a plain `instrumentUndici()` function that the\n * integration wires up directly\n */\n\n/* eslint-disable max-lines */\n\nimport * as diagch from 'diagnostics_channel';\nimport { URL } from 'url';\n\nimport type { Span, SpanAttributes } from '@sentry/core';\nimport {\n debug,\n getClient,\n getSanitizedUrlString,\n getSpanStatusFromHttpCode,\n hasSpanStreamingEnabled,\n HTTP_SPAN_NAME_FALLBACK,\n isTracingSuppressed,\n LRUMap,\n parseUrl,\n safeCallback,\n SEMANTIC_ATTRIBUTE_SENTRY_CUSTOM_SPAN_NAME,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SPAN_STATUS_ERROR,\n startInactiveSpan,\n stripDataUrlContent,\n getUrlFragment,\n getUrlQuery,\n filterCollectedUrl,\n filterCollectedUrlQuery,\n} from '@sentry/core';\nimport { addFetchRequestBreadcrumb, addTracePropagationHeadersToFetchRequest } from '../../utils/outgoingFetchRequest';\nimport {\n HTTP_REQUEST_METHOD,\n HTTP_RESPONSE_STATUS_CODE,\n NETWORK_PEER_ADDRESS,\n NETWORK_PEER_PORT,\n SENTRY_KIND,\n SENTRY_OP,\n SERVER_ADDRESS,\n SERVER_PORT,\n URL_DOMAIN,\n URL_FRAGMENT,\n URL_FULL,\n URL_PATH,\n URL_QUERY,\n URL_SCHEME,\n USER_AGENT_ORIGINAL,\n} from '@sentry/conventions/attributes';\nimport { HTTP_CLIENT } from '@sentry/conventions/op';\nimport { DEBUG_BUILD } from '../../debug-build';\nimport type {\n NodeFetchOptions,\n UndiciRequest,\n RequestErrorMessage,\n RequestHeadersMessage,\n RequestMessage,\n RequestTrailersMessage,\n ResponseHeadersMessage,\n} from './types';\n\n// `http.request.method_original` is not part of `@sentry/conventions`, so we keep it inline.\nconst ATTR_HTTP_REQUEST_METHOD_ORIGINAL = 'http.request.method_original';\n\n// Keep ref to avoid https://github.com/nodejs/node/issues/42170 bug\n// We can replace this with _isInstrumented once we drop support for Node.js 18.18.0\nconst _channelSubs: Array<unknown> = [];\nconst spanFromReq = new WeakMap<UndiciRequest, Span>();\n// Whether breadcrumbs (and span-less trace propagation) should be skipped for a given request.\n// We evaluate this at request-creation time because the active context is no longer correct by the\n// time the response-headers event fires.\nconst ignoreRequestMap = new WeakMap<UndiciRequest, boolean>();\n// Caches trace-propagation decisions per URL so we don't recompute the `tracePropagationTargets` regexes per request.\nconst propagationDecisionMap = new LRUMap<string, boolean>(100);\n\n/**\n * Instrument outgoing HTTP requests made through `undici` or the global `fetch` API: emit `http.client`\n * spans, record breadcrumbs, and propagate traces into the outgoing request headers.\n *\n * Span creation is gated by the `spans` option (defaults to `true`). When spans are disabled, breadcrumbs\n * are still recorded and trace propagation headers are still injected (gated by `tracePropagation`).\n *\n * undici reports its request lifecycle via `diagnostics_channel`, so rather than patching any module we\n * subscribe to those channels directly. This is idempotent — subsequent calls are no-ops once the\n * channels have been subscribed to, and the config of the first call wins.\n *\n * A combination of https://github.com/elastic/apm-agent-nodejs and\n * https://github.com/gadget-inc/opentelemetry-instrumentations/blob/main/packages/opentelemetry-instrumentation-undici/src/index.ts\n */\nexport function instrumentUndici(config: NodeFetchOptions = {}): void {\n // Avoid duplicate subscriptions\n if (_channelSubs.length) {\n return;\n }\n\n subscribeToChannel('undici:request:create', message => onRequestCreated(config, message as RequestMessage));\n subscribeToChannel('undici:client:sendHeaders', message =>\n onRequestHeaders(config, message as RequestHeadersMessage),\n );\n subscribeToChannel('undici:request:headers', message => onResponseHeaders(config, message as ResponseHeadersMessage));\n subscribeToChannel('undici:request:trailers', message => onDone(message as RequestTrailersMessage));\n subscribeToChannel('undici:request:error', message => onError(message as RequestErrorMessage));\n}\n\nfunction subscribeToChannel(\n diagnosticChannel: string,\n onMessage: (message: unknown, name: string | symbol) => void,\n): void {\n _channelSubs.push(diagch.subscribe?.(diagnosticChannel, onMessage));\n}\n\nfunction parseRequestHeaders(request: UndiciRequest): Map<string, string | string[]> {\n const result = new Map<string, string | string[]>();\n\n if (Array.isArray(request.headers)) {\n // headers are an array [k1, v2, k2, v2] (undici v6+)\n // values could be string or a string[] for multiple values\n for (let i = 0; i < request.headers.length; i += 2) {\n const key = request.headers[i];\n const value = request.headers[i + 1];\n\n // Key should always be a string, but the types don't know that, and let's be safe\n if (typeof key === 'string' && value !== undefined) {\n result.set(key.toLowerCase(), value);\n }\n }\n } else if (typeof request.headers === 'string') {\n // headers are a raw string (undici v5)\n // headers could be repeated in several lines for multiple values\n const headers = request.headers.split('\\r\\n');\n for (const line of headers) {\n if (!line) {\n continue;\n }\n const colonIndex = line.indexOf(':');\n if (colonIndex === -1) {\n // Invalid header? Probably this can't happen, but again let's be safe.\n continue;\n }\n const key = line.substring(0, colonIndex).toLowerCase();\n const value = line.substring(colonIndex + 1).trim();\n const allValues = result.get(key);\n\n if (allValues && Array.isArray(allValues)) {\n allValues.push(value);\n } else if (allValues) {\n result.set(key, [allValues, value]);\n } else {\n result.set(key, value);\n }\n }\n }\n return result;\n}\n\n// This is the 1st message we receive for each request (fired after request creation). Here we will\n// create the span and populate some atttributes, then link the span to the request for further\n// span processing\nfunction onRequestCreated(config: NodeFetchOptions, { request }: RequestMessage): void {\n const url = getAbsoluteUrl(request.origin, request.path);\n\n const ignoredByCallback = safeCallback(\n DEBUG_BUILD ? 'The `ignoreOutgoingRequests` callback threw an error, not ignoring the request:' : '',\n () => !!config.ignoreOutgoingRequests?.(url),\n () => false,\n );\n\n // Breadcrumbs & span-less trace propagation are additionally skipped when tracing is suppressed.\n // We store this here because the active context is no longer correct in later channel events.\n const ignoreForBreadcrumbs = isTracingSuppressed() || !!ignoredByCallback;\n ignoreRequestMap.set(request, ignoreForBreadcrumbs);\n\n // When spans are disabled we do not create a span, but we still inject trace propagation headers\n // directly (unless disabled via `tracePropagation`).\n if (!config.spans) {\n if (config.tracePropagation !== false && !ignoreForBreadcrumbs) {\n addTracePropagationHeadersToFetchRequest(request, propagationDecisionMap);\n }\n return;\n }\n\n // Ignore span creation if:\n // - the outgoing request is ignored via config\n // - method is 'CONNECT'\n if (request.method === 'CONNECT' || ignoredByCallback) {\n return;\n }\n\n let requestUrl;\n try {\n requestUrl = new URL(request.path, request.origin);\n } catch (err) {\n DEBUG_BUILD && debug.warn('could not determine url.full:', err);\n // Skip instrumenting this request.\n return;\n }\n\n const urlScheme = requestUrl.protocol.replace(':', '');\n const requestMethod = getRequestMethod(request.method);\n const attributes: SpanAttributes = {\n [SENTRY_KIND]: 'client',\n [SENTRY_OP]: HTTP_CLIENT,\n [HTTP_REQUEST_METHOD]: requestMethod,\n [ATTR_HTTP_REQUEST_METHOD_ORIGINAL]: request.method,\n [URL_FULL]: filterCollectedUrl(requestUrl.toString()),\n [URL_DOMAIN]: requestUrl.hostname || undefined,\n [URL_PATH]: requestUrl.pathname,\n [URL_QUERY]: filterCollectedUrlQuery(getUrlQuery(requestUrl.search)),\n [URL_FRAGMENT]: getUrlFragment(requestUrl.hash),\n [URL_SCHEME]: urlScheme,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.node_fetch',\n };\n\n // Sanitize data URLs to prevent long base64 strings in span attributes\n if (url.startsWith('data:')) {\n const sanitizedUrl = stripDataUrlContent(url);\n attributes[URL_FULL] = sanitizedUrl;\n attributes[SEMANTIC_ATTRIBUTE_SENTRY_CUSTOM_SPAN_NAME] = `${request.method || 'GET'} ${sanitizedUrl}`;\n }\n\n const schemePorts: Record<string, string> = { https: '443', http: '80' };\n const serverAddress = requestUrl.hostname;\n const serverPort = requestUrl.port || schemePorts[urlScheme];\n\n attributes[SERVER_ADDRESS] = serverAddress;\n if (serverPort && !isNaN(Number(serverPort))) {\n attributes[SERVER_PORT] = Number(serverPort);\n }\n\n // Get user agent from headers\n const headersMap = parseRequestHeaders(request);\n const userAgentValues = headersMap.get('user-agent');\n\n if (userAgentValues) {\n // NOTE: having multiple user agents is not expected so\n // we're going to take last one like `curl` does\n // ref: https://curl.se/docs/manpage.html#-A\n const userAgent = Array.isArray(userAgentValues) ? userAgentValues[userAgentValues.length - 1] : userAgentValues;\n attributes[USER_AGENT_ORIGINAL] = userAgent;\n }\n\n // Outside of span streaming, only record an `http.client` span when it has a parent. An orphan\n // one (no local parent) is left to the server for the downstream sampling decision: `onlyIfParent`\n // still creates a non-recording span so trace propagation headers are injected, but it isn't\n // emitted as a standalone transaction. This rule also lives in `SentrySampler`, but that only runs\n // when an OpenTelemetry SDK tracer provider is set up, so we enforce it here too, which covers\n // SDKs that don't use an OpenTelemetry tracer provider at all.\n const isDataUrl = url.startsWith('data:');\n const client = getClient();\n\n let spanName: string;\n if (requestMethod === '_OTHER') {\n spanName = HTTP_SPAN_NAME_FALLBACK;\n } else if (!!client && hasSpanStreamingEnabled(client)) {\n // With span streaming, span names have to be low cardinality, so the URL path is dropped and only\n // the domain is kept. Outgoing requests have no route to parameterize, and data URLs have no domain.\n spanName = requestUrl.hostname ? `${requestMethod} ${requestUrl.hostname}` : requestMethod;\n } else if (isDataUrl) {\n spanName = `${request.method || 'GET'} ${stripDataUrlContent(url)}`;\n } else {\n spanName = `${requestMethod} ${getSanitizedUrlString(parseUrl(requestUrl.toString()))}`;\n }\n\n const span = startInactiveSpan({\n name: spanName,\n attributes,\n onlyIfParent: !client || !hasSpanStreamingEnabled(client),\n });\n\n // Execute the request hook if defined\n safeCallback(\n DEBUG_BUILD ? 'The `requestHook` callback threw an error:' : '',\n () => config.requestHook?.(span, request),\n () => undefined,\n );\n\n // Context propagation goes last so no hook can tamper the propagation headers.\n // We propagate the trace data of the freshly created client span (not the active parent span)\n // so downstream services are parented to the http.client span, matching the upstream behavior.\n // This also de-duplicates against any trace headers the user set manually (e.g. via `getTraceData()`).\n addTracePropagationHeadersToFetchRequest(request, propagationDecisionMap, span);\n\n spanFromReq.set(request, span);\n}\n\n// This is the 2nd message we receive for each request. It is fired when connection with\n// the remote is established and about to send the first byte. Here we do have info about the\n// remote address and port so we can populate some `network.*` attributes into the span\nfunction onRequestHeaders(config: NodeFetchOptions, { request, socket }: RequestHeadersMessage): void {\n const span = spanFromReq.get(request);\n\n if (!span) {\n return;\n }\n\n const { remoteAddress, remotePort } = socket;\n const spanAttributes: SpanAttributes = {\n [NETWORK_PEER_ADDRESS]: remoteAddress,\n [NETWORK_PEER_PORT]: remotePort,\n };\n\n // After hooks have been processed (which may modify request headers)\n // we can collect the headers based on the configuration\n if (config.headersToSpanAttributes?.requestHeaders) {\n const headersToAttribs = new Set(config.headersToSpanAttributes.requestHeaders.map(n => n.toLowerCase()));\n const headersMap = parseRequestHeaders(request);\n\n for (const [name, value] of headersMap.entries()) {\n if (headersToAttribs.has(name)) {\n const attrValue = Array.isArray(value) ? value : [value];\n spanAttributes[`http.request.header.${name}`] = attrValue;\n }\n }\n }\n\n span.setAttributes(spanAttributes);\n}\n\n// This is the 3rd message we get for each request and it's fired when the server\n// headers are received, body may not be accessible yet.\n// From the response headers we can set the status and content length\nfunction onResponseHeaders(config: NodeFetchOptions, { request, response }: ResponseHeadersMessage): void {\n // Breadcrumbs are recorded independently of spans, so this runs even when span creation is disabled.\n const breadcrumbsEnabled = config.breadcrumbs !== false;\n if (breadcrumbsEnabled && !ignoreRequestMap.get(request)) {\n addFetchRequestBreadcrumb(request, response);\n }\n\n const span = spanFromReq.get(request);\n\n if (!span) {\n return;\n }\n\n const spanAttributes: SpanAttributes = {\n [HTTP_RESPONSE_STATUS_CODE]: response.statusCode,\n };\n\n // Execute the response hook if defined\n safeCallback(\n DEBUG_BUILD ? 'The `responseHook` callback threw an error:' : '',\n () => config.responseHook?.(span, { request, response }),\n () => undefined,\n );\n\n if (config.headersToSpanAttributes?.responseHeaders) {\n const headersToAttribs = new Set<string>();\n config.headersToSpanAttributes?.responseHeaders.forEach(name => headersToAttribs.add(name.toLowerCase()));\n\n for (let idx = 0; idx < response.headers.length; idx = idx + 2) {\n const nameBuf = response.headers[idx];\n const valueBuf = response.headers[idx + 1];\n if (nameBuf === undefined || valueBuf === undefined) {\n continue;\n }\n const name = nameBuf.toString().toLowerCase();\n const value = valueBuf;\n\n if (headersToAttribs.has(name)) {\n const attrName = `http.response.header.${name}`;\n if (!Object.prototype.hasOwnProperty.call(spanAttributes, attrName)) {\n spanAttributes[attrName] = [value.toString()];\n } else {\n (spanAttributes[attrName] as string[]).push(value.toString());\n }\n }\n }\n }\n\n span.setAttributes(spanAttributes);\n\n // Resolve the HTTP status code to a Sentry span status here (like the raw http client/server\n // instrumentation does) instead of setting a bare error and deferring to downstream inference.\n // The SentryTracerProvider's status finalization reads the already-stringified span status, which\n // can no longer be inferred back to `not_found` etc. the way the OpenTelemetry SDK exporter's\n // `mapStatus` does from the raw `{ code, message }`.\n if (response.statusCode >= 400) {\n span.setStatus(getSpanStatusFromHttpCode(response.statusCode));\n }\n}\n\n// This is the last event we receive if the request went without any errors\nfunction onDone({ request }: RequestTrailersMessage): void {\n const span = spanFromReq.get(request);\n\n if (!span) {\n return;\n }\n\n span.end();\n spanFromReq.delete(request);\n}\n\n// This is the event we get when something is wrong in the request like\n// - invalid options when calling `fetch` global API or any undici method for request\n// - connectivity errors such as unreachable host\n// - requests aborted through an `AbortController.signal`\n// NOTE: server errors are considered valid responses and it's the lib consumer\n// who should deal with that.\nfunction onError({ request, error }: RequestErrorMessage): void {\n const span = spanFromReq.get(request);\n\n if (!span) {\n return;\n }\n\n // NOTE: in `undici@6.3.0` when request aborted the error type changes from\n // a custom error (`RequestAbortedError`) to a built-in `DOMException` carrying\n // some differences:\n // - `code` is from DOMEXception (ABORT_ERR: 20)\n // - `message` changes\n // - stacktrace is smaller and contains node internal frames\n span.setStatus({\n code: SPAN_STATUS_ERROR,\n message: error.message,\n });\n span.end();\n spanFromReq.delete(request);\n}\n\nfunction getRequestMethod(original: string): string {\n const knownMethods = {\n CONNECT: true,\n OPTIONS: true,\n HEAD: true,\n GET: true,\n POST: true,\n PUT: true,\n PATCH: true,\n DELETE: true,\n TRACE: true,\n // QUERY from https://datatracker.ietf.org/doc/rfc10008/\n QUERY: true,\n };\n\n if (original.toUpperCase() in knownMethods) {\n return original.toUpperCase();\n }\n\n return '_OTHER';\n}\n\n// Matching the behavior of the base instrumentation\nfunction getAbsoluteUrl(origin: string, path: string = '/'): string {\n const url = `${origin}`;\n\n if (url.endsWith('/') && path.startsWith('/')) {\n return `${url}${path.slice(1)}`;\n }\n\n if (!url.endsWith('/') && !path.startsWith('/')) {\n return `${url}/${path}`;\n }\n\n return `${url}${path}`;\n}\n"],"names":["LRUMap","url","safeCallback","DEBUG_BUILD","isTracingSuppressed","addTracePropagationHeadersToFetchRequest","URL","debug","attributes","SENTRY_KIND","SENTRY_OP","HTTP_CLIENT","HTTP_REQUEST_METHOD","URL_FULL","filterCollectedUrl","URL_DOMAIN","URL_PATH","URL_QUERY","filterCollectedUrlQuery","getUrlQuery","URL_FRAGMENT","getUrlFragment","URL_SCHEME","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","stripDataUrlContent","SEMANTIC_ATTRIBUTE_SENTRY_CUSTOM_SPAN_NAME","SERVER_ADDRESS","SERVER_PORT","USER_AGENT_ORIGINAL","getClient","HTTP_SPAN_NAME_FALLBACK","hasSpanStreamingEnabled","getSanitizedUrlString","parseUrl","startInactiveSpan","NETWORK_PEER_ADDRESS","NETWORK_PEER_PORT","addFetchRequestBreadcrumb","HTTP_RESPONSE_STATUS_CODE","getSpanStatusFromHttpCode","SPAN_STATUS_ERROR"],"mappings":"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"}