{"version":3,"file":"release/index-48ed31b.js","mappings":"6rBASe,SAASA,EACtBC,EACAC,GAEA,OAAc,OAAND,GAAoB,OAANC,GACd,OAAND,GAAoB,OAANC,GACdD,EAAEE,OAASD,EAAEC,MAAQF,EAAEG,QAAUF,EAAEE,OAASH,EAAEI,MAAQH,EAAEG,ICJ7C,SAASC,EAEtBL,EAAMC,GACN,OACED,EAAEM,QAAUL,EAAEK,OACdP,EAAcC,EAAEO,WAAYN,EAAEM,aAC9BR,EAAcC,EAAEQ,SAAUP,EAAEO,U,ykCCyDhC,SAASC,EAA4BT,EAAGC,GACtC,IAAMS,EAAgBV,EAAEW,aAAa,GAC/BC,EAAgBX,EAAEU,aAAa,GACrC,OACGD,EAAcG,OAASD,EAAcC,SACtCC,EAAAA,EAAAA,SAAQJ,EAAcK,WAAYH,EAAcG,YAIpD,IAAMC,EAA6B,SAAChB,EAAGC,GAAJ,OAChCD,EAAEa,OAASZ,EAAEY,SACdC,EAAAA,EAAAA,SAAQd,EAAEe,WAAYd,EAAEc,aAG1B,SAASE,EACPjB,EACAC,GACA,QACA,OAAOiB,EAAAA,EAAAA,GAAkB,UACvBlB,EAAEmB,YAAY,UADS,QACH,KADG,UAEvBlB,EAAEkB,YAAY,UAFS,QAEH,MAIxB,IAAMC,EAA8B,SAACpB,EAAGC,GAAJ,eACjC,UAACD,EAAEqB,iBAAH,QAAgB,IAAhB,UAAsBpB,EAAEoB,iBAAxB,QAAqC,KACtCH,EAAAA,EAAAA,GAAmBlB,EAAEsB,mBAAoBrB,EAAEqB,sBAC3CR,EAAAA,EAAAA,SACEd,EAAEuB,cAAgBC,EAAYxB,EAAEyB,QAChCxB,EAAEsB,cAAgBC,EAAYvB,EAAEwB,UAEjCzB,EAAEyB,OAAOC,GAAKzB,EAAEwB,OAAOC,IAGpBC,EAAoB,SAAC3B,EAAGC,GAAJ,OACxBD,EAAE4B,SAAW3B,EAAE2B,QACf5B,EAAE6B,aAAe5B,EAAE4B,YACnB7B,EAAE8B,cAAgB7B,EAAE6B,aAGhBC,EAA+B,SAAC/B,EAAGC,GAAJ,OACnC+B,EAAAA,EAAAA,IAAYhC,EAAEmB,YAAalB,EAAEkB,YAAad,KAC1C2B,EAAAA,EAAAA,IAAYhC,EAAEiC,WAAYhC,EAAEgC,WAAYN,IAGpCO,EAAkC,SACtClC,EACAC,EACAkC,GAKA,OACEnC,EAAEyB,OAAOC,KAAOzB,EAAEwB,OAAOC,IACzB1B,EAAEuB,eAAiBtB,EAAEsB,cASrBvB,EAAEqB,YAAcpB,EAAEoB,WAMlBrB,EAAEoC,gBAAkBnC,EAAEmC,iBAErBD,EAAQE,gBACM,MAAZrC,EAAEsC,QAA8B,MAAZrC,EAAEqC,QAET,MAAZtC,EAAEsC,QACU,MAAZrC,EAAEqC,QAmLV,SAAyBtC,EAAWC,GAClC,GAAID,EAAEuC,OAAStC,EAAEsC,KACf,OAAO,EAF6C,UAIlCvC,GAJkC,IAItD,2BAAuB,KAAZwC,EAAY,QACrB,IAAKvC,EAAEwC,IAAID,GACT,OAAO,GAN2C,8BAStD,OAAO,EA3LDE,CAAa1C,EAAEsC,OAAQrC,EAAEqC,aAI5BH,EAAQQ,mCACLX,EAAAA,EAAAA,IACAhC,EAAE4C,yBACF3C,EAAE2C,yBACFb,KAMFc,EAAsC,CAC1CF,kCAAkC,EAClCN,eAAe,GAQXS,EAA0C,CAC9CH,kCAAkC,EAClCN,eAAe,GAQXU,EAAkC,CACtCJ,kCAAkC,EAClCN,eAAe,GAGXW,EACJ,SAAChD,EAAGC,GAAJ,OAAUiC,EACRlC,EAAGC,EAAG8C,IAGV,SAASE,EAAkBtC,GACzB,IAAMuC,EAASvC,EAAauC,OAC5B,OAAIvC,EAAawC,cACR,iBAAMC,UAAU,KAAhB,SAAsBF,IAExBA,EAGT,SAASG,EAAuBC,GAC9B,IAAMC,EAAOC,IAAAA,oBAAmCF,EAAU1B,QAC1D,OACE2B,EAAKE,UAAYC,EAAAA,oBACjBH,EAAKE,UAAYE,EAAAA,cAwDrB,SAASC,EAA0BC,GACjC,IAAK,IAAIC,EAAI,EAAGA,EAAID,EAAME,OAAQD,IAEhC,IADA,IAAM9D,EAAI6D,EAAMC,GACPE,EAAIF,EAAI,EAAGE,EAAIH,EAAME,OAAQC,IAAK,CACzC,IAAM/D,EAAI4D,EAAMG,GACZ3D,EAAoBL,EAAEmB,YAAY,GAAIlB,EAAEkB,YAAY,MAxD5D8C,EAyDmCjE,EAAEiC,WAxDrCiC,EAwDiDjE,EAAEgC,YApC5CD,EAAAA,EAAAA,IACLiC,EAAeE,OAAOd,GACtBa,EAAeC,OAAOd,GACtB1B,OAkCIyC,EAAAA,EAAAA,IAAqBpE,EAAEiC,WAAYhC,EAAEgC,WAAYoC,EAAAA,IACjDR,EAAMS,OAAON,EAAG,GAChBA,KAIN,IAjEF,IACEC,EACAC,EA+DSJ,EAAI,EAAGA,EAAID,EAAME,OAAQD,IAEhC,IADA,IAAM9D,EAAI6D,EAAMC,GACPE,EAAIF,EAAI,EAAGE,EAAIH,EAAME,OAAQC,IAAK,CACzC,IAAM/D,EAAI4D,EAAMG,IACZhC,EAAAA,EAAAA,IAAYhC,EAAEiC,WAAYhC,EAAEgC,WAAYN,MAC1CyC,EAAAA,EAAAA,IACEpE,EAAEmB,YACFlB,EAAEkB,YACFD,EAAAA,GAEF2C,EAAMS,OAAON,EAAG,GAChBA,MAMD,SAASO,EAAsBvE,EAAWC,GAC/C,OAAOD,EAAEwE,SAAWvE,EAAEuE,SAGxB,SAASC,EACPC,GAEA,IAAK,IAAIZ,EAAI,EAAGA,EAAIY,EAAaX,OAAQD,IACvC,IAAK,IAAIE,EAAIF,EAAI,EAAGE,EAAIU,EAAaX,OAAQC,IAAK,CAChD,IAAMW,EAAeD,EAAaZ,GAC5Bc,EAAeF,EAAaV,GA1H5B9B,EA4H+ByC,EAAcC,EA3H/C9B,KA4HF6B,EAAarC,OAAS,IAAIuC,IACxB,kBACMF,EAAarC,QAAU,KAD7B,OAEMsC,EAAatC,QAAU,KAC3BwC,KAAKP,IAETG,EAAaJ,OAAON,EAAG,GACvBA,MAMR,IAAMxC,EAAc,SAAAuD,GAAC,MAAqB,WAAjBA,EAAEC,WAA0BD,EAAEE,UAAYF,EAAEG,MAsBtD,SAASC,EACtBC,EACAC,GAM8C,MAK1ClB,EACAmB,EACAC,EACAC,EAPJ,IAAKJ,EACH,MAAO,GAQLC,IACFlB,EAASkB,EAAKlB,OACdmB,EAASD,EAAKC,OACdC,EAAeF,EAAKE,aACpBC,EAAQH,EAAKG,OAMf,IAHA,IAAMC,EAAqD,UACxDH,SADwD,QAC9C,GAlBiC,WAoBrCxB,GACP,IAAM4B,EAAeN,EAActB,GAC7BrC,EAASiE,EAAajE,OACtBkE,EAAalE,EAAOuD,WAE1B,GAAIQ,IAAUA,EAAMI,SAASD,GAC3B,iBAGF,GAAIxB,IAAWA,EAAOuB,EAAcjE,EAAQkE,GAC1C,iBAGF,IAAIE,OAAe,EAEjB,GAAwBC,EAAAA,EAAAA,IACtBL,EACAE,GACA,SAACI,EAAOJ,GAAR,OAAuBK,EAAAA,EAAAA,GAAeD,EAAMJ,WAAYA,MAH1D,eAAOM,EAAP,UAMEJ,EAAkBJ,EAAiBQ,IAEnCJ,EAAmB,CACjBK,yBAA0B,GAC1BP,WAAAA,GAEFF,EAAiBnB,OAAO2B,EAAO,EAAGJ,IAItC,IAAMM,EAAWT,EAAaS,SACxBC,EAAW5C,IAAAA,UAAyBkC,EAAaW,YAiBnDC,GAAiB,EACfC,EAAYb,EAAazD,WAC/B,GAAIsE,EACF,IAAK,IAAIzC,EAAI,EAAGA,EAAIyC,EAAUxC,OAAQD,IAAK,CACzC,IAAM0C,EAAWD,EAAUzC,GAG3B,GADEN,IAAAA,oBAAmCgD,EAAS5E,QAC7B6B,UAAYC,EAAAA,mBAAoB,CAC/C4C,GAAiB,EACjB,OAKN,IAAMG,EAAa,CACjBL,EACAG,EACAJ,EAAW,sBAAwB,eACnC,GAGEpF,EAAa2F,EAAAA,GAAAA,WAAA,EAAmBD,GAChCvD,OAAM,EAENoD,IACFpD,EAASyD,EAAAA,GAAAA,WAAA,EAAeF,IAG1B,IAAMG,EAAeT,EACjBT,EAAamB,eACbnB,EAAaoB,eAEbF,IACF7F,EAAagG,EAAO,8BAA+B,CACjDC,cAAeJ,EACfK,KAAMlG,IAGJuF,IACFpD,EAASgE,EAAM,8BAA+B,CAC5CF,cAAeJ,EACfK,KAAM/D,MAWZ,IAWS,EAXHiE,EAAiBpG,EAlbV,IAkbkCqG,OAAOhB,EAAS1E,IAC3D2F,OAAW,EAEPC,EAAezB,EAAgBK,yBACrC,GAAwBJ,EAAAA,EAAAA,IACtBwB,EACAH,GACA,SAACpB,EAAOoB,GAAR,OAA2BrG,EAAAA,EAAAA,SAAQiF,EAAMwB,IAAKJ,MAHhD,eAAOlB,EAAP,UAMEoB,EAAcC,EAAarB,IAE3BoB,EAAe,CACbG,eAAgB,GAChBD,IAAKJ,EACLxG,aAAc,CAAC,CACbwC,aAAcuC,EAAavC,aAC3BD,OAAM,UAAEA,SAAF,QAAYnC,EAClB0G,WAAYrB,EAAS3C,QACrB1C,WAAAA,EACAF,OAAQuF,EAAS1E,KAEnBgD,aAAc,IAEhB4C,EAAahD,OAAO2B,EAAO,EAAGoB,IAIlC,IAAM9F,EAAemE,EAAaS,SAC9BT,EAAaoB,eACbpB,EAAamB,eACXa,EApLV,SAA2BhC,GACzB,IAAMU,EAAW5C,IAAAA,UAAyBkC,EAAaW,YACjDF,EAAWT,EAAaS,SAE9B,OAAyC,IAAjCC,EAASuB,sBAA8BxB,GACL,IAAjCC,EAASuB,qBAA6BxB,EA+KzByB,CAAkBlC,GAChCrE,EAAYqE,EAAarE,UACzBwG,EAAa,CACjBtH,WAAYmF,EAAanF,WACzBC,SAAUkF,EAAalF,SACvBF,MAAOoF,EAAapF,OAEhB8B,IAAgBsD,EAAazD,YAC/ByD,EAAazD,WAAW8B,OAAS,EAGjCzB,EAAS,KACb,GAAIiD,EAAc,CAChB,IAAMuC,EAAiBpC,EAAaW,WAAa,IAAMX,EAAahE,GAKpEY,EAASiD,EAAawC,IAAID,IAAmB,KAG/C,IAAIE,EAAe,CACjBpF,yBAA0B,GAC1BtB,mBAAoBuG,EACpB1E,aAAcuC,EAAavC,aAC3Bf,cAAAA,EACAsF,YAAAA,EACAH,KAAKU,EAAAA,EAAAA,MACL5G,UAAAA,EACAI,OAAAA,EACAF,aAAAA,EACAe,OAAAA,GAQI4F,EAAsBb,EAAY3C,aAAayD,MACnD,SAACC,GAAD,OAlXMlG,EAmXJ8F,EACAI,EAnXEvF,MAuXFqF,EACFF,EAAcE,EAEdb,EAAY3C,aAAa2D,KAAKL,GAG5BH,IAAeG,EAAY1G,qBACzBJ,EAAAA,EAAAA,GACF2G,EACAG,EAAY1G,oBACV,IACF0G,EAAY1G,mBAAqBuG,GAIrCG,EAAYpF,yBAAyByF,KAAK,CACxCpG,YAAY,OAAIqG,EAAAA,GAAAA,WAAA,EAAsB7B,IACtCtF,YAAa,CAAC0G,KAOhBG,EAAY7E,aAAe6E,EAAY7E,cACrCuC,EAAavC,cA3MRW,EAAI,EAAGA,EAAIsB,EAAcrB,OAAQD,IAAK,EAAtCA,GApBqC,UAkOhB2B,GAlOgB,IAkO9C,2BAAgD,CAG9C,IAH8C,IACxC6B,EADwC,QACTpB,yBAE5BpC,EAAI,EAAGA,EAAIwD,EAAavD,OAAQD,IAAK,CAG5C,IAFA,IAAMY,EAAe4C,EAAaxD,GAAGY,aAE5BV,EAAI,EAAGA,EAAIU,EAAaX,OAAQC,IAAK,CAC5C,IAAMpB,EACJ8B,EAAaV,GAAGpB,yBAClBgB,EAA0BhB,GAC1BA,EAAyBkC,KAAK7D,GAG5BsE,GACFd,EAA0BC,GAG5BA,EAAaI,KAAK1D,GAGpB,IAAK,IAAI0C,EAAI,EAAGA,EAAIwD,EAAavD,OAAQD,IAAK,CAU5C,IATA,IAAMyE,EAAejB,EAAaxD,GAC5B0E,EAAgBD,EAAa5H,aAFS,cAW1C,IAAM8H,EAAenB,EAAatD,GAC5B0E,EAAiBD,EAAa9H,aAAa,GAC3CgI,EAAkBH,EAAcL,MAAK,SAAAS,GAAC,OAC1CA,EAAEnB,aAAeiB,EAAejB,cAE5BoB,EAAgBN,EAAa7D,aAC7BoE,EAAgBL,EAAa/D,aAEnC,GAAIiE,IAAmB3G,EAAAA,EAAAA,IACrB6G,EACAC,EACA9F,GACC,CAED,IAAK,IAAI+F,EAAI,EAAGA,EAAIF,EAAc9E,OAAQgF,IAAK,CAC7C,IAAMpE,EAAekE,EAAcE,GACnCpE,EAAaxB,aACXwB,EAAaxB,cAAgB2F,EAAcC,GAAG5F,aAGlD,OAAwB2C,EAAAA,EAAAA,IACtB0C,EACAE,EACA1H,GAHF,eAAOiF,EAAP,YAMEsC,EAAahB,KAplBR,IAolB0BkB,EAAalB,IAC5CiB,EAAclE,OAAO2B,EAAO,EAAGyC,GAC/BpB,EAAahD,OAAON,EAAG,GACvBA,KAxCsC,KAUnCA,EAAIF,EAAI,EAAGE,EAAIsD,EAAavD,OAAQC,IAAK,EAAzCA,GAmCTuE,EAAaf,eAAiBgB,EAAczE,OAAS,GACjDiF,EAAAA,EAAAA,GAAUR,EAAcS,IAAIhG,IAC5BA,EAAkBuF,EAAc,IAGtClB,EAAaxC,KAAKrE,IAxS0B,8BA2S9C,OAAOgF,E,qDC1nBM,SAASyD,EACtBC,GAEQ,IADRC,IACQ,yDACR,GAAID,EAAE5I,WACJ,OAAI4I,EAAE3I,SACAT,EAAcoJ,EAAE5I,WAAY4I,EAAE3I,UACR,MAApB2I,EAAE5I,WAAWH,IACR2G,EAAO,YAAa,CAACsC,MAAMC,EAAAA,EAAAA,GAAWH,EAAE5I,cAE1CwG,EAAO,YAAa,CAACsC,MAAMC,EAAAA,EAAAA,GAAWH,EAAE5I,cAE1CwG,EAAO,qCAAsC,CAClDxG,YAAY+I,EAAAA,EAAAA,GAAWH,EAAE5I,YACzBC,UAAU8I,EAAAA,EAAAA,GAAWH,EAAE3I,YAEhB2I,EAAE7I,MACJyG,EAAO,sBAAuB,CAACsC,MAAMC,EAAAA,EAAAA,GAAWH,EAAE5I,cAEpDwG,EAAO,yBAA0B,CAACsC,MAAMC,EAAAA,EAAAA,GAAWH,EAAE5I,cACvD,GAAI4I,EAAE3I,SACX,OAAOuG,EAAO,eAAgB,CAACsC,MAAMC,EAAAA,EAAAA,GAAWH,EAAE3I,YAC7C,GAAI2I,EAAE7I,MAAO,CAClB,IAAIiJ,EAAOC,EAAE,SAIb,OAHIJ,IACFG,GAAOE,EAAAA,EAAAA,GAAcF,IAEhBA,EAET,MAAO,G,gGClCT,SAASG,GACPF,EACAG,GAEA,IAAM5F,EAAS4F,EAAM5F,OAErB,IAAKA,EACH,MAAO,GAOT,IAJA,IAAI6F,EAASJ,EAAE,mBAAoB,CACjCK,eAAgBF,EAAM5F,EAAS,KAGxBD,EAAIC,EAAS,EAAGD,GAAK,EAAGA,IAC/B8F,EAASJ,EAAE,qCAAsC,CAC/CM,KAAMF,EACNG,yBAA0BJ,EAAM7F,KAIpC,OAAO8F,E,oBClBM,SAASI,GACtBC,EAKAC,GAEA,IAAMC,EAAUF,EAA6B3J,QCXhC,SACb8J,GAEA,IAAMC,EAAYD,MAAAA,OAAH,EAAGA,EAAWlK,KAC7B,GAAiB,MAAbkK,GAAkC,MAAbC,EACvB,OAAO,EAGT,IAAMC,EAAM,IAAIC,KACVC,EACCF,EAAIG,aADLD,EAGGF,EAAII,cAAgB,EAHvBF,EAIEF,EAAIK,iBAGZ,GAAIN,EAAYG,EACd,OAAO,EAGT,GAAIH,IAAcG,EAAkB,CAClC,GAAuB,MAAnBJ,EAAUjK,MACZ,OAAO,EAET,GAAIiK,EAAUjK,MAAQqK,EACpB,OAAO,EAET,GAAIJ,EAAUjK,QAAUqK,EAAmB,CACzC,GAAqB,MAAjBJ,EAAUhK,IACZ,OAAO,EAET,GAAIgK,EAAUhK,IAAMoK,EAClB,OAAO,GAKb,OAAO,EDzBUI,CAAaX,EAA6BzJ,UAE3D,MAA6B,QAAtB0J,EAAOlF,aACZmF,IAAWU,EAAAA,GAAAA,GAAYX,EAAOY,W,4BEM3B,SAASC,GACdC,GAEA,IAAMC,GAAsBC,EAAAA,EAAAA,GAC1BF,EAAK7J,YAAY8H,KAAI,SAAApB,GAAU,OAC7BqB,EAAqBrB,GAAY,OAG/BsD,GAA0BC,EAAAA,EAAAA,GAC9BJ,EAAK/I,WAAWgH,IAAIoC,EAAAA,KAEtB,OAAIJ,EACEE,GAEA,gCACGG,GAASL,GACT,IACAE,KAIAF,EAEFE,EAkDT,SA1CgC,SAAC,GAGA,IAI3BI,EANJC,EAE+B,EAF/BA,mBACA9F,EAC+B,EAD/BA,aAEMjE,EAASiE,EAAajE,OACtBF,EAAemE,EAAanE,aAC5BkK,EAAczB,GAAetE,EAAapE,mBAAoBG,GAKlE8J,EAHEC,GACA/J,EAAOiK,eACPC,EAAAA,EAAAA,GAAsBH,EAAoB/J,EAAOiK,eAC5C,SAACE,EAAA,EAAD,CAAYC,QAAStK,EAAc2I,OAAQzI,EAAQqK,UAAQ,KAGhE,SAACC,EAAA,EAAD,CACEF,QAAStK,EACTkK,YAAaA,EACbvB,OAAQzI,EACRqK,UAAQ,IAId,IHjDAnC,EGiDMqC,GHjDNrC,EGkDEjE,EAAa9C,yBAAyBqG,IAAI8B,IHhDrCrB,GAAoDxC,EAAOyC,IGkD9DrE,GACF,gCACGiG,EACAS,GACC,gCACG,KACAC,EAAAA,EAAAA,GAAUD,MAEX,QAMR,OAHItG,EAAavC,eACfmC,GAAS,iBAAMlC,UAAU,YAAhB,SAA6BkC,KAEjCA,G,ojCCxET,IAAM4G,GAAoB,SAAClE,GAAD,OACxB,SAAC,GAAD,CAAyBtC,aAAcsC,KAGnCmE,GAAoB,SAAC9E,GAAD,OACxB,UAAC,WAAD,YACE,wBAAKiE,GAASjE,EAAYG,mBAC1B,yBACGwB,EAAAA,EAAAA,GACC3B,EAAY3C,aAAauE,IAAIiD,SAJd7E,EAAYE,MAU7B6E,GAAyB,SAAC1G,GAC9B,IAAM2G,EAAO3G,EAAajE,OACpByB,GAASyD,EAAAA,EAAAA,IACbnD,IAAAA,UAAyBkC,EAAaW,YACtCX,EAAazD,WACbyD,EAAaS,SAAW,sBAAwB,eAOhD,GAGImG,EAAQ5G,EAAavC,cACvB,iBAAMC,UAAU,KAAhB,SAAsBF,IACtBA,EAEE3B,EAAemE,EAAaS,SAC9BT,EAAaoB,eACbpB,EAAamB,eAEjB,OACE,UAAC,WAAD,YACE,wBAAKyE,GAASgB,MACd,2BACE,SAACV,EAAA,EAAD,CAAYC,QAAStK,EAAc2I,OAAQmC,EAAMP,UAAQ,IACxD,KACArC,EAAAA,EAAAA,GAAcP,EACbxD,GACA,KAEF,SAAC6G,GAAD,CAA2BC,OAAQH,SATlB3G,EAAahE,KAsBhC+K,GAEF,CACFC,UAAW,IAAIC,IAAI,CACjB,CAAC,KAAK,GACN,CAAC,KAAK,GACN,CAAC,KAAK,GACN,CAAC,KAAK,GACN,CAAC,KAAK,GACN,CAAC,KAAK,GACN,CAAC,KAAK,KAERN,KAAM,IAAIM,IAAI,CACZ,CAAC,KAAK,GACN,CAAC,KAAK,GACN,CAAC,KAAK,GACN,CAAC,KAAK,GACN,CAAC,KAAK,GACN,CAAC,KAAK,GACN,CAAC,KAAK,MAIH,SAASC,GACdlH,EACAC,GAEA,IAAMkH,EAA+BJ,GAAoB9G,GACzD,OAAoC,MAAhCkH,GAGGA,EAA6B9E,IAAIrC,EAAaW,cACnDX,EAAaS,SAGjB,IAAMoG,GAA4B,SAAC,GAEM,MADvCC,EACuC,EADvCA,OAEMM,EAAoB,GA2BpBC,EAAU,GA5BuB,KAGV5H,EAC3BqH,EAAOpH,cACP,CACEjB,OAAQ,SACNuB,EACAjE,EACAkE,GAEA,MAAmB,SAAfA,GACGiH,GAAqBlH,EAAcC,IACtCmH,EAAkBzE,KAAK3C,IAElB,GAEU,QAAfC,IAGCiH,GAAqBlH,EAAcC,OApBP,IA8BvC,2BAAoD,KAAzCE,EAAyC,QAC5CF,EAAaE,EAAgBF,WAChB,QAAfA,GAGJoH,EAAQ1E,MACN,eAAIjF,UAAU,MAAd,SACGyC,EAAgBK,yBAAyB+C,IAAIkD,KADvBxG,KApCU,8BAkDvC,OARImH,EAAkB/I,QACpBgJ,EAAQ1E,MACN,eAAIjF,UAAU,MAAd,SACG0J,EAAkB7D,IAAImD,KADD,SAMrBW,GAGT,Y,6GChKMC,GAAoBC,OAAOC,OAAO,CAACC,MAAO,SAEhD,SAASC,GAAiBC,GACxB,OAAgB,MAAZA,EAAM,GACDA,EAAM,GAAGC,OAEXvG,GAAO,4BAA6B,CACzCwG,UAAWF,EAAM,GAAGC,OACpBE,YAAaH,EAAM,GAAGC,SAI1B,SAASG,GAAeC,GAOtB,IANA,IAAMpL,GAAS,OAAIoL,GAAU5I,KAAKP,GAE9B8I,EAAiC,CAAC/K,EAAO,GAAI,MAE3CqL,EAAS,CAACN,GAEPvJ,EAAI,EAAGA,EAAIxB,EAAOyB,OAAQD,IAAK,CACtC,IAAM8J,EAAQtL,EAAOwB,GACf+J,EAAaD,EAAMpJ,UACV,MAAZ6I,EAAM,GAAaA,EAAM,GAAG7I,SAAW6I,EAAM,GAAG7I,UAC/CqJ,EAAa,IACI,IAAfA,EACFR,EAAM,GAAKO,GAEXP,EAAQ,CAACO,EAAO,MAChBD,EAAOtF,KAAKgF,KAKlB,OAAOnC,EAAAA,EAAAA,GAAkByC,EAAO1E,IAAImE,KA6FtC,SArFoCU,EAAAA,MAAmB,YAMrD,IAH2C,IAF3CtC,EAE2C,EAF3CA,mBACeuC,EAC4B,EAD3C3I,cAEM4I,EAAS,GAENlK,EAAI,EAAGA,EAAIiK,EAAqBhK,OAAQD,IAAK,CAKpD,IAJA,IAAM+B,EAAkBkI,EAAqBjK,GACvCoC,EAA2BL,EAAgBK,yBAC3C+H,EAAiB,GAEdjK,EAAI,EAAGA,EAAIkC,EAAyBnC,OAAQC,IAAK,CAKxD,IAJA,IAAMqD,EAAcnB,EAAyBlC,GACvCkK,EAAY7G,EAAY3C,aAAaX,OACrCoK,EAAa,GAEVpF,EAAI,EAAGA,EAAImF,EAAWnF,IAAK,CAClC,IAAMf,EAAcX,EAAY3C,aAAaqE,GAEvCqF,GACJ,SAAC,GAAD,CACE5C,mBAAoBA,EACpB9F,aAAcsC,IAIlBmG,EAAW9F,MACT,UAAC,WAAD,WACGL,EAAY3G,UACX2G,EAAYN,YACVR,GAAM,wBAAyB,CAC7BmH,IAAKrG,EAAY3G,UACjBqE,aAAc0I,IAGhBlH,GAAM,gCAAiC,CACrCmH,IAAKrG,EAAY3G,UACjBqE,aAAc0I,IAGhBA,EACHpG,EAAY1F,QACX,gCACG,KACD,iBAAMc,UAAU,UAAhB,UACGqG,EAAAA,EAAAA,GACC1C,GACE,iBACA,kBACAiB,EAAY1F,OAAOC,KACnB,CAACD,OAAQmL,GAAezF,EAAY1F,gBAK1C,MACJ,oBA7BmB0F,EAAYT,MAkCrC0G,EAAe5F,MACb,2BACE,wBAAKiD,GAASjE,EAAYG,mBAC1B,eAAI8G,MAAO,CAACC,UAAW,aAAvB,SAAsCJ,MAF/B9G,EAAYE,MAOzByG,EAAO3F,MACL,kBACEjF,UAAU,UAEVkL,MAAOtB,GAHT,UAKE,2BACGiB,KAJEpI,EAAgBF,aAU3B,OAAOqI,K,sBC5FT,SA5BsB,SAAC,GASrB,IATgE,IAA1CQ,EAA0C,EAA1CA,UAChBC,EAAa,CACjBX,EAAAA,SACA,MAEA,eAAI1K,UAAU,iBAAd,SACGoG,GAAE,qBAGE1F,EAAI,EAAGA,EAAI0K,EAAUzK,OAAQD,IAAK,CACzC,IAAM4K,EAASlL,IAAAA,OAAsBgL,EAAU1K,IAC/C2K,EAAWpG,MACT,yBACE,SAACuD,EAAA,EAAD,CAAY1B,OAAQwE,EAAQ5C,UAAQ,OAEtC,SAAC,GAAD,CACE1G,cACED,EACEuJ,EAAOtJ,cACP,CAACjB,OAAQwK,QAMnB,OAAOb,EAAAA,cAAAA,MAA0BA,EAAOW,I,sBC9BpCG,GAAoB,CACxB,OACA,SACA,QACA,QACA,QAgCF,SAzBqB,SAAC,GASpB,IAT6D,IAAxCC,EAAwC,EAAxCA,QACfJ,EAAa,CACjBX,EAAAA,SACA,MAEA,eAAI1K,UAAU,gBAAd,SACGoG,GAAE,oBAGE1F,EAAI,EAAGA,EAAI+K,EAAQ9K,OAAQD,IAAK,CACvC,IAAMuI,EAAO7I,IAAAA,KAAoBqL,EAAQ/K,IACzC2K,EAAWpG,MACT,yBACE,SAACuD,EAAA,EAAD,CAAY1B,OAAQmC,EAAMP,UAAQ,OAEpC,SAAC,GAAD,CACE1G,cACED,EAAmBkH,EAAKjH,cAAe,CAACI,MAAOoJ,QAKvD,OAAOd,EAAAA,cAAAA,MAA0BA,EAAOW,I,wCCzBpCK,GAAiC,CACrCC,OAAQ,CACN,SACA,MACA,QACA,QACA,OACA,SACA,cAEFC,MAAO,CACL,SACA,MACA,QACA,QACA,OACA,SACA,cAEF3C,KAAM,CACJ,SACA,gBACA,UACA,OACA,MACA,QACA,QACA,OACA,SACA,aACA,UAIE4C,GAAsB,IAAIpK,IAC9BoI,OAAOiC,OAAOC,EAAAA,4BAGT,SAASR,GAAgBxF,GAC9B,OAAQ8F,GAAoBxM,IAAIe,IAAAA,UAAyB2F,EAAE9C,YAAY+I,KA6EzE,SAnEuBtB,EAAAA,MAAmB,YAKU,UAJlDuB,uBAAAA,OAIkD,SAHlDjK,EAGkD,EAHlDA,cAGkD,IAFlDkK,YAAAA,OAEkD,SADlD9C,EACkD,EADlDA,OAEI+C,EAAU/C,EAAOpH,cAChBA,IACCmK,GAAiC,WAAtB/C,EAAOxH,aACpBuK,EAAUA,EAAQpL,OAAOwK,KAE3BvJ,EAAgBD,EACdoK,EACA,CAAC/J,MAAOsJ,GAAetC,EAAOxH,eAIlC,IAAMwG,EAA2D,WAAtBgB,EAAOxH,WAC9C,CAACwK,MAAO,CAAC,CAACT,OAAQvC,EAAQiD,WAAY,GAAIvK,KAAMsH,EAAOtH,QACtDsH,EAAOd,cAAgB,KAEtBgE,EAAUL,EACZ,MACA,eAAIjM,UAAU,gBAAd,SAA+BoG,GAAE,mBAErC,OACE,gCACGpE,EAAcrB,QACb,gCACG2L,GACD,SAAC,GAAD,CACElE,mBAAoBA,EACpBpG,cAAeA,OAGK,WAAtBoH,EAAOxH,YAAP,UAAkCuK,SAAlC,OAAkC,EAASxL,QAC7C,gCACG2L,GACD,uBACGxI,GAAA,8FAGC,CAACqE,MAAM,SAACK,EAAA,EAAD,CAAY1B,OAAQsC,WAI/B8C,GACF,gCACGI,GACD,uBACGxI,GACC,+BACA,CAACqE,MAAM,SAACK,EAAA,EAAD,CAAY1B,OAAQsC,WAI/B,KACmB,cAAtBA,EAAOxH,YAA8BwH,EAAOmD,cAAc5L,QACzD,SAAC,GAAD,CAAc8K,QAASrC,EAAOmD,gBAC5B,KACmB,UAAtBnD,EAAOxH,YAA0BwH,EAAOoD,eAAe7L,QACtD,SAAC,GAAD,CAAeyK,UAAWhC,EAAOoD,iBAC/B,W,mFChIK,SAASC,GACtBC,EACAC,EACAC,GAGA,IADA,IAAM1K,EAAS,GACNxB,EAAIgM,EAAOhM,GAAKiM,EAAKjM,IAC5BwB,EAAO+C,KAAK2H,EAAKlM,IAEnB,OAAOwB,E,kGCOT,SAAS2K,GACPC,EACAC,EACAC,EACAC,GAMA,IAAMC,EAA0B,GAEhC,OADAA,EAAOH,GAAWC,EC3BL,SACbG,EACAD,GAKA,IAHA,IAAME,EAAY,IAAIC,IAAIF,GACpBG,EAAe,IAAIC,gBAAgBH,EAAUI,QAEnD,MAAkB3D,OAAO4D,KAAKP,GAA9B,eAAuC,CAAlC,IAAM/I,EAAG,KACZmJ,EAAaI,IAAIvJ,EAAK+I,EAAO/I,IAK/B,OAFAiJ,EAAUI,OAASF,EAAaK,WAEzBP,EAAUQ,KDeVC,CAAQf,EAAKI,IACjBY,GAASb,GAAQ,IAAMA,EAAO,IAoHnC,SAjHkB,SAAC,GAMuB,IALxCc,EAKwC,EALxCA,GAKwC,IAJxCC,YAAAA,OAIwC,SAHxCf,EAGwC,EAHxCA,KACAgB,EAEwC,EAFxCA,MAEwC,IADxClB,QAAAA,OACwC,MAD9B,OAC8B,EAClCmB,EAAWD,EAAME,UAEvB,GAAID,GAAY,EACd,OAAO,KAGT,IAAME,EAAYH,EAAMI,WAClBC,EAAeL,EAAMM,cACrBC,EAAWP,EAAMQ,UAEjB/B,EAASuB,EAAMS,aAAe,EAAK,EACpCT,EAAMS,aAAe,EAAK,EAEzB/B,EAAOsB,EAAMS,aAAe,EAAKR,EAClCD,EAAMS,aAAe,EAAKR,EAEzBS,EAASZ,EAAGa,IAAI9B,IAEtB,OACE,0BACE,gBAAI9M,UAAU,aAAd,UACGsO,GACC,yBACE,cAAGV,KAAMf,GAAQ8B,EAAQ5B,EAASuB,EAAcrB,GAAhD,SACG7G,GAAE,eAFC,aAMR,yBACE,0BAAOA,GAAE,eADH,gBAKV,eAAIpG,UAAU,aAAgB,qBAE7B0M,EAAQ0B,GACP,yBACE,cAAGR,KAAMf,GAAQ8B,EAAQ5B,EAASqB,EAAWnB,GAA7C,SACGmB,KAFG,SAKN,KAEH1B,EAAS0B,EAAY,GACpB,yBACE,0BAAOhI,GAAE,QADH,eAGN,KAEHqG,GAASC,EAAOC,GAAK,SAACK,GAAD,OACnBiB,EAAMS,eAAiB1B,GACtB,yBACE,cACEhN,UAAU,MACV4N,KAAMf,GAAQ8B,EAAQ5B,EAASC,EAAMC,GAFvC,UAIE,4BAASD,OALJ,UAAYA,IASrB,yBACE,cAAGY,KAAMf,GAAQ8B,EAAQ5B,EAASC,EAAMC,GAAxC,SACGD,KAFI,UAAYA,MAQxBL,EAAOuB,EAAW,GACjB,yBACE,0BAAO9H,GAAE,QADH,eAGN,KAEHuG,EAAMuB,GACL,yBACE,cAAGN,KAAMf,GAAQ8B,EAAQ5B,EAASmB,EAAUjB,GAA5C,SACGiB,KAFG,QAKN,KAEHF,GACC,yBACE,0BAAO5H,GAAE,QADH,SAGN,MAEJ,eAAIpG,UAAU,YAAd,SACGwO,GACC,yBACE,cAAGZ,KAAMf,GAAQ8B,EAAQ5B,EAASyB,EAAUvB,GAA5C,SACG7G,GAAE,WAFC,SAMR,yBACE,0BAAOA,GAAE,WADH,YARkB,uB,kkCEtHtC,SAPsB,kBACpB,gBACEpG,UAAU,sBACVkJ,MAAO9C,GAAE,kC,kICVE,SAASyI,GAAiBC,GACvC,IAAIC,EAAwB,mBAARxF,IAAqB,IAAIA,SAAQyF,EA8BrD,OA5BAH,GAAmB,SAA0BC,GAC3C,GAAc,OAAVA,ICRkCG,EDQEH,GCPsB,IAAzDI,SAASvB,SAASwB,KAAKF,GAAIG,QAAQ,kBDOQ,OAAON,ECR5C,IAA2BG,EDUtC,GAAqB,mBAAVH,EACT,MAAM,IAAIO,UAAU,sDAGtB,QAAsB,IAAXN,EAAwB,CACjC,GAAIA,EAAO1P,IAAIyP,GAAQ,OAAOC,EAAOpK,IAAImK,GAEzCC,EAAOrB,IAAIoB,EAAOQ,GAGpB,SAASA,IACP,OAAOC,EAAAA,GAAAA,GAAUT,EAAOU,WAAWC,EAAAA,GAAAA,GAAeC,MAAMC,aAW1D,OARAL,EAAQM,UAAY/F,OAAOgG,OAAOf,EAAMc,UAAW,CACjDD,YAAa,CACXvQ,MAAOkQ,EACPQ,YAAY,EACZC,UAAU,EACVC,cAAc,MAGXC,EAAAA,GAAAA,GAAeX,EAASR,KAGTA,G,0cEDnB,IAAMoB,GAAb,sCACE,aAAc,8BACZ,cAAM,+BACDpO,KAAO,aAFA,EADhB,aAAwCqO,QA+ExC,SA9DkB,YAQb,IAJHC,EAIG,EAJHA,SACAC,EAGG,EAHHA,MAIMC,EAAyC,IAAI/G,IAE/CgH,EAAc,EACdC,EAAc,EAEZC,EAAW,WACf,IAAMvJ,EAAMC,KAAKD,MAEjB,OAAKA,EAAMqJ,EAAeH,GACxBI,EAAc,EACdD,EAAcrJ,EACP,IAGLsJ,EAAcH,EAChBG,KAEAD,GAAeH,EACfI,EAAc,GAGTD,EAAcrJ,IAGvB,OAAO,SAACwJ,GACN,OAAO,WAAa,2BAATzO,EAAS,yBAATA,EAAS,gBAClB,IAAI0O,EACAC,GAAU,EAEd,MAAO,CACLC,MAAO,WACLC,aAAaH,GACbC,GAAU,GAEZG,QAAS,IAAIC,SAAQ,SAACC,EAASC,GAU7BP,EAAUQ,YATM,WACVP,EACFM,EAAO,IAAIhB,IAEXe,EAAQP,EAAUU,MAAM,GAAMnP,IAEhCqO,EAAMe,OAAOV,KAGeF,KAE9BH,EAAM5C,IAAIiD,EAASO,U,oBC3F7B,IAAMI,GAAY,SAChBvD,EACAjH,EACAyK,GAHgB,MAKhB,6BACAC,mBAAmB1K,EAAOlF,YAC1B,cACA4P,mBAAmBxN,OAAO8C,EAAOxI,KACjC,WACAkT,mBAAmBxN,OAAgB,GAATuN,IAC1B,ICPK,SACLxD,GAEA,MAAO,YAAcyD,mBAAmBzD,EAAG0D,cDIrCC,CAAoB3D,IAGtB4D,GAAa,CAAC,EAAG,EAAG,EAAG,EAAG,GA8EhC,SAlDoB,SAAC,GAAsD,MAArD7K,EAAqD,EAArDA,OACd8K,EACkB,MAAtB9K,EAAO+K,YAAsB,EAAK,EAAI/K,EAAO+K,YAAc,IACvD9D,EAAKrD,EAAAA,WAAiBoH,GAAAA,GAE5B,OACE,iBAAM9R,UAAU,gBAAhB,UACE,kBAAMA,UAAU,cAAc+R,SAAS,KAAvC,UACyB,MAAtBjL,EAAO+K,YACW,MAAjB/K,EAAOyK,OAAiB,MACtB,iBACEvR,UAAU,iBACVkL,MAAO,CAACnB,MAAO,GAAF,OAAKjD,EAAOyK,OAAZ,MAFf,SAIG,EAAIzK,EAAOyK,OAAS,OAIzB,iBACEvR,UAAU,sBACVkL,MAAO,CAACnB,MAAO,GAAF,OAAKjD,EAAO+K,YAAZ,MAFf,SAIGD,IAIJ,UAAA7D,EAAGiE,YAAH,SAASC,4BACRN,GAAW9L,KAAI,SAAA0L,GACb,IAAMW,EAAkBX,IAAWK,EAC7BO,EAAYD,EAAkB,EAAIX,EAExC,OACE,cACEvR,UAAS,gBAAWuR,EAAX,YAAqBW,EAC1B,gBACA,cACJtE,KAAM0D,GAAUvD,EAAIjH,EAAQqL,GAE5BjJ,OAAOkJ,EAAAA,GAAAA,GAAcD,GANvB,SAQGZ,GAHIA,MAOT,W,sEERZ,SA/DwB7G,EAAAA,MAAmB,YAK7B,MAJZ2H,EAIY,EAJZA,YACAxP,EAGY,EAHZA,MACA2H,EAEY,EAFZA,MACA8H,EACY,EADZA,YAEMvE,EAAKrD,EAAAA,WAAiBoH,GAAAA,GACtBS,EAAW,UAAG/H,EAAMlB,iBAAT,aAAG,EAAiBhB,aAErC,OACE,gBACEtI,WAAWwS,EAAAA,GAAAA,GAAW3P,IAAU2H,EAAMzK,aAAe,MAAQ,IAC7DzB,GAAIkM,EAAMwB,IAFZ,WAIE,eAAIhM,UAAU,QAAd,UACE,cAAG4N,KAAM,UAAYpD,EAAMwB,IAA3B,SAAiCxB,EAAMN,YAGzC,gBAAIlK,UAAU,QAAd,WACE,SAACwI,EAAA,EAAD,CACEC,QAAS+B,EAAM1I,KACfgF,OAAQ0D,EAAMlB,YAOdyE,EAAGiE,MACHO,GACA/H,EAAMlC,aAAahK,KAAOiU,EAAYjU,IAEtC,iBAAK0B,UAAU,QAAf,UACGoG,GAAE,qBACF,KACD,SAACqM,GAAA,EAAD,CAAkBnK,aAAciK,OAE9B,KAEW,WAAhBF,GACC,gBAAKrS,UAAU,MAAf,UACE,SAAC,GAAD,CAA2BoJ,OAAQoB,EAAMlB,cAEzC,QAGLgJ,GACC,yBACE,SAACG,GAAA,EAAD,CAAkBnK,aAAckC,EAAMlC,iBAEtC,MAEJ,eAAItI,UAAU,WAAd,UACE,SAAC,GAAD,CAAa8G,OAAQ0D,EAAMlB,eAG7B,eAAItJ,UAAU,YAAd,UACG0S,EAAAA,GAAAA,GAAkBlI,EAAM7J,gB,gkCClCjC,IAKMgS,GALeC,GAAsC,CACzDxC,SAAU,IACVC,MAAO,GAGWwC,EAAa,SAACC,EAAkB9F,GAClD,OAAO+F,MAAM,iBAAmBD,EAAW,SAAW9F,MAwQxD,SArQqBtC,EAAAA,MAAmB,YAS1B,MARZ2H,EAQY,EARZA,YACAW,EAOY,EAPZA,SACAC,EAMY,EANZA,kBACAC,EAKY,EALZA,WACAC,EAIY,EAJZA,OACAC,EAGY,EAHZA,SACAC,EAEY,EAFZA,QACAnU,EACY,EADZA,OAEM6O,EAAKrD,EAAAA,WAAiB4I,GAAAA,GAE5B,EACE5I,EAAAA,SAAe,IADjB,eAAO6I,EAAP,KAAuBC,EAAvB,KAGA,EACE9I,EAAAA,UAAe,GADjB,eAAO+I,EAAP,KAAsBC,EAAtB,KAGMpB,EAAc5H,EAAAA,SAClB,kBCxEW,SACb2I,EACAnU,GAEA,IAAKA,IAAWA,EAAOyB,OACrB,OAAO,EAGT,IALS,EAKHgT,EAAcN,EAAQ/K,aAAahK,GALhC,KAOWY,GAPX,IAOT,2BACE,GAD0B,QAChBoJ,aAAahK,KAAOqV,EAC5B,OAAO,EATF,8BAaT,OAAO,EDwDCC,CAAyBP,EAASnU,KACxC,CAACmU,EAASnU,IAGN2U,EAAgB,QAAI,EAAA3U,MAAAA,OAAJ,EAAIA,EAAQyB,cAAZ,QAAuB,EACvCmT,EAAoBZ,GAAcD,EAClCc,EACJD,IACsB,IAArBD,GAA0BJ,GAG7B,EAAkC/I,EAAAA,SAAc,WAC9C,IAAMsJ,EAAc,GACdC,EAAa,GACnB,GAAI/U,EAAQ,YACUA,GADV,IACV,2BAA4B,KAAjBsL,EAAiB,QACtBA,EAAM0J,YACRD,EAAWhP,KAAKuF,GAEhBwJ,EAAY/O,KAAKuF,IALX,+BASZ,MAAO,CAACwJ,EAAaC,KACpB,CAAC/U,IAbJ,eAAO8U,EAAP,KAAoBC,EAApB,KAeME,EAAWzJ,EAAAA,OAAsByI,EAAOiB,cAExCC,EAAiB3J,EAAAA,aAAkB,WACvC,GAAIoJ,EAAmB,OACrBN,EAAkBpN,GAAE,eAEpB,IAAM6H,EAAQkG,EAASG,QACjB9F,EAAQ,QAAI,EAAAP,MAAAA,OAAJ,EAAIA,EAAOQ,iBAAX,QAAyB,EAEjC8F,EAAiB5B,GAAYQ,EAAO7U,GAAIkQ,GA8B9C,OA5BA+F,EAAexD,QACZyD,MAAsB,SAAAC,GAAQ,OAAIA,EAASC,UAC3CF,MAAK,SAAAtS,GACJ,IAAM+L,EAAQ/L,EAAO+L,MACrBkG,EAASG,QAAUrG,EAEnB7N,IAAAA,oBAAmC8B,EAAOyS,iBAE1C3B,EAAS,CACPG,OAAAA,EACAjU,QAAQ0V,EAAAA,EAAAA,KACL1V,GAAU,IAAI2V,OAAO3S,EAAOhD,SAC7B,SAAAyC,GAAC,OAAIA,EAAEP,YAETjB,KAAM,gBAGRqT,EAAkB,OAEnBsB,OAAM,SAACC,GACAA,aAAiB7E,MACrB8E,EAAAA,GAAAA,IAAiBD,GACjBE,QAAQF,MAAMA,GACdvB,EAAkBpN,GAAE,+BACpBsN,GAAiB,OAIhBa,EAGT,OAAO,OACN,CACDT,EACA5U,EACAsU,EACAL,EACAH,IAGFtI,EAAAA,WAAgB,WACd,IAAI6J,EAMJ,OAJIR,IACFQ,EAAiBF,KAGZ,WAAM,MACG,QAAd,EAAAE,SAAA,SAAgB1D,WAEjB,CACDkD,EACAM,IASF,IAAMjT,EAAW4C,OAAOmP,EAAO/R,UACzB8T,EAAc,GAAK5C,EAAc,EAAI,GACrC6C,EAAchC,EAAOiB,aAE3B,OACE,mBAAOpU,UAAU,aAAjB,WACE,4BACE,eAAIA,UAAWmT,EAAOpT,aAAe,KAAO,KAA5C,UACE,eAAIqV,QAASF,EAAb,UACE,eACElV,UAAU,gBACV4N,KACE,YAAcyF,EAAQrH,IACtB,SAAW5K,EACX,QAAUA,EAEZ9C,GAAI,OAAS8C,EACbiU,QAvBZ,SAAsBC,GAEpBA,EAAMC,iBACNvC,EAAS,CAACG,OAAAA,EAAQhT,KAAM,mBAYhB,WAUE,iBAAMH,UAAU,kBAAhB,SACGkT,EAAa,IAAW,OAE3B,SAACsC,GAAA,EAAD,CAAmBrC,OAAQA,cAMnC,mBAAOjI,MAAOgI,EAAa,KAAO,CAACuC,QAAS,QAA5C,UACG5B,GACC,iCACE,gBAAI7T,UAAU,OAAd,WACE,eAAIA,UAAU,QAAd,SAAuBoG,GAAE,QACzB,wBAAKA,GAAE,WACNkM,GACC,wBAAKlM,GAAE,YACL,MACJ,eAAIpG,UAAU,WAAd,SAA0BoG,GAAE,aAC5B,eAAIpG,UAAU,YAAd,SAA2BoG,GAAE,eAI7BgN,GACA+B,GACAA,EAAYhH,UAAYgH,EAAY9G,YAEpC,yBACE,gBAAI+G,QAASF,EAAahK,MAAO,CAACwK,QAAS,OAA3C,WACE,uBACGtP,GAAE,uGAKL,SAAC,GAAD,CACE2H,GAAIA,EACJd,KAAM,SAAWkG,EAAO/R,SACxB6M,MAAOkH,SAIT,KAELnB,EAAYnO,KAAI,SAAC2E,EAAO3H,GAAR,OACf,SAAC,GAAD,CACEwP,YAAaA,EACbxP,MAAOA,EAEPyP,YAAaA,EACb9H,MAAOA,GAFFA,EAAMlM,OAMd2V,EAAWtT,QACV,iCACE,eAAIX,UAAU,OAAd,UACE,gBAAIoV,QAAQ,IAAZ,WACE,SAAC,GAAD,IACChP,GAAE,oBAGN6N,EAAWpO,KAAI,SAAC2E,EAAO3H,GAAR,OACd,SAAC,GAAD,CACEwP,YAAaA,EACbxP,MAAOA,EAEPyP,YAAaA,EACb9H,MAAOA,GAFFA,EAAMlM,UAMf,QAEJ,MAGFuV,IACAC,GACCV,GACCW,GAAaR,EA0BX,MAxBJ,yBACE,gBAAI6B,QAASF,EAAahK,MAAO,CAACwK,QAAS,OAA3C,UACG/R,GAAA,gKAIC,CACEgS,mBAAoB9B,EACpB+B,kBAAmBzC,EAAO0C,aAAe,IAG5C,KACD,cACE7V,UAAU,cACV4N,KAAK,IACLyH,QAAS,SAACC,GACRA,EAAMC,iBACN7B,GAAiB,IALrB,SAQGtN,GAAE,6BAMVmN,GACC,yBACE,eACE6B,QAASF,EACThK,MAAO,CAACwK,QAAS,OAFnB,UAIE,gBAAK1V,UAAU,kBAAf,SACGuT,QAIL,c,sBEhPZ,SAvDuB7I,EAAAA,MAAmB,gBACxC2H,EADwC,EACxCA,YACAW,EAFwC,EAExCA,SACA8C,EAHwC,EAGxCA,QAHwC,OAKxC,kBAAMxX,GAAG,iBAAT,UACGwX,EAAQnV,OAAS,GAChB,iCACE,mBACEX,UAAU,WACV1B,GAAG,qBACH+W,QAAS,WACPrC,EAAS,CACP+C,UAAU,EACVD,QAAAA,EACA3V,KAAM,wBAGVA,KAAK,SAVP,SAYGiG,GAAE,wBAEJ,OACD,mBACEpG,UAAU,WACV1B,GAAG,uBACH+W,QAAS,WACPrC,EAAS,CACP+C,UAAU,EACVD,QAAAA,EACA3V,KAAM,wBAGVA,KAAK,SAVP,SAYGiG,GAAE,0BAEJ,SAED,MACJ,mBACEpG,UAAU,WACV1B,GAAG,iBACH+W,QAAS,WACPrC,EAAS,CAAC7S,KAAM,yBAElBA,KAAK,SANP,SASMiG,GADa,WAAhBiM,EACK,yBACA,qC,mxCCrCZ,SAAS2D,GACPC,EACAC,GAEA,IAAMC,E,uWAAwB,CAAH,GAAOF,GAElC,OAAQC,EAAO/V,MACb,IAAK,sBACuB,WAAtB8V,EAAM5D,cACR+D,EAAAA,GAAAA,GAAU,iBAAkB,GAC5BD,EAAS9D,YAAc,YAEvB+D,EAAAA,GAAAA,GAAU,iBAAkB,GAC5BD,EAAS9D,YAAc,UAEzB,MAEF,IAAK,gBACH,IAAMc,EAAS+C,EAAO/C,OAChBkD,EAAqB,IAAI9M,IAAI0M,EAAMK,iBACzCD,EAAmB3I,IACjByF,EAAO/R,UACNmV,GAAiBF,EAAoBlD,IAExCgD,EAASG,gBAAkBD,EAC3B,MAEF,IAAK,qBACH,IADyB,EACnBA,EAAqB,IAAI9M,IAAI0M,EAAMK,iBADhB,KAEJJ,EAAOJ,SAFH,IAEzB,2BAAqC,KAA1B3C,EAA0B,QACnCkD,EAAmB3I,IAAIyF,EAAO/R,SAAU8U,EAAOH,WAHxB,8BAKzBI,EAASG,gBAAkBD,EAC3B,MAEF,IAAK,cACH,IAAMlD,EAAS+C,EAAO/C,OAChBqD,EAAkB,IAAIjN,IAAI0M,EAAMQ,cACtCD,EAAgB9I,IAAIyF,EAAO/R,SAAU8U,EAAOhX,QAC5CiX,EAASM,aAAeD,EAK5B,OAAOL,EAGT,SAASO,GAAmBrE,GAC1B,MAAO,CACLA,YAAAA,EAMAiE,gBAAiB,IAAI/M,IACrBkN,aAAc,IAAIlN,KAItB,SAASgN,GAAiBD,EAAiBnD,GACzC,IAAM4C,EAAWO,EAAgB3R,IAAIwO,EAAO/R,UAC5C,OAAmB,MAAZ2U,EACe,MAAjB5C,EAAOjU,OACR6W,EAGN,SAASY,GAAgBF,EAActD,GAAQ,QAC7C,2BAAOsD,EAAa9R,IAAIwO,EAAO/R,iBAA/B,QAA4C+R,EAAOjU,cAAnD,QAA6D,KAG/D,IAAM0X,GAAyB,IAAIC,QA2PnBC,GACd,4BAvL0BpM,EAAAA,MAAmB,SAACqM,GAAkB,YAE9D3D,EAGE2D,EAHF3D,SACAC,EAEE0D,EAFF1D,QACA2D,EACED,EADFC,sBAGIC,EAAuBvM,EAAAA,QAAa,GACrCuM,EAAqB3C,UACxBlU,IAAAA,oBAAmC4W,GACnCC,EAAqB3C,SAAU,GAGjC,MAA0B5J,EAAAA,WACxBsL,GACAe,EAAMG,mBACNR,IAHF,eAAOT,EAAP,KAAcjD,EAAd,KAMM8C,EAAUzC,EAAQyC,QAEtBzD,EAGE4D,EAHF5D,YACAiE,EAEEL,EAFFK,gBACAG,EACER,EADFQ,aAGIU,EAA6BzM,EAAAA,SAAc,kBAAM,IAAInB,IACzDuM,EAAQjQ,KAAI,SAAAsN,GAAM,cAAI,CACpBA,EAAO7U,GAEiB,MAAtB6U,EAAO0C,aACP1C,EAAO0C,YAAc,GACrB1C,EAAO0C,aAAP,oBACIc,GAAgBF,EAActD,UADlC,aACI,EAAuCxS,cAD3C,QACsD,UAGzD,CAAC8V,EAAcX,IAEZ7C,EAAoBvI,EAAAA,SAAc,WAAM,WACxByM,EAA2BrL,UADH,IAC5C,2BAAyD,CACvD,GADuD,QAErD,OAAO,GAHiC,8BAM5C,OAAO,IACN,CAACqL,IAEEC,EAAsB1M,EAAAA,SAAc,iBACxB,WAAhB2H,EACIyD,EAAQjQ,KAAI,SAACsN,GAAD,OApHpB,SACEjU,GAEA,IAAKA,EACH,OAAO,KAGT,IAAIgD,EAAS0U,GAAuBjS,IAAIzF,GACxC,GAAIgD,EACF,OAAOA,EAGT,IAVqD,EAU/CmV,EAAmB,GAEnBlV,EAAe,IAAIoH,IAEnB+N,EAAmB,SAAChV,EAAckI,GACtC,IAAM9F,EAAiBpC,EAAaW,WAAa,IAAMX,EAAahE,GAE9DiZ,EAAmBpV,EAAawC,IAAID,GACtC6S,EACFA,EAAiBC,IAAIhN,GAErBrI,EAAauL,IAAIhJ,EAAgB,IAAIjD,IAAI,CAAC+I,KAG5C6M,EAAiBpS,KAAK3C,IAxB6B,KA2BjCpD,GA3BiC,IA2BrD,2BAA4B,KAAjBsL,EAAiB,QACpBlB,EAAYkB,EAAMlB,UACxB,GAAKA,EAAL,CAIA,IAAMmO,EAAyBnO,EAAUtH,cACzC,GAAIyV,EAAwB,YACCA,GADD,IAC1B,2BAAmD,KAAxCnV,EAAwC,QAC3CjE,EAASiE,EAAajE,OAQ5B,GANKmL,GACHlH,EAAcjE,EAAOuD,aAErB0V,EAAiBhV,EAAckI,GAGP,SAAtBnM,EAAOuD,WAAuB,CAChC,IAAM8H,EAAoBrL,EAAO2D,cACjC,GAAI0H,EAAmB,YACUA,GADV,IACrB,2BAAkD,KAAvCgO,EAAuC,QAC3ClO,GACHkO,EAAkBrZ,EAAOuD,aAEzB0V,EAAiBI,EAAkBlN,IALlB,kCAZD,kCAlCuB,8BA8DrD,OAFAtI,EAASH,EAAmBsV,EAAkB,CAAClV,aAAAA,IAC/CyU,GAAuBlJ,IAAIxO,EAAQgD,GAC5BA,EAqDCyV,CACEhB,GAAgBF,EAActD,OAGlC,OACH,CAAC2C,EAASW,EAAcpE,IAErBuF,EAAsB,UACzBR,MAAAA,OADyB,EACzBA,EAAqBS,MAAK,SAAAlW,GAAC,OAAIA,MAAAA,OAAJ,EAAIA,EAAGhB,iBADT,SAEtBmX,IAAqB,UAAEzE,EAAQrR,qBAAV,QAAE,EAAuBrB,QAC9CoX,IACH,UAAE1E,EAAQ2E,oBAAV,iBAAE,EAAsBhW,qBAAxB,QAAE,EAAqCrB,QACpCsX,EACJL,GACAE,GACAC,EAGIC,EAAe3E,EAAQ2E,aAEvBE,EAAsBxN,EAAAA,SAC1B,kBAAMoL,EAAQnV,OACZmV,EAAQjQ,KAAI,SAACsN,GAAD,aACV,SAAC,GAAD,CACEd,YAAaA,EACbW,SAAUA,EACVC,kBAAiB,UACfkE,EAA2BxS,IAAIwO,EAAO7U,WADvB,SAEjB4U,WAAYqD,GAAiBD,EAAiBnD,GAE9CA,OAAQA,EACRC,SAAUA,EACVC,QAASA,EACTnU,OAAQyX,GAAgBF,EAActD,IAJjCA,EAAO7U,OAOd,OACJ,CACE+U,EACAyC,EACAzD,EACAiE,EACAG,EACAU,EACA/D,IAIE+E,EAA6BzN,EAAAA,SAAc,kBAC9CkN,EACC9B,EAAQjQ,KAAI,SAACsN,EAAQtQ,GACnB,IAAMb,EAAgBoV,EAAoBvU,GAC1C,OAAKb,GAIH,iBACEhC,UAAU,iBACV,gBAAemT,EAAO/R,SAFxB,WAKE,yBACE,SAACoU,GAAA,EAAD,CAAmBrC,OAAQA,OAE7B,SAAC,GAAD,CAA4BnR,cAAeA,MALtCmR,EAAO7U,IANP,QAeT,OACH,CACDsZ,EACAR,EACAtB,IAGF,OACE,iCACE,eAAI9V,UAAU,YAAd,UAA2BoG,EAAAA,EAAAA,GAAE,eAE5B0P,MAAAA,GAAAA,EAASnV,QACR,gCACGyS,EAAW,MACV,SAAC,GAAD,CACEf,YAAaA,EACbW,SAAUA,EACV8C,QAASA,IAGZoC,MAGH,wBACG9R,EAAAA,EAAAA,GAAE,qFAKN6R,GACC,iBAAK3Z,GAAG,iBAAR,WACE,yBAAK8H,EAAAA,EAAAA,GAAE,aAEW,WAAhBiM,GAA4BY,GAC5B,iBAAKjT,UAAU,UAAf,WACE,SAACoY,GAAA,EAAD,KACA,wBACGhS,EAAAA,EAAAA,GAAE,yHAIL,KAEH+R,EAEAL,GACC,iBAAKxZ,GAAG,wBAAR,WACE,yBAAK8H,EAAAA,EAAAA,GAAE,cACP,SAAC,GAAD,CAAe6F,wBAAsB,EAAC7C,OAAQiK,OAE9C,KAEF0E,GACA,iBAAKzZ,GAAG,8BAAR,WACE,yBAAK8H,EAAAA,EAAAA,GAAE,oBACP,SAAC,GAAD,CAAe6F,wBAAsB,EAAC7C,OAAQ4O,OAE9C,QAEJ,a,0ECjVV,QANsB,SAACzG,GAAD,OACT,IAAXA,EACInL,EAAE,sBACFzC,EAAQ,sBAAuB,uBAAwB4N,EAAQ,CAACA,OAAAA,O","sources":["webpack://musicbrainz-server/./root/utility/areDatesEqual.js","webpack://musicbrainz-server/./root/utility/areDatePeriodsEqual.js","webpack://musicbrainz-server/./root/utility/groupRelationships.js","webpack://musicbrainz-server/./root/utility/relationshipDateText.js","webpack://musicbrainz-server/./root/static/scripts/common/i18n/semicolonOnlyList.js","webpack://musicbrainz-server/./root/utility/isDisabledLink.js","webpack://musicbrainz-server/./root/utility/isFutureDate.js","webpack://musicbrainz-server/./root/components/RelationshipTargetLinks.js","webpack://musicbrainz-server/./root/components/GroupedTrackRelationships.js","webpack://musicbrainz-server/./root/components/StaticRelationshipsDisplay.js","webpack://musicbrainz-server/./root/components/RelatedSeries.js","webpack://musicbrainz-server/./root/components/RelatedWorks.js","webpack://musicbrainz-server/./root/components/Relationships.js","webpack://musicbrainz-server/./root/static/scripts/common/utility/mapRange.js","webpack://musicbrainz-server/./root/components/Paginator.js","webpack://musicbrainz-server/./root/utility/uriWith.js","webpack://musicbrainz-server/./root/static/scripts/common/components/DataTrackIcon.js","webpack://musicbrainz-server/./node_modules/@babel/runtime/helpers/esm/wrapNativeSuper.js","webpack://musicbrainz-server/./node_modules/@babel/runtime/helpers/esm/isNativeFunction.js","webpack://musicbrainz-server/./root/static/scripts/common/utility/pThrottle.js","webpack://musicbrainz-server/./root/components/RatingStars.js","webpack://musicbrainz-server/./root/utility/returnUri.js","webpack://musicbrainz-server/./root/static/scripts/release/components/MediumTrackRow.js","webpack://musicbrainz-server/./root/static/scripts/release/components/MediumTable.js","webpack://musicbrainz-server/./root/utility/mediumHasMultipleArtists.js","webpack://musicbrainz-server/./root/static/scripts/release/components/MediumToolbox.js","webpack://musicbrainz-server/./root/static/scripts/release/components/TracklistAndCredits.js","webpack://musicbrainz-server/./root/utility/ratingTooltip.js"],"sourcesContent":["/*\n * @flow strict\n * Copyright (C) 2018 MetaBrainz Foundation\n *\n * This file is part of MusicBrainz, the open internet music database,\n * and is licensed under the GPL version 2, or (at your option) any\n * later version: http://www.gnu.org/licenses/gpl-2.0.txt\n */\n\nexport default function areDatesEqual(\n a: PartialDateT | null,\n b: PartialDateT | null,\n): boolean %checks {\n return (a === null && b === null) || (\n a !== null && b !== null &&\n a.year === b.year && a.month === b.month && a.day === b.day\n );\n}\n","/*\n * @flow strict\n * Copyright (C) 2019 MetaBrainz Foundation\n *\n * This file is part of MusicBrainz, the open internet music database,\n * and is licensed under the GPL version 2, or (at your option) any\n * later version: http://www.gnu.org/licenses/gpl-2.0.txt\n */\n\nimport areDatesEqual from './areDatesEqual';\n\nexport default function areDatePeriodsEqual<\n T: $ReadOnly<{...DatePeriodRoleT, ...}>,\n>(a: T, b: T): boolean %checks {\n return (\n a.ended === b.ended &&\n areDatesEqual(a.begin_date, b.begin_date) &&\n areDatesEqual(a.end_date, b.end_date)\n );\n}\n","/*\n * @flow strict-local\n * Copyright (C) 2018 MetaBrainz Foundation\n *\n * This file is part of MusicBrainz, the open internet music database,\n * and is licensed under the GPL version 2, or (at your option) any\n * later version: http://www.gnu.org/licenses/gpl-2.0.txt\n */\n\nimport {\n INSTRUMENT_ROOT_ID,\n VOCAL_ROOT_ID,\n} from '../static/scripts/common/constants';\nimport {compare} from '../static/scripts/common/i18n';\nimport commaList from '../static/scripts/common/i18n/commaList';\nimport linkedEntities from '../static/scripts/common/linkedEntities';\nimport {\n compareStrings,\n} from '../static/scripts/common/utility/compare';\nimport {compareDatePeriods}\n from '../static/scripts/common/utility/compareDates';\nimport {\n arraysEqual,\n mergeSortedArrayInto,\n sortedIndexWith,\n} from '../static/scripts/common/utility/arrays';\nimport {uniqueId} from '../static/scripts/common/utility/strings';\nimport {\n cmpLinkAttrs,\n getExtraAttributes,\n interpolate,\n interpolateText,\n} from '../static/scripts/edit/utility/linkPhrase';\n\nimport areDatePeriodsEqual from './areDatePeriodsEqual';\n\nconst UNIT_SEP = '\\x1F';\n\nexport type DatedExtraAttributes = {\n +attributes: Array,\n +datePeriods: Array,\n};\n\nexport type RelationshipTargetGroupT = {\n datedExtraAttributesList: Array,\n earliestDatePeriod: DatePeriodRoleT,\n editsPending: boolean,\n hasAttributes: boolean,\n isOrderable: boolean,\n key: string,\n linkOrder: number | null,\n target: CoreEntityT,\n targetCredit: string,\n tracks: Set | null,\n};\n\nexport type RelationshipPhraseGroupT = {\n combinedPhrase: Expand2ReactOutput,\n key: string,\n linkTypeInfo: Array<{\n editsPending: boolean,\n phrase: Expand2ReactOutput,\n rootTypeId: number | null,\n textPhrase: string,\n typeId: number,\n }>,\n targetGroups: Array,\n};\n\nexport type RelationshipTargetTypeGroupT = {\n +relationshipPhraseGroups: Array,\n +targetType: string,\n};\n\nfunction cmpRelationshipPhraseGroups(a, b) {\n const linkTypeInfoA = a.linkTypeInfo[0];\n const linkTypeInfoB = b.linkTypeInfo[0];\n return (\n (linkTypeInfoA.typeId - linkTypeInfoB.typeId) ||\n compare(linkTypeInfoA.textPhrase, linkTypeInfoB.textPhrase)\n );\n}\n\nconst cmpPhraseGroupLinkTypeInfo = (a, b) => (\n (a.typeId - b.typeId) ||\n compare(a.textPhrase, b.textPhrase)\n);\n\nfunction cmpFirstDatePeriods(\n a: DatedExtraAttributes,\n b: DatedExtraAttributes,\n) {\n return compareDatePeriods(\n a.datePeriods[0] ?? null,\n b.datePeriods[0] ?? null,\n );\n}\n\nconst cmpRelationshipTargetGroups = (a, b) => (\n ((a.linkOrder ?? 0) - (b.linkOrder ?? 0)) ||\n compareDatePeriods(a.earliestDatePeriod, b.earliestDatePeriod) ||\n compare(\n a.targetCredit || getSortName(a.target),\n b.targetCredit || getSortName(b.target),\n ) ||\n (a.target.id - b.target.id)\n);\n\nconst areLinkAttrsEqual = (a, b) => (\n a.typeID === b.typeID &&\n a.text_value === b.text_value &&\n a.credited_as === b.credited_as\n);\n\nconst areDatedExtraAttributesEqual = (a, b) => (\n arraysEqual(a.datePeriods, b.datePeriods, areDatePeriodsEqual) &&\n arraysEqual(a.attributes, b.attributes, areLinkAttrsEqual)\n);\n\nconst compareRelationshipTargetGroups = (\n a: RelationshipTargetGroupT,\n b: RelationshipTargetGroupT,\n options: {\n compareDatedExtraAttributesLists: boolean,\n compareTracks: boolean,\n },\n) => {\n return (\n a.target.id === b.target.id &&\n a.targetCredit === b.targetCredit &&\n /*\n * Ordered relationships are displayed as a numbered list. It doesn't\n * make sense to group differently-numbered parts together, even if they\n * refer to the same entity, so we include the linkOrder in the key.\n * (As an example, there are some known cases with \"part of\" work\n * relationships where a sub-work is supposed to be played twice in\n * different orders.)\n */\n a.linkOrder === b.linkOrder &&\n /*\n * Don't merge relationships without attributes into ones that have\n * them; that makes the ones without any completely invisible to the\n * user.\n */\n a.hasAttributes === b.hasAttributes &&\n\n (options.compareTracks ? (\n (a.tracks == null && b.tracks == null) ||\n (\n a.tracks != null &&\n b.tracks != null &&\n areSetsEqual(a.tracks, b.tracks)\n )\n ) : true) &&\n\n (options.compareDatedExtraAttributesLists\n ? arraysEqual(\n a.datedExtraAttributesList,\n b.datedExtraAttributesList,\n areDatedExtraAttributesEqual,\n )\n : true)\n );\n};\n\nconst canMergeTargetGroupsByTracksOptions = {\n compareDatedExtraAttributesLists: false,\n compareTracks: true,\n};\n\nconst canMergeTargetGroupsByTracks =\n (a, b) => compareRelationshipTargetGroups(\n a, b, canMergeTargetGroupsByTracksOptions,\n );\n\nconst canMergeTargetGroupsByAttributesOptions = {\n compareDatedExtraAttributesLists: true,\n compareTracks: false,\n};\n\nconst canMergeTargetGroupsByAttributes =\n (a, b) => compareRelationshipTargetGroups(\n a, b, canMergeTargetGroupsByAttributesOptions,\n );\n\nconst areTargetGroupsIdenticalOptions = {\n compareDatedExtraAttributesLists: true,\n compareTracks: true,\n};\n\nconst areTargetGroupsIdentical =\n (a, b) => compareRelationshipTargetGroups(\n a, b, areTargetGroupsIdenticalOptions,\n );\n\nfunction displayLinkPhrase(linkTypeInfo) {\n const phrase = linkTypeInfo.phrase;\n if (linkTypeInfo.editsPending) {\n return {phrase};\n }\n return phrase;\n}\n\nfunction isNotInstrumentOrVocal(attribute) {\n const type = linkedEntities.link_attribute_type[attribute.typeID];\n return (\n type.root_id !== INSTRUMENT_ROOT_ID &&\n type.root_id !== VOCAL_ROOT_ID\n );\n}\n\nfunction areAttributeListsMergeable(\n attributeList1,\n attributeList2,\n) {\n /*\n * Two attribute lists are mergeable for display if all their non-\n * instrument and non-vocal attributes are equal. This is basically\n * the inverse of Data::Util::split_relationship_by_attributes on the\n * server, which was added for MBS-1377 and introduced the display\n * issue described by MBS-7678.\n *\n * This method helps on orderable link types such as \"recording of.\"\n * When displaying those, we don't interpolate any attributes into\n * the link phrase in order to keep the relevant relationships\n * grouped and numbered together in a single list. Thus, without\n * the check below, something like\n * recording of: Work (in 2001: cover; in 2001: cover, live)\n * would be displayed only as\n * recording of: Work (in 2001: cover, live)\n * which creates a deficiency in the editing interface insofar as\n * it doesn't make duplicates visible to the user.\n */\n return arraysEqual(\n attributeList1.filter(isNotInstrumentOrVocal),\n attributeList2.filter(isNotInstrumentOrVocal),\n areLinkAttrsEqual,\n );\n}\n\n/*\n * MBS-7678: Given the following relationships,\n * member: A (1999-2005) (bass)\n * member: A (1999-2005) (guitar)\n * member: A (2009-) (bass)\n * member: A (2009-) (guitar)\n *\n * `groupedRelationships` below will compute a `datedExtraAttributesList`\n * for each relationship target group as follows:\n * [{attributes: [bass], datePeriods: [1999-2005]},\n * {attributes: [guitar], datePeriods: [1999-2005]},\n * {attributes: [bass], datePeriods: [2009-]},\n * {attributes: [guitar], datePeriods: [2009-]}]\n *\n * `mergeDatedExtraAttributes` implements part of MBS-7678 by taking the\n * above list, and\n * (1) merging the attributes lists where datePeriods are identical;\n * (2) merging the datePeriods lists where the attributes are identical\n *\n * in that order. The result then resembles the object below.\n * [{attributes: [bass, guitar], datePeriods: [1999-2005, 2009-]}]\n */\n\nfunction mergeDatedExtraAttributes(pairs) {\n for (let i = 0; i < pairs.length; i++) {\n const a = pairs[i];\n for (let j = i + 1; j < pairs.length; j++) {\n const b = pairs[j];\n if (areDatePeriodsEqual(a.datePeriods[0], b.datePeriods[0]) &&\n areAttributeListsMergeable(a.attributes, b.attributes)) {\n mergeSortedArrayInto(a.attributes, b.attributes, cmpLinkAttrs);\n pairs.splice(j, 1);\n j--;\n }\n }\n }\n for (let i = 0; i < pairs.length; i++) {\n const a = pairs[i];\n for (let j = i + 1; j < pairs.length; j++) {\n const b = pairs[j];\n if (arraysEqual(a.attributes, b.attributes, areLinkAttrsEqual)) {\n mergeSortedArrayInto(\n a.datePeriods,\n b.datePeriods,\n compareDatePeriods,\n );\n pairs.splice(j, 1);\n j--;\n }\n }\n }\n}\n\nexport function compareTrackPositions(a: TrackT, b: TrackT): number {\n return a.position - b.position;\n}\n\nfunction mergeTargetGroupsByTracks(\n targetGroups: Array,\n): void {\n for (let i = 0; i < targetGroups.length; i++) {\n for (let j = i + 1; j < targetGroups.length; j++) {\n const targetGroup1 = targetGroups[i];\n const targetGroup2 = targetGroups[j];\n\n if (canMergeTargetGroupsByAttributes(targetGroup1, targetGroup2)) {\n targetGroup1.tracks = new Set(\n [\n ...(targetGroup1.tracks || []),\n ...(targetGroup2.tracks || []),\n ].sort(compareTrackPositions),\n );\n targetGroups.splice(j, 1);\n j--;\n }\n }\n }\n}\n\nconst getSortName = x => x.entityType === 'artist' ? x.sort_name : x.name;\n\nfunction targetIsOrderable(relationship: RelationshipT) {\n const linkType = linkedEntities.link_type[relationship.linkTypeID];\n const backward = relationship.backward;\n // `backward` indicates that the relationship target is entity0\n return (linkType.orderable_direction === 1 && !backward) ||\n (linkType.orderable_direction === 2 && backward);\n}\n\nfunction areSetsEqual(a: Set, b: Set): boolean {\n if (a.size !== b.size) {\n return false;\n }\n for (const value of a) {\n if (!b.has(value)) {\n return false;\n }\n }\n return true;\n}\n\nexport default function groupRelationships(\n relationships: ?$ReadOnlyArray,\n args?: {\n +filter?: (RelationshipT, CoreEntityT, CoreEntityTypeT) => boolean,\n +result?: Array,\n +trackMapping?: Map>,\n +types?: ?$ReadOnlyArray,\n },\n): $ReadOnlyArray {\n if (!relationships) {\n return [];\n }\n\n let filter;\n let result;\n let trackMapping;\n let types;\n\n if (args) {\n filter = args.filter;\n result = args.result;\n trackMapping = args.trackMapping;\n types = args.types;\n }\n\n const targetTypeGroups: Array =\n (result ?? []);\n\n for (let i = 0; i < relationships.length; i++) {\n const relationship = relationships[i];\n const target = relationship.target;\n const targetType = target.entityType;\n\n if (types && !types.includes(targetType)) {\n continue;\n }\n\n if (filter && !filter(relationship, target, targetType)) {\n continue;\n }\n\n let targetTypeGroup;\n {\n const [index, exists] = sortedIndexWith(\n targetTypeGroups,\n targetType,\n (group, targetType) => compareStrings(group.targetType, targetType),\n );\n if (exists) {\n targetTypeGroup = targetTypeGroups[index];\n } else {\n targetTypeGroup = ({\n relationshipPhraseGroups: [],\n targetType,\n }: RelationshipTargetTypeGroupT);\n targetTypeGroups.splice(index, 0, targetTypeGroup);\n }\n }\n\n const backward = relationship.backward;\n const linkType = linkedEntities.link_type[relationship.linkTypeID];\n\n /*\n * In order to group relationships by link phrase, the link phrase\n * must be a string. However, phrases with instruments contain\n * links, so produce a React element from `interpolate`. We can't\n * use a React element as a grouping key for obvious reasons. (We\n * could convert it to HTML and use that as the key, but the HTML\n * would be more difficult to sort properly.) The solution is to\n * always call `interpolateText` to produce a rendered phrase\n * suitable for grouping. If the relationship contains instruments,\n * we additionally call `interpolate` to produce a phrase with\n * links for display. There's currently no other case where\n * `interpolateText` doesn't suffice for display, so we otherwise\n * just use the `textPhrase` for display if the relationship is\n * instrument-free.\n */\n let hasInstruments = false;\n const linkAttrs = relationship.attributes;\n if (linkAttrs) {\n for (let i = 0; i < linkAttrs.length; i++) {\n const linkAttr = linkAttrs[i];\n const linkAttrType =\n linkedEntities.link_attribute_type[linkAttr.typeID];\n if (linkAttrType.root_id === INSTRUMENT_ROOT_ID) {\n hasInstruments = true;\n break;\n }\n }\n }\n\n const phraseArgs = [\n linkType,\n linkAttrs,\n backward ? 'reverse_link_phrase' : 'link_phrase',\n true, /* forGrouping */\n ];\n\n let textPhrase = interpolateText(...phraseArgs);\n let phrase;\n\n if (hasInstruments) {\n phrase = interpolate(...phraseArgs);\n }\n\n const sourceCredit = backward\n ? relationship.entity1_credit\n : relationship.entity0_credit;\n\n if (sourceCredit) {\n textPhrase = texp.l('{role} (as {credited_name})', {\n credited_name: sourceCredit,\n role: textPhrase,\n });\n\n if (hasInstruments /*:: && nonEmpty(phrase) */) {\n phrase = exp.l('{role} (as {credited_name})', {\n credited_name: sourceCredit,\n role: phrase,\n });\n }\n }\n\n /*\n * linkType.id shouldn't really be needed in the grouping key, since\n * two different link types to the same entity types shouldn't ever\n * produce the same text phrase. Nonetheless, the code should continue\n * to work if that happens.\n */\n const phraseGroupKey = textPhrase + UNIT_SEP + String(linkType.id);\n let phraseGroup;\n {\n const phraseGroups = targetTypeGroup.relationshipPhraseGroups;\n const [index, exists] = sortedIndexWith(\n phraseGroups,\n phraseGroupKey,\n (group, phraseGroupKey) => compare(group.key, phraseGroupKey),\n );\n if (exists) {\n phraseGroup = phraseGroups[index];\n } else {\n phraseGroup = ({\n combinedPhrase: '',\n key: phraseGroupKey,\n linkTypeInfo: [{\n editsPending: relationship.editsPending,\n phrase: phrase ?? textPhrase,\n rootTypeId: linkType.root_id,\n textPhrase,\n typeId: linkType.id,\n }],\n targetGroups: [],\n }: RelationshipPhraseGroupT);\n phraseGroups.splice(index, 0, phraseGroup);\n }\n }\n\n const targetCredit = relationship.backward\n ? relationship.entity0_credit\n : relationship.entity1_credit;\n const isOrderable = targetIsOrderable(relationship);\n const linkOrder = relationship.linkOrder;\n const datePeriod = {\n begin_date: relationship.begin_date,\n end_date: relationship.end_date,\n ended: relationship.ended,\n };\n const hasAttributes = relationship.attributes\n ? relationship.attributes.length > 0\n : false;\n\n let tracks = null;\n if (trackMapping) {\n const relationshipId = relationship.linkTypeID + '-' + relationship.id;\n /*\n * Get the tracks this relationship appears on.\n * (A recording or work can be linked to multiple tracks.)\n */\n tracks = trackMapping.get(relationshipId) || null;\n }\n\n let targetGroup = ({\n datedExtraAttributesList: [],\n earliestDatePeriod: datePeriod,\n editsPending: relationship.editsPending,\n hasAttributes,\n isOrderable,\n key: uniqueId(),\n linkOrder,\n target,\n targetCredit,\n tracks,\n }: RelationshipTargetGroupT);\n\n /*\n * Ensure we're not merging target groups across different tracks yet.\n * This will be done later, as a separate step, after attribute/date\n * lists are combined. See `mergeTargetGroupsByTracks`.\n */\n const existingTargetGroup = phraseGroup.targetGroups.find(\n (otherTargetGroup) => canMergeTargetGroupsByTracks(\n targetGroup,\n otherTargetGroup,\n ),\n );\n\n if (existingTargetGroup) {\n targetGroup = existingTargetGroup;\n } else {\n phraseGroup.targetGroups.push(targetGroup);\n }\n\n if (datePeriod !== targetGroup.earliestDatePeriod) {\n if (compareDatePeriods(\n datePeriod,\n targetGroup.earliestDatePeriod,\n ) < 0) {\n targetGroup.earliestDatePeriod = datePeriod;\n }\n }\n\n targetGroup.datedExtraAttributesList.push({\n attributes: [...getExtraAttributes(...phraseArgs)],\n datePeriods: [datePeriod],\n });\n\n /*\n * If one of the relationships in the target group has pending edits,\n * mark the whole group as having pending edits.\n */\n targetGroup.editsPending = targetGroup.editsPending ||\n relationship.editsPending;\n }\n\n for (const targetTypeGroup of targetTypeGroups) {\n const phraseGroups = targetTypeGroup.relationshipPhraseGroups;\n\n for (let i = 0; i < phraseGroups.length; i++) {\n const targetGroups = phraseGroups[i].targetGroups;\n\n for (let j = 0; j < targetGroups.length; j++) {\n const datedExtraAttributesList =\n targetGroups[j].datedExtraAttributesList;\n mergeDatedExtraAttributes(datedExtraAttributesList);\n datedExtraAttributesList.sort(cmpFirstDatePeriods);\n }\n\n if (trackMapping) {\n mergeTargetGroupsByTracks(targetGroups);\n }\n\n targetGroups.sort(cmpRelationshipTargetGroups);\n }\n\n for (let i = 0; i < phraseGroups.length; i++) {\n const phraseGroup1 = phraseGroups[i];\n const linkTypeInfo1 = phraseGroup1.linkTypeInfo;\n\n /*\n * As a final nicety for MBS-7678, we further merge phrase groups\n * together that (1) share a link type or parent link type, and (2)\n * have completely identical target entity lists *including* the\n * dated extra attribute lists for each target.\n */\n for (let j = i + 1; j < phraseGroups.length; j++) {\n const phraseGroup2 = phraseGroups[j];\n const firstLinkType2 = phraseGroup2.linkTypeInfo[0];\n const relatedLinkType = linkTypeInfo1.find(t => (\n t.rootTypeId === firstLinkType2.rootTypeId\n ));\n const targetGroups1 = phraseGroup1.targetGroups;\n const targetGroups2 = phraseGroup2.targetGroups;\n\n if (relatedLinkType && arraysEqual(\n targetGroups1,\n targetGroups2,\n areTargetGroupsIdentical,\n )) {\n // Merge editsPending flags\n for (let k = 0; k < targetGroups1.length; k++) {\n const targetGroup1 = targetGroups1[k];\n targetGroup1.editsPending =\n targetGroup1.editsPending || targetGroups2[k].editsPending;\n }\n\n const [index, exists] = sortedIndexWith(\n linkTypeInfo1,\n firstLinkType2,\n cmpPhraseGroupLinkTypeInfo,\n );\n if (!exists) {\n phraseGroup1.key += UNIT_SEP + phraseGroup2.key;\n linkTypeInfo1.splice(index, 0, firstLinkType2);\n phraseGroups.splice(j, 1);\n j--;\n }\n }\n }\n\n phraseGroup1.combinedPhrase = linkTypeInfo1.length > 1\n ? commaList(linkTypeInfo1.map(displayLinkPhrase))\n : displayLinkPhrase(linkTypeInfo1[0]);\n }\n\n phraseGroups.sort(cmpRelationshipPhraseGroups);\n }\n\n return targetTypeGroups;\n}\n","/*\n * @flow strict-local\n * Copyright (C) 2019 MetaBrainz Foundation\n *\n * This file is part of MusicBrainz, the open internet music database,\n * and is licensed under the GPL version 2, or (at your option) any\n * later version: http://www.gnu.org/licenses/gpl-2.0.txt\n */\n\nimport {bracketedText} from '../static/scripts/common/utility/bracketed';\nimport formatDate from '../static/scripts/common/utility/formatDate';\n\nimport areDatesEqual from './areDatesEqual';\n\nexport default function relationshipDateText(\n r: $ReadOnly<{...DatePeriodRoleT, ...}>,\n bracketEnded?: boolean = true,\n): string {\n if (r.begin_date) {\n if (r.end_date) {\n if (areDatesEqual(r.begin_date, r.end_date)) {\n if (r.begin_date.day != null) {\n return texp.l('on {date}', {date: formatDate(r.begin_date)});\n }\n return texp.l('in {date}', {date: formatDate(r.begin_date)});\n }\n return texp.l('from {begin_date} until {end_date}', {\n begin_date: formatDate(r.begin_date),\n end_date: formatDate(r.end_date),\n });\n } else if (r.ended) {\n return texp.l('from {date} to ????', {date: formatDate(r.begin_date)});\n }\n return texp.l('from {date} to present', {date: formatDate(r.begin_date)});\n } else if (r.end_date) {\n return texp.l('until {date}', {date: formatDate(r.end_date)});\n } else if (r.ended) {\n let text = l('ended');\n if (bracketEnded) {\n text = bracketedText(text);\n }\n return text;\n }\n return '';\n}\n","/*\n * @flow strict\n * Copyright (C) 2015-2016 MetaBrainz Foundation\n *\n * This file is part of MusicBrainz, the open internet music database,\n * and is licensed under the GPL version 2, or (at your option) any\n * later version: http://www.gnu.org/licenses/gpl-2.0.txt\n */\n\nfunction _semicolonOnlyList(\n l: ExpandLFunc,\n items: $ReadOnlyArray,\n): Output | string {\n const length = items.length;\n\n if (!length) {\n return '';\n }\n\n let output = l('{last_list_item}', {\n last_list_item: items[length - 1],\n });\n\n for (let i = length - 2; i >= 0; i--) {\n output = l('{semicolon_only_list_item}; {rest}', {\n rest: output,\n semicolon_only_list_item: items[i],\n });\n }\n\n return output;\n}\n\nexport default function semicolonOnlyList(\n items: $ReadOnlyArray,\n): Expand2ReactOutput | string {\n return _semicolonOnlyList(exp.l, items);\n}\n\nexport function semicolonOnlyListText(\n items: $ReadOnlyArray,\n): string {\n return _semicolonOnlyList(texp.l, items);\n}\n","/*\n * @flow strict\n * Copyright (C) 2020 MetaBrainz Foundation\n *\n * This file is part of MusicBrainz, the open internet music database,\n * and is licensed under the GPL version 2, or (at your option) any\n * later version: http://www.gnu.org/licenses/gpl-2.0.txt\n */\n\nimport isGreyedOut from '../url/utility/isGreyedOut';\nimport isFutureDate from '../utility/isFutureDate';\n\nexport default function isDisabledLink(\n relationshipOrLinkDatePeriod: {\n +end_date: PartialDateT | null,\n +ended: boolean,\n ...\n },\n entity: CoreEntityT,\n): boolean {\n const isEnded = relationshipOrLinkDatePeriod.ended &&\n !isFutureDate(relationshipOrLinkDatePeriod.end_date);\n\n return entity.entityType === 'url' && (\n isEnded || isGreyedOut(entity.href_url)\n );\n}\n","/*\n * @flow strict\n * Copyright (C) 2020 MetaBrainz Foundation\n *\n * This file is part of MusicBrainz, the open internet music database,\n * and is licensed under the GPL version 2, or (at your option) any\n * later version: http://www.gnu.org/licenses/gpl-2.0.txt\n */\n\nexport default function isFutureDate(\n givenDate: PartialDateT | null,\n): boolean {\n const givenYear = givenDate?.year;\n if (givenDate == null || givenYear == null) {\n return false;\n }\n\n const now = new Date();\n const currentDate = {\n day: now.getUTCDate(),\n // Months in JavaScript are 0-based. (Days and years are not.)\n month: now.getUTCMonth() + 1,\n year: now.getUTCFullYear(),\n };\n\n if (givenYear > currentDate.year) {\n return true;\n }\n\n if (givenYear === currentDate.year) {\n if (givenDate.month == null) {\n return false;\n }\n if (givenDate.month > currentDate.month) {\n return true;\n }\n if (givenDate.month === currentDate.month) {\n if (givenDate.day == null) {\n return false;\n }\n if (givenDate.day > currentDate.day) {\n return true;\n }\n }\n }\n\n return false;\n}\n","/*\n * @flow strict-local\n * Copyright (C) 2018 MetaBrainz Foundation\n *\n * This file is part of MusicBrainz, the open internet music database,\n * and is licensed under the GPL version 2, or (at your option) any\n * later version: http://www.gnu.org/licenses/gpl-2.0.txt\n */\n\nimport * as React from 'react';\n\nimport EntityLink from '../static/scripts/common/components/EntityLink';\nimport DescriptiveLink\n from '../static/scripts/common/components/DescriptiveLink';\nimport commaOnlyList, {commaOnlyListText}\n from '../static/scripts/common/i18n/commaOnlyList';\nimport bracketed from '../static/scripts/common/utility/bracketed';\nimport displayLinkAttribute\n from '../static/scripts/common/utility/displayLinkAttribute';\nimport {artistCreditsAreEqual}\n from '../static/scripts/common/immutable-entities';\nimport semicolonOnlyList\n from '../static/scripts/common/i18n/semicolonOnlyList';\nimport type {\n DatedExtraAttributes,\n RelationshipTargetGroupT,\n} from '../utility/groupRelationships';\nimport isDisabledLink from '../utility/isDisabledLink';\nimport relationshipDateText from '../utility/relationshipDateText';\n\nexport function displayDatedExtraAttributes(\n pair: DatedExtraAttributes,\n): React.MixedElement | string {\n const renderedDatePeriods = commaOnlyListText(\n pair.datePeriods.map(datePeriod => (\n relationshipDateText(datePeriod, false /* bracketEnded */)\n )),\n );\n const renderedExtraAttributes = commaOnlyList(\n pair.attributes.map(displayLinkAttribute),\n );\n if (renderedDatePeriods) {\n if (renderedExtraAttributes) {\n return (\n <>\n {addColon(renderedDatePeriods)}\n {' '}\n {renderedExtraAttributes}\n \n );\n }\n return renderedDatePeriods;\n }\n return renderedExtraAttributes;\n}\n\ntype Props = {\n +hiddenArtistCredit?: ?ArtistCreditT,\n +relationship: RelationshipTargetGroupT,\n};\n\nconst RelationshipTargetLinks = ({\n hiddenArtistCredit,\n relationship,\n}: Props): React.MixedElement => {\n const target = relationship.target;\n const targetCredit = relationship.targetCredit;\n const disableLink = isDisabledLink(relationship.earliestDatePeriod, target);\n let link;\n if (hiddenArtistCredit &&\n target.artistCredit &&\n artistCreditsAreEqual(hiddenArtistCredit, target.artistCredit)) {\n link = ;\n } else {\n link = (\n \n );\n }\n const datesAndAttributes = semicolonOnlyList(\n relationship.datedExtraAttributesList.map(displayDatedExtraAttributes),\n );\n let result = (\n <>\n {link}\n {datesAndAttributes ? (\n <>\n {' '}\n {bracketed(datesAndAttributes)}\n \n ) : null}\n \n );\n if (relationship.editsPending) {\n result = {result};\n }\n return result;\n};\n\nexport default RelationshipTargetLinks;\n","/*\n * @flow strict-local\n * Copyright (C) 2019 MetaBrainz Foundation\n *\n * This file is part of MusicBrainz, the open internet music database,\n * and is licensed under the GPL version 2, or (at your option) any\n * later version: http://www.gnu.org/licenses/gpl-2.0.txt\n */\n\nimport * as React from 'react';\n\nimport EntityLink from '../static/scripts/common/components/EntityLink';\nimport commaList from '../static/scripts/common/i18n/commaList';\nimport linkedEntities from '../static/scripts/common/linkedEntities';\nimport {bracketedText} from '../static/scripts/common/utility/bracketed';\nimport {interpolate} from '../static/scripts/edit/utility/linkPhrase';\nimport groupRelationships, {\n type RelationshipPhraseGroupT,\n type RelationshipTargetGroupT,\n} from '../utility/groupRelationships';\nimport relationshipDateText from '../utility/relationshipDateText';\n\nimport RelationshipTargetLinks from './RelationshipTargetLinks';\n\ntype Props = {\n +source: CoreEntityT,\n};\n\nconst renderTargetGroup = (targetGroup: RelationshipTargetGroupT) => (\n \n);\n\nconst renderPhraseGroup = (phraseGroup: RelationshipPhraseGroupT) => (\n \n
{addColon(phraseGroup.combinedPhrase)}
\n
\n {commaList(\n phraseGroup.targetGroups.map(renderTargetGroup),\n )}\n
\n
\n);\n\nconst renderWorkRelationship = (relationship: RelationshipT) => {\n const work = relationship.target;\n const phrase = interpolate(\n linkedEntities.link_type[relationship.linkTypeID],\n relationship.attributes,\n relationship.backward ? 'reverse_link_phrase' : 'link_phrase',\n /*\n * Work relationships are not grouped together on a single line,\n * because we have to output the relationships of the work under\n * its parent recording-work relationship. So it's intentional that\n * we use forGrouping=false here.\n */\n false, /* forGrouping */\n );\n\n const title = relationship.editsPending\n ? {phrase}\n : phrase;\n\n const targetCredit = relationship.backward\n ? relationship.entity0_credit\n : relationship.entity1_credit;\n\n return (\n \n
{addColon(title)}
\n
\n \n {' '}\n {bracketedText(relationshipDateText(\n relationship,\n false /* bracketEnded */,\n ))}\n \n
\n
\n );\n};\n\n/*\n * Specifically ignore rels that do not give information\n * relevant to this track, such as other arrangements of the work,\n * all the parts of the work linked, or all remixes of this recording.\n *\n * The format of the map is [id, is backward (direction)]\n */\nconst irrelevantLinkTypes: {\n [entity: CoreEntityTypeT]: Map,\n} = {\n recording: new Map([\n [226, false], // karaoke versions of this\n [227, true], // DJ-mixes of this\n [228, true], // recordings compiling this one\n [230, true], // remixes of this\n [231, true], // recordings sampling this one\n [232, true], // mash-ups of this\n [309, true], // edits of this\n ]),\n work: new Map([\n [239, true], // medleys including this\n [241, false], // generic later versions\n [281, false], // parts\n [314, false], // works based on this\n [315, false], // revisions\n [316, false], // orchestrations\n [350, false], // arrangements\n ]),\n};\n\nexport function isIrrelevantLinkType(\n relationship: RelationshipT,\n targetType: CoreEntityTypeT,\n): boolean {\n const irrelevantTypesForTargetType = irrelevantLinkTypes[targetType];\n if (irrelevantTypesForTargetType == null) {\n return false;\n }\n return irrelevantTypesForTargetType.get(relationship.linkTypeID) ===\n relationship.backward;\n}\n\nconst GroupedTrackRelationships = ({\n source,\n}: Props): Array> => {\n const workRelationships = [];\n\n const groupedRelationships = groupRelationships(\n source.relationships,\n {\n filter: (\n relationship: RelationshipT,\n target: CoreEntityT,\n targetType: CoreEntityTypeT,\n ) => {\n if (targetType === 'work') {\n if (!isIrrelevantLinkType(relationship, targetType)) {\n workRelationships.push(relationship);\n }\n return false;\n }\n if (targetType === 'url') {\n return false;\n }\n if (!isIrrelevantLinkType(relationship, targetType)) {\n return true;\n }\n return false;\n },\n },\n );\n\n const arsList = [];\n\n for (const targetTypeGroup of groupedRelationships) {\n const targetType = targetTypeGroup.targetType;\n if (targetType === 'url') {\n continue;\n }\n arsList.push(\n
\n {targetTypeGroup.relationshipPhraseGroups.map(renderPhraseGroup)}\n
,\n );\n }\n\n if (workRelationships.length) {\n arsList.push(\n
\n {workRelationships.map(renderWorkRelationship)}\n
,\n );\n }\n\n return arsList;\n};\n\nexport default GroupedTrackRelationships;\n","/*\n * @flow\n * Copyright (C) 2018 MetaBrainz Foundation\n *\n * This file is part of MusicBrainz, the open internet music database,\n * and is licensed under the GPL version 2, or (at your option) any\n * later version: http://www.gnu.org/licenses/gpl-2.0.txt\n */\n\nimport * as React from 'react';\n\nimport RelationshipTargetLinks from '../components/RelationshipTargetLinks';\nimport {commaOnlyListText} from '../static/scripts/common/i18n/commaOnlyList';\nimport {bracketedText} from '../static/scripts/common/utility/bracketed';\nimport {\n type RelationshipTargetTypeGroupT,\n compareTrackPositions,\n} from '../utility/groupRelationships';\n\nconst detailsTableStyle = Object.freeze({width: '100%'});\n\nfunction formatTrackRange(range) {\n if (range[1] == null) {\n return range[0].number;\n }\n return texp.l('{start_track}–{end_track}', {\n end_track: range[1].number,\n start_track: range[0].number,\n });\n}\n\nfunction getTrackRanges(trackSet) {\n const tracks = [...trackSet].sort(compareTrackPositions);\n\n let range: [TrackT, TrackT | null] = [tracks[0], null];\n\n const ranges = [range];\n\n for (let i = 1; i < tracks.length; i++) {\n const track = tracks[i];\n const difference = track.position -\n (range[1] == null ? range[0].position : range[1].position);\n if (difference > 0) {\n if (difference === 1) {\n range[1] = track;\n } else {\n range = [track, null];\n ranges.push(range);\n }\n }\n }\n\n return commaOnlyListText(ranges.map(formatTrackRange));\n}\n\ntype PropsT = {\n +hiddenArtistCredit?: ?ArtistCreditT,\n +relationships: $ReadOnlyArray,\n};\n\nconst StaticRelationshipsDisplay = (React.memo(({\n hiddenArtistCredit,\n relationships: groupedRelationships,\n}: PropsT): Array> => {\n const tables = [];\n\n for (let i = 0; i < groupedRelationships.length; i++) {\n const targetTypeGroup = groupedRelationships[i];\n const relationshipPhraseGroups = targetTypeGroup.relationshipPhraseGroups;\n const targetTypeRows = [];\n\n for (let j = 0; j < relationshipPhraseGroups.length; j++) {\n const phraseGroup = relationshipPhraseGroups[j];\n const groupSize = phraseGroup.targetGroups.length;\n const phraseRows = [];\n\n for (let k = 0; k < groupSize; k++) {\n const targetGroup = phraseGroup.targetGroups[k];\n\n const relationshipLink = (\n \n );\n\n phraseRows.push(\n \n {targetGroup.linkOrder ? (\n targetGroup.isOrderable ? (\n exp.l('{num}. {relationship}', {\n num: targetGroup.linkOrder,\n relationship: relationshipLink,\n })\n ) : (\n exp.l('{relationship} (order: {num})', {\n num: targetGroup.linkOrder,\n relationship: relationshipLink,\n })\n )\n ) : relationshipLink}\n {targetGroup.tracks ? (\n <>\n {' '}\n \n {bracketedText(\n texp.ln(\n 'track {tracks}',\n 'tracks {tracks}',\n targetGroup.tracks.size,\n {tracks: getTrackRanges(targetGroup.tracks)},\n ),\n )}\n \n \n ) : null}\n
\n
,\n );\n }\n\n targetTypeRows.push(\n \n {addColon(phraseGroup.combinedPhrase)}\n {phraseRows}\n ,\n );\n }\n\n tables.push(\n \n \n {targetTypeRows}\n \n ,\n );\n }\n\n return tables;\n}): React.AbstractComponent);\n\nexport default StaticRelationshipsDisplay;\n","/*\n * @flow strict-local\n * Copyright (C) 2018 MetaBrainz Foundation\n *\n * This file is part of MusicBrainz, the open internet music database,\n * and is licensed under the GPL version 2, or (at your option) any\n * later version: http://www.gnu.org/licenses/gpl-2.0.txt\n */\n\nimport * as React from 'react';\n\nimport EntityLink from '../static/scripts/common/components/EntityLink';\nimport linkedEntities from '../static/scripts/common/linkedEntities';\nimport groupRelationships from '../utility/groupRelationships';\n\nimport {isNotSeriesPart} from './Relationships';\nimport StaticRelationshipsDisplay from './StaticRelationshipsDisplay';\n\ntype Props = {\n +seriesIds: $ReadOnlyArray,\n};\n\nconst RelatedSeries = ({seriesIds}: Props): React.MixedElement => {\n const createArgs = [\n React.Fragment,\n null,\n /* eslint-disable react/jsx-key */\n

\n {l('Related series')}\n

,\n ];\n for (let i = 0; i < seriesIds.length; i++) {\n const series = linkedEntities.series[seriesIds[i]];\n createArgs.push(\n

\n \n

,\n ,\n );\n }\n return React.createElement.apply(React, createArgs);\n};\n\nexport default RelatedSeries;\n","/*\n * @flow strict-local\n * Copyright (C) 2018 MetaBrainz Foundation\n *\n * This file is part of MusicBrainz, the open internet music database,\n * and is licensed under the GPL version 2, or (at your option) any\n * later version: http://www.gnu.org/licenses/gpl-2.0.txt\n */\n\nimport * as React from 'react';\n\nimport EntityLink from '../static/scripts/common/components/EntityLink';\nimport linkedEntities from '../static/scripts/common/linkedEntities';\nimport groupRelationships from '../utility/groupRelationships';\n\nimport StaticRelationshipsDisplay from './StaticRelationshipsDisplay';\n\nconst targetEntityTypes = [\n 'area',\n 'artist',\n 'label',\n 'place',\n 'work',\n];\n\ntype Props = {\n +workIds: $ReadOnlyArray,\n};\n\nconst RelatedWorks = ({workIds}: Props): React.MixedElement => {\n const createArgs = [\n React.Fragment,\n null,\n /* eslint-disable react/jsx-key */\n

\n {l('Related works')}\n

,\n ];\n for (let i = 0; i < workIds.length; i++) {\n const work = linkedEntities.work[workIds[i]];\n createArgs.push(\n

\n \n

,\n ,\n );\n }\n return React.createElement.apply(React, createArgs);\n};\n\nexport default RelatedWorks;\n","/*\n * @flow\n * Copyright (C) 2018 MetaBrainz Foundation\n *\n * This file is part of MusicBrainz, the open internet music database,\n * and is licensed under the GPL version 2, or (at your option) any\n * later version: http://www.gnu.org/licenses/gpl-2.0.txt\n */\n\nimport * as React from 'react';\n\nimport {PART_OF_SERIES_LINK_TYPES} from '../static/scripts/common/constants';\nimport EntityLink from '../static/scripts/common/components/EntityLink';\nimport linkedEntities from '../static/scripts/common/linkedEntities';\nimport groupRelationships, {type RelationshipTargetTypeGroupT}\n from '../utility/groupRelationships';\n\nimport RelatedSeries from './RelatedSeries';\nimport RelatedWorks from './RelatedWorks';\nimport StaticRelationshipsDisplay from './StaticRelationshipsDisplay';\n\ntype DisplayTargets = {\n +[coreEntityType: CoreEntityTypeT]: ?$ReadOnlyArray,\n ...\n};\n\nconst displayTargets: DisplayTargets = {\n artist: [\n 'artist',\n 'url',\n 'label',\n 'place',\n 'area',\n 'series',\n 'instrument',\n ],\n label: [\n 'artist',\n 'url',\n 'label',\n 'place',\n 'area',\n 'series',\n 'instrument',\n ],\n work: [\n 'artist',\n 'release_group',\n 'release',\n 'work',\n 'url',\n 'label',\n 'place',\n 'area',\n 'series',\n 'instrument',\n 'event',\n ],\n};\n\nconst seriesPartLinkTypes = new Set(\n Object.values(PART_OF_SERIES_LINK_TYPES),\n);\n\nexport function isNotSeriesPart(r: RelationshipT): boolean {\n return !seriesPartLinkTypes.has(linkedEntities.link_type[r.linkTypeID].gid);\n}\n\ntype PropsT = {\n +noRelationshipsHeading?: boolean,\n +relationships?: $ReadOnlyArray,\n +showIfEmpty?: boolean,\n +source: CoreEntityT,\n};\n\nconst Relationships = (React.memo(({\n noRelationshipsHeading = false,\n relationships,\n showIfEmpty = false,\n source,\n}: PropsT): React.Element => {\n let srcRels = source.relationships;\n if (!relationships) {\n if (srcRels && source.entityType === 'series') {\n srcRels = srcRels.filter(isNotSeriesPart);\n }\n relationships = groupRelationships(\n srcRels,\n {types: displayTargets[source.entityType]},\n );\n }\n\n const hiddenArtistCredit: ?ArtistCreditT = source.entityType === 'artist'\n ? {names: [{artist: source, joinPhrase: '', name: source.name}]}\n : (source.artistCredit || null);\n\n const heading = noRelationshipsHeading\n ? null\n :

{l('Relationships')}

;\n\n return (\n <>\n {relationships.length ? (\n <>\n {heading}\n \n \n ) : source.entityType === 'artist' && srcRels?.length ? (\n <>\n {heading}\n

\n {exp.l(\n `{link} only has event relationships,\n which are displayed in the Events tab.`,\n {link: },\n )}\n

\n \n ) : showIfEmpty ? (\n <>\n {heading}\n

\n {exp.l(\n '{link} has no relationships.',\n {link: },\n )}\n

\n \n ) : null}\n {source.entityType === 'recording' && source.related_works.length ? (\n \n ) : null}\n {source.entityType === 'event' && source.related_series.length ? (\n \n ) : null}\n \n );\n}): React.AbstractComponent);\n\nexport default Relationships;\n","/*\n * @flow strict\n * Copyright (C) 2020 MetaBrainz Foundation\n *\n * This file is part of MusicBrainz, the open internet music database,\n * and is licensed under the GPL version 2, or (at your option) any\n * later version: http://www.gnu.org/licenses/gpl-2.0.txt\n */\n\nexport default function mapRange(\n start: number,\n end: number,\n func: (number) => T,\n): Array {\n const result = [];\n for (let i = start; i <= end; i++) {\n result.push(func(i));\n }\n return result;\n}\n","/*\n * @flow\n * Copyright (C) 2018 MetaBrainz Foundation\n *\n * This file is part of MusicBrainz, the open internet music database,\n * and is licensed under the GPL version 2, or (at your option) any\n * later version: http://www.gnu.org/licenses/gpl-2.0.txt\n */\n\nimport * as React from 'react';\n\nimport mapRange from '../static/scripts/common/utility/mapRange';\nimport uriWith from '../utility/uriWith';\n\ntype PageQueryParam = 'apps_page' | 'page' | 'tokens_page';\ntype PageQueryObject = {[pageVar: PageQueryParam]: number, ...};\n\ntype Props = {\n +$c: CatalystContextT,\n +guessSearch?: boolean,\n +hash?: string,\n +pager: PagerT,\n +pageVar?: PageQueryParam,\n};\n\nfunction uriPage(\n uri: string,\n pageVar: PageQueryParam,\n page: number,\n hash: ?string,\n) {\n /*\n * See \"Flow errors on unions in computed properties\" here:\n * https://medium.com/flow-type/spreads-common-errors-fixes-9701012e9d58\n */\n const params: PageQueryObject = {};\n params[pageVar] = page;\n return uriWith(uri, params) +\n (nonEmpty(hash) ? '#' + hash : '');\n}\n\nconst Paginator = ({\n $c,\n guessSearch = false,\n hash,\n pager,\n pageVar = 'page',\n}: Props): React.Element<'nav'> | null => {\n const lastPage = pager.last_page;\n\n if (lastPage <= 1) {\n return null;\n }\n\n const firstPage = pager.first_page;\n const previousPage = pager.previous_page;\n const nextPage = pager.next_page;\n\n const start = (pager.current_page - 4) > 0\n ? (pager.current_page - 4) : 1;\n\n const end = (pager.current_page + 4) < lastPage\n ? (pager.current_page + 4) : lastPage;\n\n const reqUri = $c.req.uri;\n\n return (\n \n );\n};\n\nexport default Paginator;\n","/*\n * @flow strict\n * Copyright (C) 2018 MetaBrainz Foundation\n *\n * This file is part of MusicBrainz, the open internet music database,\n * and is licensed under the GPL version 2, or (at your option) any\n * later version: http://www.gnu.org/licenses/gpl-2.0.txt\n */\n\nexport default function uriWith(\n uriString: string,\n params: T,\n): string {\n const urlObject = new URL(uriString);\n const searchParams = new URLSearchParams(urlObject.search);\n\n for (const key of Object.keys(params)) {\n searchParams.set(key, params[key]);\n }\n\n urlObject.search = searchParams.toString();\n\n return urlObject.href;\n}\n","/*\n * @flow strict\n * Copyright (C) 2020 MetaBrainz Foundation\n *\n * This file is part of MusicBrainz, the open internet music database,\n * and is licensed under the GPL version 2, or (at your option) any\n * later version: http://www.gnu.org/licenses/gpl-2.0.txt\n */\n\nimport * as React from 'react';\n\nconst DataTrackIcon = (): React.Element<'div'> => (\n \n);\n\nexport default DataTrackIcon;\n","import getPrototypeOf from \"./getPrototypeOf.js\";\nimport setPrototypeOf from \"./setPrototypeOf.js\";\nimport isNativeFunction from \"./isNativeFunction.js\";\nimport construct from \"./construct.js\";\nexport default function _wrapNativeSuper(Class) {\n var _cache = typeof Map === \"function\" ? new Map() : undefined;\n\n _wrapNativeSuper = function _wrapNativeSuper(Class) {\n if (Class === null || !isNativeFunction(Class)) return Class;\n\n if (typeof Class !== \"function\") {\n throw new TypeError(\"Super expression must either be null or a function\");\n }\n\n if (typeof _cache !== \"undefined\") {\n if (_cache.has(Class)) return _cache.get(Class);\n\n _cache.set(Class, Wrapper);\n }\n\n function Wrapper() {\n return construct(Class, arguments, getPrototypeOf(this).constructor);\n }\n\n Wrapper.prototype = Object.create(Class.prototype, {\n constructor: {\n value: Wrapper,\n enumerable: false,\n writable: true,\n configurable: true\n }\n });\n return setPrototypeOf(Wrapper, Class);\n };\n\n return _wrapNativeSuper(Class);\n}","export default function _isNativeFunction(fn) {\n return Function.toString.call(fn).indexOf(\"[native code]\") !== -1;\n}","/*\n * @flow strict\n * MIT License\n *\n * Copyright (c) Sindre Sorhus \n * (https://sindresorhus.com)\n *\n * Permission is hereby granted, free of charge, to any person\n * obtaining a copy of this software and associated documentation files\n * (the \"Software\"), to deal in the Software without restriction,\n * including without limitation the rights to use, copy, modify, merge,\n * publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so,\n * subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\n * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\n * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n/*\n * This is a fork of https://github.com/sindresorhus/p-throttle that\n * (1) adds Flow types\n * (2) makes individual calls abortable\n */\n\nexport class ThrottleAbortError extends Error {\n constructor() {\n super('Throttled function aborted');\n this.name = 'AbortError';\n }\n}\n\nexport type ThrottleOptionsT = {\n +interval: number,\n +limit: number,\n};\n\nexport type ThrottleResultT<+R: mixed> = {\n +abort: () => void,\n +promise: Promise,\n};\n\nconst pThrottle = <\n -A: $ReadOnlyArray,\n +R: mixed,\n>({\n interval,\n limit,\n}: ThrottleOptionsT): (\n ((...A) => R | Promise) => ((...A) => ThrottleResultT)\n) => {\n const queue: Map void> = new Map();\n\n let currentTick = 0;\n let activeCount = 0;\n\n const getDelay = () => {\n const now = Date.now();\n\n if ((now - currentTick) > interval) {\n activeCount = 1;\n currentTick = now;\n return 0;\n }\n\n if (activeCount < limit) {\n activeCount++;\n } else {\n currentTick += interval;\n activeCount = 1;\n }\n\n return currentTick - now;\n };\n\n return (function_) => {\n return (...args) => {\n let timeout;\n let aborted = false;\n\n return {\n abort: () => {\n clearTimeout(timeout);\n aborted = true;\n },\n promise: new Promise((resolve, reject) => {\n const execute = () => {\n if (aborted) {\n reject(new ThrottleAbortError());\n } else {\n resolve(function_.apply(this, args));\n }\n queue.delete(timeout);\n };\n\n timeout = setTimeout(execute, getDelay());\n\n queue.set(timeout, reject);\n }),\n };\n };\n };\n};\n\nexport default pThrottle;\n","/*\n * @flow strict-local\n * Copyright (C) 2017 MetaBrainz Foundation\n *\n * This file is part of MusicBrainz, the open internet music database,\n * and is licensed under the GPL version 2, or (at your option) any\n * later version: http://www.gnu.org/licenses/gpl-2.0.txt\n */\n\nimport * as React from 'react';\n\nimport {SanitizedCatalystContext} from '../context';\nimport ratingTooltip from '../utility/ratingTooltip';\nimport {returnToCurrentPage} from '../utility/returnUri';\n\nconst ratingURL = (\n $c: SanitizedCatalystContextT,\n entity: RatableT,\n rating: number,\n) => (\n '/rating/rate/?entity_type=' +\n encodeURIComponent(entity.entityType) +\n '&entity_id=' +\n encodeURIComponent(String(entity.id)) +\n '&rating=' +\n encodeURIComponent(String(rating * 20)) +\n '&' + returnToCurrentPage($c)\n);\n\nconst ratingInts = [1, 2, 3, 4, 5];\n\ntype StaticRatingStarsProps = {\n +rating: ?number,\n};\n\ntype RatingStarsProps = {\n +entity: RatableT,\n};\n\nexport const StaticRatingStars = ({\n rating,\n}: StaticRatingStarsProps): React.Element<'span'> => {\n const starRating = rating == null ? 0 : (5 * rating / 100);\n return (\n \n \n \n {starRating}\n \n \n \n );\n};\n\nconst RatingStars = ({entity}: RatingStarsProps): React.Element<'span'> => {\n const currentStarRating =\n entity.user_rating == null ? 0 : (5 * entity.user_rating / 100);\n const $c = React.useContext(SanitizedCatalystContext);\n\n return (\n \n \n {entity.user_rating == null ? (\n entity.rating == null ? null : (\n \n {5 * entity.rating / 100}\n \n )\n ) : (\n \n {currentStarRating}\n \n )}\n\n {$c.user?.has_confirmed_email_address ? (\n ratingInts.map(rating => {\n const isCurrentRating = rating === currentStarRating;\n const newRating = isCurrentRating ? 0 : rating;\n\n return (\n \n {rating}\n \n );\n })\n ) : null}\n \n \n );\n};\n\nexport default RatingStars;\n","/*\n * @flow strict\n * Copyright (C) 2018 MetaBrainz Foundation\n *\n * This file is part of MusicBrainz, the open internet music database,\n * and is licensed under the GPL version 2, or (at your option) any\n * later version: http://www.gnu.org/licenses/gpl-2.0.txt\n */\n\nexport default function returnUri(\n $c: CatalystContextT,\n path: string,\n redirect?: string = '',\n): string {\n return path + '?returnto=' + encodeURIComponent(\n $c.req.query_params.returnto || redirect || $c.relative_uri,\n );\n}\n\nexport function returnToCurrentPage(\n $c: CatalystContextT | SanitizedCatalystContextT,\n): string {\n return 'returnto=' + encodeURIComponent($c.relative_uri);\n}\n","/*\n * @flow\n * Copyright (C) 2020 MetaBrainz Foundation\n *\n * This file is part of MusicBrainz, the open internet music database,\n * and is licensed under the GPL version 2, or (at your option) any\n * later version: http://www.gnu.org/licenses/gpl-2.0.txt\n */\n\nimport * as React from 'react';\n\nimport GroupedTrackRelationships\n from '../../../../components/GroupedTrackRelationships';\nimport RatingStars from '../../../../components/RatingStars';\nimport {SanitizedCatalystContext} from '../../../../context';\nimport loopParity from '../../../../utility/loopParity';\nimport ArtistCreditLink\n from '../../common/components/ArtistCreditLink';\nimport EntityLink from '../../common/components/EntityLink';\nimport formatTrackLength\n from '../../common/utility/formatTrackLength';\nimport type {CreditsModeT} from '../types';\n\ntype PropsT = {\n +creditsMode: CreditsModeT,\n +index: number,\n +showArtists?: boolean,\n +track: TrackWithRecordingT,\n};\n\nconst MediumTrackRow = (React.memo(({\n creditsMode,\n index,\n track,\n showArtists,\n}: PropsT) => {\n const $c = React.useContext(SanitizedCatalystContext);\n const recordingAC = track.recording?.artistCredit;\n\n return (\n \n \n {track.number}\n \n\n \n \n\n {/* Show recording artist only to logged in users to avoid confusing\n * visitors with recordings.\n */}\n {(\n $c.user &&\n recordingAC &&\n track.artistCredit.id !== recordingAC.id\n ) ? (\n
\n {l('Recording artist:')}\n {' '}\n \n
\n ) : null}\n\n {creditsMode === 'inline' ? (\n
\n \n
\n ) : null}\n \n\n {showArtists ? (\n \n \n \n ) : null}\n\n \n \n \n\n \n {formatTrackLength(track.length)}\n \n \n );\n}): React.AbstractComponent);\n\nexport default MediumTrackRow;\n","/*\n * @flow\n * Copyright (C) 2020 MetaBrainz Foundation\n *\n * This file is part of MusicBrainz, the open internet music database,\n * and is licensed under the GPL version 2, or (at your option) any\n * later version: http://www.gnu.org/licenses/gpl-2.0.txt\n */\n\nimport * as React from 'react';\nimport {captureException} from '@sentry/browser';\n\nimport Paginator from '../../../../components/Paginator';\nimport {CatalystContext} from '../../../../context';\nimport mediumHasMultipleArtists\n from '../../../../utility/mediumHasMultipleArtists';\nimport DataTrackIcon\n from '../../common/components/DataTrackIcon';\nimport MediumDescription\n from '../../common/components/MediumDescription';\nimport {uniqBy} from '../../common/utility/arrays';\nimport pThrottle, {\n ThrottleAbortError,\n} from '../../common/utility/pThrottle';\nimport type {CreditsModeT, ActionT} from '../types';\nimport linkedEntities from '../../common/linkedEntities';\n\nimport MediumTrackRow from './MediumTrackRow';\n\ntype PropsT = {\n +creditsMode: CreditsModeT,\n +dispatch: (ActionT) => void,\n +hasUnloadedTracks: boolean,\n +isExpanded: boolean,\n +medium: MediumWithRecordingsT,\n +noScript: boolean,\n +release: ReleaseWithMediumsT,\n +tracks: $ReadOnlyArray | null,\n};\n\ntype TracksResponseT = {\n +linked_entities: {\n link_attribute_type: {\n [linkAttributeTypeIdOrGid: StrOrNum]: LinkAttrTypeT,\n },\n link_type: {\n [linkTypeIdOrGid: StrOrNum]: LinkTypeT,\n },\n },\n +pager: PagerT,\n +tracks: $ReadOnlyArray,\n};\n\nconst throttleFunc = pThrottle<[number, number], Response>({\n interval: 1000,\n limit: 1,\n});\n\nconst fetchTracks = throttleFunc((mediumId: number, page: number) => {\n return fetch('/ws/js/tracks/' + mediumId + '?page=' + page);\n});\n\nconst MediumTable = (React.memo(({\n creditsMode,\n dispatch,\n hasUnloadedTracks,\n isExpanded,\n medium,\n noScript,\n release,\n tracks,\n}: PropsT) => {\n const $c = React.useContext(CatalystContext);\n\n const [loadingMessage, setLoadingMessage] =\n React.useState('');\n\n const [loadAllTracks, setLoadAllTracks] =\n React.useState(false);\n\n const showArtists = React.useMemo(\n () => mediumHasMultipleArtists(release, tracks),\n [release, tracks],\n );\n\n const loadedTrackCount = (tracks?.length) ?? 0;\n const canLoadMoreTracks = isExpanded && hasUnloadedTracks;\n const isLoading = (\n canLoadMoreTracks &&\n (loadedTrackCount === 0 || loadAllTracks)\n );\n\n const [audioTracks, dataTracks] = React.useMemo(() => {\n const audioTracks = [];\n const dataTracks = [];\n if (tracks) {\n for (const track of tracks) {\n if (track.isDataTrack) {\n dataTracks.push(track);\n } else {\n audioTracks.push(track);\n }\n }\n }\n return [audioTracks, dataTracks];\n }, [tracks]);\n\n const pagerRef = React.useRef(medium.tracks_pager);\n\n const loadMoreTracks = React.useCallback(() => {\n if (canLoadMoreTracks) {\n setLoadingMessage(l('Loading...'));\n\n const pager = pagerRef.current;\n const nextPage = (pager?.next_page) ?? 1;\n\n const throttleResult = fetchTracks(medium.id, nextPage);\n\n throttleResult.promise\n .then(response => response.json())\n .then(result => {\n const pager = result.pager;\n pagerRef.current = pager;\n\n linkedEntities.mergeLinkedEntities(result.linked_entities);\n\n dispatch({\n medium,\n tracks: uniqBy(\n (tracks || []).concat(result.tracks),\n x => x.position,\n ),\n type: 'load-tracks',\n });\n\n setLoadingMessage('');\n })\n .catch((error) => {\n if (!(error instanceof ThrottleAbortError)) {\n captureException(error);\n console.error(error);\n setLoadingMessage(l('Failed to load the medium.'));\n setLoadAllTracks(false);\n }\n });\n\n return throttleResult;\n }\n\n return null;\n }, [\n canLoadMoreTracks,\n tracks,\n setLoadingMessage,\n medium,\n dispatch,\n ]);\n\n React.useEffect(() => {\n let throttleResult;\n\n if (isLoading) {\n throttleResult = loadMoreTracks();\n }\n\n return () => {\n throttleResult?.abort();\n };\n }, [\n isLoading,\n loadMoreTracks,\n ]);\n\n function toggleMedium(event) {\n // Prevent the browser from following the link.\n event.preventDefault();\n dispatch({medium, type: 'toggle-medium'});\n }\n\n const position = String(medium.position);\n const columnCount = 4 + (showArtists ? 1 : 0);\n const tracksPager = medium.tracks_pager;\n\n return (\n \n \n \n \n \n \n\n \n {loadedTrackCount ? (\n <>\n \n \n \n {showArtists ? (\n \n ) : null}\n \n \n \n\n {(\n noScript &&\n tracksPager &&\n tracksPager.last_page > tracksPager.first_page\n ) ? (\n \n \n \n ) : null}\n\n {audioTracks.map((track, index) => (\n \n ))}\n\n {dataTracks.length ? (\n <>\n \n \n \n {dataTracks.map((track, index) => (\n \n ))}\n \n ) : null}\n \n ) : null}\n\n {(\n loadedTrackCount &&\n canLoadMoreTracks &&\n !noScript &&\n !(isLoading && loadingMessage)\n ) ? (\n \n \n \n ) : null}\n\n {loadingMessage ? (\n \n \n
\n {loadingMessage}\n
\n \n
\n ) : null}\n \n
\n \n \n {isExpanded ? '\\u25BC' : '\\u25B6'}\n \n \n \n
{l('#')}{l('Title')}{l('Artist')}{l('Rating')}{l('Length')}
\n

\n {l(\n `This medium has too many tracks to load at once,\n so it’s been paginated.`,\n )}\n

\n \n
\n \n {l('Data Tracks')}\n
\n {texp.l(\n `This medium has too many tracks to load at once;\n currently showing {loaded_track_count} out of\n {total_track_count} total.`,\n {\n loaded_track_count: loadedTrackCount,\n total_track_count: medium.track_count || 0,\n },\n )}\n {' '}\n {\n event.preventDefault();\n setLoadAllTracks(true);\n }}\n >\n {l('Load all tracks...')}\n \n
\n );\n}): React.AbstractComponent);\n\nexport default MediumTable;\n","/*\n * @flow strict\n * Copyright (C) 2019 MetaBrainz Foundation\n *\n * This file is part of MusicBrainz, the open internet music database,\n * and is licensed under the GPL version 2, or (at your option) any\n * later version: http://www.gnu.org/licenses/gpl-2.0.txt\n */\n\nexport default function mediumHasMultipleArtists(\n release: ReleaseT,\n tracks: ?$ReadOnlyArray,\n): boolean {\n if (!tracks || !tracks.length) {\n return false;\n }\n\n const releaseAcId = release.artistCredit.id;\n\n for (const track of tracks) {\n if (track.artistCredit.id !== releaseAcId) {\n return true;\n }\n }\n\n return false;\n}\n","/*\n * @flow strict\n * Copyright (C) 2020 MetaBrainz Foundation\n *\n * This file is part of MusicBrainz, the open internet music database,\n * and is licensed under the GPL version 2, or (at your option) any\n * later version: http://www.gnu.org/licenses/gpl-2.0.txt\n */\n\nimport * as React from 'react';\n\nimport type {\n ActionT,\n CreditsModeT,\n} from '../types';\n\ntype PropsT = {\n +creditsMode: CreditsModeT,\n +dispatch: (ActionT) => void,\n +mediums: $ReadOnlyArray,\n};\n\nconst MediumToolbox = (React.memo(({\n creditsMode,\n dispatch,\n mediums,\n}: PropsT): React.Element<'span'> => (\n \n {mediums.length > 1 ? (\n <>\n {\n dispatch({\n expanded: true,\n mediums,\n type: 'toggle-all-mediums',\n });\n }}\n type=\"button\"\n >\n {l('Expand all mediums')}\n \n {' | '}\n {\n dispatch({\n expanded: false,\n mediums,\n type: 'toggle-all-mediums',\n });\n }}\n type=\"button\"\n >\n {l('Collapse all mediums')}\n \n {' | '}\n \n ) : null}\n {\n dispatch({type: 'toggle-credits-mode'});\n }}\n type=\"button\"\n >\n {creditsMode === 'bottom'\n ? l('Display Credits Inline')\n : l('Display Credits at Bottom')}\n \n \n)): React.AbstractComponent);\n\nexport default MediumToolbox;\n","/*\n * @flow\n * Copyright (C) 2020 MetaBrainz Foundation\n *\n * This file is part of MusicBrainz, the open internet music database,\n * and is licensed under the GPL version 2, or (at your option) any\n * later version: http://www.gnu.org/licenses/gpl-2.0.txt\n */\n\nimport * as React from 'react';\n\nimport {isIrrelevantLinkType}\n from '../../../../components/GroupedTrackRelationships';\nimport Relationships from '../../../../components/Relationships';\nimport StaticRelationshipsDisplay\n from '../../../../components/StaticRelationshipsDisplay';\nimport groupRelationships, {\n type RelationshipTargetTypeGroupT,\n} from '../../../../utility/groupRelationships';\nimport MediumDescription\n from '../../common/components/MediumDescription';\nimport WarningIcon from '../../common/components/WarningIcon';\nimport {l} from '../../common/i18n';\nimport linkedEntities from '../../common/linkedEntities';\nimport setCookie from '../../common/utility/setCookie';\nimport type {\n PropsT,\n StateT,\n ActionT,\n CreditsModeT,\n} from '../types';\n\nimport MediumTable from './MediumTable';\nimport MediumToolbox from './MediumToolbox';\n\nfunction reducer(\n state: StateT,\n action: ActionT,\n): StateT {\n const newState: {...StateT} = {...state};\n\n switch (action.type) {\n case 'toggle-credits-mode': {\n if (state.creditsMode === 'bottom') {\n setCookie('bottom-credits', 0);\n newState.creditsMode = 'inline';\n } else {\n setCookie('bottom-credits', 1);\n newState.creditsMode = 'bottom';\n }\n break;\n }\n case 'toggle-medium': {\n const medium = action.medium;\n const newExpandedMediums = new Map(state.expandedMediums);\n newExpandedMediums.set(\n medium.position,\n !isMediumExpanded(newExpandedMediums, medium),\n );\n newState.expandedMediums = newExpandedMediums;\n break;\n }\n case 'toggle-all-mediums': {\n const newExpandedMediums = new Map(state.expandedMediums);\n for (const medium of action.mediums) {\n newExpandedMediums.set(medium.position, action.expanded);\n }\n newState.expandedMediums = newExpandedMediums;\n break;\n }\n case 'load-tracks': {\n const medium = action.medium;\n const newLoadedTracks = new Map(state.loadedTracks);\n newLoadedTracks.set(medium.position, action.tracks);\n newState.loadedTracks = newLoadedTracks;\n break;\n }\n }\n\n return newState;\n}\n\nfunction createInitialState(creditsMode: CreditsModeT) {\n return {\n creditsMode,\n /*\n * This information is stored separate from the medium objects\n * to maintain referential equality of those and minimize the\n * number of component updates.\n */\n expandedMediums: new Map(),\n loadedTracks: new Map(),\n };\n}\n\nfunction isMediumExpanded(expandedMediums, medium) {\n const expanded = expandedMediums.get(medium.position);\n return expanded == null\n ? (medium.tracks != null)\n : expanded;\n}\n\nfunction getMediumTracks(loadedTracks, medium) {\n return loadedTracks.get(medium.position) ?? medium.tracks ?? null;\n}\n\nconst combinedTrackRelsCache = new WeakMap();\n\nfunction getCombinedTrackRelationships(\n tracks: $ReadOnlyArray | null,\n): $ReadOnlyArray | null {\n if (!tracks) {\n return null;\n }\n\n let result = combinedTrackRelsCache.get(tracks);\n if (result) {\n return result;\n }\n\n const allRelationships = [];\n // Maps relationships to the tracks they're associated with.\n const trackMapping = new Map>();\n\n const pushRelationship = (relationship, track) => {\n const relationshipId = relationship.linkTypeID + '-' + relationship.id;\n\n const associatedTracks = trackMapping.get(relationshipId);\n if (associatedTracks) {\n associatedTracks.add(track);\n } else {\n trackMapping.set(relationshipId, new Set([track]));\n }\n\n allRelationships.push(relationship);\n };\n\n for (const track of tracks) {\n const recording = track.recording;\n if (!recording) {\n continue;\n }\n\n const recordingRelationships = recording.relationships;\n if (recordingRelationships) {\n for (const relationship of recordingRelationships) {\n const target = relationship.target;\n\n if (!isIrrelevantLinkType(\n relationship, target.entityType,\n )) {\n pushRelationship(relationship, track);\n }\n\n if (target.entityType === 'work') {\n const workRelationships = target.relationships;\n if (workRelationships) {\n for (const workRelationship of workRelationships) {\n if (!isIrrelevantLinkType(\n workRelationship, target.entityType,\n )) {\n pushRelationship(workRelationship, track);\n }\n }\n }\n }\n }\n }\n }\n\n result = groupRelationships(allRelationships, {trackMapping});\n combinedTrackRelsCache.set(tracks, result);\n return result;\n}\n\nconst TracklistAndCredits = React.memo((props: PropsT) => {\n const {\n noScript,\n release,\n initialLinkedEntities,\n } = props;\n\n const setLinkedEntitiesRef = React.useRef(false);\n if (!setLinkedEntitiesRef.current) {\n linkedEntities.mergeLinkedEntities(initialLinkedEntities);\n setLinkedEntitiesRef.current = true;\n }\n\n const [state, dispatch] = React.useReducer(\n reducer,\n props.initialCreditsMode,\n createInitialState,\n );\n\n const mediums = release.mediums;\n const {\n creditsMode,\n expandedMediums,\n loadedTracks,\n } = state;\n\n const hasUnloadedTracksPerMedium = React.useMemo(() => new Map(\n mediums.map(medium => [\n medium.id,\n (\n medium.track_count != null &&\n medium.track_count > 0 &&\n medium.track_count >\n ((getMediumTracks(loadedTracks, medium)?.length) ?? 0)\n ),\n ]),\n ), [loadedTracks, mediums]);\n\n const hasUnloadedTracks = React.useMemo(() => {\n for (const value of hasUnloadedTracksPerMedium.values()) {\n if (value) {\n return true;\n }\n }\n return false;\n }, [hasUnloadedTracksPerMedium]);\n\n const bottomMediumCredits = React.useMemo(() => (\n creditsMode === 'bottom'\n ? mediums.map((medium) => (\n getCombinedTrackRelationships(\n getMediumTracks(loadedTracks, medium),\n )\n ))\n : null\n ), [mediums, loadedTracks, creditsMode]);\n\n const hasBottomMediumCredits =\n (bottomMediumCredits?.some(x => x?.length)) ?? false;\n const hasReleaseCredits = !!(release.relationships?.length);\n const hasReleaseGroupCredits =\n !!(release.releaseGroup?.relationships?.length);\n const hasBottomCredits = (\n hasBottomMediumCredits ||\n hasReleaseCredits ||\n hasReleaseGroupCredits\n );\n\n const releaseGroup = release.releaseGroup;\n\n const mediumTableElements = React.useMemo(\n () => mediums.length ? (\n mediums.map((medium) => (\n \n ))\n ) : null,\n [\n release,\n mediums,\n creditsMode,\n expandedMediums,\n loadedTracks,\n hasUnloadedTracksPerMedium,\n noScript,\n ],\n );\n\n const bottomMediumCreditElements = React.useMemo(() => (\n (hasBottomMediumCredits /*:: && bottomMediumCredits */) ? (\n mediums.map((medium, index) => {\n const relationships = bottomMediumCredits[index];\n if (!relationships) {\n return null;\n }\n return (\n \n

\n \n

\n \n \n );\n })\n ) : null\n ), [\n hasBottomMediumCredits,\n bottomMediumCredits,\n mediums,\n ]);\n\n return (\n <>\n

{l('Tracklist')}

\n\n {mediums?.length ? (\n <>\n {noScript ? null : (\n \n )}\n {mediumTableElements}\n \n ) : (\n

\n {l(`We have no information about this release’s\n media and tracklist.`)}\n

\n )}\n\n {hasBottomCredits ? (\n
\n

{l('Credits')}

\n\n {(creditsMode === 'bottom' && hasUnloadedTracks) ? (\n
\n \n

\n {l(`The credits listed below may be incomplete, as some\n tracks/mediums haven’t been loaded yet.`)}\n

\n
\n ) : null}\n\n {bottomMediumCreditElements}\n\n {hasReleaseCredits ? (\n
\n

{l('Release')}

\n \n
\n ) : null}\n\n {(hasReleaseGroupCredits /*:: && releaseGroup */) ? (\n
\n

{l('Release Group')}

\n \n
\n ) : null}\n
\n ) : null}\n \n );\n});\n\nexport default (hydrate(\n 'div.tracklist-and-credits',\n TracklistAndCredits,\n): React.AbstractComponent);\n","/*\n * @flow strict\n * Copyright (C) 2013 MetaBrainz Foundation\n *\n * This file is part of MusicBrainz, the open internet music database,\n * and is licensed under the GPL version 2, or (at your option) any\n * later version: http://www.gnu.org/licenses/gpl-2.0.txt\n */\n\nconst ratingTooltip = (rating: number): string => (\n rating === 0\n ? l('Remove your rating')\n : texp.ln('Rate: {rating} star', 'Rate: {rating} stars', rating, {rating})\n);\n\nexport default ratingTooltip;\n"],"names":["areDatesEqual","a","b","year","month","day","areDatePeriodsEqual","ended","begin_date","end_date","cmpRelationshipPhraseGroups","linkTypeInfoA","linkTypeInfo","linkTypeInfoB","typeId","compare","textPhrase","cmpPhraseGroupLinkTypeInfo","cmpFirstDatePeriods","compareDatePeriods","datePeriods","cmpRelationshipTargetGroups","linkOrder","earliestDatePeriod","targetCredit","getSortName","target","id","areLinkAttrsEqual","typeID","text_value","credited_as","areDatedExtraAttributesEqual","arraysEqual","attributes","compareRelationshipTargetGroups","options","hasAttributes","compareTracks","tracks","size","value","has","areSetsEqual","compareDatedExtraAttributesLists","datedExtraAttributesList","canMergeTargetGroupsByTracksOptions","canMergeTargetGroupsByAttributesOptions","areTargetGroupsIdenticalOptions","areTargetGroupsIdentical","displayLinkPhrase","phrase","editsPending","className","isNotInstrumentOrVocal","attribute","type","linkedEntities","root_id","INSTRUMENT_ROOT_ID","VOCAL_ROOT_ID","mergeDatedExtraAttributes","pairs","i","length","j","attributeList1","attributeList2","filter","mergeSortedArrayInto","cmpLinkAttrs","splice","compareTrackPositions","position","mergeTargetGroupsByTracks","targetGroups","targetGroup1","targetGroup2","Set","sort","x","entityType","sort_name","name","groupRelationships","relationships","args","result","trackMapping","types","targetTypeGroups","relationship","targetType","includes","targetTypeGroup","sortedIndexWith","group","compareStrings","index","relationshipPhraseGroups","backward","linkType","linkTypeID","hasInstruments","linkAttrs","linkAttr","phraseArgs","interpolateText","interpolate","sourceCredit","entity1_credit","entity0_credit","texp","credited_name","role","exp","phraseGroupKey","String","phraseGroup","phraseGroups","key","combinedPhrase","rootTypeId","isOrderable","orderable_direction","targetIsOrderable","datePeriod","relationshipId","get","targetGroup","uniqueId","existingTargetGroup","find","otherTargetGroup","push","getExtraAttributes","phraseGroup1","linkTypeInfo1","phraseGroup2","firstLinkType2","relatedLinkType","t","targetGroups1","targetGroups2","k","commaList","map","relationshipDateText","r","bracketEnded","date","formatDate","text","l","bracketedText","_semicolonOnlyList","items","output","last_list_item","rest","semicolon_only_list_item","isDisabledLink","relationshipOrLinkDatePeriod","entity","isEnded","givenDate","givenYear","now","Date","currentDate","getUTCDate","getUTCMonth","getUTCFullYear","isFutureDate","isGreyedOut","href_url","displayDatedExtraAttributes","pair","renderedDatePeriods","commaOnlyListText","renderedExtraAttributes","commaOnlyList","displayLinkAttribute","addColon","link","hiddenArtistCredit","disableLink","artistCredit","artistCreditsAreEqual","EntityLink","content","showIcon","DescriptiveLink","datesAndAttributes","bracketed","renderTargetGroup","renderPhraseGroup","renderWorkRelationship","work","title","GroupedTrackRelationships","source","irrelevantLinkTypes","recording","Map","isIrrelevantLinkType","irrelevantTypesForTargetType","workRelationships","arsList","detailsTableStyle","Object","freeze","width","formatTrackRange","range","number","end_track","start_track","getTrackRanges","trackSet","ranges","track","difference","React","groupedRelationships","tables","targetTypeRows","groupSize","phraseRows","relationshipLink","num","style","wordBreak","seriesIds","createArgs","series","isNotSeriesPart","targetEntityTypes","workIds","displayTargets","artist","label","seriesPartLinkTypes","values","PART_OF_SERIES_LINK_TYPES","gid","noRelationshipsHeading","showIfEmpty","srcRels","names","joinPhrase","heading","related_works","related_series","mapRange","start","end","func","uriPage","uri","pageVar","page","hash","params","uriString","urlObject","URL","searchParams","URLSearchParams","search","keys","set","toString","href","uriWith","nonEmpty","$c","guessSearch","pager","lastPage","last_page","firstPage","first_page","previousPage","previous_page","nextPage","next_page","current_page","reqUri","req","_wrapNativeSuper","Class","_cache","undefined","fn","Function","call","indexOf","TypeError","Wrapper","construct","arguments","getPrototypeOf","this","constructor","prototype","create","enumerable","writable","configurable","setPrototypeOf","ThrottleAbortError","Error","interval","limit","queue","currentTick","activeCount","getDelay","function_","timeout","aborted","abort","clearTimeout","promise","Promise","resolve","reject","setTimeout","apply","delete","ratingURL","rating","encodeURIComponent","relative_uri","returnToCurrentPage","ratingInts","currentStarRating","user_rating","SanitizedCatalystContext","tabIndex","user","has_confirmed_email_address","isCurrentRating","newRating","ratingTooltip","creditsMode","showArtists","recordingAC","loopParity","ArtistCreditLink","formatTrackLength","fetchTracks","pThrottle","throttleFunc","mediumId","fetch","dispatch","hasUnloadedTracks","isExpanded","medium","noScript","release","CatalystContext","loadingMessage","setLoadingMessage","loadAllTracks","setLoadAllTracks","releaseAcId","mediumHasMultipleArtists","loadedTrackCount","canLoadMoreTracks","isLoading","audioTracks","dataTracks","isDataTrack","pagerRef","tracks_pager","loadMoreTracks","current","throttleResult","then","response","json","linked_entities","uniqBy","concat","catch","error","captureException","console","columnCount","tracksPager","colSpan","onClick","event","preventDefault","MediumDescription","display","padding","loaded_track_count","total_track_count","track_count","mediums","expanded","reducer","state","action","newState","setCookie","newExpandedMediums","expandedMediums","isMediumExpanded","newLoadedTracks","loadedTracks","createInitialState","getMediumTracks","combinedTrackRelsCache","WeakMap","hydrate","props","initialLinkedEntities","setLinkedEntitiesRef","initialCreditsMode","hasUnloadedTracksPerMedium","bottomMediumCredits","allRelationships","pushRelationship","associatedTracks","add","recordingRelationships","workRelationship","getCombinedTrackRelationships","hasBottomMediumCredits","some","hasReleaseCredits","hasReleaseGroupCredits","releaseGroup","hasBottomCredits","mediumTableElements","bottomMediumCreditElements","WarningIcon"],"sourceRoot":""}