def webMapFromDictionaryList(features):
    """creates html page with Leaflet based web map displaying a list of point features provided as parameters as a list of dictionaries with name, lat, lon properties"""
    html = """
<!DOCTYPE html>
  <html>
    <head>
      <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
      <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.2.0/leaflet.css" type="text/css" crossorigin="">
      <script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.2.0/leaflet.js" crossorigin=""></script>
      <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>

      <style>
        
        #mapid {
    width: 295px;
    height: 195px;
    border: 1px solid #ccc;
}
        
body {        
margin: 0 !important;
padding: 0 !important;
}

.leaflet-container {
    background: #fff;
}

      </style>

      <script type="text/javascript">
          
        var map;
        var features = """ + str(features) + """;
        
        
        function init() {
          // create map and set center and zoom level
          map = new L.map('mapid', { zoomControl:false });
          map.setView([39.960,-75.210],0);

          // create and add osm tile layer
          var osm = L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
            maxZoom: 19,
            attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
          });
         osm.addTo(map);
         
         
         markers = [];
         
         
         for (var i = 0; i < features.length; i++) {
                 var marker = 
                  new L.CircleMarker([features[i]['lat'], features[i]['lon']],  {
                  radius: 4,
            color: 'blue',
            fillColor: '#bbf',
            fillOpacity: 0.5
        }).addTo(map);
                 markers.push(marker);
                 marker.bindPopup(features[i]['name'] + ' ('+features[i]['lat']+','+features[i]['lon']+')', { maxWidth : 150 });
        }
         
        group = new L.featureGroup(markers);
        map.fitBounds(group.getBounds());
         
      }
            
      </script>
    </head>

  <body onload="init()">
                <div id="mapid">
                </div>      
  </body>
</html>
"""
    return html
