Freezing of browser when attempting to unmount 4k+ Markers on react-google-mapsGoogle Maps JS API v3 - Simple Multiple Marker ExampleGoogle Maps infowindow shows same content for each markerAsync displaying markers with React-Google-Maps and ReduxClose open info window on individual markers 'react-google-maps'React Google maps/ Markerclusterer multiple markers at same locationHow to use React with Google Places API, to display place markers on a Google map?Show marker to Google Map on ClickEntire map re-renders when I only want the change marker text in react-google-mapsReact Google Maps InfoWindow toggle display one at a timeReact move marker without re-rendering map in react-google-maps
I'm in charge of equipment buying but no one's ever happy with what I choose. How to fix this?
Who must act to prevent Brexit on March 29th?
Why does this part of the Space Shuttle launch pad seem to be floating in air?
Why are on-board computers allowed to change controls without notifying the pilots?
Word describing multiple paths to the same abstract outcome
Is there a problem with hiding "forgot password" until it's needed?
Can I rely on these GitHub repository files?
Why isn't KTEX's runway designation 10/28 instead of 9/27?
"lassen" in meaning "sich fassen"
Reply ‘no position’ while the job posting is still there (‘HiWi’ position in Germany)
Is infinity mathematically observable?
Is there an wasy way to program in Tikz something like the one in the image?
Hostile work environment after whistle-blowing on coworker and our boss. What do I do?
Are taller landing gear bad for aircraft, particulary large airliners?
In Star Trek IV, why did the Bounty go back to a time when whales were already rare?
My boss asked me to take a one-day class, then signs it up as a day off
Books on the History of math research at European universities
Indicating multiple different modes of speech (fantasy language or telepathy)
Simulating a probability of 1 of 2^N with less than N random bits
Visiting the UK as unmarried couple
Can somebody explain Brexit in a few child-proof sentences?
What is the term when two people sing in harmony, but they aren't singing the same notes?
Stereotypical names
What will be the benefits of Brexit?
Freezing of browser when attempting to unmount 4k+ Markers on react-google-maps
Google Maps JS API v3 - Simple Multiple Marker ExampleGoogle Maps infowindow shows same content for each markerAsync displaying markers with React-Google-Maps and ReduxClose open info window on individual markers 'react-google-maps'React Google maps/ Markerclusterer multiple markers at same locationHow to use React with Google Places API, to display place markers on a Google map?Show marker to Google Map on ClickEntire map re-renders when I only want the change marker text in react-google-mapsReact Google Maps InfoWindow toggle display one at a timeReact move marker without re-rendering map in react-google-maps
I'm building a React app in which many Markers are displayed on a react-google-maps map. The user can filter the Markers so that not all are displayed at once. Displaying 4000 Markers with a MarkerClusterer works fine. It takes a resonable amount of time to display them and the map is responsive afterwards.
My problem now occurs when I attempt to only display none or few Markers after I rendered 4000 before. The browser freezes and I can't do anything in the browser anymore. There is no infinite loop warning or error. The console displays nothing that could help me before the freeze.
The code to display the map component:
import React from 'react';
import compose, withProps, withHandlers from "recompose"
import withScriptjs, withGoogleMap, GoogleMap, TrafficLayer from "react-google-maps"
import connect from 'react-redux';
import MarkersList from './MarkersList';
const MarkerClusterer = require("react-google-maps/lib/components/addons/MarkerClusterer");
const Map = compose(
withProps(
googleMapURL: "https://maps.googleapis.com/maps/api/js?key=*******&callback=initMap",
loadingElement: <div style= height: `100%` />,
containerElement: <div style= height: `100vh` />,
mapElement: <div style= height: `100%` />
),
withHandlers(
onMarkerClustererClick: () => (markerClusterer) =>
const clickedMarkers = markerClusterer.getMarkers()
console.log(`Current clicked markers length: $clickedMarkers.length`)
console.log(clickedMarkers)
),
withScriptjs,
withGoogleMap
)((props) =>
<GoogleMap
defaultZoom=5.76
defaultCenter= lat: 49.4299758, lng: 14.0531568
mapTypeId="terrain"
fullscreenControl=false
>
<TrafficLayer autoUpdate />
<MarkerClusterer
onClick=props.onMarkerClustererClick
averageCenter
enableRetinalIcons
gridSize=60
>
props.isMarkerShown && <MarkersList/>
</MarkerClusterer>
</GoogleMap>
);
export default connect()(Map);
The MarkersList component:
import React from 'react';
import bindActionCreators from 'redux';
import connect from 'react-redux';
import Marker, InfoWindow from 'react-google-maps';
import markersActionCreators from './MarkersActions';
class MarkersList extends React.Component
componentDidMount()
if(this.props.markers.length === 0)
this.props.requestMarkers();
render()
var listComponent = this.props.displayedMarkers.map((marker, index) =>
<Marker
key=index
position=lat: marker.currentPositionLat, lng: marker.currentPositionLng
onClick=() => this.props.onToggleOpen(index)
tracksViewChanges=false
>
this.props.isOpen && this.props.infoIndex === index &&
<InfoWindow onCloseClick=() => this.props.onToggleOpen(index)>
<div>
<h6>Truck Id: marker.vehicleName</h6>
<b>Registration Plate: marker.registrationNumber</b>
<br/>
<p>
Position recorded on <i>marker.time</i> <br/>
Engine is [marker.currentIgnitionState] <br/>
Fuel Level: marker.currentFuelLevel L left <br/>
Speed: marker.currentSpeed Km/h <br/>
</p>
</div>
</InfoWindow>
</Marker>
);
return <div>listComponent</div>;
;
export default connect(
state => state.mainArea.markersReducer,
dispatch => bindActionCreators(markersActionCreators, dispatch)
)(MarkersList);
I ensured that displayedMarkers has the correct value after selecting something (in this case displayedMarkers changes from 4000 entries to 1). I stepped through my whole app to ensure that every value I calculate is correct when this unfortunate behaviour occurs. Furthermore the render method doesn't get called a second time before the freeze. The change from 4000 displayed Markers to 3999 or 3980 works as it should.
For a better overview of the app I made a CodeSandbox (it doesn't render anything because the api key and data is missing): https://codesandbox.io/s/v830m9p7ry?fontsize=14&view=editor
I'm new to react and redux and I really don't know what I should test or do next to find why this is happening.
Thanks in advance for any help!
EDIT: Added performance analysis. And also
this is displayed after the 30 second mark in the performance analysis.
It is rendering every marker and is removing them one by one.
javascript google-maps react-redux google-maps-markers react-google-maps
add a comment |
I'm building a React app in which many Markers are displayed on a react-google-maps map. The user can filter the Markers so that not all are displayed at once. Displaying 4000 Markers with a MarkerClusterer works fine. It takes a resonable amount of time to display them and the map is responsive afterwards.
My problem now occurs when I attempt to only display none or few Markers after I rendered 4000 before. The browser freezes and I can't do anything in the browser anymore. There is no infinite loop warning or error. The console displays nothing that could help me before the freeze.
The code to display the map component:
import React from 'react';
import compose, withProps, withHandlers from "recompose"
import withScriptjs, withGoogleMap, GoogleMap, TrafficLayer from "react-google-maps"
import connect from 'react-redux';
import MarkersList from './MarkersList';
const MarkerClusterer = require("react-google-maps/lib/components/addons/MarkerClusterer");
const Map = compose(
withProps(
googleMapURL: "https://maps.googleapis.com/maps/api/js?key=*******&callback=initMap",
loadingElement: <div style= height: `100%` />,
containerElement: <div style= height: `100vh` />,
mapElement: <div style= height: `100%` />
),
withHandlers(
onMarkerClustererClick: () => (markerClusterer) =>
const clickedMarkers = markerClusterer.getMarkers()
console.log(`Current clicked markers length: $clickedMarkers.length`)
console.log(clickedMarkers)
),
withScriptjs,
withGoogleMap
)((props) =>
<GoogleMap
defaultZoom=5.76
defaultCenter= lat: 49.4299758, lng: 14.0531568
mapTypeId="terrain"
fullscreenControl=false
>
<TrafficLayer autoUpdate />
<MarkerClusterer
onClick=props.onMarkerClustererClick
averageCenter
enableRetinalIcons
gridSize=60
>
props.isMarkerShown && <MarkersList/>
</MarkerClusterer>
</GoogleMap>
);
export default connect()(Map);
The MarkersList component:
import React from 'react';
import bindActionCreators from 'redux';
import connect from 'react-redux';
import Marker, InfoWindow from 'react-google-maps';
import markersActionCreators from './MarkersActions';
class MarkersList extends React.Component
componentDidMount()
if(this.props.markers.length === 0)
this.props.requestMarkers();
render()
var listComponent = this.props.displayedMarkers.map((marker, index) =>
<Marker
key=index
position=lat: marker.currentPositionLat, lng: marker.currentPositionLng
onClick=() => this.props.onToggleOpen(index)
tracksViewChanges=false
>
this.props.isOpen && this.props.infoIndex === index &&
<InfoWindow onCloseClick=() => this.props.onToggleOpen(index)>
<div>
<h6>Truck Id: marker.vehicleName</h6>
<b>Registration Plate: marker.registrationNumber</b>
<br/>
<p>
Position recorded on <i>marker.time</i> <br/>
Engine is [marker.currentIgnitionState] <br/>
Fuel Level: marker.currentFuelLevel L left <br/>
Speed: marker.currentSpeed Km/h <br/>
</p>
</div>
</InfoWindow>
</Marker>
);
return <div>listComponent</div>;
;
export default connect(
state => state.mainArea.markersReducer,
dispatch => bindActionCreators(markersActionCreators, dispatch)
)(MarkersList);
I ensured that displayedMarkers has the correct value after selecting something (in this case displayedMarkers changes from 4000 entries to 1). I stepped through my whole app to ensure that every value I calculate is correct when this unfortunate behaviour occurs. Furthermore the render method doesn't get called a second time before the freeze. The change from 4000 displayed Markers to 3999 or 3980 works as it should.
For a better overview of the app I made a CodeSandbox (it doesn't render anything because the api key and data is missing): https://codesandbox.io/s/v830m9p7ry?fontsize=14&view=editor
I'm new to react and redux and I really don't know what I should test or do next to find why this is happening.
Thanks in advance for any help!
EDIT: Added performance analysis. And also
this is displayed after the 30 second mark in the performance analysis.
It is rendering every marker and is removing them one by one.
javascript google-maps react-redux google-maps-markers react-google-maps
Would it be possible to share a codesandbox?
– Maaz Syed Adeeb
Mar 7 at 10:34
I'll try to make one. But the data and the map api key won't be there.
– Mack
Mar 7 at 10:43
If you can reproduce the problem in a shareable sandbox, then create one. Or else, it won't be of help to answer the question.
– Maaz Syed Adeeb
Mar 7 at 10:48
Okay then no it isn't possible because the google api key is private.
– Mack
Mar 7 at 10:55
add a comment |
I'm building a React app in which many Markers are displayed on a react-google-maps map. The user can filter the Markers so that not all are displayed at once. Displaying 4000 Markers with a MarkerClusterer works fine. It takes a resonable amount of time to display them and the map is responsive afterwards.
My problem now occurs when I attempt to only display none or few Markers after I rendered 4000 before. The browser freezes and I can't do anything in the browser anymore. There is no infinite loop warning or error. The console displays nothing that could help me before the freeze.
The code to display the map component:
import React from 'react';
import compose, withProps, withHandlers from "recompose"
import withScriptjs, withGoogleMap, GoogleMap, TrafficLayer from "react-google-maps"
import connect from 'react-redux';
import MarkersList from './MarkersList';
const MarkerClusterer = require("react-google-maps/lib/components/addons/MarkerClusterer");
const Map = compose(
withProps(
googleMapURL: "https://maps.googleapis.com/maps/api/js?key=*******&callback=initMap",
loadingElement: <div style= height: `100%` />,
containerElement: <div style= height: `100vh` />,
mapElement: <div style= height: `100%` />
),
withHandlers(
onMarkerClustererClick: () => (markerClusterer) =>
const clickedMarkers = markerClusterer.getMarkers()
console.log(`Current clicked markers length: $clickedMarkers.length`)
console.log(clickedMarkers)
),
withScriptjs,
withGoogleMap
)((props) =>
<GoogleMap
defaultZoom=5.76
defaultCenter= lat: 49.4299758, lng: 14.0531568
mapTypeId="terrain"
fullscreenControl=false
>
<TrafficLayer autoUpdate />
<MarkerClusterer
onClick=props.onMarkerClustererClick
averageCenter
enableRetinalIcons
gridSize=60
>
props.isMarkerShown && <MarkersList/>
</MarkerClusterer>
</GoogleMap>
);
export default connect()(Map);
The MarkersList component:
import React from 'react';
import bindActionCreators from 'redux';
import connect from 'react-redux';
import Marker, InfoWindow from 'react-google-maps';
import markersActionCreators from './MarkersActions';
class MarkersList extends React.Component
componentDidMount()
if(this.props.markers.length === 0)
this.props.requestMarkers();
render()
var listComponent = this.props.displayedMarkers.map((marker, index) =>
<Marker
key=index
position=lat: marker.currentPositionLat, lng: marker.currentPositionLng
onClick=() => this.props.onToggleOpen(index)
tracksViewChanges=false
>
this.props.isOpen && this.props.infoIndex === index &&
<InfoWindow onCloseClick=() => this.props.onToggleOpen(index)>
<div>
<h6>Truck Id: marker.vehicleName</h6>
<b>Registration Plate: marker.registrationNumber</b>
<br/>
<p>
Position recorded on <i>marker.time</i> <br/>
Engine is [marker.currentIgnitionState] <br/>
Fuel Level: marker.currentFuelLevel L left <br/>
Speed: marker.currentSpeed Km/h <br/>
</p>
</div>
</InfoWindow>
</Marker>
);
return <div>listComponent</div>;
;
export default connect(
state => state.mainArea.markersReducer,
dispatch => bindActionCreators(markersActionCreators, dispatch)
)(MarkersList);
I ensured that displayedMarkers has the correct value after selecting something (in this case displayedMarkers changes from 4000 entries to 1). I stepped through my whole app to ensure that every value I calculate is correct when this unfortunate behaviour occurs. Furthermore the render method doesn't get called a second time before the freeze. The change from 4000 displayed Markers to 3999 or 3980 works as it should.
For a better overview of the app I made a CodeSandbox (it doesn't render anything because the api key and data is missing): https://codesandbox.io/s/v830m9p7ry?fontsize=14&view=editor
I'm new to react and redux and I really don't know what I should test or do next to find why this is happening.
Thanks in advance for any help!
EDIT: Added performance analysis. And also
this is displayed after the 30 second mark in the performance analysis.
It is rendering every marker and is removing them one by one.
javascript google-maps react-redux google-maps-markers react-google-maps
I'm building a React app in which many Markers are displayed on a react-google-maps map. The user can filter the Markers so that not all are displayed at once. Displaying 4000 Markers with a MarkerClusterer works fine. It takes a resonable amount of time to display them and the map is responsive afterwards.
My problem now occurs when I attempt to only display none or few Markers after I rendered 4000 before. The browser freezes and I can't do anything in the browser anymore. There is no infinite loop warning or error. The console displays nothing that could help me before the freeze.
The code to display the map component:
import React from 'react';
import compose, withProps, withHandlers from "recompose"
import withScriptjs, withGoogleMap, GoogleMap, TrafficLayer from "react-google-maps"
import connect from 'react-redux';
import MarkersList from './MarkersList';
const MarkerClusterer = require("react-google-maps/lib/components/addons/MarkerClusterer");
const Map = compose(
withProps(
googleMapURL: "https://maps.googleapis.com/maps/api/js?key=*******&callback=initMap",
loadingElement: <div style= height: `100%` />,
containerElement: <div style= height: `100vh` />,
mapElement: <div style= height: `100%` />
),
withHandlers(
onMarkerClustererClick: () => (markerClusterer) =>
const clickedMarkers = markerClusterer.getMarkers()
console.log(`Current clicked markers length: $clickedMarkers.length`)
console.log(clickedMarkers)
),
withScriptjs,
withGoogleMap
)((props) =>
<GoogleMap
defaultZoom=5.76
defaultCenter= lat: 49.4299758, lng: 14.0531568
mapTypeId="terrain"
fullscreenControl=false
>
<TrafficLayer autoUpdate />
<MarkerClusterer
onClick=props.onMarkerClustererClick
averageCenter
enableRetinalIcons
gridSize=60
>
props.isMarkerShown && <MarkersList/>
</MarkerClusterer>
</GoogleMap>
);
export default connect()(Map);
The MarkersList component:
import React from 'react';
import bindActionCreators from 'redux';
import connect from 'react-redux';
import Marker, InfoWindow from 'react-google-maps';
import markersActionCreators from './MarkersActions';
class MarkersList extends React.Component
componentDidMount()
if(this.props.markers.length === 0)
this.props.requestMarkers();
render()
var listComponent = this.props.displayedMarkers.map((marker, index) =>
<Marker
key=index
position=lat: marker.currentPositionLat, lng: marker.currentPositionLng
onClick=() => this.props.onToggleOpen(index)
tracksViewChanges=false
>
this.props.isOpen && this.props.infoIndex === index &&
<InfoWindow onCloseClick=() => this.props.onToggleOpen(index)>
<div>
<h6>Truck Id: marker.vehicleName</h6>
<b>Registration Plate: marker.registrationNumber</b>
<br/>
<p>
Position recorded on <i>marker.time</i> <br/>
Engine is [marker.currentIgnitionState] <br/>
Fuel Level: marker.currentFuelLevel L left <br/>
Speed: marker.currentSpeed Km/h <br/>
</p>
</div>
</InfoWindow>
</Marker>
);
return <div>listComponent</div>;
;
export default connect(
state => state.mainArea.markersReducer,
dispatch => bindActionCreators(markersActionCreators, dispatch)
)(MarkersList);
I ensured that displayedMarkers has the correct value after selecting something (in this case displayedMarkers changes from 4000 entries to 1). I stepped through my whole app to ensure that every value I calculate is correct when this unfortunate behaviour occurs. Furthermore the render method doesn't get called a second time before the freeze. The change from 4000 displayed Markers to 3999 or 3980 works as it should.
For a better overview of the app I made a CodeSandbox (it doesn't render anything because the api key and data is missing): https://codesandbox.io/s/v830m9p7ry?fontsize=14&view=editor
I'm new to react and redux and I really don't know what I should test or do next to find why this is happening.
Thanks in advance for any help!
EDIT: Added performance analysis. And also
this is displayed after the 30 second mark in the performance analysis.
It is rendering every marker and is removing them one by one.
javascript google-maps react-redux google-maps-markers react-google-maps
javascript google-maps react-redux google-maps-markers react-google-maps
edited Mar 7 at 16:58
Mack
asked Mar 7 at 10:14
MackMack
12
12
Would it be possible to share a codesandbox?
– Maaz Syed Adeeb
Mar 7 at 10:34
I'll try to make one. But the data and the map api key won't be there.
– Mack
Mar 7 at 10:43
If you can reproduce the problem in a shareable sandbox, then create one. Or else, it won't be of help to answer the question.
– Maaz Syed Adeeb
Mar 7 at 10:48
Okay then no it isn't possible because the google api key is private.
– Mack
Mar 7 at 10:55
add a comment |
Would it be possible to share a codesandbox?
– Maaz Syed Adeeb
Mar 7 at 10:34
I'll try to make one. But the data and the map api key won't be there.
– Mack
Mar 7 at 10:43
If you can reproduce the problem in a shareable sandbox, then create one. Or else, it won't be of help to answer the question.
– Maaz Syed Adeeb
Mar 7 at 10:48
Okay then no it isn't possible because the google api key is private.
– Mack
Mar 7 at 10:55
Would it be possible to share a codesandbox?
– Maaz Syed Adeeb
Mar 7 at 10:34
Would it be possible to share a codesandbox?
– Maaz Syed Adeeb
Mar 7 at 10:34
I'll try to make one. But the data and the map api key won't be there.
– Mack
Mar 7 at 10:43
I'll try to make one. But the data and the map api key won't be there.
– Mack
Mar 7 at 10:43
If you can reproduce the problem in a shareable sandbox, then create one. Or else, it won't be of help to answer the question.
– Maaz Syed Adeeb
Mar 7 at 10:48
If you can reproduce the problem in a shareable sandbox, then create one. Or else, it won't be of help to answer the question.
– Maaz Syed Adeeb
Mar 7 at 10:48
Okay then no it isn't possible because the google api key is private.
– Mack
Mar 7 at 10:55
Okay then no it isn't possible because the google api key is private.
– Mack
Mar 7 at 10:55
add a comment |
0
active
oldest
votes
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55041229%2ffreezing-of-browser-when-attempting-to-unmount-4k-markers-on-react-google-maps%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
0
active
oldest
votes
0
active
oldest
votes
active
oldest
votes
active
oldest
votes
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55041229%2ffreezing-of-browser-when-attempting-to-unmount-4k-markers-on-react-google-maps%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Would it be possible to share a codesandbox?
– Maaz Syed Adeeb
Mar 7 at 10:34
I'll try to make one. But the data and the map api key won't be there.
– Mack
Mar 7 at 10:43
If you can reproduce the problem in a shareable sandbox, then create one. Or else, it won't be of help to answer the question.
– Maaz Syed Adeeb
Mar 7 at 10:48
Okay then no it isn't possible because the google api key is private.
– Mack
Mar 7 at 10:55