{"version":3,"sources":["jsdelivr-header.js","/gh/googlemaps/v3-utility-library@07f15d84/markerclustererplus/src/markerclusterer.js"],"names":[],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA,AC0FA,SAAS,YAAY,EAAS,GAC5B,EAAQ,qBAAqB,OAAO,YAAa,OAAO,KAAK,aAE7D,KAAK,SAAW,EAChB,KAAK,WAAa,EAAQ,qBAAqB,kBAC/C,KAAK,QAAU,EACf,KAAK,QAAU,KACf,KAAK,KAAO,KACZ,KAAK,MAAQ,KACb,KAAK,UAAW,EAEhB,KAAK,OAAO,EAAQ,SACtB,CAsPA,SAAS,QAAQ,GACf,KAAK,iBAAmB,EACxB,KAAK,KAAO,EAAG,SACf,KAAK,UAAY,EAAG,cACpB,KAAK,gBAAkB,EAAG,wBAC1B,KAAK,eAAiB,EAAG,mBACzB,KAAK,SAAW,GAChB,KAAK,QAAU,KACf,KAAK,QAAU,KACf,KAAK,aAAe,IAAI,YAAY,KAAM,EAAG,YAC/C,CA0SA,SAAS,gBAAgB,EAAK,EAAa,GAMzC,KAAK,OAAO,gBAAiB,OAAO,KAAK,aAEzC,EAAc,GAAe,GAC7B,EAAc,GAAe,CAAC,EAE9B,KAAK,SAAW,GAChB,KAAK,UAAY,GACjB,KAAK,WAAa,GAClB,KAAK,WAAa,KAClB,KAAK,QAAS,EAEd,KAAK,UAAY,EAAY,UAAY,GACzC,KAAK,gBAAkB,EAAY,oBAAsB,EACzD,KAAK,SAAW,EAAY,SAAW,KACvC,KAAK,QAAU,EAAY,QAAU,GACrC,KAAK,OAAS,EAAY,OAAS,GACnC,KAAK,cAAe,OACY,IAA5B,EAAY,cACd,KAAK,aAAe,EAAY,aAElC,KAAK,gBAAiB,OACY,IAA9B,EAAY,gBACd,KAAK,eAAiB,EAAY,eAEpC,KAAK,eAAgB,OACY,IAA7B,EAAY,eACd,KAAK,cAAgB,EAAY,cAEnC,KAAK,oBAAqB,OACY,IAAlC,EAAY,oBACd,KAAK,mBAAqB,EAAY,mBAExC,KAAK,WAAa,EAAY,WAAa,gBAAgB,WAC3D,KAAK,gBAAkB,EAAY,gBAAkB,gBAAgB,gBACrE,KAAK,YAAc,EAAY,YAAc,gBAAgB,YAC7D,KAAK,YAAc,EAAY,YAAc,gBAAgB,WAC7D,KAAK,WAAa,EAAY,WAAa,gBAAgB,WAC3D,KAAK,aAAe,EAAY,aAAe,gBAAgB,cAC/D,KAAK,cAAgB,EAAY,cAAgB,WAEU,IAAvD,UAAU,UAAU,cAAc,QAAQ,UAE5C,KAAK,WAAa,KAAK,cAGzB,KAAK,eAEL,KAAK,WAAW,GAAa,GAC7B,KAAK,OAAO,EACd,CA3lBA,YAAY,UAAU,MAAQ,WAC5B,IACI,EACA,EAFA,EAAe,KAInB,KAAK,KAAO,SAAS,cAAc,OACnC,KAAK,KAAK,UAAY,KAAK,WACvB,KAAK,UACP,KAAK,OAGP,KAAK,WAAW,mBAAmB,YAAY,KAAK,MAGpD,KAAK,uBAAyB,OAAO,KAAK,MAAM,YAAY,KAAK,SAAU,kBAAkB,WAC3F,EAAwB,CAC1B,IAEA,OAAO,KAAK,MAAM,eAAe,KAAK,KAAM,aAAa,WACvD,GAAsB,EACtB,GAAwB,CAC1B,IAEA,OAAO,KAAK,MAAM,eAAe,KAAK,KAAM,SAAS,SAAU,GAE7D,GADA,GAAsB,GACjB,EAAuB,CAC1B,IAAI,EACA,EACA,EAAK,EAAa,SAAS,qBAO/B,OAAO,KAAK,MAAM,QAAQ,EAAI,QAAS,EAAa,UACpD,OAAO,KAAK,MAAM,QAAQ,EAAI,eAAgB,EAAa,UAIvD,EAAG,mBAEL,EAAK,EAAG,aACR,EAAY,EAAa,SAAS,YAClC,EAAG,SAAS,UAAU,GAEtB,YAAW,WACT,EAAG,SAAS,UAAU,GAEX,OAAP,GAAgB,EAAG,SAAS,UAAY,GAC1C,EAAG,SAAS,QAAQ,EAAK,EAE7B,GAAG,MAIL,EAAE,cAAe,EACb,EAAE,iBACJ,EAAE,iBAEN,CACF,IAEA,OAAO,KAAK,MAAM,eAAe,KAAK,KAAM,aAAa,WACvD,IAAI,EAAK,EAAa,SAAS,qBAO/B,OAAO,KAAK,MAAM,QAAQ,EAAI,YAAa,EAAa,SAC1D,IAEA,OAAO,KAAK,MAAM,eAAe,KAAK,KAAM,YAAY,WACtD,IAAI,EAAK,EAAa,SAAS,qBAO/B,OAAO,KAAK,MAAM,QAAQ,EAAI,WAAY,EAAa,SACzD,GACF,EAMA,YAAY,UAAU,SAAW,WAC3B,KAAK,MAAQ,KAAK,KAAK,aACzB,KAAK,OACL,OAAO,KAAK,MAAM,eAAe,KAAK,wBACtC,OAAO,KAAK,MAAM,uBAAuB,KAAK,MAC9C,KAAK,KAAK,WAAW,YAAY,KAAK,MACtC,KAAK,KAAO,KAEhB,EAMA,YAAY,UAAU,KAAO,WAC3B,GAAI,KAAK,SAAU,CACjB,IAAI,EAAM,KAAK,kBAAkB,KAAK,SACtC,KAAK,KAAK,MAAM,IAAM,EAAI,EAAI,KAC9B,KAAK,KAAK,MAAM,KAAO,EAAI,EAAI,IACjC,CACF,EAMA,YAAY,UAAU,KAAO,WACvB,KAAK,OACP,KAAK,KAAK,MAAM,QAAU,QAE5B,KAAK,UAAW,CAClB,EAMA,YAAY,UAAU,KAAO,WAC3B,GAAI,KAAK,KAAM,CACb,IAAI,EAAM,GAEN,EAAK,KAAK,oBAAoB,MAAM,KACpC,EAAU,SAAS,EAAG,GAAG,QAAQ,aAAc,IAAK,IACpD,EAAU,SAAS,EAAG,GAAG,QAAQ,aAAc,IAAK,IACpD,EAAM,KAAK,kBAAkB,KAAK,SACtC,KAAK,KAAK,MAAM,QAAU,KAAK,UAAU,GACzC,EAAM,aAAe,KAAK,KAAO,qCAAuC,EAAU,aAAe,EAAU,OACtG,KAAK,SAAS,qBAAqB,qBACtC,GAAO,eAAkB,EAAI,EAAW,SAAY,EAAI,EAAW,KAAK,QAAU,SAC3E,EAAI,EAAW,KAAK,SAAW,QAAW,EAAI,EAAW,QAElE,GAAO,KACP,KAAK,KAAK,UAAY,yCAER,KAAK,YAAY,GAFT,YAGP,KAAK,YAAY,GAHV,aAIN,KAAK,WAJC,eAKF,KAAK,UALH,mBAMA,KAAK,YANL,iBAOA,KAAK,YAPL,gBAQD,KAAK,WARJ,qBASI,KAAK,gBATT,8BAWN,KAAK,OAXC,kBAYD,KAAK,QAZJ,QAaX,KAAK,MAAM,KAAO,cACG,IAArB,KAAK,MAAM,OAA8C,KAArB,KAAK,MAAM,MACxD,KAAK,KAAK,MAAQ,KAAK,SAAS,qBAAqB,WAErD,KAAK,KAAK,MAAQ,KAAK,MAAM,MAE/B,KAAK,KAAK,MAAM,QAAU,EAC5B,CACA,KAAK,UAAW,CAClB,EAQA,YAAY,UAAU,SAAW,SAAU,GACzC,KAAK,MAAQ,EACb,IAAI,EAAQ,KAAK,IAAI,EAAG,EAAK,MAAQ,GACrC,EAAQ,KAAK,IAAI,KAAK,QAAQ,OAAS,EAAG,GAC1C,IAAI,EAAQ,KAAK,QAAQ,GACzB,KAAK,KAAO,EAAM,IAClB,KAAK,QAAU,EAAM,OACrB,KAAK,OAAS,EAAM,MACpB,KAAK,YAAc,EAAM,YAAc,CAAC,EAAG,GAC3C,KAAK,YAAc,EAAM,YAAc,CAAC,SAAS,KAAK,QAAU,EAAG,IAAK,SAAS,KAAK,OAAS,EAAG,KAClG,KAAK,WAAa,EAAM,WAAa,QACrC,KAAK,UAAY,EAAM,UAAY,GACnC,KAAK,gBAAkB,EAAM,gBAAkB,OAC/C,KAAK,YAAc,EAAM,YAAc,OACvC,KAAK,WAAa,EAAM,WAAa,SACrC,KAAK,YAAc,EAAM,YAAc,mBACvC,KAAK,oBAAsB,EAAM,oBAAsB,KACzD,EAQA,YAAY,UAAU,UAAY,SAAU,GAC1C,KAAK,QAAU,CACjB,EASA,YAAY,UAAU,UAAY,SAAU,GAC1C,IAAI,EAAQ,GAIZ,OAHA,EAAM,KAAK,oBACX,EAAM,KAAK,4BAA8B,EAAI,EAAI,aAAe,EAAI,EAAI,OACxE,EAAM,KAAK,UAAY,KAAK,OAAS,eAAiB,KAAK,QAAU,OAC9D,EAAM,KAAK,GACpB,EASA,YAAY,UAAU,kBAAoB,SAAU,GAClD,IAAI,EAAM,KAAK,gBAAgB,qBAAqB,GAKpD,OAJA,EAAI,GAAK,KAAK,YAAY,GAC1B,EAAI,GAAK,KAAK,YAAY,GAC1B,EAAI,EAAI,SAAS,EAAI,EAAG,IACxB,EAAI,EAAI,SAAS,EAAI,EAAG,IACjB,CACT,EA8BA,QAAQ,UAAU,QAAU,WAC1B,OAAO,KAAK,SAAS,MACvB,EAUA,QAAQ,UAAU,WAAa,WAC7B,OAAO,KAAK,QACd,EAUA,QAAQ,UAAU,UAAY,WAC5B,OAAO,KAAK,OACd,EASA,QAAQ,UAAU,OAAS,WACzB,OAAO,KAAK,IACd,EASA,QAAQ,UAAU,mBAAqB,WACrC,OAAO,KAAK,gBACd,EASA,QAAQ,UAAU,UAAY,WAC5B,IAAI,EACA,EAAS,IAAI,OAAO,KAAK,aAAa,KAAK,QAAS,KAAK,SACzD,EAAU,KAAK,aACnB,IAAK,EAAI,EAAG,EAAI,EAAQ,OAAQ,IAC9B,EAAO,OAAO,EAAQ,GAAG,eAE3B,OAAO,CACT,EAQA,QAAQ,UAAU,OAAS,WACzB,KAAK,aAAa,OAAO,MACzB,KAAK,SAAW,UACT,KAAK,QACd,EAUA,QAAQ,UAAU,UAAY,SAAU,GACtC,IAAI,EACA,EACA,EAEJ,GAAI,KAAK,sBAAsB,GAC7B,OAAO,EAGT,GAAK,KAAK,SAIR,GAAI,KAAK,eAAgB,CACvB,IAAI,EAAI,KAAK,SAAS,OAAS,EAC3B,GAAO,KAAK,QAAQ,OAAS,EAAI,GAAK,EAAO,cAAc,OAAS,EACpE,GAAO,KAAK,QAAQ,OAAS,EAAI,GAAK,EAAO,cAAc,OAAS,EACxE,KAAK,QAAU,IAAI,OAAO,KAAK,OAAO,EAAK,GAC3C,KAAK,kBACP,OATA,KAAK,QAAU,EAAO,cACtB,KAAK,mBAgBP,GALA,EAAO,SAAU,EACjB,KAAK,SAAS,KAAK,GAEnB,EAAS,KAAK,SAAS,OAEZ,QADX,EAAK,KAAK,iBAAiB,eACR,KAAK,KAAK,UAAY,EAEnC,EAAO,WAAa,KAAK,MAC3B,EAAO,OAAO,KAAK,WAEhB,GAAI,EAAS,KAAK,gBAEnB,EAAO,WAAa,KAAK,MAC3B,EAAO,OAAO,KAAK,WAEhB,GAAI,IAAW,KAAK,gBAEzB,IAAK,EAAI,EAAG,EAAI,EAAQ,IACtB,KAAK,SAAS,GAAG,OAAO,WAG1B,EAAO,OAAO,MAIhB,OADA,KAAK,eACE,CACT,EAUA,QAAQ,UAAU,wBAA0B,SAAU,GACpD,OAAO,KAAK,QAAQ,SAAS,EAAO,cACtC,EAMA,QAAQ,UAAU,iBAAmB,WACnC,IAAI,EAAS,IAAI,OAAO,KAAK,aAAa,KAAK,QAAS,KAAK,SAC7D,KAAK,QAAU,KAAK,iBAAiB,kBAAkB,EACzD,EAMA,QAAQ,UAAU,YAAc,WAC9B,IAAI,EAAS,KAAK,SAAS,OACvB,EAAK,KAAK,iBAAiB,aAE/B,GAAW,OAAP,GAAe,KAAK,KAAK,UAAY,EACvC,KAAK,aAAa,YAIpB,GAAI,EAAS,KAAK,gBAEhB,KAAK,aAAa,WAFpB,CAMA,IAAI,EAAY,KAAK,iBAAiB,YAAY,OAC9C,EAAO,KAAK,iBAAiB,eAAtB,CAAsC,KAAK,SAAU,GAChE,KAAK,aAAa,UAAU,KAAK,SACjC,KAAK,aAAa,SAAS,GAC3B,KAAK,aAAa,MANlB,CAOF,EASA,QAAQ,UAAU,sBAAwB,SAAU,GAClD,IAAI,EACJ,GAAI,KAAK,SAAS,QAChB,OAA0C,IAAnC,KAAK,SAAS,QAAQ,GAE7B,IAAK,EAAI,EAAG,EAAI,KAAK,SAAS,OAAQ,IACpC,GAAI,IAAW,KAAK,SAAS,GAC3B,OAAO,EAIb,OAAO,CACT,EAmJA,gBAAgB,UAAU,MAAQ,WAChC,IAAI,EAAmB,KAEvB,KAAK,WAAa,KAAK,SACvB,KAAK,QAAS,EAEd,KAAK,UAGL,KAAK,WAAa,CAChB,OAAO,KAAK,MAAM,YAAY,KAAK,SAAU,gBAAgB,WAC3D,EAAiB,gBAAe,GAM5B,KAAK,aAAe,KAAK,IAAI,YAAc,IAAM,KAAK,YAAc,KAAK,IAAI,YAC/E,OAAO,KAAK,MAAM,QAAQ,KAAM,OAEpC,IACA,OAAO,KAAK,MAAM,YAAY,KAAK,SAAU,QAAQ,WACnD,EAAiB,SACnB,IAEJ,EASA,gBAAgB,UAAU,SAAW,WACnC,IAAI,EAGJ,IAAK,EAAI,EAAG,EAAI,KAAK,SAAS,OAAQ,IAChC,KAAK,SAAS,GAAG,WAAa,KAAK,YACrC,KAAK,SAAS,GAAG,OAAO,KAAK,YAKjC,IAAK,EAAI,EAAG,EAAI,KAAK,UAAU,OAAQ,IACrC,KAAK,UAAU,GAAG,SAKpB,IAHA,KAAK,UAAY,GAGZ,EAAI,EAAG,EAAI,KAAK,WAAW,OAAQ,IACtC,OAAO,KAAK,MAAM,eAAe,KAAK,WAAW,IAEnD,KAAK,WAAa,GAElB,KAAK,WAAa,KAClB,KAAK,QAAS,CAChB,EAOA,gBAAgB,UAAU,KAAO,WAAa,EAM9C,gBAAgB,UAAU,aAAe,WACvC,IAAI,EAAG,EACP,KAAI,KAAK,QAAQ,OAAS,GAI1B,IAAK,EAAI,EAAG,EAAI,KAAK,YAAY,OAAQ,IACvC,EAAO,KAAK,YAAY,GACxB,KAAK,QAAQ,KAAK,CAChB,IAAK,KAAK,YAAc,EAAI,GAAK,IAAM,KAAK,gBAC5C,OAAQ,EACR,MAAO,GAGb,EAMA,gBAAgB,UAAU,gBAAkB,WAC1C,IAAI,EACA,EAAU,KAAK,aACf,EAAS,IAAI,OAAO,KAAK,aAC7B,IAAK,EAAI,EAAG,EAAI,EAAQ,OAAQ,IAC9B,EAAO,OAAO,EAAQ,GAAG,eAG3B,KAAK,SAAS,UAAU,EAC1B,EAQA,gBAAgB,UAAU,YAAc,WACtC,OAAO,KAAK,SACd,EAQA,gBAAgB,UAAU,YAAc,SAAU,GAChD,KAAK,UAAY,CACnB,EAQA,gBAAgB,UAAU,sBAAwB,WAChD,OAAO,KAAK,eACd,EAOA,gBAAgB,UAAU,sBAAwB,SAAU,GAC1D,KAAK,gBAAkB,CACzB,EAQA,gBAAgB,UAAU,WAAa,WACrC,OAAO,KAAK,QACd,EAQA,gBAAgB,UAAU,WAAa,SAAU,GAC/C,KAAK,SAAW,CAClB,EAQA,gBAAgB,UAAU,UAAY,WACpC,OAAO,KAAK,OACd,EAQA,gBAAgB,UAAU,UAAY,SAAU,GAC9C,KAAK,QAAU,CACjB,EAQA,gBAAgB,UAAU,SAAW,WACnC,OAAO,KAAK,MACd,EAQA,gBAAgB,UAAU,SAAW,SAAU,GAC7C,KAAK,OAAS,CAChB,EAQA,gBAAgB,UAAU,eAAiB,WACzC,OAAO,KAAK,YACd,EAQA,gBAAgB,UAAU,eAAiB,SAAU,GACnD,KAAK,aAAe,CACtB,EAQA,gBAAgB,UAAU,iBAAmB,WAC3C,OAAO,KAAK,cACd,EAQA,gBAAgB,UAAU,iBAAmB,SAAU,GACrD,KAAK,eAAiB,CACxB,EAQA,gBAAgB,UAAU,gBAAkB,WAC1C,OAAO,KAAK,aACd,EAQA,gBAAgB,UAAU,gBAAkB,SAAU,GACpD,KAAK,cAAgB,CACvB,EAQA,gBAAgB,UAAU,qBAAuB,WAC/C,OAAO,KAAK,kBACd,EAQA,gBAAgB,UAAU,qBAAuB,SAAU,GACzD,KAAK,mBAAqB,CAC5B,EAQA,gBAAgB,UAAU,kBAAoB,WAC5C,OAAO,KAAK,eACd,EAQA,gBAAgB,UAAU,kBAAoB,SAAU,GACtD,KAAK,gBAAkB,CACzB,EAQA,gBAAgB,UAAU,aAAe,WACvC,OAAO,KAAK,UACd,EAQA,gBAAgB,UAAU,aAAe,SAAU,GACjD,KAAK,WAAa,CACpB,EAQA,gBAAgB,UAAU,cAAgB,WACxC,OAAO,KAAK,WACd,EAQA,gBAAgB,UAAU,cAAgB,SAAU,GAClD,KAAK,YAAc,CACrB,EAQA,gBAAgB,UAAU,cAAgB,WACxC,OAAO,KAAK,WACd,EASA,gBAAgB,UAAU,cAAgB,SAAU,GAClD,KAAK,YAAc,CACrB,EAQA,gBAAgB,UAAU,eAAiB,WACzC,OAAO,KAAK,YACd,EAQA,gBAAgB,UAAU,eAAiB,SAAU,GACnD,KAAK,aAAe,CACtB,EAQA,gBAAgB,UAAU,gBAAkB,WAC1C,OAAO,KAAK,aACd,EAQA,gBAAgB,UAAU,gBAAkB,SAAU,GACpD,KAAK,cAAgB,CACvB,EAQA,gBAAgB,UAAU,WAAa,WACrC,OAAO,KAAK,QACd,EAQA,gBAAgB,UAAU,gBAAkB,WAC1C,OAAO,KAAK,SAAS,MACvB,EAQA,gBAAgB,UAAU,YAAc,WACtC,OAAO,KAAK,SACd,EAQA,gBAAgB,UAAU,iBAAmB,WAC3C,OAAO,KAAK,UAAU,MACxB,EAUA,gBAAgB,UAAU,UAAY,SAAU,EAAQ,GACtD,KAAK,cAAc,GACd,GACH,KAAK,SAET,EAUA,gBAAgB,UAAU,WAAa,SAAU,EAAS,GACxD,IAAI,EACJ,IAAK,KAAO,EACN,EAAQ,eAAe,IACzB,KAAK,cAAc,EAAQ,IAG1B,GACH,KAAK,SAET,EAQA,gBAAgB,UAAU,cAAgB,SAAU,GAElD,GAAI,EAAO,eAAgB,CACzB,IAAI,EAAmB,KACvB,OAAO,KAAK,MAAM,YAAY,EAAQ,WAAW,WAC3C,EAAiB,SACnB,KAAK,SAAU,EACf,EAAiB,UAErB,GACF,CACA,EAAO,SAAU,EACjB,KAAK,SAAS,KAAK,EACrB,EAYA,gBAAgB,UAAU,aAAe,SAAU,EAAQ,GACzD,IAAI,EAAU,KAAK,cAAc,GAMjC,OAJK,GAAc,GACjB,KAAK,UAGA,CACT,EAYA,gBAAgB,UAAU,cAAgB,SAAU,EAAS,GAC3D,IAAI,EAAG,EACH,GAAU,EAEd,IAAK,EAAI,EAAG,EAAI,EAAQ,OAAQ,IAC9B,EAAI,KAAK,cAAc,EAAQ,IAC/B,EAAU,GAAW,EAOvB,OAJK,GAAc,GACjB,KAAK,UAGA,CACT,EASA,gBAAgB,UAAU,cAAgB,SAAU,GAClD,IAAI,EACA,GAAS,EACb,GAAI,KAAK,SAAS,QAChB,EAAQ,KAAK,SAAS,QAAQ,QAE9B,IAAK,EAAI,EAAG,EAAI,KAAK,SAAS,OAAQ,IACpC,GAAI,IAAW,KAAK,SAAS,GAAI,CAC/B,EAAQ,EACR,KACF,CAIJ,OAAe,IAAX,IAKJ,EAAO,OAAO,MACd,KAAK,SAAS,OAAO,EAAO,IACrB,EACT,EAOA,gBAAgB,UAAU,aAAe,WACvC,KAAK,gBAAe,GACpB,KAAK,SAAW,EAClB,EAOA,gBAAgB,UAAU,QAAU,WAClC,IAAI,EAAc,KAAK,UAAU,QACjC,KAAK,UAAY,GACjB,KAAK,gBAAe,GACpB,KAAK,UAIL,YAAW,WACT,IAAI,EACJ,IAAK,EAAI,EAAG,EAAI,EAAY,OAAQ,IAClC,EAAY,GAAG,QAEnB,GAAG,EACL,EAUA,gBAAgB,UAAU,kBAAoB,SAAU,GACtD,IAAI,EAAa,KAAK,gBAGlB,EAAK,IAAI,OAAO,KAAK,OAAO,EAAO,eAAe,MAClD,EAAO,eAAe,OACtB,EAAK,IAAI,OAAO,KAAK,OAAO,EAAO,eAAe,MAClD,EAAO,eAAe,OAGtB,EAAQ,EAAW,qBAAqB,GAC5C,EAAM,GAAK,KAAK,UAChB,EAAM,GAAK,KAAK,UAEhB,IAAI,EAAQ,EAAW,qBAAqB,GAC5C,EAAM,GAAK,KAAK,UAChB,EAAM,GAAK,KAAK,UAGhB,IAAI,EAAK,EAAW,qBAAqB,GACrC,EAAK,EAAW,qBAAqB,GAMzC,OAHA,EAAO,OAAO,GACd,EAAO,OAAO,GAEP,CACT,EAMA,gBAAgB,UAAU,QAAU,WAClC,KAAK,gBAAgB,EACvB,EAUA,gBAAgB,UAAU,eAAiB,SAAU,GACnD,IAAI,EAAG,EAEP,IAAK,EAAI,EAAG,EAAI,KAAK,UAAU,OAAQ,IACrC,KAAK,UAAU,GAAG,SAKpB,IAHA,KAAK,UAAY,GAGZ,EAAI,EAAG,EAAI,KAAK,SAAS,OAAQ,KACpC,EAAS,KAAK,SAAS,IAChB,SAAU,EACb,GACF,EAAO,OAAO,KAGpB,EAWA,gBAAgB,UAAU,uBAAyB,SAAU,EAAI,GAC/D,IACI,GAAQ,EAAG,MAAQ,EAAG,OAAS,KAAK,GAAK,IACzC,GAAQ,EAAG,MAAQ,EAAG,OAAS,KAAK,GAAK,IACzC,EAAI,KAAK,IAAI,EAAO,GAAK,KAAK,IAAI,EAAO,GAC3C,KAAK,IAAI,EAAG,MAAQ,KAAK,GAAK,KAAO,KAAK,IAAI,EAAG,MAAQ,KAAK,GAAK,KACnE,KAAK,IAAI,EAAO,GAAK,KAAK,IAAI,EAAO,GAGvC,OARQ,MAMA,EAAI,KAAK,MAAM,KAAK,KAAK,GAAI,KAAK,KAAK,EAAI,IAGrD,EAUA,gBAAgB,UAAU,kBAAoB,SAAU,EAAQ,GAC9D,OAAO,EAAO,SAAS,EAAO,cAChC,EAQA,gBAAgB,UAAU,qBAAuB,SAAU,GACzD,IAAI,EAAG,EAAG,EAAS,EACf,EAAW,IACX,EAAiB,KACrB,IAAK,EAAI,EAAG,EAAI,KAAK,UAAU,OAAQ,KAErC,GADA,EAAU,KAAK,UAAU,IACR,eAEf,EAAI,KAAK,uBAAuB,EAAQ,EAAO,gBACvC,IACN,EAAW,EACX,EAAiB,GAKnB,GAAkB,EAAe,wBAAwB,GAC3D,EAAe,UAAU,KAEzB,EAAU,IAAI,QAAQ,OACd,UAAU,GAClB,KAAK,UAAU,KAAK,GAExB,EAUA,gBAAgB,UAAU,gBAAkB,SAAU,GACpD,IAAI,EAAG,EACH,EACA,EAAmB,KACvB,GAAK,KAAK,OAAV,CAKe,IAAX,IAQF,OAAO,KAAK,MAAM,QAAQ,KAAM,kBAAmB,WAEhB,IAAxB,KAAK,iBACd,aAAa,KAAK,uBACX,KAAK,iBASd,EADE,KAAK,SAAS,UAAY,EAChB,IAAI,OAAO,KAAK,aAAa,KAAK,SAAS,YAAY,eACjE,KAAK,SAAS,YAAY,gBAEhB,IAAI,OAAO,KAAK,aAAa,IAAI,OAAO,KAAK,OAAO,mBAAoB,iBAAkB,IAAI,OAAO,KAAK,QAAQ,kBAAmB,kBAEnJ,IAAI,EAAS,KAAK,kBAAkB,GAEhC,EAAQ,KAAK,IAAI,EAAS,KAAK,WAAY,KAAK,SAAS,QAE7D,IAAK,EAAI,EAAQ,EAAI,EAAO,MAC1B,EAAS,KAAK,SAAS,IACX,SAAW,KAAK,kBAAkB,EAAQ,MAC/C,KAAK,eAAkB,KAAK,eAAiB,EAAO,eACvD,KAAK,qBAAqB,GAK5B,EAAQ,KAAK,SAAS,OACxB,KAAK,eAAiB,YAAW,WAC/B,EAAiB,gBAAgB,EACnC,GAAG,WAEI,KAAK,eASZ,OAAO,KAAK,MAAM,QAAQ,KAAM,gBAAiB,MAxDnD,CA0DF,EAWA,gBAAgB,UAAU,OAAS,SAAU,EAAM,GACjD,OAAO,SAAW,GAChB,IAAI,EACJ,IAAK,KAAY,EAAO,UACtB,KAAK,UAAU,GAAY,EAAO,UAAU,GAE9C,OAAO,IACR,EAAE,MAAM,EAAM,CAAC,GAClB,EAaA,gBAAgB,WAAa,SAAU,EAAS,GAM9C,IALA,IAAI,EAAQ,EAER,EAAQ,EAAQ,OAAO,WAEvB,EAAK,EACK,IAAP,GACL,EAAK,SAAS,EAAK,GAAI,IACvB,IAIF,MAAO,CACL,KAAM,EACN,MAHF,EAAQ,KAAK,IAAI,EAAO,GAItB,MAbU,GAed,EASA,gBAAgB,WAAa,IAS7B,gBAAgB,cAAgB,IAShC,gBAAgB,WAAa,cAS7B,gBAAgB,gBAAkB,MASlC,gBAAgB,YAAc,CAAC,GAAI,GAAI,GAAI,GAAI","file":"/gh/googlemaps/v3-utility-library@07f15d84/markerclustererplus/src/markerclusterer.js","sourceRoot":"","sourcesContent":["/**\n * Minified by jsDelivr using Terser v5.39.0.\n * Original file: /gh/googlemaps/v3-utility-library@07f15d84/markerclustererplus/src/markerclusterer.js\n *\n * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files\n */\n","/**\n * @name MarkerClustererPlus for Google Maps V3\n * @version 2.1.2 [May 28, 2014]\n * @author Gary Little\n * @fileoverview\n * The library creates and manages per-zoom-level clusters for large amounts of markers.\n * <p>\n * This is an enhanced V3 implementation of the\n * <a href=\"http://gmaps-utility-library-dev.googlecode.com/svn/tags/markerclusterer/\"\n * >V2 MarkerClusterer</a> by Xiaoxi Wu. It is based on the\n * <a href=\"http://google-maps-utility-library-v3.googlecode.com/svn/tags/markerclusterer/\"\n * >V3 MarkerClusterer</a> port by Luke Mahe. MarkerClustererPlus was created by Gary Little.\n * <p>\n * v2.0 release: MarkerClustererPlus v2.0 is backward compatible with MarkerClusterer v1.0. It\n *  adds support for the <code>ignoreHidden</code>, <code>title</code>, <code>batchSizeIE</code>,\n *  and <code>calculator</code> properties as well as support for four more events. It also allows\n *  greater control over the styling of the text that appears on the cluster marker. The\n *  documentation has been significantly improved and the overall code has been simplified and\n *  polished. Very large numbers of markers can now be managed without causing Javascript timeout\n *  errors on Internet Explorer. Note that the name of the <code>clusterclick</code> event has been\n *  deprecated. The new name is <code>click</code>, so please change your application code now.\n */\n\n/**\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\n/**\n * @name ClusterIconStyle\n * @class This class represents the object for values in the <code>styles</code> array passed\n *  to the {@link MarkerClusterer} constructor. The element in this array that is used to\n *  style the cluster icon is determined by calling the <code>calculator</code> function.\n *\n * @property {string} url The URL of the cluster icon image file. Required.\n * @property {number} height The display height (in pixels) of the cluster icon. Required.\n * @property {number} width The display width (in pixels) of the cluster icon. Required.\n * @property {Array} [anchorText] The position (in pixels) from the center of the cluster icon to\n *  where the text label is to be centered and drawn. The format is <code>[yoffset, xoffset]</code>\n *  where <code>yoffset</code> increases as you go down from center and <code>xoffset</code>\n *  increases to the right of center. The default is <code>[0, 0]</code>.\n * @property {Array} [anchorIcon] The anchor position (in pixels) of the cluster icon. This is the\n *  spot on the cluster icon that is to be aligned with the cluster position. The format is\n *  <code>[yoffset, xoffset]</code> where <code>yoffset</code> increases as you go down and\n *  <code>xoffset</code> increases to the right of the top-left corner of the icon. The default\n *  anchor position is the center of the cluster icon.\n * @property {string} [textColor=\"black\"] The color of the label text shown on the\n *  cluster icon.\n * @property {number} [textSize=11] The size (in pixels) of the label text shown on the\n *  cluster icon.\n * @property {string} [textDecoration=\"none\"] The value of the CSS <code>text-decoration</code>\n *  property for the label text shown on the cluster icon.\n * @property {string} [fontWeight=\"bold\"] The value of the CSS <code>font-weight</code>\n *  property for the label text shown on the cluster icon.\n * @property {string} [fontStyle=\"normal\"] The value of the CSS <code>font-style</code>\n *  property for the label text shown on the cluster icon.\n * @property {string} [fontFamily=\"Arial,sans-serif\"] The value of the CSS <code>font-family</code>\n *  property for the label text shown on the cluster icon.\n * @property {string} [backgroundPosition=\"0 0\"] The position of the cluster icon image\n *  within the image defined by <code>url</code>. The format is <code>\"xpos ypos\"</code>\n *  (the same format as for the CSS <code>background-position</code> property). You must set\n *  this property appropriately when the image defined by <code>url</code> represents a sprite\n *  containing multiple images. Note that the position <i>must</i> be specified in px units.\n */\n/**\n * @name ClusterIconInfo\n * @class This class is an object containing general information about a cluster icon. This is\n *  the object that a <code>calculator</code> function returns.\n *\n * @property {string} text The text of the label to be shown on the cluster icon.\n * @property {number} index The index plus 1 of the element in the <code>styles</code>\n *  array to be used to style the cluster icon.\n * @property {string} title The tooltip to display when the mouse moves over the cluster icon.\n *  If this value is <code>undefined</code> or <code>\"\"</code>, <code>title</code> is set to the\n *  value of the <code>title</code> property passed to the MarkerClusterer.\n */\n/**\n * A cluster icon.\n *\n * @constructor\n * @extends google.maps.OverlayView\n * @param {Cluster} cluster The cluster with which the icon is to be associated.\n * @param {Array} [styles] An array of {@link ClusterIconStyle} defining the cluster icons\n *  to use for various cluster sizes.\n * @private\n */\nfunction ClusterIcon(cluster, styles) {\n  cluster.getMarkerClusterer().extend(ClusterIcon, google.maps.OverlayView);\n\n  this.cluster_ = cluster;\n  this.className_ = cluster.getMarkerClusterer().getClusterClass();\n  this.styles_ = styles;\n  this.center_ = null;\n  this.div_ = null;\n  this.sums_ = null;\n  this.visible_ = false;\n\n  this.setMap(cluster.getMap()); // Note: this causes onAdd to be called\n}\n\n\n/**\n * Adds the icon to the DOM.\n */\nClusterIcon.prototype.onAdd = function () {\n  var cClusterIcon = this;\n  var cMouseDownInCluster;\n  var cDraggingMapByCluster;\n\n  this.div_ = document.createElement(\"div\");\n  this.div_.className = this.className_;\n  if (this.visible_) {\n    this.show();\n  }\n\n  this.getPanes().overlayMouseTarget.appendChild(this.div_);\n\n  // Fix for Issue 157\n  this.boundsChangedListener_ = google.maps.event.addListener(this.getMap(), \"bounds_changed\", function () {\n    cDraggingMapByCluster = cMouseDownInCluster;\n  });\n\n  google.maps.event.addDomListener(this.div_, \"mousedown\", function () {\n    cMouseDownInCluster = true;\n    cDraggingMapByCluster = false;\n  });\n\n  google.maps.event.addDomListener(this.div_, \"click\", function (e) {\n    cMouseDownInCluster = false;\n    if (!cDraggingMapByCluster) {\n      var theBounds;\n      var mz;\n      var mc = cClusterIcon.cluster_.getMarkerClusterer();\n      /**\n       * This event is fired when a cluster marker is clicked.\n       * @name MarkerClusterer#click\n       * @param {Cluster} c The cluster that was clicked.\n       * @event\n       */\n      google.maps.event.trigger(mc, \"click\", cClusterIcon.cluster_);\n      google.maps.event.trigger(mc, \"clusterclick\", cClusterIcon.cluster_); // deprecated name\n\n      // The default click handler follows. Disable it by setting\n      // the zoomOnClick property to false.\n      if (mc.getZoomOnClick()) {\n        // Zoom into the cluster.\n        mz = mc.getMaxZoom();\n        theBounds = cClusterIcon.cluster_.getBounds();\n        mc.getMap().fitBounds(theBounds);\n        // There is a fix for Issue 170 here:\n        setTimeout(function () {\n          mc.getMap().fitBounds(theBounds);\n          // Don't zoom beyond the max zoom level\n          if (mz !== null && (mc.getMap().getZoom() > mz)) {\n            mc.getMap().setZoom(mz + 1);\n          }\n        }, 100);\n      }\n\n      // Prevent event propagation to the map:\n      e.cancelBubble = true;\n      if (e.stopPropagation) {\n        e.stopPropagation();\n      }\n    }\n  });\n\n  google.maps.event.addDomListener(this.div_, \"mouseover\", function () {\n    var mc = cClusterIcon.cluster_.getMarkerClusterer();\n    /**\n     * This event is fired when the mouse moves over a cluster marker.\n     * @name MarkerClusterer#mouseover\n     * @param {Cluster} c The cluster that the mouse moved over.\n     * @event\n     */\n    google.maps.event.trigger(mc, \"mouseover\", cClusterIcon.cluster_);\n  });\n\n  google.maps.event.addDomListener(this.div_, \"mouseout\", function () {\n    var mc = cClusterIcon.cluster_.getMarkerClusterer();\n    /**\n     * This event is fired when the mouse moves out of a cluster marker.\n     * @name MarkerClusterer#mouseout\n     * @param {Cluster} c The cluster that the mouse moved out of.\n     * @event\n     */\n    google.maps.event.trigger(mc, \"mouseout\", cClusterIcon.cluster_);\n  });\n};\n\n\n/**\n * Removes the icon from the DOM.\n */\nClusterIcon.prototype.onRemove = function () {\n  if (this.div_ && this.div_.parentNode) {\n    this.hide();\n    google.maps.event.removeListener(this.boundsChangedListener_);\n    google.maps.event.clearInstanceListeners(this.div_);\n    this.div_.parentNode.removeChild(this.div_);\n    this.div_ = null;\n  }\n};\n\n\n/**\n * Draws the icon.\n */\nClusterIcon.prototype.draw = function () {\n  if (this.visible_) {\n    var pos = this.getPosFromLatLng_(this.center_);\n    this.div_.style.top = pos.y + \"px\";\n    this.div_.style.left = pos.x + \"px\";\n  }\n};\n\n\n/**\n * Hides the icon.\n */\nClusterIcon.prototype.hide = function () {\n  if (this.div_) {\n    this.div_.style.display = \"none\";\n  }\n  this.visible_ = false;\n};\n\n\n/**\n * Positions and shows the icon.\n */\nClusterIcon.prototype.show = function () {\n  if (this.div_) {\n    var img = \"\";\n    // NOTE: values must be specified in px units\n    var bp = this.backgroundPosition_.split(\" \");\n    var spriteH = parseInt(bp[0].replace(/^\\s+|\\s+$/g, \"\"), 10);\n    var spriteV = parseInt(bp[1].replace(/^\\s+|\\s+$/g, \"\"), 10);\n    var pos = this.getPosFromLatLng_(this.center_);\n    this.div_.style.cssText = this.createCss(pos);\n    img = \"<img src='\" + this.url_ + \"' style='position: absolute; top: \" + spriteV + \"px; left: \" + spriteH + \"px; \";\n    if (!this.cluster_.getMarkerClusterer().enableRetinaIcons_) {\n      img += \"clip: rect(\" + (-1 * spriteV) + \"px, \" + ((-1 * spriteH) + this.width_) + \"px, \" +\n          ((-1 * spriteV) + this.height_) + \"px, \" + (-1 * spriteH) + \"px);\";\n    }\n    img += \"'>\";\n    this.div_.innerHTML = img + \"<div style='\" +\n        \"position: absolute;\" +\n        \"top: \" + this.anchorText_[0] + \"px;\" +\n        \"left: \" + this.anchorText_[1] + \"px;\" +\n        \"color: \" + this.textColor_ + \";\" +\n        \"font-size: \" + this.textSize_ + \"px;\" +\n        \"font-family: \" + this.fontFamily_ + \";\" +\n        \"font-weight: \" + this.fontWeight_ + \";\" +\n        \"font-style: \" + this.fontStyle_ + \";\" +\n        \"text-decoration: \" + this.textDecoration_ + \";\" +\n        \"text-align: center;\" +\n        \"width: \" + this.width_ + \"px;\" +\n        \"line-height:\" + this.height_ + \"px;\" +\n        \"'>\" + this.sums_.text + \"</div>\";\n    if (typeof this.sums_.title === \"undefined\" || this.sums_.title === \"\") {\n      this.div_.title = this.cluster_.getMarkerClusterer().getTitle();\n    } else {\n      this.div_.title = this.sums_.title;\n    }\n    this.div_.style.display = \"\";\n  }\n  this.visible_ = true;\n};\n\n\n/**\n * Sets the icon styles to the appropriate element in the styles array.\n *\n * @param {ClusterIconInfo} sums The icon label text and styles index.\n */\nClusterIcon.prototype.useStyle = function (sums) {\n  this.sums_ = sums;\n  var index = Math.max(0, sums.index - 1);\n  index = Math.min(this.styles_.length - 1, index);\n  var style = this.styles_[index];\n  this.url_ = style.url;\n  this.height_ = style.height;\n  this.width_ = style.width;\n  this.anchorText_ = style.anchorText || [0, 0];\n  this.anchorIcon_ = style.anchorIcon || [parseInt(this.height_ / 2, 10), parseInt(this.width_ / 2, 10)];\n  this.textColor_ = style.textColor || \"black\";\n  this.textSize_ = style.textSize || 11;\n  this.textDecoration_ = style.textDecoration || \"none\";\n  this.fontWeight_ = style.fontWeight || \"bold\";\n  this.fontStyle_ = style.fontStyle || \"normal\";\n  this.fontFamily_ = style.fontFamily || \"Arial,sans-serif\";\n  this.backgroundPosition_ = style.backgroundPosition || \"0 0\";\n};\n\n\n/**\n * Sets the position at which to center the icon.\n *\n * @param {google.maps.LatLng} center The latlng to set as the center.\n */\nClusterIcon.prototype.setCenter = function (center) {\n  this.center_ = center;\n};\n\n\n/**\n * Creates the cssText style parameter based on the position of the icon.\n *\n * @param {google.maps.Point} pos The position of the icon.\n * @return {string} The CSS style text.\n */\nClusterIcon.prototype.createCss = function (pos) {\n  var style = [];\n  style.push(\"cursor: pointer;\");\n  style.push(\"position: absolute; top: \" + pos.y + \"px; left: \" + pos.x + \"px;\");\n  style.push(\"width: \" + this.width_ + \"px; height: \" + this.height_ + \"px;\");\n  return style.join(\"\");\n};\n\n\n/**\n * Returns the position at which to place the DIV depending on the latlng.\n *\n * @param {google.maps.LatLng} latlng The position in latlng.\n * @return {google.maps.Point} The position in pixels.\n */\nClusterIcon.prototype.getPosFromLatLng_ = function (latlng) {\n  var pos = this.getProjection().fromLatLngToDivPixel(latlng);\n  pos.x -= this.anchorIcon_[1];\n  pos.y -= this.anchorIcon_[0];\n  pos.x = parseInt(pos.x, 10);\n  pos.y = parseInt(pos.y, 10);\n  return pos;\n};\n\n\n/**\n * Creates a single cluster that manages a group of proximate markers.\n *  Used internally, do not call this constructor directly.\n * @constructor\n * @param {MarkerClusterer} mc The <code>MarkerClusterer</code> object with which this\n *  cluster is associated.\n */\nfunction Cluster(mc) {\n  this.markerClusterer_ = mc;\n  this.map_ = mc.getMap();\n  this.gridSize_ = mc.getGridSize();\n  this.minClusterSize_ = mc.getMinimumClusterSize();\n  this.averageCenter_ = mc.getAverageCenter();\n  this.markers_ = [];\n  this.center_ = null;\n  this.bounds_ = null;\n  this.clusterIcon_ = new ClusterIcon(this, mc.getStyles());\n}\n\n\n/**\n * Returns the number of markers managed by the cluster. You can call this from\n * a <code>click</code>, <code>mouseover</code>, or <code>mouseout</code> event handler\n * for the <code>MarkerClusterer</code> object.\n *\n * @return {number} The number of markers in the cluster.\n */\nCluster.prototype.getSize = function () {\n  return this.markers_.length;\n};\n\n\n/**\n * Returns the array of markers managed by the cluster. You can call this from\n * a <code>click</code>, <code>mouseover</code>, or <code>mouseout</code> event handler\n * for the <code>MarkerClusterer</code> object.\n *\n * @return {Array} The array of markers in the cluster.\n */\nCluster.prototype.getMarkers = function () {\n  return this.markers_;\n};\n\n\n/**\n * Returns the center of the cluster. You can call this from\n * a <code>click</code>, <code>mouseover</code>, or <code>mouseout</code> event handler\n * for the <code>MarkerClusterer</code> object.\n *\n * @return {google.maps.LatLng} The center of the cluster.\n */\nCluster.prototype.getCenter = function () {\n  return this.center_;\n};\n\n\n/**\n * Returns the map with which the cluster is associated.\n *\n * @return {google.maps.Map} The map.\n * @ignore\n */\nCluster.prototype.getMap = function () {\n  return this.map_;\n};\n\n\n/**\n * Returns the <code>MarkerClusterer</code> object with which the cluster is associated.\n *\n * @return {MarkerClusterer} The associated marker clusterer.\n * @ignore\n */\nCluster.prototype.getMarkerClusterer = function () {\n  return this.markerClusterer_;\n};\n\n\n/**\n * Returns the bounds of the cluster.\n *\n * @return {google.maps.LatLngBounds} the cluster bounds.\n * @ignore\n */\nCluster.prototype.getBounds = function () {\n  var i;\n  var bounds = new google.maps.LatLngBounds(this.center_, this.center_);\n  var markers = this.getMarkers();\n  for (i = 0; i < markers.length; i++) {\n    bounds.extend(markers[i].getPosition());\n  }\n  return bounds;\n};\n\n\n/**\n * Removes the cluster from the map.\n *\n * @ignore\n */\nCluster.prototype.remove = function () {\n  this.clusterIcon_.setMap(null);\n  this.markers_ = [];\n  delete this.markers_;\n};\n\n\n/**\n * Adds a marker to the cluster.\n *\n * @param {google.maps.Marker} marker The marker to be added.\n * @return {boolean} True if the marker was added.\n * @ignore\n */\nCluster.prototype.addMarker = function (marker) {\n  var i;\n  var mCount;\n  var mz;\n\n  if (this.isMarkerAlreadyAdded_(marker)) {\n    return false;\n  }\n\n  if (!this.center_) {\n    this.center_ = marker.getPosition();\n    this.calculateBounds_();\n  } else {\n    if (this.averageCenter_) {\n      var l = this.markers_.length + 1;\n      var lat = (this.center_.lat() * (l - 1) + marker.getPosition().lat()) / l;\n      var lng = (this.center_.lng() * (l - 1) + marker.getPosition().lng()) / l;\n      this.center_ = new google.maps.LatLng(lat, lng);\n      this.calculateBounds_();\n    }\n  }\n\n  marker.isAdded = true;\n  this.markers_.push(marker);\n\n  mCount = this.markers_.length;\n  mz = this.markerClusterer_.getMaxZoom();\n  if (mz !== null && this.map_.getZoom() > mz) {\n    // Zoomed in past max zoom, so show the marker.\n    if (marker.getMap() !== this.map_) {\n      marker.setMap(this.map_);\n    }\n  } else if (mCount < this.minClusterSize_) {\n    // Min cluster size not reached so show the marker.\n    if (marker.getMap() !== this.map_) {\n      marker.setMap(this.map_);\n    }\n  } else if (mCount === this.minClusterSize_) {\n    // Hide the markers that were showing.\n    for (i = 0; i < mCount; i++) {\n      this.markers_[i].setMap(null);\n    }\n  } else {\n    marker.setMap(null);\n  }\n\n  this.updateIcon_();\n  return true;\n};\n\n\n/**\n * Determines if a marker lies within the cluster's bounds.\n *\n * @param {google.maps.Marker} marker The marker to check.\n * @return {boolean} True if the marker lies in the bounds.\n * @ignore\n */\nCluster.prototype.isMarkerInClusterBounds = function (marker) {\n  return this.bounds_.contains(marker.getPosition());\n};\n\n\n/**\n * Calculates the extended bounds of the cluster with the grid.\n */\nCluster.prototype.calculateBounds_ = function () {\n  var bounds = new google.maps.LatLngBounds(this.center_, this.center_);\n  this.bounds_ = this.markerClusterer_.getExtendedBounds(bounds);\n};\n\n\n/**\n * Updates the cluster icon.\n */\nCluster.prototype.updateIcon_ = function () {\n  var mCount = this.markers_.length;\n  var mz = this.markerClusterer_.getMaxZoom();\n\n  if (mz !== null && this.map_.getZoom() > mz) {\n    this.clusterIcon_.hide();\n    return;\n  }\n\n  if (mCount < this.minClusterSize_) {\n    // Min cluster size not yet reached.\n    this.clusterIcon_.hide();\n    return;\n  }\n\n  var numStyles = this.markerClusterer_.getStyles().length;\n  var sums = this.markerClusterer_.getCalculator()(this.markers_, numStyles);\n  this.clusterIcon_.setCenter(this.center_);\n  this.clusterIcon_.useStyle(sums);\n  this.clusterIcon_.show();\n};\n\n\n/**\n * Determines if a marker has already been added to the cluster.\n *\n * @param {google.maps.Marker} marker The marker to check.\n * @return {boolean} True if the marker has already been added.\n */\nCluster.prototype.isMarkerAlreadyAdded_ = function (marker) {\n  var i;\n  if (this.markers_.indexOf) {\n    return this.markers_.indexOf(marker) !== -1;\n  } else {\n    for (i = 0; i < this.markers_.length; i++) {\n      if (marker === this.markers_[i]) {\n        return true;\n      }\n    }\n  }\n  return false;\n};\n\n\n/**\n * @name MarkerClustererOptions\n * @class This class represents the optional parameter passed to\n *  the {@link MarkerClusterer} constructor.\n * @property {number} [gridSize=60] The grid size of a cluster in pixels. The grid is a square.\n * @property {number} [maxZoom=null] The maximum zoom level at which clustering is enabled or\n *  <code>null</code> if clustering is to be enabled at all zoom levels.\n * @property {boolean} [zoomOnClick=true] Whether to zoom the map when a cluster marker is\n *  clicked. You may want to set this to <code>false</code> if you have installed a handler\n *  for the <code>click</code> event and it deals with zooming on its own.\n * @property {boolean} [averageCenter=false] Whether the position of a cluster marker should be\n *  the average position of all markers in the cluster. If set to <code>false</code>, the\n *  cluster marker is positioned at the location of the first marker added to the cluster.\n * @property {number} [minimumClusterSize=2] The minimum number of markers needed in a cluster\n *  before the markers are hidden and a cluster marker appears.\n * @property {boolean} [ignoreHidden=false] Whether to ignore hidden markers in clusters. You\n *  may want to set this to <code>true</code> to ensure that hidden markers are not included\n *  in the marker count that appears on a cluster marker (this count is the value of the\n *  <code>text</code> property of the result returned by the default <code>calculator</code>).\n *  If set to <code>true</code> and you change the visibility of a marker being clustered, be\n *  sure to also call <code>MarkerClusterer.repaint()</code>.\n * @property {string} [title=\"\"] The tooltip to display when the mouse moves over a cluster\n *  marker. (Alternatively, you can use a custom <code>calculator</code> function to specify a\n *  different tooltip for each cluster marker.)\n * @property {function} [calculator=MarkerClusterer.CALCULATOR] The function used to determine\n *  the text to be displayed on a cluster marker and the index indicating which style to use\n *  for the cluster marker. The input parameters for the function are (1) the array of markers\n *  represented by a cluster marker and (2) the number of cluster icon styles. It returns a\n *  {@link ClusterIconInfo} object. The default <code>calculator</code> returns a\n *  <code>text</code> property which is the number of markers in the cluster and an\n *  <code>index</code> property which is one higher than the lowest integer such that\n *  <code>10^i</code> exceeds the number of markers in the cluster, or the size of the styles\n *  array, whichever is less. The <code>styles</code> array element used has an index of\n *  <code>index</code> minus 1. For example, the default <code>calculator</code> returns a\n *  <code>text</code> value of <code>\"125\"</code> and an <code>index</code> of <code>3</code>\n *  for a cluster icon representing 125 markers so the element used in the <code>styles</code>\n *  array is <code>2</code>. A <code>calculator</code> may also return a <code>title</code>\n *  property that contains the text of the tooltip to be used for the cluster marker. If\n *   <code>title</code> is not defined, the tooltip is set to the value of the <code>title</code>\n *   property for the MarkerClusterer.\n * @property {string} [clusterClass=\"cluster\"] The name of the CSS class defining general styles\n *  for the cluster markers. Use this class to define CSS styles that are not set up by the code\n *  that processes the <code>styles</code> array.\n * @property {Array} [styles] An array of {@link ClusterIconStyle} elements defining the styles\n *  of the cluster markers to be used. The element to be used to style a given cluster marker\n *  is determined by the function defined by the <code>calculator</code> property.\n *  The default is an array of {@link ClusterIconStyle} elements whose properties are derived\n *  from the values for <code>imagePath</code>, <code>imageExtension</code>, and\n *  <code>imageSizes</code>.\n * @property {boolean} [enableRetinaIcons=false] Whether to allow the use of cluster icons that\n * have sizes that are some multiple (typically double) of their actual display size. Icons such\n * as these look better when viewed on high-resolution monitors such as Apple's Retina displays.\n * Note: if this property is <code>true</code>, sprites cannot be used as cluster icons.\n * @property {number} [batchSize=MarkerClusterer.BATCH_SIZE] Set this property to the\n *  number of markers to be processed in a single batch when using a browser other than\n *  Internet Explorer (for Internet Explorer, use the batchSizeIE property instead).\n * @property {number} [batchSizeIE=MarkerClusterer.BATCH_SIZE_IE] When Internet Explorer is\n *  being used, markers are processed in several batches with a small delay inserted between\n *  each batch in an attempt to avoid Javascript timeout errors. Set this property to the\n *  number of markers to be processed in a single batch; select as high a number as you can\n *  without causing a timeout error in the browser. This number might need to be as low as 100\n *  if 15,000 markers are being managed, for example.\n * @property {string} [imagePath=MarkerClusterer.IMAGE_PATH]\n *  The full URL of the root name of the group of image files to use for cluster icons.\n *  The complete file name is of the form <code>imagePath</code>n.<code>imageExtension</code>\n *  where n is the image file number (1, 2, etc.).\n * @property {string} [imageExtension=MarkerClusterer.IMAGE_EXTENSION]\n *  The extension name for the cluster icon image files (e.g., <code>\"png\"</code> or\n *  <code>\"jpg\"</code>).\n * @property {Array} [imageSizes=MarkerClusterer.IMAGE_SIZES]\n *  An array of numbers containing the widths of the group of\n *  <code>imagePath</code>n.<code>imageExtension</code> image files.\n *  (The images are assumed to be square.)\n */\n/**\n * Creates a MarkerClusterer object with the options specified in {@link MarkerClustererOptions}.\n * @constructor\n * @extends google.maps.OverlayView\n * @param {google.maps.Map} map The Google map to attach to.\n * @param {Array.<google.maps.Marker>} [opt_markers] The markers to be added to the cluster.\n * @param {MarkerClustererOptions} [opt_options] The optional parameters.\n */\nfunction MarkerClusterer(map, opt_markers, opt_options) {\n  // MarkerClusterer implements google.maps.OverlayView interface. We use the\n  // extend function to extend MarkerClusterer with google.maps.OverlayView\n  // because it might not always be available when the code is defined so we\n  // look for it at the last possible moment. If it doesn't exist now then\n  // there is no point going ahead :)\n  this.extend(MarkerClusterer, google.maps.OverlayView);\n\n  opt_markers = opt_markers || [];\n  opt_options = opt_options || {};\n\n  this.markers_ = [];\n  this.clusters_ = [];\n  this.listeners_ = [];\n  this.activeMap_ = null;\n  this.ready_ = false;\n\n  this.gridSize_ = opt_options.gridSize || 60;\n  this.minClusterSize_ = opt_options.minimumClusterSize || 2;\n  this.maxZoom_ = opt_options.maxZoom || null;\n  this.styles_ = opt_options.styles || [];\n  this.title_ = opt_options.title || \"\";\n  this.zoomOnClick_ = true;\n  if (opt_options.zoomOnClick !== undefined) {\n    this.zoomOnClick_ = opt_options.zoomOnClick;\n  }\n  this.averageCenter_ = false;\n  if (opt_options.averageCenter !== undefined) {\n    this.averageCenter_ = opt_options.averageCenter;\n  }\n  this.ignoreHidden_ = false;\n  if (opt_options.ignoreHidden !== undefined) {\n    this.ignoreHidden_ = opt_options.ignoreHidden;\n  }\n  this.enableRetinaIcons_ = false;\n  if (opt_options.enableRetinaIcons !== undefined) {\n    this.enableRetinaIcons_ = opt_options.enableRetinaIcons;\n  }\n  this.imagePath_ = opt_options.imagePath || MarkerClusterer.IMAGE_PATH;\n  this.imageExtension_ = opt_options.imageExtension || MarkerClusterer.IMAGE_EXTENSION;\n  this.imageSizes_ = opt_options.imageSizes || MarkerClusterer.IMAGE_SIZES;\n  this.calculator_ = opt_options.calculator || MarkerClusterer.CALCULATOR;\n  this.batchSize_ = opt_options.batchSize || MarkerClusterer.BATCH_SIZE;\n  this.batchSizeIE_ = opt_options.batchSizeIE || MarkerClusterer.BATCH_SIZE_IE;\n  this.clusterClass_ = opt_options.clusterClass || \"cluster\";\n\n  if (navigator.userAgent.toLowerCase().indexOf(\"msie\") !== -1) {\n    // Try to avoid IE timeout when processing a huge number of markers:\n    this.batchSize_ = this.batchSizeIE_;\n  }\n\n  this.setupStyles_();\n\n  this.addMarkers(opt_markers, true);\n  this.setMap(map); // Note: this causes onAdd to be called\n}\n\n\n/**\n * Implementation of the onAdd interface method.\n * @ignore\n */\nMarkerClusterer.prototype.onAdd = function () {\n  var cMarkerClusterer = this;\n\n  this.activeMap_ = this.getMap();\n  this.ready_ = true;\n\n  this.repaint();\n\n  // Add the map event listeners\n  this.listeners_ = [\n    google.maps.event.addListener(this.getMap(), \"zoom_changed\", function () {\n      cMarkerClusterer.resetViewport_(false);\n      // Workaround for this Google bug: when map is at level 0 and \"-\" of\n      // zoom slider is clicked, a \"zoom_changed\" event is fired even though\n      // the map doesn't zoom out any further. In this situation, no \"idle\"\n      // event is triggered so the cluster markers that have been removed\n      // do not get redrawn. Same goes for a zoom in at maxZoom.\n      if (this.getZoom() === (this.get(\"minZoom\") || 0) || this.getZoom() === this.get(\"maxZoom\")) {\n        google.maps.event.trigger(this, \"idle\");\n      }\n    }),\n    google.maps.event.addListener(this.getMap(), \"idle\", function () {\n      cMarkerClusterer.redraw_();\n    })\n  ];\n};\n\n\n/**\n * Implementation of the onRemove interface method.\n * Removes map event listeners and all cluster icons from the DOM.\n * All managed markers are also put back on the map.\n * @ignore\n */\nMarkerClusterer.prototype.onRemove = function () {\n  var i;\n\n  // Put all the managed markers back on the map:\n  for (i = 0; i < this.markers_.length; i++) {\n    if (this.markers_[i].getMap() !== this.activeMap_) {\n      this.markers_[i].setMap(this.activeMap_);\n    }\n  }\n\n  // Remove all clusters:\n  for (i = 0; i < this.clusters_.length; i++) {\n    this.clusters_[i].remove();\n  }\n  this.clusters_ = [];\n\n  // Remove map event listeners:\n  for (i = 0; i < this.listeners_.length; i++) {\n    google.maps.event.removeListener(this.listeners_[i]);\n  }\n  this.listeners_ = [];\n\n  this.activeMap_ = null;\n  this.ready_ = false;\n};\n\n\n/**\n * Implementation of the draw interface method.\n * @ignore\n */\nMarkerClusterer.prototype.draw = function () {};\n\n\n/**\n * Sets up the styles object.\n */\nMarkerClusterer.prototype.setupStyles_ = function () {\n  var i, size;\n  if (this.styles_.length > 0) {\n    return;\n  }\n\n  for (i = 0; i < this.imageSizes_.length; i++) {\n    size = this.imageSizes_[i];\n    this.styles_.push({\n      url: this.imagePath_ + (i + 1) + \".\" + this.imageExtension_,\n      height: size,\n      width: size\n    });\n  }\n};\n\n\n/**\n *  Fits the map to the bounds of the markers managed by the clusterer.\n */\nMarkerClusterer.prototype.fitMapToMarkers = function () {\n  var i;\n  var markers = this.getMarkers();\n  var bounds = new google.maps.LatLngBounds();\n  for (i = 0; i < markers.length; i++) {\n    bounds.extend(markers[i].getPosition());\n  }\n\n  this.getMap().fitBounds(bounds);\n};\n\n\n/**\n * Returns the value of the <code>gridSize</code> property.\n *\n * @return {number} The grid size.\n */\nMarkerClusterer.prototype.getGridSize = function () {\n  return this.gridSize_;\n};\n\n\n/**\n * Sets the value of the <code>gridSize</code> property.\n *\n * @param {number} gridSize The grid size.\n */\nMarkerClusterer.prototype.setGridSize = function (gridSize) {\n  this.gridSize_ = gridSize;\n};\n\n\n/**\n * Returns the value of the <code>minimumClusterSize</code> property.\n *\n * @return {number} The minimum cluster size.\n */\nMarkerClusterer.prototype.getMinimumClusterSize = function () {\n  return this.minClusterSize_;\n};\n\n/**\n * Sets the value of the <code>minimumClusterSize</code> property.\n *\n * @param {number} minimumClusterSize The minimum cluster size.\n */\nMarkerClusterer.prototype.setMinimumClusterSize = function (minimumClusterSize) {\n  this.minClusterSize_ = minimumClusterSize;\n};\n\n\n/**\n *  Returns the value of the <code>maxZoom</code> property.\n *\n *  @return {number} The maximum zoom level.\n */\nMarkerClusterer.prototype.getMaxZoom = function () {\n  return this.maxZoom_;\n};\n\n\n/**\n *  Sets the value of the <code>maxZoom</code> property.\n *\n *  @param {number} maxZoom The maximum zoom level.\n */\nMarkerClusterer.prototype.setMaxZoom = function (maxZoom) {\n  this.maxZoom_ = maxZoom;\n};\n\n\n/**\n *  Returns the value of the <code>styles</code> property.\n *\n *  @return {Array} The array of styles defining the cluster markers to be used.\n */\nMarkerClusterer.prototype.getStyles = function () {\n  return this.styles_;\n};\n\n\n/**\n *  Sets the value of the <code>styles</code> property.\n *\n *  @param {Array.<ClusterIconStyle>} styles The array of styles to use.\n */\nMarkerClusterer.prototype.setStyles = function (styles) {\n  this.styles_ = styles;\n};\n\n\n/**\n * Returns the value of the <code>title</code> property.\n *\n * @return {string} The content of the title text.\n */\nMarkerClusterer.prototype.getTitle = function () {\n  return this.title_;\n};\n\n\n/**\n *  Sets the value of the <code>title</code> property.\n *\n *  @param {string} title The value of the title property.\n */\nMarkerClusterer.prototype.setTitle = function (title) {\n  this.title_ = title;\n};\n\n\n/**\n * Returns the value of the <code>zoomOnClick</code> property.\n *\n * @return {boolean} True if zoomOnClick property is set.\n */\nMarkerClusterer.prototype.getZoomOnClick = function () {\n  return this.zoomOnClick_;\n};\n\n\n/**\n *  Sets the value of the <code>zoomOnClick</code> property.\n *\n *  @param {boolean} zoomOnClick The value of the zoomOnClick property.\n */\nMarkerClusterer.prototype.setZoomOnClick = function (zoomOnClick) {\n  this.zoomOnClick_ = zoomOnClick;\n};\n\n\n/**\n * Returns the value of the <code>averageCenter</code> property.\n *\n * @return {boolean} True if averageCenter property is set.\n */\nMarkerClusterer.prototype.getAverageCenter = function () {\n  return this.averageCenter_;\n};\n\n\n/**\n *  Sets the value of the <code>averageCenter</code> property.\n *\n *  @param {boolean} averageCenter The value of the averageCenter property.\n */\nMarkerClusterer.prototype.setAverageCenter = function (averageCenter) {\n  this.averageCenter_ = averageCenter;\n};\n\n\n/**\n * Returns the value of the <code>ignoreHidden</code> property.\n *\n * @return {boolean} True if ignoreHidden property is set.\n */\nMarkerClusterer.prototype.getIgnoreHidden = function () {\n  return this.ignoreHidden_;\n};\n\n\n/**\n *  Sets the value of the <code>ignoreHidden</code> property.\n *\n *  @param {boolean} ignoreHidden The value of the ignoreHidden property.\n */\nMarkerClusterer.prototype.setIgnoreHidden = function (ignoreHidden) {\n  this.ignoreHidden_ = ignoreHidden;\n};\n\n\n/**\n * Returns the value of the <code>enableRetinaIcons</code> property.\n *\n * @return {boolean} True if enableRetinaIcons property is set.\n */\nMarkerClusterer.prototype.getEnableRetinaIcons = function () {\n  return this.enableRetinaIcons_;\n};\n\n\n/**\n *  Sets the value of the <code>enableRetinaIcons</code> property.\n *\n *  @param {boolean} enableRetinaIcons The value of the enableRetinaIcons property.\n */\nMarkerClusterer.prototype.setEnableRetinaIcons = function (enableRetinaIcons) {\n  this.enableRetinaIcons_ = enableRetinaIcons;\n};\n\n\n/**\n * Returns the value of the <code>imageExtension</code> property.\n *\n * @return {string} The value of the imageExtension property.\n */\nMarkerClusterer.prototype.getImageExtension = function () {\n  return this.imageExtension_;\n};\n\n\n/**\n *  Sets the value of the <code>imageExtension</code> property.\n *\n *  @param {string} imageExtension The value of the imageExtension property.\n */\nMarkerClusterer.prototype.setImageExtension = function (imageExtension) {\n  this.imageExtension_ = imageExtension;\n};\n\n\n/**\n * Returns the value of the <code>imagePath</code> property.\n *\n * @return {string} The value of the imagePath property.\n */\nMarkerClusterer.prototype.getImagePath = function () {\n  return this.imagePath_;\n};\n\n\n/**\n *  Sets the value of the <code>imagePath</code> property.\n *\n *  @param {string} imagePath The value of the imagePath property.\n */\nMarkerClusterer.prototype.setImagePath = function (imagePath) {\n  this.imagePath_ = imagePath;\n};\n\n\n/**\n * Returns the value of the <code>imageSizes</code> property.\n *\n * @return {Array} The value of the imageSizes property.\n */\nMarkerClusterer.prototype.getImageSizes = function () {\n  return this.imageSizes_;\n};\n\n\n/**\n *  Sets the value of the <code>imageSizes</code> property.\n *\n *  @param {Array} imageSizes The value of the imageSizes property.\n */\nMarkerClusterer.prototype.setImageSizes = function (imageSizes) {\n  this.imageSizes_ = imageSizes;\n};\n\n\n/**\n * Returns the value of the <code>calculator</code> property.\n *\n * @return {function} the value of the calculator property.\n */\nMarkerClusterer.prototype.getCalculator = function () {\n  return this.calculator_;\n};\n\n\n/**\n * Sets the value of the <code>calculator</code> property.\n *\n * @param {function(Array.<google.maps.Marker>, number)} calculator The value\n *  of the calculator property.\n */\nMarkerClusterer.prototype.setCalculator = function (calculator) {\n  this.calculator_ = calculator;\n};\n\n\n/**\n * Returns the value of the <code>batchSizeIE</code> property.\n *\n * @return {number} the value of the batchSizeIE property.\n */\nMarkerClusterer.prototype.getBatchSizeIE = function () {\n  return this.batchSizeIE_;\n};\n\n\n/**\n * Sets the value of the <code>batchSizeIE</code> property.\n *\n *  @param {number} batchSizeIE The value of the batchSizeIE property.\n */\nMarkerClusterer.prototype.setBatchSizeIE = function (batchSizeIE) {\n  this.batchSizeIE_ = batchSizeIE;\n};\n\n\n/**\n * Returns the value of the <code>clusterClass</code> property.\n *\n * @return {string} the value of the clusterClass property.\n */\nMarkerClusterer.prototype.getClusterClass = function () {\n  return this.clusterClass_;\n};\n\n\n/**\n * Sets the value of the <code>clusterClass</code> property.\n *\n *  @param {string} clusterClass The value of the clusterClass property.\n */\nMarkerClusterer.prototype.setClusterClass = function (clusterClass) {\n  this.clusterClass_ = clusterClass;\n};\n\n\n/**\n *  Returns the array of markers managed by the clusterer.\n *\n *  @return {Array} The array of markers managed by the clusterer.\n */\nMarkerClusterer.prototype.getMarkers = function () {\n  return this.markers_;\n};\n\n\n/**\n *  Returns the number of markers managed by the clusterer.\n *\n *  @return {number} The number of markers.\n */\nMarkerClusterer.prototype.getTotalMarkers = function () {\n  return this.markers_.length;\n};\n\n\n/**\n * Returns the current array of clusters formed by the clusterer.\n *\n * @return {Array} The array of clusters formed by the clusterer.\n */\nMarkerClusterer.prototype.getClusters = function () {\n  return this.clusters_;\n};\n\n\n/**\n * Returns the number of clusters formed by the clusterer.\n *\n * @return {number} The number of clusters formed by the clusterer.\n */\nMarkerClusterer.prototype.getTotalClusters = function () {\n  return this.clusters_.length;\n};\n\n\n/**\n * Adds a marker to the clusterer. The clusters are redrawn unless\n *  <code>opt_nodraw</code> is set to <code>true</code>.\n *\n * @param {google.maps.Marker} marker The marker to add.\n * @param {boolean} [opt_nodraw] Set to <code>true</code> to prevent redrawing.\n */\nMarkerClusterer.prototype.addMarker = function (marker, opt_nodraw) {\n  this.pushMarkerTo_(marker);\n  if (!opt_nodraw) {\n    this.redraw_();\n  }\n};\n\n\n/**\n * Adds an array of markers to the clusterer. The clusters are redrawn unless\n *  <code>opt_nodraw</code> is set to <code>true</code>.\n *\n * @param {Array.<google.maps.Marker>} markers The markers to add.\n * @param {boolean} [opt_nodraw] Set to <code>true</code> to prevent redrawing.\n */\nMarkerClusterer.prototype.addMarkers = function (markers, opt_nodraw) {\n  var key;\n  for (key in markers) {\n    if (markers.hasOwnProperty(key)) {\n      this.pushMarkerTo_(markers[key]);\n    }\n  }  \n  if (!opt_nodraw) {\n    this.redraw_();\n  }\n};\n\n\n/**\n * Pushes a marker to the clusterer.\n *\n * @param {google.maps.Marker} marker The marker to add.\n */\nMarkerClusterer.prototype.pushMarkerTo_ = function (marker) {\n  // If the marker is draggable add a listener so we can update the clusters on the dragend:\n  if (marker.getDraggable()) {\n    var cMarkerClusterer = this;\n    google.maps.event.addListener(marker, \"dragend\", function () {\n      if (cMarkerClusterer.ready_) {\n        this.isAdded = false;\n        cMarkerClusterer.repaint();\n      }\n    });\n  }\n  marker.isAdded = false;\n  this.markers_.push(marker);\n};\n\n\n/**\n * Removes a marker from the cluster.  The clusters are redrawn unless\n *  <code>opt_nodraw</code> is set to <code>true</code>. Returns <code>true</code> if the\n *  marker was removed from the clusterer.\n *\n * @param {google.maps.Marker} marker The marker to remove.\n * @param {boolean} [opt_nodraw] Set to <code>true</code> to prevent redrawing.\n * @return {boolean} True if the marker was removed from the clusterer.\n */\nMarkerClusterer.prototype.removeMarker = function (marker, opt_nodraw) {\n  var removed = this.removeMarker_(marker);\n\n  if (!opt_nodraw && removed) {\n    this.repaint();\n  }\n\n  return removed;\n};\n\n\n/**\n * Removes an array of markers from the cluster. The clusters are redrawn unless\n *  <code>opt_nodraw</code> is set to <code>true</code>. Returns <code>true</code> if markers\n *  were removed from the clusterer.\n *\n * @param {Array.<google.maps.Marker>} markers The markers to remove.\n * @param {boolean} [opt_nodraw] Set to <code>true</code> to prevent redrawing.\n * @return {boolean} True if markers were removed from the clusterer.\n */\nMarkerClusterer.prototype.removeMarkers = function (markers, opt_nodraw) {\n  var i, r;\n  var removed = false;\n\n  for (i = 0; i < markers.length; i++) {\n    r = this.removeMarker_(markers[i]);\n    removed = removed || r;\n  }\n\n  if (!opt_nodraw && removed) {\n    this.repaint();\n  }\n\n  return removed;\n};\n\n\n/**\n * Removes a marker and returns true if removed, false if not.\n *\n * @param {google.maps.Marker} marker The marker to remove\n * @return {boolean} Whether the marker was removed or not\n */\nMarkerClusterer.prototype.removeMarker_ = function (marker) {\n  var i;\n  var index = -1;\n  if (this.markers_.indexOf) {\n    index = this.markers_.indexOf(marker);\n  } else {\n    for (i = 0; i < this.markers_.length; i++) {\n      if (marker === this.markers_[i]) {\n        index = i;\n        break;\n      }\n    }\n  }\n\n  if (index === -1) {\n    // Marker is not in our list of markers, so do nothing:\n    return false;\n  }\n\n  marker.setMap(null);\n  this.markers_.splice(index, 1); // Remove the marker from the list of managed markers\n  return true;\n};\n\n\n/**\n * Removes all clusters and markers from the map and also removes all markers\n *  managed by the clusterer.\n */\nMarkerClusterer.prototype.clearMarkers = function () {\n  this.resetViewport_(true);\n  this.markers_ = [];\n};\n\n\n/**\n * Recalculates and redraws all the marker clusters from scratch.\n *  Call this after changing any properties.\n */\nMarkerClusterer.prototype.repaint = function () {\n  var oldClusters = this.clusters_.slice();\n  this.clusters_ = [];\n  this.resetViewport_(false);\n  this.redraw_();\n\n  // Remove the old clusters.\n  // Do it in a timeout to prevent blinking effect.\n  setTimeout(function () {\n    var i;\n    for (i = 0; i < oldClusters.length; i++) {\n      oldClusters[i].remove();\n    }\n  }, 0);\n};\n\n\n/**\n * Returns the current bounds extended by the grid size.\n *\n * @param {google.maps.LatLngBounds} bounds The bounds to extend.\n * @return {google.maps.LatLngBounds} The extended bounds.\n * @ignore\n */\nMarkerClusterer.prototype.getExtendedBounds = function (bounds) {\n  var projection = this.getProjection();\n\n  // Turn the bounds into latlng.\n  var tr = new google.maps.LatLng(bounds.getNorthEast().lat(),\n      bounds.getNorthEast().lng());\n  var bl = new google.maps.LatLng(bounds.getSouthWest().lat(),\n      bounds.getSouthWest().lng());\n\n  // Convert the points to pixels and the extend out by the grid size.\n  var trPix = projection.fromLatLngToDivPixel(tr);\n  trPix.x += this.gridSize_;\n  trPix.y -= this.gridSize_;\n\n  var blPix = projection.fromLatLngToDivPixel(bl);\n  blPix.x -= this.gridSize_;\n  blPix.y += this.gridSize_;\n\n  // Convert the pixel points back to LatLng\n  var ne = projection.fromDivPixelToLatLng(trPix);\n  var sw = projection.fromDivPixelToLatLng(blPix);\n\n  // Extend the bounds to contain the new bounds.\n  bounds.extend(ne);\n  bounds.extend(sw);\n\n  return bounds;\n};\n\n\n/**\n * Redraws all the clusters.\n */\nMarkerClusterer.prototype.redraw_ = function () {\n  this.createClusters_(0);\n};\n\n\n/**\n * Removes all clusters from the map. The markers are also removed from the map\n *  if <code>opt_hide</code> is set to <code>true</code>.\n *\n * @param {boolean} [opt_hide] Set to <code>true</code> to also remove the markers\n *  from the map.\n */\nMarkerClusterer.prototype.resetViewport_ = function (opt_hide) {\n  var i, marker;\n  // Remove all the clusters\n  for (i = 0; i < this.clusters_.length; i++) {\n    this.clusters_[i].remove();\n  }\n  this.clusters_ = [];\n\n  // Reset the markers to not be added and to be removed from the map.\n  for (i = 0; i < this.markers_.length; i++) {\n    marker = this.markers_[i];\n    marker.isAdded = false;\n    if (opt_hide) {\n      marker.setMap(null);\n    }\n  }\n};\n\n\n/**\n * Calculates the distance between two latlng locations in km.\n *\n * @param {google.maps.LatLng} p1 The first lat lng point.\n * @param {google.maps.LatLng} p2 The second lat lng point.\n * @return {number} The distance between the two points in km.\n * @see http://www.movable-type.co.uk/scripts/latlong.html\n*/\nMarkerClusterer.prototype.distanceBetweenPoints_ = function (p1, p2) {\n  var R = 6371; // Radius of the Earth in km\n  var dLat = (p2.lat() - p1.lat()) * Math.PI / 180;\n  var dLon = (p2.lng() - p1.lng()) * Math.PI / 180;\n  var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +\n    Math.cos(p1.lat() * Math.PI / 180) * Math.cos(p2.lat() * Math.PI / 180) *\n    Math.sin(dLon / 2) * Math.sin(dLon / 2);\n  var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));\n  var d = R * c;\n  return d;\n};\n\n\n/**\n * Determines if a marker is contained in a bounds.\n *\n * @param {google.maps.Marker} marker The marker to check.\n * @param {google.maps.LatLngBounds} bounds The bounds to check against.\n * @return {boolean} True if the marker is in the bounds.\n */\nMarkerClusterer.prototype.isMarkerInBounds_ = function (marker, bounds) {\n  return bounds.contains(marker.getPosition());\n};\n\n\n/**\n * Adds a marker to a cluster, or creates a new cluster.\n *\n * @param {google.maps.Marker} marker The marker to add.\n */\nMarkerClusterer.prototype.addToClosestCluster_ = function (marker) {\n  var i, d, cluster, center;\n  var distance = 40000; // Some large number\n  var clusterToAddTo = null;\n  for (i = 0; i < this.clusters_.length; i++) {\n    cluster = this.clusters_[i];\n    center = cluster.getCenter();\n    if (center) {\n      d = this.distanceBetweenPoints_(center, marker.getPosition());\n      if (d < distance) {\n        distance = d;\n        clusterToAddTo = cluster;\n      }\n    }\n  }\n\n  if (clusterToAddTo && clusterToAddTo.isMarkerInClusterBounds(marker)) {\n    clusterToAddTo.addMarker(marker);\n  } else {\n    cluster = new Cluster(this);\n    cluster.addMarker(marker);\n    this.clusters_.push(cluster);\n  }\n};\n\n\n/**\n * Creates the clusters. This is done in batches to avoid timeout errors\n *  in some browsers when there is a huge number of markers.\n *\n * @param {number} iFirst The index of the first marker in the batch of\n *  markers to be added to clusters.\n */\nMarkerClusterer.prototype.createClusters_ = function (iFirst) {\n  var i, marker;\n  var mapBounds;\n  var cMarkerClusterer = this;\n  if (!this.ready_) {\n    return;\n  }\n\n  // Cancel previous batch processing if we're working on the first batch:\n  if (iFirst === 0) {\n    /**\n     * This event is fired when the <code>MarkerClusterer</code> begins\n     *  clustering markers.\n     * @name MarkerClusterer#clusteringbegin\n     * @param {MarkerClusterer} mc The MarkerClusterer whose markers are being clustered.\n     * @event\n     */\n    google.maps.event.trigger(this, \"clusteringbegin\", this);\n\n    if (typeof this.timerRefStatic !== \"undefined\") {\n      clearTimeout(this.timerRefStatic);\n      delete this.timerRefStatic;\n    }\n  }\n\n  // Get our current map view bounds.\n  // Create a new bounds object so we don't affect the map.\n  //\n  // See Comments 9 & 11 on Issue 3651 relating to this workaround for a Google Maps bug:\n  if (this.getMap().getZoom() > 3) {\n    mapBounds = new google.maps.LatLngBounds(this.getMap().getBounds().getSouthWest(),\n      this.getMap().getBounds().getNorthEast());\n  } else {\n    mapBounds = new google.maps.LatLngBounds(new google.maps.LatLng(85.02070771743472, -178.48388434375), new google.maps.LatLng(-85.08136444384544, 178.00048865625));\n  }\n  var bounds = this.getExtendedBounds(mapBounds);\n\n  var iLast = Math.min(iFirst + this.batchSize_, this.markers_.length);\n\n  for (i = iFirst; i < iLast; i++) {\n    marker = this.markers_[i];\n    if (!marker.isAdded && this.isMarkerInBounds_(marker, bounds)) {\n      if (!this.ignoreHidden_ || (this.ignoreHidden_ && marker.getVisible())) {\n        this.addToClosestCluster_(marker);\n      }\n    }\n  }\n\n  if (iLast < this.markers_.length) {\n    this.timerRefStatic = setTimeout(function () {\n      cMarkerClusterer.createClusters_(iLast);\n    }, 0);\n  } else {\n    delete this.timerRefStatic;\n\n    /**\n     * This event is fired when the <code>MarkerClusterer</code> stops\n     *  clustering markers.\n     * @name MarkerClusterer#clusteringend\n     * @param {MarkerClusterer} mc The MarkerClusterer whose markers are being clustered.\n     * @event\n     */\n    google.maps.event.trigger(this, \"clusteringend\", this);\n  }\n};\n\n\n/**\n * Extends an object's prototype by another's.\n *\n * @param {Object} obj1 The object to be extended.\n * @param {Object} obj2 The object to extend with.\n * @return {Object} The new extended object.\n * @ignore\n */\nMarkerClusterer.prototype.extend = function (obj1, obj2) {\n  return (function (object) {\n    var property;\n    for (property in object.prototype) {\n      this.prototype[property] = object.prototype[property];\n    }\n    return this;\n  }).apply(obj1, [obj2]);\n};\n\n\n/**\n * The default function for determining the label text and style\n * for a cluster icon.\n *\n * @param {Array.<google.maps.Marker>} markers The array of markers represented by the cluster.\n * @param {number} numStyles The number of marker styles available.\n * @return {ClusterIconInfo} The information resource for the cluster.\n * @constant\n * @ignore\n */\nMarkerClusterer.CALCULATOR = function (markers, numStyles) {\n  var index = 0;\n  var title = \"\";\n  var count = markers.length.toString();\n\n  var dv = count;\n  while (dv !== 0) {\n    dv = parseInt(dv / 10, 10);\n    index++;\n  }\n\n  index = Math.min(index, numStyles);\n  return {\n    text: count,\n    index: index,\n    title: title\n  };\n};\n\n\n/**\n * The number of markers to process in one batch.\n *\n * @type {number}\n * @constant\n */\nMarkerClusterer.BATCH_SIZE = 2000;\n\n\n/**\n * The number of markers to process in one batch (IE only).\n *\n * @type {number}\n * @constant\n */\nMarkerClusterer.BATCH_SIZE_IE = 500;\n\n\n/**\n * The default root name for the marker cluster images.\n *\n * @type {string}\n * @constant\n */\nMarkerClusterer.IMAGE_PATH = \"../images/m\";\n\n\n/**\n * The default extension name for the marker cluster images.\n *\n * @type {string}\n * @constant\n */\nMarkerClusterer.IMAGE_EXTENSION = \"png\";\n\n\n/**\n * The default array of sizes for the marker cluster images.\n *\n * @type {Array.<number>}\n * @constant\n */\nMarkerClusterer.IMAGE_SIZES = [53, 56, 66, 78, 90];\n"]}