update cached information and add a little paragraph about the boroughs

This commit is contained in:
David 2022-03-19 11:45:05 -04:00
parent 2cd3020151
commit 5b2f60992c
3 changed files with 947 additions and 627 deletions

View File

@ -1,29 +1,61 @@
<html><head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<title>Independent Bookstores in New York City - Best Community Bookstores in NYC</title>
<meta name="google-site-verification" content="hEfog9h0E3JQW91ZUZM5ayPb6DND0WbUa2_W8yTIuVw">
<link rel="icon" type="image/png" href="/img/favicon.png">
<link rel="apple-touch-icon" href="/img/social.jpg">
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="x-ua-compatible" content="ie=edge" />
<title>
Independent Bookstores in New York City - Best Community Bookstores in NYC
</title>
<meta
name="google-site-verification"
content="hEfog9h0E3JQW91ZUZM5ayPb6DND0WbUa2_W8yTIuVw"
/>
<link rel="icon" type="image/png" href="/img/favicon.png" />
<link rel="apple-touch-icon" href="/img/social.jpg" />
<script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript" src="js/mustache.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery-scrollTo/2.1.0/jquery.scrollTo.min.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<script src="https://api.mapbox.com/mapbox-gl-js/v0.34.0/mapbox-gl.js"></script>
<link href="https://api.mapbox.com/mapbox-gl-js/v0.34.0/mapbox-gl.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Acme|Lato" rel="stylesheet">
<link media="screen" rel="stylesheet" type="text/css" href="css/site.css">
<meta property="title" name="title" content="Independent Bookstores in New York City - Best Community Bookstores in NYC">
<meta property="description" name="description" content="A guide to and map of every independent bookstore in New York City. We have a full list of community bookstores in NYC with locations and descriptions.">
<meta name="twitter:card" content="summary">
<meta name="twitter:site" content="www.nycbookstores.org">
<meta name="twitter:title" content="NYC Bookstores">
<meta name="twitter:description" content="A Guide To The Many Independent Bookstores Of New York City">
<meta name="twitter:image" content="https://www.nycbookstores.org/img/social.jpg">
<meta property="og:url" content="https://www.nycbookstores.org/">
<meta property="og:title" content="NYC Bookstores">
<meta property="og:description" content="A Guide To The Many Independent Bookstores Of New York City">
<meta property="og:image" content="https://www.nycbookstores.org/img/social.jpg">
<link
href="https://api.mapbox.com/mapbox-gl-js/v0.34.0/mapbox-gl.css"
rel="stylesheet"
/>
<link
href="https://fonts.googleapis.com/css?family=Acme|Lato"
rel="stylesheet"
/>
<link media="screen" rel="stylesheet" type="text/css" href="css/site.css" />
<meta
property="title"
name="title"
content="Independent Bookstores in New York City - Best Community Bookstores in NYC"
/>
<meta
property="description"
name="description"
content="A guide to and map of every independent bookstore in New York City. We have a complete list of community bookstores in NYC with locations and descriptions."
/>
<meta name="twitter:card" content="summary" />
<meta name="twitter:site" content="www.nycbookstores.org" />
<meta name="twitter:title" content="NYC Bookstores" />
<meta
name="twitter:description"
content="A Guide To The Many Independent Bookstores Of New York City"
/>
<meta
name="twitter:image"
content="https://www.nycbookstores.org/img/social.jpg"
/>
<meta property="og:url" content="https://www.nycbookstores.org/" />
<meta property="og:title" content="NYC Bookstores" />
<meta
property="og:description"
content="A Guide To The Many Independent Bookstores Of New York City"
/>
<meta
property="og:image"
content="https://www.nycbookstores.org/img/social.jpg"
/>
</head>
<body>
<div id="wrapper">
@ -32,16 +64,70 @@
<ul class="nav">
<li><h2>The Many Independent Bookstores of New York City</h2></li>
<li><a id="viewInfo">info</a></li>
<li><a href="https://git.yetaga.in/alazyreader/nyc-bookstores/" target="_blank">git</a></li>
<li><a href="https://www.twitter.com/alazyreader" target="_blank">@alazyreader</a></li>
<li>
<a
href="https://git.yetaga.in/alazyreader/nyc-bookstores/"
target="_blank"
>git</a
>
</li>
<li>
<a href="https://www.twitter.com/alazyreader" target="_blank"
>@alazyreader</a
>
</li>
</ul>
</div>
<div class="container">
<div id="map"></div>
<div id="info">
<p>New York City loves its independent bookstores. It <a href="https://www.nytimes.com/2006/10/15/nyregion/thecity/15book.html" target="_blank">eulogizes those that have faded</a> and celebrates when new ventures are launched. And while the historic <a href="https://untappedcities.com/2015/08/26/4th-avenue-the-history-of-nycs-book-row/" target="_blank">Book Row may have passed away in the 80s</a>, there are still many indie bookstores dotting the map. Here, I have attempted to collect all of the currently-open general-interest independent booksellers in NYC. Any store with regular-ish hours (excluding religious booksellers and appointment-only rare book sellers) is included.</p>
<p>The listings here are kept up-to-date to the best of my ability; however, I make no promises about either the accuracy or reliability of the information. If you spot an error, or I&apos;ve missed a shop, please let me know by <a href="mailto:delta.mu.alpha@gmail.com" target="_blank">email</a> or <a href="https://www.twitter.com/alazyreader" target="_blank">twitter</a>. Based on the &quot;<a href="https://github.com/jlord/hack-spots" target="_blank">Hack Spots</a>&quot; website by <a href="https://www.twitter.com/jllord" target="_blank">@jllord</a>.</p>
<p>There are currently <span id="storeCount"></span> stores indexed on this page.</p>
<p>
New York City loves its independent bookstores. It
<a
href="https://www.nytimes.com/2006/10/15/nyregion/thecity/15book.html"
target="_blank"
>eulogizes those that have faded</a
>
and celebrates when new ventures are launched. And while the
historic
<a
href="https://untappedcities.com/2015/08/26/4th-avenue-the-history-of-nycs-book-row/"
target="_blank"
>Book Row may have passed away in the 80s</a
>, there are still many indie bookstores dotting the map, across all
five boroughs. Here, I have attempted to collect all of the
currently-open general-interest independent booksellers in NYC. Any
store with regular-ish hours (excluding religious booksellers and
appointment-only rare book sellers) is included.
</p>
<p>
While Manhattan and Brooklyn still lead the pack, Queens has a
respectable number of stores, and all five boroughs are represented,
with the Bronx and Staten Island both hosting independent stores.
Lower Manhattan has the highest density of booksellers, however.
</p>
<p>
The listings here are kept up-to-date to the best of my ability;
however, I make no promises about either the accuracy or reliability
of the information. If you spot an error, or I&apos;ve missed a
shop, please let me know by
<a href="mailto:delta.mu.alpha@gmail.com" target="_blank">email</a>
or
<a href="https://www.twitter.com/alazyreader" target="_blank"
>twitter</a
>. Orignally based on the &quot;<a
href="https://github.com/jlord/hack-spots"
target="_blank"
>Hack Spots</a
>&quot; website by
<a href="https://www.twitter.com/jllord" target="_blank">@jllord</a>
(although I don&apos;t believe any of the actual underlying code
still survives at this point).
</p>
<p>
There are currently <span id="storeCount">97</span> stores indexed
on this page.
</p>
</div>
<div id="selected"></div>
</div>
@ -51,7 +137,11 @@
<div class="container">
<div id="Stores">
<table>
<tbody><tr><th class="tHeader">Name</th><th class="tHeader">Address</th></tr>
<tbody>
<tr>
<th class="tHeader">Name</th>
<th class="tHeader">Address</th>
</tr>
<tr id class="spotRow">
<td class="name">192 Books</td>
<td>192 10th Ave, New York</td>
@ -84,14 +174,6 @@
<td class="name">Avoid The Day Bookstore &amp; Cafe</td>
<td>99-04 A Rockaway Beach Blvd, Rockaway Park</td>
</tr>
<tr id class="spotRow">
<td class="name">Bankstreet Bookstore</td>
<td>2780 Broadway, New York</td>
</tr>
<tr id class="spotRow">
<td class="name">Ben&apos;s Books</td>
<td>145 Ainslie St, Brooklyn</td>
</tr>
<tr id class="spotRow">
<td class="name">Berl&apos;s Brooklyn Poetry Shop</td>
<td>126A Front St, Brooklyn</td>
@ -108,6 +190,10 @@
<td class="name">Bonnie Slotnick Cookbooks</td>
<td>28 East 2nd St, New York</td>
</tr>
<tr id class="spotRow">
<td class="name">Book Club Bar</td>
<td>197 E 3rd St, New York</td>
</tr>
<tr id class="spotRow">
<td class="name">Book Culture</td>
<td>536 W 112th St, New York</td>
@ -142,7 +228,7 @@
</tr>
<tr id class="spotRow">
<td class="name">Books Of Wonder</td>
<td>18 West 18th St, New York</td>
<td>42 West 17th St, New York</td>
</tr>
<tr id class="spotRow">
<td class="name">Books Of Wonder (Upper West Side)</td>
@ -180,6 +266,10 @@
<td class="name">Community Bookstore</td>
<td>143 7th Ave, Brooklyn</td>
</tr>
<tr id class="spotRow">
<td class="name">Cups and Books</td>
<td>2024 Bedford Ave, Brooklyn</td>
</tr>
<tr id class="spotRow">
<td class="name">Dashwood Books</td>
<td>33 Bond St, New York</td>
@ -193,7 +283,9 @@
<td>99 St. Mark&apos;s Place, New York</td>
</tr>
<tr id class="spotRow">
<td class="name">Every Thing Goes Book Cafe and Neighborhood Stage</td>
<td class="name">
Every Thing Goes Book Cafe and Neighborhood Stage
</td>
<td>208 Bay St, Staten Island</td>
</tr>
<tr id class="spotRow">
@ -205,7 +297,9 @@
<td>686 Fulton St, Brooklyn</td>
</tr>
<tr id class="spotRow">
<td class="name">Greenlight Bookstore (Prospect Lefferts Gardens)</td>
<td class="name">
Greenlight Bookstore (Prospect Lefferts Gardens)
</td>
<td>632 Flatbush Ave, Brooklyn</td>
</tr>
<tr id class="spotRow">
@ -297,8 +391,8 @@
<td>2 W 14th St, New York</td>
</tr>
<tr id class="spotRow">
<td class="name">Pioneer Books</td>
<td>159 Pioneer St, Brooklyn</td>
<td class="name">Pillow-Cat Books</td>
<td>328 East 9th St, New York</td>
</tr>
<tr id class="spotRow">
<td class="name">Posman Books Chelsea Market</td>
@ -345,7 +439,9 @@
<td>939 Lexington Ave, New York</td>
</tr>
<tr id class="spotRow">
<td class="name">Shakespeare &amp; Company (Upper West Side)</td>
<td class="name">
Shakespeare &amp; Company (Upper West Side)
</td>
<td>2020 Broadway, New York</td>
</tr>
<tr id class="spotRow">
@ -364,6 +460,10 @@
<td class="name">Strand Bookstore</td>
<td>828 Broadway, New York</td>
</tr>
<tr id class="spotRow">
<td class="name">Sweet Pickle Books</td>
<td>47 Orchard St, New York</td>
</tr>
<tr id class="spotRow">
<td class="name">Terrace Books</td>
<td>242 Prospect Park West, Brooklyn</td>
@ -394,7 +494,7 @@
</tr>
<tr id class="spotRow">
<td class="name">Three Lives &amp; Company</td>
<td>154 West 10th St, New York</td>
<td>238 West 10th St, New York</td>
</tr>
<tr id class="spotRow">
<td class="name">Topos Bookstore Cafe</td>
@ -432,14 +532,23 @@
<td class="name">Word Up Books</td>
<td>2113 Amsterdam Ave, New York</td>
</tr>
</tbody></table>
<tr id class="spotRow">
<td class="name">Yu and Me Books</td>
<td>44 Mulberry St, New York</td>
</tr>
</tbody>
</table>
</div>
</div>
</div><!-- end wrapper -->
</div>
<!-- end wrapper -->
<script id="Table" type="text/html">
<table>
<tr><th class="tHeader">Name</th><th class="tHeader">Address</th></tr>
<tr>
<th class="tHeader">Name</th>
<th class="tHeader">Address</th>
</tr>
{{#rows}}
<tr id="{{rowNumber}}" class="spotRow">
<td class="name">{{name}}</td>
@ -452,65 +561,75 @@
<script id="selectedStore" type="text/html">
{{#store}}
<h2>{{name}}</h2>
<p class="address">{{address}}<p>
<p class="address">{{city}},NY {{#postcode}} {{postcode}} {{/postcode}}</p>
<p class="address">{{address}}</p>
<p></p>
<p class="address">
{{city}},NY {{#postcode}} {{postcode}} {{/postcode}}
</p>
<p>
<a href="https://maps.google.com/maps?q={{name}} {{address}},{{city}},NY" target="_blank">View in Google Maps</a>
<a
href="https://maps.google.com/maps?q={{name}} {{address}},{{city}},NY"
target="_blank"
>View in Google Maps</a
>
</p>
<ul>
<li>
<span class="store-details">Events:</span> {{events}}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="store-details">Events:</span>
{{events}}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="store-details">Caf&eacute;:</span> {{cafe}}
</li>
{{#website}}
<li><a href='{{website}}' target="_blank">{{website}}</a></li>
<li><a href="{{website}}" target="_blank">{{website}}</a></li>
{{/website}}
</ul>
{{#description}}
<p class="description">{{description}}</p>
{{/description}}
{{/store}}
{{/description}} {{/store}}
</script>
<script>
mapboxgl.accessToken = 'pk.eyJ1IjoiYWxhenlyZWFkZXIiLCJhIjoiY2lucDZhb2JxMHp6MHRxa2pvaTFoOWpuZyJ9.DILGYYxxt7A-A_lHHwp6tQ';
mapboxgl.accessToken =
"pk.eyJ1IjoiYWxhenlyZWFkZXIiLCJhIjoiY2lucDZhb2JxMHp6MHRxa2pvaTFoOWpuZyJ9.DILGYYxxt7A-A_lHHwp6tQ";
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/basic-v9',
container: "map",
style: "mapbox://styles/mapbox/basic-v9",
center: [-73.957292, 40.729071], // arbitrary center point
zoom: 10,
minZoom: 9,
maxZoom: 17,
dragRotate: false
dragRotate: false,
});
var popup = new mapboxgl.Popup({
closeOnClick: false,
closeButton: false
closeButton: false,
});
document.addEventListener('DOMContentLoaded', function() {
$.getJSON('./stores.json', function(data) {
data.sort(
function(a, b) {
document.addEventListener("DOMContentLoaded", function () {
$.getJSON("./stores.json", function (data) {
data.sort(function (a, b) {
var aname = a.name.toLowerCase();
var bname = b.name.toLowerCase();
return aname === bname ? 0 : +(aname > bname) || -1;
}
)
});
$.each(data, function (key, value) {
value.rowNumber = key;
value.slug = slugify(value.name);
});
$('#storeCount').html(data.length);
$("#storeCount").html(data.length);
window.data = data;
loadMap(data);
});
});
window.addEventListener("hashchange", function(e){
updateViewBySlug(e.newURL.split('#')[1]);
}, false);
window.addEventListener(
"hashchange",
function (e) {
updateViewBySlug(e.newURL.split("#")[1]);
},
false
);
function updateHash(slug) {
history.pushState(null, null, "#" + slug);
@ -519,13 +638,13 @@
function slugify(str) {
return str
.toLowerCase()
.replace(/é/g,'e')
.replace(/&/g,' and ')
.replace(/ /g,'-')
.replace(/[']+/g,'')
.replace(/[^\w-]+/g,'-')
.replace(/-+/g,'-')
.replace(/^-|-$/g,'');
.replace(/é/g, "e")
.replace(/&/g, " and ")
.replace(/ /g, "-")
.replace(/[']+/g, "")
.replace(/[^\w-]+/g, "-")
.replace(/-+/g, "-")
.replace(/^-|-$/g, "");
}
function getStoreBySlug(slug) {
@ -552,32 +671,33 @@
function boundingBox(point) {
// add some buffer to a point to give the user some leeway
return [[point.x - 5, point.y - 5], [point.x + 5, point.y + 5]]
return [
[point.x - 5, point.y - 5],
[point.x + 5, point.y + 5],
];
}
function updateSelectedStore(store, pushState = false) {
map.flyTo({ center: [store.long, store.lat] });
popup.setLngLat([store.long, store.lat])
.setHTML(store.name)
.addTo(map);
popup.setLngLat([store.long, store.lat]).setHTML(store.name).addTo(map);
$('#info').hide();
var template = $('#selectedStore').html();
$("#info").hide();
var template = $("#selectedStore").html();
var rendered = Mustache.render(template, { store: store });
$('#selected').html(rendered);
$('#selected').show();
$("#selected").html(rendered);
$("#selected").show();
if (pushState) {
updateHash(store.slug);
}
}
function showInfo(pushState = true) {
$('#selected').hide();
$("#selected").hide();
popup.remove();
$('#info').show();
$("#info").show();
if (pushState) {
updateHash('info');
updateHash("info");
}
}
@ -587,43 +707,47 @@
var points = [];
$.each(data, function (key, value) {
points.push({
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [value.long, value.lat]
type: "Feature",
geometry: {
type: "Point",
coordinates: [value.long, value.lat],
},
"properties": value
properties: value,
});
});
map.on('load', function () {
map.on("load", function () {
map.addLayer({
"id": "stores",
"type": "circle",
"source": {
"type": "geojson",
"data": {
"type": "FeatureCollection",
"features": points
}
id: "stores",
type: "circle",
source: {
type: "geojson",
data: {
type: "FeatureCollection",
features: points,
},
"paint": {
},
paint: {
"circle-radius": 5,
"circle-color": "#B9FCFC",
"circle-stroke-width": 2,
"circle-stroke-color": "#000000"
}
})
map.addControl(new mapboxgl.NavigationControl(), 'top-left');
map.addControl(geolocate, 'top-right');
"circle-stroke-color": "#000000",
},
});
map.addControl(new mapboxgl.NavigationControl(), "top-left");
map.addControl(geolocate, "top-right");
updateViewBySlug(window.location.hash.split("#")[1]);
});
map.on('click', function (e) {
if (!map.getLayer('stores')) { return; }
map.on("click", function (e) {
if (!map.getLayer("stores")) {
return;
}
popup.remove();
// Use queryRenderedFeatures to get features at a click event's point
var features = map.queryRenderedFeatures(boundingBox(e.point), { layers: ['stores'] });
var features = map.queryRenderedFeatures(boundingBox(e.point), {
layers: ["stores"],
});
// fly to the location of the click event
if (features.length) {
var store = features[0];
@ -633,40 +757,60 @@
});
// indicate that the symbols are clickable by changing the cursor style to 'pointer'.
map.on('mousemove', function (e) {
if (!map.getLayer('stores')) { return; }
var features = map.queryRenderedFeatures(boundingBox(e.point), { layers: ['stores'] });
map.getCanvas().style.cursor = features.length ? 'pointer' : '';
map.on("mousemove", function (e) {
if (!map.getLayer("stores")) {
return;
}
var features = map.queryRenderedFeatures(boundingBox(e.point), {
layers: ["stores"],
});
map.getCanvas().style.cursor = features.length ? "pointer" : "";
});
geolocate.on('geolocate', function (e) {
geolocate.on("geolocate", function (e) {
map.setZoom(14);
popup.setLngLat([e.coords.longitude, e.coords.latitude])
.setHTML('Current Location')
popup
.setLngLat([e.coords.longitude, e.coords.latitude])
.setHTML("Current Location")
.addTo(map);
});
var template = $('#Table').html();
var template = $("#Table").html();
var rendered = Mustache.render(template, { rows: data });
$('#Stores').html(rendered);
$("#Stores tbody tr").not(':first').on("click", function() {
$("#Stores").html(rendered);
$("#Stores tbody tr")
.not(":first")
.on("click", function () {
updateSelectedStore(data[$(this)[0].id], true);
$(window).scrollTo($("#selected"), 250, { offset: { top: -15 } });
});
$('#viewInfo').on("click", showInfo);
};
$("#viewInfo").on("click", showInfo);
}
</script>
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
(function (i, s, o, g, r, a, m) {
i["GoogleAnalyticsObject"] = r;
(i[r] =
i[r] ||
function () {
(i[r].q = i[r].q || []).push(arguments);
}),
(i[r].l = 1 * new Date());
(a = s.createElement(o)), (m = s.getElementsByTagName(o)[0]);
a.async = 1;
a.src = g;
m.parentNode.insertBefore(a, m);
})(
window,
document,
"script",
"https://www.google-analytics.com/analytics.js",
"ga"
);
ga('create', 'UA-100418882-1', 'auto');
ga('send', 'pageview');
ga("create", "UA-100418882-1", "auto");
ga("send", "pageview");
</script>
</body></html>
</body>
</html>

View File

@ -1,24 +1,25 @@
const cheerio = require('cheerio');
const mustache = require('./js/mustache.js');
const fs = require('fs');
const stores = require('./stores.json');
const cheerio = require("cheerio");
const mustache = require("./js/mustache.js");
const fs = require("fs");
const stores = require("./stores.json");
fs.readFile('./index.html', function (err, data) {
if (err) { throw err; }
fs.readFile("./index.html", function (err, data) {
if (err) {
throw err;
}
const $ = cheerio.load(data);
stores.sort(
function(a, b) {
stores.sort(function (a, b) {
var aname = a.name.toLowerCase();
var bname = b.name.toLowerCase();
return aname === bname ? 0 : +(aname > bname) || -1;
}
);
});
$('#Stores').html(mustache.render($('#Table').html(), {rows: stores}));
$("#Stores").html(mustache.render($("#Table").html(), { rows: stores }));
$("#storeCount").html(stores.length);
fs.writeFile('./index.html', $.html(), (err) => {
fs.writeFile("./index.html", $.html(), (err) => {
if (err) throw err;
console.log('Default view updated.');
console.log("Default view updated.");
});
});

177
package-lock.json generated
View File

@ -1,8 +1,183 @@
{
"name": "nyc-bookstores",
"version": "1.0.0",
"lockfileVersion": 1,
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "nyc-bookstores",
"version": "1.0.0",
"license": "BSD-3-Clause",
"dependencies": {
"cheerio": "^1.0.0-rc.1"
}
},
"node_modules/@types/node": {
"version": "14.6.4",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.6.4.tgz",
"integrity": "sha512-Wk7nG1JSaMfMpoMJDKUsWYugliB2Vy55pdjLpmLixeyMi7HizW2I/9QoxsPCkXl3dO+ZOVqPumKaDUv5zJu2uQ=="
},
"node_modules/boolbase": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
"integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24="
},
"node_modules/cheerio": {
"version": "1.0.0-rc.3",
"resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.3.tgz",
"integrity": "sha512-0td5ijfUPuubwLUu0OBoe98gZj8C/AA+RW3v67GPlGOrvxWjZmBXiBCRU+I8VEiNyJzjth40POfHiz2RB3gImA==",
"dependencies": {
"css-select": "~1.2.0",
"dom-serializer": "~0.1.1",
"entities": "~1.1.1",
"htmlparser2": "^3.9.1",
"lodash": "^4.15.0",
"parse5": "^3.0.1"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/css-select": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz",
"integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=",
"dependencies": {
"boolbase": "~1.0.0",
"css-what": "2.1",
"domutils": "1.5.1",
"nth-check": "~1.0.1"
}
},
"node_modules/css-what": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz",
"integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==",
"engines": {
"node": "*"
}
},
"node_modules/dom-serializer": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz",
"integrity": "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==",
"dependencies": {
"domelementtype": "^1.3.0",
"entities": "^1.1.1"
}
},
"node_modules/domelementtype": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz",
"integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w=="
},
"node_modules/domhandler": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz",
"integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==",
"dependencies": {
"domelementtype": "1"
}
},
"node_modules/domutils": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz",
"integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=",
"dependencies": {
"dom-serializer": "0",
"domelementtype": "1"
}
},
"node_modules/entities": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz",
"integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w=="
},
"node_modules/htmlparser2": {
"version": "3.10.1",
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz",
"integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==",
"dependencies": {
"domelementtype": "^1.3.1",
"domhandler": "^2.3.0",
"domutils": "^1.5.1",
"entities": "^1.1.1",
"inherits": "^2.0.1",
"readable-stream": "^3.1.1"
}
},
"node_modules/inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"node_modules/lodash": {
"version": "4.17.20",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
"integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA=="
},
"node_modules/nth-check": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz",
"integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==",
"dependencies": {
"boolbase": "~1.0.0"
}
},
"node_modules/parse5": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/parse5/-/parse5-3.0.3.tgz",
"integrity": "sha512-rgO9Zg5LLLkfJF9E6CCmXlSE4UVceloys8JrFqCcHloC3usd/kJCyPDwH2SOlzix2j3xaP9sUX3e8+kvkuleAA==",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/readable-stream": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
"dependencies": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
"util-deprecate": "^1.0.1"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
]
},
"node_modules/string_decoder": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
"dependencies": {
"safe-buffer": "~5.2.0"
}
},
"node_modules/util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
}
},
"dependencies": {
"@types/node": {
"version": "14.6.4",