{"id":2146,"date":"2026-05-29T05:05:44","date_gmt":"2026-05-29T05:05:44","guid":{"rendered":"https:\/\/blq.dev.techademics.tech\/explorar-el-distrito\/directorio-de-negocios\/"},"modified":"2026-07-27T12:48:11","modified_gmt":"2026-07-27T12:48:11","slug":"directorio-de-negocios","status":"publish","type":"page","link":"https:\/\/blq.dev.techademics.tech\/es\/explorar-el-distrito\/directorio-de-negocios\/","title":{"rendered":"Directorio de Negocios"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"2146\" class=\"elementor elementor-2146 elementor-1619\" data-elementor-post-type=\"page\">\n\t\t\t\t<div class=\"elementor-element elementor-element-2a8005c e-con-full quarter-section e-flex e-con e-parent\" data-id=\"2a8005c\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-aafce06 e-con-full quarter-left-box e-flex e-con e-child\" data-id=\"aafce06\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-e6e886c nanum-pen elementor-widget-mobile__width-initial elementor-widget elementor-widget-heading\" data-id=\"e6e886c\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">DIRECTORIO DE NEGOCIOS<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-08108e8 porter-font elementor-widget elementor-widget-heading\" data-id=\"08108e8\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Directorio de Negocios<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-4cf64d4 elementor-widget__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"4cf64d4\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t\t\t\t\t\t<p><span style=\"font-weight: 400;\">Encuentre negocios locales en el Barrio Latino de Boston.<\/span><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-fbc3949 e-con-full quarter-right-box e-flex e-con e-child\" data-id=\"fbc3949\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-8f84dd1 elementor-align-justify movement-button elementor-widget elementor-widget-button\" data-id=\"8f84dd1\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"button.default\">\n\t\t\t\t\t\t\t\t\t\t<a class=\"elementor-button elementor-button-link elementor-size-sm\" href=\"https:\/\/blq.dev.techademics.tech\/es\/eventos\/\">\n\t\t\t\t\t\t<span class=\"elementor-button-content-wrapper\">\n\t\t\t\t\t\t<span class=\"elementor-button-icon\">\n\t\t\t\t<svg aria-hidden=\"true\" class=\"e-font-icon-svg e-fas-arrow-right\" viewBox=\"0 0 448 512\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\"><path d=\"M190.5 66.9l22.2-22.2c9.4-9.4 24.6-9.4 33.9 0L441 239c9.4 9.4 9.4 24.6 0 33.9L246.6 467.3c-9.4 9.4-24.6 9.4-33.9 0l-22.2-22.2c-9.5-9.5-9.3-25 .4-34.3L311.4 296H24c-13.3 0-24-10.7-24-24v-32c0-13.3 10.7-24 24-24h287.4L190.9 101.2c-9.8-9.3-10-24.8-.4-34.3z\"><\/path><\/svg>\t\t\t<\/span>\n\t\t\t\t\t\t\t\t\t<span class=\"elementor-button-text\">Explorar eventos<\/span>\n\t\t\t\t\t<\/span>\n\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-163330a e-con-full e-flex e-con e-parent\" data-id=\"163330a\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-759b9c7 elementor-widget elementor-widget-html\" data-id=\"759b9c7\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t\t<!--\n  Copyright 2023 Google LLC\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      https:\/\/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    <title>Barrio Latino de Boston<\/title>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">\n    <script src=\"https:\/\/ajax.googleapis.com\/ajax\/libs\/handlebars\/4.7.7\/handlebars.min.js\"><\/script>\n    <link href=\"https:\/\/fonts.googleapis.com\/css?family=Roboto\" rel=\"stylesheet\">\n    <link href=\"https:\/\/fonts.googleapis.com\/icon?family=Material+Icons\" rel=\"stylesheet\">\n    <style>\n      html, body {\n        height: 100%;\n        margin: 0;\n        padding: 0;\n      }\n\n      .neighborhood-discovery {\n        box-sizing: border-box;\n        font-family: \"Roboto\", sans-serif;\n        height: 100%;\n        min-height: 1000px;\n        position: relative;\n        width: 100%;\n      }\n\n      .neighborhood-discovery a {\n        color: #4285f4;\n        text-decoration: none;\n      }\n\n      .neighborhood-discovery button {\n        background: none;\n        border: none;\n        color: inherit;\n        cursor: pointer;\n        font: inherit;\n        font-size: inherit;\n        padding: 0;\n      }\n\n      .neighborhood-discovery .info {\n        color: #555;\n        font-size: 0.9em;\n        margin-top: 0.3em;\n      }\n\n      .neighborhood-discovery .panel {\n        background: white;\n        bottom: 0;\n        box-sizing: border-box;\n        left: 0;\n        overflow-y: auto;\n        position: absolute;\n        top: 0;\n        width: 20em;\n      }\n\n      .neighborhood-discovery .panel.no-scroll {\n        overflow-y: hidden;\n      }\n\n      .neighborhood-discovery .photo {\n        background-color: #dadce0;\n        background-position: center;\n        background-size: cover;\n        border-radius: 0.3em;\n        cursor: pointer;\n      }\n\n      .neighborhood-discovery .navbar {\n        background: white;\n        position: sticky;\n        top: 0;\n        z-index: 2;\n      }\n\n      .neighborhood-discovery .right {\n        float: right;\n      }\n\n      .neighborhood-discovery .map {\n        bottom: 0;\n        left: 20em;\n        position: absolute;\n        right: 0;\n        top: 0;\n      }\n\n      @media only screen and (max-width: 640px) {\n        .neighborhood-discovery .panel {\n          right: 0;\n          top: 50%;\n          width: unset;\n        }\n\n        .neighborhood-discovery .map {\n          bottom: 50%;\n          left: 0;\n        }\n      }\n\n      \/* --------------------------- PLACES PANEL --------------------------- *\/\n\n      .neighborhood-discovery .places-panel {\n        box-shadow: 0 0 10px rgb(60 64 67 \/ 28%);\n        z-index: 1;\n      }\n\n      .neighborhood-discovery .places-panel header {\n        padding: 0.5em;\n      }\n\n      .neighborhood-discovery .layer-section + .layer-section {\n        border-top: 1px solid rgba(0, 0, 0, 0.12);\n      }\n\n      .neighborhood-discovery .layer-heading {\n        align-items: center;\n        background: white;\n        border: none;\n        box-sizing: border-box;\n        color: #555;\n        cursor: pointer;\n        display: flex;\n        font: inherit;\n        font-size: 0.85em;\n        font-weight: 500;\n        justify-content: space-between;\n        letter-spacing: 0.04em;\n        margin: 0;\n        padding: 0.6em 0.8em;\n        text-transform: uppercase;\n        width: 100%;\n      }\n\n      .neighborhood-discovery .layer-heading:hover {\n        background: #f8f9fa;\n      }\n\n      .neighborhood-discovery .layer-heading .layer-chevron {\n        flex-shrink: 0;\n        height: 1.2em;\n        transition: transform 0.2s ease;\n        width: 1.2em;\n      }\n\n      .neighborhood-discovery .layer-section.collapsed .layer-heading .layer-chevron {\n        transform: rotate(-90deg);\n      }\n\n      .neighborhood-discovery .layer-content {\n        display: block;\n      }\n\n      .neighborhood-discovery .layer-section.collapsed .layer-content {\n        display: none;\n      }\n\n      .neighborhood-discovery .layer-heading-label {\n        align-items: center;\n        display: flex;\n        gap: 0.5em;\n      }\n\n      .neighborhood-discovery .layer-color-swatch {\n        border: 2px solid;\n        border-radius: 50%;\n        flex-shrink: 0;\n        height: 0.65em;\n        width: 0.65em;\n      }\n\n      .neighborhood-discovery .search-input input {\n        border: 1px solid rgba(0, 0, 0, 0.2);\n        border-radius: 0.3em;\n        box-sizing: border-box;\n        font-size: 1em;\n        height: 2.2em;\n        padding: 0 2.5em 0 1em;\n        width: 100%;\n      }\n\n      .neighborhood-discovery .search-input button {\n        position: absolute;\n        right: 0.8em;\n        top: 0.8em;\n      }\n\n      .neighborhood-discovery .show-more-button {\n        bottom: 0.5em;\n        display: none;\n        left: 28%;\n        line-height: 1.5em;\n        padding: 0.6em;\n        position: relative;\n        width: 44%;\n      }\n\n      .neighborhood-discovery .show-more-button.sticky {\n        background: white;\n        border-radius: 1.5em;\n        box-shadow: 0 4px 10px rgb(60 64 67 \/ 28%);\n        position: sticky;\n        z-index: 2;\n      }\n\n      .neighborhood-discovery .show-more-button:disabled {\n        opacity: 0.5;\n      }\n\n      .neighborhood-discovery .place-results-list {\n        list-style-type: none;\n        margin: 0;\n        padding: 0;\n      }\n\n      .neighborhood-discovery .place-result {\n        border-top: 1px solid rgba(0, 0, 0, 0.12);\n        cursor: pointer;\n        display: flex;\n        padding: 0.8em;\n      }\n\n      .neighborhood-discovery .place-result .text {\n        flex-grow: 1;\n      }\n\n      .neighborhood-discovery .place-result .name {\n        font-size: 1em;\n        font-weight: 500;\n        text-align: left;\n      }\n\n      .neighborhood-discovery .place-result .photo {\n        flex: 0 0 4em;\n        height: 4em;\n        margin-left: 0.8em;\n      }\n\n      \/* -------------------------- DETAILS PANEL --------------------------- *\/\n\n      .neighborhood-discovery .details-panel {\n        display: none;\n        z-index: 20;\n      }\n\n      .neighborhood-discovery .details-panel .back-button {\n        color: #4285f4;\n        padding: 0.9em;\n      }\n\n      .neighborhood-discovery .details-panel .back-button .icon {\n        \/* Match link color #4285f4 *\/\n        filter: invert(47%) sepia(71%) saturate(2372%) hue-rotate(200deg) brightness(97%) contrast(98%);\n        height: 1.2em;\n        width: 1.2em;\n        vertical-align: bottom;\n      }\n\n      .neighborhood-discovery .details-panel header {\n        padding: 0.9em;\n      }\n\n      .neighborhood-discovery .details-panel h2 {\n        font-size: 1.4em;\n        font-weight: 400;\n        margin: 0;\n      }\n\n      .neighborhood-discovery .details-panel .section {\n        border-top: 1px solid rgba(0, 0, 0, 0.12);\n        padding: 0.9em;\n      }\n\n      .neighborhood-discovery .details-panel .contact {\n        align-items: center;\n        display: flex;\n        font-size: 0.9em;\n        margin: 0.8em 0;\n      }\n\n      .neighborhood-discovery .details-panel .contact .icon {\n        width: 1.5em;\n        height: 1.5em;\n      }\n\n      .neighborhood-discovery .details-panel .contact .text {\n        margin-left: 1em;\n      }\n\n      .neighborhood-discovery .details-panel .contact .weekday {\n        display: inline-block;\n        width: 5em;\n      }\n\n      .neighborhood-discovery .details-panel .photos {\n        text-align: center;\n        padding: 0;\n      }\n\n      .neighborhood-discovery .details-panel .photo {\n        border-radius: 0;\n        height: 0;\n        margin-bottom: 0.3em;\n        padding-top: 100%;\n        width: 100%;\n      }\n\n      .neighborhood-discovery .details-panel .attribution {\n        color: #777;\n        margin: 0;\n        font-size: 0.8em;\n        font-style: italic;\n      }\n\n      \/* --------------------------- PHOTO MODAL ---------------------------- *\/\n\n      .neighborhood-discovery .photo-modal {\n        background: rgba(0, 0, 0, 0.8);\n        display: none;\n        height: 100%;\n        position: fixed;\n        width: 100%;\n        z-index: 100;\n      }\n\n      .neighborhood-discovery .photo-modal > img {\n        bottom: 0;\n        left: 0;\n        margin: auto;\n        max-height: 100%;\n        max-width: 100%;\n        position: absolute;\n        right: 0;\n        top: 0;\n      }\n\n      .neighborhood-discovery .photo-modal > div {\n        border-radius: 0.4em;\n        color: white;\n        background: rgba(0, 0, 0, 0.6);\n        margin: 1em;\n        padding: 0.9em;\n        position: absolute;\n      }\n\n      .neighborhood-discovery .photo-modal .back-button .icon {\n        filter: brightness(0) invert(1);\n        margin: 0.4em 0.6em 0 0;\n      }\n\n      .neighborhood-discovery .photo-modal .photo-text {\n        float: right;\n      }\n\n      .neighborhood-discovery .photo-modal .photo-attrs {\n        font-size: 0.8em;\n        margin-top: 0.3em;\n      }\n    <\/style>\n    <script>\n      'use strict';\n\n      \/** Hides a DOM element and optionally focuses on focusEl. *\/\n      function hideElement(el, focusEl) {\n        el.style.display = 'none';\n        if (focusEl) focusEl.focus();\n      }\n\n      \/** Shows a DOM element that has been hidden and optionally focuses on focusEl. *\/\n      function showElement(el, focusEl) {\n        el.style.display = 'block';\n        if (focusEl) focusEl.focus();\n      }\n\n      \/** Determines if a DOM element contains content that cannot be scrolled into view. *\/\n      function hasHiddenContent(el) {\n        const noscroll = window.getComputedStyle(el).overflowY.includes('hidden');\n        return noscroll && el.scrollHeight > el.clientHeight;\n      }\n\n      \/** Format a Place Type string by capitalizing and replacing underscores with spaces. *\/\n      function formatPlaceType(str) {\n        const capitalized = str.charAt(0).toUpperCase() + str.slice(1);\n        return capitalized.replace(\/_\/g, ' ');\n      }\n\n      \/**\n       * Constructs an array of opening hours by day from a PlaceOpeningHours object,\n       * where adjacent days of week with the same hours are collapsed into one element.\n       *\/\n      function parseDaysHours(openingHours) {\n        const daysHours = openingHours.weekday_text.map((e) => e.split(\/\\:\\s+\/))\n                  .map((e) => ({'days': e[0].substr(0, 3), 'hours': e[1]}));\n\n        for (let i = 1; i < daysHours.length; i++) {\n          if (daysHours[i - 1].hours === daysHours[i].hours) {\n            if (daysHours[i - 1].days.indexOf('-') !== -1) {\n              daysHours[i - 1].days =\n                  daysHours[i - 1].days.replace(\/\\w+$\/, daysHours[i].days);\n            } else {\n              daysHours[i - 1].days += ' - ' + daysHours[i].days;\n            }\n            daysHours.splice(i--, 1);\n          }\n        }\n        return daysHours;\n      }\n\n      \/** Number of POIs to show on widget load. *\/\n      const ND_NUM_PLACES_INITIAL = 5;\n\n      \/** Number of additional POIs to show when 'Show More' button is clicked. *\/\n      const ND_NUM_PLACES_SHOW_MORE = 5;\n\n      \/** Maximum number of place photos to show on the details panel. *\/\n      const ND_NUM_PLACE_PHOTOS_MAX = 6;\n\n      \/** Minimum zoom level at which the default map POI pins will be shown. *\/\n      const ND_DEFAULT_POI_MIN_ZOOM = 18;\n\n      \/** Marker pin colors by layer name (fill and stroke). *\/\n      const ND_LAYER_COLORS = {\n        'Local Businesses': {fill: '#EA4335', stroke: '#C5221F'},\n        'Housing': {fill: '#4285F4', stroke: '#1967D2'},\n        'Public Resources': {fill: '#34A853', stroke: '#137333'},\n        'Cultural Organizations': {fill: '#9334E6', stroke: '#7627BB'},\n        'Non Profits': {fill: '#F9AB00', stroke: '#E37400'},\n        '_default': {fill: '#5F6368', stroke: '#3C4043'},\n      };\n\n      \/** Returns marker colors for a layer, using config overrides when set. *\/\n      function getLayerColors(layer) {\n        if (layer.markerColor) {\n          return {\n            fill: layer.markerColor,\n            stroke: layer.markerStrokeColor || layer.markerColor,\n          };\n        }\n        return ND_LAYER_COLORS[layer.name] || ND_LAYER_COLORS._default;\n      }\n\n      \/** Creates a small color swatch matching a layer's marker pin. *\/\n      function createLayerColorSwatch(fillColor, strokeColor) {\n        const swatch = document.createElement('span');\n        swatch.className = 'layer-color-swatch';\n        swatch.style.backgroundColor = fillColor;\n        swatch.style.borderColor = strokeColor;\n        swatch.setAttribute('aria-hidden', 'true');\n        return swatch;\n      }\n\n      \/** Mapping of Place Types to Material Icons used to render custom map markers. *\/\n      const ND_MARKER_ICONS_BY_TYPE = {\n        \/\/ Full list of icons can be found at https:\/\/fonts.google.com\/icons\n        '_default': 'circle',\n        'restaurant': 'restaurant',\n        'cafe': 'local_cafe',\n        'museum': 'museum',\n        'book_store': 'local_mall',\n        'jewelry_store': 'local_mall',\n        'home_goods_store': 'local_mall',\n      };\n\n      \/**\n       * Defines an instance of the Neighborhood Discovery widget, to be\n       * instantiated when the Maps library is loaded.\n       *\/\n      function NeighborhoodDiscovery(configuration) {\n        const widget = this;\n        const widgetEl = document.querySelector('.neighborhood-discovery');\n\n        widget.center = configuration.mapOptions.center;\n        widget.layers = configuration.layers || [];\n        widget.places = widget.layers.flatMap((layer) =>\n          (layer.pois || []).map((poi, index) => Object.assign({}, poi, {\n            layerName: layer.name,\n            poiId: layer.name + '::' + index,\n          }))\n        );\n        widget.markerLayers = new Map();\n        for (const layer of widget.layers) {\n          const colors = getLayerColors(layer);\n          widget.markerLayers.set(layer.name, {\n            visible: true,\n            markers: [],\n            fillColor: colors.fill,\n            strokeColor: colors.stroke,\n          });\n        }\n        const placeIdsToDetails = new Map();\n\n        \/\/ Initialize core functionalities -------------------------------------\n\n        initializeMap();\n        initializePlaceDetails();\n        resolvePlaceIds(() => {\n          initializeSidePanel();\n          initializeSearchInput();\n        });\n\n        \/\/ Initializer function definitions ------------------------------------\n\n        \/** Initializes the interactive map and adds place markers. *\/\n        function initializeMap() {\n          const mapOptions = configuration.mapOptions;\n          if (configuration.boundaryPoints.length > 0) {\n            widget.mapBounds = new google.maps.LatLngBounds();\n            for (const pt of configuration.boundaryPoints) {\n              widget.mapBounds.extend(pt);\n            }\n          } else {\n            widget.mapBounds = new google.maps.Circle(\n              {center: widget.center, radius: configuration.mapRadius}).getBounds();\n          }\n          mapOptions.restriction = {latLngBounds: widget.mapBounds};\n          mapOptions.mapTypeControlOptions = {position: google.maps.ControlPosition.TOP_RIGHT};\n          widget.map = new google.maps.Map(widgetEl.querySelector('.map'), mapOptions);\n          widget.map.fitBounds(widget.mapBounds, \/* padding= *\/ 0);\n          widget.map.addListener('click', (e) => {\n            \/\/ Check if user clicks on a POI pin from the base map.\n            if (e.placeId) {\n              e.stop();\n              widget.selectPlaceById(e.placeId);\n            }\n          });\n          widget.map.addListener('zoom_changed', () => {\n            \/\/ Customize map styling to show\/hide default POI pins or text based on zoom level.\n            const hideDefaultPoiPins = widget.map.getZoom() < ND_DEFAULT_POI_MIN_ZOOM;\n            widget.map.setOptions({\n              styles: [{\n                featureType: 'poi',\n                elementType: hideDefaultPoiPins ? 'labels' : 'labels.text',\n                stylers: [{visibility: 'off'}],\n              }],\n            });\n          });\n\n          \/\/ Add neighborhood boundary as a Data Layer Polygon (if specified).\n          if (configuration.boundaryPoints.length > 0) {\n            \/\/ Darken map areas outside the boundary.\n            const shadingLayer = [\n              new google.maps.LatLng(-90, -180),\n              new google.maps.LatLng(90, -180),\n              new google.maps.LatLng(90, 180),\n              new google.maps.LatLng(-90, 180),\n              new google.maps.LatLng(-90, 0)\n            ];\n            widget.map.data.add({\n              geometry: new google.maps.Data.Polygon([\n                shadingLayer,\n                configuration.boundaryPoints,\n              ]),\n            });\n            widget.map.data.setStyle({\n              clickable: false,\n              fillColor: '#c4c4c4',\n              strokeColor: '#ea4335',\n              strokeWeight: 3,\n            });\n          }\n\n          const markerPath = widgetEl.querySelector('.marker-pin path').getAttribute('d');\n          const drawMarker = function(title, position, fillColor, strokeColor, labelText, layerName) {\n            const layer = widget.markerLayers.get(layerName);\n            return new google.maps.Marker({\n              title: title,\n              position: position,\n              map: layer?.visible ? widget.map : null,\n              icon: {\n                path: markerPath,\n                fillColor: fillColor,\n                fillOpacity: 1,\n                strokeColor: strokeColor,\n                anchor: new google.maps.Point(13, 35),\n                labelOrigin: new google.maps.Point(13, 13),\n              },\n              label: {\n                text: labelText,\n                color: 'white',\n                fontSize: '16px',\n                fontFamily: 'Material Icons',\n              },\n            });\n          };\n\n          widget.setLayerVisible = function(layerName, visible) {\n            const layer = widget.markerLayers.get(layerName);\n            if (!layer) return;\n            layer.visible = visible;\n            for (const marker of layer.markers) {\n              marker.setMap(visible ? widget.map : null);\n            }\n          };\n\n          \/\/ Add marker for the specified Place object.\n          widget.addPlaceMarker = function(place) {\n            const layerName = place.layerName || 'Local Businesses';\n            const layer = widget.markerLayers.get(layerName);\n            const fillColor = layer?.fillColor || ND_LAYER_COLORS._default.fill;\n            const strokeColor = layer?.strokeColor || ND_LAYER_COLORS._default.stroke;\n            place.marker = drawMarker(\n              place.name, place.coords, fillColor, strokeColor, place.icon, layerName);\n            place.marker.addListener('click', () => void widget.selectPlace(place.poiId));\n            if (layer) layer.markers.push(place.marker);\n          };\n\n          \/\/ Fit map to bounds that contain all markers of the specified Place objects.\n          widget.updateBounds = function(places) {\n            const bounds = new google.maps.LatLngBounds();\n            bounds.extend(widget.center);\n            for (let place of places) {\n              bounds.extend(place.marker.getPosition());\n            }\n            widget.map.fitBounds(bounds, \/* padding= *\/ 100);\n          };\n\n          \/\/ Marker used to highlight a place from Autocomplete search.\n          widget.selectedPlaceMarker = new google.maps.Marker({title: 'Point of Interest'});\n        }\n\n        \/** Resolves Google Place IDs for POIs defined with name and coordinates. *\/\n        function resolvePlaceIds(done) {\n          const lookupService = new google.maps.places.PlacesService(widget.map);\n          const unresolved = widget.places.filter((place) => !place.placeId);\n          if (unresolved.length === 0) {\n            registerPlaces();\n            done();\n            return;\n          }\n\n          let remaining = unresolved.length;\n          for (const place of unresolved) {\n            const center = new google.maps.LatLng(place.coords.lat, place.coords.lng);\n            lookupService.findPlaceFromQuery({\n              query: place.name,\n              fields: ['place_id'],\n              locationBias: {center, radius: 100},\n            }, (results, status) => {\n              if (status === google.maps.places.PlacesServiceStatus.OK && results?.[0]?.place_id) {\n                place.placeId = results[0].place_id;\n              } else {\n                place.placeId = 'kml-' + place.name.replace(\/\\s+\/g, '-').toLowerCase();\n                place.coords = center;\n                place.icon = ND_MARKER_ICONS_BY_TYPE['_default'];\n                place.type = 'Business';\n              }\n              if (--remaining === 0) {\n                registerPlaces();\n                done();\n              }\n            });\n          }\n        }\n\n        \/** Registers POI objects for place detail lookups. *\/\n        function registerPlaces() {\n          for (const place of widget.places) {\n            if (place.coords && !(place.coords instanceof google.maps.LatLng)) {\n              place.coords = new google.maps.LatLng(place.coords.lat, place.coords.lng);\n            }\n            place.fetchedFields = new Set(['place_id']);\n            if (place.name) place.fetchedFields.add('name');\n            if (place.coords) place.fetchedFields.add('geometry.location');\n            if (place.type) place.fetchedFields.add('types');\n            if (place.icon) place.fetchedFields.add('types');\n            placeIdsToDetails.set(place.poiId, place);\n          }\n        }\n\n        \/** Initializes Place Details service for the widget. *\/\n        function initializePlaceDetails() {\n          const detailsService = new google.maps.places.PlacesService(widget.map);\n\n          widget.fetchPlaceDetails = function(poiId, fields, callback) {\n            if (!poiId || !fields) return;\n\n            let place = placeIdsToDetails.get(poiId);\n            if (!place) return;\n            if (place.placeId.startsWith('kml-')) {\n              callback(place);\n              return;\n            }\n            const missingFields = fields.filter((field) => !place.fetchedFields.has(field));\n            if (missingFields.length === 0) {\n              callback(place);\n              return;\n            }\n\n            const request = {placeId: place.placeId, fields: missingFields};\n            let retryCount = 0;\n            const processResult = function(result, status) {\n              if (status !== google.maps.places.PlacesServiceStatus.OK) {\n                \/\/ If query limit has been reached, wait before making another call;\n                \/\/ Increase wait time of each successive retry with exponential backoff\n                \/\/ and terminate after five failed attempts.\n                if (status === google.maps.places.PlacesServiceStatus.OVER_QUERY_LIMIT &&\n                    retryCount < 5) {\n                  const delay = (Math.pow(2, retryCount) + Math.random()) * 500;\n                  setTimeout(() => void detailsService.getDetails(request, processResult), delay);\n                  retryCount++;\n                }\n                return;\n              }\n\n              \/\/ Basic details.\n              if (missingFields.includes('name') && result.name) place.name = result.name;\n              if (missingFields.includes('geometry.location') && result.geometry) {\n                place.coords = result.geometry.location;\n              }\n              if (result.formatted_address) place.address = result.formatted_address;\n              if (result.photos) {\n                place.photos = result.photos.map((photo) => ({\n                  urlSmall: photo.getUrl({maxWidth: 200, maxHeight: 200}),\n                  urlLarge: photo.getUrl({maxWidth: 1200, maxHeight: 1200}),\n                  attrs: photo.html_attributions,\n                })).slice(0, ND_NUM_PLACE_PHOTOS_MAX);\n              }\n              if (result.types) {\n                place.type = formatPlaceType(result.types[0]);\n                place.icon = ND_MARKER_ICONS_BY_TYPE['_default'];\n                for (let type of result.types) {\n                  if (type in ND_MARKER_ICONS_BY_TYPE) {\n                    place.type = formatPlaceType(type);\n                    place.icon = ND_MARKER_ICONS_BY_TYPE[type];\n                    break;\n                  }\n                }\n              }\n              if (result.url) place.url = result.url;\n\n              \/\/ Contact details.\n              if (result.website) {\n                place.website = result.website;\n                const url = new URL(place.website);\n                place.websiteDomain = url.hostname;\n              }\n              if (result.formatted_phone_number) place.phoneNumber = result.formatted_phone_number;\n              if (result.opening_hours) place.openingHours = parseDaysHours(result.opening_hours);\n\n              for (let field of missingFields) {\n                place.fetchedFields.add(field);\n              }\n              callback(place);\n            };\n\n            \/\/ Use result from Place Autocomplete if available.\n            if (widget.placeIdsToAutocompleteResults) {\n              const autoCompleteResult = widget.placeIdsToAutocompleteResults.get(place.placeId);\n              if (autoCompleteResult) {\n                processResult(autoCompleteResult, google.maps.places.PlacesServiceStatus.OK);\n                return;\n              }\n            }\n            detailsService.getDetails(request, processResult);\n          };\n\n          widget.fetchPlaceDetailsByGoogleId = function(placeId, fields, callback) {\n            if (!placeId || !fields) return;\n            const poiId = 'google::' + placeId;\n            let place = placeIdsToDetails.get(poiId);\n            if (!place) {\n              place = {placeId: placeId, poiId: poiId, fetchedFields: new Set(['place_id'])};\n              placeIdsToDetails.set(poiId, place);\n            }\n            const missingFields = fields.filter((field) => !place.fetchedFields.has(field));\n            if (missingFields.length === 0) {\n              callback(place);\n              return;\n            }\n            const request = {placeId: placeId, fields: missingFields};\n            detailsService.getDetails(request, (result, status) => {\n              if (status !== google.maps.places.PlacesServiceStatus.OK) return;\n              if (result.name) place.name = result.name;\n              if (result.geometry) place.coords = result.geometry.location;\n              if (result.formatted_address) place.address = result.formatted_address;\n              if (result.photos) {\n                place.photos = result.photos.map((photo) => ({\n                  urlSmall: photo.getUrl({maxWidth: 200, maxHeight: 200}),\n                  urlLarge: photo.getUrl({maxWidth: 1200, maxHeight: 1200}),\n                  attrs: photo.html_attributions,\n                })).slice(0, ND_NUM_PLACE_PHOTOS_MAX);\n              }\n              if (result.types) {\n                place.type = formatPlaceType(result.types[0]);\n                place.icon = ND_MARKER_ICONS_BY_TYPE['_default'];\n                for (let type of result.types) {\n                  if (type in ND_MARKER_ICONS_BY_TYPE) {\n                    place.type = formatPlaceType(type);\n                    place.icon = ND_MARKER_ICONS_BY_TYPE[type];\n                    break;\n                  }\n                }\n              }\n              if (result.url) place.url = result.url;\n              if (result.website) {\n                place.website = result.website;\n                place.websiteDomain = new URL(place.website).hostname;\n              }\n              if (result.formatted_phone_number) place.phoneNumber = result.formatted_phone_number;\n              if (result.opening_hours) place.openingHours = parseDaysHours(result.opening_hours);\n              for (let field of missingFields) place.fetchedFields.add(field);\n              callback(place);\n            });\n          };\n        }\n\n        \/** Initializes the side panel that holds curated POI results. *\/\n        function initializeSidePanel() {\n          const placesPanelEl = widgetEl.querySelector('.places-panel');\n          const detailsPanelEl = widgetEl.querySelector('.details-panel');\n          const resultsContainerEl = widgetEl.querySelector('.results');\n          const showMoreButtonEl = widgetEl.querySelector('.show-more-button');\n          const photoModalEl = widgetEl.querySelector('.photo-modal');\n          const detailsTemplate = Handlebars.compile(\n              document.getElementById('nd-place-details-tmpl').innerHTML);\n          const resultsTemplate = Handlebars.compile(\n              document.getElementById('nd-place-results-tmpl').innerHTML);\n\n          \/\/ Show specified POI photo in a modal.\n          const showPhotoModal = function(photo, placeName) {\n            const prevFocusEl = document.activeElement;\n            const imgEl = photoModalEl.querySelector('img');\n            imgEl.src = photo.urlLarge;\n            const backButtonEl = photoModalEl.querySelector('.back-button');\n            backButtonEl.addEventListener('click', () => {\n              hideElement(photoModalEl, prevFocusEl);\n              imgEl.src = '';\n            });\n            photoModalEl.querySelector('.photo-place').innerHTML = placeName;\n            photoModalEl.querySelector('.photo-attrs span').innerHTML = photo.attrs;\n            const attributionEl = photoModalEl.querySelector('.photo-attrs a');\n            if (attributionEl) attributionEl.setAttribute('target', '_blank');\n            photoModalEl.addEventListener('click', (e) => {\n              if (e.target === photoModalEl) {\n                hideElement(photoModalEl, prevFocusEl);\n                imgEl.src = '';\n              }\n            });\n            showElement(photoModalEl, backButtonEl);\n          };\n\n          let selectedPoiId;\n          widget.selectPlace = function(poiId, panToMarker) {\n            if (selectedPoiId === poiId) return;\n            selectedPoiId = poiId;\n            const prevFocusEl = document.activeElement;\n\n            const showDetailsPanel = function(place) {\n              detailsPanelEl.innerHTML = detailsTemplate(place);\n              const backButtonEl = detailsPanelEl.querySelector('.back-button');\n              backButtonEl.addEventListener('click', () => {\n                hideElement(detailsPanelEl, prevFocusEl);\n                selectedPoiId = undefined;\n                widget.selectedPlaceMarker.setMap(null);\n              });\n              detailsPanelEl.querySelectorAll('.photo').forEach((photoEl, i) => {\n                photoEl.addEventListener('click', () => {\n                  showPhotoModal(place.photos[i], place.name);\n                });\n              });\n              showElement(detailsPanelEl, backButtonEl);\n              detailsPanelEl.scrollTop = 0;\n            };\n\n            const processResult = function(place) {\n              if (place.marker) {\n                widget.selectedPlaceMarker.setMap(null);\n              } else {\n                widget.selectedPlaceMarker.setPosition(place.coords);\n                widget.selectedPlaceMarker.setMap(widget.map);\n              }\n              if (panToMarker) {\n                widget.map.panTo(place.coords);\n              }\n              showDetailsPanel(place);\n            };\n\n            widget.fetchPlaceDetails(poiId, [\n              'name', 'types', 'geometry.location', 'formatted_address', 'photo', 'url',\n              'website', 'formatted_phone_number', 'opening_hours',\n            ], processResult);\n          };\n\n          \/\/ Select a place by Google Place ID (autocomplete \/ map POI clicks).\n          widget.selectPlaceById = function(placeId, panToMarker) {\n            const configuredPlace = widget.places.find((place) => place.placeId === placeId);\n            if (configuredPlace) {\n              widget.selectPlace(configuredPlace.poiId, panToMarker);\n              return;\n            }\n            selectedPoiId = placeId;\n            const prevFocusEl = document.activeElement;\n            const showDetailsPanel = function(place) {\n              detailsPanelEl.innerHTML = detailsTemplate(place);\n              const backButtonEl = detailsPanelEl.querySelector('.back-button');\n              backButtonEl.addEventListener('click', () => {\n                hideElement(detailsPanelEl, prevFocusEl);\n                selectedPoiId = undefined;\n                widget.selectedPlaceMarker.setMap(null);\n              });\n              detailsPanelEl.querySelectorAll('.photo').forEach((photoEl, i) => {\n                photoEl.addEventListener('click', () => {\n                  showPhotoModal(place.photos[i], place.name);\n                });\n              });\n              showElement(detailsPanelEl, backButtonEl);\n              detailsPanelEl.scrollTop = 0;\n            };\n            widget.fetchPlaceDetailsByGoogleId(placeId, [\n              'name', 'types', 'geometry.location', 'formatted_address', 'photo', 'url',\n              'website', 'formatted_phone_number', 'opening_hours',\n            ], (place) => {\n              widget.selectedPlaceMarker.setPosition(place.coords);\n              widget.selectedPlaceMarker.setMap(widget.map);\n              if (panToMarker) widget.map.panTo(place.coords);\n              showDetailsPanel(place);\n            });\n          };\n\n          \/\/ Render the specified place objects into a layer's list.\n          const renderPlaceResults = function(places, listEl) {\n            const startCount = listEl.querySelectorAll('.place-result').length;\n            listEl.insertAdjacentHTML('beforeend', resultsTemplate({places: places}));\n            listEl.querySelectorAll('.place-result').forEach((resultEl, i) => {\n              const place = places[i - startCount];\n              if (!place) return;\n              resultEl.addEventListener('click', () => {\n                widget.selectPlace(place.poiId, \/* panToMarker= *\/ true);\n              });\n              resultEl.querySelector('.name').addEventListener('click', (e) => {\n                widget.selectPlace(place.poiId, \/* panToMarker= *\/ true);\n                e.stopPropagation();\n              });\n              const photoEl = resultEl.querySelector('.photo');\n              if (photoEl && place.photos?.[0]) {\n                photoEl.addEventListener('click', (e) => {\n                  showPhotoModal(place.photos[0], place.name);\n                  e.stopPropagation();\n                });\n              }\n              widget.addPlaceMarker(place);\n            });\n          };\n\n          \/\/ Build a sidebar section per layer.\n          resultsContainerEl.innerHTML = '';\n          const layerSections = new Map();\n          for (const layer of widget.layers) {\n            const section = document.createElement('section');\n            section.className = 'layer-section';\n            section.dataset.layerName = layer.name;\n            const heading = document.createElement('button');\n            heading.type = 'button';\n            heading.className = 'layer-heading';\n            heading.setAttribute('aria-expanded', 'true');\n            const layerState = widget.markerLayers.get(layer.name);\n            const headingLabel = document.createElement('span');\n            headingLabel.className = 'layer-heading-label';\n            headingLabel.appendChild(createLayerColorSwatch(\n              layerState.fillColor, layerState.strokeColor));\n            headingLabel.appendChild(document.createTextNode(layer.name));\n            const chevron = document.createElement('img');\n            chevron.className = 'layer-chevron';\n            chevron.src = 'https:\/\/fonts.gstatic.com\/s\/i\/googlematerialicons\/expand_more\/v11\/24px.svg';\n            chevron.alt = '';\n            heading.append(headingLabel, chevron);\n            heading.addEventListener('click', () => {\n              const collapsed = section.classList.toggle('collapsed');\n              heading.setAttribute('aria-expanded', String(!collapsed));\n              widget.setLayerVisible(layer.name, !collapsed);\n            });\n            const content = document.createElement('div');\n            content.className = 'layer-content';\n            const list = document.createElement('ul');\n            list.className = 'place-results-list';\n            content.appendChild(list);\n            section.append(heading, content);\n            resultsContainerEl.appendChild(section);\n            layerSections.set(layer.name, {section, list, nextIndex: 0});\n          }\n\n          \/\/ Fetch and show basic info for the next N places in a layer.\n          const showNextPlacesForLayer = function(layerName, n, done) {\n            const layerSection = layerSections.get(layerName);\n            if (!layerSection) {\n              done?.();\n              return;\n            }\n            const layerPlaces = widget.places.filter((place) => place.layerName === layerName);\n            const nextPlaces = layerPlaces.slice(\n              layerSection.nextIndex, layerSection.nextIndex + n);\n            if (nextPlaces.length < 1) {\n              done?.();\n              return;\n            }\n\n            let count = nextPlaces.length;\n            for (const place of nextPlaces) {\n              widget.fetchPlaceDetails(place.poiId, [\n                'name', 'types', 'geometry.location', 'photo',\n              ], () => {\n                count--;\n                if (count > 0) return;\n                renderPlaceResults(nextPlaces, layerSection.list);\n                layerSection.nextIndex += n;\n                done?.();\n              });\n            }\n          };\n\n          let layersPending = widget.layers.length;\n          for (const layer of widget.layers) {\n            showNextPlacesForLayer(layer.name, layer.pois.length, () => {\n              if (--layersPending === 0) {\n                widget.updateBounds(placesWithMarkers());\n                hideElement(showMoreButtonEl);\n              }\n            });\n          }\n        }\n\n        \/** Initializes Search Input for the widget. *\/\n        function initializeSearchInput() {\n          const searchInputEl = widgetEl.querySelector('.place-search-input');\n          widget.placeIdsToAutocompleteResults = new Map();\n\n          \/\/ Set up Autocomplete on the search input.\n          const autocomplete = new google.maps.places.Autocomplete(searchInputEl, {\n            types: ['establishment'],\n            fields: [\n              'place_id', 'name', 'types', 'geometry.location', 'formatted_address', 'photo', 'url',\n              'website', 'formatted_phone_number', 'opening_hours',\n            ],\n            bounds: widget.mapBounds,\n            strictBounds: true,\n          });\n          autocomplete.addListener('place_changed', () => {\n            const place = autocomplete.getPlace();\n            widget.placeIdsToAutocompleteResults.set(place.place_id, place);\n            widget.selectPlaceById(place.place_id, \/* panToMarker= *\/ true);\n            searchInputEl.value = '';\n          });\n        }\n      }\n    <\/script>\n    <script>\n      const CONFIGURATION = {\n        \"capabilities\": {\"search\":true,\"distances\":false,\"directions\":false,\"contacts\":true,\"atmospheres\":false,\"thumbnails\":true},\n        \"layers\": [\n          {\n            \"name\": \"Local Businesses\",\n            \"pois\": [\n              {\"name\": \"El Oriental De Cuba\", \"coords\": {\"lat\": 42.3207613, \"lng\": -71.1104739}},\n              {\"name\": \"Brendan Behan Pub\", \"coords\": {\"lat\": 42.3220056, \"lng\": -71.109334}},\n              {\"name\": \"Ultra Beauty Salon\", \"coords\": {\"lat\": 42.3217856, \"lng\": -71.1102584}},\n              {\"name\": \"Blue Nile Restaurant\", \"coords\": {\"lat\": 42.3222087, \"lng\": -71.1095854}},\n              {\"name\": \"Fat Ram's Pumpkin Tattoo\", \"coords\": {\"lat\": 42.3220746, \"lng\": -71.1089129}},\n              {\"name\": \"Centre Fashion\", \"coords\": {\"lat\": 42.3223225, \"lng\": -71.1081041}},\n              {\"name\": \"Alex's Chimis\", \"coords\": {\"lat\": 42.3223531, \"lng\": -71.1077129}},\n              {\"name\": \"Fernandez Beauty & Barber Shop\", \"coords\": {\"lat\": 42.3228219, \"lng\": -71.1053675}},\n              {\"name\": \"Gondres Bakery\", \"coords\": {\"lat\": 42.3228344, \"lng\": -71.1050955}}\n            ]\n          },\n          {\n            \"name\": \"Housing\",\n            \"pois\": [\n              {\"name\": \"Betsaida Gutierrez Coop\", \"coords\": {\"lat\": 42.3227747, \"lng\": -71.1082644}},\n              {\"name\": \"Bromley-Heath Housing\/Mildred C. Hailey Apartments\", \"coords\": {\"lat\": 42.3233190, \"lng\": -71.1022019}},\n              {\"name\": \"Urban Edge (CDC)\", \"coords\": {\"lat\": 42.3232939, \"lng\": -71.0983117}}\n            ]\n          },\n          {\n            \"name\": \"Public Resources\",\n            \"pois\": [\n              {\"name\": \"Mary E Curley School\", \"coords\": {\"lat\": 42.3185211, \"lng\": -71.1135991}},\n              {\"name\": \"Connolly Library\", \"coords\": {\"lat\": 42.3206515, \"lng\": -71.1110858}},\n              {\"name\": \"Hennigan School\", \"coords\": {\"lat\": 42.3261145, \"lng\": -71.1067352}},\n              {\"name\": \"John F. Kennedy Elementary School\", \"coords\": {\"lat\": 42.3216913, \"lng\": -71.1058143}},\n              {\"name\": \"Mozart Park\", \"coords\": {\"lat\": 42.3222896, \"lng\": -71.1044807}},\n              {\"name\": \"Jackson T Stop\", \"coords\": {\"lat\": 42.3231, \"lng\": -71.0998}},\n              {\"name\": \"Southwest Corridor\", \"coords\": {\"lat\": 42.3198, \"lng\": -71.1050}}\n            ]\n          },\n          {\n            \"name\": \"Cultural Organizations\",\n            \"pois\": [\n              {\"name\": \"JP Arts and Civic Center\", \"coords\": {\"lat\": 42.3236121, \"lng\": -71.1070249}},\n              {\"name\": \"Hyde Square Task Force\", \"coords\": {\"lat\": 42.3236108, \"lng\": -71.1074541}},\n              {\"name\": \"Spontaneous Celebrations\", \"coords\": {\"lat\": 42.3175834, \"lng\": -71.1056469}}\n            ]\n          },\n          {\n            \"name\": \"Non Profits\",\n            \"pois\": [\n              {\"name\": \"Hyde-Jackson Main Strs.\", \"coords\": {\"lat\": 42.3229353, \"lng\": -71.1044273}},\n              {\"name\": \"Martha Eliott Health Cntr\", \"coords\": {\"lat\": 42.3244500, \"lng\": -71.1021487}},\n              {\"name\": \"Nurtury Child Care\", \"coords\": {\"lat\": 42.3251537, \"lng\": -71.1019691}}\n            ]\n          }\n        ],\n        \"boundaryPoints\": [\n          {\"lat\":42.3251235,\"lng\":-71.0993791},\n          {\"lat\":42.3258334,\"lng\":-71.1001007},\n          {\"lat\":42.3261795,\"lng\":-71.1004561},\n          {\"lat\":42.3264145,\"lng\":-71.10079},\n          {\"lat\":42.3264324,\"lng\":-71.101419},\n          {\"lat\":42.326355,\"lng\":-71.1022947},\n          {\"lat\":42.3261369,\"lng\":-71.1040891},\n          {\"lat\":42.326113,\"lng\":-71.1052103},\n          {\"lat\":42.3262089,\"lng\":-71.1057578},\n          {\"lat\":42.3263842,\"lng\":-71.1063053},\n          {\"lat\":42.3268775,\"lng\":-71.107132},\n          {\"lat\":42.3273405,\"lng\":-71.108335},\n          {\"lat\":42.3288853,\"lng\":-71.1107088},\n          {\"lat\":42.3277153,\"lng\":-71.1108804},\n          {\"lat\":42.3266524,\"lng\":-71.1113042},\n          {\"lat\":42.3258354,\"lng\":-71.1118514},\n          {\"lat\":42.3249549,\"lng\":-71.1122055},\n          {\"lat\":42.3239237,\"lng\":-71.112286},\n          {\"lat\":42.3216391,\"lng\":-71.1121089},\n          {\"lat\":42.3195767,\"lng\":-71.1116476},\n          {\"lat\":42.3191939,\"lng\":-71.111083},\n          {\"lat\":42.318823,\"lng\":-71.1104433},\n          {\"lat\":42.3183693,\"lng\":-71.109369},\n          {\"lat\":42.3180307,\"lng\":-71.1084584},\n          {\"lat\":42.3177422,\"lng\":-71.1076671},\n          {\"lat\":42.3174866,\"lng\":-71.1071213},\n          {\"lat\":42.3172607,\"lng\":-71.1066774},\n          {\"lat\":42.3169598,\"lng\":-71.1059077},\n          {\"lat\":42.3169389,\"lng\":-71.1056334},\n          {\"lat\":42.3169796,\"lng\":-71.1053726},\n          {\"lat\":42.3170361,\"lng\":-71.1049099},\n          {\"lat\":42.3172291,\"lng\":-71.1047757},\n          {\"lat\":42.3174599,\"lng\":-71.1046415},\n          {\"lat\":42.3179074,\"lng\":-71.1043623},\n          {\"lat\":42.3190028,\"lng\":-71.1035572},\n          {\"lat\":42.3194443,\"lng\":-71.1031701},\n          {\"lat\":42.3203354,\"lng\":-71.1024603},\n          {\"lat\":42.3215542,\"lng\":-71.1014376},\n          {\"lat\":42.3228099,\"lng\":-71.1005507},\n          {\"lat\":42.322792,\"lng\":-71.1002985},\n          {\"lat\":42.3228823,\"lng\":-71.1002261},\n          {\"lat\":42.3237905,\"lng\":-71.0996065},\n          {\"lat\":42.3250446,\"lng\":-71.0990806},\n          {\"lat\":42.3251235,\"lng\":-71.0993791}\n        ],\n        \"mapRadius\": 950,\n        \"mapOptions\": {\"center\":{\"lat\":42.3223176,\"lng\":-71.1056063},\"fullscreenControl\":true,\"mapTypeControl\":true,\"streetViewControl\":false,\"zoom\":16,\"zoomControl\":true,\"maxZoom\":20,\"mapId\":\"\"},\n        \"mapsApiKey\": \"AIzaSyB95wccdMhLBku8_WIXvCnEWoNSfLe46uU\"\n      };\n\n      function initMap() {\n        new NeighborhoodDiscovery(CONFIGURATION);\n      }\n    <\/script>\n    <script id=\"nd-place-results-tmpl\" type=\"text\/x-handlebars-template\">\n      {{#each places}}\n        <li class=\"place-result\">\n          <div class=\"text\">\n            <button class=\"name\">{{name}}<\/button>\n            <div class=\"info\">{{type}}<\/div>\n          <\/div>\n          <button class=\"photo\" style=\"background-image:url({{photos.0.urlSmall}})\" aria-label=\"show photo in viewer\"><\/button>\n        <\/li>\n      {{\/each}}\n    <\/script>\n    <script id=\"nd-place-details-tmpl\" type=\"text\/x-handlebars-template\">\n      <div class=\"navbar\">\n        <button class=\"back-button\">\n          <img decoding=\"async\" class=\"icon\" src=\"https:\/\/fonts.gstatic.com\/s\/i\/googlematerialicons\/arrow_back\/v11\/24px.svg\" alt=\"back\"\/>\n          Back\n        <\/button>\n      <\/div>\n      <header>\n        <h2>{{name}}<\/h2>\n        <div class=\"info\">\n          <a href=\"{{url}}\" target=\"_blank\">See on Google Maps<\/a>\n        <\/div>\n        {{#if type}}\n          <div class=\"info\">{{type}}<\/div>\n        {{\/if}}\n      <\/header>\n      <div class=\"section\">\n        {{#if address}}\n          <div class=\"contact\">\n            <img decoding=\"async\" src=\"https:\/\/fonts.gstatic.com\/s\/i\/googlematerialicons\/place\/v10\/24px.svg\" alt=\"Address\" class=\"icon\"\/>\n            <div class=\"text\">\n              {{address}}\n            <\/div>\n          <\/div>\n        {{\/if}}\n        {{#if website}}\n          <div class=\"contact\">\n            <img decoding=\"async\" src=\"https:\/\/fonts.gstatic.com\/s\/i\/googlematerialicons\/public\/v10\/24px.svg\" alt=\"Website\" class=\"icon\"\/>\n            <div class=\"text\">\n              <a href=\"{{website}}\" target=\"_blank\">{{websiteDomain}}<\/a>\n            <\/div>\n          <\/div>\n        {{\/if}}\n        {{#if phoneNumber}}\n          <div class=\"contact\">\n            <img decoding=\"async\" src=\"https:\/\/fonts.gstatic.com\/s\/i\/googlematerialicons\/phone\/v10\/24px.svg\" alt=\"Phone number\" class=\"icon\"\/>\n            <div class=\"text\">\n              {{phoneNumber}}\n            <\/div>\n          <\/div>\n        {{\/if}}\n        {{#if openingHours}}\n          <div class=\"contact\">\n            <img decoding=\"async\" src=\"https:\/\/fonts.gstatic.com\/s\/i\/googlematerialicons\/schedule\/v12\/24px.svg\" alt=\"Opening hours\" class=\"icon\"\/>\n            <div class=\"text\">\n              {{#each openingHours}}\n                <div>\n                  <span class=\"weekday\">{{days}}<\/span>\n                  <span class=\"hours\">{{hours}}<\/span>\n                <\/div>\n              {{\/each}}\n            <\/div>\n          <\/div>\n        {{\/if}}\n      <\/div>\n      {{#if photos}}\n        <div class=\"photos section\">\n          {{#each photos}}\n            <button class=\"photo\" style=\"background-image:url({{urlLarge}})\" aria-label=\"show photo in viewer\"><\/button>\n          {{\/each}}\n        <\/div>\n      {{\/if}}\n      {{#if html_attributions}}\n        <div class=\"section\">\n          {{#each html_attributions}}\n            <p class=\"attribution\">{{{this}}}<\/p>\n          {{\/each}}\n        <\/div>\n      {{\/if}}\n    <\/script>\n  \n  \n    <div class=\"neighborhood-discovery\">\n      <div class=\"places-panel panel\">\n        <header class=\"navbar\">\n          <div class=\"search-input\">\n            <input class=\"place-search-input\" placeholder=\"Busca lugares cercanos\">\n            <button class=\"place-search-button\">\n              <img decoding=\"async\" src=\"https:\/\/fonts.gstatic.com\/s\/i\/googlematerialicons\/search\/v11\/24px.svg\" alt=\"buscar\">\n            <\/button>\n          <\/div>\n        <\/header>\n        <div class=\"results\"><\/div>\n        <button class=\"show-more-button sticky\">\n          <span>Mostrar m\u00e1s<\/span>\n          <img decoding=\"async\" class=\"right\" src=\"https:\/\/fonts.gstatic.com\/s\/i\/googlematerialicons\/expand_more\/v11\/24px.svg\" alt=\"expandir\">\n        <\/button>\n      <\/div>\n      <div class=\"details-panel panel\"><\/div>\n      <div class=\"map\"><\/div>\n      <div class=\"photo-modal\">\n        <img alt=\"foto del lugar\">\n        <div>\n          <button class=\"back-button\">\n            <img decoding=\"async\" class=\"icon\" src=\"https:\/\/fonts.gstatic.com\/s\/i\/googlematerialicons\/arrow_back\/v11\/24px.svg\" alt=\"volver\">\n          <\/button>\n          <div class=\"photo-text\">\n            <div class=\"photo-place\"><\/div>\n            <div class=\"photo-attrs\">Foto de  <span><\/span><\/div>\n          <\/div>\n        <\/div>\n      <\/div>\n      <svg class=\"marker-pin\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"26\" height=\"38\" fill=\"none\">\n        <path d=\"M13 0C5.817 0 0 5.93 0 13.267c0 7.862 5.59 10.81 9.555 17.624C12.09 35.248 11.342 38 13 38c1.723 0 .975-2.817 3.445-7.043C20.085 24.503 26 21.162 26 13.267 26 5.93 20.183 0 13 0Z\"><\/path>\n      <\/svg>\n    <\/div>\n    <script src=\"https:\/\/maps.googleapis.com\/maps\/api\/js?key=AIzaSyB95wccdMhLBku8_WIXvCnEWoNSfLe46uU&amp;callback=initMap&amp;libraries=places,geometry&amp;solution_channel=GMP_QB_neighborhooddiscovery_v3_cADF\" async=\"\" defer><\/script>\n  \n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-8aedae4 e-con-full e-flex e-con e-parent\" data-id=\"8aedae4\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-2c1956f elementor-widget__width-initial elementor-absolute elementor-widget elementor-widget-image\" data-id=\"2c1956f\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_position&quot;:&quot;absolute&quot;}\" data-widget_type=\"image.default\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<a href=\"https:\/\/blq.dev.techademics.tech\/es\/apoyar\/\">\n\t\t\t\t\t\t\t<img fetchpriority=\"high\" decoding=\"async\" width=\"381\" height=\"400\" src=\"https:\/\/blq.dev.techademics.tech\/wp-content\/uploads\/2026\/05\/Group-92.png\" class=\"attachment-large size-large wp-image-2138\" alt=\"\" srcset=\"https:\/\/blq.dev.techademics.tech\/wp-content\/uploads\/2026\/05\/Group-92.png 381w, https:\/\/blq.dev.techademics.tech\/wp-content\/uploads\/2026\/05\/Group-92-286x300.png 286w\" sizes=\"(max-width: 381px) 100vw, 381px\" \/>\t\t\t\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-f5f504a e-con-full e-flex e-con e-child\" data-id=\"f5f504a\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-ade67ae e-con-full e-flex e-con e-child\" data-id=\"ade67ae\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-d34c6d1 e-con-full e-flex e-con e-child\" data-id=\"d34c6d1\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-898739e nanum-pen elementor-widget-mobile__width-initial elementor-widget__width-initial elementor-widget elementor-widget-heading\" data-id=\"898739e\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">MANT\u00c9NGASE CONECTADO<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-019f8b2 porter-font elementor-widget__width-initial elementor-widget elementor-widget-heading\" data-id=\"019f8b2\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Vuelva a consultar a medida que el directorio crezca.<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-8c1357d elementor-widget elementor-widget-image\" data-id=\"8c1357d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" width=\"300\" height=\"20\" src=\"https:\/\/blq.dev.techademics.tech\/wp-content\/uploads\/2026\/05\/Frame-28-2.png\" class=\"attachment-large size-large wp-image-2115\" alt=\"\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-3f51436 elementor-widget__width-initial elementor-widget-tablet__width-initial elementor-widget elementor-widget-text-editor\" data-id=\"3f51436\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t\t\t\t\t\t<p><span style=\"font-weight: 400;\">El directorio de negocios ayudar\u00e1 a visitantes y miembros de la comunidad a descubrir todo lo que el Barrio Latino de Boston tiene para ofrecer.<\/span><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-ac22fce e-con-full e-flex e-con e-child\" data-id=\"ac22fce\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>DIRECTORIO DE NEGOCIOS Directorio de Negocios Encuentre negocios locales en el Barrio Latino de Boston. Explorar eventos Barrio Latino de Boston Mostrar m\u00e1s Foto de MANT\u00c9NGASE CONECTADO Vuelva a consultar a medida que el directorio crezca. El directorio de negocios ayudar\u00e1 a visitantes y miembros de la comunidad a descubrir todo lo que el Barrio [&hellip;]<\/p>\n","protected":false},"author":4,"featured_media":0,"parent":2134,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-2146","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/blq.dev.techademics.tech\/es\/wp-json\/wp\/v2\/pages\/2146","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blq.dev.techademics.tech\/es\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/blq.dev.techademics.tech\/es\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/blq.dev.techademics.tech\/es\/wp-json\/wp\/v2\/users\/4"}],"replies":[{"embeddable":true,"href":"https:\/\/blq.dev.techademics.tech\/es\/wp-json\/wp\/v2\/comments?post=2146"}],"version-history":[{"count":22,"href":"https:\/\/blq.dev.techademics.tech\/es\/wp-json\/wp\/v2\/pages\/2146\/revisions"}],"predecessor-version":[{"id":4344,"href":"https:\/\/blq.dev.techademics.tech\/es\/wp-json\/wp\/v2\/pages\/2146\/revisions\/4344"}],"up":[{"embeddable":true,"href":"https:\/\/blq.dev.techademics.tech\/es\/wp-json\/wp\/v2\/pages\/2134"}],"wp:attachment":[{"href":"https:\/\/blq.dev.techademics.tech\/es\/wp-json\/wp\/v2\/media?parent=2146"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}