Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save haythemhammami/83e60a81d6066b5652bc57876947c7a3 to your computer and use it in GitHub Desktop.
Save haythemhammami/83e60a81d6066b5652bc57876947c7a3 to your computer and use it in GitHub Desktop.
crawling
This gist exceeds the recommended number of files (~10). To access all files, please clone this gist.
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
<excludeFolder url="file://$MODULE_DIR$/temp" />
<excludeFolder url="file://$MODULE_DIR$/tmp" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/crawlerByTimos.iml" filepath="$PROJECT_DIR$/.idea/crawlerByTimos.iml" />
</modules>
</component>
</project>
[{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"B Resist"},{"marque":"B Resist"}][{"marque":"AGCI"}][][][][][][][][{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"}][{"marque":"MOTTEZ"},{"marque":"CIME"},{"marque":"MOTTEZ"},{"marque":"MOTTEZ"}][{"marque":"VYNEX"},{"marque":"VYNEX"},{"marque":"VYNEX"},{"marque":"VYNEX"},{"marque":"VYNEX"},{"marque":"VYNEX"},{"marque":"VYNEX"},{"marque":"VYNEX"},{"marque":"VYNEX"},{"marque":"VYNEX"},{"marque":"VYNEX"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"}][{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"}][{"marque":"THIRARD"},{"marque":"B RESIST"}][{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"}][{"marque":"AGCI"},{"marque":"AGCI"},{"marque":"AGCI"},{"marque":"AGCI"}][{"marque":"CIME"},{"marque":"CIME"}][{"marque":"AGCI"},{"marque":"AGCI"},{"marque":"AGCI"},{"marque":"AGCI"},{"marque":"AGCI"},{"marque":"AGCI"},{"marque":"AGCI"},{"marque":"AGCI"},{"marque":"AGCI"},{"marque":"AGCI"},{"marque":"AGCI"},{"marque":"AGCI"},{"marque":"AGCI"},{"marque":"AGCI"},{"marque":"AGCI"},{"marque":"AGCI"}][{"marque":".B"},{"marque":".B"},{"marque":".B"}][][{"marque":"B Resist"},{"marque":"THIRARD"},{"marque":"THIRARD"}][{"marque":"B Resist"},{"marque":"B Resist"},{"marque":"THIRARD"},{"marque":"B RESIST"}][][][][{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"}][{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"}][{"marque":"CIME"}][{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"GPI"},{"marque":"CIME"}][{"marque":"THIRARD"}][{"marque":"CHAPUIS"},{"marque":"Scotch"},{"marque":"Scotch"},{"marque":"Scotch"},{"marque":"Scotch"},{"marque":"Scotch"},{"marque":"Scotch"},{"marque":"Scotch"},{"marque":"Scotch"},{"marque":"Scotch"},{"marque":"Scotch"},{"marque":"Scotch"},{"marque":"CHAPUIS"},{"marque":"Scratch Fix"},{"marque":"Scratch Fix"},{"marque":"Scratch Fix"},{"marque":"Scratch Fix"},{"marque":"Scratch Fix"},{"marque":"Scratch Fix"},{"marque":"Scratch Grip"},{"marque":"Scratch Fix"},{"marque":"Scratch Grip"},{"marque":"Scratch Fix"},{"marque":"CIME"}][{"marque":"B RESIST"},{"marque":"B RESIST"},{"marque":"VYNEX"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"}][][{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"}][{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"}][][{"marque":"N/C"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":"1ER"},{"marque":"1ER"}][{"marque":"CIME"},{"marque":"CIME"}][{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"}][{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"}][][{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":"CLASS'INOX"},{"marque":"CLASS'INOX"}][{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"},{"marque":"CHAPUIS"}][][][{"marque":"BAR+"},{"marque":"RENZ"},{"marque":"RENZ"},{"marque":"GAH ALBERTS"},{"marque":"GAH ALBERTS"}][][{"marque":"3M"},{"marque":"3M"},{"marque":"3M"},{"marque":"3M"},{"marque":"3M"},{"marque":"GPI"},{"marque":"3M"},{"marque":"3M"},{"marque":"3M"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"B HOME"},{"marque":"Einhell"}][{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"},{"marque":"BAR+"}][{"marque":"THIRARD"},{"marque":"B Resist"},{"marque":"B Resist"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"B Resist"},{"marque":"THIRARD"},{"marque":"B Resist"},{"marque":"B Resist"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"B RESIST"},{"marque":"B RESIST"},{"marque":"B RESIST"},{"marque":"B RESIST"},{"marque":"B RESIST"},{"marque":"B RESIST"},{"marque":"1ER"},{"marque":"THIRARD"}][{"marque":"B Resist"},{"marque":"B Resist"},{"marque":"B Resist"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"B RESIST"},{"marque":"B RESIST"},{"marque":"B RESIST"},{"marque":"B RESIST"},{"marque":"B RESIST"},{"marque":"B RESIST"},{"marque":"B RESIST"},{"marque":"B RESIST"},{"marque":"B RESIST"},{"marque":"1ER"},{"marque":"1ER"},{"marque":"1ER"},{"marque":"THIRARD"},{"marque":"1ER"},{"marque":"1ER"},{"marque":"1ER"},{"marque":"1ER"}][{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"B Resist"},{"marque":"B Resist"},{"marque":"B Resist"},{"marque":"B Resist"},{"marque":"B Resist"},{"marque":"B Resist"},{"marque":"B Resist"},{"marque":"B Resist"},{"marque":"B Resist"},{"marque":"B Resist"},{"marque":"B Resist"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"B RESIST"},{"marque":"B RESIST"},{"marque":"1ER"},{"marque":"1ER"},{"marque":"1ER"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"}][{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"}][{"marque":".B"},{"marque":"CLASS'INOX"},{"marque":"CLASS'INOX"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"}][{"marque":"THIRARD"},{"marque":"B Resist"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"B Resist"},{"marque":"B Resist"},{"marque":"B Resist"},{"marque":"B Resist"},{"marque":"B Resist"},{"marque":"B Resist"},{"marque":"B Resist"},{"marque":"B Resist"},{"marque":"THIRARD"},{"marque":"1ER"},{"marque":"1ER"},{"marque":"1ER"},{"marque":"1ER"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"THIRARD"},{"marque":"B RESIST"},{"marque":"B RESIST"},{"marque":"B RESIST"},{"marque":"1ER"}][{"marque":"MOTTEZ"},{"marque":"MOTTEZ"},{"marque":"MOTTEZ"},{"marque":"MOTTEZ"},{"marque":"MOTTEZ"},{"marque":"MOTTEZ"},{"marque":"MOTTEZ"},{"marque":"MOTTEZ"},{"marque":"MOTTEZ"}][{"marque":"N/C"},{"marque":"3M"},{"marque":"3M"},{"marque":"GPI"},{"marque":"GPI"},{"marque":"GPI"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"MOTTEZ"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"Home Fix"},{"marque":"Home Fix"},{"marque":"Home Fix"},{"marque":"Home Fix"},{"marque":"Home Fix"},{"marque":"Home Fix"},{"marque":"Home Fix"},{"marque":"Home Fix"},{"marque":"Home Fix"},{"marque":"Home Fix"},{"marque":"Home Fix"},{"marque":"3M"},{"marque":"3M"},{"marque":"MOTTEZ"},{"marque":"MOTTEZ"},{"marque":"MOTTEZ"},{"marque":"MOTTEZ"},{"marque":"MOTTEZ"},{"marque":"MOTTEZ"},{"marque":"MOTTEZ"},{"marque":"MOTTEZ"},{"marque":"MOTTEZ"},{"marque":"MOTTEZ"},{"marque":"MOTTEZ"},{"marque":"MOTTEZ"},{"marque":"MOTTEZ"},{"marque":"MOTTEZ"},{"marque":"MOTTEZ"},{"marque":"MOTTEZ"},{"marque":"MOTTEZ"},{"marque":"MOTTEZ"},{"marque":"MOTTEZ"},{"marque":"MOTTEZ"},{"marque":"MOTTEZ"},{"marque":"MOTTEZ"},{"marque":"MOTTEZ"},{"marque":"MOTTEZ"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"MOTTEZ"},{"marque":"MOTTEZ"},{"marque":"MOTTEZ"},{"marque":"MOTTEZ"},{"marque":"MOTTEZ"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"},{"marque":"LE CROCHET FRANCAIS"}][{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"}][{"marque":"1ER"},{"marque":"1ER"},{"marque":"1ER"},{"marque":"1ER"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"}][{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"}][][{"marque":"LEGRAND"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"ROCKET"},{"marque":"ROCKET"},{"marque":"ROCKET"},{"marque":"ROCKET"},{"marque":"ROCKET"},{"marque":"ROCKET"},{"marque":"ROCKET"},{"marque":"ROCKET"},{"marque":"ROCKET"},{"marque":"ROCKET"},{"marque":"ROCKET"},{"marque":"ROCKET"},{"marque":"ROCKET"},{"marque":"ROCKET"},{"marque":"ROCKET"},{"marque":"ROCKET"},{"marque":"ROCKET"},{"marque":"ROCKET"},{"marque":"ROCKET"},{"marque":"ROCKET"},{"marque":"ROCKET"},{"marque":"ROCKET"},{"marque":"ROCKET"},{"marque":"ROCKET"},{"marque":"ROCKET"},{"marque":"ROCKET"},{"marque":"ROCKET"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":"CLASS'INOX"},{"marque":"CLASS'INOX"},{"marque":"CLASS'INOX"},{"marque":"CLASS'INOX"},{"marque":"CLASS'INOX"},{"marque":"CLASS'INOX"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":".B"},{"marque":"Scell it"}][{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"MR BRICOLAGE"},{"marque":"MR BRICOLAGE"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"Mr Bricolage"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"Chainey"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"Chainey"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"Chainey"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"Chainey"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"},{"marque":"B BEAUTY"}][{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":".B"},{"marque":"B RESIST"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"RED HEAD"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"RED HEAD"},{"marque":"WOLFCRAFT"},{"marque":"WOLFCRAFT"},{"marque":"WOLFCRAFT"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"FISCHER"},{"marque":"Scell it"}][{"marque":"Caujolle"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"},{"marque":"CIME"}][{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"},{"marque":"ARCANSAS"}][{"marque":"N/C"},{"marque":"RENZ"},{"marque":"DECAYEUX"},{"marque":"CKW"},{"marque":"SIGNEE"},{"marque":"SIGNEE"},{"marque":"SIGNEE"},{"marque":"SIGNEE"},{"marque":"SIGNEE"},{"marque":"SIGNEE"},{"marque":"SIGNEE"},{"marque":"SIGNEE"},{"marque":"SIGNEE"},{"marque":"SIGNEE"},{"marque":"SIGNEE"},{"marque":"SIGNEE"},{"marque":"SIGNEE"},{"marque":"SIGNEE"},{"marque":"SIGNEE"},{"marque":"SIGNEE"},{"marque":"SIGNEE"},{"marque":"SIGNEE"},{"marque":"SIGNEE"},{"marque":"SIGNEE"},{"marque":"SIGNEE"},{"marque":"SIGNEE"},{"marque":"SIGNEE"},{"marque":"SIGNEE"},{"marque":"SIGNEE"},{"marque":"SIGNEE"},{"marque":"SIGNEE"},{"marque":"SIGNEE"},{"marque":"SIGNEE"},{"marque":"SIGNEE"},{"marque":"SIGNEE"},{"marque":"SIGNEE"},{"marque":"SIGNEE"},{"marque":"RENZ"},{"marque":"RENZ"},{"marque":"RENZ"},{"marque":"RENZ"},{"marque":"RENZ"},{"marque":"RENZ"},{"marque":"RENZ"},{"marque":"RENZ"},{"marque":"RENZ"},{"marque":"RENZ"},{"marque":"RENZ"},{"marque":"RENZ"},{"marque":"RENZ"},{"marque":"RENZ"},{"marque":"RENZ"},{"marque":"RENZ"},{"marque":"RENZ"},{"marque":"RENZ"},{"marque":"RENZ"},{"marque":"RENZ"},{"marque":"RENZ"},{"marque":"RENZ"},{"marque":"RENZ"},{"marque":"RENZ"},{"marque":"RENZ"},{"marque":"RENZ"},{"marque":"RENZ"},{"marque":"RENZ"},{"marque":"RENZ"},{"marque":"RENZ"},{"marque":"SIGNEE"},{"marque":"SIGNEE"},{"marque":"SIGNEE"},{"marque":"DECAYEUX"},{"marque":"DECAYEUX"},{"marque":"DECAYEUX"},{"marque":"DECAYEUX"},{"marque":"DECAYEUX"},{"marque":"DECAYEUX"},{"marque":"DECAYEUX"},{"marque":"DECAYEUX"},{"marque":"DECAYEUX"},{"marque":"DECAYEUX"},{"marque":"DECAYEUX"},{"marque":"DECAYEUX"},{"marque":"DECAYEUX"},{"marque":"DECAYEUX"},{"marque":"DECAYEUX"},{"marque":"DECAYEUX"},{"marque":"DECAYEUX"},{"marque":"DECAYEUX"},{"marque":"DECAYEUX"},{"marque":"DECAYEUX"},{"marque":"DECAYEUX"},{"marque":"DECAYEUX"},{"marque":"DECAYEUX"},{"marque":"DECAYEUX"},{"marque":"DECAYEUX"},{"marque":"DECAYEUX"},{"marque":"DECAYEUX"},{"marque":"DECAYEUX"},{"marque":"DECAYEUX"},{"marque":"DECAYEUX"},{"marque":"DECAYEUX"},{"marque":"DECAYEUX"},{"marque":"DECAYEUX"},{"marque":"DECAYEUX"},{"marque":"DECAYEUX"},{"marque":"DECAYEUX"},{"marque":"DECAYEUX"},{"marque":"RENZ"},{"marque":"RENZ"},{"marque":"RENZ"},{"marque":"RENZ"},{"marque":"RENZ"},{"marque":"RENZ"},{"marque":"RENZ"},{"marque":"RENZ"},{"marque":"RENZ"},{"marque":"RENZ"},{"marque":"RENZ"},{"marque":"RENZ"},{"marque":"RENZ"},{"marque":"RENZ"},{"marque":"DECAYEUX"},{"marque":"DECAYEUX"},{"marque":"DECAYEUX"},{"marque":"SIGNEE"},{"marque":"SIGNEE"},{"marque":"SIGNEE"},{"marque":"SIGNEE"},{"marque":"SIGNEE"},{"marque":"SIGNEE"},{"marque":"SIGNEE"},{"marque":"SIGNEE"},{"marque":"SIGNEE"},{"marque":"SIGNEE"},{"marque":"SIGNEE"},{"marque":"SIGNEE"},{"marque":"SIGNEE"},{"marque":"SIGNEE"},{"marque":"SIGNEE"},{"marque":"SIGNEE"},{"marque":"SIGNEE"},{"marque":"SIGNEE"},{"marque":"SIGNEE"},{"marque":"SIGNEE"}]
titre :John Wick 2titre :Cinquante nuances plus sombrestitre :Lego Batman, le filmtitre :Splittitre :Tu ne tueras pointtitre :Avengers: Infinity Wartitre :Premier contacttitre :La La Landtitre :Les Trollstitre :Liontitre :La Grande Murailletitre :Logantitre :Manchester by the Seatitre :John Wicktitre :A Cure for Lifetitre :Moonlighttitre :La Belle et la Bêtetitre :Nocturnal Animalstitre :Doctor Strangetitre :Ghost in the Shelltitre :Les figures de l'ombretitre :Underworld: Blood Warstitre :Pirates des Caraïbes - La vengeance de Salazartitre :Goldtitre :Passengerstitre :Cinquante nuances de Greytitre :Alliéstitre :The Bad Batchtitre :Thor: Ragnaröktitre :Get Outtitre :Justice League: 1ère partietitre :Vaiana, la légende du bout du mondetitre :Le Cercle: Ringstitre :La fille du traintitre :T2 Trainspottingtitre :Ittitre :Les gardiens de la galaxie 2titre :Power Rangerstitre :Suicide Squadtitre :Resident Evil: Chapitre finaltitre :Mr. Wolfftitre :Fist Fighttitre :Tous en scènetitre :Fencestitre :Everything, Everythingtitre :The Edge of Seventeentitre :Comancheriatitre :The Housetitre :Alien: Covenanttitre :Le fondateurtitre :Silencetitre :Kong: Skull Islandtitre :xXx: Reactivatedtitre :Les Proiestitre :Les animaux fantastiquestitre :Les sept mercenairestitre :Transformers: The Last Knighttitre :Rogue Onetitre :L'espace qui nous séparetitre :Don't Hang Uptitre :Quelques minutes après minuittitre :Star Wars: The Last Jedititre :Le monde de Dorytitre :Mes vies de chientitre :Jackietitre :The Circletitre :Spider-Man: Homecomingtitre :Trainspottingtitre :Miss Peregrine et les enfants particulierstitre :Jack Reacher: Never Go Backtitre :Colossaltitre :Fast & Furious 8titre :Deepwatertitre :Aftermathtitre :Captain Fantastictitre :Baywatchtitre :Girlfriend's Daytitre :La Tour sombretitre :Eternal Sunshine of the Spotless Mindtitre :Agents presque secretstitre :Deantitre :Moi, Daniel Blaketitre :Infernotitre :Un héros ordinairetitre :Deadpooltitre :Titanictitre :Les gardiens de la galaxietitre :Live by Nighttitre :The Nice Guystitre :Batman v Superman: L'aube de la justicetitre :Love Actuallytitre :Captain America: Civil Wartitre :Zootopietitre :The LEGO NINJAGO Movietitre :Les évadéstitre :Comme des bêtestitre :Le chasseur et la reine des glacestitre :Traque à Bostontitre :Wonder Womantitre :La grande aventure Legotitre :Logantitre :Moonlighttitre :Get Outtitre :La La Landtitre :Alien: Covenanttitre :Manchester by the Seatitre :Pirates of the Caribbean: Dead Men Tell No Talestitre :Hacksaw Ridgetitre :Beauty and the Beasttitre :Liontitre :John Wick: Chapter 2titre :Guardians of the Galaxy Vol. 2titre :Kong: Skull Islandtitre :Arrivaltitre :Fantastic Beasts and Where to Find Themtitre :Moanatitre :Splittitre :Hidden Figurestitre :Passengerstitre :Fifty Shades Darkertitre :Nocturnal Animalstitre :Fencestitre :Titanictitre :Sausage Partytitre :Trollstitre :Collateral Beautytitre :Doctor Strangetitre :The Great Walltitre :The Shacktitre :The LEGO Batman Movietitre :Justice Leaguetitre :Power Rangerstitre :A Cure for Wellnesstitre :Suicide Squadtitre :Thor: Ragnaröktitre :Hell or High Watertitre :John Wicktitre :I Don't Feel at Home in This World Anymoretitre :Singtitre :Before I Falltitre :Alliedtitre :T2 Trainspottingtitre :Captain Fantastictitre :Jackietitre :Ittitre :Silencetitre :Mike and Dave Need Wedding Datestitre :Ghost in the Shelltitre :Assassin's Creedtitre :Fist Fighttitre :The Girl on the Traintitre :Avengers: Infinity Wartitre :Brighttitre :Forushandetitre :X-Men: Apocalypsetitre :Zootopiatitre :Alienstitre :The Fate of the Furioustitre :Resident Evil: The Final Chaptertitre :Rogue Onetitre :The Accountanttitre :Table 19titre :Elletitre :Star Wars: The Last Jedititre :Deadpooltitre :Spider-Man: Homecomingtitre :Twistertitre :Fifty Shades of Greytitre :The Legend of Tarzantitre :Collidetitre :Trainspottingtitre :The Wolverinetitre :The Promisetitre :Prometheustitre :The Dark Towertitre :The Edge of Seventeentitre :The Helptitre :Wonder Womantitre :Guardians of the Galaxytitre :Lifetitre :Man Downtitre :Interstellartitre :The Magnificent Seventitre :Roomtitre :King Arthur: Legend of the Swordtitre :Dunkirktitre :Underworld: Blood Warstitre :The Levellingtitre :Bonnie and Clydetitre :Goldtitre :Batman v Superman: Dawn of Justicetitre :Deepwater Horizontitre :Weird Sciencetitre :The Shawshank Redemptiontitre :Transformers: The Last Knighttitre :Patriots Daytitre :X-Men Origins: Wolverinetitre :The Jungle Booktitre :Whiplashtitre :Song to Song
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../har-validator/bin/har-validator" "$@"
ret=$?
else
node "$basedir/../har-validator/bin/har-validator" "$@"
ret=$?
fi
exit $ret
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\har-validator\bin\har-validator" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\har-validator\bin\har-validator" %*
)
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../sshpk/bin/sshpk-conv" "$@"
ret=$?
else
node "$basedir/../sshpk/bin/sshpk-conv" "$@"
ret=$?
fi
exit $ret
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\sshpk\bin\sshpk-conv" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\sshpk\bin\sshpk-conv" %*
)
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../sshpk/bin/sshpk-sign" "$@"
ret=$?
else
node "$basedir/../sshpk/bin/sshpk-sign" "$@"
ret=$?
fi
exit $ret
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\sshpk\bin\sshpk-sign" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\sshpk\bin\sshpk-sign" %*
)
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../sshpk/bin/sshpk-verify" "$@"
ret=$?
else
node "$basedir/../sshpk/bin/sshpk-verify" "$@"
ret=$?
fi
exit $ret
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\sshpk\bin\sshpk-verify" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\sshpk\bin\sshpk-verify" %*
)
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../uuid/bin/uuid" "$@"
ret=$?
else
node "$basedir/../uuid/bin/uuid" "$@"
ret=$?
fi
exit $ret
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\uuid\bin\uuid" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\uuid\bin\uuid" %*
)
'use strict';
module.exports = function () {
return /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-PRZcf-nqry=><]/g;
};
The MIT License (MIT)
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
{
"_args": [
[
{
"raw": "ansi-regex@^2.0.0",
"scope": null,
"escapedName": "ansi-regex",
"name": "ansi-regex",
"rawSpec": "^2.0.0",
"spec": ">=2.0.0 <3.0.0",
"type": "range"
},
"F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\has-ansi"
]
],
"_from": "ansi-regex@>=2.0.0 <3.0.0",
"_id": "ansi-regex@2.1.1",
"_inCache": true,
"_location": "/ansi-regex",
"_nodeVersion": "0.10.32",
"_npmOperationalInternal": {
"host": "packages-18-east.internal.npmjs.com",
"tmp": "tmp/ansi-regex-2.1.1.tgz_1484363378013_0.4482989883981645"
},
"_npmUser": {
"name": "qix",
"email": "i.am.qix@gmail.com"
},
"_npmVersion": "2.14.2",
"_phantomChildren": {},
"_requested": {
"raw": "ansi-regex@^2.0.0",
"scope": null,
"escapedName": "ansi-regex",
"name": "ansi-regex",
"rawSpec": "^2.0.0",
"spec": ">=2.0.0 <3.0.0",
"type": "range"
},
"_requiredBy": [
"/has-ansi",
"/strip-ansi"
],
"_resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
"_shasum": "c3b33ab5ee360d86e0e628f0468ae7ef27d654df",
"_shrinkwrap": null,
"_spec": "ansi-regex@^2.0.0",
"_where": "F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\has-ansi",
"author": {
"name": "Sindre Sorhus",
"email": "sindresorhus@gmail.com",
"url": "sindresorhus.com"
},
"bugs": {
"url": "https://github.com/chalk/ansi-regex/issues"
},
"dependencies": {},
"description": "Regular expression for matching ANSI escape codes",
"devDependencies": {
"ava": "0.17.0",
"xo": "0.16.0"
},
"directories": {},
"dist": {
"shasum": "c3b33ab5ee360d86e0e628f0468ae7ef27d654df",
"tarball": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz"
},
"engines": {
"node": ">=0.10.0"
},
"files": [
"index.js"
],
"gitHead": "7c908e7b4eb6cd82bfe1295e33fdf6d166c7ed85",
"homepage": "https://github.com/chalk/ansi-regex#readme",
"keywords": [
"ansi",
"styles",
"color",
"colour",
"colors",
"terminal",
"console",
"cli",
"string",
"tty",
"escape",
"formatting",
"rgb",
"256",
"shell",
"xterm",
"command-line",
"text",
"regex",
"regexp",
"re",
"match",
"test",
"find",
"pattern"
],
"license": "MIT",
"maintainers": [
{
"name": "qix",
"email": "i.am.qix@gmail.com"
},
{
"name": "sindresorhus",
"email": "sindresorhus@gmail.com"
}
],
"name": "ansi-regex",
"optionalDependencies": {},
"readme": "ERROR: No README data found!",
"repository": {
"type": "git",
"url": "git+https://github.com/chalk/ansi-regex.git"
},
"scripts": {
"test": "xo && ava --verbose",
"view-supported": "node fixtures/view-codes.js"
},
"version": "2.1.1",
"xo": {
"rules": {
"guard-for-in": 0,
"no-loop-func": 0
}
}
}

ansi-regex Build Status

Regular expression for matching ANSI escape codes

Install

$ npm install --save ansi-regex

Usage

const ansiRegex = require('ansi-regex');

ansiRegex().test('\u001b[4mcake\u001b[0m');
//=> true

ansiRegex().test('cake');
//=> false

'\u001b[4mcake\u001b[0m'.match(ansiRegex());
//=> ['\u001b[4m', '\u001b[0m']

FAQ

Why do you test for codes not in the ECMA 48 standard?

Some of the codes we run as a test are codes that we acquired finding various lists of non-standard or manufacturer specific codes. If I recall correctly, we test for both standard and non-standard codes, as most of them follow the same or similar format and can be safely matched in strings without the risk of removing actual string content. There are a few non-standard control codes that do not follow the traditional format (i.e. they end in numbers) thus forcing us to exclude them from the test because we cannot reliably match them.

On the historical side, those ECMA standards were established in the early 90's whereas the VT100, for example, was designed in the mid/late 70's. At that point in time, control codes were still pretty ungoverned and engineers used them for a multitude of things, namely to activate hardware ports that may have been proprietary. Somewhere else you see a similar 'anarchy' of codes is in the x86 architecture for processors; there are a ton of "interrupts" that can mean different things on certain brands of processors, most of which have been phased out.

License

MIT © Sindre Sorhus

'use strict';
function assembleStyles () {
var styles = {
modifiers: {
reset: [0, 0],
bold: [1, 22], // 21 isn't widely supported and 22 does the same thing
dim: [2, 22],
italic: [3, 23],
underline: [4, 24],
inverse: [7, 27],
hidden: [8, 28],
strikethrough: [9, 29]
},
colors: {
black: [30, 39],
red: [31, 39],
green: [32, 39],
yellow: [33, 39],
blue: [34, 39],
magenta: [35, 39],
cyan: [36, 39],
white: [37, 39],
gray: [90, 39]
},
bgColors: {
bgBlack: [40, 49],
bgRed: [41, 49],
bgGreen: [42, 49],
bgYellow: [43, 49],
bgBlue: [44, 49],
bgMagenta: [45, 49],
bgCyan: [46, 49],
bgWhite: [47, 49]
}
};
// fix humans
styles.colors.grey = styles.colors.gray;
Object.keys(styles).forEach(function (groupName) {
var group = styles[groupName];
Object.keys(group).forEach(function (styleName) {
var style = group[styleName];
styles[styleName] = group[styleName] = {
open: '\u001b[' + style[0] + 'm',
close: '\u001b[' + style[1] + 'm'
};
});
Object.defineProperty(styles, groupName, {
value: group,
enumerable: false
});
});
return styles;
}
Object.defineProperty(module, 'exports', {
enumerable: true,
get: assembleStyles
});
The MIT License (MIT)
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
{
"_args": [
[
{
"raw": "ansi-styles@^2.2.1",
"scope": null,
"escapedName": "ansi-styles",
"name": "ansi-styles",
"rawSpec": "^2.2.1",
"spec": ">=2.2.1 <3.0.0",
"type": "range"
},
"F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\chalk"
]
],
"_from": "ansi-styles@>=2.2.1 <3.0.0",
"_id": "ansi-styles@2.2.1",
"_inCache": true,
"_location": "/ansi-styles",
"_nodeVersion": "4.3.0",
"_npmOperationalInternal": {
"host": "packages-12-west.internal.npmjs.com",
"tmp": "tmp/ansi-styles-2.2.1.tgz_1459197317833_0.9694824463222176"
},
"_npmUser": {
"name": "sindresorhus",
"email": "sindresorhus@gmail.com"
},
"_npmVersion": "3.8.3",
"_phantomChildren": {},
"_requested": {
"raw": "ansi-styles@^2.2.1",
"scope": null,
"escapedName": "ansi-styles",
"name": "ansi-styles",
"rawSpec": "^2.2.1",
"spec": ">=2.2.1 <3.0.0",
"type": "range"
},
"_requiredBy": [
"/chalk"
],
"_resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
"_shasum": "b432dd3358b634cf75e1e4664368240533c1ddbe",
"_shrinkwrap": null,
"_spec": "ansi-styles@^2.2.1",
"_where": "F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\chalk",
"author": {
"name": "Sindre Sorhus",
"email": "sindresorhus@gmail.com",
"url": "sindresorhus.com"
},
"bugs": {
"url": "https://github.com/chalk/ansi-styles/issues"
},
"dependencies": {},
"description": "ANSI escape codes for styling strings in the terminal",
"devDependencies": {
"mocha": "*"
},
"directories": {},
"dist": {
"shasum": "b432dd3358b634cf75e1e4664368240533c1ddbe",
"tarball": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz"
},
"engines": {
"node": ">=0.10.0"
},
"files": [
"index.js"
],
"gitHead": "95c59b23be760108b6530ca1c89477c21b258032",
"homepage": "https://github.com/chalk/ansi-styles#readme",
"keywords": [
"ansi",
"styles",
"color",
"colour",
"colors",
"terminal",
"console",
"cli",
"string",
"tty",
"escape",
"formatting",
"rgb",
"256",
"shell",
"xterm",
"log",
"logging",
"command-line",
"text"
],
"license": "MIT",
"maintainers": [
{
"name": "sindresorhus",
"email": "sindresorhus@gmail.com"
}
],
"name": "ansi-styles",
"optionalDependencies": {},
"readme": "ERROR: No README data found!",
"repository": {
"type": "git",
"url": "git+https://github.com/chalk/ansi-styles.git"
},
"scripts": {
"test": "mocha"
},
"version": "2.2.1"
}

ansi-styles Build Status

ANSI escape codes for styling strings in the terminal

You probably want the higher-level chalk module for styling your strings.

Install

$ npm install --save ansi-styles

Usage

var ansi = require('ansi-styles');

console.log(ansi.green.open + 'Hello world!' + ansi.green.close);

API

Each style has an open and close property.

Styles

Modifiers

  • reset
  • bold
  • dim
  • italic (not widely supported)
  • underline
  • inverse
  • hidden
  • strikethrough (not widely supported)

Colors

  • black
  • red
  • green
  • yellow
  • blue
  • magenta
  • cyan
  • white
  • gray

Background colors

  • bgBlack
  • bgRed
  • bgGreen
  • bgYellow
  • bgBlue
  • bgMagenta
  • bgCyan
  • bgWhite

Advanced usage

By default you get a map of styles, but the styles are also available as groups. They are non-enumerable so they don't show up unless you access them explicitly. This makes it easier to expose only a subset in a higher-level module.

  • ansi.modifiers
  • ansi.colors
  • ansi.bgColors
Example
console.log(ansi.colors.green.open);

License

MIT © Sindre Sorhus

language: node_js
node_js:
- 0.8
- 0.10
// Copyright 2011 Mark Cavage <mcavage@gmail.com> All rights reserved.
module.exports = {
newInvalidAsn1Error: function(msg) {
var e = new Error();
e.name = 'InvalidAsn1Error';
e.message = msg || '';
return e;
}
};
// Copyright 2011 Mark Cavage <mcavage@gmail.com> All rights reserved.
var errors = require('./errors');
var types = require('./types');
var Reader = require('./reader');
var Writer = require('./writer');
///--- Exports
module.exports = {
Reader: Reader,
Writer: Writer
};
for (var t in types) {
if (types.hasOwnProperty(t))
module.exports[t] = types[t];
}
for (var e in errors) {
if (errors.hasOwnProperty(e))
module.exports[e] = errors[e];
}
// Copyright 2011 Mark Cavage <mcavage@gmail.com> All rights reserved.
var assert = require('assert');
var ASN1 = require('./types');
var errors = require('./errors');
///--- Globals
var newInvalidAsn1Error = errors.newInvalidAsn1Error;
///--- API
function Reader(data) {
if (!data || !Buffer.isBuffer(data))
throw new TypeError('data must be a node Buffer');
this._buf = data;
this._size = data.length;
// These hold the "current" state
this._len = 0;
this._offset = 0;
}
Object.defineProperty(Reader.prototype, 'length', {
enumerable: true,
get: function () { return (this._len); }
});
Object.defineProperty(Reader.prototype, 'offset', {
enumerable: true,
get: function () { return (this._offset); }
});
Object.defineProperty(Reader.prototype, 'remain', {
get: function () { return (this._size - this._offset); }
});
Object.defineProperty(Reader.prototype, 'buffer', {
get: function () { return (this._buf.slice(this._offset)); }
});
/**
* Reads a single byte and advances offset; you can pass in `true` to make this
* a "peek" operation (i.e., get the byte, but don't advance the offset).
*
* @param {Boolean} peek true means don't move offset.
* @return {Number} the next byte, null if not enough data.
*/
Reader.prototype.readByte = function(peek) {
if (this._size - this._offset < 1)
return null;
var b = this._buf[this._offset] & 0xff;
if (!peek)
this._offset += 1;
return b;
};
Reader.prototype.peek = function() {
return this.readByte(true);
};
/**
* Reads a (potentially) variable length off the BER buffer. This call is
* not really meant to be called directly, as callers have to manipulate
* the internal buffer afterwards.
*
* As a result of this call, you can call `Reader.length`, until the
* next thing called that does a readLength.
*
* @return {Number} the amount of offset to advance the buffer.
* @throws {InvalidAsn1Error} on bad ASN.1
*/
Reader.prototype.readLength = function(offset) {
if (offset === undefined)
offset = this._offset;
if (offset >= this._size)
return null;
var lenB = this._buf[offset++] & 0xff;
if (lenB === null)
return null;
if ((lenB & 0x80) == 0x80) {
lenB &= 0x7f;
if (lenB == 0)
throw newInvalidAsn1Error('Indefinite length not supported');
if (lenB > 4)
throw newInvalidAsn1Error('encoding too long');
if (this._size - offset < lenB)
return null;
this._len = 0;
for (var i = 0; i < lenB; i++)
this._len = (this._len << 8) + (this._buf[offset++] & 0xff);
} else {
// Wasn't a variable length
this._len = lenB;
}
return offset;
};
/**
* Parses the next sequence in this BER buffer.
*
* To get the length of the sequence, call `Reader.length`.
*
* @return {Number} the sequence's tag.
*/
Reader.prototype.readSequence = function(tag) {
var seq = this.peek();
if (seq === null)
return null;
if (tag !== undefined && tag !== seq)
throw newInvalidAsn1Error('Expected 0x' + tag.toString(16) +
': got 0x' + seq.toString(16));
var o = this.readLength(this._offset + 1); // stored in `length`
if (o === null)
return null;
this._offset = o;
return seq;
};
Reader.prototype.readInt = function() {
return this._readTag(ASN1.Integer);
};
Reader.prototype.readBoolean = function() {
return (this._readTag(ASN1.Boolean) === 0 ? false : true);
};
Reader.prototype.readEnumeration = function() {
return this._readTag(ASN1.Enumeration);
};
Reader.prototype.readString = function(tag, retbuf) {
if (!tag)
tag = ASN1.OctetString;
var b = this.peek();
if (b === null)
return null;
if (b !== tag)
throw newInvalidAsn1Error('Expected 0x' + tag.toString(16) +
': got 0x' + b.toString(16));
var o = this.readLength(this._offset + 1); // stored in `length`
if (o === null)
return null;
if (this.length > this._size - o)
return null;
this._offset = o;
if (this.length === 0)
return retbuf ? new Buffer(0) : '';
var str = this._buf.slice(this._offset, this._offset + this.length);
this._offset += this.length;
return retbuf ? str : str.toString('utf8');
};
Reader.prototype.readOID = function(tag) {
if (!tag)
tag = ASN1.OID;
var b = this.readString(tag, true);
if (b === null)
return null;
var values = [];
var value = 0;
for (var i = 0; i < b.length; i++) {
var byte = b[i] & 0xff;
value <<= 7;
value += byte & 0x7f;
if ((byte & 0x80) == 0) {
values.push(value);
value = 0;
}
}
value = values.shift();
values.unshift(value % 40);
values.unshift((value / 40) >> 0);
return values.join('.');
};
Reader.prototype._readTag = function(tag) {
assert.ok(tag !== undefined);
var b = this.peek();
if (b === null)
return null;
if (b !== tag)
throw newInvalidAsn1Error('Expected 0x' + tag.toString(16) +
': got 0x' + b.toString(16));
var o = this.readLength(this._offset + 1); // stored in `length`
if (o === null)
return null;
if (this.length > 4)
throw newInvalidAsn1Error('Integer too long: ' + this.length);
if (this.length > this._size - o)
return null;
this._offset = o;
var fb = this._buf[this._offset];
var value = 0;
for (var i = 0; i < this.length; i++) {
value <<= 8;
value |= (this._buf[this._offset++] & 0xff);
}
if ((fb & 0x80) == 0x80 && i !== 4)
value -= (1 << (i * 8));
return value >> 0;
};
///--- Exported API
module.exports = Reader;
// Copyright 2011 Mark Cavage <mcavage@gmail.com> All rights reserved.
module.exports = {
EOC: 0,
Boolean: 1,
Integer: 2,
BitString: 3,
OctetString: 4,
Null: 5,
OID: 6,
ObjectDescriptor: 7,
External: 8,
Real: 9, // float
Enumeration: 10,
PDV: 11,
Utf8String: 12,
RelativeOID: 13,
Sequence: 16,
Set: 17,
NumericString: 18,
PrintableString: 19,
T61String: 20,
VideotexString: 21,
IA5String: 22,
UTCTime: 23,
GeneralizedTime: 24,
GraphicString: 25,
VisibleString: 26,
GeneralString: 28,
UniversalString: 29,
CharacterString: 30,
BMPString: 31,
Constructor: 32,
Context: 128
};
// Copyright 2011 Mark Cavage <mcavage@gmail.com> All rights reserved.
var assert = require('assert');
var ASN1 = require('./types');
var errors = require('./errors');
///--- Globals
var newInvalidAsn1Error = errors.newInvalidAsn1Error;
var DEFAULT_OPTS = {
size: 1024,
growthFactor: 8
};
///--- Helpers
function merge(from, to) {
assert.ok(from);
assert.equal(typeof(from), 'object');
assert.ok(to);
assert.equal(typeof(to), 'object');
var keys = Object.getOwnPropertyNames(from);
keys.forEach(function(key) {
if (to[key])
return;
var value = Object.getOwnPropertyDescriptor(from, key);
Object.defineProperty(to, key, value);
});
return to;
}
///--- API
function Writer(options) {
options = merge(DEFAULT_OPTS, options || {});
this._buf = new Buffer(options.size || 1024);
this._size = this._buf.length;
this._offset = 0;
this._options = options;
// A list of offsets in the buffer where we need to insert
// sequence tag/len pairs.
this._seq = [];
}
Object.defineProperty(Writer.prototype, 'buffer', {
get: function () {
if (this._seq.length)
throw new InvalidAsn1Error(this._seq.length + ' unended sequence(s)');
return (this._buf.slice(0, this._offset));
}
});
Writer.prototype.writeByte = function(b) {
if (typeof(b) !== 'number')
throw new TypeError('argument must be a Number');
this._ensure(1);
this._buf[this._offset++] = b;
};
Writer.prototype.writeInt = function(i, tag) {
if (typeof(i) !== 'number')
throw new TypeError('argument must be a Number');
if (typeof(tag) !== 'number')
tag = ASN1.Integer;
var sz = 4;
while ((((i & 0xff800000) === 0) || ((i & 0xff800000) === 0xff800000 >> 0)) &&
(sz > 1)) {
sz--;
i <<= 8;
}
if (sz > 4)
throw new InvalidAsn1Error('BER ints cannot be > 0xffffffff');
this._ensure(2 + sz);
this._buf[this._offset++] = tag;
this._buf[this._offset++] = sz;
while (sz-- > 0) {
this._buf[this._offset++] = ((i & 0xff000000) >>> 24);
i <<= 8;
}
};
Writer.prototype.writeNull = function() {
this.writeByte(ASN1.Null);
this.writeByte(0x00);
};
Writer.prototype.writeEnumeration = function(i, tag) {
if (typeof(i) !== 'number')
throw new TypeError('argument must be a Number');
if (typeof(tag) !== 'number')
tag = ASN1.Enumeration;
return this.writeInt(i, tag);
};
Writer.prototype.writeBoolean = function(b, tag) {
if (typeof(b) !== 'boolean')
throw new TypeError('argument must be a Boolean');
if (typeof(tag) !== 'number')
tag = ASN1.Boolean;
this._ensure(3);
this._buf[this._offset++] = tag;
this._buf[this._offset++] = 0x01;
this._buf[this._offset++] = b ? 0xff : 0x00;
};
Writer.prototype.writeString = function(s, tag) {
if (typeof(s) !== 'string')
throw new TypeError('argument must be a string (was: ' + typeof(s) + ')');
if (typeof(tag) !== 'number')
tag = ASN1.OctetString;
var len = Buffer.byteLength(s);
this.writeByte(tag);
this.writeLength(len);
if (len) {
this._ensure(len);
this._buf.write(s, this._offset);
this._offset += len;
}
};
Writer.prototype.writeBuffer = function(buf, tag) {
if (typeof(tag) !== 'number')
throw new TypeError('tag must be a number');
if (!Buffer.isBuffer(buf))
throw new TypeError('argument must be a buffer');
this.writeByte(tag);
this.writeLength(buf.length);
this._ensure(buf.length);
buf.copy(this._buf, this._offset, 0, buf.length);
this._offset += buf.length;
};
Writer.prototype.writeStringArray = function(strings) {
if ((!strings instanceof Array))
throw new TypeError('argument must be an Array[String]');
var self = this;
strings.forEach(function(s) {
self.writeString(s);
});
};
// This is really to solve DER cases, but whatever for now
Writer.prototype.writeOID = function(s, tag) {
if (typeof(s) !== 'string')
throw new TypeError('argument must be a string');
if (typeof(tag) !== 'number')
tag = ASN1.OID;
if (!/^([0-9]+\.){3,}[0-9]+$/.test(s))
throw new Error('argument is not a valid OID string');
function encodeOctet(bytes, octet) {
if (octet < 128) {
bytes.push(octet);
} else if (octet < 16384) {
bytes.push((octet >>> 7) | 0x80);
bytes.push(octet & 0x7F);
} else if (octet < 2097152) {
bytes.push((octet >>> 14) | 0x80);
bytes.push(((octet >>> 7) | 0x80) & 0xFF);
bytes.push(octet & 0x7F);
} else if (octet < 268435456) {
bytes.push((octet >>> 21) | 0x80);
bytes.push(((octet >>> 14) | 0x80) & 0xFF);
bytes.push(((octet >>> 7) | 0x80) & 0xFF);
bytes.push(octet & 0x7F);
} else {
bytes.push(((octet >>> 28) | 0x80) & 0xFF);
bytes.push(((octet >>> 21) | 0x80) & 0xFF);
bytes.push(((octet >>> 14) | 0x80) & 0xFF);
bytes.push(((octet >>> 7) | 0x80) & 0xFF);
bytes.push(octet & 0x7F);
}
}
var tmp = s.split('.');
var bytes = [];
bytes.push(parseInt(tmp[0], 10) * 40 + parseInt(tmp[1], 10));
tmp.slice(2).forEach(function(b) {
encodeOctet(bytes, parseInt(b, 10));
});
var self = this;
this._ensure(2 + bytes.length);
this.writeByte(tag);
this.writeLength(bytes.length);
bytes.forEach(function(b) {
self.writeByte(b);
});
};
Writer.prototype.writeLength = function(len) {
if (typeof(len) !== 'number')
throw new TypeError('argument must be a Number');
this._ensure(4);
if (len <= 0x7f) {
this._buf[this._offset++] = len;
} else if (len <= 0xff) {
this._buf[this._offset++] = 0x81;
this._buf[this._offset++] = len;
} else if (len <= 0xffff) {
this._buf[this._offset++] = 0x82;
this._buf[this._offset++] = len >> 8;
this._buf[this._offset++] = len;
} else if (len <= 0xffffff) {
this._buf[this._offset++] = 0x83;
this._buf[this._offset++] = len >> 16;
this._buf[this._offset++] = len >> 8;
this._buf[this._offset++] = len;
} else {
throw new InvalidAsn1ERror('Length too long (> 4 bytes)');
}
};
Writer.prototype.startSequence = function(tag) {
if (typeof(tag) !== 'number')
tag = ASN1.Sequence | ASN1.Constructor;
this.writeByte(tag);
this._seq.push(this._offset);
this._ensure(3);
this._offset += 3;
};
Writer.prototype.endSequence = function() {
var seq = this._seq.pop();
var start = seq + 3;
var len = this._offset - start;
if (len <= 0x7f) {
this._shift(start, len, -2);
this._buf[seq] = len;
} else if (len <= 0xff) {
this._shift(start, len, -1);
this._buf[seq] = 0x81;
this._buf[seq + 1] = len;
} else if (len <= 0xffff) {
this._buf[seq] = 0x82;
this._buf[seq + 1] = len >> 8;
this._buf[seq + 2] = len;
} else if (len <= 0xffffff) {
this._shift(start, len, 1);
this._buf[seq] = 0x83;
this._buf[seq + 1] = len >> 16;
this._buf[seq + 2] = len >> 8;
this._buf[seq + 3] = len;
} else {
throw new InvalidAsn1Error('Sequence too long');
}
};
Writer.prototype._shift = function(start, len, shift) {
assert.ok(start !== undefined);
assert.ok(len !== undefined);
assert.ok(shift);
this._buf.copy(this._buf, start + shift, start, start + len);
this._offset += shift;
};
Writer.prototype._ensure = function(len) {
assert.ok(len);
if (this._size - this._offset < len) {
var sz = this._size * this._options.growthFactor;
if (sz - this._offset < len)
sz += len;
var buf = new Buffer(sz);
this._buf.copy(buf, 0, 0, this._offset);
this._buf = buf;
this._size = sz;
}
};
///--- Exported API
module.exports = Writer;
// Copyright 2011 Mark Cavage <mcavage@gmail.com> All rights reserved.
// If you have no idea what ASN.1 or BER is, see this:
// ftp://ftp.rsa.com/pub/pkcs/ascii/layman.asc
var Ber = require('./ber/index');
///--- Exported API
module.exports = {
Ber: Ber,
BerReader: Ber.Reader,
BerWriter: Ber.Writer
};
Copyright (c) 2011 Mark Cavage, All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE
{
"_args": [
[
{
"raw": "asn1@~0.2.3",
"scope": null,
"escapedName": "asn1",
"name": "asn1",
"rawSpec": "~0.2.3",
"spec": ">=0.2.3 <0.3.0",
"type": "range"
},
"F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\sshpk"
]
],
"_from": "asn1@>=0.2.3 <0.3.0",
"_id": "asn1@0.2.3",
"_inCache": true,
"_location": "/asn1",
"_npmUser": {
"name": "pfmooney",
"email": "patrick.f.mooney@gmail.com"
},
"_npmVersion": "1.4.28",
"_phantomChildren": {},
"_requested": {
"raw": "asn1@~0.2.3",
"scope": null,
"escapedName": "asn1",
"name": "asn1",
"rawSpec": "~0.2.3",
"spec": ">=0.2.3 <0.3.0",
"type": "range"
},
"_requiredBy": [
"/sshpk"
],
"_resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz",
"_shasum": "dac8787713c9966849fc8180777ebe9c1ddf3b86",
"_shrinkwrap": null,
"_spec": "asn1@~0.2.3",
"_where": "F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\sshpk",
"author": {
"name": "Mark Cavage",
"email": "mcavage@gmail.com"
},
"bugs": {
"url": "https://github.com/mcavage/node-asn1/issues"
},
"contributors": [
{
"name": "David Gwynne",
"email": "loki@animata.net"
},
{
"name": "Yunong Xiao",
"email": "yunong@joyent.com"
},
{
"name": "Alex Wilson",
"email": "alex.wilson@joyent.com"
}
],
"dependencies": {},
"description": "Contains parsers and serializers for ASN.1 (currently BER only)",
"devDependencies": {
"tap": "0.4.8"
},
"directories": {},
"dist": {
"shasum": "dac8787713c9966849fc8180777ebe9c1ddf3b86",
"tarball": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz"
},
"homepage": "https://github.com/mcavage/node-asn1",
"license": "MIT",
"main": "lib/index.js",
"maintainers": [
{
"name": "mcavage",
"email": "mcavage@gmail.com"
},
{
"name": "pfmooney",
"email": "patrick.f.mooney@gmail.com"
}
],
"name": "asn1",
"optionalDependencies": {},
"readme": "ERROR: No README data found!",
"repository": {
"type": "git",
"url": "git://github.com/mcavage/node-asn1.git"
},
"scripts": {
"test": "tap ./tst"
},
"version": "0.2.3"
}

node-asn1 is a library for encoding and decoding ASN.1 datatypes in pure JS. Currently BER encoding is supported; at some point I'll likely have to do DER.

Usage

Mostly, if you're actually needing to read and write ASN.1, you probably don't need this readme to explain what and why. If you have no idea what ASN.1 is, see this: ftp://ftp.rsa.com/pub/pkcs/ascii/layman.asc

The source is pretty much self-explanatory, and has read/write methods for the common types out there.

Decoding

The following reads an ASN.1 sequence with a boolean.

var Ber = require('asn1').Ber;

var reader = new Ber.Reader(new Buffer([0x30, 0x03, 0x01, 0x01, 0xff]));

reader.readSequence();
console.log('Sequence len: ' + reader.length);
if (reader.peek() === Ber.Boolean)
  console.log(reader.readBoolean());

Encoding

The following generates the same payload as above.

var Ber = require('asn1').Ber;

var writer = new Ber.Writer();

writer.startSequence();
writer.writeBoolean(true);
writer.endSequence();

console.log(writer.buffer);

Installation

npm install asn1

License

MIT.

Bugs

See https://github.com/mcavage/node-asn1/issues.

// Copyright 2011 Mark Cavage <mcavage@gmail.com> All rights reserved.
var test = require('tap').test;
///--- Globals
var BerReader;
///--- Tests
test('load library', function(t) {
BerReader = require('../../lib/index').BerReader;
t.ok(BerReader);
try {
new BerReader();
t.fail('Should have thrown');
} catch (e) {
t.ok(e instanceof TypeError, 'Should have been a type error');
}
t.end();
});
test('read byte', function(t) {
var reader = new BerReader(new Buffer([0xde]));
t.ok(reader);
t.equal(reader.readByte(), 0xde, 'wrong value');
t.end();
});
test('read 1 byte int', function(t) {
var reader = new BerReader(new Buffer([0x02, 0x01, 0x03]));
t.ok(reader);
t.equal(reader.readInt(), 0x03, 'wrong value');
t.equal(reader.length, 0x01, 'wrong length');
t.end();
});
test('read 2 byte int', function(t) {
var reader = new BerReader(new Buffer([0x02, 0x02, 0x7e, 0xde]));
t.ok(reader);
t.equal(reader.readInt(), 0x7ede, 'wrong value');
t.equal(reader.length, 0x02, 'wrong length');
t.end();
});
test('read 3 byte int', function(t) {
var reader = new BerReader(new Buffer([0x02, 0x03, 0x7e, 0xde, 0x03]));
t.ok(reader);
t.equal(reader.readInt(), 0x7ede03, 'wrong value');
t.equal(reader.length, 0x03, 'wrong length');
t.end();
});
test('read 4 byte int', function(t) {
var reader = new BerReader(new Buffer([0x02, 0x04, 0x7e, 0xde, 0x03, 0x01]));
t.ok(reader);
t.equal(reader.readInt(), 0x7ede0301, 'wrong value');
t.equal(reader.length, 0x04, 'wrong length');
t.end();
});
test('read 1 byte negative int', function(t) {
var reader = new BerReader(new Buffer([0x02, 0x01, 0xdc]));
t.ok(reader);
t.equal(reader.readInt(), -36, 'wrong value');
t.equal(reader.length, 0x01, 'wrong length');
t.end();
});
test('read 2 byte negative int', function(t) {
var reader = new BerReader(new Buffer([0x02, 0x02, 0xc0, 0x4e]));
t.ok(reader);
t.equal(reader.readInt(), -16306, 'wrong value');
t.equal(reader.length, 0x02, 'wrong length');
t.end();
});
test('read 3 byte negative int', function(t) {
var reader = new BerReader(new Buffer([0x02, 0x03, 0xff, 0x00, 0x19]));
t.ok(reader);
t.equal(reader.readInt(), -65511, 'wrong value');
t.equal(reader.length, 0x03, 'wrong length');
t.end();
});
test('read 4 byte negative int', function(t) {
var reader = new BerReader(new Buffer([0x02, 0x04, 0x91, 0x7c, 0x22, 0x1f]));
t.ok(reader);
t.equal(reader.readInt(), -1854135777, 'wrong value');
t.equal(reader.length, 0x04, 'wrong length');
t.end();
});
test('read boolean true', function(t) {
var reader = new BerReader(new Buffer([0x01, 0x01, 0xff]));
t.ok(reader);
t.equal(reader.readBoolean(), true, 'wrong value');
t.equal(reader.length, 0x01, 'wrong length');
t.end();
});
test('read boolean false', function(t) {
var reader = new BerReader(new Buffer([0x01, 0x01, 0x00]));
t.ok(reader);
t.equal(reader.readBoolean(), false, 'wrong value');
t.equal(reader.length, 0x01, 'wrong length');
t.end();
});
test('read enumeration', function(t) {
var reader = new BerReader(new Buffer([0x0a, 0x01, 0x20]));
t.ok(reader);
t.equal(reader.readEnumeration(), 0x20, 'wrong value');
t.equal(reader.length, 0x01, 'wrong length');
t.end();
});
test('read string', function(t) {
var dn = 'cn=foo,ou=unit,o=test';
var buf = new Buffer(dn.length + 2);
buf[0] = 0x04;
buf[1] = Buffer.byteLength(dn);
buf.write(dn, 2);
var reader = new BerReader(buf);
t.ok(reader);
t.equal(reader.readString(), dn, 'wrong value');
t.equal(reader.length, dn.length, 'wrong length');
t.end();
});
test('read sequence', function(t) {
var reader = new BerReader(new Buffer([0x30, 0x03, 0x01, 0x01, 0xff]));
t.ok(reader);
t.equal(reader.readSequence(), 0x30, 'wrong value');
t.equal(reader.length, 0x03, 'wrong length');
t.equal(reader.readBoolean(), true, 'wrong value');
t.equal(reader.length, 0x01, 'wrong length');
t.end();
});
test('anonymous LDAPv3 bind', function(t) {
var BIND = new Buffer(14);
BIND[0] = 0x30; // Sequence
BIND[1] = 12; // len
BIND[2] = 0x02; // ASN.1 Integer
BIND[3] = 1; // len
BIND[4] = 0x04; // msgid (make up 4)
BIND[5] = 0x60; // Bind Request
BIND[6] = 7; // len
BIND[7] = 0x02; // ASN.1 Integer
BIND[8] = 1; // len
BIND[9] = 0x03; // v3
BIND[10] = 0x04; // String (bind dn)
BIND[11] = 0; // len
BIND[12] = 0x80; // ContextSpecific (choice)
BIND[13] = 0; // simple bind
// Start testing ^^
var ber = new BerReader(BIND);
t.equal(ber.readSequence(), 48, 'Not an ASN.1 Sequence');
t.equal(ber.length, 12, 'Message length should be 12');
t.equal(ber.readInt(), 4, 'Message id should have been 4');
t.equal(ber.readSequence(), 96, 'Bind Request should have been 96');
t.equal(ber.length, 7, 'Bind length should have been 7');
t.equal(ber.readInt(), 3, 'LDAP version should have been 3');
t.equal(ber.readString(), '', 'Bind DN should have been empty');
t.equal(ber.length, 0, 'string length should have been 0');
t.equal(ber.readByte(), 0x80, 'Should have been ContextSpecific (choice)');
t.equal(ber.readByte(), 0, 'Should have been simple bind');
t.equal(null, ber.readByte(), 'Should be out of data');
t.end();
});
test('long string', function(t) {
var buf = new Buffer(256);
var o;
var s =
'2;649;CN=Red Hat CS 71GA Demo,O=Red Hat CS 71GA Demo,C=US;' +
'CN=RHCS Agent - admin01,UID=admin01,O=redhat,C=US [1] This is ' +
'Teena Vradmin\'s description.';
buf[0] = 0x04;
buf[1] = 0x81;
buf[2] = 0x94;
buf.write(s, 3);
var ber = new BerReader(buf.slice(0, 3 + s.length));
t.equal(ber.readString(), s);
t.end();
});
// Copyright 2011 Mark Cavage <mcavage@gmail.com> All rights reserved.
var test = require('tap').test;
var sys = require('sys');
///--- Globals
var BerWriter;
var BerReader;
///--- Tests
test('load library', function(t) {
BerWriter = require('../../lib/index').BerWriter;
t.ok(BerWriter);
t.ok(new BerWriter());
t.end();
});
test('write byte', function(t) {
var writer = new BerWriter();
writer.writeByte(0xC2);
var ber = writer.buffer;
t.ok(ber);
t.equal(ber.length, 1, 'Wrong length');
t.equal(ber[0], 0xC2, 'value wrong');
t.end();
});
test('write 1 byte int', function(t) {
var writer = new BerWriter();
writer.writeInt(0x7f);
var ber = writer.buffer;
t.ok(ber);
t.equal(ber.length, 3, 'Wrong length for an int: ' + ber.length);
t.equal(ber[0], 0x02, 'ASN.1 tag wrong (2) -> ' + ber[0]);
t.equal(ber[1], 0x01, 'length wrong(1) -> ' + ber[1]);
t.equal(ber[2], 0x7f, 'value wrong(3) -> ' + ber[2]);
t.end();
});
test('write 2 byte int', function(t) {
var writer = new BerWriter();
writer.writeInt(0x7ffe);
var ber = writer.buffer;
t.ok(ber);
t.equal(ber.length, 4, 'Wrong length for an int');
t.equal(ber[0], 0x02, 'ASN.1 tag wrong');
t.equal(ber[1], 0x02, 'length wrong');
t.equal(ber[2], 0x7f, 'value wrong (byte 1)');
t.equal(ber[3], 0xfe, 'value wrong (byte 2)');
t.end();
});
test('write 3 byte int', function(t) {
var writer = new BerWriter();
writer.writeInt(0x7ffffe);
var ber = writer.buffer;
t.ok(ber);
t.equal(ber.length, 5, 'Wrong length for an int');
t.equal(ber[0], 0x02, 'ASN.1 tag wrong');
t.equal(ber[1], 0x03, 'length wrong');
t.equal(ber[2], 0x7f, 'value wrong (byte 1)');
t.equal(ber[3], 0xff, 'value wrong (byte 2)');
t.equal(ber[4], 0xfe, 'value wrong (byte 3)');
t.end();
});
test('write 4 byte int', function(t) {
var writer = new BerWriter();
writer.writeInt(0x7ffffffe);
var ber = writer.buffer;
t.ok(ber);
t.equal(ber.length, 6, 'Wrong length for an int');
t.equal(ber[0], 0x02, 'ASN.1 tag wrong');
t.equal(ber[1], 0x04, 'length wrong');
t.equal(ber[2], 0x7f, 'value wrong (byte 1)');
t.equal(ber[3], 0xff, 'value wrong (byte 2)');
t.equal(ber[4], 0xff, 'value wrong (byte 3)');
t.equal(ber[5], 0xfe, 'value wrong (byte 4)');
t.end();
});
test('write 1 byte negative int', function(t) {
var writer = new BerWriter();
writer.writeInt(-128);
var ber = writer.buffer;
t.ok(ber);
t.equal(ber.length, 3, 'Wrong length for an int');
t.equal(ber[0], 0x02, 'ASN.1 tag wrong');
t.equal(ber[1], 0x01, 'length wrong');
t.equal(ber[2], 0x80, 'value wrong (byte 1)');
t.end();
});
test('write 2 byte negative int', function(t) {
var writer = new BerWriter();
writer.writeInt(-22400);
var ber = writer.buffer;
t.ok(ber);
t.equal(ber.length, 4, 'Wrong length for an int');
t.equal(ber[0], 0x02, 'ASN.1 tag wrong');
t.equal(ber[1], 0x02, 'length wrong');
t.equal(ber[2], 0xa8, 'value wrong (byte 1)');
t.equal(ber[3], 0x80, 'value wrong (byte 2)');
t.end();
});
test('write 3 byte negative int', function(t) {
var writer = new BerWriter();
writer.writeInt(-481653);
var ber = writer.buffer;
t.ok(ber);
t.equal(ber.length, 5, 'Wrong length for an int');
t.equal(ber[0], 0x02, 'ASN.1 tag wrong');
t.equal(ber[1], 0x03, 'length wrong');
t.equal(ber[2], 0xf8, 'value wrong (byte 1)');
t.equal(ber[3], 0xa6, 'value wrong (byte 2)');
t.equal(ber[4], 0x8b, 'value wrong (byte 3)');
t.end();
});
test('write 4 byte negative int', function(t) {
var writer = new BerWriter();
writer.writeInt(-1522904131);
var ber = writer.buffer;
t.ok(ber);
t.equal(ber.length, 6, 'Wrong length for an int');
t.equal(ber[0], 0x02, 'ASN.1 tag wrong');
t.equal(ber[1], 0x04, 'length wrong');
t.equal(ber[2], 0xa5, 'value wrong (byte 1)');
t.equal(ber[3], 0x3a, 'value wrong (byte 2)');
t.equal(ber[4], 0x53, 'value wrong (byte 3)');
t.equal(ber[5], 0xbd, 'value wrong (byte 4)');
t.end();
});
test('write boolean', function(t) {
var writer = new BerWriter();
writer.writeBoolean(true);
writer.writeBoolean(false);
var ber = writer.buffer;
t.ok(ber);
t.equal(ber.length, 6, 'Wrong length');
t.equal(ber[0], 0x01, 'tag wrong');
t.equal(ber[1], 0x01, 'length wrong');
t.equal(ber[2], 0xff, 'value wrong');
t.equal(ber[3], 0x01, 'tag wrong');
t.equal(ber[4], 0x01, 'length wrong');
t.equal(ber[5], 0x00, 'value wrong');
t.end();
});
test('write string', function(t) {
var writer = new BerWriter();
writer.writeString('hello world');
var ber = writer.buffer;
t.ok(ber);
t.equal(ber.length, 13, 'wrong length');
t.equal(ber[0], 0x04, 'wrong tag');
t.equal(ber[1], 11, 'wrong length');
t.equal(ber.slice(2).toString('utf8'), 'hello world', 'wrong value');
t.end();
});
test('write buffer', function(t) {
var writer = new BerWriter();
// write some stuff to start with
writer.writeString('hello world');
var ber = writer.buffer;
var buf = new Buffer([0x04, 0x0b, 0x30, 0x09, 0x02, 0x01, 0x0f, 0x01, 0x01,
0xff, 0x01, 0x01, 0xff]);
writer.writeBuffer(buf.slice(2, buf.length), 0x04);
ber = writer.buffer;
t.ok(ber);
t.equal(ber.length, 26, 'wrong length');
t.equal(ber[0], 0x04, 'wrong tag');
t.equal(ber[1], 11, 'wrong length');
t.equal(ber.slice(2, 13).toString('utf8'), 'hello world', 'wrong value');
t.equal(ber[13], buf[0], 'wrong tag');
t.equal(ber[14], buf[1], 'wrong length');
for (var i = 13, j = 0; i < ber.length && j < buf.length; i++, j++) {
t.equal(ber[i], buf[j], 'buffer contents not identical');
}
t.end();
});
test('write string array', function(t) {
var writer = new BerWriter();
writer.writeStringArray(['hello world', 'fubar!']);
var ber = writer.buffer;
t.ok(ber);
t.equal(ber.length, 21, 'wrong length');
t.equal(ber[0], 0x04, 'wrong tag');
t.equal(ber[1], 11, 'wrong length');
t.equal(ber.slice(2, 13).toString('utf8'), 'hello world', 'wrong value');
t.equal(ber[13], 0x04, 'wrong tag');
t.equal(ber[14], 6, 'wrong length');
t.equal(ber.slice(15).toString('utf8'), 'fubar!', 'wrong value');
t.end();
});
test('resize internal buffer', function(t) {
var writer = new BerWriter({size: 2});
writer.writeString('hello world');
var ber = writer.buffer;
t.ok(ber);
t.equal(ber.length, 13, 'wrong length');
t.equal(ber[0], 0x04, 'wrong tag');
t.equal(ber[1], 11, 'wrong length');
t.equal(ber.slice(2).toString('utf8'), 'hello world', 'wrong value');
t.end();
});
test('sequence', function(t) {
var writer = new BerWriter({size: 25});
writer.startSequence();
writer.writeString('hello world');
writer.endSequence();
var ber = writer.buffer;
t.ok(ber);
console.log(ber);
t.equal(ber.length, 15, 'wrong length');
t.equal(ber[0], 0x30, 'wrong tag');
t.equal(ber[1], 13, 'wrong length');
t.equal(ber[2], 0x04, 'wrong tag');
t.equal(ber[3], 11, 'wrong length');
t.equal(ber.slice(4).toString('utf8'), 'hello world', 'wrong value');
t.end();
});
test('nested sequence', function(t) {
var writer = new BerWriter({size: 25});
writer.startSequence();
writer.writeString('hello world');
writer.startSequence();
writer.writeString('hello world');
writer.endSequence();
writer.endSequence();
var ber = writer.buffer;
t.ok(ber);
t.equal(ber.length, 30, 'wrong length');
t.equal(ber[0], 0x30, 'wrong tag');
t.equal(ber[1], 28, 'wrong length');
t.equal(ber[2], 0x04, 'wrong tag');
t.equal(ber[3], 11, 'wrong length');
t.equal(ber.slice(4, 15).toString('utf8'), 'hello world', 'wrong value');
t.equal(ber[15], 0x30, 'wrong tag');
t.equal(ber[16], 13, 'wrong length');
t.equal(ber[17], 0x04, 'wrong tag');
t.equal(ber[18], 11, 'wrong length');
t.equal(ber.slice(19, 30).toString('utf8'), 'hello world', 'wrong value');
t.end();
});
test('LDAP bind message', function(t) {
var dn = 'cn=foo,ou=unit,o=test';
var writer = new BerWriter();
writer.startSequence();
writer.writeInt(3); // msgid = 3
writer.startSequence(0x60); // ldap bind
writer.writeInt(3); // ldap v3
writer.writeString(dn);
writer.writeByte(0x80);
writer.writeByte(0x00);
writer.endSequence();
writer.endSequence();
var ber = writer.buffer;
t.ok(ber);
t.equal(ber.length, 35, 'wrong length (buffer)');
t.equal(ber[0], 0x30, 'wrong tag');
t.equal(ber[1], 33, 'wrong length');
t.equal(ber[2], 0x02, 'wrong tag');
t.equal(ber[3], 1, 'wrong length');
t.equal(ber[4], 0x03, 'wrong value');
t.equal(ber[5], 0x60, 'wrong tag');
t.equal(ber[6], 28, 'wrong length');
t.equal(ber[7], 0x02, 'wrong tag');
t.equal(ber[8], 1, 'wrong length');
t.equal(ber[9], 0x03, 'wrong value');
t.equal(ber[10], 0x04, 'wrong tag');
t.equal(ber[11], dn.length, 'wrong length');
t.equal(ber.slice(12, 33).toString('utf8'), dn, 'wrong value');
t.equal(ber[33], 0x80, 'wrong tag');
t.equal(ber[34], 0x00, 'wrong len');
t.end();
});
test('Write OID', function(t) {
var oid = '1.2.840.113549.1.1.1';
var writer = new BerWriter();
writer.writeOID(oid);
var ber = writer.buffer;
t.ok(ber);
console.log(require('util').inspect(ber));
console.log(require('util').inspect(new Buffer([0x06, 0x09, 0x2a, 0x86,
0x48, 0x86, 0xf7, 0x0d,
0x01, 0x01, 0x01])));
t.end();
});
// Copyright (c) 2012, Mark Cavage. All rights reserved.
// Copyright 2015 Joyent, Inc.
var assert = require('assert');
var Stream = require('stream').Stream;
var util = require('util');
///--- Globals
/* JSSTYLED */
var UUID_REGEXP = /^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$/;
///--- Internal
function _capitalize(str) {
return (str.charAt(0).toUpperCase() + str.slice(1));
}
function _toss(name, expected, oper, arg, actual) {
throw new assert.AssertionError({
message: util.format('%s (%s) is required', name, expected),
actual: (actual === undefined) ? typeof (arg) : actual(arg),
expected: expected,
operator: oper || '===',
stackStartFunction: _toss.caller
});
}
function _getClass(arg) {
return (Object.prototype.toString.call(arg).slice(8, -1));
}
function noop() {
// Why even bother with asserts?
}
///--- Exports
var types = {
bool: {
check: function (arg) { return typeof (arg) === 'boolean'; }
},
func: {
check: function (arg) { return typeof (arg) === 'function'; }
},
string: {
check: function (arg) { return typeof (arg) === 'string'; }
},
object: {
check: function (arg) {
return typeof (arg) === 'object' && arg !== null;
}
},
number: {
check: function (arg) {
return typeof (arg) === 'number' && !isNaN(arg) && isFinite(arg);
}
},
buffer: {
check: function (arg) { return Buffer.isBuffer(arg); },
operator: 'Buffer.isBuffer'
},
array: {
check: function (arg) { return Array.isArray(arg); },
operator: 'Array.isArray'
},
stream: {
check: function (arg) { return arg instanceof Stream; },
operator: 'instanceof',
actual: _getClass
},
date: {
check: function (arg) { return arg instanceof Date; },
operator: 'instanceof',
actual: _getClass
},
regexp: {
check: function (arg) { return arg instanceof RegExp; },
operator: 'instanceof',
actual: _getClass
},
uuid: {
check: function (arg) {
return typeof (arg) === 'string' && UUID_REGEXP.test(arg);
},
operator: 'isUUID'
}
};
function _setExports(ndebug) {
var keys = Object.keys(types);
var out;
/* re-export standard assert */
if (process.env.NODE_NDEBUG) {
out = noop;
} else {
out = function (arg, msg) {
if (!arg) {
_toss(msg, 'true', arg);
}
};
}
/* standard checks */
keys.forEach(function (k) {
if (ndebug) {
out[k] = noop;
return;
}
var type = types[k];
out[k] = function (arg, msg) {
if (!type.check(arg)) {
_toss(msg, k, type.operator, arg, type.actual);
}
};
});
/* optional checks */
keys.forEach(function (k) {
var name = 'optional' + _capitalize(k);
if (ndebug) {
out[name] = noop;
return;
}
var type = types[k];
out[name] = function (arg, msg) {
if (arg === undefined || arg === null) {
return;
}
if (!type.check(arg)) {
_toss(msg, k, type.operator, arg, type.actual);
}
};
});
/* arrayOf checks */
keys.forEach(function (k) {
var name = 'arrayOf' + _capitalize(k);
if (ndebug) {
out[name] = noop;
return;
}
var type = types[k];
var expected = '[' + k + ']';
out[name] = function (arg, msg) {
if (!Array.isArray(arg)) {
_toss(msg, expected, type.operator, arg, type.actual);
}
var i;
for (i = 0; i < arg.length; i++) {
if (!type.check(arg[i])) {
_toss(msg, expected, type.operator, arg, type.actual);
}
}
};
});
/* optionalArrayOf checks */
keys.forEach(function (k) {
var name = 'optionalArrayOf' + _capitalize(k);
if (ndebug) {
out[name] = noop;
return;
}
var type = types[k];
var expected = '[' + k + ']';
out[name] = function (arg, msg) {
if (arg === undefined || arg === null) {
return;
}
if (!Array.isArray(arg)) {
_toss(msg, expected, type.operator, arg, type.actual);
}
var i;
for (i = 0; i < arg.length; i++) {
if (!type.check(arg[i])) {
_toss(msg, expected, type.operator, arg, type.actual);
}
}
};
});
/* re-export built-in assertions */
Object.keys(assert).forEach(function (k) {
if (k === 'AssertionError') {
out[k] = assert[k];
return;
}
if (ndebug) {
out[k] = noop;
return;
}
out[k] = assert[k];
});
/* export ourselves (for unit tests _only_) */
out._setExports = _setExports;
return out;
}
module.exports = _setExports(process.env.NODE_NDEBUG);
Dave Eddy <dave@daveeddy.com>
Fred Kuo <fred.kuo@joyent.com>
Lars-Magnus Skog <ralphtheninja@riseup.net>
Mark Cavage <mcavage@gmail.com>
Patrick Mooney <pmooney@pfmooney.com>
Rob Gulewich <robert.gulewich@joyent.com>

assert-plus Changelog

0.2.0

  • Fix assert.object(null) so it throws
  • Fix optional/arrayOf exports for non-type-of asserts
  • Add optiona/arrayOf exports for Stream/Date/Regex/uuid
  • Add basic unit test coverage
{
"_args": [
[
{
"raw": "assert-plus@^0.2.0",
"scope": null,
"escapedName": "assert-plus",
"name": "assert-plus",
"rawSpec": "^0.2.0",
"spec": ">=0.2.0 <0.3.0",
"type": "range"
},
"F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\http-signature"
]
],
"_from": "assert-plus@>=0.2.0 <0.3.0",
"_id": "assert-plus@0.2.0",
"_inCache": true,
"_location": "/assert-plus",
"_nodeVersion": "0.10.36",
"_npmUser": {
"name": "pfmooney",
"email": "patrick.f.mooney@gmail.com"
},
"_npmVersion": "3.3.8",
"_phantomChildren": {},
"_requested": {
"raw": "assert-plus@^0.2.0",
"scope": null,
"escapedName": "assert-plus",
"name": "assert-plus",
"rawSpec": "^0.2.0",
"spec": ">=0.2.0 <0.3.0",
"type": "range"
},
"_requiredBy": [
"/http-signature"
],
"_resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz",
"_shasum": "d74e1b87e7affc0db8aadb7021f3fe48101ab234",
"_shrinkwrap": null,
"_spec": "assert-plus@^0.2.0",
"_where": "F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\http-signature",
"author": {
"name": "Mark Cavage",
"email": "mcavage@gmail.com"
},
"bugs": {
"url": "https://github.com/mcavage/node-assert-plus/issues"
},
"contributors": [
{
"name": "Dave Eddy",
"email": "dave@daveeddy.com"
},
{
"name": "Fred Kuo",
"email": "fred.kuo@joyent.com"
},
{
"name": "Lars-Magnus Skog",
"email": "ralphtheninja@riseup.net"
},
{
"name": "Mark Cavage",
"email": "mcavage@gmail.com"
},
{
"name": "Patrick Mooney",
"email": "pmooney@pfmooney.com"
},
{
"name": "Rob Gulewich",
"email": "robert.gulewich@joyent.com"
}
],
"dependencies": {},
"description": "Extra assertions on top of node's assert module",
"devDependencies": {
"faucet": "0.0.1",
"tape": "4.2.2"
},
"directories": {},
"dist": {
"shasum": "d74e1b87e7affc0db8aadb7021f3fe48101ab234",
"tarball": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz"
},
"engines": {
"node": ">=0.8"
},
"homepage": "https://github.com/mcavage/node-assert-plus#readme",
"license": "MIT",
"main": "./assert.js",
"maintainers": [
{
"name": "mcavage",
"email": "mcavage@gmail.com"
},
{
"name": "pfmooney",
"email": "patrick.f.mooney@gmail.com"
}
],
"name": "assert-plus",
"optionalDependencies": {},
"readme": "ERROR: No README data found!",
"repository": {
"type": "git",
"url": "git+https://github.com/mcavage/node-assert-plus.git"
},
"scripts": {
"test": "tape tests/*.js | ./node_modules/.bin/faucet"
},
"version": "0.2.0"
}

assert-plus

This library is a super small wrapper over node's assert module that has two things: (1) the ability to disable assertions with the environment variable NODE_NDEBUG, and (2) some API wrappers for argument testing. Like assert.string(myArg, 'myArg'). As a simple example, most of my code looks like this:

    var assert = require('assert-plus');

    function fooAccount(options, callback) {
        assert.object(options, 'options');
        assert.number(options.id, 'options.id');
        assert.bool(options.isManager, 'options.isManager');
        assert.string(options.name, 'options.name');
        assert.arrayOfString(options.email, 'options.email');
        assert.func(callback, 'callback');

        // Do stuff
        callback(null, {});
    }

API

All methods that aren't part of node's core assert API are simply assumed to take an argument, and then a string 'name' that's not a message; AssertionError will be thrown if the assertion fails with a message like:

AssertionError: foo (string) is required
at test (/home/mark/work/foo/foo.js:3:9)
at Object.<anonymous> (/home/mark/work/foo/foo.js:15:1)
at Module._compile (module.js:446:26)
at Object..js (module.js:464:10)
at Module.load (module.js:353:31)
at Function._load (module.js:311:12)
at Array.0 (module.js:484:10)
at EventEmitter._tickCallback (node.js:190:38)

from:

    function test(foo) {
        assert.string(foo, 'foo');
    }

There you go. You can check that arrays are of a homogeneous type with Arrayof$Type:

    function test(foo) {
        assert.arrayOfString(foo, 'foo');
    }

You can assert IFF an argument is not undefined (i.e., an optional arg):

    assert.optionalString(foo, 'foo');

Lastly, you can opt-out of assertion checking altogether by setting the environment variable NODE_NDEBUG=1. This is pseudo-useful if you have lots of assertions, and don't want to pay typeof () taxes to v8 in production. Be advised: The standard functions re-exported from assert are also disabled in assert-plus if NDEBUG is specified. Using them directly from the assert module avoids this behavior.

The complete list of APIs is:

  • assert.array
  • assert.bool
  • assert.buffer
  • assert.func
  • assert.number
  • assert.object
  • assert.string
  • assert.stream
  • assert.date
  • assert.regex
  • assert.uuid
  • assert.arrayOfArray
  • assert.arrayOfBool
  • assert.arrayOfBuffer
  • assert.arrayOfFunc
  • assert.arrayOfNumber
  • assert.arrayOfObject
  • assert.arrayOfString
  • assert.arrayOfStream
  • assert.arrayOfDate
  • assert.arrayOfUuid
  • assert.optionalArray
  • assert.optionalBool
  • assert.optionalBuffer
  • assert.optionalFunc
  • assert.optionalNumber
  • assert.optionalObject
  • assert.optionalString
  • assert.optionalStream
  • assert.optionalDate
  • assert.optionalUuid
  • assert.optionalArrayOfArray
  • assert.optionalArrayOfBool
  • assert.optionalArrayOfBuffer
  • assert.optionalArrayOfFunc
  • assert.optionalArrayOfNumber
  • assert.optionalArrayOfObject
  • assert.optionalArrayOfString
  • assert.optionalArrayOfStream
  • assert.optionalArrayOfDate
  • assert.optionalArrayOfUuid
  • assert.AssertionError
  • assert.fail
  • assert.ok
  • assert.equal
  • assert.notEqual
  • assert.deepEqual
  • assert.notDeepEqual
  • assert.strictEqual
  • assert.notStrictEqual
  • assert.throws
  • assert.doesNotThrow
  • assert.ifError

Installation

npm install assert-plus

License

The MIT License (MIT) Copyright (c) 2012 Mark Cavage

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Bugs

See https://github.com/mcavage/node-assert-plus/issues.

/* eslint no-console: "off" */
var asynckit = require('./')
, async = require('async')
, assert = require('assert')
, expected = 0
;
var Benchmark = require('benchmark');
var suite = new Benchmark.Suite;
var source = [];
for (var z = 1; z < 100; z++)
{
source.push(z);
expected += z;
}
suite
// add tests
.add('async.map', function(deferred)
{
var total = 0;
async.map(source,
function(i, cb)
{
setImmediate(function()
{
total += i;
cb(null, total);
});
},
function(err, result)
{
assert.ifError(err);
assert.equal(result[result.length - 1], expected);
deferred.resolve();
});
}, {'defer': true})
.add('asynckit.parallel', function(deferred)
{
var total = 0;
asynckit.parallel(source,
function(i, cb)
{
setImmediate(function()
{
total += i;
cb(null, total);
});
},
function(err, result)
{
assert.ifError(err);
assert.equal(result[result.length - 1], expected);
deferred.resolve();
});
}, {'defer': true})
// add listeners
.on('cycle', function(ev)
{
console.log(String(ev.target));
})
.on('complete', function()
{
console.log('Fastest is ' + this.filter('fastest').map('name'));
})
// run async
.run({ 'async': true });
module.exports =
{
parallel : require('./parallel.js'),
serial : require('./serial.js'),
serialOrdered : require('./serialOrdered.js')
};
// API
module.exports = abort;
/**
* Aborts leftover active jobs
*
* @param {object} state - current state object
*/
function abort(state)
{
Object.keys(state.jobs).forEach(clean.bind(state));
// reset leftover jobs
state.jobs = {};
}
/**
* Cleans up leftover job by invoking abort function for the provided job id
*
* @this state
* @param {string|number} key - job id to abort
*/
function clean(key)
{
if (typeof this.jobs[key] == 'function')
{
this.jobs[key]();
}
}
var defer = require('./defer.js');
// API
module.exports = async;
/**
* Runs provided callback asynchronously
* even if callback itself is not
*
* @param {function} callback - callback to invoke
* @returns {function} - augmented callback
*/
function async(callback)
{
var isAsync = false;
// check if async happened
defer(function() { isAsync = true; });
return function async_callback(err, result)
{
if (isAsync)
{
callback(err, result);
}
else
{
defer(function nextTick_callback()
{
callback(err, result);
});
}
};
}
module.exports = defer;
/**
* Runs provided function on next iteration of the event loop
*
* @param {function} fn - function to run
*/
function defer(fn)
{
var nextTick = typeof setImmediate == 'function'
? setImmediate
: (
typeof process == 'object' && typeof process.nextTick == 'function'
? process.nextTick
: null
);
if (nextTick)
{
nextTick(fn);
}
else
{
setTimeout(fn, 0);
}
}
var async = require('./async.js')
, abort = require('./abort.js')
;
// API
module.exports = iterate;
/**
* Iterates over each job object
*
* @param {array|object} list - array or object (named list) to iterate over
* @param {function} iterator - iterator to run
* @param {object} state - current job status
* @param {function} callback - invoked when all elements processed
*/
function iterate(list, iterator, state, callback)
{
// store current index
var key = state['keyedList'] ? state['keyedList'][state.index] : state.index;
state.jobs[key] = runJob(iterator, key, list[key], function(error, output)
{
// don't repeat yourself
// skip secondary callbacks
if (!(key in state.jobs))
{
return;
}
// clean up jobs
delete state.jobs[key];
if (error)
{
// don't process rest of the results
// stop still active jobs
// and reset the list
abort(state);
}
else
{
state.results[key] = output;
}
// return salvaged results
callback(error, state.results);
});
}
/**
* Runs iterator over provided job element
*
* @param {function} iterator - iterator to invoke
* @param {string|number} key - key/index of the element in the list of jobs
* @param {mixed} item - job description
* @param {function} callback - invoked after iterator is done with the job
* @returns {function|mixed} - job abort function or something else
*/
function runJob(iterator, key, item, callback)
{
var aborter;
// allow shortcut if iterator expects only two arguments
if (iterator.length == 2)
{
aborter = iterator(item, async(callback));
}
// otherwise go with full three arguments
else
{
aborter = iterator(item, key, async(callback));
}
return aborter;
}
var streamify = require('./streamify.js')
, defer = require('./defer.js')
;
// API
module.exports = ReadableAsyncKit;
/**
* Base constructor for all streams
* used to hold properties/methods
*/
function ReadableAsyncKit()
{
ReadableAsyncKit.super_.apply(this, arguments);
// list of active jobs
this.jobs = {};
// add stream methods
this.destroy = destroy;
this._start = _start;
this._read = _read;
}
/**
* Destroys readable stream,
* by aborting outstanding jobs
*
* @returns {void}
*/
function destroy()
{
if (this.destroyed)
{
return;
}
this.destroyed = true;
if (typeof this.terminator == 'function')
{
this.terminator();
}
}
/**
* Starts provided jobs in async manner
*
* @private
*/
function _start()
{
// first argument – runner function
var runner = arguments[0]
// take away first argument
, args = Array.prototype.slice.call(arguments, 1)
// second argument - input data
, input = args[0]
// last argument - result callback
, endCb = streamify.callback.call(this, args[args.length - 1])
;
args[args.length - 1] = endCb;
// third argument - iterator
args[1] = streamify.iterator.call(this, args[1]);
// allow time for proper setup
defer(function()
{
if (!this.destroyed)
{
this.terminator = runner.apply(null, args);
}
else
{
endCb(null, Array.isArray(input) ? [] : {});
}
}.bind(this));
}
/**
* Implement _read to comply with Readable streams
* Doesn't really make sense for flowing object mode
*
* @private
*/
function _read()
{
}
var parallel = require('../parallel.js');
// API
module.exports = ReadableParallel;
/**
* Streaming wrapper to `asynckit.parallel`
*
* @param {array|object} list - array or object (named list) to iterate over
* @param {function} iterator - iterator to run
* @param {function} callback - invoked when all elements processed
* @returns {stream.Readable#}
*/
function ReadableParallel(list, iterator, callback)
{
if (!(this instanceof ReadableParallel))
{
return new ReadableParallel(list, iterator, callback);
}
// turn on object mode
ReadableParallel.super_.call(this, {objectMode: true});
this._start(parallel, list, iterator, callback);
}
var serial = require('../serial.js');
// API
module.exports = ReadableSerial;
/**
* Streaming wrapper to `asynckit.serial`
*
* @param {array|object} list - array or object (named list) to iterate over
* @param {function} iterator - iterator to run
* @param {function} callback - invoked when all elements processed
* @returns {stream.Readable#}
*/
function ReadableSerial(list, iterator, callback)
{
if (!(this instanceof ReadableSerial))
{
return new ReadableSerial(list, iterator, callback);
}
// turn on object mode
ReadableSerial.super_.call(this, {objectMode: true});
this._start(serial, list, iterator, callback);
}
var serialOrdered = require('../serialOrdered.js');
// API
module.exports = ReadableSerialOrdered;
// expose sort helpers
module.exports.ascending = serialOrdered.ascending;
module.exports.descending = serialOrdered.descending;
/**
* Streaming wrapper to `asynckit.serialOrdered`
*
* @param {array|object} list - array or object (named list) to iterate over
* @param {function} iterator - iterator to run
* @param {function} sortMethod - custom sort function
* @param {function} callback - invoked when all elements processed
* @returns {stream.Readable#}
*/
function ReadableSerialOrdered(list, iterator, sortMethod, callback)
{
if (!(this instanceof ReadableSerialOrdered))
{
return new ReadableSerialOrdered(list, iterator, sortMethod, callback);
}
// turn on object mode
ReadableSerialOrdered.super_.call(this, {objectMode: true});
this._start(serialOrdered, list, iterator, sortMethod, callback);
}
// API
module.exports = state;
/**
* Creates initial state object
* for iteration over list
*
* @param {array|object} list - list to iterate over
* @param {function|null} sortMethod - function to use for keys sort,
* or `null` to keep them as is
* @returns {object} - initial state object
*/
function state(list, sortMethod)
{
var isNamedList = !Array.isArray(list)
, initState =
{
index : 0,
keyedList: isNamedList || sortMethod ? Object.keys(list) : null,
jobs : {},
results : isNamedList ? {} : [],
size : isNamedList ? Object.keys(list).length : list.length
}
;
if (sortMethod)
{
// sort array keys based on it's values
// sort object's keys just on own merit
initState.keyedList.sort(isNamedList ? sortMethod : function(a, b)
{
return sortMethod(list[a], list[b]);
});
}
return initState;
}
var async = require('./async.js');
// API
module.exports = {
iterator: wrapIterator,
callback: wrapCallback
};
/**
* Wraps iterators with long signature
*
* @this ReadableAsyncKit#
* @param {function} iterator - function to wrap
* @returns {function} - wrapped function
*/
function wrapIterator(iterator)
{
var stream = this;
return function(item, key, cb)
{
var aborter
, wrappedCb = async(wrapIteratorCallback.call(stream, cb, key))
;
stream.jobs[key] = wrappedCb;
// it's either shortcut (item, cb)
if (iterator.length == 2)
{
aborter = iterator(item, wrappedCb);
}
// or long format (item, key, cb)
else
{
aborter = iterator(item, key, wrappedCb);
}
return aborter;
};
}
/**
* Wraps provided callback function
* allowing to execute snitch function before
* real callback
*
* @this ReadableAsyncKit#
* @param {function} callback - function to wrap
* @returns {function} - wrapped function
*/
function wrapCallback(callback)
{
var stream = this;
var wrapped = function(error, result)
{
return finisher.call(stream, error, result, callback);
};
return wrapped;
}
/**
* Wraps provided iterator callback function
* makes sure snitch only called once,
* but passes secondary calls to the original callback
*
* @this ReadableAsyncKit#
* @param {function} callback - callback to wrap
* @param {number|string} key - iteration key
* @returns {function} wrapped callback
*/
function wrapIteratorCallback(callback, key)
{
var stream = this;
return function(error, output)
{
// don't repeat yourself
if (!(key in stream.jobs))
{
callback(error, output);
return;
}
// clean up jobs
delete stream.jobs[key];
return streamer.call(stream, error, {key: key, value: output}, callback);
};
}
/**
* Stream wrapper for iterator callback
*
* @this ReadableAsyncKit#
* @param {mixed} error - error response
* @param {mixed} output - iterator output
* @param {function} callback - callback that expects iterator results
*/
function streamer(error, output, callback)
{
if (error && !this.error)
{
this.error = error;
this.pause();
this.emit('error', error);
// send back value only, as expected
callback(error, output && output.value);
return;
}
// stream stuff
this.push(output);
// back to original track
// send back value only, as expected
callback(error, output && output.value);
}
/**
* Stream wrapper for finishing callback
*
* @this ReadableAsyncKit#
* @param {mixed} error - error response
* @param {mixed} output - iterator output
* @param {function} callback - callback that expects final results
*/
function finisher(error, output, callback)
{
// signal end of the stream
// only for successfully finished streams
if (!error)
{
this.push(null);
}
// back to original track
callback(error, output);
}
var abort = require('./abort.js')
, async = require('./async.js')
;
// API
module.exports = terminator;
/**
* Terminates jobs in the attached state context
*
* @this AsyncKitState#
* @param {function} callback - final callback to invoke after termination
*/
function terminator(callback)
{
if (!Object.keys(this.jobs).length)
{
return;
}
// fast forward iteration index
this.index = this.size;
// abort jobs
abort(this);
// send back results we have so far
async(callback)(null, this.results);
}
The MIT License (MIT)
Copyright (c) 2016 Alex Indigo
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
{
"_args": [
[
{
"raw": "asynckit@^0.4.0",
"scope": null,
"escapedName": "asynckit",
"name": "asynckit",
"rawSpec": "^0.4.0",
"spec": ">=0.4.0 <0.5.0",
"type": "range"
},
"F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\form-data"
]
],
"_from": "asynckit@>=0.4.0 <0.5.0",
"_id": "asynckit@0.4.0",
"_inCache": true,
"_location": "/asynckit",
"_nodeVersion": "0.12.11",
"_npmOperationalInternal": {
"host": "packages-16-east.internal.npmjs.com",
"tmp": "tmp/asynckit-0.4.0.tgz_1465928940169_0.8008207362145185"
},
"_npmUser": {
"name": "alexindigo",
"email": "iam@alexindigo.com"
},
"_npmVersion": "2.15.6",
"_phantomChildren": {},
"_requested": {
"raw": "asynckit@^0.4.0",
"scope": null,
"escapedName": "asynckit",
"name": "asynckit",
"rawSpec": "^0.4.0",
"spec": ">=0.4.0 <0.5.0",
"type": "range"
},
"_requiredBy": [
"/form-data"
],
"_resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"_shasum": "c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79",
"_shrinkwrap": null,
"_spec": "asynckit@^0.4.0",
"_where": "F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\form-data",
"author": {
"name": "Alex Indigo",
"email": "iam@alexindigo.com"
},
"bugs": {
"url": "https://github.com/alexindigo/asynckit/issues"
},
"dependencies": {},
"description": "Minimal async jobs utility library, with streams support",
"devDependencies": {
"browserify": "^13.0.0",
"browserify-istanbul": "^2.0.0",
"coveralls": "^2.11.9",
"eslint": "^2.9.0",
"istanbul": "^0.4.3",
"obake": "^0.1.2",
"phantomjs-prebuilt": "^2.1.7",
"pre-commit": "^1.1.3",
"reamde": "^1.1.0",
"rimraf": "^2.5.2",
"size-table": "^0.2.0",
"tap-spec": "^4.1.1",
"tape": "^4.5.1"
},
"directories": {},
"dist": {
"shasum": "c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79",
"tarball": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz"
},
"gitHead": "583a75ed4fe41761b66416bb6e703ebb1f8963bf",
"homepage": "https://github.com/alexindigo/asynckit#readme",
"keywords": [
"async",
"jobs",
"parallel",
"serial",
"iterator",
"array",
"object",
"stream",
"destroy",
"terminate",
"abort"
],
"license": "MIT",
"main": "index.js",
"maintainers": [
{
"name": "alexindigo",
"email": "iam@alexindigo.com"
}
],
"name": "asynckit",
"optionalDependencies": {},
"pre-commit": [
"clean",
"lint",
"test",
"browser",
"report",
"size"
],
"readme": "ERROR: No README data found!",
"repository": {
"type": "git",
"url": "git+https://github.com/alexindigo/asynckit.git"
},
"scripts": {
"browser": "browserify -t browserify-istanbul test/lib/browserify_adjustment.js test/test-*.js | obake --coverage | tap-spec",
"clean": "rimraf coverage",
"debug": "tape test/test-*.js",
"lint": "eslint *.js lib/*.js test/*.js",
"report": "istanbul report",
"size": "browserify index.js | size-table asynckit",
"test": "istanbul cover --reporter=json tape -- 'test/test-*.js' | tap-spec",
"win-test": "tape test/test-*.js"
},
"version": "0.4.0"
}
var iterate = require('./lib/iterate.js')
, initState = require('./lib/state.js')
, terminator = require('./lib/terminator.js')
;
// Public API
module.exports = parallel;
/**
* Runs iterator over provided array elements in parallel
*
* @param {array|object} list - array or object (named list) to iterate over
* @param {function} iterator - iterator to run
* @param {function} callback - invoked when all elements processed
* @returns {function} - jobs terminator
*/
function parallel(list, iterator, callback)
{
var state = initState(list);
while (state.index < (state['keyedList'] || list).length)
{
iterate(list, iterator, state, function(error, result)
{
if (error)
{
callback(error, result);
return;
}
// looks like it's the last one
if (Object.keys(state.jobs).length === 0)
{
callback(null, state.results);
return;
}
});
state.index++;
}
return terminator.bind(state, callback);
}

asynckit NPM Module

Minimal async jobs utility library, with streams support.

PhantomJS Build Linux Build Windows Build

Coverage Status Dependency Status bitHound Overall Score

AsyncKit provides harness for parallel and serial iterators over list of items represented by arrays or objects. Optionally it accepts abort function (should be synchronously return by iterator for each item), and terminates left over jobs upon an error event. For specific iteration order built-in (ascending and descending) and custom sort helpers also supported, via asynckit.serialOrdered method.

It ensures async operations to keep behavior more stable and prevent Maximum call stack size exceeded errors, from sync iterators.

compression size
asynckit.js 12.34 kB
asynckit.min.js 4.11 kB
asynckit.min.js.gz 1.47 kB

Install

$ npm install --save asynckit

Examples

Parallel Jobs

Runs iterator over provided array in parallel. Stores output in the result array, on the matching positions. In unlikely event of an error from one of the jobs, will terminate rest of the active jobs (if abort function is provided) and return error along with salvaged data to the main callback function.

Input Array

var parallel = require('asynckit').parallel
  , assert   = require('assert')
  ;

var source         = [ 1, 1, 4, 16, 64, 32, 8, 2 ]
  , expectedResult = [ 2, 2, 8, 32, 128, 64, 16, 4 ]
  , expectedTarget = [ 1, 1, 2, 4, 8, 16, 32, 64 ]
  , target         = []
  ;

parallel(source, asyncJob, function(err, result)
{
  assert.deepEqual(result, expectedResult);
  assert.deepEqual(target, expectedTarget);
});

// async job accepts one element from the array
// and a callback function
function asyncJob(item, cb)
{
  // different delays (in ms) per item
  var delay = item * 25;

  // pretend different jobs take different time to finish
  // and not in consequential order
  var timeoutId = setTimeout(function() {
    target.push(item);
    cb(null, item * 2);
  }, delay);

  // allow to cancel "leftover" jobs upon error
  // return function, invoking of which will abort this job
  return clearTimeout.bind(null, timeoutId);
}

More examples could be found in test/test-parallel-array.js.

Input Object

Also it supports named jobs, listed via object.

var parallel = require('asynckit/parallel')
  , assert   = require('assert')
  ;

var source         = { first: 1, one: 1, four: 4, sixteen: 16, sixtyFour: 64, thirtyTwo: 32, eight: 8, two: 2 }
  , expectedResult = { first: 2, one: 2, four: 8, sixteen: 32, sixtyFour: 128, thirtyTwo: 64, eight: 16, two: 4 }
  , expectedTarget = [ 1, 1, 2, 4, 8, 16, 32, 64 ]
  , expectedKeys   = [ 'first', 'one', 'two', 'four', 'eight', 'sixteen', 'thirtyTwo', 'sixtyFour' ]
  , target         = []
  , keys           = []
  ;

parallel(source, asyncJob, function(err, result)
{
  assert.deepEqual(result, expectedResult);
  assert.deepEqual(target, expectedTarget);
  assert.deepEqual(keys, expectedKeys);
});

// supports full value, key, callback (shortcut) interface
function asyncJob(item, key, cb)
{
  // different delays (in ms) per item
  var delay = item * 25;

  // pretend different jobs take different time to finish
  // and not in consequential order
  var timeoutId = setTimeout(function() {
    keys.push(key);
    target.push(item);
    cb(null, item * 2);
  }, delay);

  // allow to cancel "leftover" jobs upon error
  // return function, invoking of which will abort this job
  return clearTimeout.bind(null, timeoutId);
}

More examples could be found in test/test-parallel-object.js.

Serial Jobs

Runs iterator over provided array sequentially. Stores output in the result array, on the matching positions. In unlikely event of an error from one of the jobs, will not proceed to the rest of the items in the list and return error along with salvaged data to the main callback function.

Input Array

var serial = require('asynckit/serial')
  , assert = require('assert')
  ;

var source         = [ 1, 1, 4, 16, 64, 32, 8, 2 ]
  , expectedResult = [ 2, 2, 8, 32, 128, 64, 16, 4 ]
  , expectedTarget = [ 0, 1, 2, 3, 4, 5, 6, 7 ]
  , target         = []
  ;

serial(source, asyncJob, function(err, result)
{
  assert.deepEqual(result, expectedResult);
  assert.deepEqual(target, expectedTarget);
});

// extended interface (item, key, callback)
// also supported for arrays
function asyncJob(item, key, cb)
{
  target.push(key);

  // it will be automatically made async
  // even it iterator "returns" in the same event loop
  cb(null, item * 2);
}

More examples could be found in test/test-serial-array.js.

Input Object

Also it supports named jobs, listed via object.

var serial = require('asynckit').serial
  , assert = require('assert')
  ;

var source         = [ 1, 1, 4, 16, 64, 32, 8, 2 ]
  , expectedResult = [ 2, 2, 8, 32, 128, 64, 16, 4 ]
  , expectedTarget = [ 0, 1, 2, 3, 4, 5, 6, 7 ]
  , target         = []
  ;

var source         = { first: 1, one: 1, four: 4, sixteen: 16, sixtyFour: 64, thirtyTwo: 32, eight: 8, two: 2 }
  , expectedResult = { first: 2, one: 2, four: 8, sixteen: 32, sixtyFour: 128, thirtyTwo: 64, eight: 16, two: 4 }
  , expectedTarget = [ 1, 1, 4, 16, 64, 32, 8, 2 ]
  , target         = []
  ;


serial(source, asyncJob, function(err, result)
{
  assert.deepEqual(result, expectedResult);
  assert.deepEqual(target, expectedTarget);
});

// shortcut interface (item, callback)
// works for object as well as for the arrays
function asyncJob(item, cb)
{
  target.push(item);

  // it will be automatically made async
  // even it iterator "returns" in the same event loop
  cb(null, item * 2);
}

More examples could be found in test/test-serial-object.js.

Note: Since object is an unordered collection of properties, it may produce unexpected results with sequential iterations. Whenever order of the jobs' execution is important please use serialOrdered method.

Ordered Serial Iterations

TBD

For example compare-property package.

Streaming interface

TBD

Want to Know More?

More examples can be found in test folder.

Or open an issue with questions and/or suggestions.

License

AsyncKit is licensed under the MIT license.

var serialOrdered = require('./serialOrdered.js');
// Public API
module.exports = serial;
/**
* Runs iterator over provided array elements in series
*
* @param {array|object} list - array or object (named list) to iterate over
* @param {function} iterator - iterator to run
* @param {function} callback - invoked when all elements processed
* @returns {function} - jobs terminator
*/
function serial(list, iterator, callback)
{
return serialOrdered(list, iterator, null, callback);
}
var iterate = require('./lib/iterate.js')
, initState = require('./lib/state.js')
, terminator = require('./lib/terminator.js')
;
// Public API
module.exports = serialOrdered;
// sorting helpers
module.exports.ascending = ascending;
module.exports.descending = descending;
/**
* Runs iterator over provided sorted array elements in series
*
* @param {array|object} list - array or object (named list) to iterate over
* @param {function} iterator - iterator to run
* @param {function} sortMethod - custom sort function
* @param {function} callback - invoked when all elements processed
* @returns {function} - jobs terminator
*/
function serialOrdered(list, iterator, sortMethod, callback)
{
var state = initState(list, sortMethod);
iterate(list, iterator, state, function iteratorHandler(error, result)
{
if (error)
{
callback(error, result);
return;
}
state.index++;
// are we there yet?
if (state.index < (state['keyedList'] || list).length)
{
iterate(list, iterator, state, iteratorHandler);
return;
}
// done here
callback(null, state.results);
});
return terminator.bind(state, callback);
}
/*
* -- Sort methods
*/
/**
* sort helper to sort array elements in ascending order
*
* @param {mixed} a - an item to compare
* @param {mixed} b - an item to compare
* @returns {number} - comparison result
*/
function ascending(a, b)
{
return a < b ? -1 : a > b ? 1 : 0;
}
/**
* sort helper to sort array elements in descending order
*
* @param {mixed} a - an item to compare
* @param {mixed} b - an item to compare
* @returns {number} - comparison result
*/
function descending(a, b)
{
return -1 * ascending(a, b);
}
var inherits = require('util').inherits
, Readable = require('stream').Readable
, ReadableAsyncKit = require('./lib/readable_asynckit.js')
, ReadableParallel = require('./lib/readable_parallel.js')
, ReadableSerial = require('./lib/readable_serial.js')
, ReadableSerialOrdered = require('./lib/readable_serial_ordered.js')
;
// API
module.exports =
{
parallel : ReadableParallel,
serial : ReadableSerial,
serialOrdered : ReadableSerialOrdered,
};
inherits(ReadableAsyncKit, Readable);
inherits(ReadableParallel, ReadableAsyncKit);
inherits(ReadableSerial, ReadableAsyncKit);
inherits(ReadableSerialOrdered, ReadableAsyncKit);
/*!
* Copyright 2010 LearnBoost <dev@learnboost.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Module dependencies.
*/
var crypto = require('crypto')
, parse = require('url').parse
;
/**
* Valid keys.
*/
var keys =
[ 'acl'
, 'location'
, 'logging'
, 'notification'
, 'partNumber'
, 'policy'
, 'requestPayment'
, 'torrent'
, 'uploadId'
, 'uploads'
, 'versionId'
, 'versioning'
, 'versions'
, 'website'
]
/**
* Return an "Authorization" header value with the given `options`
* in the form of "AWS <key>:<signature>"
*
* @param {Object} options
* @return {String}
* @api private
*/
function authorization (options) {
return 'AWS ' + options.key + ':' + sign(options)
}
module.exports = authorization
module.exports.authorization = authorization
/**
* Simple HMAC-SHA1 Wrapper
*
* @param {Object} options
* @return {String}
* @api private
*/
function hmacSha1 (options) {
return crypto.createHmac('sha1', options.secret).update(options.message).digest('base64')
}
module.exports.hmacSha1 = hmacSha1
/**
* Create a base64 sha1 HMAC for `options`.
*
* @param {Object} options
* @return {String}
* @api private
*/
function sign (options) {
options.message = stringToSign(options)
return hmacSha1(options)
}
module.exports.sign = sign
/**
* Create a base64 sha1 HMAC for `options`.
*
* Specifically to be used with S3 presigned URLs
*
* @param {Object} options
* @return {String}
* @api private
*/
function signQuery (options) {
options.message = queryStringToSign(options)
return hmacSha1(options)
}
module.exports.signQuery= signQuery
/**
* Return a string for sign() with the given `options`.
*
* Spec:
*
* <verb>\n
* <md5>\n
* <content-type>\n
* <date>\n
* [headers\n]
* <resource>
*
* @param {Object} options
* @return {String}
* @api private
*/
function stringToSign (options) {
var headers = options.amazonHeaders || ''
if (headers) headers += '\n'
var r =
[ options.verb
, options.md5
, options.contentType
, options.date ? options.date.toUTCString() : ''
, headers + options.resource
]
return r.join('\n')
}
module.exports.queryStringToSign = stringToSign
/**
* Return a string for sign() with the given `options`, but is meant exclusively
* for S3 presigned URLs
*
* Spec:
*
* <date>\n
* <resource>
*
* @param {Object} options
* @return {String}
* @api private
*/
function queryStringToSign (options){
return 'GET\n\n\n' + options.date + '\n' + options.resource
}
module.exports.queryStringToSign = queryStringToSign
/**
* Perform the following:
*
* - ignore non-amazon headers
* - lowercase fields
* - sort lexicographically
* - trim whitespace between ":"
* - join with newline
*
* @param {Object} headers
* @return {String}
* @api private
*/
function canonicalizeHeaders (headers) {
var buf = []
, fields = Object.keys(headers)
;
for (var i = 0, len = fields.length; i < len; ++i) {
var field = fields[i]
, val = headers[field]
, field = field.toLowerCase()
;
if (0 !== field.indexOf('x-amz')) continue
buf.push(field + ':' + val)
}
return buf.sort().join('\n')
}
module.exports.canonicalizeHeaders = canonicalizeHeaders
/**
* Perform the following:
*
* - ignore non sub-resources
* - sort lexicographically
*
* @param {String} resource
* @return {String}
* @api private
*/
function canonicalizeResource (resource) {
var url = parse(resource, true)
, path = url.pathname
, buf = []
;
Object.keys(url.query).forEach(function(key){
if (!~keys.indexOf(key)) return
var val = '' == url.query[key] ? '' : '=' + encodeURIComponent(url.query[key])
buf.push(key + val)
})
return path + (buf.length ? '?' + buf.sort().join('&') : '')
}
module.exports.canonicalizeResource = canonicalizeResource
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
You must give any other recipients of the Work or Derivative Works a copy of this License; and
You must cause any modified files to carry prominent notices stating that You changed the files; and
You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
{
"_args": [
[
{
"raw": "aws-sign2@~0.6.0",
"scope": null,
"escapedName": "aws-sign2",
"name": "aws-sign2",
"rawSpec": "~0.6.0",
"spec": ">=0.6.0 <0.7.0",
"type": "range"
},
"F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\request"
]
],
"_from": "aws-sign2@>=0.6.0 <0.7.0",
"_id": "aws-sign2@0.6.0",
"_inCache": true,
"_location": "/aws-sign2",
"_nodeVersion": "4.1.2",
"_npmUser": {
"name": "mikeal",
"email": "mikeal.rogers@gmail.com"
},
"_npmVersion": "2.14.4",
"_phantomChildren": {},
"_requested": {
"raw": "aws-sign2@~0.6.0",
"scope": null,
"escapedName": "aws-sign2",
"name": "aws-sign2",
"rawSpec": "~0.6.0",
"spec": ">=0.6.0 <0.7.0",
"type": "range"
},
"_requiredBy": [
"/request"
],
"_resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz",
"_shasum": "14342dd38dbcc94d0e5b87d763cd63612c0e794f",
"_shrinkwrap": null,
"_spec": "aws-sign2@~0.6.0",
"_where": "F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\request",
"author": {
"name": "Mikeal Rogers",
"email": "mikeal.rogers@gmail.com",
"url": "http://www.futurealoof.com"
},
"bugs": {
"url": "https://github.com/mikeal/aws-sign/issues"
},
"dependencies": {},
"description": "AWS signing. Originally pulled from LearnBoost/knox, maintained as vendor in request, now a standalone module.",
"devDependencies": {},
"directories": {},
"dist": {
"shasum": "14342dd38dbcc94d0e5b87d763cd63612c0e794f",
"tarball": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz"
},
"engines": {
"node": "*"
},
"gitHead": "8554bdb41268fa295eb1ee300f4adaa9f7f07fec",
"homepage": "https://github.com/mikeal/aws-sign#readme",
"license": "Apache-2.0",
"main": "index.js",
"maintainers": [
{
"name": "mikeal",
"email": "mikeal.rogers@gmail.com"
}
],
"name": "aws-sign2",
"optionalDependencies": {},
"readme": "ERROR: No README data found!",
"repository": {
"url": "git+https://github.com/mikeal/aws-sign.git"
},
"scripts": {},
"version": "0.6.0"
}

aws-sign

AWS signing. Originally pulled from LearnBoost/knox, maintained as vendor in request, now a standalone module.

language: node_js
node_js:
- "0.10"
- "0.12"
- "4.2"
var aws4 = exports,
url = require('url'),
querystring = require('querystring'),
crypto = require('crypto'),
lru = require('./lru'),
credentialsCache = lru(1000)
// http://docs.amazonwebservices.com/general/latest/gr/signature-version-4.html
function hmac(key, string, encoding) {
return crypto.createHmac('sha256', key).update(string, 'utf8').digest(encoding)
}
function hash(string, encoding) {
return crypto.createHash('sha256').update(string, 'utf8').digest(encoding)
}
// This function assumes the string has already been percent encoded
function encodeRfc3986(urlEncodedString) {
return urlEncodedString.replace(/[!'()*]/g, function(c) {
return '%' + c.charCodeAt(0).toString(16).toUpperCase()
})
}
// request: { path | body, [host], [method], [headers], [service], [region] }
// credentials: { accessKeyId, secretAccessKey, [sessionToken] }
function RequestSigner(request, credentials) {
if (typeof request === 'string') request = url.parse(request)
var headers = request.headers = (request.headers || {}),
hostParts = this.matchHost(request.hostname || request.host || headers.Host || headers.host)
this.request = request
this.credentials = credentials || this.defaultCredentials()
this.service = request.service || hostParts[0] || ''
this.region = request.region || hostParts[1] || 'us-east-1'
// SES uses a different domain from the service name
if (this.service === 'email') this.service = 'ses'
if (!request.method && request.body)
request.method = 'POST'
if (!headers.Host && !headers.host) {
headers.Host = request.hostname || request.host || this.createHost()
// If a port is specified explicitly, use it as is
if (request.port)
headers.Host += ':' + request.port
}
if (!request.hostname && !request.host)
request.hostname = headers.Host || headers.host
this.isCodeCommitGit = this.service === 'codecommit' && request.method === 'GIT'
}
RequestSigner.prototype.matchHost = function(host) {
var match = (host || '').match(/([^\.]+)\.(?:([^\.]*)\.)?amazonaws\.com$/)
var hostParts = (match || []).slice(1, 3)
// ES's hostParts are sometimes the other way round, if the value that is expected
// to be region equals ‘es’ switch them back
// e.g. search-cluster-name-aaaa00aaaa0aaa0aaaaaaa0aaa.us-east-1.es.amazonaws.com
if (hostParts[1] === 'es')
hostParts = hostParts.reverse()
return hostParts
}
// http://docs.aws.amazon.com/general/latest/gr/rande.html
RequestSigner.prototype.isSingleRegion = function() {
// Special case for S3 and SimpleDB in us-east-1
if (['s3', 'sdb'].indexOf(this.service) >= 0 && this.region === 'us-east-1') return true
return ['cloudfront', 'ls', 'route53', 'iam', 'importexport', 'sts']
.indexOf(this.service) >= 0
}
RequestSigner.prototype.createHost = function() {
var region = this.isSingleRegion() ? '' :
(this.service === 's3' && this.region !== 'us-east-1' ? '-' : '.') + this.region,
service = this.service === 'ses' ? 'email' : this.service
return service + region + '.amazonaws.com'
}
RequestSigner.prototype.prepareRequest = function() {
this.parsePath()
var request = this.request, headers = request.headers, query
if (request.signQuery) {
this.parsedPath.query = query = this.parsedPath.query || {}
if (this.credentials.sessionToken)
query['X-Amz-Security-Token'] = this.credentials.sessionToken
if (this.service === 's3' && !query['X-Amz-Expires'])
query['X-Amz-Expires'] = 86400
if (query['X-Amz-Date'])
this.datetime = query['X-Amz-Date']
else
query['X-Amz-Date'] = this.getDateTime()
query['X-Amz-Algorithm'] = 'AWS4-HMAC-SHA256'
query['X-Amz-Credential'] = this.credentials.accessKeyId + '/' + this.credentialString()
query['X-Amz-SignedHeaders'] = this.signedHeaders()
} else {
if (!request.doNotModifyHeaders && !this.isCodeCommitGit) {
if (request.body && !headers['Content-Type'] && !headers['content-type'])
headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=utf-8'
if (request.body && !headers['Content-Length'] && !headers['content-length'])
headers['Content-Length'] = Buffer.byteLength(request.body)
if (this.credentials.sessionToken && !headers['X-Amz-Security-Token'] && !headers['x-amz-security-token'])
headers['X-Amz-Security-Token'] = this.credentials.sessionToken
if (this.service === 's3' && !headers['X-Amz-Content-Sha256'] && !headers['x-amz-content-sha256'])
headers['X-Amz-Content-Sha256'] = hash(this.request.body || '', 'hex')
if (headers['X-Amz-Date'] || headers['x-amz-date'])
this.datetime = headers['X-Amz-Date'] || headers['x-amz-date']
else
headers['X-Amz-Date'] = this.getDateTime()
}
delete headers.Authorization
delete headers.authorization
}
}
RequestSigner.prototype.sign = function() {
if (!this.parsedPath) this.prepareRequest()
if (this.request.signQuery) {
this.parsedPath.query['X-Amz-Signature'] = this.signature()
} else {
this.request.headers.Authorization = this.authHeader()
}
this.request.path = this.formatPath()
return this.request
}
RequestSigner.prototype.getDateTime = function() {
if (!this.datetime) {
var headers = this.request.headers,
date = new Date(headers.Date || headers.date || new Date)
this.datetime = date.toISOString().replace(/[:\-]|\.\d{3}/g, '')
// Remove the trailing 'Z' on the timestamp string for CodeCommit git access
if (this.isCodeCommitGit) this.datetime = this.datetime.slice(0, -1)
}
return this.datetime
}
RequestSigner.prototype.getDate = function() {
return this.getDateTime().substr(0, 8)
}
RequestSigner.prototype.authHeader = function() {
return [
'AWS4-HMAC-SHA256 Credential=' + this.credentials.accessKeyId + '/' + this.credentialString(),
'SignedHeaders=' + this.signedHeaders(),
'Signature=' + this.signature(),
].join(', ')
}
RequestSigner.prototype.signature = function() {
var date = this.getDate(),
cacheKey = [this.credentials.secretAccessKey, date, this.region, this.service].join(),
kDate, kRegion, kService, kCredentials = credentialsCache.get(cacheKey)
if (!kCredentials) {
kDate = hmac('AWS4' + this.credentials.secretAccessKey, date)
kRegion = hmac(kDate, this.region)
kService = hmac(kRegion, this.service)
kCredentials = hmac(kService, 'aws4_request')
credentialsCache.set(cacheKey, kCredentials)
}
return hmac(kCredentials, this.stringToSign(), 'hex')
}
RequestSigner.prototype.stringToSign = function() {
return [
'AWS4-HMAC-SHA256',
this.getDateTime(),
this.credentialString(),
hash(this.canonicalString(), 'hex'),
].join('\n')
}
RequestSigner.prototype.canonicalString = function() {
if (!this.parsedPath) this.prepareRequest()
var pathStr = this.parsedPath.path,
query = this.parsedPath.query,
headers = this.request.headers,
queryStr = '',
normalizePath = this.service !== 's3',
decodePath = this.service === 's3' || this.request.doNotEncodePath,
decodeSlashesInPath = this.service === 's3',
firstValOnly = this.service === 's3',
bodyHash
if (this.service === 's3' && this.request.signQuery) {
bodyHash = 'UNSIGNED-PAYLOAD'
} else if (this.isCodeCommitGit) {
bodyHash = ''
} else {
bodyHash = headers['X-Amz-Content-Sha256'] || headers['x-amz-content-sha256'] ||
hash(this.request.body || '', 'hex')
}
if (query) {
queryStr = encodeRfc3986(querystring.stringify(Object.keys(query).sort().reduce(function(obj, key) {
if (!key) return obj
obj[key] = !Array.isArray(query[key]) ? query[key] :
(firstValOnly ? query[key][0] : query[key].slice().sort())
return obj
}, {})))
}
if (pathStr !== '/') {
if (normalizePath) pathStr = pathStr.replace(/\/{2,}/g, '/')
pathStr = pathStr.split('/').reduce(function(path, piece) {
if (normalizePath && piece === '..') {
path.pop()
} else if (!normalizePath || piece !== '.') {
if (decodePath) piece = querystring.unescape(piece)
path.push(encodeRfc3986(querystring.escape(piece)))
}
return path
}, []).join('/')
if (pathStr[0] !== '/') pathStr = '/' + pathStr
if (decodeSlashesInPath) pathStr = pathStr.replace(/%2F/g, '/')
}
return [
this.request.method || 'GET',
pathStr,
queryStr,
this.canonicalHeaders() + '\n',
this.signedHeaders(),
bodyHash,
].join('\n')
}
RequestSigner.prototype.canonicalHeaders = function() {
var headers = this.request.headers
function trimAll(header) {
return header.toString().trim().replace(/\s+/g, ' ')
}
return Object.keys(headers)
.sort(function(a, b) { return a.toLowerCase() < b.toLowerCase() ? -1 : 1 })
.map(function(key) { return key.toLowerCase() + ':' + trimAll(headers[key]) })
.join('\n')
}
RequestSigner.prototype.signedHeaders = function() {
return Object.keys(this.request.headers)
.map(function(key) { return key.toLowerCase() })
.sort()
.join(';')
}
RequestSigner.prototype.credentialString = function() {
return [
this.getDate(),
this.region,
this.service,
'aws4_request',
].join('/')
}
RequestSigner.prototype.defaultCredentials = function() {
var env = process.env
return {
accessKeyId: env.AWS_ACCESS_KEY_ID || env.AWS_ACCESS_KEY,
secretAccessKey: env.AWS_SECRET_ACCESS_KEY || env.AWS_SECRET_KEY,
sessionToken: env.AWS_SESSION_TOKEN,
}
}
RequestSigner.prototype.parsePath = function() {
var path = this.request.path || '/',
queryIx = path.indexOf('?'),
query = null
if (queryIx >= 0) {
query = querystring.parse(path.slice(queryIx + 1))
path = path.slice(0, queryIx)
}
// S3 doesn't always encode characters > 127 correctly and
// all services don't encode characters > 255 correctly
// So if there are non-reserved chars (and it's not already all % encoded), just encode them all
if (/[^0-9A-Za-z!'()*\-._~%/]/.test(path)) {
path = path.split('/').map(function(piece) {
return querystring.escape(querystring.unescape(piece))
}).join('/')
}
this.parsedPath = {
path: path,
query: query,
}
}
RequestSigner.prototype.formatPath = function() {
var path = this.parsedPath.path,
query = this.parsedPath.query
if (!query) return path
// Services don't support empty query string keys
if (query[''] != null) delete query['']
return path + '?' + encodeRfc3986(querystring.stringify(query))
}
aws4.RequestSigner = RequestSigner
aws4.sign = function(request, credentials) {
return new RequestSigner(request, credentials).sign()
}
Copyright 2013 Michael Hart (michael.hart.au@gmail.com)
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
module.exports = function(size) {
return new LruCache(size)
}
function LruCache(size) {
this.capacity = size | 0
this.map = Object.create(null)
this.list = new DoublyLinkedList()
}
LruCache.prototype.get = function(key) {
var node = this.map[key]
if (node == null) return undefined
this.used(node)
return node.val
}
LruCache.prototype.set = function(key, val) {
var node = this.map[key]
if (node != null) {
node.val = val
} else {
if (!this.capacity) this.prune()
if (!this.capacity) return false
node = new DoublyLinkedNode(key, val)
this.map[key] = node
this.capacity--
}
this.used(node)
return true
}
LruCache.prototype.used = function(node) {
this.list.moveToFront(node)
}
LruCache.prototype.prune = function() {
var node = this.list.pop()
if (node != null) {
delete this.map[node.key]
this.capacity++
}
}
function DoublyLinkedList() {
this.firstNode = null
this.lastNode = null
}
DoublyLinkedList.prototype.moveToFront = function(node) {
if (this.firstNode == node) return
this.remove(node)
if (this.firstNode == null) {
this.firstNode = node
this.lastNode = node
node.prev = null
node.next = null
} else {
node.prev = null
node.next = this.firstNode
node.next.prev = node
this.firstNode = node
}
}
DoublyLinkedList.prototype.pop = function() {
var lastNode = this.lastNode
if (lastNode != null) {
this.remove(lastNode)
}
return lastNode
}
DoublyLinkedList.prototype.remove = function(node) {
if (this.firstNode == node) {
this.firstNode = node.next
} else if (node.prev != null) {
node.prev.next = node.next
}
if (this.lastNode == node) {
this.lastNode = node.prev
} else if (node.next != null) {
node.next.prev = node.prev
}
}
function DoublyLinkedNode(key, val) {
this.key = key
this.val = val
this.prev = null
this.next = null
}
{
"_args": [
[
{
"raw": "aws4@^1.2.1",
"scope": null,
"escapedName": "aws4",
"name": "aws4",
"rawSpec": "^1.2.1",
"spec": ">=1.2.1 <2.0.0",
"type": "range"
},
"F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\request"
]
],
"_from": "aws4@>=1.2.1 <2.0.0",
"_id": "aws4@1.6.0",
"_inCache": true,
"_location": "/aws4",
"_nodeVersion": "4.5.0",
"_npmOperationalInternal": {
"host": "packages-18-east.internal.npmjs.com",
"tmp": "tmp/aws4-1.6.0.tgz_1486481933920_0.6127187723759562"
},
"_npmUser": {
"name": "hichaelmart",
"email": "michael.hart.au@gmail.com"
},
"_npmVersion": "4.0.5",
"_phantomChildren": {},
"_requested": {
"raw": "aws4@^1.2.1",
"scope": null,
"escapedName": "aws4",
"name": "aws4",
"rawSpec": "^1.2.1",
"spec": ">=1.2.1 <2.0.0",
"type": "range"
},
"_requiredBy": [
"/request"
],
"_resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz",
"_shasum": "83ef5ca860b2b32e4a0deedee8c771b9db57471e",
"_shrinkwrap": null,
"_spec": "aws4@^1.2.1",
"_where": "F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\request",
"author": {
"name": "Michael Hart",
"email": "michael.hart.au@gmail.com",
"url": "http://github.com/mhart"
},
"bugs": {
"url": "https://github.com/mhart/aws4/issues"
},
"dependencies": {},
"description": "Signs and prepares requests using AWS Signature Version 4",
"devDependencies": {
"mocha": "^2.4.5",
"should": "^8.2.2"
},
"directories": {},
"dist": {
"shasum": "83ef5ca860b2b32e4a0deedee8c771b9db57471e",
"tarball": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz"
},
"gitHead": "74bf0b64d1e8cbcd184964999c7ef53f52d7ad32",
"homepage": "https://github.com/mhart/aws4#readme",
"keywords": [
"amazon",
"aws",
"signature",
"s3",
"ec2",
"autoscaling",
"cloudformation",
"elasticloadbalancing",
"elb",
"elasticbeanstalk",
"cloudsearch",
"dynamodb",
"kinesis",
"lambda",
"glacier",
"sqs",
"sns",
"iam",
"sts",
"ses",
"swf",
"storagegateway",
"datapipeline",
"directconnect",
"redshift",
"opsworks",
"rds",
"monitoring",
"cloudtrail",
"cloudfront",
"codedeploy",
"elasticache",
"elasticmapreduce",
"elastictranscoder",
"emr",
"cloudwatch",
"mobileanalytics",
"cognitoidentity",
"cognitosync",
"cognito",
"containerservice",
"ecs",
"appstream",
"keymanagementservice",
"kms",
"config",
"cloudhsm",
"route53",
"route53domains",
"logs"
],
"license": "MIT",
"main": "aws4.js",
"maintainers": [
{
"name": "hichaelmart",
"email": "michael.hart.au@gmail.com"
}
],
"name": "aws4",
"optionalDependencies": {},
"readme": "ERROR: No README data found!",
"repository": {
"type": "git",
"url": "git+https://github.com/mhart/aws4.git"
},
"scripts": {
"test": "mocha ./test/fast.js ./test/slow.js -b -t 100s -R list"
},
"version": "1.6.0"
}

aws4

Build Status

A small utility to sign vanilla node.js http(s) request options using Amazon's AWS Signature Version 4.

Can also be used in the browser.

This signature is supported by nearly all Amazon services, including S3, EC2, DynamoDB, Kinesis, Lambda, SQS, SNS, IAM, STS, RDS, CloudWatch, CloudWatch Logs, CodeDeploy, CloudFront, CloudTrail, ElastiCache, EMR, Glacier, CloudSearch, Elastic Load Balancing, Elastic Transcoder, CloudFormation, Elastic Beanstalk, Storage Gateway, Data Pipeline, Direct Connect, Redshift, OpsWorks, SES, SWF, AutoScaling, Mobile Analytics, Cognito Identity, Cognito Sync, Container Service, AppStream, Key Management Service, Config, CloudHSM, Route53 and Route53 Domains.

Indeed, the only AWS services that don't support v4 as of 2014-12-30 are Import/Export and SimpleDB (they only support AWS Signature Version 2).

It also provides defaults for a number of core AWS headers and request parameters, making it very easy to query AWS services, or build out a fully-featured AWS library.

Example

var http  = require('http'),
    https = require('https'),
    aws4  = require('aws4')

// given an options object you could pass to http.request
var opts = {host: 'sqs.us-east-1.amazonaws.com', path: '/?Action=ListQueues'}

// alternatively (as aws4 can infer the host):
opts = {service: 'sqs', region: 'us-east-1', path: '/?Action=ListQueues'}

// alternatively (as us-east-1 is default):
opts = {service: 'sqs', path: '/?Action=ListQueues'}

aws4.sign(opts) // assumes AWS credentials are available in process.env

console.log(opts)
/*
{
  host: 'sqs.us-east-1.amazonaws.com',
  path: '/?Action=ListQueues',
  headers: {
    Host: 'sqs.us-east-1.amazonaws.com',
    'X-Amz-Date': '20121226T061030Z',
    Authorization: 'AWS4-HMAC-SHA256 Credential=ABCDEF/20121226/us-east-1/sqs/aws4_request, ...'
  }
}
*/

// we can now use this to query AWS using the standard node.js http API
http.request(opts, function(res) { res.pipe(process.stdout) }).end()
/*
<?xml version="1.0"?>
<ListQueuesResponse xmlns="http://queue.amazonaws.com/doc/2012-11-05/">
...
*/

More options

// you can also pass AWS credentials in explicitly (otherwise taken from process.env)
aws4.sign(opts, {accessKeyId: '', secretAccessKey: ''})

// can also add the signature to query strings
aws4.sign({service: 's3', path: '/my-bucket?X-Amz-Expires=12345', signQuery: true})

// create a utility function to pipe to stdout (with https this time)
function request(o) { https.request(o, function(res) { res.pipe(process.stdout) }).end(o.body || '') }

// aws4 can infer the HTTP method if a body is passed in
// method will be POST and Content-Type: 'application/x-www-form-urlencoded; charset=utf-8'
request(aws4.sign({service: 'iam', body: 'Action=ListGroups&Version=2010-05-08'}))
/*
<ListGroupsResponse xmlns="https://iam.amazonaws.com/doc/2010-05-08/">
...
*/

// can specify any custom option or header as per usual
request(aws4.sign({
  service: 'dynamodb',
  region: 'ap-southeast-2',
  method: 'POST',
  path: '/',
  headers: {
    'Content-Type': 'application/x-amz-json-1.0',
    'X-Amz-Target': 'DynamoDB_20120810.ListTables'
  },
  body: '{}'
}))
/*
{"TableNames":[]}
...
*/

// works with all other services that support Signature Version 4

request(aws4.sign({service: 's3', path: '/', signQuery: true}))
/*
<ListAllMyBucketsResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
...
*/

request(aws4.sign({service: 'ec2', path: '/?Action=DescribeRegions&Version=2014-06-15'}))
/*
<DescribeRegionsResponse xmlns="http://ec2.amazonaws.com/doc/2014-06-15/">
...
*/

request(aws4.sign({service: 'sns', path: '/?Action=ListTopics&Version=2010-03-31'}))
/*
<ListTopicsResponse xmlns="http://sns.amazonaws.com/doc/2010-03-31/">
...
*/

request(aws4.sign({service: 'sts', path: '/?Action=GetSessionToken&Version=2011-06-15'}))
/*
<GetSessionTokenResponse xmlns="https://sts.amazonaws.com/doc/2011-06-15/">
...
*/

request(aws4.sign({service: 'cloudsearch', path: '/?Action=ListDomainNames&Version=2013-01-01'}))
/*
<ListDomainNamesResponse xmlns="http://cloudsearch.amazonaws.com/doc/2013-01-01/">
...
*/

request(aws4.sign({service: 'ses', path: '/?Action=ListIdentities&Version=2010-12-01'}))
/*
<ListIdentitiesResponse xmlns="http://ses.amazonaws.com/doc/2010-12-01/">
...
*/

request(aws4.sign({service: 'autoscaling', path: '/?Action=DescribeAutoScalingInstances&Version=2011-01-01'}))
/*
<DescribeAutoScalingInstancesResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
...
*/

request(aws4.sign({service: 'elasticloadbalancing', path: '/?Action=DescribeLoadBalancers&Version=2012-06-01'}))
/*
<DescribeLoadBalancersResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2012-06-01/">
...
*/

request(aws4.sign({service: 'cloudformation', path: '/?Action=ListStacks&Version=2010-05-15'}))
/*
<ListStacksResponse xmlns="http://cloudformation.amazonaws.com/doc/2010-05-15/">
...
*/

request(aws4.sign({service: 'elasticbeanstalk', path: '/?Action=ListAvailableSolutionStacks&Version=2010-12-01'}))
/*
<ListAvailableSolutionStacksResponse xmlns="http://elasticbeanstalk.amazonaws.com/docs/2010-12-01/">
...
*/

request(aws4.sign({service: 'rds', path: '/?Action=DescribeDBInstances&Version=2012-09-17'}))
/*
<DescribeDBInstancesResponse xmlns="http://rds.amazonaws.com/doc/2012-09-17/">
...
*/

request(aws4.sign({service: 'monitoring', path: '/?Action=ListMetrics&Version=2010-08-01'}))
/*
<ListMetricsResponse xmlns="http://monitoring.amazonaws.com/doc/2010-08-01/">
...
*/

request(aws4.sign({service: 'redshift', path: '/?Action=DescribeClusters&Version=2012-12-01'}))
/*
<DescribeClustersResponse xmlns="http://redshift.amazonaws.com/doc/2012-12-01/">
...
*/

request(aws4.sign({service: 'cloudfront', path: '/2014-05-31/distribution'}))
/*
<DistributionList xmlns="http://cloudfront.amazonaws.com/doc/2014-05-31/">
...
*/

request(aws4.sign({service: 'elasticache', path: '/?Action=DescribeCacheClusters&Version=2014-07-15'}))
/*
<DescribeCacheClustersResponse xmlns="http://elasticache.amazonaws.com/doc/2014-07-15/">
...
*/

request(aws4.sign({service: 'elasticmapreduce', path: '/?Action=DescribeJobFlows&Version=2009-03-31'}))
/*
<DescribeJobFlowsResponse xmlns="http://elasticmapreduce.amazonaws.com/doc/2009-03-31">
...
*/

request(aws4.sign({service: 'route53', path: '/2013-04-01/hostedzone'}))
/*
<ListHostedZonesResponse xmlns="https://route53.amazonaws.com/doc/2013-04-01/">
...
*/

request(aws4.sign({service: 'appstream', path: '/applications'}))
/*
{"_links":{"curie":[{"href":"http://docs.aws.amazon.com/appstream/latest/...
...
*/

request(aws4.sign({service: 'cognito-sync', path: '/identitypools'}))
/*
{"Count":0,"IdentityPoolUsages":[],"MaxResults":16,"NextToken":null}
...
*/

request(aws4.sign({service: 'elastictranscoder', path: '/2012-09-25/pipelines'}))
/*
{"NextPageToken":null,"Pipelines":[]}
...
*/

request(aws4.sign({service: 'lambda', path: '/2014-11-13/functions/'}))
/*
{"Functions":[],"NextMarker":null}
...
*/

request(aws4.sign({service: 'ecs', path: '/?Action=ListClusters&Version=2014-11-13'}))
/*
<ListClustersResponse xmlns="http://ecs.amazonaws.com/doc/2014-11-13/">
...
*/

request(aws4.sign({service: 'glacier', path: '/-/vaults', headers: {'X-Amz-Glacier-Version': '2012-06-01'}}))
/*
{"Marker":null,"VaultList":[]}
...
*/

request(aws4.sign({service: 'storagegateway', body: '{}', headers: {
  'Content-Type': 'application/x-amz-json-1.1',
  'X-Amz-Target': 'StorageGateway_20120630.ListGateways'
}}))
/*
{"Gateways":[]}
...
*/

request(aws4.sign({service: 'datapipeline', body: '{}', headers: {
  'Content-Type': 'application/x-amz-json-1.1',
  'X-Amz-Target': 'DataPipeline.ListPipelines'
}}))
/*
{"hasMoreResults":false,"pipelineIdList":[]}
...
*/

request(aws4.sign({service: 'opsworks', body: '{}', headers: {
  'Content-Type': 'application/x-amz-json-1.1',
  'X-Amz-Target': 'OpsWorks_20130218.DescribeStacks'
}}))
/*
{"Stacks":[]}
...
*/

request(aws4.sign({service: 'route53domains', body: '{}', headers: {
  'Content-Type': 'application/x-amz-json-1.1',
  'X-Amz-Target': 'Route53Domains_v20140515.ListDomains'
}}))
/*
{"Domains":[]}
...
*/

request(aws4.sign({service: 'kinesis', body: '{}', headers: {
  'Content-Type': 'application/x-amz-json-1.1',
  'X-Amz-Target': 'Kinesis_20131202.ListStreams'
}}))
/*
{"HasMoreStreams":false,"StreamNames":[]}
...
*/

request(aws4.sign({service: 'cloudtrail', body: '{}', headers: {
  'Content-Type': 'application/x-amz-json-1.1',
  'X-Amz-Target': 'CloudTrail_20131101.DescribeTrails'
}}))
/*
{"trailList":[]}
...
*/

request(aws4.sign({service: 'logs', body: '{}', headers: {
  'Content-Type': 'application/x-amz-json-1.1',
  'X-Amz-Target': 'Logs_20140328.DescribeLogGroups'
}}))
/*
{"logGroups":[]}
...
*/

request(aws4.sign({service: 'codedeploy', body: '{}', headers: {
  'Content-Type': 'application/x-amz-json-1.1',
  'X-Amz-Target': 'CodeDeploy_20141006.ListApplications'
}}))
/*
{"applications":[]}
...
*/

request(aws4.sign({service: 'directconnect', body: '{}', headers: {
  'Content-Type': 'application/x-amz-json-1.1',
  'X-Amz-Target': 'OvertureService.DescribeConnections'
}}))
/*
{"connections":[]}
...
*/

request(aws4.sign({service: 'kms', body: '{}', headers: {
  'Content-Type': 'application/x-amz-json-1.1',
  'X-Amz-Target': 'TrentService.ListKeys'
}}))
/*
{"Keys":[],"Truncated":false}
...
*/

request(aws4.sign({service: 'config', body: '{}', headers: {
  'Content-Type': 'application/x-amz-json-1.1',
  'X-Amz-Target': 'StarlingDoveService.DescribeDeliveryChannels'
}}))
/*
{"DeliveryChannels":[]}
...
*/

request(aws4.sign({service: 'cloudhsm', body: '{}', headers: {
  'Content-Type': 'application/x-amz-json-1.1',
  'X-Amz-Target': 'CloudHsmFrontendService.ListAvailableZones'
}}))
/*
{"AZList":["us-east-1a","us-east-1b","us-east-1c"]}
...
*/

request(aws4.sign({
  service: 'swf',
  body: '{"registrationStatus":"REGISTERED"}',
  headers: {
    'Content-Type': 'application/x-amz-json-1.0',
    'X-Amz-Target': 'SimpleWorkflowService.ListDomains'
  }
}))
/*
{"domainInfos":[]}
...
*/

request(aws4.sign({
  service: 'cognito-identity',
  body: '{"MaxResults": 1}',
  headers: {
    'Content-Type': 'application/x-amz-json-1.1',
    'X-Amz-Target': 'AWSCognitoIdentityService.ListIdentityPools'
  }
}))
/*
{"IdentityPools":[]}
...
*/

request(aws4.sign({
  service: 'mobileanalytics',
  path: '/2014-06-05/events',
  body: JSON.stringify({events:[{
    eventType: 'a',
    timestamp: new Date().toISOString(),
    session: {},
  }]}),
  headers: {
    'Content-Type': 'application/json',
    'X-Amz-Client-Context': JSON.stringify({
      client: {client_id: 'a', app_title: 'a'},
      custom: {},
      env: {platform: 'a'},
      services: {},
    }),
  }
}))
/*
(HTTP 202, empty response)
*/

// Generate CodeCommit Git access password
var signer = new aws4.RequestSigner({
  service: 'codecommit',
  host: 'git-codecommit.us-east-1.amazonaws.com',
  method: 'GIT',
  path: '/v1/repos/MyAwesomeRepo',
})
var password = signer.getDateTime() + 'Z' + signer.signature()

API

aws4.sign(requestOptions, [credentials])

This calculates and populates the Authorization header of requestOptions, and any other necessary AWS headers and/or request options. Returns requestOptions as a convenience for chaining.

requestOptions is an object holding the same options that the node.js http.request function takes.

The following properties of requestOptions are used in the signing or populated if they don't already exist:

  • hostname or host (will be determined from service and region if not given)
  • method (will use 'GET' if not given or 'POST' if there is a body)
  • path (will use '/' if not given)
  • body (will use '' if not given)
  • service (will be calculated from hostname or host if not given)
  • region (will be calculated from hostname or host or use 'us-east-1' if not given)
  • headers['Host'] (will use hostname or host or be calculated if not given)
  • headers['Content-Type'] (will use 'application/x-www-form-urlencoded; charset=utf-8' if not given and there is a body)
  • headers['Date'] (used to calculate the signature date if given, otherwise new Date is used)

Your AWS credentials (which can be found in your AWS console) can be specified in one of two ways:

  • As the second argument, like this:
aws4.sign(requestOptions, {
  secretAccessKey: "<your-secret-access-key>",
  accessKeyId: "<your-access-key-id>",
  sessionToken: "<your-session-token>"
})
  • From process.env, such as this:
export AWS_SECRET_ACCESS_KEY="<your-secret-access-key>"
export AWS_ACCESS_KEY_ID="<your-access-key-id>"
export AWS_SESSION_TOKEN="<your-session-token>"

(will also use AWS_ACCESS_KEY and AWS_SECRET_KEY if available)

The sessionToken property and AWS_SESSION_TOKEN environment variable are optional for signing with IAM STS temporary credentials.

Installation

With npm do:

npm install aws4

Can also be used in the browser.

Thanks

Thanks to @jed for his dynamo-client lib where I first committed and subsequently extracted this code.

Also thanks to the official node.js AWS SDK for giving me a start on implementing the v4 signature.

'use strict';
var crypto_hash_sha512 = require('tweetnacl').lowlevel.crypto_hash;
/*
* This file is a 1:1 port from the OpenBSD blowfish.c and bcrypt_pbkdf.c. As a
* result, it retains the original copyright and license. The two files are
* under slightly different (but compatible) licenses, and are here combined in
* one file.
*
* Credit for the actual porting work goes to:
* Devi Mandiri <me@devi.web.id>
*/
/*
* The Blowfish portions are under the following license:
*
* Blowfish block cipher for OpenBSD
* Copyright 1997 Niels Provos <provos@physnet.uni-hamburg.de>
* All rights reserved.
*
* Implementation advice by David Mazieres <dm@lcs.mit.edu>.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* The bcrypt_pbkdf portions are under the following license:
*
* Copyright (c) 2013 Ted Unangst <tedu@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
* Performance improvements (Javascript-specific):
*
* Copyright 2016, Joyent Inc
* Author: Alex Wilson <alex.wilson@joyent.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
// Ported from OpenBSD bcrypt_pbkdf.c v1.9
var BLF_J = 0;
var Blowfish = function() {
this.S = [
new Uint32Array([
0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7,
0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99,
0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e,
0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee,
0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef,
0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e,
0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440,
0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce,
0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e,
0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677,
0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032,
0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88,
0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e,
0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0,
0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98,
0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88,
0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6,
0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d,
0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7,
0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba,
0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f,
0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09,
0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb,
0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279,
0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab,
0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82,
0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573,
0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0,
0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790,
0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8,
0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0,
0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7,
0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad,
0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1,
0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9,
0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477,
0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49,
0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af,
0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5,
0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41,
0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400,
0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915,
0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a]),
new Uint32Array([
0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623,
0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266,
0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1,
0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e,
0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6,
0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e,
0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1,
0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737,
0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8,
0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff,
0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701,
0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7,
0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41,
0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331,
0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf,
0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e,
0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87,
0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c,
0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2,
0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16,
0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b,
0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509,
0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e,
0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3,
0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f,
0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4,
0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960,
0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66,
0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28,
0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802,
0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510,
0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf,
0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,
0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e,
0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50,
0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8,
0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281,
0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99,
0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696,
0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128,
0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0,
0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0,
0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105,
0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250,
0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3,
0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00,
0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061,
0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb,
0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e,
0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735,
0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9,
0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340,
0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20,
0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7]),
new Uint32Array([
0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934,
0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068,
0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af,
0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840,
0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45,
0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a,
0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb,
0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee,
0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6,
0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42,
0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2,
0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb,
0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527,
0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b,
0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33,
0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3,
0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc,
0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17,
0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564,
0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b,
0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922,
0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728,
0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0,
0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e,
0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37,
0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804,
0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b,
0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3,
0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb,
0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d,
0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350,
0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9,
0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,
0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe,
0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d,
0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f,
0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61,
0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2,
0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9,
0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2,
0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e,
0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633,
0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10,
0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169,
0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52,
0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5,
0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62,
0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634,
0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76,
0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24,
0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4,
0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c,
0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837,
0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0]),
new Uint32Array([
0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b,
0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe,
0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4,
0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8,
0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304,
0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22,
0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6,
0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9,
0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593,
0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51,
0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c,
0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b,
0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c,
0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd,
0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319,
0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb,
0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991,
0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32,
0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166,
0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae,
0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5,
0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47,
0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d,
0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84,
0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8,
0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd,
0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7,
0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38,
0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c,
0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525,
0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442,
0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964,
0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8,
0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d,
0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299,
0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02,
0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614,
0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a,
0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b,
0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0,
0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e,
0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9,
0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6])
];
this.P = new Uint32Array([
0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344,
0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89,
0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917,
0x9216d5d9, 0x8979fb1b]);
};
function F(S, x8, i) {
return (((S[0][x8[i+3]] +
S[1][x8[i+2]]) ^
S[2][x8[i+1]]) +
S[3][x8[i]]);
};
Blowfish.prototype.encipher = function(x, x8) {
if (x8 === undefined) {
x8 = new Uint8Array(x.buffer);
if (x.byteOffset !== 0)
x8 = x8.subarray(x.byteOffset);
}
x[0] ^= this.P[0];
for (var i = 1; i < 16; i += 2) {
x[1] ^= F(this.S, x8, 0) ^ this.P[i];
x[0] ^= F(this.S, x8, 4) ^ this.P[i+1];
}
var t = x[0];
x[0] = x[1] ^ this.P[17];
x[1] = t;
};
Blowfish.prototype.decipher = function(x) {
var x8 = new Uint8Array(x.buffer);
if (x.byteOffset !== 0)
x8 = x8.subarray(x.byteOffset);
x[0] ^= this.P[17];
for (var i = 16; i > 0; i -= 2) {
x[1] ^= F(this.S, x8, 0) ^ this.P[i];
x[0] ^= F(this.S, x8, 4) ^ this.P[i-1];
}
var t = x[0];
x[0] = x[1] ^ this.P[0];
x[1] = t;
};
function stream2word(data, databytes){
var i, temp = 0;
for (i = 0; i < 4; i++, BLF_J++) {
if (BLF_J >= databytes) BLF_J = 0;
temp = (temp << 8) | data[BLF_J];
}
return temp;
};
Blowfish.prototype.expand0state = function(key, keybytes) {
var d = new Uint32Array(2), i, k;
var d8 = new Uint8Array(d.buffer);
for (i = 0, BLF_J = 0; i < 18; i++) {
this.P[i] ^= stream2word(key, keybytes);
}
BLF_J = 0;
for (i = 0; i < 18; i += 2) {
this.encipher(d, d8);
this.P[i] = d[0];
this.P[i+1] = d[1];
}
for (i = 0; i < 4; i++) {
for (k = 0; k < 256; k += 2) {
this.encipher(d, d8);
this.S[i][k] = d[0];
this.S[i][k+1] = d[1];
}
}
};
Blowfish.prototype.expandstate = function(data, databytes, key, keybytes) {
var d = new Uint32Array(2), i, k;
for (i = 0, BLF_J = 0; i < 18; i++) {
this.P[i] ^= stream2word(key, keybytes);
}
for (i = 0, BLF_J = 0; i < 18; i += 2) {
d[0] ^= stream2word(data, databytes);
d[1] ^= stream2word(data, databytes);
this.encipher(d);
this.P[i] = d[0];
this.P[i+1] = d[1];
}
for (i = 0; i < 4; i++) {
for (k = 0; k < 256; k += 2) {
d[0] ^= stream2word(data, databytes);
d[1] ^= stream2word(data, databytes);
this.encipher(d);
this.S[i][k] = d[0];
this.S[i][k+1] = d[1];
}
}
BLF_J = 0;
};
Blowfish.prototype.enc = function(data, blocks) {
for (var i = 0; i < blocks; i++) {
this.encipher(data.subarray(i*2));
}
};
Blowfish.prototype.dec = function(data, blocks) {
for (var i = 0; i < blocks; i++) {
this.decipher(data.subarray(i*2));
}
};
var BCRYPT_BLOCKS = 8,
BCRYPT_HASHSIZE = 32;
function bcrypt_hash(sha2pass, sha2salt, out) {
var state = new Blowfish(),
cdata = new Uint32Array(BCRYPT_BLOCKS), i,
ciphertext = new Uint8Array([79,120,121,99,104,114,111,109,97,116,105,
99,66,108,111,119,102,105,115,104,83,119,97,116,68,121,110,97,109,
105,116,101]); //"OxychromaticBlowfishSwatDynamite"
state.expandstate(sha2salt, 64, sha2pass, 64);
for (i = 0; i < 64; i++) {
state.expand0state(sha2salt, 64);
state.expand0state(sha2pass, 64);
}
for (i = 0; i < BCRYPT_BLOCKS; i++)
cdata[i] = stream2word(ciphertext, ciphertext.byteLength);
for (i = 0; i < 64; i++)
state.enc(cdata, cdata.byteLength / 8);
for (i = 0; i < BCRYPT_BLOCKS; i++) {
out[4*i+3] = cdata[i] >>> 24;
out[4*i+2] = cdata[i] >>> 16;
out[4*i+1] = cdata[i] >>> 8;
out[4*i+0] = cdata[i];
}
};
function bcrypt_pbkdf(pass, passlen, salt, saltlen, key, keylen, rounds) {
var sha2pass = new Uint8Array(64),
sha2salt = new Uint8Array(64),
out = new Uint8Array(BCRYPT_HASHSIZE),
tmpout = new Uint8Array(BCRYPT_HASHSIZE),
countsalt = new Uint8Array(saltlen+4),
i, j, amt, stride, dest, count,
origkeylen = keylen;
if (rounds < 1)
return -1;
if (passlen === 0 || saltlen === 0 || keylen === 0 ||
keylen > (out.byteLength * out.byteLength) || saltlen > (1<<20))
return -1;
stride = Math.floor((keylen + out.byteLength - 1) / out.byteLength);
amt = Math.floor((keylen + stride - 1) / stride);
for (i = 0; i < saltlen; i++)
countsalt[i] = salt[i];
crypto_hash_sha512(sha2pass, pass, passlen);
for (count = 1; keylen > 0; count++) {
countsalt[saltlen+0] = count >>> 24;
countsalt[saltlen+1] = count >>> 16;
countsalt[saltlen+2] = count >>> 8;
countsalt[saltlen+3] = count;
crypto_hash_sha512(sha2salt, countsalt, saltlen + 4);
bcrypt_hash(sha2pass, sha2salt, tmpout);
for (i = out.byteLength; i--;)
out[i] = tmpout[i];
for (i = 1; i < rounds; i++) {
crypto_hash_sha512(sha2salt, tmpout, tmpout.byteLength);
bcrypt_hash(sha2pass, sha2salt, tmpout);
for (j = 0; j < out.byteLength; j++)
out[j] ^= tmpout[j];
}
amt = Math.min(amt, keylen);
for (i = 0; i < amt; i++) {
dest = i * stride + (count - 1);
if (dest >= origkeylen)
break;
key[dest] = out[i];
}
keylen -= i;
}
return 0;
};
module.exports = {
BLOCKS: BCRYPT_BLOCKS,
HASHSIZE: BCRYPT_HASHSIZE,
hash: bcrypt_hash,
pbkdf: bcrypt_pbkdf
};
{
"_args": [
[
{
"raw": "bcrypt-pbkdf@^1.0.0",
"scope": null,
"escapedName": "bcrypt-pbkdf",
"name": "bcrypt-pbkdf",
"rawSpec": "^1.0.0",
"spec": ">=1.0.0 <2.0.0",
"type": "range"
},
"F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\sshpk"
]
],
"_from": "bcrypt-pbkdf@>=1.0.0 <2.0.0",
"_id": "bcrypt-pbkdf@1.0.1",
"_inCache": true,
"_location": "/bcrypt-pbkdf",
"_nodeVersion": "0.12.9",
"_npmOperationalInternal": {
"host": "packages-18-east.internal.npmjs.com",
"tmp": "tmp/bcrypt-pbkdf-1.0.1.tgz_1486007687899_0.974529881728813"
},
"_npmUser": {
"name": "arekinath",
"email": "alex@cooperi.net"
},
"_npmVersion": "2.14.9",
"_phantomChildren": {},
"_requested": {
"raw": "bcrypt-pbkdf@^1.0.0",
"scope": null,
"escapedName": "bcrypt-pbkdf",
"name": "bcrypt-pbkdf",
"rawSpec": "^1.0.0",
"spec": ">=1.0.0 <2.0.0",
"type": "range"
},
"_requiredBy": [
"/sshpk"
],
"_resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz",
"_shasum": "63bc5dcb61331b92bc05fd528953c33462a06f8d",
"_shrinkwrap": null,
"_spec": "bcrypt-pbkdf@^1.0.0",
"_where": "F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\sshpk",
"dependencies": {
"tweetnacl": "^0.14.3"
},
"description": "Port of the OpenBSD bcrypt_pbkdf function to pure JS",
"devDependencies": {},
"directories": {},
"dist": {
"shasum": "63bc5dcb61331b92bc05fd528953c33462a06f8d",
"tarball": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz"
},
"gitHead": "fa2ab3ae9efa15367264151398635a915c7b411d",
"license": "BSD-3-Clause",
"main": "index.js",
"maintainers": [
{
"name": "arekinath",
"email": "alex@cooperi.net"
},
{
"name": "dap",
"email": "dap@cs.brown.edu"
},
{
"name": "jclulow",
"email": "josh@sysmgr.org"
},
{
"name": "trentm",
"email": "trentm@gmail.com"
}
],
"name": "bcrypt-pbkdf",
"optionalDependencies": {},
"readme": "ERROR: No README data found!",
"scripts": {},
"version": "1.0.1"
}

Port of the OpenBSD bcrypt_pbkdf function to pure Javascript. npm-ified version of [Devi Mandiri's port] (https://github.com/devi/tmp/blob/master/js/bcrypt_pbkdf.js), with some minor performance improvements. The code is copied verbatim (and un-styled) from Devi's work.

This product includes software developed by Niels Provos.

API

bcrypt_pbkdf.pbkdf(pass, passlen, salt, saltlen, key, keylen, rounds)

Derive a cryptographic key of arbitrary length from a given password and salt, using the OpenBSD bcrypt_pbkdf function. This is a combination of Blowfish and SHA-512.

See this article for further information.

Parameters:

  • pass, a Uint8Array of length passlen
  • passlen, an integer Number
  • salt, a Uint8Array of length saltlen
  • saltlen, an integer Number
  • key, a Uint8Array of length keylen, will be filled with output
  • keylen, an integer Number
  • rounds, an integer Number, number of rounds of the PBKDF to run

bcrypt_pbkdf.hash(sha2pass, sha2salt, out)

Calculate a Blowfish hash, given SHA2-512 output of a password and salt. Used as part of the inner round function in the PBKDF.

Parameters:

  • sha2pass, a Uint8Array of length 64
  • sha2salt, a Uint8Array of length 64
  • out, a Uint8Array of length 32, will be filled with output
module.exports = {
trueFunc: function trueFunc(){
return true;
},
falseFunc: function falseFunc(){
return false;
}
};
{
"_args": [
[
{
"raw": "boolbase@~1.0.0",
"scope": null,
"escapedName": "boolbase",
"name": "boolbase",
"rawSpec": "~1.0.0",
"spec": ">=1.0.0 <1.1.0",
"type": "range"
},
"F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\css-select"
]
],
"_from": "boolbase@>=1.0.0 <1.1.0",
"_id": "boolbase@1.0.0",
"_inCache": true,
"_location": "/boolbase",
"_npmUser": {
"name": "feedic",
"email": "me@feedic.com"
},
"_npmVersion": "1.4.2",
"_phantomChildren": {},
"_requested": {
"raw": "boolbase@~1.0.0",
"scope": null,
"escapedName": "boolbase",
"name": "boolbase",
"rawSpec": "~1.0.0",
"spec": ">=1.0.0 <1.1.0",
"type": "range"
},
"_requiredBy": [
"/css-select",
"/nth-check"
],
"_resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
"_shasum": "68dff5fbe60c51eb37725ea9e3ed310dcc1e776e",
"_shrinkwrap": null,
"_spec": "boolbase@~1.0.0",
"_where": "F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\css-select",
"author": {
"name": "Felix Boehm",
"email": "me@feedic.com"
},
"bugs": {
"url": "https://github.com/fb55/boolbase/issues"
},
"dependencies": {},
"description": "two functions: One that returns true, one that returns false",
"devDependencies": {},
"directories": {},
"dist": {
"shasum": "68dff5fbe60c51eb37725ea9e3ed310dcc1e776e",
"tarball": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz"
},
"homepage": "https://github.com/fb55/boolbase",
"keywords": [
"boolean",
"function"
],
"license": "ISC",
"main": "index.js",
"maintainers": [
{
"name": "feedic",
"email": "me@feedic.com"
}
],
"name": "boolbase",
"optionalDependencies": {},
"readme": "ERROR: No README data found!",
"repository": {
"type": "git",
"url": "git+https://github.com/fb55/boolbase.git"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"version": "1.0.0"
}

#boolbase This very simple module provides two basic functions, one that always returns true (trueFunc) and one that always returns false (falseFunc).

###WTF?

By having only a single instance of these functions around, it's possible to do some nice optimizations. Eg. CSSselect uses these functions to determine whether a selector won't match any elements. If that's the case, the DOM doesn't even have to be touched.

###And why is this a separate module?

I'm trying to modularize CSSselect and most modules depend on these functions. IMHO, having a separate module is the easiest solution to this problem.

.idea
*.iml
npm-debug.log
dump.rdb
node_modules
results.tap
results.xml
npm-shrinkwrap.json
config.json
.DS_Store
*/.DS_Store
*/*/.DS_Store
._*
*/._*
*/*/._*
coverage.*
lib-cov
language: node_js
node_js:
- 0.10
- 4.0
sudo: false
// Load modules
var Http = require('http');
var Hoek = require('hoek');
// Declare internals
var internals = {};
exports.wrap = function (error, statusCode, message) {
Hoek.assert(error instanceof Error, 'Cannot wrap non-Error object');
return (error.isBoom ? error : internals.initialize(error, statusCode || 500, message));
};
exports.create = function (statusCode, message, data) {
return internals.create(statusCode, message, data, exports.create);
};
internals.create = function (statusCode, message, data, ctor) {
var error = new Error(message ? message : undefined); // Avoids settings null message
Error.captureStackTrace(error, ctor); // Filter the stack to our external API
error.data = data || null;
internals.initialize(error, statusCode);
return error;
};
internals.initialize = function (error, statusCode, message) {
var numberCode = parseInt(statusCode, 10);
Hoek.assert(!isNaN(numberCode) && numberCode >= 400, 'First argument must be a number (400+):', statusCode);
error.isBoom = true;
error.isServer = numberCode >= 500;
if (!error.hasOwnProperty('data')) {
error.data = null;
}
error.output = {
statusCode: numberCode,
payload: {},
headers: {}
};
error.reformat = internals.reformat;
error.reformat();
if (!message &&
!error.message) {
message = error.output.payload.error;
}
if (message) {
error.message = (message + (error.message ? ': ' + error.message : ''));
}
return error;
};
internals.reformat = function () {
this.output.payload.statusCode = this.output.statusCode;
this.output.payload.error = Http.STATUS_CODES[this.output.statusCode] || 'Unknown';
if (this.output.statusCode === 500) {
this.output.payload.message = 'An internal server error occurred'; // Hide actual error from user
}
else if (this.message) {
this.output.payload.message = this.message;
}
};
// 4xx Client Errors
exports.badRequest = function (message, data) {
return internals.create(400, message, data, exports.badRequest);
};
exports.unauthorized = function (message, scheme, attributes) { // Or function (message, wwwAuthenticate[])
var err = internals.create(401, message, undefined, exports.unauthorized);
if (!scheme) {
return err;
}
var wwwAuthenticate = '';
var i = 0;
var il = 0;
if (typeof scheme === 'string') {
// function (message, scheme, attributes)
wwwAuthenticate = scheme;
if (attributes || message) {
err.output.payload.attributes = {};
}
if (attributes) {
var names = Object.keys(attributes);
for (i = 0, il = names.length; i < il; ++i) {
var name = names[i];
if (i) {
wwwAuthenticate += ',';
}
var value = attributes[name];
if (value === null ||
value === undefined) { // Value can be zero
value = '';
}
wwwAuthenticate += ' ' + name + '="' + Hoek.escapeHeaderAttribute(value.toString()) + '"';
err.output.payload.attributes[name] = value;
}
}
if (message) {
if (attributes) {
wwwAuthenticate += ',';
}
wwwAuthenticate += ' error="' + Hoek.escapeHeaderAttribute(message) + '"';
err.output.payload.attributes.error = message;
}
else {
err.isMissing = true;
}
}
else {
// function (message, wwwAuthenticate[])
var wwwArray = scheme;
for (i = 0, il = wwwArray.length; i < il; ++i) {
if (i) {
wwwAuthenticate += ', ';
}
wwwAuthenticate += wwwArray[i];
}
}
err.output.headers['WWW-Authenticate'] = wwwAuthenticate;
return err;
};
exports.forbidden = function (message, data) {
return internals.create(403, message, data, exports.forbidden);
};
exports.notFound = function (message, data) {
return internals.create(404, message, data, exports.notFound);
};
exports.methodNotAllowed = function (message, data) {
return internals.create(405, message, data, exports.methodNotAllowed);
};
exports.notAcceptable = function (message, data) {
return internals.create(406, message, data, exports.notAcceptable);
};
exports.proxyAuthRequired = function (message, data) {
return internals.create(407, message, data, exports.proxyAuthRequired);
};
exports.clientTimeout = function (message, data) {
return internals.create(408, message, data, exports.clientTimeout);
};
exports.conflict = function (message, data) {
return internals.create(409, message, data, exports.conflict);
};
exports.resourceGone = function (message, data) {
return internals.create(410, message, data, exports.resourceGone);
};
exports.lengthRequired = function (message, data) {
return internals.create(411, message, data, exports.lengthRequired);
};
exports.preconditionFailed = function (message, data) {
return internals.create(412, message, data, exports.preconditionFailed);
};
exports.entityTooLarge = function (message, data) {
return internals.create(413, message, data, exports.entityTooLarge);
};
exports.uriTooLong = function (message, data) {
return internals.create(414, message, data, exports.uriTooLong);
};
exports.unsupportedMediaType = function (message, data) {
return internals.create(415, message, data, exports.unsupportedMediaType);
};
exports.rangeNotSatisfiable = function (message, data) {
return internals.create(416, message, data, exports.rangeNotSatisfiable);
};
exports.expectationFailed = function (message, data) {
return internals.create(417, message, data, exports.expectationFailed);
};
exports.badData = function (message, data) {
return internals.create(422, message, data, exports.badData);
};
exports.preconditionRequired = function (message, data) {
return internals.create(428, message, data, exports.preconditionRequired);
};
exports.tooManyRequests = function (message, data) {
return internals.create(429, message, data, exports.tooManyRequests);
};
// 5xx Server Errors
exports.internal = function (message, data, statusCode) {
return internals.serverError(message, data, statusCode, exports.internal);
};
internals.serverError = function (message, data, statusCode, ctor) {
var error;
if (data instanceof Error) {
error = exports.wrap(data, statusCode, message);
} else {
error = internals.create(statusCode || 500, message, undefined, ctor);
error.data = data;
}
return error;
};
exports.notImplemented = function (message, data) {
return internals.serverError(message, data, 501, exports.notImplemented);
};
exports.badGateway = function (message, data) {
return internals.serverError(message, data, 502, exports.badGateway);
};
exports.serverTimeout = function (message, data) {
return internals.serverError(message, data, 503, exports.serverTimeout);
};
exports.gatewayTimeout = function (message, data) {
return internals.serverError(message, data, 504, exports.gatewayTimeout);
};
exports.badImplementation = function (message, data) {
var err = internals.serverError(message, data, 500, exports.badImplementation);
err.isDeveloperError = true;
return err;
};
Copyright (c) 2012-2014, Walmart and other contributors.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* The names of any contributors may not be used to endorse or promote
products derived from this software without specific prior written
permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* * *
The complete list of contributors can be found at: https://github.com/hapijs/boom/graphs/contributors
{
"_args": [
[
{
"raw": "boom@2.x.x",
"scope": null,
"escapedName": "boom",
"name": "boom",
"rawSpec": "2.x.x",
"spec": ">=2.0.0 <3.0.0",
"type": "range"
},
"F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\hawk"
]
],
"_from": "boom@>=2.0.0 <3.0.0",
"_id": "boom@2.10.1",
"_inCache": true,
"_location": "/boom",
"_nodeVersion": "0.10.40",
"_npmUser": {
"name": "arb",
"email": "arbretz@gmail.com"
},
"_npmVersion": "2.11.1",
"_phantomChildren": {},
"_requested": {
"raw": "boom@2.x.x",
"scope": null,
"escapedName": "boom",
"name": "boom",
"rawSpec": "2.x.x",
"spec": ">=2.0.0 <3.0.0",
"type": "range"
},
"_requiredBy": [
"/cryptiles",
"/hawk"
],
"_resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz",
"_shasum": "39c8918ceff5799f83f9492a848f625add0c766f",
"_shrinkwrap": null,
"_spec": "boom@2.x.x",
"_where": "F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\hawk",
"bugs": {
"url": "https://github.com/hapijs/boom/issues"
},
"dependencies": {
"hoek": "2.x.x"
},
"description": "HTTP-friendly error objects",
"devDependencies": {
"code": "1.x.x",
"lab": "7.x.x"
},
"directories": {},
"dist": {
"shasum": "39c8918ceff5799f83f9492a848f625add0c766f",
"tarball": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz"
},
"engines": {
"node": ">=0.10.40"
},
"gitHead": "ff1a662a86b39426cdd18f4441b112d307a34a6f",
"homepage": "https://github.com/hapijs/boom#readme",
"keywords": [
"error",
"http"
],
"license": "BSD-3-Clause",
"main": "lib/index.js",
"maintainers": [
{
"name": "hueniverse",
"email": "eran@hueniverse.com"
},
{
"name": "wyatt",
"email": "wpreul@gmail.com"
},
{
"name": "arb",
"email": "arbretz@gmail.com"
}
],
"name": "boom",
"optionalDependencies": {},
"readme": "ERROR: No README data found!",
"repository": {
"type": "git",
"url": "git://github.com/hapijs/boom.git"
},
"scripts": {
"test": "lab -a code -t 100 -L",
"test-cov-html": "lab -a code -r html -o coverage.html -L"
},
"version": "2.10.1"
}

boom Logo

HTTP-friendly error objects

Build Status Current Version

Lead Maintainer: Adam Bretz

boom provides a set of utilities for returning HTTP errors. Each utility returns a Boom error response object (instance of Error) which includes the following properties:

  • isBoom - if true, indicates this is a Boom object instance.
  • isServer - convenience bool indicating status code >= 500.
  • message - the error message.
  • output - the formatted response. Can be directly manipulated after object construction to return a custom error response. Allowed root keys:
    • statusCode - the HTTP status code (typically 4xx or 5xx).
    • headers - an object containing any HTTP headers where each key is a header name and value is the header content.
    • payload - the formatted object used as the response payload (stringified). Can be directly manipulated but any changes will be lost if reformat() is called. Any content allowed and by default includes the following content:
      • statusCode - the HTTP status code, derived from error.output.statusCode.
      • error - the HTTP status message (e.g. 'Bad Request', 'Internal Server Error') derived from statusCode.
      • message - the error message derived from error.message.
  • inherited Error properties.

The Boom object also supports the following method:

  • reformat() - rebuilds error.output using the other object properties.

Overview

Helper Methods

wrap(error, [statusCode], [message])

Decorates an error with the boom properties where:

  • error - the error object to wrap. If error is already a boom object, returns back the same object.
  • statusCode - optional HTTP status code. Defaults to 500.
  • message - optional message string. If the error already has a message, it adds the message as a prefix. Defaults to no message.
var error = new Error('Unexpected input');
Boom.wrap(error, 400);

create(statusCode, [message], [data])

Generates an Error object with the boom decorations where:

  • statusCode - an HTTP error code number. Must be greater or equal 400.
  • message - optional message string.
  • data - additional error data set to error.data property.
var error = Boom.create(400, 'Bad request', { timestamp: Date.now() });

HTTP 4xx Errors

Boom.badRequest([message], [data])

Returns a 400 Bad Request error where:

  • message - optional message.
  • data - optional additional error data.
Boom.badRequest('invalid query');

Generates the following response payload:

{
    "statusCode": 400,
    "error": "Bad Request",
    "message": "invalid query"
}

Boom.unauthorized([message], [scheme], [attributes])

Returns a 401 Unauthorized error where:

  • message - optional message.
  • scheme can be one of the following:
    • an authentication scheme name
    • an array of string values. These values will be separated by ', ' and set to the 'WWW-Authenticate' header.
  • attributes - an object of values to use while setting the 'WWW-Authenticate' header. This value is only used when schema is a string, otherwise it is ignored. Every key/value pair will be included in the 'WWW-Authenticate' in the format of 'key="value"' as well as in the response payload under the attributes key. null and undefined will be replaced with an empty string. If attributes is set, message will be used as the 'error' segment of the 'WWW-Authenticate' header. If message is unset, the 'error' segment of the header will not be present and isMissing will be true on the error object.

If either scheme or attributes are set, the resultant Boom object will have the 'WWW-Authenticate' header set for the response.

Boom.unauthorized('invalid password');

Generates the following response:

"payload": {
    "statusCode": 401,
    "error": "Unauthorized",
    "message": "invalid password"
},
"headers" {}
Boom.unauthorized('invalid password', 'sample');

Generates the following response:

"payload": {
    "statusCode": 401,
    "error": "Unauthorized",
    "message": "invalid password",
    "attributes": {
        "error": "invalid password"
    }
},
"headers" {
  "WWW-Authenticate": "sample error=\"invalid password\""
}
Boom.unauthorized('invalid password', 'sample', { ttl: 0, cache: null, foo: 'bar' });

Generates the following response:

"payload": {
    "statusCode": 401,
    "error": "Unauthorized",
    "message": "invalid password",
    "attributes": {
        "error": "invalid password",
        "ttl": 0,
        "cache": "",
        "foo": "bar"
    }
},
"headers" {
  "WWW-Authenticate": "sample ttl=\"0\", cache=\"\", foo=\"bar\", error=\"invalid password\""
}

Boom.forbidden([message], [data])

Returns a 403 Forbidden error where:

  • message - optional message.
  • data - optional additional error data.
Boom.forbidden('try again some time');

Generates the following response payload:

{
    "statusCode": 403,
    "error": "Forbidden",
    "message": "try again some time"
}

Boom.notFound([message], [data])

Returns a 404 Not Found error where:

  • message - optional message.
  • data - optional additional error data.
Boom.notFound('missing');

Generates the following response payload:

{
    "statusCode": 404,
    "error": "Not Found",
    "message": "missing"
}

Boom.methodNotAllowed([message], [data])

Returns a 405 Method Not Allowed error where:

  • message - optional message.
  • data - optional additional error data.
Boom.methodNotAllowed('that method is not allowed');

Generates the following response payload:

{
    "statusCode": 405,
    "error": "Method Not Allowed",
    "message": "that method is not allowed"
}

Boom.notAcceptable([message], [data])

Returns a 406 Not Acceptable error where:

  • message - optional message.
  • data - optional additional error data.
Boom.notAcceptable('unacceptable');

Generates the following response payload:

{
    "statusCode": 406,
    "error": "Not Acceptable",
    "message": "unacceptable"
}

Boom.proxyAuthRequired([message], [data])

Returns a 407 Proxy Authentication Required error where:

  • message - optional message.
  • data - optional additional error data.
Boom.proxyAuthRequired('auth missing');

Generates the following response payload:

{
    "statusCode": 407,
    "error": "Proxy Authentication Required",
    "message": "auth missing"
}

Boom.clientTimeout([message], [data])

Returns a 408 Request Time-out error where:

  • message - optional message.
  • data - optional additional error data.
Boom.clientTimeout('timed out');

Generates the following response payload:

{
    "statusCode": 408,
    "error": "Request Time-out",
    "message": "timed out"
}

Boom.conflict([message], [data])

Returns a 409 Conflict error where:

  • message - optional message.
  • data - optional additional error data.
Boom.conflict('there was a conflict');

Generates the following response payload:

{
    "statusCode": 409,
    "error": "Conflict",
    "message": "there was a conflict"
}

Boom.resourceGone([message], [data])

Returns a 410 Gone error where:

  • message - optional message.
  • data - optional additional error data.
Boom.resourceGone('it is gone');

Generates the following response payload:

{
    "statusCode": 410,
    "error": "Gone",
    "message": "it is gone"
}

Boom.lengthRequired([message], [data])

Returns a 411 Length Required error where:

  • message - optional message.
  • data - optional additional error data.
Boom.lengthRequired('length needed');

Generates the following response payload:

{
    "statusCode": 411,
    "error": "Length Required",
    "message": "length needed"
}

Boom.preconditionFailed([message], [data])

Returns a 412 Precondition Failed error where:

  • message - optional message.
  • data - optional additional error data.
Boom.preconditionFailed();

Generates the following response payload:

{
    "statusCode": 412,
    "error": "Precondition Failed"
}

Boom.entityTooLarge([message], [data])

Returns a 413 Request Entity Too Large error where:

  • message - optional message.
  • data - optional additional error data.
Boom.entityTooLarge('too big');

Generates the following response payload:

{
    "statusCode": 413,
    "error": "Request Entity Too Large",
    "message": "too big"
}

Boom.uriTooLong([message], [data])

Returns a 414 Request-URI Too Large error where:

  • message - optional message.
  • data - optional additional error data.
Boom.uriTooLong('uri is too long');

Generates the following response payload:

{
    "statusCode": 414,
    "error": "Request-URI Too Large",
    "message": "uri is too long"
}

Boom.unsupportedMediaType([message], [data])

Returns a 415 Unsupported Media Type error where:

  • message - optional message.
  • data - optional additional error data.
Boom.unsupportedMediaType('that media is not supported');

Generates the following response payload:

{
    "statusCode": 415,
    "error": "Unsupported Media Type",
    "message": "that media is not supported"
}

Boom.rangeNotSatisfiable([message], [data])

Returns a 416 Requested Range Not Satisfiable error where:

  • message - optional message.
  • data - optional additional error data.
Boom.rangeNotSatisfiable();

Generates the following response payload:

{
    "statusCode": 416,
    "error": "Requested Range Not Satisfiable"
}

Boom.expectationFailed([message], [data])

Returns a 417 Expectation Failed error where:

  • message - optional message.
  • data - optional additional error data.
Boom.expectationFailed('expected this to work');

Generates the following response payload:

{
    "statusCode": 417,
    "error": "Expectation Failed",
    "message": "expected this to work"
}

Boom.badData([message], [data])

Returns a 422 Unprocessable Entity error where:

  • message - optional message.
  • data - optional additional error data.
Boom.badData('your data is bad and you should feel bad');

Generates the following response payload:

{
    "statusCode": 422,
    "error": "Unprocessable Entity",
    "message": "your data is bad and you should feel bad"
}

Boom.preconditionRequired([message], [data])

Returns a 428 Precondition Required error where:

  • message - optional message.
  • data - optional additional error data.
Boom.preconditionRequired('you must supply an If-Match header');

Generates the following response payload:

{
    "statusCode": 428,
    "error": "Precondition Required",
    "message": "you must supply an If-Match header"
}

Boom.tooManyRequests([message], [data])

Returns a 429 Too Many Requests error where:

  • message - optional message.
  • data - optional additional error data.
Boom.tooManyRequests('you have exceeded your request limit');

Generates the following response payload:

{
    "statusCode": 429,
    "error": "Too Many Requests",
    "message": "you have exceeded your request limit"
}

HTTP 5xx Errors

All 500 errors hide your message from the end user. Your message is recorded in the server log.

Boom.badImplementation([message], [data])

Returns a 500 Internal Server Error error where:

  • message - optional message.
  • data - optional additional error data.
Boom.badImplementation('terrible implementation');

Generates the following response payload:

{
    "statusCode": 500,
    "error": "Internal Server Error",
    "message": "An internal server error occurred"
}

Boom.notImplemented([message], [data])

Returns a 501 Not Implemented error where:

  • message - optional message.
  • data - optional additional error data.
Boom.notImplemented('method not implemented');

Generates the following response payload:

{
    "statusCode": 501,
    "error": "Not Implemented",
    "message": "method not implemented"
}

Boom.badGateway([message], [data])

Returns a 502 Bad Gateway error where:

  • message - optional message.
  • data - optional additional error data.
Boom.badGateway('that is a bad gateway');

Generates the following response payload:

{
    "statusCode": 502,
    "error": "Bad Gateway",
    "message": "that is a bad gateway"
}

Boom.serverTimeout([message], [data])

Returns a 503 Service Unavailable error where:

  • message - optional message.
  • data - optional additional error data.
Boom.serverTimeout('unavailable');

Generates the following response payload:

{
    "statusCode": 503,
    "error": "Service Unavailable",
    "message": "unavailable"
}

Boom.gatewayTimeout([message], [data])

Returns a 504 Gateway Time-out error where:

  • message - optional message.
  • data - optional additional error data.
Boom.gatewayTimeout();

Generates the following response payload:

{
    "statusCode": 504,
    "error": "Gateway Time-out"
}

F.A.Q.

How do I include extra information in my responses? output.payload is missing data, what gives?

There is a reason the values passed back in the response payloads are pretty locked down. It's mostly for security and to not leak any important information back to the client. This means you will need to put in a little more effort to include extra information about your custom error. Check out the "Error transformation" section in the hapi documentation.

// Load modules
var Code = require('code');
var Boom = require('../lib');
var Lab = require('lab');
// Declare internals
var internals = {};
// Test shortcuts
var lab = exports.lab = Lab.script();
var describe = lab.describe;
var it = lab.it;
var expect = Code.expect;
it('returns the same object when already boom', function (done) {
var error = Boom.badRequest();
var wrapped = Boom.wrap(error);
expect(error).to.equal(wrapped);
done();
});
it('returns an error with info when constructed using another error', function (done) {
var error = new Error('ka-boom');
error.xyz = 123;
var err = Boom.wrap(error);
expect(err.xyz).to.equal(123);
expect(err.message).to.equal('ka-boom');
expect(err.output).to.deep.equal({
statusCode: 500,
payload: {
statusCode: 500,
error: 'Internal Server Error',
message: 'An internal server error occurred'
},
headers: {}
});
expect(err.data).to.equal(null);
done();
});
it('does not override data when constructed using another error', function (done) {
var error = new Error('ka-boom');
error.data = { useful: 'data' };
var err = Boom.wrap(error);
expect(err.data).to.equal(error.data);
done();
});
it('sets new message when none exists', function (done) {
var error = new Error();
var wrapped = Boom.wrap(error, 400, 'something bad');
expect(wrapped.message).to.equal('something bad');
done();
});
it('throws when statusCode is not a number', function (done) {
expect(function () {
Boom.create('x');
}).to.throw('First argument must be a number (400+): x');
done();
});
it('will cast a number-string to an integer', function (done) {
var codes = [
{ input: '404', result: 404 },
{ input: '404.1', result: 404 },
{ input: 400, result: 400 },
{ input: 400.123, result: 400 }];
for (var i = 0, il = codes.length; i < il; ++i) {
var code = codes[i];
var err = Boom.create(code.input);
expect(err.output.statusCode).to.equal(code.result);
}
done();
});
it('throws when statusCode is not finite', function (done) {
expect(function () {
Boom.create(1 / 0);
}).to.throw('First argument must be a number (400+): null');
done();
});
it('sets error code to unknown', function (done) {
var err = Boom.create(999);
expect(err.output.payload.error).to.equal('Unknown');
done();
});
describe('create()', function () {
it('does not sets null message', function (done) {
var error = Boom.unauthorized(null);
expect(error.output.payload.message).to.not.exist();
expect(error.isServer).to.be.false();
done();
});
it('sets message and data', function (done) {
var error = Boom.badRequest('Missing data', { type: 'user' });
expect(error.data.type).to.equal('user');
expect(error.output.payload.message).to.equal('Missing data');
done();
});
});
describe('isBoom()', function () {
it('returns true for Boom object', function (done) {
expect(Boom.badRequest().isBoom).to.equal(true);
done();
});
it('returns false for Error object', function (done) {
expect((new Error()).isBoom).to.not.exist();
done();
});
});
describe('badRequest()', function () {
it('returns a 400 error statusCode', function (done) {
var error = Boom.badRequest();
expect(error.output.statusCode).to.equal(400);
expect(error.isServer).to.be.false();
done();
});
it('sets the message with the passed in message', function (done) {
expect(Boom.badRequest('my message').message).to.equal('my message');
done();
});
it('sets the message to HTTP status if none provided', function (done) {
expect(Boom.badRequest().message).to.equal('Bad Request');
done();
});
});
describe('unauthorized()', function () {
it('returns a 401 error statusCode', function (done) {
var err = Boom.unauthorized();
expect(err.output.statusCode).to.equal(401);
expect(err.output.headers).to.deep.equal({});
done();
});
it('sets the message with the passed in message', function (done) {
expect(Boom.unauthorized('my message').message).to.equal('my message');
done();
});
it('returns a WWW-Authenticate header when passed a scheme', function (done) {
var err = Boom.unauthorized('boom', 'Test');
expect(err.output.statusCode).to.equal(401);
expect(err.output.headers['WWW-Authenticate']).to.equal('Test error="boom"');
done();
});
it('returns a WWW-Authenticate header set to the schema array value', function (done) {
var err = Boom.unauthorized(null, ['Test','one','two']);
expect(err.output.statusCode).to.equal(401);
expect(err.output.headers['WWW-Authenticate']).to.equal('Test, one, two');
done();
});
it('returns a WWW-Authenticate header when passed a scheme and attributes', function (done) {
var err = Boom.unauthorized('boom', 'Test', { a: 1, b: 'something', c: null, d: 0 });
expect(err.output.statusCode).to.equal(401);
expect(err.output.headers['WWW-Authenticate']).to.equal('Test a="1", b="something", c="", d="0", error="boom"');
expect(err.output.payload.attributes).to.deep.equal({ a: 1, b: 'something', c: '', d: 0, error: 'boom' });
done();
});
it('returns a WWW-Authenticate header when passed attributes, missing error', function (done) {
var err = Boom.unauthorized(null, 'Test', { a: 1, b: 'something', c: null, d: 0 });
expect(err.output.statusCode).to.equal(401);
expect(err.output.headers['WWW-Authenticate']).to.equal('Test a="1", b="something", c="", d="0"');
expect(err.isMissing).to.equal(true);
done();
});
it('sets the isMissing flag when error message is empty', function (done) {
var err = Boom.unauthorized('', 'Basic');
expect(err.isMissing).to.equal(true);
done();
});
it('does not set the isMissing flag when error message is not empty', function (done) {
var err = Boom.unauthorized('message', 'Basic');
expect(err.isMissing).to.equal(undefined);
done();
});
it('sets a WWW-Authenticate when passed as an array', function (done) {
var err = Boom.unauthorized('message', ['Basic', 'Example e="1"', 'Another x="3", y="4"']);
expect(err.output.headers['WWW-Authenticate']).to.equal('Basic, Example e="1", Another x="3", y="4"');
done();
});
});
describe('methodNotAllowed()', function () {
it('returns a 405 error statusCode', function (done) {
expect(Boom.methodNotAllowed().output.statusCode).to.equal(405);
done();
});
it('sets the message with the passed in message', function (done) {
expect(Boom.methodNotAllowed('my message').message).to.equal('my message');
done();
});
});
describe('notAcceptable()', function () {
it('returns a 406 error statusCode', function (done) {
expect(Boom.notAcceptable().output.statusCode).to.equal(406);
done();
});
it('sets the message with the passed in message', function (done) {
expect(Boom.notAcceptable('my message').message).to.equal('my message');
done();
});
});
describe('proxyAuthRequired()', function () {
it('returns a 407 error statusCode', function (done) {
expect(Boom.proxyAuthRequired().output.statusCode).to.equal(407);
done();
});
it('sets the message with the passed in message', function (done) {
expect(Boom.proxyAuthRequired('my message').message).to.equal('my message');
done();
});
});
describe('clientTimeout()', function () {
it('returns a 408 error statusCode', function (done) {
expect(Boom.clientTimeout().output.statusCode).to.equal(408);
done();
});
it('sets the message with the passed in message', function (done) {
expect(Boom.clientTimeout('my message').message).to.equal('my message');
done();
});
});
describe('conflict()', function () {
it('returns a 409 error statusCode', function (done) {
expect(Boom.conflict().output.statusCode).to.equal(409);
done();
});
it('sets the message with the passed in message', function (done) {
expect(Boom.conflict('my message').message).to.equal('my message');
done();
});
});
describe('resourceGone()', function () {
it('returns a 410 error statusCode', function (done) {
expect(Boom.resourceGone().output.statusCode).to.equal(410);
done();
});
it('sets the message with the passed in message', function (done) {
expect(Boom.resourceGone('my message').message).to.equal('my message');
done();
});
});
describe('lengthRequired()', function () {
it('returns a 411 error statusCode', function (done) {
expect(Boom.lengthRequired().output.statusCode).to.equal(411);
done();
});
it('sets the message with the passed in message', function (done) {
expect(Boom.lengthRequired('my message').message).to.equal('my message');
done();
});
});
describe('preconditionFailed()', function () {
it('returns a 412 error statusCode', function (done) {
expect(Boom.preconditionFailed().output.statusCode).to.equal(412);
done();
});
it('sets the message with the passed in message', function (done) {
expect(Boom.preconditionFailed('my message').message).to.equal('my message');
done();
});
});
describe('entityTooLarge()', function () {
it('returns a 413 error statusCode', function (done) {
expect(Boom.entityTooLarge().output.statusCode).to.equal(413);
done();
});
it('sets the message with the passed in message', function (done) {
expect(Boom.entityTooLarge('my message').message).to.equal('my message');
done();
});
});
describe('uriTooLong()', function () {
it('returns a 414 error statusCode', function (done) {
expect(Boom.uriTooLong().output.statusCode).to.equal(414);
done();
});
it('sets the message with the passed in message', function (done) {
expect(Boom.uriTooLong('my message').message).to.equal('my message');
done();
});
});
describe('unsupportedMediaType()', function () {
it('returns a 415 error statusCode', function (done) {
expect(Boom.unsupportedMediaType().output.statusCode).to.equal(415);
done();
});
it('sets the message with the passed in message', function (done) {
expect(Boom.unsupportedMediaType('my message').message).to.equal('my message');
done();
});
});
describe('rangeNotSatisfiable()', function () {
it('returns a 416 error statusCode', function (done) {
expect(Boom.rangeNotSatisfiable().output.statusCode).to.equal(416);
done();
});
it('sets the message with the passed in message', function (done) {
expect(Boom.rangeNotSatisfiable('my message').message).to.equal('my message');
done();
});
});
describe('expectationFailed()', function () {
it('returns a 417 error statusCode', function (done) {
expect(Boom.expectationFailed().output.statusCode).to.equal(417);
done();
});
it('sets the message with the passed in message', function (done) {
expect(Boom.expectationFailed('my message').message).to.equal('my message');
done();
});
});
describe('badData()', function () {
it('returns a 422 error statusCode', function (done) {
expect(Boom.badData().output.statusCode).to.equal(422);
done();
});
it('sets the message with the passed in message', function (done) {
expect(Boom.badData('my message').message).to.equal('my message');
done();
});
});
describe('preconditionRequired()', function () {
it('returns a 428 error statusCode', function (done) {
expect(Boom.preconditionRequired().output.statusCode).to.equal(428);
done();
});
it('sets the message with the passed in message', function (done) {
expect(Boom.preconditionRequired('my message').message).to.equal('my message');
done();
});
});
describe('tooManyRequests()', function () {
it('returns a 429 error statusCode', function (done) {
expect(Boom.tooManyRequests().output.statusCode).to.equal(429);
done();
});
it('sets the message with the passed-in message', function (done) {
expect(Boom.tooManyRequests('my message').message).to.equal('my message');
done();
});
});
describe('serverTimeout()', function () {
it('returns a 503 error statusCode', function (done) {
expect(Boom.serverTimeout().output.statusCode).to.equal(503);
done();
});
it('sets the message with the passed in message', function (done) {
expect(Boom.serverTimeout('my message').message).to.equal('my message');
done();
});
});
describe('forbidden()', function () {
it('returns a 403 error statusCode', function (done) {
expect(Boom.forbidden().output.statusCode).to.equal(403);
done();
});
it('sets the message with the passed in message', function (done) {
expect(Boom.forbidden('my message').message).to.equal('my message');
done();
});
});
describe('notFound()', function () {
it('returns a 404 error statusCode', function (done) {
expect(Boom.notFound().output.statusCode).to.equal(404);
done();
});
it('sets the message with the passed in message', function (done) {
expect(Boom.notFound('my message').message).to.equal('my message');
done();
});
});
describe('internal()', function () {
it('returns a 500 error statusCode', function (done) {
expect(Boom.internal().output.statusCode).to.equal(500);
done();
});
it('sets the message with the passed in message', function (done) {
var err = Boom.internal('my message');
expect(err.message).to.equal('my message');
expect(err.isServer).to.true();
expect(err.output.payload.message).to.equal('An internal server error occurred');
done();
});
it('passes data on the callback if its passed in', function (done) {
expect(Boom.internal('my message', { my: 'data' }).data.my).to.equal('data');
done();
});
it('returns an error with composite message', function (done) {
try {
JSON.parse('{');
}
catch (err) {
var boom = Boom.internal('Someting bad', err);
expect(boom.message).to.equal('Someting bad: Unexpected end of input');
expect(boom.isServer).to.be.true();
done();
}
});
});
describe('notImplemented()', function () {
it('returns a 501 error statusCode', function (done) {
expect(Boom.notImplemented().output.statusCode).to.equal(501);
done();
});
it('sets the message with the passed in message', function (done) {
expect(Boom.notImplemented('my message').message).to.equal('my message');
done();
});
});
describe('badGateway()', function () {
it('returns a 502 error statusCode', function (done) {
expect(Boom.badGateway().output.statusCode).to.equal(502);
done();
});
it('sets the message with the passed in message', function (done) {
expect(Boom.badGateway('my message').message).to.equal('my message');
done();
});
});
describe('gatewayTimeout()', function () {
it('returns a 504 error statusCode', function (done) {
expect(Boom.gatewayTimeout().output.statusCode).to.equal(504);
done();
});
it('sets the message with the passed in message', function (done) {
expect(Boom.gatewayTimeout('my message').message).to.equal('my message');
done();
});
});
describe('badImplementation()', function () {
it('returns a 500 error statusCode', function (done) {
var err = Boom.badImplementation();
expect(err.output.statusCode).to.equal(500);
expect(err.isDeveloperError).to.equal(true);
expect(err.isServer).to.be.true();
done();
});
});
describe('stack trace', function () {
it('should omit lib', function (done) {
['badRequest', 'unauthorized', 'forbidden', 'notFound', 'methodNotAllowed',
'notAcceptable', 'proxyAuthRequired', 'clientTimeout', 'conflict',
'resourceGone', 'lengthRequired', 'preconditionFailed', 'entityTooLarge',
'uriTooLong', 'unsupportedMediaType', 'rangeNotSatisfiable', 'expectationFailed',
'badData', 'preconditionRequired', 'tooManyRequests',
// 500s
'internal', 'notImplemented', 'badGateway', 'serverTimeout', 'gatewayTimeout',
'badImplementation'
].forEach(function (name) {
var err = Boom[name]();
expect(err.stack).to.not.match(/\/lib\/index\.js/);
});
done();
});
});
'use strict';
var buffer = require('buffer');
var Buffer = buffer.Buffer;
var SlowBuffer = buffer.SlowBuffer;
var MAX_LEN = buffer.kMaxLength || 2147483647;
exports.alloc = function alloc(size, fill, encoding) {
if (typeof Buffer.alloc === 'function') {
return Buffer.alloc(size, fill, encoding);
}
if (typeof encoding === 'number') {
throw new TypeError('encoding must not be number');
}
if (typeof size !== 'number') {
throw new TypeError('size must be a number');
}
if (size > MAX_LEN) {
throw new RangeError('size is too large');
}
var enc = encoding;
var _fill = fill;
if (_fill === undefined) {
enc = undefined;
_fill = 0;
}
var buf = new Buffer(size);
if (typeof _fill === 'string') {
var fillBuf = new Buffer(_fill, enc);
var flen = fillBuf.length;
var i = -1;
while (++i < size) {
buf[i] = fillBuf[i % flen];
}
} else {
buf.fill(_fill);
}
return buf;
}
exports.allocUnsafe = function allocUnsafe(size) {
if (typeof Buffer.allocUnsafe === 'function') {
return Buffer.allocUnsafe(size);
}
if (typeof size !== 'number') {
throw new TypeError('size must be a number');
}
if (size > MAX_LEN) {
throw new RangeError('size is too large');
}
return new Buffer(size);
}
exports.from = function from(value, encodingOrOffset, length) {
if (typeof Buffer.from === 'function' && (!global.Uint8Array || Uint8Array.from !== Buffer.from)) {
return Buffer.from(value, encodingOrOffset, length);
}
if (typeof value === 'number') {
throw new TypeError('"value" argument must not be a number');
}
if (typeof value === 'string') {
return new Buffer(value, encodingOrOffset);
}
if (typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer) {
var offset = encodingOrOffset;
if (arguments.length === 1) {
return new Buffer(value);
}
if (typeof offset === 'undefined') {
offset = 0;
}
var len = length;
if (typeof len === 'undefined') {
len = value.byteLength - offset;
}
if (offset >= value.byteLength) {
throw new RangeError('\'offset\' is out of bounds');
}
if (len > value.byteLength - offset) {
throw new RangeError('\'length\' is out of bounds');
}
return new Buffer(value.slice(offset, offset + len));
}
if (Buffer.isBuffer(value)) {
var out = new Buffer(value.length);
value.copy(out, 0, 0, value.length);
return out;
}
if (value) {
if (Array.isArray(value) || (typeof ArrayBuffer !== 'undefined' && value.buffer instanceof ArrayBuffer) || 'length' in value) {
return new Buffer(value);
}
if (value.type === 'Buffer' && Array.isArray(value.data)) {
return new Buffer(value.data);
}
}
throw new TypeError('First argument must be a string, Buffer, ' + 'ArrayBuffer, Array, or array-like object.');
}
exports.allocUnsafeSlow = function allocUnsafeSlow(size) {
if (typeof Buffer.allocUnsafeSlow === 'function') {
return Buffer.allocUnsafeSlow(size);
}
if (typeof size !== 'number') {
throw new TypeError('size must be a number');
}
if (size >= MAX_LEN) {
throw new RangeError('size is too large');
}
return new SlowBuffer(size);
}

Copyright (c) 2016 Calvin Metcalf

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

{
"_args": [
[
{
"raw": "buffer-shims@^1.0.0",
"scope": null,
"escapedName": "buffer-shims",
"name": "buffer-shims",
"rawSpec": "^1.0.0",
"spec": ">=1.0.0 <2.0.0",
"type": "range"
},
"F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\readable-stream"
]
],
"_from": "buffer-shims@>=1.0.0 <2.0.0",
"_id": "buffer-shims@1.0.0",
"_inCache": true,
"_location": "/buffer-shims",
"_nodeVersion": "5.11.0",
"_npmOperationalInternal": {
"host": "packages-16-east.internal.npmjs.com",
"tmp": "tmp/buffer-shims-1.0.0.tgz_1462560889323_0.8640750856138766"
},
"_npmUser": {
"name": "cwmma",
"email": "calvin.metcalf@gmail.com"
},
"_npmVersion": "3.8.6",
"_phantomChildren": {},
"_requested": {
"raw": "buffer-shims@^1.0.0",
"scope": null,
"escapedName": "buffer-shims",
"name": "buffer-shims",
"rawSpec": "^1.0.0",
"spec": ">=1.0.0 <2.0.0",
"type": "range"
},
"_requiredBy": [
"/readable-stream"
],
"_resolved": "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz",
"_shasum": "9978ce317388c649ad8793028c3477ef044a8b51",
"_shrinkwrap": null,
"_spec": "buffer-shims@^1.0.0",
"_where": "F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\readable-stream",
"bugs": {
"url": "https://github.com/calvinmetcalf/buffer-shims/issues"
},
"dependencies": {},
"description": "some shims for node buffers",
"devDependencies": {
"tape": "^4.5.1"
},
"directories": {},
"dist": {
"shasum": "9978ce317388c649ad8793028c3477ef044a8b51",
"tarball": "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz"
},
"files": [
"index.js"
],
"gitHead": "ea89b3857ab5b8203957922a84e9a48cf4c47e0a",
"homepage": "https://github.com/calvinmetcalf/buffer-shims#readme",
"license": "MIT",
"main": "index.js",
"maintainers": [
{
"name": "cwmma",
"email": "calvin.metcalf@gmail.com"
}
],
"name": "buffer-shims",
"optionalDependencies": {},
"readme": "ERROR: No README data found!",
"repository": {
"type": "git",
"url": "git+ssh://git@github.com/calvinmetcalf/buffer-shims.git"
},
"scripts": {
"test": "tape test/*.js"
},
"version": "1.0.0"
}

buffer-shims

functions to make sure the new buffer methods work in older browsers.

var bufferShim = require('buffer-shims');
bufferShim.from('foo');
bufferShim.alloc(9, 'cafeface', 'hex');
bufferShim.allocUnsafe(15);
bufferShim.allocUnsafeSlow(21);

should just use the original in newer nodes and on older nodes uses fallbacks.

Known Issues

  • this does not patch the buffer object, only the constructor stuff
  • it's actually a polyfill

function Caseless (dict) {
this.dict = dict || {}
}
Caseless.prototype.set = function (name, value, clobber) {
if (typeof name === 'object') {
for (var i in name) {
this.set(i, name[i], value)
}
} else {
if (typeof clobber === 'undefined') clobber = true
var has = this.has(name)
if (!clobber && has) this.dict[has] = this.dict[has] + ',' + value
else this.dict[has || name] = value
return has
}
}
Caseless.prototype.has = function (name) {
var keys = Object.keys(this.dict)
, name = name.toLowerCase()
;
for (var i=0;i<keys.length;i++) {
if (keys[i].toLowerCase() === name) return keys[i]
}
return false
}
Caseless.prototype.get = function (name) {
name = name.toLowerCase()
var result, _key
var headers = this.dict
Object.keys(headers).forEach(function (key) {
_key = key.toLowerCase()
if (name === _key) result = headers[key]
})
return result
}
Caseless.prototype.swap = function (name) {
var has = this.has(name)
if (!has) throw new Error('There is no header than matches "'+name+'"')
this.dict[name] = this.dict[has]
delete this.dict[has]
}
Caseless.prototype.del = function (name) {
var has = this.has(name)
return delete this.dict[has || name]
}
module.exports = function (dict) {return new Caseless(dict)}
module.exports.httpify = function (resp, headers) {
var c = new Caseless(headers)
resp.setHeader = function (key, value, clobber) {
if (typeof value === 'undefined') return
return c.set(key, value, clobber)
}
resp.hasHeader = function (key) {
return c.has(key)
}
resp.getHeader = function (key) {
return c.get(key)
}
resp.removeHeader = function (key) {
return c.del(key)
}
resp.headers = c.dict
return c
}
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
You must give any other recipients of the Work or Derivative Works a copy of this License; and
You must cause any modified files to carry prominent notices stating that You changed the files; and
You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
{
"_args": [
[
{
"raw": "caseless@~0.11.0",
"scope": null,
"escapedName": "caseless",
"name": "caseless",
"rawSpec": "~0.11.0",
"spec": ">=0.11.0 <0.12.0",
"type": "range"
},
"F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\request"
]
],
"_from": "caseless@>=0.11.0 <0.12.0",
"_id": "caseless@0.11.0",
"_inCache": true,
"_location": "/caseless",
"_nodeVersion": "1.8.1",
"_npmUser": {
"name": "mikeal",
"email": "mikeal.rogers@gmail.com"
},
"_npmVersion": "2.8.3",
"_phantomChildren": {},
"_requested": {
"raw": "caseless@~0.11.0",
"scope": null,
"escapedName": "caseless",
"name": "caseless",
"rawSpec": "~0.11.0",
"spec": ">=0.11.0 <0.12.0",
"type": "range"
},
"_requiredBy": [
"/request"
],
"_resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz",
"_shasum": "715b96ea9841593cc33067923f5ec60ebda4f7d7",
"_shrinkwrap": null,
"_spec": "caseless@~0.11.0",
"_where": "F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\request",
"author": {
"name": "Mikeal Rogers",
"email": "mikeal.rogers@gmail.com"
},
"bugs": {
"url": "https://github.com/mikeal/caseless/issues"
},
"dependencies": {},
"description": "Caseless object set/get/has, very useful when working with HTTP headers.",
"devDependencies": {
"tape": "^2.10.2"
},
"directories": {},
"dist": {
"shasum": "715b96ea9841593cc33067923f5ec60ebda4f7d7",
"tarball": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz"
},
"gitHead": "c578232a02cc2b46b6da8851caf57fdbfac89ff5",
"homepage": "https://github.com/mikeal/caseless#readme",
"keywords": [
"headers",
"http",
"caseless"
],
"license": "Apache-2.0",
"main": "index.js",
"maintainers": [
{
"name": "mikeal",
"email": "mikeal.rogers@gmail.com"
},
{
"name": "nylen",
"email": "jnylen@gmail.com"
},
{
"name": "simov",
"email": "simeonvelichkov@gmail.com"
}
],
"name": "caseless",
"optionalDependencies": {},
"readme": "ERROR: No README data found!",
"repository": {
"type": "git",
"url": "git+https://github.com/mikeal/caseless.git"
},
"scripts": {
"test": "node test.js"
},
"test": "node test.js",
"version": "0.11.0"
}

Caseless -- wrap an object to set and get property with caseless semantics but also preserve caseing.

This library is incredibly useful when working with HTTP headers. It allows you to get/set/check for headers in a caseless manner while also preserving the caseing of headers the first time they are set.

Usage

var headers = {}
  , c = caseless(headers)
  ;
c.set('a-Header', 'asdf')
c.get('a-header') === 'asdf'

has(key)

Has takes a name and if it finds a matching header will return that header name with the preserved caseing it was set with.

c.has('a-header') === 'a-Header'

set(key, value[, clobber=true])

Set is fairly straight forward except that if the header exists and clobber is disabled it will add ','+value to the existing header.

c.set('a-Header', 'fdas')
c.set('a-HEADER', 'more', false)
c.get('a-header') === 'fdsa,more'

swap(key)

Swaps the casing of a header with the new one that is passed in.

var headers = {}
  , c = caseless(headers)
  ;
c.set('a-Header', 'fdas')
c.swap('a-HEADER')
c.has('a-header') === 'a-HEADER'
headers === {'a-HEADER': 'fdas'}
var tape = require('tape')
, caseless = require('./')
;
tape('set get has', function (t) {
var headers = {}
, c = caseless(headers)
;
t.plan(17)
c.set('a-Header', 'asdf')
t.equal(c.get('a-header'), 'asdf')
t.equal(c.has('a-header'), 'a-Header')
t.ok(!c.has('nothing'))
// old bug where we used the wrong regex
t.ok(!c.has('a-hea'))
c.set('a-header', 'fdsa')
t.equal(c.get('a-header'), 'fdsa')
t.equal(c.get('a-Header'), 'fdsa')
c.set('a-HEADER', 'more', false)
t.equal(c.get('a-header'), 'fdsa,more')
t.deepEqual(headers, {'a-Header': 'fdsa,more'})
c.swap('a-HEADER')
t.deepEqual(headers, {'a-HEADER': 'fdsa,more'})
c.set('deleteme', 'foobar')
t.ok(c.has('deleteme'))
t.ok(c.del('deleteme'))
t.notOk(c.has('deleteme'))
t.notOk(c.has('idonotexist'))
t.ok(c.del('idonotexist'))
c.set('tva', 'test1')
c.set('tva-header', 'test2')
t.equal(c.has('tva'), 'tva')
t.notOk(c.has('header'))
t.equal(c.get('tva'), 'test1')
})
'use strict';
var escapeStringRegexp = require('escape-string-regexp');
var ansiStyles = require('ansi-styles');
var stripAnsi = require('strip-ansi');
var hasAnsi = require('has-ansi');
var supportsColor = require('supports-color');
var defineProps = Object.defineProperties;
var isSimpleWindowsTerm = process.platform === 'win32' && !/^xterm/i.test(process.env.TERM);
function Chalk(options) {
// detect mode if not set manually
this.enabled = !options || options.enabled === undefined ? supportsColor : options.enabled;
}
// use bright blue on Windows as the normal blue color is illegible
if (isSimpleWindowsTerm) {
ansiStyles.blue.open = '\u001b[94m';
}
var styles = (function () {
var ret = {};
Object.keys(ansiStyles).forEach(function (key) {
ansiStyles[key].closeRe = new RegExp(escapeStringRegexp(ansiStyles[key].close), 'g');
ret[key] = {
get: function () {
return build.call(this, this._styles.concat(key));
}
};
});
return ret;
})();
var proto = defineProps(function chalk() {}, styles);
function build(_styles) {
var builder = function () {
return applyStyle.apply(builder, arguments);
};
builder._styles = _styles;
builder.enabled = this.enabled;
// __proto__ is used because we must return a function, but there is
// no way to create a function with a different prototype.
/* eslint-disable no-proto */
builder.__proto__ = proto;
return builder;
}
function applyStyle() {
// support varags, but simply cast to string in case there's only one arg
var args = arguments;
var argsLen = args.length;
var str = argsLen !== 0 && String(arguments[0]);
if (argsLen > 1) {
// don't slice `arguments`, it prevents v8 optimizations
for (var a = 1; a < argsLen; a++) {
str += ' ' + args[a];
}
}
if (!this.enabled || !str) {
return str;
}
var nestedStyles = this._styles;
var i = nestedStyles.length;
// Turns out that on Windows dimmed gray text becomes invisible in cmd.exe,
// see https://github.com/chalk/chalk/issues/58
// If we're on Windows and we're dealing with a gray color, temporarily make 'dim' a noop.
var originalDim = ansiStyles.dim.open;
if (isSimpleWindowsTerm && (nestedStyles.indexOf('gray') !== -1 || nestedStyles.indexOf('grey') !== -1)) {
ansiStyles.dim.open = '';
}
while (i--) {
var code = ansiStyles[nestedStyles[i]];
// Replace any instances already present with a re-opening code
// otherwise only the part of the string until said closing code
// will be colored, and the rest will simply be 'plain'.
str = code.open + str.replace(code.closeRe, code.open) + code.close;
}
// Reset the original 'dim' if we changed it to work around the Windows dimmed gray issue.
ansiStyles.dim.open = originalDim;
return str;
}
function init() {
var ret = {};
Object.keys(styles).forEach(function (name) {
ret[name] = {
get: function () {
return build.call(this, [name]);
}
};
});
return ret;
}
defineProps(Chalk.prototype, init());
module.exports = new Chalk();
module.exports.styles = ansiStyles;
module.exports.hasColor = hasAnsi;
module.exports.stripColor = stripAnsi;
module.exports.supportsColor = supportsColor;
The MIT License (MIT)
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
{
"_args": [
[
{
"raw": "chalk@^1.1.1",
"scope": null,
"escapedName": "chalk",
"name": "chalk",
"rawSpec": "^1.1.1",
"spec": ">=1.1.1 <2.0.0",
"type": "range"
},
"F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\har-validator"
]
],
"_from": "chalk@>=1.1.1 <2.0.0",
"_id": "chalk@1.1.3",
"_inCache": true,
"_location": "/chalk",
"_nodeVersion": "0.10.32",
"_npmOperationalInternal": {
"host": "packages-12-west.internal.npmjs.com",
"tmp": "tmp/chalk-1.1.3.tgz_1459210604109_0.3892582862172276"
},
"_npmUser": {
"name": "qix",
"email": "i.am.qix@gmail.com"
},
"_npmVersion": "2.14.2",
"_phantomChildren": {},
"_requested": {
"raw": "chalk@^1.1.1",
"scope": null,
"escapedName": "chalk",
"name": "chalk",
"rawSpec": "^1.1.1",
"spec": ">=1.1.1 <2.0.0",
"type": "range"
},
"_requiredBy": [
"/har-validator"
],
"_resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"_shasum": "a8115c55e4a702fe4d150abd3872822a7e09fc98",
"_shrinkwrap": null,
"_spec": "chalk@^1.1.1",
"_where": "F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\har-validator",
"bugs": {
"url": "https://github.com/chalk/chalk/issues"
},
"dependencies": {
"ansi-styles": "^2.2.1",
"escape-string-regexp": "^1.0.2",
"has-ansi": "^2.0.0",
"strip-ansi": "^3.0.0",
"supports-color": "^2.0.0"
},
"description": "Terminal string styling done right. Much color.",
"devDependencies": {
"coveralls": "^2.11.2",
"matcha": "^0.6.0",
"mocha": "*",
"nyc": "^3.0.0",
"require-uncached": "^1.0.2",
"resolve-from": "^1.0.0",
"semver": "^4.3.3",
"xo": "*"
},
"directories": {},
"dist": {
"shasum": "a8115c55e4a702fe4d150abd3872822a7e09fc98",
"tarball": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz"
},
"engines": {
"node": ">=0.10.0"
},
"files": [
"index.js"
],
"gitHead": "0d8d8c204eb87a4038219131ad4d8369c9f59d24",
"homepage": "https://github.com/chalk/chalk#readme",
"keywords": [
"color",
"colour",
"colors",
"terminal",
"console",
"cli",
"string",
"str",
"ansi",
"style",
"styles",
"tty",
"formatting",
"rgb",
"256",
"shell",
"xterm",
"log",
"logging",
"command-line",
"text"
],
"license": "MIT",
"maintainers": [
{
"name": "qix",
"email": "i.am.qix@gmail.com"
},
{
"name": "sindresorhus",
"email": "sindresorhus@gmail.com"
},
{
"name": "unicorn",
"email": "sindresorhus+unicorn@gmail.com"
}
],
"name": "chalk",
"optionalDependencies": {},
"readme": "ERROR: No README data found!",
"repository": {
"type": "git",
"url": "git+https://github.com/chalk/chalk.git"
},
"scripts": {
"bench": "matcha benchmark.js",
"coverage": "nyc npm test && nyc report",
"coveralls": "nyc npm test && nyc report --reporter=text-lcov | coveralls",
"test": "xo && mocha"
},
"version": "1.1.3",
"xo": {
"envs": [
"node",
"mocha"
]
}
}



chalk


Terminal string styling done right

Build Status Coverage Status

colors.js used to be the most popular string styling module, but it has serious deficiencies like extending String.prototype which causes all kinds of problems. Although there are other ones, they either do too much or not enough.

Chalk is a clean and focused alternative.

Why

  • Highly performant
  • Doesn't extend String.prototype
  • Expressive API
  • Ability to nest styles
  • Clean and focused
  • Auto-detects color support
  • Actively maintained
  • Used by ~4500 modules as of July 15, 2015

Install

$ npm install --save chalk

Usage

Chalk comes with an easy to use composable API where you just chain and nest the styles you want.

var chalk = require('chalk');

// style a string
chalk.blue('Hello world!');

// combine styled and normal strings
chalk.blue('Hello') + 'World' + chalk.red('!');

// compose multiple styles using the chainable API
chalk.blue.bgRed.bold('Hello world!');

// pass in multiple arguments
chalk.blue('Hello', 'World!', 'Foo', 'bar', 'biz', 'baz');

// nest styles
chalk.red('Hello', chalk.underline.bgBlue('world') + '!');

// nest styles of the same type even (color, underline, background)
chalk.green(
	'I am a green line ' +
	chalk.blue.underline.bold('with a blue substring') +
	' that becomes green again!'
);

Easily define your own themes.

var chalk = require('chalk');
var error = chalk.bold.red;
console.log(error('Error!'));

Take advantage of console.log string substitution.

var name = 'Sindre';
console.log(chalk.green('Hello %s'), name);
//=> Hello Sindre

API

chalk.<style>[.<style>...](string, [string...])

Example: chalk.red.bold.underline('Hello', 'world');

Chain styles and call the last one as a method with a string argument. Order doesn't matter, and later styles take precedent in case of a conflict. This simply means that Chalk.red.yellow.green is equivalent to Chalk.green.

Multiple arguments will be separated by space.

chalk.enabled

Color support is automatically detected, but you can override it by setting the enabled property. You should however only do this in your own code as it applies globally to all chalk consumers.

If you need to change this in a reusable module create a new instance:

var ctx = new chalk.constructor({enabled: false});

chalk.supportsColor

Detect whether the terminal supports color. Used internally and handled for you, but exposed for convenience.

Can be overridden by the user with the flags --color and --no-color. For situations where using --color is not possible, add an environment variable FORCE_COLOR with any value to force color. Trumps --no-color.

chalk.styles

Exposes the styles as ANSI escape codes.

Generally not useful, but you might need just the .open or .close escape code if you're mixing externally styled strings with your own.

var chalk = require('chalk');

console.log(chalk.styles.red);
//=> {open: '\u001b[31m', close: '\u001b[39m'}

console.log(chalk.styles.red.open + 'Hello' + chalk.styles.red.close);

chalk.hasColor(string)

Check whether a string has color.

chalk.stripColor(string)

Strip color from a string.

Can be useful in combination with .supportsColor to strip color on externally styled text when it's not supported.

Example:

var chalk = require('chalk');
var styledString = getText();

if (!chalk.supportsColor) {
	styledString = chalk.stripColor(styledString);
}

Styles

Modifiers

  • reset
  • bold
  • dim
  • italic (not widely supported)
  • underline
  • inverse
  • hidden
  • strikethrough (not widely supported)

Colors

  • black
  • red
  • green
  • yellow
  • blue (on Windows the bright version is used as normal blue is illegible)
  • magenta
  • cyan
  • white
  • gray

Background colors

  • bgBlack
  • bgRed
  • bgGreen
  • bgYellow
  • bgBlue
  • bgMagenta
  • bgCyan
  • bgWhite

256-colors

Chalk does not support anything other than the base eight colors, which guarantees it will work on all terminals and systems. Some terminals, specifically xterm compliant ones, will support the full range of 8-bit colors. For this the lower level ansi-256-colors package can be used.

Windows

If you're on Windows, do yourself a favor and use cmder instead of cmd.exe.

Related

  • chalk-cli - CLI for this module
  • ansi-styles - ANSI escape codes for styling strings in the terminal
  • supports-color - Detect whether a terminal supports color
  • strip-ansi - Strip ANSI escape codes
  • has-ansi - Check if a string has ANSI escape codes
  • ansi-regex - Regular expression for matching ANSI escape codes
  • wrap-ansi - Wordwrap a string with ANSI escape codes

License

MIT © Sindre Sorhus

0.22.0 / 2016-08-23

  • Return undefined in .prop if given an invalid element or tag (#880)
  • Merge pull request #884 from cheeriojs/readme-cleanup
  • readme updates
  • Merge pull request #881 from piamancini/patch-1
  • Added backers and sponsors from OpenCollective
  • Use jQuery from the jquery module in benchmarks (#871)
  • Document, test, and extend static $.text method (#855)
  • Fix typo on calling _.extend (#861)
  • Update versions (#870)
  • Use individual lodash functions (#864)
  • Added .serialize() support. Fixes #69 (#827)
  • Update Readme.md (#857)
  • add extension for JSON require call
  • remove gittask badge
  • Merge pull request #672 from underdogio/dev/checkbox.radio.values.sqwished
  • Added default value for checkboxes/radios

0.20.0 / 2016-02-01

  • Add coveralls badge, remove link to old report (Felix Böhm)
  • Update lodash dependeny to 4.1.0 (leif.hanack)
  • Fix PR #726 adding 'appendTo()' and 'prependTo()' (Delgan)
  • Added appendTo and prependTo with tests #641 (digihaven)
  • Fix #780 by changing options context in '.find()' (Felix Böhm)
  • Add an unit test checking the query of child (Delgan)
  • fix #667: attr({foo: null}) removes attribute foo, like attr('foo', null) (Ray Waldin)
  • Include reference to dedicated "Loading" section (Mike Pennisi)
  • Added load method to $ (alanev)
  • update css-select to 1.2.0 (Felix Böhm)
  • Fixing Grammatical Error (Dan Corman)
  • Test against node v0.12 --> v4.2 (Jason Kurian)
  • Correct output in example (Felix Böhm)
  • Fix npm files filter (Bogdan Chadkin)
  • Enable setting data on all elements in selection (Mike Pennisi)
  • Reinstate $.fn.toArray (Mike Pennisi)
  • update css-select to 1.1.0 (Thomas Shafer)
  • Complete implementation of wrap (Mike Pennisi)
  • Correct name of unit test (Mike Pennisi)
  • Correct grammar in test titles (Mike Pennisi)
  • Normalize whitespace (Mike Pennisi)
  • Insert omitted assertion (Mike Pennisi)
  • Update invocation of children (Mike Pennisi)
  • Begin implementation of wrap method (Dandlezzz)
  • Update Readme.md (Sven Slootweg)
  • fix document's mistake in Readme.md (exoticknight)
  • Add tests for setting text and html as non-strings (Ryc O'Chet)
  • Fix for passing non-string values to .html or .text (Ryc O'Chet)
  • use a selector to filter form elements (fb55)
  • fix README.md typo (Yutian Li)
  • README: fix spelling (Chris Rebert)
  • Added support for options without a value attribute. Fixes #633 (Todd Wolfson)
  • responding to pull request feedback - remove item() method and related tests (Ray Waldin)
  • add length property and item method to object returned by prop('style'), plus tests (Ray Waldin)
  • Added .prop method to readme (Artem Burtsev)
  • Added .prop method (Artem Burtsev)
  • Added Gitter badge (The Gitter Badger)

0.19.0 / 2015-03-21

  • fixed allignment (fb55)
  • added test case for malformed json in data attributes (fb55)
  • fix: handle some extreme cases like data-custom="{{templatevar}}". There is possibility error while parsing json . (Harish.K)
  • Add missing optional selector doc for {prev,next}{All,Until} (Jérémie Astori)
  • update to dom-serializer@0.1.0 (Felix Böhm)
  • Document Cheerio#serialzeArray (Mike Pennisi)
  • Fixed up serializeArray() and added multiple support (Todd Wolfson)
  • Implement serializeArray() (Jarno Leppänen)
  • recognize options in $.xml() (fb55)
  • lib/static.js: text(): rm errant space before ++ (Chris Rebert)
  • Do not expose internal children array (Mike Pennisi)
  • Change lodash dependencies to ^3.1.0 (Samy Pessé)
  • Update lodash@3.1.0 (Samy Pessé)
  • Updates Readme.md: .not(function (index, elem)) (Patrick Ward)
  • update to css-select@1.0.0 (fb55)
  • Allow failures in Node.js v0.11 (Mike Pennisi)
  • Added: Gittask badge (Matthew Mueller)
  • Isolate prototypes of functions created via load (Mike Pennisi)
  • Updates Readme.md: adds JS syntax highlighting (frankcash)
  • #608 -- Add support for insertBefore/insertAfter syntax. Supports target types of: $, [$], selector (both single and multiple results) (Ben Cochran)
  • Clone input nodes when inserting over a set (Mike Pennisi)
  • Move unit test files (Mike Pennisi)
  • remove unnecessarily tricky code (David Chambers)
  • pass options to $.html in toString (fb55)
  • add license info to package.json (Chris Rebert)
  • xyz@~0.5.0 (David Chambers)
  • Remove unofficial signature of children (Mike Pennisi)
  • Fix bug in css method (Mike Pennisi)
  • Correct bug in implementation of Cheerio#val (Mike Pennisi)

0.18.0 / 2014-11-06

  • bump htmlparser2 dependency to ~3.8.1 (Chris Rebert)
  • Correct unit test titles (Mike Pennisi)
  • Correct behavior of after and before (Mike Pennisi)
  • implement jQuery's .has() (Chris Rebert)
  • Update repository url (haqii)
  • attr() should return undefined or name for booleans (Raoul Millais)
  • Update Readme.md (Ryan Breen)
  • Implement Cheerio#not (Mike Pennisi)
  • Clone nodes according to original parsing options (Mike Pennisi)
  • fix lint error (David Chambers)
  • Add explicit tests for DOM level 1 API (Mike Pennisi)
  • Expose DOM level 1 API for Node-like objects (Mike Pennisi)
  • Correct error in documentation (Mike Pennisi)
  • Return a fully-qualified Function from $.load (Mike Pennisi)
  • Update tests to avoid duck typing (Mike Pennisi)
  • Alter "loaded" functions to produce true instances (Mike Pennisi)
  • Organize tests for cheerio.load (Mike Pennisi)
  • Complete $.prototype.find (Mike Pennisi)
  • Use JSHint's extends option (Mike Pennisi)
  • Remove aliases for exported methods (Mike Pennisi)
  • Disallow unused variables (Mike Pennisi)
  • Remove unused internal variables (Mike Pennisi)
  • Remove unused variables from unit tests (Mike Pennisi)
  • Remove unused API method references (Mike Pennisi)
  • Move tests for contains method (Mike Pennisi)
  • xyz@0.4.0 (David Chambers)
  • Created a wiki for companies using cheerio in production (Matthew Mueller)
  • Implement $.prototype.index (Mike Pennisi)
  • Implement $.prototype.addBack (Mike Pennisi)
  • Added double quotes to radio attribute name to account for characters such as brackets (akant10)
  • Update History.md (Gabriel Falkenberg)
  • add 0.17.0 changelog (David Chambers)
  • exit prepublish script if tag not found (David Chambers)
  • alphabetize devDependencies (fb55)
  • ignore coverage dir (fb55)
  • submit coverage to coveralls (fb55)
  • replace jscoverage with istanbul (fb55)

0.17.0 / 2014-06-10

  • Fix bug in internal uniqueSplice function (Mike Pennisi)
  • accept buffer argument to cheerio.load (David Chambers)
  • Respect options on the element level (Alex Indigo)
  • Change state definition to more readable (Artem Burtsev)
  • added test (0xBADC0FFEE)
  • add class only if doesn't exist (Artem Burtsev)
  • Made it less insane. (Alex Indigo)
  • Implement Cheerio#add (Mike Pennisi)
  • Use "loaded" instance of Cheerio in unit tests (Mike Pennisi)
  • Be more strict with object check. (Alex Indigo)
  • Added options argument to .html() static method. (Alex Indigo)
  • Fixed encoding mishaps. Adjusted tests. (Alex Indigo)
  • use dom-serializer module (fb55)
  • don't test on 0.8, don't ignore 0.11 (Felix Böhm)
  • parse: rm unused variables (coderaiser)
  • cheerio: rm unused variable (coderaiser)
  • Fixed test (Avi Kohn)
  • Added test (Avi Kohn)
  • Changed == to === (Avi Kohn)
  • Fixed a bug in removing type="hidden" attr (Avi Kohn)
  • sorted (Alexey Raspopov)
  • add muted attr to booleanAttributes (Alexey Raspopov)
  • fixed context of this in .html (Felix Böhm)
  • append new elements for each element in selection (fb55)

0.16.0 / 2014-05-08

  • fix make bench (David Chambers)
  • makefile: add release-* targets (David Chambers)
  • alphabetize dependencies (David Chambers)
  • Rewrite data internals with caching behavior (Mike Pennisi)
  • Fence .val example as js (Kevin Sawicki)
  • Fixed typos. Deleted trailing whitespace from test/render.js (Nattaphoom Ch)
  • Fix manipulation APIs with removed elements (kpdecker)
  • Perform manual string parsing for hasClass (kpdecker)
  • Fix existing element removal (kpdecker)
  • update render tests (Felix Böhm)
  • fixed cheerio path (Felix Böhm)
  • use entities.escape for attribute values (Felix Böhm)
  • bump entities version (Felix Böhm)
  • remove lowerCaseTags option from readme (Felix Böhm)
  • added test case for .html in xmlMode (fb55)
  • render xml in html() when xmlMode: true (fb55)
  • use a map for booleanAttributes (fb55)
  • update singleTags, use utils.isTag (fb55)
  • update travis badge URL (Felix Böhm)
  • use typeof instead of _.isString and _.isNumber (fb55)
  • use Array.isArray instead of _.isArray (fb55)
  • replace _.isFunction with typeof (fb55)
  • removed unnecessary error message (fb55)
  • decode entities in htmlparser2 (fb55)
  • pass options object to CSSselect (fb55)

0.15.0 / 2014-04-08

  • Update callbacks to pass element per docs (@kpdecker)
  • preserve options (@fb55)
  • Use SVG travis badge (@t3chnoboy)
  • only use static requires (@fb55)
  • Optimize manipulation methods (@kpdecker)
  • Optimize add and remove class cases (@kpdecker)
  • accept dom of DomHandler to cheerio.load (@nleush)
  • added parentsUntil method (@finspin)
  • Add performance optimization and bug fix empty method (@kpdecker)

0.14.0 / 2014-04-01

  • call encodeXML and directly expose decodeHTML (@fb55)
  • use latest htmlparser2 and entities versions (@fb55)
  • Deprecate $.fn.toArray (@jugglinmike)
  • Implement $.fn.get (@jugglinmike)
  • .replaceWith now replaces all selected elements. (@xavi-)
  • Correct arguments for 'replaceWith' callback (@jugglinmike)
  • switch to lodash (@fb55)
  • update to entities@0.5.0 (@fb55)
  • Fix attr when $ collection contains text modules (@kpdecker)
  • Update to latest version of expect.js (@jugglinmike)
  • Remove nodes from their previous structures (@jugglinmike)
  • Update render.js (@stevenvachon)
  • CDATA test (@stevenvachon)
  • only ever one child index for cdata (@stevenvachon)
  • don't loop through cdata children array (@stevenvachon)
  • proper rendering of CDATA (@stevenvachon)
  • Add cheerio-only bench option (@kpdecker)
  • Avoid delete operations (@kpdecker)
  • Add independent html benchmark (@kpdecker)
  • Cache tag check in render (@kpdecker)
  • Simplify attribute rendering step (@kpdecker)
  • Add html rendering bench case (@kpdecker)
  • Remove unnecessary check from removeAttr (@kpdecker)
  • Remove unnecessary encoding step for attrs (@kpdecker)
  • Add test for removeAttr+attr on boolean attributes (@kpdecker)
  • Add single element benchmark case (@kpdecker)
  • Optimize filter with selector (@kpdecker)
  • Fix passing context as dom node (@alfred-nsh)
  • Fix bug in nextUntil (@jugglinmike)
  • Fix bug in nextAll (@jugglinmike)
  • Implement selector argument of next method (@jugglinmike)
  • Fix bug in prevUntil (@jugglinmike)
  • Implement selector argument of prev method (@jugglinmike)
  • Fix bug in prevAll (@jugglinmike)
  • Fix bug in siblings (@jugglinmike)
  • Avoid unnecessary indexOf from toggleClass (@kpdecker)
  • Use strict equality rather than falsy check in eq (@kpdecker)
  • Add benchmark coverage for all $ APIs (@kpdecker)
  • Optimize filter Cheerio intermediate creation (@kpdecker)
  • Optimize siblings cheerio instance creation (@kpdecker)
  • Optimize identity cases for first/last/eq (@kpdecker)
  • Use domEach for traversal (@kpdecker)
  • Inline children lookup in find (@kpdecker)
  • Use domEach in data accessor (@kpdecker)
  • Avoid cheerio creation in add/remove/toggleClass (@kpdecker)
  • Implement getAttr local helper (@kpdecker)

0.13.1 / 2014-01-07

  • Fix select with context in Cheerio function (@jugglinmike)
  • Remove unecessary DOM maintenance logic (@jugglinmike)
  • Deprecate support for node 0.6

0.13.0 / 2013-12-30

  • Remove "root" node (@jugglinmike)
  • Fix bug in prevAll, prev, nextAll, next, prevUntil, nextUntil (@jugglinmike)
  • Fix replaceWith method (@jugglinmike)
  • added nextUntil() and prevUntil() (@finspin)
  • Remove internal connect function (@jugglinmike)
  • Rename Cheerio#make to document private status (@jugginmike)
  • Remove extraneous call to _.uniq (@jugglinmike)
  • Use CSSselect library directly (@jugglinmike)
  • Run CI against Node v0.11 as an allowed failure (@jugginmike)
  • Correct bug in Cheerio#parents (@jugglinmike)
  • Implement $.fn.end (@jugginmike)
  • Ignore colons inside of url(.*) when parsing css (@Meekohi)
  • Introduce rudimentary benchmark suite (@jugglinmike)
  • Update HtmlParser2 version (@jugglinmike)
  • Correct inconsistency in $.fn.map (@jugglinmike)
  • fixed traversing tests (@finspin)
  • Simplify make method (@jugglinmike)
  • Avoid shadowing instance methods from arrays (@jugglinmike)

0.12.4 / 2013-11-12

  • Coerce JSON values returned by data (@jugglinmike)
  • issue #284: when rendering HTML, use original data attributes (@Trott)
  • Introduce JSHint for automated code linting (@jugglinmike)
  • Prevent find from returning duplicate elements (@jugglinmike)
  • Implement function signature of replaceWith (@jugglinmike)
  • Implement function signature of before (@jugglinmike)
  • Implement function signature of after (@jugglinmike)
  • Implement function signature of append/prepend (@jugglinmike)
  • Extend iteration methods to accept nodes (@jugglinmike)
  • Improve removeClass (@jugglinmike)
  • Complete function signature of addClass (@jugglinmike)
  • Fix bug in removeClass (@jugglinmike)
  • Improve contributing.md (@jugglinmike)
  • Fix and document .css() (@jugglinmike)

0.12.3 / 2013-10-04

  • Add .toggleClass() function (@cyberthom)
  • Add contributing guidelines (@jugglinmike)
  • Fix bug in siblings (@jugglinmike)
  • Correct the implementation filter and is (@jugglinmike)
  • add .data() function (@andi-neck)
  • add .css() (@yields)
  • Implements contents() (@jlep)

0.12.2 / 2013-09-04

  • Correct implementation of $.fn.text (@jugglinmike)
  • Refactor Cheerio array creation (@jugglinmike)
  • Extend manipulation methods to accept Arrays (@jugglinmike)
  • support .attr(attributeName, function(index, attr)) (@xiaohwan)

0.12.1 / 2013-07-30

  • Correct behavior of Cheerio#parents (@jugglinmike)
  • Double quotes inside attributes kills HTML (@khoomeister)
  • Making next({}) and prev({}) return empty object (@absentTelegraph)
  • Implement $.parseHTML (@jugglinmike)
  • Correct bug in jQuery.fn.closest (@jugglinmike)
  • Correct behavior of $.fn.val on 'option' elements (@jugglinmike)

0.12.0 / 2013-06-09

  • Breaking Change: Changed context from parent to the actual passed one (@swissmanu)
  • Fixed: jquery checkbox val behavior (@jhubble)
  • Added: output xml with $.xml() (@Maciek416)
  • Bumped: htmlparser2 to 3.1.1
  • Fixed: bug in attr(key, val) on empty objects (@farhadi)
  • Added: prevAll, nextAll (@lessmind)
  • Fixed: Safety check in parents and closest (@zero21xxx)
  • Added: .is(sel) (@zero21xxx)

0.11.0 / 2013-04-22

  • Added: .closest() (@jeremy-dentel)
  • Added: .parents() (@zero21xxx)
  • Added: .val() (@rschmukler & @leahciMic)
  • Added: Travis support for node 0.10.0 (@jeremy-dentel)
  • Fixed: .find() if no selector (@davidchambers)
  • Fixed: Propagate syntax errors caused by invalid selectors (@davidchambers)

0.10.8 / 2013-03-11

  • Add slice method (SBoudrias)

0.10.7 / 2013-02-10

  • Code & doc cleanup (davidchambers)
  • Fixed bug in filter (jugglinmike)

0.10.6 / 2013-01-29

  • Added $.contains(...) (jugglinmike)
  • formatting cleanup (davidchambers)
  • Bug fix for .children() (jugglinmike & davidchambers)
  • Remove global render bug (wvl)

0.10.5 / 2012-12-18

  • Fixed botched publish from 0.10.4 - changes should now be present

0.10.4 / 2012-12-16

  • $.find should query descendants only (@jugglinmike)
  • Tighter underscore dependency

0.10.3 / 2012-11-18

  • fixed outer html bug
  • Updated documentation for $(...).html() and $.html()

0.10.2 / 2012-11-17

  • Added a toString() method (@bensheldon)
  • use _.each and _.map to simplify cheerio namesakes (@davidchambers)
  • Added filter() with tests and updated readme (@bensheldon & @davidchambers)
  • Added spaces between attributes rewritten by removeClass (@jos3000)
  • updated docs to remove reference to size method (@ironchefpython)
  • removed HTML tidy/pretty print from cheerio

0.10.1 / 2012-10-04

  • Fixed regression, filtering with a context (#106)

0.10.0 / 2012-09-24

  • Greatly simplified and reorganized the library, reducing the loc by 30%
  • Now supports mocha's test-coverage
  • Deprecated self-closing tags (HTML5 doesn't require them)
  • Fixed error thrown in removeClass(...) @robashton

0.9.2 / 2012-08-10

  • added $(...).map(fn)
  • manipulation: refactor makeCheerioArray
  • make .removeClass() remove all occurrences (#64)

0.9.1 / 2012-08-03

  • fixed bug causing options not to make it to the parser

0.9.0 / 2012-07-24

  • Added node 8.x support
  • Removed node 4.x support
  • Add html(dom) support (@wvl)
  • fixed xss vulnerabilities on .attr(), .text(), & .html() (@benatkin, @FB55)
  • Rewrote tests into javascript, removing coffeescript dependency (@davidchambers)
  • Tons of cleanup (@davidchambers)

0.8.3 / 2012-06-12

  • Fixed minor package regression (closes #60)

0.8.2 / 2012-06-11

  • Now fails gracefully in cases that involve special chars, which is inline with jQuery (closes #59)
  • text() now decode special entities (closes #52)
  • updated travis.yml to test node 4.x

0.8.1 / 2012-06-02

  • fixed regression where if you created an element, it would update the root
  • compatible with node 4.x (again)

0.8.0 / 2012-05-27

  • Updated CSS parser to use FB55/CSSselect. Cheerio now supports most CSS3 psuedo selectors thanks to @FB55.
  • ignoreWhitespace now on by default again. See #55 for context.
  • Changed $(':root') to $.root(), cleaned up $.clone()
  • Support for .eq(i) thanks to @alexbardas
  • Removed support for node 0.4.x
  • Fixed memory leak where package.json was continually loaded
  • Tons more tests

0.7.0 / 2012-04-08

  • Now testing with node v0.7.7
  • Added travis-ci integration
  • Replaced should.js with expect.js. Browser testing to come
  • Fixed spacing between attributes and their values
  • Added HTML tidy/pretty print
  • Exposed node-htmlparser2 parsing options
  • Revert .replaceWith(...) to be consistent with jQuery

0.6.2 / 2012-02-12

  • Fixed .replaceWith(...) regression

0.6.1 / 2012-02-12

  • Added .first(), .last(), and .clone() commands.
  • Option to parse using whitespace added to .load.
  • Many bug fixes to make cheerio more aligned with jQuery.
  • Added $(':root') to select the highest level element.

Many thanks to the contributors that made this release happen: @ironchefpython and @siddMahen

0.6.0 / 2012-02-07

  • Important: $(...).html() now returns inner HTML, which is in line with the jQuery spec
  • $.html() returns the full HTML string. $.html([cheerioObject]) will return the outer(selected element's tag) and inner HTML of that object
  • Fixed bug that prevented HTML strings with depth (eg. append('<ul><li><li></ul>')) from getting parent, next, prev attributes.
  • Halted htmlparser2 at v2.2.2 until single attributes bug gets fixed.

0.5.1 / 2012-02-05

  • Fixed minor regression: $(...).text(fn) would fail

0.5.1 / 2012-02-05

  • Fixed regression: HTML pages with comments would fail

0.5.0 / 2012-02-04

  • Transitioned from Coffeescript back to Javascript
  • Parser now ignores whitespace
  • Fixed issue with double slashes on self-enclosing tags
  • Added boolean attributes to html rendering

0.4.2 / 2012-01-16

  • Multiple selectors support: $('.apple, .orange'). Thanks @siddMahen!
  • Update package.json to always use latest cheerio-soupselect
  • Fix memory leak in index.js

0.4.1 / 2011-12-19

  • Minor packaging changes to allow make test to work from npm installation

0.4.0 / 2011-12-19

  • Rewrote all unit tests as cheerio transitioned from vows -> mocha
  • Internally, renderer.render -> render(...), parser.parse -> parse(...)
  • Append, prepend, html, before, after all work with only text (no tags)
  • Bugfix: Attributes can now be removed from script and style tags
  • Added yield as a single tag
  • Cheerio now compatible with node >=0.4.7

0.3.2 / 2011-12-1

  • Fixed $(...).text(...) to work with "root" element

0.3.1 / 2011-11-25

  • Now relying on cheerio-soupselect instead of node-soupselect
  • Removed all lingering htmlparser dependencies
  • parser now returns parent "root" element. Root now never needs to be updated when there is multiple roots. This fixes ongoing issues with before(...), after(...) and other manipulation functions
  • Added jQuery's $(...).replaceWith(...)

0.3.0 / 2011-11-19

  • Now using htmlparser2 for parsing (2x speed increase, cleaner, actively developed)
  • Added benchmark directory for future speed tests
  • $('...').dom() was funky, so it was removed in favor of $('...').get(). $.dom() still works the same.
  • $.root now correctly static across all instances of $
  • Added a screencast

0.2.2 / 2011-11-9

  • Traversing will select <script> and <style> tags (Closes Issue: #8)
  • .text(string) now working with empty elements (Closes Issue: #7)
  • Fixed before(...) & after(...) again if there is no parent (Closes Issue: #2)

0.2.1 / 2011-11-5

  • Fixed before(...) & after(...) if there is no parent (Closes Issue: #2)
  • Comments now rendered correctly (Closes Issue: #5)

< 0.2.0 / 2011-10-31

  • Initial release (untracked development)
/**
* Export cheerio (with )
*/
exports = module.exports = require('./lib/cheerio');
/*
Export the version
*/
exports.version = require('./package.json').version;
var $ = require('../static'),
utils = require('../utils'),
isTag = utils.isTag,
domEach = utils.domEach,
hasOwn = Object.prototype.hasOwnProperty,
camelCase = utils.camelCase,
cssCase = utils.cssCase,
rspace = /\s+/,
dataAttrPrefix = 'data-',
_ = {
forEach: require('lodash.foreach'),
extend: require('lodash.assignin'),
some: require('lodash.some')
},
// Lookup table for coercing string data-* attributes to their corresponding
// JavaScript primitives
primitives = {
null: null,
true: true,
false: false
},
// Attributes that are booleans
rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,
// Matches strings that look like JSON objects or arrays
rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/;
var getAttr = function(elem, name) {
if (!elem || !isTag(elem)) return;
if (!elem.attribs) {
elem.attribs = {};
}
// Return the entire attribs object if no attribute specified
if (!name) {
return elem.attribs;
}
if (hasOwn.call(elem.attribs, name)) {
// Get the (decoded) attribute
return rboolean.test(name) ? name : elem.attribs[name];
}
// Mimic the DOM and return text content as value for `option's`
if (elem.name === 'option' && name === 'value') {
return $.text(elem.children);
}
// Mimic DOM with default value for radios/checkboxes
if (elem.name === 'input' &&
(elem.attribs.type === 'radio' || elem.attribs.type === 'checkbox') &&
name === 'value') {
return 'on';
}
};
var setAttr = function(el, name, value) {
if (value === null) {
removeAttribute(el, name);
} else {
el.attribs[name] = value+'';
}
};
exports.attr = function(name, value) {
// Set the value (with attr map support)
if (typeof name === 'object' || value !== undefined) {
if (typeof value === 'function') {
return domEach(this, function(i, el) {
setAttr(el, name, value.call(el, i, el.attribs[name]));
});
}
return domEach(this, function(i, el) {
if (!isTag(el)) return;
if (typeof name === 'object') {
_.forEach(name, function(value, name) {
setAttr(el, name, value);
});
} else {
setAttr(el, name, value);
}
});
}
return getAttr(this[0], name);
};
var getProp = function (el, name) {
if (!el || !isTag(el)) return;
return el.hasOwnProperty(name)
? el[name]
: rboolean.test(name)
? getAttr(el, name) !== undefined
: getAttr(el, name);
};
var setProp = function (el, name, value) {
el[name] = rboolean.test(name) ? !!value : value;
};
exports.prop = function (name, value) {
var i = 0,
property;
if (typeof name === 'string' && value === undefined) {
switch (name) {
case 'style':
property = this.css();
_.forEach(property, function (v, p) {
property[i++] = p;
});
property.length = i;
break;
case 'tagName':
case 'nodeName':
property = this[0].name.toUpperCase();
break;
default:
property = getProp(this[0], name);
}
return property;
}
if (typeof name === 'object' || value !== undefined) {
if (typeof value === 'function') {
return domEach(this, function(i, el) {
setProp(el, name, value.call(el, i, getProp(el, name)));
});
}
return domEach(this, function(i, el) {
if (!isTag(el)) return;
if (typeof name === 'object') {
_.forEach(name, function(val, name) {
setProp(el, name, val);
});
} else {
setProp(el, name, value);
}
});
}
};
var setData = function(el, name, value) {
if (!el.data) {
el.data = {};
}
if (typeof name === 'object') return _.extend(el.data, name);
if (typeof name === 'string' && value !== undefined) {
el.data[name] = value;
} else if (typeof name === 'object') {
_.extend(el.data, name);
}
};
// Read the specified attribute from the equivalent HTML5 `data-*` attribute,
// and (if present) cache the value in the node's internal data store. If no
// attribute name is specified, read *all* HTML5 `data-*` attributes in this
// manner.
var readData = function(el, name) {
var readAll = arguments.length === 1;
var domNames, domName, jsNames, jsName, value, idx, length;
if (readAll) {
domNames = Object.keys(el.attribs).filter(function(attrName) {
return attrName.slice(0, dataAttrPrefix.length) === dataAttrPrefix;
});
jsNames = domNames.map(function(domName) {
return camelCase(domName.slice(dataAttrPrefix.length));
});
} else {
domNames = [dataAttrPrefix + cssCase(name)];
jsNames = [name];
}
for (idx = 0, length = domNames.length; idx < length; ++idx) {
domName = domNames[idx];
jsName = jsNames[idx];
if (hasOwn.call(el.attribs, domName)) {
value = el.attribs[domName];
if (hasOwn.call(primitives, value)) {
value = primitives[value];
} else if (value === String(Number(value))) {
value = Number(value);
} else if (rbrace.test(value)) {
try {
value = JSON.parse(value);
} catch(e){ }
}
el.data[jsName] = value;
}
}
return readAll ? el.data : value;
};
exports.data = function(name, value) {
var elem = this[0];
if (!elem || !isTag(elem)) return;
if (!elem.data) {
elem.data = {};
}
// Return the entire data object if no data specified
if (!name) {
return readData(elem);
}
// Set the value (with attr map support)
if (typeof name === 'object' || value !== undefined) {
domEach(this, function(i, el) {
setData(el, name, value);
});
return this;
} else if (hasOwn.call(elem.data, name)) {
return elem.data[name];
}
return readData(elem, name);
};
/**
* Get the value of an element
*/
exports.val = function(value) {
var querying = arguments.length === 0,
element = this[0];
if(!element) return;
switch (element.name) {
case 'textarea':
return this.text(value);
case 'input':
switch (this.attr('type')) {
case 'radio':
if (querying) {
return this.attr('value');
} else {
this.attr('value', value);
return this;
}
break;
default:
return this.attr('value', value);
}
return;
case 'select':
var option = this.find('option:selected'),
returnValue;
if (option === undefined) return undefined;
if (!querying) {
if (!this.attr().hasOwnProperty('multiple') && typeof value == 'object') {
return this;
}
if (typeof value != 'object') {
value = [value];
}
this.find('option').removeAttr('selected');
for (var i = 0; i < value.length; i++) {
this.find('option[value="' + value[i] + '"]').attr('selected', '');
}
return this;
}
returnValue = option.attr('value');
if (this.attr().hasOwnProperty('multiple')) {
returnValue = [];
domEach(option, function(i, el) {
returnValue.push(getAttr(el, 'value'));
});
}
return returnValue;
case 'option':
if (!querying) {
this.attr('value', value);
return this;
}
return this.attr('value');
}
};
/**
* Remove an attribute
*/
var removeAttribute = function(elem, name) {
if (!elem.attribs || !hasOwn.call(elem.attribs, name))
return;
delete elem.attribs[name];
};
exports.removeAttr = function(name) {
domEach(this, function(i, elem) {
removeAttribute(elem, name);
});
return this;
};
exports.hasClass = function(className) {
return _.some(this, function(elem) {
var attrs = elem.attribs,
clazz = attrs && attrs['class'],
idx = -1,
end;
if (clazz) {
while ((idx = clazz.indexOf(className, idx+1)) > -1) {
end = idx + className.length;
if ((idx === 0 || rspace.test(clazz[idx-1]))
&& (end === clazz.length || rspace.test(clazz[end]))) {
return true;
}
}
}
});
};
exports.addClass = function(value) {
// Support functions
if (typeof value === 'function') {
return domEach(this, function(i, el) {
var className = el.attribs['class'] || '';
exports.addClass.call([el], value.call(el, i, className));
});
}
// Return if no value or not a string or function
if (!value || typeof value !== 'string') return this;
var classNames = value.split(rspace),
numElements = this.length;
for (var i = 0; i < numElements; i++) {
// If selected element isn't a tag, move on
if (!isTag(this[i])) continue;
// If we don't already have classes
var className = getAttr(this[i], 'class'),
numClasses,
setClass;
if (!className) {
setAttr(this[i], 'class', classNames.join(' ').trim());
} else {
setClass = ' ' + className + ' ';
numClasses = classNames.length;
// Check if class already exists
for (var j = 0; j < numClasses; j++) {
var appendClass = classNames[j] + ' ';
if (setClass.indexOf(' ' + appendClass) < 0)
setClass += appendClass;
}
setAttr(this[i], 'class', setClass.trim());
}
}
return this;
};
var splitClass = function(className) {
return className ? className.trim().split(rspace) : [];
};
exports.removeClass = function(value) {
var classes,
numClasses,
removeAll;
// Handle if value is a function
if (typeof value === 'function') {
return domEach(this, function(i, el) {
exports.removeClass.call(
[el], value.call(el, i, el.attribs['class'] || '')
);
});
}
classes = splitClass(value);
numClasses = classes.length;
removeAll = arguments.length === 0;
return domEach(this, function(i, el) {
if (!isTag(el)) return;
if (removeAll) {
// Short circuit the remove all case as this is the nice one
el.attribs.class = '';
} else {
var elClasses = splitClass(el.attribs.class),
index,
changed;
for (var j = 0; j < numClasses; j++) {
index = elClasses.indexOf(classes[j]);
if (index >= 0) {
elClasses.splice(index, 1);
changed = true;
// We have to do another pass to ensure that there are not duplicate
// classes listed
j--;
}
}
if (changed) {
el.attribs.class = elClasses.join(' ');
}
}
});
};
exports.toggleClass = function(value, stateVal) {
// Support functions
if (typeof value === 'function') {
return domEach(this, function(i, el) {
exports.toggleClass.call(
[el],
value.call(el, i, el.attribs['class'] || '', stateVal),
stateVal
);
});
}
// Return if no value or not a string or function
if (!value || typeof value !== 'string') return this;
var classNames = value.split(rspace),
numClasses = classNames.length,
state = typeof stateVal === 'boolean' ? stateVal ? 1 : -1 : 0,
numElements = this.length,
elementClasses,
index;
for (var i = 0; i < numElements; i++) {
// If selected element isn't a tag, move on
if (!isTag(this[i])) continue;
elementClasses = splitClass(this[i].attribs.class);
// Check if class already exists
for (var j = 0; j < numClasses; j++) {
// Check if the class name is currently defined
index = elementClasses.indexOf(classNames[j]);
// Add if stateValue === true or we are toggling and there is no value
if (state >= 0 && index < 0) {
elementClasses.push(classNames[j]);
} else if (state <= 0 && index >= 0) {
// Otherwise remove but only if the item exists
elementClasses.splice(index, 1);
}
}
this[i].attribs.class = elementClasses.join(' ');
}
return this;
};
exports.is = function (selector) {
if (selector) {
return this.filter(selector).length > 0;
}
return false;
};
var domEach = require('../utils').domEach,
_ = {
pick: require('lodash.pick'),
};
var toString = Object.prototype.toString;
/**
* Set / Get css.
*
* @param {String|Object} prop
* @param {String} val
* @return {self}
* @api public
*/
exports.css = function(prop, val) {
if (arguments.length === 2 ||
// When `prop` is a "plain" object
(toString.call(prop) === '[object Object]')) {
return domEach(this, function(idx, el) {
setCss(el, prop, val, idx);
});
} else {
return getCss(this[0], prop);
}
};
/**
* Set styles of all elements.
*
* @param {String|Object} prop
* @param {String} val
* @param {Number} idx - optional index within the selection
* @return {self}
* @api private
*/
function setCss(el, prop, val, idx) {
if ('string' == typeof prop) {
var styles = getCss(el);
if (typeof val === 'function') {
val = val.call(el, idx, styles[prop]);
}
if (val === '') {
delete styles[prop];
} else if (val != null) {
styles[prop] = val;
}
el.attribs.style = stringify(styles);
} else if ('object' == typeof prop) {
Object.keys(prop).forEach(function(k){
setCss(el, k, prop[k]);
});
}
}
/**
* Get parsed styles of the first element.
*
* @param {String} prop
* @return {Object}
* @api private
*/
function getCss(el, prop) {
var styles = parse(el.attribs.style);
if (typeof prop === 'string') {
return styles[prop];
} else if (Array.isArray(prop)) {
return _.pick(styles, prop);
} else {
return styles;
}
}
/**
* Stringify `obj` to styles.
*
* @param {Object} obj
* @return {Object}
* @api private
*/
function stringify(obj) {
return Object.keys(obj || {})
.reduce(function(str, prop){
return str += ''
+ (str ? ' ' : '')
+ prop
+ ': '
+ obj[prop]
+ ';';
}, '');
}
/**
* Parse `styles`.
*
* @param {String} styles
* @return {Object}
* @api private
*/
function parse(styles) {
styles = (styles || '').trim();
if (!styles) return {};
return styles
.split(';')
.reduce(function(obj, str){
var n = str.indexOf(':');
// skip if there is no :, or if it is the first/last character
if (n < 1 || n === str.length-1) return obj;
obj[str.slice(0,n).trim()] = str.slice(n+1).trim();
return obj;
}, {});
}
// https://github.com/jquery/jquery/blob/2.1.3/src/manipulation/var/rcheckableType.js
// https://github.com/jquery/jquery/blob/2.1.3/src/serialize.js
var submittableSelector = 'input,select,textarea,keygen',
r20 = /%20/g,
rCRLF = /\r?\n/g,
_ = {
map: require('lodash.map')
};
exports.serialize = function() {
// Convert form elements into name/value objects
var arr = this.serializeArray();
// Serialize each element into a key/value string
var retArr = _.map(arr, function(data) {
return encodeURIComponent(data.name) + '=' + encodeURIComponent(data.value);
});
// Return the resulting serialization
return retArr.join('&').replace(r20, '+');
};
exports.serializeArray = function() {
// Resolve all form elements from either forms or collections of form elements
var Cheerio = this.constructor;
return this.map(function() {
var elem = this;
var $elem = Cheerio(elem);
if (elem.name === 'form') {
return $elem.find(submittableSelector).toArray();
} else {
return $elem.filter(submittableSelector).toArray();
}
}).filter(
// Verify elements have a name (`attr.name`) and are not disabled (`:disabled`)
'[name!=""]:not(:disabled)'
// and cannot be clicked (`[type=submit]`) or are used in `x-www-form-urlencoded` (`[type=file]`)
+ ':not(:submit, :button, :image, :reset, :file)'
// and are either checked/don't have a checkable state
+ ':matches([checked], :not(:checkbox, :radio))'
// Convert each of the elements to its value(s)
).map(function(i, elem) {
var $elem = Cheerio(elem);
var name = $elem.attr('name');
var val = $elem.val();
// If there is no value set (e.g. `undefined`, `null`), then return nothing
if (val == null) {
return null;
} else {
// If we have an array of values (e.g. `<select multiple>`), return an array of key/value pairs
if (Array.isArray(val)) {
return _.map(val, function(val) {
// We trim replace any line endings (e.g. `\r` or `\r\n` with `\r\n`) to guarantee consistency across platforms
// These can occur inside of `<textarea>'s`
return {name: name, value: val.replace( rCRLF, '\r\n' )};
});
// Otherwise (e.g. `<input type="text">`, return only one key/value pair
} else {
return {name: name, value: val.replace( rCRLF, '\r\n' )};
}
}
// Convert our result to an array
}).get();
};
var parse = require('../parse'),
$ = require('../static'),
updateDOM = parse.update,
evaluate = parse.evaluate,
utils = require('../utils'),
domEach = utils.domEach,
cloneDom = utils.cloneDom,
isHtml = utils.isHtml,
slice = Array.prototype.slice,
_ = {
flatten: require('lodash.flatten'),
bind: require('lodash.bind'),
forEach: require('lodash.foreach')
};
// Create an array of nodes, recursing into arrays and parsing strings if
// necessary
exports._makeDomArray = function makeDomArray(elem, clone) {
if (elem == null) {
return [];
} else if (elem.cheerio) {
return clone ? cloneDom(elem.get(), elem.options) : elem.get();
} else if (Array.isArray(elem)) {
return _.flatten(elem.map(function(el) {
return this._makeDomArray(el, clone);
}, this));
} else if (typeof elem === 'string') {
return evaluate(elem, this.options);
} else {
return clone ? cloneDom([elem]) : [elem];
}
};
var _insert = function(concatenator) {
return function() {
var elems = slice.call(arguments),
lastIdx = this.length - 1;
return domEach(this, function(i, el) {
var dom, domSrc;
if (typeof elems[0] === 'function') {
domSrc = elems[0].call(el, i, $.html(el.children));
} else {
domSrc = elems;
}
dom = this._makeDomArray(domSrc, i < lastIdx);
concatenator(dom, el.children, el);
});
};
};
/*
* Modify an array in-place, removing some number of elements and adding new
* elements directly following them.
*
* @param {Array} array Target array to splice.
* @param {Number} spliceIdx Index at which to begin changing the array.
* @param {Number} spliceCount Number of elements to remove from the array.
* @param {Array} newElems Elements to insert into the array.
*
* @api private
*/
var uniqueSplice = function(array, spliceIdx, spliceCount, newElems, parent) {
var spliceArgs = [spliceIdx, spliceCount].concat(newElems),
prev = array[spliceIdx - 1] || null,
next = array[spliceIdx] || null;
var idx, len, prevIdx, node, oldParent;
// Before splicing in new elements, ensure they do not already appear in the
// current array.
for (idx = 0, len = newElems.length; idx < len; ++idx) {
node = newElems[idx];
oldParent = node.parent || node.root;
prevIdx = oldParent && oldParent.children.indexOf(newElems[idx]);
if (oldParent && prevIdx > -1) {
oldParent.children.splice(prevIdx, 1);
if (parent === oldParent && spliceIdx > prevIdx) {
spliceArgs[0]--;
}
}
node.root = null;
node.parent = parent;
if (node.prev) {
node.prev.next = node.next || null;
}
if (node.next) {
node.next.prev = node.prev || null;
}
node.prev = newElems[idx - 1] || prev;
node.next = newElems[idx + 1] || next;
}
if (prev) {
prev.next = newElems[0];
}
if (next) {
next.prev = newElems[newElems.length - 1];
}
return array.splice.apply(array, spliceArgs);
};
exports.appendTo = function(target) {
if (!target.cheerio) {
target = this.constructor.call(this.constructor, target, null, this._originalRoot);
}
target.append(this);
return this;
};
exports.prependTo = function(target) {
if (!target.cheerio) {
target = this.constructor.call(this.constructor, target, null, this._originalRoot);
}
target.prepend(this);
return this;
};
exports.append = _insert(function(dom, children, parent) {
uniqueSplice(children, children.length, 0, dom, parent);
});
exports.prepend = _insert(function(dom, children, parent) {
uniqueSplice(children, 0, 0, dom, parent);
});
exports.wrap = function(wrapper) {
var wrapperFn = typeof wrapper === 'function' && wrapper,
lastIdx = this.length - 1;
_.forEach(this, _.bind(function(el, i) {
var parent = el.parent || el.root,
siblings = parent.children,
dom, index;
if (!parent) {
return;
}
if (wrapperFn) {
wrapper = wrapperFn.call(el, i);
}
if (typeof wrapper === 'string' && !isHtml(wrapper)) {
wrapper = this.parents().last().find(wrapper).clone();
}
dom = this._makeDomArray(wrapper, i < lastIdx).slice(0, 1);
index = siblings.indexOf(el);
updateDOM([el], dom[0]);
// The previous operation removed the current element from the `siblings`
// array, so the `dom` array can be inserted without removing any
// additional elements.
uniqueSplice(siblings, index, 0, dom, parent);
}, this));
return this;
};
exports.after = function() {
var elems = slice.call(arguments),
lastIdx = this.length - 1;
domEach(this, function(i, el) {
var parent = el.parent || el.root;
if (!parent) {
return;
}
var siblings = parent.children,
index = siblings.indexOf(el),
domSrc, dom;
// If not found, move on
if (index < 0) return;
if (typeof elems[0] === 'function') {
domSrc = elems[0].call(el, i, $.html(el.children));
} else {
domSrc = elems;
}
dom = this._makeDomArray(domSrc, i < lastIdx);
// Add element after `this` element
uniqueSplice(siblings, index + 1, 0, dom, parent);
});
return this;
};
exports.insertAfter = function(target) {
var clones = [],
self = this;
if (typeof target === 'string') {
target = this.constructor.call(this.constructor, target, null, this._originalRoot);
}
target = this._makeDomArray(target);
self.remove();
domEach(target, function(i, el) {
var clonedSelf = self._makeDomArray(self.clone());
var parent = el.parent || el.root;
if (!parent) {
return;
}
var siblings = parent.children,
index = siblings.indexOf(el);
// If not found, move on
if (index < 0) return;
// Add cloned `this` element(s) after target element
uniqueSplice(siblings, index + 1, 0, clonedSelf, parent);
clones.push(clonedSelf);
});
return this.constructor.call(this.constructor, this._makeDomArray(clones));
};
exports.before = function() {
var elems = slice.call(arguments),
lastIdx = this.length - 1;
domEach(this, function(i, el) {
var parent = el.parent || el.root;
if (!parent) {
return;
}
var siblings = parent.children,
index = siblings.indexOf(el),
domSrc, dom;
// If not found, move on
if (index < 0) return;
if (typeof elems[0] === 'function') {
domSrc = elems[0].call(el, i, $.html(el.children));
} else {
domSrc = elems;
}
dom = this._makeDomArray(domSrc, i < lastIdx);
// Add element before `el` element
uniqueSplice(siblings, index, 0, dom, parent);
});
return this;
};
exports.insertBefore = function(target) {
var clones = [],
self = this;
if (typeof target === 'string') {
target = this.constructor.call(this.constructor, target, null, this._originalRoot);
}
target = this._makeDomArray(target);
self.remove();
domEach(target, function(i, el) {
var clonedSelf = self._makeDomArray(self.clone());
var parent = el.parent || el.root;
if (!parent) {
return;
}
var siblings = parent.children,
index = siblings.indexOf(el);
// If not found, move on
if (index < 0) return;
// Add cloned `this` element(s) after target element
uniqueSplice(siblings, index, 0, clonedSelf, parent);
clones.push(clonedSelf);
});
return this.constructor.call(this.constructor, this._makeDomArray(clones));
};
/*
remove([selector])
*/
exports.remove = function(selector) {
var elems = this;
// Filter if we have selector
if (selector)
elems = elems.filter(selector);
domEach(elems, function(i, el) {
var parent = el.parent || el.root;
if (!parent) {
return;
}
var siblings = parent.children,
index = siblings.indexOf(el);
if (index < 0) return;
siblings.splice(index, 1);
if (el.prev) {
el.prev.next = el.next;
}
if (el.next) {
el.next.prev = el.prev;
}
el.prev = el.next = el.parent = el.root = null;
});
return this;
};
exports.replaceWith = function(content) {
var self = this;
domEach(this, function(i, el) {
var parent = el.parent || el.root;
if (!parent) {
return;
}
var siblings = parent.children,
dom = self._makeDomArray(typeof content === 'function' ? content.call(el, i, el) : content),
index;
// In the case that `dom` contains nodes that already exist in other
// structures, ensure those nodes are properly removed.
updateDOM(dom, null);
index = siblings.indexOf(el);
// Completely remove old element
uniqueSplice(siblings, index, 1, dom, parent);
el.parent = el.prev = el.next = el.root = null;
});
return this;
};
exports.empty = function() {
domEach(this, function(i, el) {
_.forEach(el.children, function(el) {
el.next = el.prev = el.parent = null;
});
el.children.length = 0;
});
return this;
};
/**
* Set/Get the HTML
*/
exports.html = function(str) {
if (str === undefined) {
if (!this[0] || !this[0].children) return null;
return $.html(this[0].children, this.options);
}
var opts = this.options;
domEach(this, function(i, el) {
_.forEach(el.children, function(el) {
el.next = el.prev = el.parent = null;
});
var content = str.cheerio ? str.clone().get() : evaluate('' + str, opts);
updateDOM(content, el);
});
return this;
};
exports.toString = function() {
return $.html(this, this.options);
};
exports.text = function(str) {
// If `str` is undefined, act as a "getter"
if (str === undefined) {
return $.text(this);
} else if (typeof str === 'function') {
// Function support
return domEach(this, function(i, el) {
var $el = [el];
return exports.text.call($el, str.call(el, i, $.text($el)));
});
}
// Append text node to each selected elements
domEach(this, function(i, el) {
_.forEach(el.children, function(el) {
el.next = el.prev = el.parent = null;
});
var elem = {
data: '' + str,
type: 'text',
parent: el,
prev: null,
next: null,
children: []
};
updateDOM(elem, el);
});
return this;
};
exports.clone = function() {
return this._make(cloneDom(this.get(), this.options));
};
var select = require('css-select'),
utils = require('../utils'),
domEach = utils.domEach,
uniqueSort = require('htmlparser2').DomUtils.uniqueSort,
isTag = utils.isTag,
_ = {
bind: require('lodash.bind'),
forEach: require('lodash.foreach'),
reject: require('lodash.reject'),
filter: require('lodash.filter'),
reduce: require('lodash.reduce')
};
exports.find = function(selectorOrHaystack) {
var elems = _.reduce(this, function(memo, elem) {
return memo.concat(_.filter(elem.children, isTag));
}, []);
var contains = this.constructor.contains;
var haystack;
if (selectorOrHaystack && typeof selectorOrHaystack !== 'string') {
if (selectorOrHaystack.cheerio) {
haystack = selectorOrHaystack.get();
} else {
haystack = [selectorOrHaystack];
}
return this._make(haystack.filter(function(elem) {
var idx, len;
for (idx = 0, len = this.length; idx < len; ++idx) {
if (contains(this[idx], elem)) {
return true;
}
}
}, this));
}
var options = {__proto__: this.options, context: this.toArray()};
return this._make(select(selectorOrHaystack, elems, options));
};
// Get the parent of each element in the current set of matched elements,
// optionally filtered by a selector.
exports.parent = function(selector) {
var set = [];
domEach(this, function(idx, elem) {
var parentElem = elem.parent;
if (parentElem && set.indexOf(parentElem) < 0) {
set.push(parentElem);
}
});
if (arguments.length) {
set = exports.filter.call(set, selector, this);
}
return this._make(set);
};
exports.parents = function(selector) {
var parentNodes = [];
// When multiple DOM elements are in the original set, the resulting set will
// be in *reverse* order of the original elements as well, with duplicates
// removed.
this.get().reverse().forEach(function(elem) {
traverseParents(this, elem.parent, selector, Infinity)
.forEach(function(node) {
if (parentNodes.indexOf(node) === -1) {
parentNodes.push(node);
}
}
);
}, this);
return this._make(parentNodes);
};
exports.parentsUntil = function(selector, filter) {
var parentNodes = [], untilNode, untilNodes;
if (typeof selector === 'string') {
untilNode = select(selector, this.parents().toArray(), this.options)[0];
} else if (selector && selector.cheerio) {
untilNodes = selector.toArray();
} else if (selector) {
untilNode = selector;
}
// When multiple DOM elements are in the original set, the resulting set will
// be in *reverse* order of the original elements as well, with duplicates
// removed.
this.toArray().reverse().forEach(function(elem) {
while ((elem = elem.parent)) {
if ((untilNode && elem !== untilNode) ||
(untilNodes && untilNodes.indexOf(elem) === -1) ||
(!untilNode && !untilNodes)) {
if (isTag(elem) && parentNodes.indexOf(elem) === -1) { parentNodes.push(elem); }
} else {
break;
}
}
}, this);
return this._make(filter ? select(filter, parentNodes, this.options) : parentNodes);
};
// For each element in the set, get the first element that matches the selector
// by testing the element itself and traversing up through its ancestors in the
// DOM tree.
exports.closest = function(selector) {
var set = [];
if (!selector) {
return this._make(set);
}
domEach(this, function(idx, elem) {
var closestElem = traverseParents(this, elem, selector, 1)[0];
// Do not add duplicate elements to the set
if (closestElem && set.indexOf(closestElem) < 0) {
set.push(closestElem);
}
}.bind(this));
return this._make(set);
};
exports.next = function(selector) {
if (!this[0]) { return this; }
var elems = [];
_.forEach(this, function(elem) {
while ((elem = elem.next)) {
if (isTag(elem)) {
elems.push(elem);
return;
}
}
});
return selector ?
exports.filter.call(elems, selector, this) :
this._make(elems);
};
exports.nextAll = function(selector) {
if (!this[0]) { return this; }
var elems = [];
_.forEach(this, function(elem) {
while ((elem = elem.next)) {
if (isTag(elem) && elems.indexOf(elem) === -1) {
elems.push(elem);
}
}
});
return selector ?
exports.filter.call(elems, selector, this) :
this._make(elems);
};
exports.nextUntil = function(selector, filterSelector) {
if (!this[0]) { return this; }
var elems = [], untilNode, untilNodes;
if (typeof selector === 'string') {
untilNode = select(selector, this.nextAll().get(), this.options)[0];
} else if (selector && selector.cheerio) {
untilNodes = selector.get();
} else if (selector) {
untilNode = selector;
}
_.forEach(this, function(elem) {
while ((elem = elem.next)) {
if ((untilNode && elem !== untilNode) ||
(untilNodes && untilNodes.indexOf(elem) === -1) ||
(!untilNode && !untilNodes)) {
if (isTag(elem) && elems.indexOf(elem) === -1) {
elems.push(elem);
}
} else {
break;
}
}
});
return filterSelector ?
exports.filter.call(elems, filterSelector, this) :
this._make(elems);
};
exports.prev = function(selector) {
if (!this[0]) { return this; }
var elems = [];
_.forEach(this, function(elem) {
while ((elem = elem.prev)) {
if (isTag(elem)) {
elems.push(elem);
return;
}
}
});
return selector ?
exports.filter.call(elems, selector, this) :
this._make(elems);
};
exports.prevAll = function(selector) {
if (!this[0]) { return this; }
var elems = [];
_.forEach(this, function(elem) {
while ((elem = elem.prev)) {
if (isTag(elem) && elems.indexOf(elem) === -1) {
elems.push(elem);
}
}
});
return selector ?
exports.filter.call(elems, selector, this) :
this._make(elems);
};
exports.prevUntil = function(selector, filterSelector) {
if (!this[0]) { return this; }
var elems = [], untilNode, untilNodes;
if (typeof selector === 'string') {
untilNode = select(selector, this.prevAll().get(), this.options)[0];
} else if (selector && selector.cheerio) {
untilNodes = selector.get();
} else if (selector) {
untilNode = selector;
}
_.forEach(this, function(elem) {
while ((elem = elem.prev)) {
if ((untilNode && elem !== untilNode) ||
(untilNodes && untilNodes.indexOf(elem) === -1) ||
(!untilNode && !untilNodes)) {
if (isTag(elem) && elems.indexOf(elem) === -1) {
elems.push(elem);
}
} else {
break;
}
}
});
return filterSelector ?
exports.filter.call(elems, filterSelector, this) :
this._make(elems);
};
exports.siblings = function(selector) {
var parent = this.parent();
var elems = _.filter(
parent ? parent.children() : this.siblingsAndMe(),
_.bind(function(elem) { return isTag(elem) && !this.is(elem); }, this)
);
if (selector !== undefined) {
return exports.filter.call(elems, selector, this);
} else {
return this._make(elems);
}
};
exports.children = function(selector) {
var elems = _.reduce(this, function(memo, elem) {
return memo.concat(_.filter(elem.children, isTag));
}, []);
if (selector === undefined) return this._make(elems);
return exports.filter.call(elems, selector, this);
};
exports.contents = function() {
return this._make(_.reduce(this, function(all, elem) {
all.push.apply(all, elem.children);
return all;
}, []));
};
exports.each = function(fn) {
var i = 0, len = this.length;
while (i < len && fn.call(this[i], i, this[i]) !== false) ++i;
return this;
};
exports.map = function(fn) {
return this._make(_.reduce(this, function(memo, el, i) {
var val = fn.call(el, i, el);
return val == null ? memo : memo.concat(val);
}, []));
};
var makeFilterMethod = function(filterFn) {
return function(match, container) {
var testFn;
container = container || this;
if (typeof match === 'string') {
testFn = select.compile(match, container.options);
} else if (typeof match === 'function') {
testFn = function(el, i) {
return match.call(el, i, el);
};
} else if (match.cheerio) {
testFn = match.is.bind(match);
} else {
testFn = function(el) {
return match === el;
};
}
return container._make(filterFn(this, testFn));
};
};
exports.filter = makeFilterMethod(_.filter);
exports.not = makeFilterMethod(_.reject);
exports.has = function(selectorOrHaystack) {
var that = this;
return exports.filter.call(this, function() {
return that._make(this).find(selectorOrHaystack).length > 0;
});
};
exports.first = function() {
return this.length > 1 ? this._make(this[0]) : this;
};
exports.last = function() {
return this.length > 1 ? this._make(this[this.length - 1]) : this;
};
// Reduce the set of matched elements to the one at the specified index.
exports.eq = function(i) {
i = +i;
// Use the first identity optimization if possible
if (i === 0 && this.length <= 1) return this;
if (i < 0) i = this.length + i;
return this[i] ? this._make(this[i]) : this._make([]);
};
// Retrieve the DOM elements matched by the jQuery object.
exports.get = function(i) {
if (i == null) {
return Array.prototype.slice.call(this);
} else {
return this[i < 0 ? (this.length + i) : i];
}
};
// Search for a given element from among the matched elements.
exports.index = function(selectorOrNeedle) {
var $haystack, needle;
if (arguments.length === 0) {
$haystack = this.parent().children();
needle = this[0];
} else if (typeof selectorOrNeedle === 'string') {
$haystack = this._make(selectorOrNeedle);
needle = this[0];
} else {
$haystack = this;
needle = selectorOrNeedle.cheerio ? selectorOrNeedle[0] : selectorOrNeedle;
}
return $haystack.get().indexOf(needle);
};
exports.slice = function() {
return this._make([].slice.apply(this, arguments));
};
function traverseParents(self, elem, selector, limit) {
var elems = [];
while (elem && elems.length < limit) {
if (!selector || exports.filter.call([elem], selector, self).length) {
elems.push(elem);
}
elem = elem.parent;
}
return elems;
}
// End the most recent filtering operation in the current chain and return the
// set of matched elements to its previous state.
exports.end = function() {
return this.prevObject || this._make([]);
};
exports.add = function(other, context) {
var selection = this._make(other, context);
var contents = uniqueSort(selection.get().concat(this.get()));
for (var i = 0; i < contents.length; ++i) {
selection[i] = contents[i];
}
selection.length = contents.length;
return selection;
};
// Add the previous set of elements on the stack to the current set, optionally
// filtered by a selector.
exports.addBack = function(selector) {
return this.add(
arguments.length ? this.prevObject.filter(selector) : this.prevObject
);
};
/*
Module dependencies
*/
var parse = require('./parse'),
isHtml = require('./utils').isHtml,
_ = {
extend: require('lodash.assignin'),
bind: require('lodash.bind'),
forEach: require('lodash.foreach'),
defaults: require('lodash.defaults')
};
/*
* The API
*/
var api = [
require('./api/attributes'),
require('./api/traversing'),
require('./api/manipulation'),
require('./api/css'),
require('./api/forms')
];
/*
* Instance of cheerio
*/
var Cheerio = module.exports = function(selector, context, root, options) {
if (!(this instanceof Cheerio)) return new Cheerio(selector, context, root, options);
this.options = _.defaults(options || {}, this.options);
// $(), $(null), $(undefined), $(false)
if (!selector) return this;
if (root) {
if (typeof root === 'string') root = parse(root, this.options);
this._root = Cheerio.call(this, root);
}
// $($)
if (selector.cheerio) return selector;
// $(dom)
if (isNode(selector))
selector = [selector];
// $([dom])
if (Array.isArray(selector)) {
_.forEach(selector, _.bind(function(elem, idx) {
this[idx] = elem;
}, this));
this.length = selector.length;
return this;
}
// $(<html>)
if (typeof selector === 'string' && isHtml(selector)) {
return Cheerio.call(this, parse(selector, this.options).children);
}
// If we don't have a context, maybe we have a root, from loading
if (!context) {
context = this._root;
} else if (typeof context === 'string') {
if (isHtml(context)) {
// $('li', '<ul>...</ul>')
context = parse(context, this.options);
context = Cheerio.call(this, context);
} else {
// $('li', 'ul')
selector = [context, selector].join(' ');
context = this._root;
}
// $('li', node), $('li', [nodes])
} else if (!context.cheerio) {
context = Cheerio.call(this, context);
}
// If we still don't have a context, return
if (!context) return this;
// #id, .class, tag
return context.find(selector);
};
/**
* Mix in `static`
*/
_.extend(Cheerio, require('./static'));
/*
* Set a signature of the object
*/
Cheerio.prototype.cheerio = '[cheerio object]';
/*
* Cheerio default options
*/
Cheerio.prototype.options = {
withDomLvl1: true,
normalizeWhitespace: false,
xmlMode: false,
decodeEntities: true
};
/*
* Make cheerio an array-like object
*/
Cheerio.prototype.length = 0;
Cheerio.prototype.splice = Array.prototype.splice;
/*
* Make a cheerio object
*
* @api private
*/
Cheerio.prototype._make = function(dom, context) {
var cheerio = new this.constructor(dom, context, this._root, this.options);
cheerio.prevObject = this;
return cheerio;
};
/**
* Turn a cheerio object into an array
*/
Cheerio.prototype.toArray = function() {
return this.get();
};
/**
* Plug in the API
*/
api.forEach(function(mod) {
_.extend(Cheerio.prototype, mod);
});
var isNode = function(obj) {
return obj.name || obj.type === 'text' || obj.type === 'comment';
};
/*
Module Dependencies
*/
var htmlparser = require('htmlparser2');
/*
Parser
*/
exports = module.exports = function(content, options) {
var dom = exports.evaluate(content, options),
// Generic root element
root = exports.evaluate('<root></root>', options)[0];
root.type = 'root';
// Update the dom using the root
exports.update(dom, root);
return root;
};
exports.evaluate = function(content, options) {
// options = options || $.fn.options;
var dom;
if (typeof content === 'string' || Buffer.isBuffer(content)) {
dom = htmlparser.parseDOM(content, options);
} else {
dom = content;
}
return dom;
};
/*
Update the dom structure, for one changed layer
*/
exports.update = function(arr, parent) {
// normalize
if (!Array.isArray(arr)) arr = [arr];
// Update parent
if (parent) {
parent.children = arr;
} else {
parent = null;
}
// Update neighbors
for (var i = 0; i < arr.length; i++) {
var node = arr[i];
// Cleanly remove existing nodes from their previous structures.
var oldParent = node.parent || node.root,
oldSiblings = oldParent && oldParent.children;
if (oldSiblings && oldSiblings !== arr) {
oldSiblings.splice(oldSiblings.indexOf(node), 1);
if (node.prev) {
node.prev.next = node.next;
}
if (node.next) {
node.next.prev = node.prev;
}
}
if (parent) {
node.prev = arr[i - 1] || null;
node.next = arr[i + 1] || null;
} else {
node.prev = node.next = null;
}
if (parent && parent.type === 'root') {
node.root = parent;
node.parent = null;
} else {
node.root = null;
node.parent = parent;
}
}
return parent;
};
// module.exports = $.extend(exports);
/**
* Module dependencies
*/
var serialize = require('dom-serializer'),
select = require('css-select'),
parse = require('./parse'),
_ = {
merge: require('lodash.merge'),
defaults: require('lodash.defaults')
};
/**
* $.load(str)
*/
exports.load = function(content, options) {
var Cheerio = require('./cheerio');
options = _.defaults(options || {}, Cheerio.prototype.options);
var root = parse(content, options);
var initialize = function(selector, context, r, opts) {
if (!(this instanceof initialize)) {
return new initialize(selector, context, r, opts);
}
opts = _.defaults(opts || {}, options);
return Cheerio.call(this, selector, context, r || root, opts);
};
// Ensure that selections created by the "loaded" `initialize` function are
// true Cheerio instances.
initialize.prototype = Object.create(Cheerio.prototype);
initialize.prototype.constructor = initialize;
// Mimic jQuery's prototype alias for plugin authors.
initialize.fn = initialize.prototype;
// Keep a reference to the top-level scope so we can chain methods that implicitly
// resolve selectors; e.g. $("<span>").(".bar"), which otherwise loses ._root
initialize.prototype._originalRoot = root;
// Add in the static methods
_.merge(initialize, exports);
// Add in the root
initialize._root = root;
// store options
initialize._options = options;
return initialize;
};
/*
* Helper function
*/
function render(that, dom, options) {
if (!dom) {
if (that._root && that._root.children) {
dom = that._root.children;
} else {
return '';
}
} else if (typeof dom === 'string') {
dom = select(dom, that._root, options);
}
return serialize(dom, options);
}
/**
* $.html([selector | dom], [options])
*/
exports.html = function(dom, options) {
var Cheerio = require('./cheerio');
// be flexible about parameters, sometimes we call html(),
// with options as only parameter
// check dom argument for dom element specific properties
// assume there is no 'length' or 'type' properties in the options object
if (Object.prototype.toString.call(dom) === '[object Object]' && !options && !('length' in dom) && !('type' in dom))
{
options = dom;
dom = undefined;
}
// sometimes $.html() used without preloading html
// so fallback non existing options to the default ones
options = _.defaults(options || {}, this._options, Cheerio.prototype.options);
return render(this, dom, options);
};
/**
* $.xml([selector | dom])
*/
exports.xml = function(dom) {
var options = _.defaults({xmlMode: true}, this._options);
return render(this, dom, options);
};
/**
* $.text(dom)
*/
exports.text = function(elems) {
if (!elems) {
elems = this.root();
}
var ret = '',
len = elems.length,
elem;
for (var i = 0; i < len; i++) {
elem = elems[i];
if (elem.type === 'text') ret += elem.data;
else if (elem.children && elem.type !== 'comment') {
ret += exports.text(elem.children);
}
}
return ret;
};
/**
* $.parseHTML(data [, context ] [, keepScripts ])
* Parses a string into an array of DOM nodes. The `context` argument has no
* meaning for Cheerio, but it is maintained for API compatibility with jQuery.
*/
exports.parseHTML = function(data, context, keepScripts) {
var parsed;
if (!data || typeof data !== 'string') {
return null;
}
if (typeof context === 'boolean') {
keepScripts = context;
}
parsed = this.load(data);
if (!keepScripts) {
parsed('script').remove();
}
// The `children` array is used by Cheerio internally to group elements that
// share the same parents. When nodes created through `parseHTML` are
// inserted into previously-existing DOM structures, they will be removed
// from the `children` array. The results of `parseHTML` should remain
// constant across these operations, so a shallow copy should be returned.
return parsed.root()[0].children.slice();
};
/**
* $.root()
*/
exports.root = function() {
return this(this._root);
};
/**
* $.contains()
*/
exports.contains = function(container, contained) {
// According to the jQuery API, an element does not "contain" itself
if (contained === container) {
return false;
}
// Step up the descendants, stopping when the root element is reached
// (signaled by `.parent` returning a reference to the same object)
while (contained && contained !== contained.parent) {
contained = contained.parent;
if (contained === container) {
return true;
}
}
return false;
};
var parse = require('./parse'),
render = require('dom-serializer');
/**
* HTML Tags
*/
var tags = { tag: true, script: true, style: true };
/**
* Check if the DOM element is a tag
*
* isTag(type) includes <script> and <style> tags
*/
exports.isTag = function(type) {
if (type.type) type = type.type;
return tags[type] || false;
};
/**
* Convert a string to camel case notation.
* @param {String} str String to be converted.
* @return {String} String in camel case notation.
*/
exports.camelCase = function(str) {
return str.replace(/[_.-](\w|$)/g, function(_, x) {
return x.toUpperCase();
});
};
/**
* Convert a string from camel case to "CSS case", where word boundaries are
* described by hyphens ("-") and all characters are lower-case.
* @param {String} str String to be converted.
* @return {string} String in "CSS case".
*/
exports.cssCase = function(str) {
return str.replace(/[A-Z]/g, '-$&').toLowerCase();
};
/**
* Iterate over each DOM element without creating intermediary Cheerio instances.
*
* This is indented for use internally to avoid otherwise unnecessary memory pressure introduced
* by _make.
*/
exports.domEach = function(cheerio, fn) {
var i = 0, len = cheerio.length;
while (i < len && fn.call(cheerio, i, cheerio[i]) !== false) ++i;
return cheerio;
};
/**
* Create a deep copy of the given DOM structure by first rendering it to a
* string and then parsing the resultant markup.
*
* @argument {Object} dom - The htmlparser2-compliant DOM structure
* @argument {Object} options - The parsing/rendering options
*/
exports.cloneDom = function(dom, options) {
return parse(render(dom, options), options).children;
};
/*
* A simple way to check for HTML strings or ID strings
*/
var quickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/;
/*
* Check if string is HTML
*/
exports.isHtml = function(str) {
// Faster than running regex, if str starts with `<` and ends with `>`, assume it's HTML
if (str.charAt(0) === '<' && str.charAt(str.length - 1) === '>' && str.length >= 3) return true;
// Run the regex
var match = quickExpr.exec(str);
return !!(match && match[1]);
};
{
"_args": [
[
{
"raw": "cheerio",
"scope": null,
"escapedName": "cheerio",
"name": "cheerio",
"rawSpec": "",
"spec": "latest",
"type": "tag"
},
"F:\\piweb\\web scraping\\test\\crawlerByTimos"
]
],
"_from": "cheerio@latest",
"_id": "cheerio@0.22.0",
"_inCache": true,
"_location": "/cheerio",
"_nodeVersion": "6.2.2",
"_npmOperationalInternal": {
"host": "packages-12-west.internal.npmjs.com",
"tmp": "tmp/cheerio-0.22.0.tgz_1471954900169_0.12557715992443264"
},
"_npmUser": {
"name": "mattmueller",
"email": "mattmuelle@gmail.com"
},
"_npmVersion": "3.10.6",
"_phantomChildren": {},
"_requested": {
"raw": "cheerio",
"scope": null,
"escapedName": "cheerio",
"name": "cheerio",
"rawSpec": "",
"spec": "latest",
"type": "tag"
},
"_requiredBy": [
"#USER",
"/"
],
"_resolved": "https://registry.npmjs.org/cheerio/-/cheerio-0.22.0.tgz",
"_shasum": "a9baa860a3f9b595a6b81b1a86873121ed3a269e",
"_shrinkwrap": null,
"_spec": "cheerio",
"_where": "F:\\piweb\\web scraping\\test\\crawlerByTimos",
"author": {
"name": "Matt Mueller",
"email": "mattmuelle@gmail.com",
"url": "mat.io"
},
"bugs": {
"url": "https://github.com/cheeriojs/cheerio/issues"
},
"dependencies": {
"css-select": "~1.2.0",
"dom-serializer": "~0.1.0",
"entities": "~1.1.1",
"htmlparser2": "^3.9.1",
"lodash.assignin": "^4.0.9",
"lodash.bind": "^4.1.4",
"lodash.defaults": "^4.0.1",
"lodash.filter": "^4.4.0",
"lodash.flatten": "^4.2.0",
"lodash.foreach": "^4.3.0",
"lodash.map": "^4.4.0",
"lodash.merge": "^4.4.0",
"lodash.pick": "^4.2.1",
"lodash.reduce": "^4.4.0",
"lodash.reject": "^4.4.0",
"lodash.some": "^4.4.0"
},
"description": "Tiny, fast, and elegant implementation of core jQuery designed specifically for the server",
"devDependencies": {
"benchmark": "^2.1.0",
"coveralls": "^2.11.9",
"expect.js": "~0.3.1",
"istanbul": "^0.4.3",
"jquery": "^3.0.0",
"jsdom": "^9.2.1",
"jshint": "^2.9.2",
"mocha": "^2.5.3",
"xyz": "~0.5.0"
},
"directories": {},
"dist": {
"shasum": "a9baa860a3f9b595a6b81b1a86873121ed3a269e",
"tarball": "https://registry.npmjs.org/cheerio/-/cheerio-0.22.0.tgz"
},
"engines": {
"node": ">= 0.6"
},
"files": [
"index.js",
"lib"
],
"gitHead": "35c4917205dca9d08139c95419e2626c0689e38a",
"homepage": "https://github.com/cheeriojs/cheerio#readme",
"keywords": [
"htmlparser",
"jquery",
"selector",
"scraper",
"parser",
"html"
],
"license": "MIT",
"main": "./index.js",
"maintainers": [
{
"name": "mattmueller",
"email": "mattmuelle@gmail.com"
},
{
"name": "davidchambers",
"email": "dc@davidchambers.me"
},
{
"name": "jugglinmike",
"email": "mike@mikepennisi.com"
},
{
"name": "feedic",
"email": "me@feedic.com"
}
],
"name": "cheerio",
"optionalDependencies": {},
"readme": "ERROR: No README data found!",
"repository": {
"type": "git",
"url": "git://github.com/cheeriojs/cheerio.git"
},
"scripts": {
"test": "make test"
},
"version": "0.22.0"
}

cheerio

Fast, flexible & lean implementation of core jQuery designed specifically for the server.

let cheerio = require('cheerio')
let $ = cheerio.load('<h2 class="title">Hello world</h2>')

$('h2.title').text('Hello there!')
$('h2').addClass('welcome')

$.html()
//=> <h2 class="title welcome">Hello there!</h2>

Installation

npm install cheerio

Features

❤ Familiar syntax: Cheerio implements a subset of core jQuery. Cheerio removes all the DOM inconsistencies and browser cruft from the jQuery library, revealing its truly gorgeous API.

ϟ Blazingly fast: Cheerio works with a very simple, consistent DOM model. As a result parsing, manipulating, and rendering are incredibly efficient. Preliminary end-to-end benchmarks suggest that cheerio is about 8x faster than JSDOM.

❁ Incredibly flexible: Cheerio wraps around @FB55's forgiving htmlparser2. Cheerio can parse nearly any HTML or XML document.

Sponsors

Does your company use Cheerio in production? Please consider sponsoring this project. Your help will allow maintainers to dedicate more time and resources to its development and support.

Backers

Become a backer to show your support for Cheerio and help us maintain and improve this open source project.

API

Markup example we'll be using:

<ul id="fruits">
  <li class="apple">Apple</li>
  <li class="orange">Orange</li>
  <li class="pear">Pear</li>
</ul>

This is the HTML markup we will be using in all of the API examples.

Loading

First you need to load in the HTML. This step in jQuery is implicit, since jQuery operates on the one, baked-in DOM. With Cheerio, we need to pass in the HTML document.

This is the preferred method:

var cheerio = require('cheerio'),
    $ = cheerio.load('<ul id="fruits">...</ul>');

Optionally, you can also load in the HTML by passing the string as the context:

$ = require('cheerio');
$('ul', '<ul id="fruits">...</ul>');

Or as the root:

$ = require('cheerio');
$('li', 'ul', '<ul id="fruits">...</ul>');

You can also pass an extra object to .load() if you need to modify any of the default parsing options:

$ = cheerio.load('<ul id="fruits">...</ul>', {
    normalizeWhitespace: true,
    xmlMode: true
});

These parsing options are taken directly from htmlparser2, therefore any options that can be used in htmlparser2 are valid in cheerio as well. The default options are:

{
    withDomLvl1: true,
    normalizeWhitespace: false,
    xmlMode: false,
    decodeEntities: true
}

For a full list of options and their effects, see this and htmlparser2's options.

Selectors

Cheerio's selector implementation is nearly identical to jQuery's, so the API is very similar.

$( selector, [context], [root] )

selector searches within the context scope which searches within the root scope. selector and context can be a string expression, DOM Element, array of DOM elements, or cheerio object. root is typically the HTML document string.

This selector method is the starting point for traversing and manipulating the document. Like jQuery, it's the primary method for selecting elements in the document, but unlike jQuery it's built on top of the CSSSelect library, which implements most of the Sizzle selectors.

$('.apple', '#fruits').text()
//=> Apple

$('ul .pear').attr('class')
//=> pear

$('li[class=orange]').html()
//=> Orange

Attributes

Methods for getting and modifying attributes.

.attr( name, value )

Method for getting and setting attributes. Gets the attribute value for only the first element in the matched set. If you set an attribute's value to null, you remove that attribute. You may also pass a map and function like jQuery.

$('ul').attr('id')
//=> fruits

$('.apple').attr('id', 'favorite').html()
//=> <li class="apple" id="favorite">Apple</li>

See http://api.jquery.com/attr/ for more information

.prop( name, value )

Method for getting and setting properties. Gets the property value for only the first element in the matched set.

$('input[type="checkbox"]').prop('checked')
//=> false

$('input[type="checkbox"]').prop('checked', true).val()
//=> ok

See http://api.jquery.com/prop/ for more information

.data( name, value )

Method for getting and setting data attributes. Gets or sets the data attribute value for only the first element in the matched set.

$('<div data-apple-color="red"></div>').data()
//=> { appleColor: 'red' }

$('<div data-apple-color="red"></div>').data('apple-color')
//=> 'red'

var apple = $('.apple').data('kind', 'mac')
apple.data('kind')
//=> 'mac'

See http://api.jquery.com/data/ for more information

.val( [value] )

Method for getting and setting the value of input, select, and textarea. Note: Support for map, and function has not been added yet.

$('input[type="text"]').val()
//=> input_text

$('input[type="text"]').val('test').html()
//=> <input type="text" value="test"/>

.removeAttr( name )

Method for removing attributes by name.

$('.pear').removeAttr('class').html()
//=> <li>Pear</li>

.hasClass( className )

Check to see if any of the matched elements have the given className.

$('.pear').hasClass('pear')
//=> true

$('apple').hasClass('fruit')
//=> false

$('li').hasClass('pear')
//=> true

.addClass( className )

Adds class(es) to all of the matched elements. Also accepts a function like jQuery.

$('.pear').addClass('fruit').html()
//=> <li class="pear fruit">Pear</li>

$('.apple').addClass('fruit red').html()
//=> <li class="apple fruit red">Apple</li>

See http://api.jquery.com/addClass/ for more information.

.removeClass( [className] )

Removes one or more space-separated classes from the selected elements. If no className is defined, all classes will be removed. Also accepts a function like jQuery.

$('.pear').removeClass('pear').html()
//=> <li class="">Pear</li>

$('.apple').addClass('red').removeClass().html()
//=> <li class="">Apple</li>

See http://api.jquery.com/removeClass/ for more information.

.toggleClass( className, [switch] )

Add or remove class(es) from the matched elements, depending on either the class's presence or the value of the switch argument. Also accepts a function like jQuery.

$('.apple.green').toggleClass('fruit green red').html()
//=> <li class="apple fruit red">Apple</li>

$('.apple.green').toggleClass('fruit green red', true).html()
//=> <li class="apple green fruit red">Apple</li>

See http://api.jquery.com/toggleClass/ for more information.

.is( selector )

.is( element )

.is( selection )

.is( function(index) )

Checks the current list of elements and returns true if any of the elements match the selector. If using an element or Cheerio selection, returns true if any of the elements match. If using a predicate function, the function is executed in the context of the selected element, so this refers to the current element.

Forms

.serializeArray()

Encode a set of form elements as an array of names and values.

$('<form><input name="foo" value="bar" /></form>').serializeArray()
//=> [ { name: 'foo', value: 'bar' } ]

Traversing

.find(selector)

.find(selection)

.find(node)

Get the descendants of each element in the current set of matched elements, filtered by a selector, jQuery object, or element.

$('#fruits').find('li').length
//=> 3
$('#fruits').find($('.apple')).length
//=> 1

.parent([selector])

Get the parent of each element in the current set of matched elements, optionally filtered by a selector.

$('.pear').parent().attr('id')
//=> fruits

.parents([selector])

Get a set of parents filtered by selector of each element in the current set of match elements.

$('.orange').parents().length
// => 2
$('.orange').parents('#fruits').length
// => 1

.parentsUntil([selector][,filter])

Get the ancestors of each element in the current set of matched elements, up to but not including the element matched by the selector, DOM node, or cheerio object.

$('.orange').parentsUntil('#food').length
// => 1

.closest(selector)

For each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree.

$('.orange').closest()
// => []
$('.orange').closest('.apple')
// => []
$('.orange').closest('li')
// => [<li class="orange">Orange</li>]
$('.orange').closest('#fruits')
// => [<ul id="fruits"> ... </ul>]

.next([selector])

Gets the next sibling of the first selected element, optionally filtered by a selector.

$('.apple').next().hasClass('orange')
//=> true

.nextAll([selector])

Gets all the following siblings of the first selected element, optionally filtered by a selector.

$('.apple').nextAll()
//=> [<li class="orange">Orange</li>, <li class="pear">Pear</li>]
$('.apple').nextAll('.orange')
//=> [<li class="orange">Orange</li>]

.nextUntil([selector], [filter])

Gets all the following siblings up to but not including the element matched by the selector, optionally filtered by another selector.

$('.apple').nextUntil('.pear')
//=> [<li class="orange">Orange</li>]

.prev([selector])

Gets the previous sibling of the first selected element optionally filtered by a selector.

$('.orange').prev().hasClass('apple')
//=> true

.prevAll([selector])

Gets all the preceding siblings of the first selected element, optionally filtered by a selector.

$('.pear').prevAll()
//=> [<li class="orange">Orange</li>, <li class="apple">Apple</li>]
$('.pear').prevAll('.orange')
//=> [<li class="orange">Orange</li>]

.prevUntil([selector], [filter])

Gets all the preceding siblings up to but not including the element matched by the selector, optionally filtered by another selector.

$('.pear').prevUntil('.apple')
//=> [<li class="orange">Orange</li>]

.slice( start, [end] )

Gets the elements matching the specified range

$('li').slice(1).eq(0).text()
//=> 'Orange'

$('li').slice(1, 2).length
//=> 1

.siblings([selector])

Gets the first selected element's siblings, excluding itself.

$('.pear').siblings().length
//=> 2

$('.pear').siblings('.orange').length
//=> 1

.children([selector])

Gets the children of the first selected element.

$('#fruits').children().length
//=> 3

$('#fruits').children('.pear').text()
//=> Pear

.contents()

Gets the children of each element in the set of matched elements, including text and comment nodes.

$('#fruits').contents().length
//=> 3

.each( function(index, element) )

Iterates over a cheerio object, executing a function for each matched element. When the callback is fired, the function is fired in the context of the DOM element, so this refers to the current element, which is equivalent to the function parameter element. To break out of the each loop early, return with false.

var fruits = [];

$('li').each(function(i, elem) {
  fruits[i] = $(this).text();
});

fruits.join(', ');
//=> Apple, Orange, Pear

.map( function(index, element) )

Pass each element in the current matched set through a function, producing a new Cheerio object containing the return values. The function can return an individual data item or an array of data items to be inserted into the resulting set. If an array is returned, the elements inside the array are inserted into the set. If the function returns null or undefined, no element will be inserted.

$('li').map(function(i, el) {
  // this === el
  return $(this).text();
}).get().join(' ');
//=> "apple orange pear"

.filter( selector )
.filter( selection )
.filter( element )
.filter( function(index) )

Iterates over a cheerio object, reducing the set of selector elements to those that match the selector or pass the function's test. When a Cheerio selection is specified, return only the elements contained in that selection. When an element is specified, return only that element (if it is contained in the original selection). If using the function method, the function is executed in the context of the selected element, so this refers to the current element.

Selector:

$('li').filter('.orange').attr('class');
//=> orange

Function:

$('li').filter(function(i, el) {
  // this === el
  return $(this).attr('class') === 'orange';
}).attr('class')
//=> orange

.not( selector )
.not( selection )
.not( element )
.not( function(index, elem) )

Remove elements from the set of matched elements. Given a jQuery object that represents a set of DOM elements, the .not() method constructs a new jQuery object from a subset of the matching elements. The supplied selector is tested against each element; the elements that don't match the selector will be included in the result. The .not() method can take a function as its argument in the same way that .filter() does. Elements for which the function returns true are excluded from the filtered set; all other elements are included.

Selector:

$('li').not('.apple').length;
//=> 2

Function:

$('li').not(function(i, el) {
  // this === el
  return $(this).attr('class') === 'orange';
}).length;
//=> 2

.has( selector )
.has( element )

Filters the set of matched elements to only those which have the given DOM element as a descendant or which have a descendant that matches the given selector. Equivalent to .filter(':has(selector)').

Selector:

$('ul').has('.pear').attr('id');
//=> fruits

Element:

$('ul').has($('.pear')[0]).attr('id');
//=> fruits

.first()

Will select the first element of a cheerio object

$('#fruits').children().first().text()
//=> Apple

.last()

Will select the last element of a cheerio object

$('#fruits').children().last().text()
//=> Pear

.eq( i )

Reduce the set of matched elements to the one at the specified index. Use .eq(-i) to count backwards from the last selected element.

$('li').eq(0).text()
//=> Apple

$('li').eq(-1).text()
//=> Pear

.get( [i] )

Retrieve the DOM elements matched by the Cheerio object. If an index is specified, retrieve one of the elements matched by the Cheerio object:

$('li').get(0).tagName
//=> li

If no index is specified, retrieve all elements matched by the Cheerio object:

$('li').get().length
//=> 3

.index()

.index( selector )

.index( nodeOrSelection )

Search for a given element from among the matched elements.

$('.pear').index()
//=> 2
$('.orange').index('li')
//=> 1
$('.apple').index($('#fruit, li'))
//=> 1

.end()

End the most recent filtering operation in the current chain and return the set of matched elements to its previous state.

$('li').eq(0).end().length
//=> 3

.add( selector [, context] )

.add( element )

.add( elements )

.add( html )

.add( selection )

Add elements to the set of matched elements.

$('.apple').add('.orange').length
//=> 2

.addBack( [filter] )

Add the previous set of elements on the stack to the current set, optionally filtered by a selector.

$('li').eq(0).addBack('.orange').length
//=> 2

Manipulation

Methods for modifying the DOM structure.

.append( content, [content, ...] )

Inserts content as the last child of each of the selected elements.

$('ul').append('<li class="plum">Plum</li>')
$.html()
//=>  <ul id="fruits">
//      <li class="apple">Apple</li>
//      <li class="orange">Orange</li>
//      <li class="pear">Pear</li>
//      <li class="plum">Plum</li>
//    </ul>

.appendTo( target )

Insert every element in the set of matched elements to the end of the target.

$('<li class="plum">Plum</li>').appendTo('#fruits')
$.html()
//=>  <ul id="fruits">
//      <li class="apple">Apple</li>
//      <li class="orange">Orange</li>
//      <li class="pear">Pear</li>
//      <li class="plum">Plum</li>
//    </ul>

.prepend( content, [content, ...] )

Inserts content as the first child of each of the selected elements.

$('ul').prepend('<li class="plum">Plum</li>')
$.html()
//=>  <ul id="fruits">
//      <li class="plum">Plum</li>
//      <li class="apple">Apple</li>
//      <li class="orange">Orange</li>
//      <li class="pear">Pear</li>
//    </ul>

.prependTo( target )

Insert every element in the set of matched elements to the beginning of the target.

$('<li class="plum">Plum</li>').prependTo('#fruits')
$.html()
//=>  <ul id="fruits">
//      <li class="plum">Plum</li>
//      <li class="apple">Apple</li>
//      <li class="orange">Orange</li>
//      <li class="pear">Pear</li>
//    </ul>

.after( content, [content, ...] )

Insert content next to each element in the set of matched elements.

$('.apple').after('<li class="plum">Plum</li>')
$.html()
//=>  <ul id="fruits">
//      <li class="apple">Apple</li>
//      <li class="plum">Plum</li>
//      <li class="orange">Orange</li>
//      <li class="pear">Pear</li>
//    </ul>

.insertAfter( target )

Insert every element in the set of matched elements after the target.

$('<li class="plum">Plum</li>').insertAfter('.apple')
$.html()
//=>  <ul id="fruits">
//      <li class="apple">Apple</li>
//      <li class="plum">Plum</li>
//      <li class="orange">Orange</li>
//      <li class="pear">Pear</li>
//    </ul>

.before( content, [content, ...] )

Insert content previous to each element in the set of matched elements.

$('.apple').before('<li class="plum">Plum</li>')
$.html()
//=>  <ul id="fruits">
//      <li class="plum">Plum</li>
//      <li class="apple">Apple</li>
//      <li class="orange">Orange</li>
//      <li class="pear">Pear</li>
//    </ul>

.insertBefore( target )

Insert every element in the set of matched elements before the target.

$('<li class="plum">Plum</li>').insertBefore('.apple')
$.html()
//=>  <ul id="fruits">
//      <li class="plum">Plum</li>
//      <li class="apple">Apple</li>
//      <li class="orange">Orange</li>
//      <li class="pear">Pear</li>
//    </ul>

.remove( [selector] )

Removes the set of matched elements from the DOM and all their children. selector filters the set of matched elements to be removed.

$('.pear').remove()
$.html()
//=>  <ul id="fruits">
//      <li class="apple">Apple</li>
//      <li class="orange">Orange</li>
//    </ul>

.replaceWith( content )

Replaces matched elements with content.

var plum = $('<li class="plum">Plum</li>')
$('.pear').replaceWith(plum)
$.html()
//=> <ul id="fruits">
//     <li class="apple">Apple</li>
//     <li class="orange">Orange</li>
//     <li class="plum">Plum</li>
//   </ul>

.empty()

Empties an element, removing all its children.

$('ul').empty()
$.html()
//=>  <ul id="fruits"></ul>

.html( [htmlString] )

Gets an html content string from the first selected element. If htmlString is specified, each selected element's content is replaced by the new content.

$('.orange').html()
//=> Orange

$('#fruits').html('<li class="mango">Mango</li>').html()
//=> <li class="mango">Mango</li>

.text( [textString] )

Get the combined text contents of each element in the set of matched elements, including their descendants.. If textString is specified, each selected element's content is replaced by the new text content.

$('.orange').text()
//=> Orange

$('ul').text()
//=>  Apple
//    Orange
//    Pear

.wrap( content )

The .wrap() function can take any string or object that could be passed to the $() factory function to specify a DOM structure. This structure may be nested several levels deep, but should contain only one inmost element. A copy of this structure will be wrapped around each of the elements in the set of matched elements. This method returns the original set of elements for chaining purposes.

var redFruit = $('<div class="red-fruit"></div>')
$('.apple').wrap(redFruit)

//=> <ul id="fruits">
//     <div class="red-fruit">
//      <li class="apple">Apple</li>
//     </div>
//     <li class="orange">Orange</li>
//     <li class="plum">Plum</li>
//   </ul>

var healthy = $('<div class="healthy"></div>')
$('li').wrap(healthy)

//=> <ul id="fruits">
//     <div class="healthy">
//       <li class="apple">Apple</li>
//     </div>
//     <div class="healthy">
//       <li class="orange">Orange</li>
//     </div>
//     <div class="healthy">
//        <li class="plum">Plum</li>
//     </div>
//   </ul>

.css( [propertName] )
.css( [ propertyNames] )
.css( [propertyName], [value] )
.css( [propertName], [function] )
.css( [properties] )

Get the value of a style property for the first element in the set of matched elements or set one or more CSS properties for every matched element.

Rendering

When you're ready to render the document, you can use the html utility function:

$.html()
//=>  <ul id="fruits">
//      <li class="apple">Apple</li>
//      <li class="orange">Orange</li>
//      <li class="pear">Pear</li>
//    </ul>

If you want to return the outerHTML you can use $.html(selector):

$.html('.pear')
//=> <li class="pear">Pear</li>

By default, html will leave some tags open. Sometimes you may instead want to render a valid XML document. For example, you might parse the following XML snippet:

$ = cheerio.load('<media:thumbnail url="http://www.foo.com/keyframe.jpg" width="75" height="50" time="12:05:01.123"/>');

... and later want to render to XML. To do this, you can use the 'xml' utility function:

$.xml()
//=>  <media:thumbnail url="http://www.foo.com/keyframe.jpg" width="75" height="50" time="12:05:01.123"/>

You may also render the text content of a Cheerio object using the text static method:

$ = cheerio.load('This is <em>content</em>.')
$.text()
//=> This is content.

The method may be called on the Cheerio module itself--be sure to pass a collection of nodes!

$ = cheerio.load('<div>This is <em>content</em>.</div>')
cheerio.text($('div'))
//=> This is content.

Miscellaneous

DOM element methods that don't fit anywhere else

.toArray()

Retrieve all the DOM elements contained in the jQuery set as an array.

$('li').toArray()
//=> [ {...}, {...}, {...} ]

.clone()

Clone the cheerio object.

var moreFruit = $('#fruits').clone()

Utilities

$.root

Sometimes you need to work with the top-level root element. To query it, you can use $.root().

$.root().append('<ul id="vegetables"></ul>').html();
//=> <ul id="fruits">...</ul><ul id="vegetables"></ul>

$.contains( container, contained )

Checks to see if the contained DOM element is a descendant of the container DOM element.

$.parseHTML( data [, context ] [, keepScripts ] )

Parses a string into an array of DOM nodes. The context argument has no meaning for Cheerio, but it is maintained for API compatability.

$.load( html[, options ] )

Load in the HTML. (See the previous section titled "Loading" for more information.)

Plugins

Once you have loaded a document, you may extend the prototype or the equivalent fn property with custom plugin methods:

var $ = cheerio.load('<html><body>Hello, <b>world</b>!</body></html>');
$.prototype.logHtml = function() {
  console.log(this.html());
};

$('body').logHtml(); // logs "Hello, <b>world</b>!" to the console

The "DOM Node" object

Cheerio collections are made up of objects that bear some resemblence to browser-based DOM nodes. You can expect them to define the following properties:

  • tagName
  • parentNode
  • previousSibling
  • nextSibling
  • nodeValue
  • firstChild
  • childNodes
  • lastChild

What about JSDOM?

I wrote cheerio because I found myself increasingly frustrated with JSDOM. For me, there were three main sticking points that I kept running into again and again:

• JSDOM's built-in parser is too strict: JSDOM's bundled HTML parser cannot handle many popular sites out there today.

• JSDOM is too slow: Parsing big websites with JSDOM has a noticeable delay.

• JSDOM feels too heavy: The goal of JSDOM is to provide an identical DOM environment as what we see in the browser. I never really needed all this, I just wanted a simple, familiar way to do HTML manipulation.

When I would use JSDOM

Cheerio will not solve all your problems. I would still use JSDOM if I needed to work in a browser-like environment on the server, particularly if I wanted to automate functional tests.

Screencasts

http://vimeo.com/31950192

This video tutorial is a follow-up to Nettut's "How to Scrape Web Pages with Node.js and jQuery", using cheerio instead of JSDOM + jQuery. This video shows how easy it is to use cheerio and how much faster cheerio is than JSDOM + jQuery.

Contributors

These are some of the contributors that have made cheerio possible:

project  : cheerio
 repo age : 2 years, 6 months
 active   : 285 days
 commits  : 762
 files    : 36
 authors  :
   293  Matt Mueller            38.5%
   133  Matthew Mueller         17.5%
    92  Mike Pennisi            12.1%
    54  David Chambers          7.1%
    30  kpdecker                3.9%
    19  Felix Böhm             2.5%
    17  fb55                    2.2%
    15  Siddharth Mahendraker   2.0%
    11  Adam Bretz              1.4%
     8  Nazar Leush             1.0%
     7  ironchefpython          0.9%
     6  Jarno Leppänen         0.8%
     5  Ben Sheldon             0.7%
     5  Jos Shepherd            0.7%
     5  Ryan Schmukler          0.7%
     5  Steven Vachon           0.7%
     4  Maciej Adwent           0.5%
     4  Amir Abu Shareb         0.5%
     3  jeremy.dentel@brandingbrand.com 0.4%
     3  Andi Neck               0.4%
     2  steve                   0.3%
     2  alexbardas              0.3%
     2  finspin                 0.3%
     2  Ali Farhadi             0.3%
     2  Chris Khoo              0.3%
     2  Rob Ashton              0.3%
     2  Thomas Heymann          0.3%
     2  Jaro Spisak             0.3%
     2  Dan Dascalescu          0.3%
     2  Torstein Thune          0.3%
     2  Wayne Larsen            0.3%
     1  Timm Preetz             0.1%
     1  Xavi                    0.1%
     1  Alex Shaindlin          0.1%
     1  mattym                  0.1%
     1  Felix Böhm            0.1%
     1  Farid Neshat            0.1%
     1  Dmitry Mazuro           0.1%
     1  Jeremy Hubble           0.1%
     1  nevermind               0.1%
     1  Manuel Alabor           0.1%
     1  Matt Liegey             0.1%
     1  Chris O'Hara            0.1%
     1  Michael Holroyd         0.1%
     1  Michiel De Mey          0.1%
     1  Ben Atkin               0.1%
     1  Rich Trott              0.1%
     1  Rob "Hurricane" Ashton  0.1%
     1  Robin Gloster           0.1%
     1  Simon Boudrias          0.1%
     1  Sindre Sorhus           0.1%
     1  xiaohwan                0.1%

Cheerio in the real world

Are you using cheerio in production? Add it to the wiki!

Testing

To run the test suite, download the repository, then within the cheerio directory, run:

make setup
make test

This will download the development packages and run the test suite.

Special Thanks

This library stands on the shoulders of some incredible developers. A special thanks to:

• @FB55 for node-htmlparser2 & CSSSelect: Felix has a knack for writing speedy parsing engines. He completely re-wrote both @tautologistic's node-htmlparser and @harry's node-soupselect from the ground up, making both of them much faster and more flexible. Cheerio would not be possible without his foundational work

• @jQuery team for jQuery: The core API is the best of its class and despite dealing with all the browser inconsistencies the code base is extremely clean and easy to follow. Much of cheerio's implementation and documentation is from jQuery. Thanks guys.

• @visionmedia: The style, the structure, the open-source"-ness" of this library comes from studying TJ's style and using many of his libraries. This dude consistently pumps out high-quality libraries and has always been more than willing to help or answer questions. You rock TJ.

License

MIT

var util = require('util');
var Stream = require('stream').Stream;
var DelayedStream = require('delayed-stream');
module.exports = CombinedStream;
function CombinedStream() {
this.writable = false;
this.readable = true;
this.dataSize = 0;
this.maxDataSize = 2 * 1024 * 1024;
this.pauseStreams = true;
this._released = false;
this._streams = [];
this._currentStream = null;
}
util.inherits(CombinedStream, Stream);
CombinedStream.create = function(options) {
var combinedStream = new this();
options = options || {};
for (var option in options) {
combinedStream[option] = options[option];
}
return combinedStream;
};
CombinedStream.isStreamLike = function(stream) {
return (typeof stream !== 'function')
&& (typeof stream !== 'string')
&& (typeof stream !== 'boolean')
&& (typeof stream !== 'number')
&& (!Buffer.isBuffer(stream));
};
CombinedStream.prototype.append = function(stream) {
var isStreamLike = CombinedStream.isStreamLike(stream);
if (isStreamLike) {
if (!(stream instanceof DelayedStream)) {
var newStream = DelayedStream.create(stream, {
maxDataSize: Infinity,
pauseStream: this.pauseStreams,
});
stream.on('data', this._checkDataSize.bind(this));
stream = newStream;
}
this._handleErrors(stream);
if (this.pauseStreams) {
stream.pause();
}
}
this._streams.push(stream);
return this;
};
CombinedStream.prototype.pipe = function(dest, options) {
Stream.prototype.pipe.call(this, dest, options);
this.resume();
return dest;
};
CombinedStream.prototype._getNext = function() {
this._currentStream = null;
var stream = this._streams.shift();
if (typeof stream == 'undefined') {
this.end();
return;
}
if (typeof stream !== 'function') {
this._pipeNext(stream);
return;
}
var getStream = stream;
getStream(function(stream) {
var isStreamLike = CombinedStream.isStreamLike(stream);
if (isStreamLike) {
stream.on('data', this._checkDataSize.bind(this));
this._handleErrors(stream);
}
this._pipeNext(stream);
}.bind(this));
};
CombinedStream.prototype._pipeNext = function(stream) {
this._currentStream = stream;
var isStreamLike = CombinedStream.isStreamLike(stream);
if (isStreamLike) {
stream.on('end', this._getNext.bind(this));
stream.pipe(this, {end: false});
return;
}
var value = stream;
this.write(value);
this._getNext();
};
CombinedStream.prototype._handleErrors = function(stream) {
var self = this;
stream.on('error', function(err) {
self._emitError(err);
});
};
CombinedStream.prototype.write = function(data) {
this.emit('data', data);
};
CombinedStream.prototype.pause = function() {
if (!this.pauseStreams) {
return;
}
if(this.pauseStreams && this._currentStream && typeof(this._currentStream.pause) == 'function') this._currentStream.pause();
this.emit('pause');
};
CombinedStream.prototype.resume = function() {
if (!this._released) {
this._released = true;
this.writable = true;
this._getNext();
}
if(this.pauseStreams && this._currentStream && typeof(this._currentStream.resume) == 'function') this._currentStream.resume();
this.emit('resume');
};
CombinedStream.prototype.end = function() {
this._reset();
this.emit('end');
};
CombinedStream.prototype.destroy = function() {
this._reset();
this.emit('close');
};
CombinedStream.prototype._reset = function() {
this.writable = false;
this._streams = [];
this._currentStream = null;
};
CombinedStream.prototype._checkDataSize = function() {
this._updateDataSize();
if (this.dataSize <= this.maxDataSize) {
return;
}
var message =
'DelayedStream#maxDataSize of ' + this.maxDataSize + ' bytes exceeded.';
this._emitError(new Error(message));
};
CombinedStream.prototype._updateDataSize = function() {
this.dataSize = 0;
var self = this;
this._streams.forEach(function(stream) {
if (!stream.dataSize) {
return;
}
self.dataSize += stream.dataSize;
});
if (this._currentStream && this._currentStream.dataSize) {
this.dataSize += this._currentStream.dataSize;
}
};
CombinedStream.prototype._emitError = function(err) {
this._reset();
this.emit('error', err);
};
Copyright (c) 2011 Debuggable Limited <felix@debuggable.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
{
"_args": [
[
{
"raw": "combined-stream@~1.0.5",
"scope": null,
"escapedName": "combined-stream",
"name": "combined-stream",
"rawSpec": "~1.0.5",
"spec": ">=1.0.5 <1.1.0",
"type": "range"
},
"F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\request"
]
],
"_from": "combined-stream@>=1.0.5 <1.1.0",
"_id": "combined-stream@1.0.5",
"_inCache": true,
"_location": "/combined-stream",
"_nodeVersion": "0.12.4",
"_npmUser": {
"name": "alexindigo",
"email": "iam@alexindigo.com"
},
"_npmVersion": "2.10.1",
"_phantomChildren": {},
"_requested": {
"raw": "combined-stream@~1.0.5",
"scope": null,
"escapedName": "combined-stream",
"name": "combined-stream",
"rawSpec": "~1.0.5",
"spec": ">=1.0.5 <1.1.0",
"type": "range"
},
"_requiredBy": [
"/form-data",
"/request"
],
"_resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz",
"_shasum": "938370a57b4a51dea2c77c15d5c5fdf895164009",
"_shrinkwrap": null,
"_spec": "combined-stream@~1.0.5",
"_where": "F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\request",
"author": {
"name": "Felix Geisendörfer",
"email": "felix@debuggable.com",
"url": "http://debuggable.com/"
},
"bugs": {
"url": "https://github.com/felixge/node-combined-stream/issues"
},
"dependencies": {
"delayed-stream": "~1.0.0"
},
"description": "A stream that emits multiple other streams one after another.",
"devDependencies": {
"far": "~0.0.7"
},
"directories": {},
"dist": {
"shasum": "938370a57b4a51dea2c77c15d5c5fdf895164009",
"tarball": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz"
},
"engines": {
"node": ">= 0.8"
},
"gitHead": "cfc7b815d090a109bcedb5bb0f6713148d55a6b7",
"homepage": "https://github.com/felixge/node-combined-stream",
"license": "MIT",
"main": "./lib/combined_stream",
"maintainers": [
{
"name": "felixge",
"email": "felix@debuggable.com"
},
{
"name": "celer",
"email": "dtyree77@gmail.com"
},
{
"name": "alexindigo",
"email": "iam@alexindigo.com"
},
{
"name": "apechimp",
"email": "apeherder@gmail.com"
}
],
"name": "combined-stream",
"optionalDependencies": {},
"readme": "ERROR: No README data found!",
"repository": {
"type": "git",
"url": "git://github.com/felixge/node-combined-stream.git"
},
"scripts": {
"test": "node test/run.js"
},
"version": "1.0.5"
}

combined-stream

A stream that emits multiple other streams one after another.

NB Currently combined-stream works with streams vesrion 1 only. There is ongoing effort to switch this library to streams version 2. Any help is welcome. :) Meanwhile you can explore other libraries that provide streams2 support with more or less compatability with combined-stream.

  • combined-stream2: A drop-in streams2-compatible replacement for the combined-stream module.

  • multistream: A stream that emits multiple other streams one after another.

Installation

npm install combined-stream

Usage

Here is a simple example that shows how you can use combined-stream to combine two files into one:

var CombinedStream = require('combined-stream');
var fs = require('fs');

var combinedStream = CombinedStream.create();
combinedStream.append(fs.createReadStream('file1.txt'));
combinedStream.append(fs.createReadStream('file2.txt'));

combinedStream.pipe(fs.createWriteStream('combined.txt'));

While the example above works great, it will pause all source streams until they are needed. If you don't want that to happen, you can set pauseStreams to false:

var CombinedStream = require('combined-stream');
var fs = require('fs');

var combinedStream = CombinedStream.create({pauseStreams: false});
combinedStream.append(fs.createReadStream('file1.txt'));
combinedStream.append(fs.createReadStream('file2.txt'));

combinedStream.pipe(fs.createWriteStream('combined.txt'));

However, what if you don't have all the source streams yet, or you don't want to allocate the resources (file descriptors, memory, etc.) for them right away? Well, in that case you can simply provide a callback that supplies the stream by calling a next() function:

var CombinedStream = require('combined-stream');
var fs = require('fs');

var combinedStream = CombinedStream.create();
combinedStream.append(function(next) {
  next(fs.createReadStream('file1.txt'));
});
combinedStream.append(function(next) {
  next(fs.createReadStream('file2.txt'));
});

combinedStream.pipe(fs.createWriteStream('combined.txt'));

API

CombinedStream.create([options])

Returns a new combined stream object. Available options are:

  • maxDataSize
  • pauseStreams

The effect of those options is described below.

combinedStream.pauseStreams = true

Whether to apply back pressure to the underlaying streams. If set to false, the underlaying streams will never be paused. If set to true, the underlaying streams will be paused right after being appended, as well as when delayedStream.pipe() wants to throttle.

combinedStream.maxDataSize = 2 * 1024 * 1024

The maximum amount of bytes (or characters) to buffer for all source streams. If this value is exceeded, combinedStream emits an 'error' event.

combinedStream.dataSize = 0

The amount of bytes (or characters) currently buffered by combinedStream.

combinedStream.append(stream)

Appends the given stream to the combinedStream object. If pauseStreams is set to `true, this stream will also be paused right away.

streams can also be a function that takes one parameter called next. next is a function that must be invoked in order to provide the next stream, see example above.

Regardless of how the stream is appended, combined-stream always attaches an 'error' listener to it, so you don't have to do that manually.

Special case: stream can also be a String or Buffer.

combinedStream.write(data)

You should not call this, combinedStream takes care of piping the appended streams into itself for you.

combinedStream.resume()

Causes combinedStream to start drain the streams it manages. The function is idempotent, and also emits a 'resume' event each time which usually goes to the stream that is currently being drained.

combinedStream.pause();

If combinedStream.pauseStreams is set to false, this does nothing. Otherwise a 'pause' event is emitted, this goes to the stream that is currently being drained, so you can use it to apply back pressure.

combinedStream.end();

Sets combinedStream.writable to false, emits an 'end' event, and removes all streams from the queue.

combinedStream.destroy();

Same as combinedStream.end(), except it emits a 'close' event instead of 'end'.

License

combined-stream is licensed under the MIT license.

2.9.0 / 2015-10-13

  • Add option isDefault to set default subcommand #415 @Qix-
  • Add callback to allow filtering or post-processing of help text #434 @djulien
  • Fix undefined text in help information close #414 #416 @zhiyelee

2.8.1 / 2015-04-22

  • Back out support multiline description Close #396 #397

2.8.0 / 2015-04-07

  • Add process.execArg support, execution args like --harmony will be passed to sub-commands #387 @DigitalIO @zhiyelee
  • Fix bug in Git-style sub-commands #372 @zhiyelee
  • Allow commands to be hidden from help #383 @tonylukasavage
  • When git-style sub-commands are in use, yet none are called, display help #382 @claylo
  • Add ability to specify arguments syntax for top-level command #258 @rrthomas
  • Support multiline descriptions #208 @zxqfox

2.7.1 / 2015-03-11

  • Revert #347 (fix collisions when option and first arg have same name) which causes a bug in #367.

2.7.0 / 2015-03-09

  • Fix git-style bug when installed globally. Close #335 #349 @zhiyelee
  • Fix collisions when option and first arg have same name. Close #346 #347 @tonylukasavage
  • Add support for camelCase on opts(). Close #353 @nkzawa
  • Add node.js 0.12 and io.js to travis.yml
  • Allow RegEx options. #337 @palanik
  • Fixes exit code when sub-command failing. Close #260 #332 @pirelenito
  • git-style bin files in $PATH make sense. Close #196 #327 @zhiyelee

2.6.0 / 2014-12-30

  • added Command#allowUnknownOption method. Close #138 #318 @doozr @zhiyelee
  • Add application description to the help msg. Close #112 @dalssoft

2.5.1 / 2014-12-15

  • fixed two bugs incurred by variadic arguments. Close #291 @Quentin01 #302 @zhiyelee

2.5.0 / 2014-10-24

  • add support for variadic arguments. Closes #277 @whitlockjc

2.4.0 / 2014-10-17

  • fixed a bug on executing the coercion function of subcommands option. Closes #270
  • added Command.prototype.name to retrieve command name. Closes #264 #266 @tonylukasavage
  • added Command.prototype.opts to retrieve all the options as a simple object of key-value pairs. Closes #262 @tonylukasavage
  • fixed a bug on subcommand name. Closes #248 @jonathandelgado
  • fixed function normalize doesn’t honor option terminator. Closes #216 @abbr

2.3.0 / 2014-07-16

  • add command alias'. Closes PR #210
  • fix: Typos. Closes #99
  • fix: Unused fs module. Closes #217

2.2.0 / 2014-03-29

  • add passing of previous option value
  • fix: support subcommands on windows. Closes #142
  • Now the defaultValue passed as the second argument of the coercion function.

2.1.0 / 2013-11-21

  • add: allow cflag style option params, unit test, fixes #174

2.0.0 / 2013-07-18

  • remove input methods (.prompt, .confirm, etc)

1.3.2 / 2013-07-18

  • add support for sub-commands to co-exist with the original command

1.3.1 / 2013-07-18

  • add quick .runningCommand hack so you can opt-out of other logic when running a sub command

1.3.0 / 2013-07-09

  • add EACCES error handling
  • fix sub-command --help

1.2.0 / 2013-06-13

  • allow "-" hyphen as an option argument
  • support for RegExp coercion

1.1.1 / 2012-11-20

  • add more sub-command padding
  • fix .usage() when args are present. Closes #106

1.1.0 / 2012-11-16

  • add git-style executable subcommand support. Closes #94

1.0.5 / 2012-10-09

  • fix --name clobbering. Closes #92
  • fix examples/help. Closes #89

1.0.4 / 2012-09-03

  • add outputHelp() method.

1.0.3 / 2012-08-30

  • remove invalid .version() defaulting

1.0.2 / 2012-08-24

  • add --foo=bar support [arv]
  • fix password on node 0.8.8. Make backward compatible with 0.6 [focusaurus]

1.0.1 / 2012-08-03

  • fix issue #56
  • fix tty.setRawMode(mode) was moved to tty.ReadStream#setRawMode() (i.e. process.stdin.setRawMode())

1.0.0 / 2012-07-05

  • add support for optional option descriptions
  • add defaulting of .version() to package.json's version

0.6.1 / 2012-06-01

  • Added: append (yes or no) on confirmation
  • Added: allow node.js v0.7.x

0.6.0 / 2012-04-10

  • Added .prompt(obj, callback) support. Closes #49
  • Added default support to .choose(). Closes #41
  • Fixed the choice example

0.5.1 / 2011-12-20

  • Fixed password() for recent nodes. Closes #36

0.5.0 / 2011-12-04

  • Added sub-command option support [itay]

0.4.3 / 2011-12-04

  • Fixed custom help ordering. Closes #32

0.4.2 / 2011-11-24

  • Added travis support
  • Fixed: line-buffered input automatically trimmed. Closes #31

0.4.1 / 2011-11-18

  • Removed listening for "close" on --help

0.4.0 / 2011-11-15

  • Added support for --. Closes #24

0.3.3 / 2011-11-14

  • Fixed: wait for close event when writing help info [Jerry Hamlet]

0.3.2 / 2011-11-01

  • Fixed long flag definitions with values [felixge]

0.3.1 / 2011-10-31

  • Changed --version short flag to -V from -v
  • Changed .version() so it's configurable [felixge]

0.3.0 / 2011-10-31

  • Added support for long flags only. Closes #18

0.2.1 / 2011-10-24

  • "node": ">= 0.4.x < 0.7.0". Closes #20

0.2.0 / 2011-09-26

  • Allow for defaults that are not just boolean. Default peassignment only occurs for --no-*, optional, and required arguments. [Jim Isaacs]

0.1.0 / 2011-08-24

  • Added support for custom --help output

0.0.5 / 2011-08-18

  • Changed: when the user enters nothing prompt for password again
  • Fixed issue with passwords beginning with numbers [NuckChorris]

0.0.4 / 2011-08-15

  • Fixed Commander#args

0.0.3 / 2011-08-15

  • Added default option value support

0.0.2 / 2011-08-15

  • Added mask support to Command#password(str[, mask], fn)
  • Added Command#password(str, fn)

0.0.1 / 2010-01-03

  • Initial release
/**
* Module dependencies.
*/
var EventEmitter = require('events').EventEmitter;
var spawn = require('child_process').spawn;
var readlink = require('graceful-readlink').readlinkSync;
var path = require('path');
var dirname = path.dirname;
var basename = path.basename;
var fs = require('fs');
/**
* Expose the root command.
*/
exports = module.exports = new Command();
/**
* Expose `Command`.
*/
exports.Command = Command;
/**
* Expose `Option`.
*/
exports.Option = Option;
/**
* Initialize a new `Option` with the given `flags` and `description`.
*
* @param {String} flags
* @param {String} description
* @api public
*/
function Option(flags, description) {
this.flags = flags;
this.required = ~flags.indexOf('<');
this.optional = ~flags.indexOf('[');
this.bool = !~flags.indexOf('-no-');
flags = flags.split(/[ ,|]+/);
if (flags.length > 1 && !/^[[<]/.test(flags[1])) this.short = flags.shift();
this.long = flags.shift();
this.description = description || '';
}
/**
* Return option name.
*
* @return {String}
* @api private
*/
Option.prototype.name = function() {
return this.long
.replace('--', '')
.replace('no-', '');
};
/**
* Check if `arg` matches the short or long flag.
*
* @param {String} arg
* @return {Boolean}
* @api private
*/
Option.prototype.is = function(arg) {
return arg == this.short || arg == this.long;
};
/**
* Initialize a new `Command`.
*
* @param {String} name
* @api public
*/
function Command(name) {
this.commands = [];
this.options = [];
this._execs = {};
this._allowUnknownOption = false;
this._args = [];
this._name = name || '';
}
/**
* Inherit from `EventEmitter.prototype`.
*/
Command.prototype.__proto__ = EventEmitter.prototype;
/**
* Add command `name`.
*
* The `.action()` callback is invoked when the
* command `name` is specified via __ARGV__,
* and the remaining arguments are applied to the
* function for access.
*
* When the `name` is "*" an un-matched command
* will be passed as the first arg, followed by
* the rest of __ARGV__ remaining.
*
* Examples:
*
* program
* .version('0.0.1')
* .option('-C, --chdir <path>', 'change the working directory')
* .option('-c, --config <path>', 'set config path. defaults to ./deploy.conf')
* .option('-T, --no-tests', 'ignore test hook')
*
* program
* .command('setup')
* .description('run remote setup commands')
* .action(function() {
* console.log('setup');
* });
*
* program
* .command('exec <cmd>')
* .description('run the given remote command')
* .action(function(cmd) {
* console.log('exec "%s"', cmd);
* });
*
* program
* .command('teardown <dir> [otherDirs...]')
* .description('run teardown commands')
* .action(function(dir, otherDirs) {
* console.log('dir "%s"', dir);
* if (otherDirs) {
* otherDirs.forEach(function (oDir) {
* console.log('dir "%s"', oDir);
* });
* }
* });
*
* program
* .command('*')
* .description('deploy the given env')
* .action(function(env) {
* console.log('deploying "%s"', env);
* });
*
* program.parse(process.argv);
*
* @param {String} name
* @param {String} [desc] for git-style sub-commands
* @return {Command} the new command
* @api public
*/
Command.prototype.command = function(name, desc, opts) {
opts = opts || {};
var args = name.split(/ +/);
var cmd = new Command(args.shift());
if (desc) {
cmd.description(desc);
this.executables = true;
this._execs[cmd._name] = true;
if (opts.isDefault) this.defaultExecutable = cmd._name;
}
cmd._noHelp = !!opts.noHelp;
this.commands.push(cmd);
cmd.parseExpectedArgs(args);
cmd.parent = this;
if (desc) return this;
return cmd;
};
/**
* Define argument syntax for the top-level command.
*
* @api public
*/
Command.prototype.arguments = function (desc) {
return this.parseExpectedArgs(desc.split(/ +/));
};
/**
* Add an implicit `help [cmd]` subcommand
* which invokes `--help` for the given command.
*
* @api private
*/
Command.prototype.addImplicitHelpCommand = function() {
this.command('help [cmd]', 'display help for [cmd]');
};
/**
* Parse expected `args`.
*
* For example `["[type]"]` becomes `[{ required: false, name: 'type' }]`.
*
* @param {Array} args
* @return {Command} for chaining
* @api public
*/
Command.prototype.parseExpectedArgs = function(args) {
if (!args.length) return;
var self = this;
args.forEach(function(arg) {
var argDetails = {
required: false,
name: '',
variadic: false
};
switch (arg[0]) {
case '<':
argDetails.required = true;
argDetails.name = arg.slice(1, -1);
break;
case '[':
argDetails.name = arg.slice(1, -1);
break;
}
if (argDetails.name.length > 3 && argDetails.name.slice(-3) === '...') {
argDetails.variadic = true;
argDetails.name = argDetails.name.slice(0, -3);
}
if (argDetails.name) {
self._args.push(argDetails);
}
});
return this;
};
/**
* Register callback `fn` for the command.
*
* Examples:
*
* program
* .command('help')
* .description('display verbose help')
* .action(function() {
* // output help here
* });
*
* @param {Function} fn
* @return {Command} for chaining
* @api public
*/
Command.prototype.action = function(fn) {
var self = this;
var listener = function(args, unknown) {
// Parse any so-far unknown options
args = args || [];
unknown = unknown || [];
var parsed = self.parseOptions(unknown);
// Output help if necessary
outputHelpIfNecessary(self, parsed.unknown);
// If there are still any unknown options, then we simply
// die, unless someone asked for help, in which case we give it
// to them, and then we die.
if (parsed.unknown.length > 0) {
self.unknownOption(parsed.unknown[0]);
}
// Leftover arguments need to be pushed back. Fixes issue #56
if (parsed.args.length) args = parsed.args.concat(args);
self._args.forEach(function(arg, i) {
if (arg.required && null == args[i]) {
self.missingArgument(arg.name);
} else if (arg.variadic) {
if (i !== self._args.length - 1) {
self.variadicArgNotLast(arg.name);
}
args[i] = args.splice(i);
}
});
// Always append ourselves to the end of the arguments,
// to make sure we match the number of arguments the user
// expects
if (self._args.length) {
args[self._args.length] = self;
} else {
args.push(self);
}
fn.apply(self, args);
};
var parent = this.parent || this;
var name = parent === this ? '*' : this._name;
parent.on(name, listener);
if (this._alias) parent.on(this._alias, listener);
return this;
};
/**
* Define option with `flags`, `description` and optional
* coercion `fn`.
*
* The `flags` string should contain both the short and long flags,
* separated by comma, a pipe or space. The following are all valid
* all will output this way when `--help` is used.
*
* "-p, --pepper"
* "-p|--pepper"
* "-p --pepper"
*
* Examples:
*
* // simple boolean defaulting to false
* program.option('-p, --pepper', 'add pepper');
*
* --pepper
* program.pepper
* // => Boolean
*
* // simple boolean defaulting to true
* program.option('-C, --no-cheese', 'remove cheese');
*
* program.cheese
* // => true
*
* --no-cheese
* program.cheese
* // => false
*
* // required argument
* program.option('-C, --chdir <path>', 'change the working directory');
*
* --chdir /tmp
* program.chdir
* // => "/tmp"
*
* // optional argument
* program.option('-c, --cheese [type]', 'add cheese [marble]');
*
* @param {String} flags
* @param {String} description
* @param {Function|Mixed} fn or default
* @param {Mixed} defaultValue
* @return {Command} for chaining
* @api public
*/
Command.prototype.option = function(flags, description, fn, defaultValue) {
var self = this
, option = new Option(flags, description)
, oname = option.name()
, name = camelcase(oname);
// default as 3rd arg
if (typeof fn != 'function') {
if (fn instanceof RegExp) {
var regex = fn;
fn = function(val, def) {
var m = regex.exec(val);
return m ? m[0] : def;
}
}
else {
defaultValue = fn;
fn = null;
}
}
// preassign default value only for --no-*, [optional], or <required>
if (false == option.bool || option.optional || option.required) {
// when --no-* we make sure default is true
if (false == option.bool) defaultValue = true;
// preassign only if we have a default
if (undefined !== defaultValue) self[name] = defaultValue;
}
// register the option
this.options.push(option);
// when it's passed assign the value
// and conditionally invoke the callback
this.on(oname, function(val) {
// coercion
if (null !== val && fn) val = fn(val, undefined === self[name]
? defaultValue
: self[name]);
// unassigned or bool
if ('boolean' == typeof self[name] || 'undefined' == typeof self[name]) {
// if no value, bool true, and we have a default, then use it!
if (null == val) {
self[name] = option.bool
? defaultValue || true
: false;
} else {
self[name] = val;
}
} else if (null !== val) {
// reassign
self[name] = val;
}
});
return this;
};
/**
* Allow unknown options on the command line.
*
* @param {Boolean} arg if `true` or omitted, no error will be thrown
* for unknown options.
* @api public
*/
Command.prototype.allowUnknownOption = function(arg) {
this._allowUnknownOption = arguments.length === 0 || arg;
return this;
};
/**
* Parse `argv`, settings options and invoking commands when defined.
*
* @param {Array} argv
* @return {Command} for chaining
* @api public
*/
Command.prototype.parse = function(argv) {
// implicit help
if (this.executables) this.addImplicitHelpCommand();
// store raw args
this.rawArgs = argv;
// guess name
this._name = this._name || basename(argv[1], '.js');
// github-style sub-commands with no sub-command
if (this.executables && argv.length < 3 && !this.defaultExecutable) {
// this user needs help
argv.push('--help');
}
// process argv
var parsed = this.parseOptions(this.normalize(argv.slice(2)));
var args = this.args = parsed.args;
var result = this.parseArgs(this.args, parsed.unknown);
// executable sub-commands
var name = result.args[0];
if (this._execs[name] && typeof this._execs[name] != "function") {
return this.executeSubCommand(argv, args, parsed.unknown);
} else if (this.defaultExecutable) {
// use the default subcommand
args.unshift(name = this.defaultExecutable);
return this.executeSubCommand(argv, args, parsed.unknown);
}
return result;
};
/**
* Execute a sub-command executable.
*
* @param {Array} argv
* @param {Array} args
* @param {Array} unknown
* @api private
*/
Command.prototype.executeSubCommand = function(argv, args, unknown) {
args = args.concat(unknown);
if (!args.length) this.help();
if ('help' == args[0] && 1 == args.length) this.help();
// <cmd> --help
if ('help' == args[0]) {
args[0] = args[1];
args[1] = '--help';
}
// executable
var f = argv[1];
// name of the subcommand, link `pm-install`
var bin = basename(f, '.js') + '-' + args[0];
// In case of globally installed, get the base dir where executable
// subcommand file should be located at
var baseDir
, link = readlink(f);
// when symbolink is relative path
if (link !== f && link.charAt(0) !== '/') {
link = path.join(dirname(f), link)
}
baseDir = dirname(link);
// prefer local `./<bin>` to bin in the $PATH
var localBin = path.join(baseDir, bin);
// whether bin file is a js script with explicit `.js` extension
var isExplicitJS = false;
if (exists(localBin + '.js')) {
bin = localBin + '.js';
isExplicitJS = true;
} else if (exists(localBin)) {
bin = localBin;
}
args = args.slice(1);
var proc;
if (process.platform !== 'win32') {
if (isExplicitJS) {
args.unshift(localBin);
// add executable arguments to spawn
args = (process.execArgv || []).concat(args);
proc = spawn('node', args, { stdio: 'inherit', customFds: [0, 1, 2] });
} else {
proc = spawn(bin, args, { stdio: 'inherit', customFds: [0, 1, 2] });
}
} else {
args.unshift(localBin);
proc = spawn(process.execPath, args, { stdio: 'inherit'});
}
proc.on('close', process.exit.bind(process));
proc.on('error', function(err) {
if (err.code == "ENOENT") {
console.error('\n %s(1) does not exist, try --help\n', bin);
} else if (err.code == "EACCES") {
console.error('\n %s(1) not executable. try chmod or run with root\n', bin);
}
process.exit(1);
});
// Store the reference to the child process
this.runningCommand = proc;
};
/**
* Normalize `args`, splitting joined short flags. For example
* the arg "-abc" is equivalent to "-a -b -c".
* This also normalizes equal sign and splits "--abc=def" into "--abc def".
*
* @param {Array} args
* @return {Array}
* @api private
*/
Command.prototype.normalize = function(args) {
var ret = []
, arg
, lastOpt
, index;
for (var i = 0, len = args.length; i < len; ++i) {
arg = args[i];
if (i > 0) {
lastOpt = this.optionFor(args[i-1]);
}
if (arg === '--') {
// Honor option terminator
ret = ret.concat(args.slice(i));
break;
} else if (lastOpt && lastOpt.required) {
ret.push(arg);
} else if (arg.length > 1 && '-' == arg[0] && '-' != arg[1]) {
arg.slice(1).split('').forEach(function(c) {
ret.push('-' + c);
});
} else if (/^--/.test(arg) && ~(index = arg.indexOf('='))) {
ret.push(arg.slice(0, index), arg.slice(index + 1));
} else {
ret.push(arg);
}
}
return ret;
};
/**
* Parse command `args`.
*
* When listener(s) are available those
* callbacks are invoked, otherwise the "*"
* event is emitted and those actions are invoked.
*
* @param {Array} args
* @return {Command} for chaining
* @api private
*/
Command.prototype.parseArgs = function(args, unknown) {
var name;
if (args.length) {
name = args[0];
if (this.listeners(name).length) {
this.emit(args.shift(), args, unknown);
} else {
this.emit('*', args);
}
} else {
outputHelpIfNecessary(this, unknown);
// If there were no args and we have unknown options,
// then they are extraneous and we need to error.
if (unknown.length > 0) {
this.unknownOption(unknown[0]);
}
}
return this;
};
/**
* Return an option matching `arg` if any.
*
* @param {String} arg
* @return {Option}
* @api private
*/
Command.prototype.optionFor = function(arg) {
for (var i = 0, len = this.options.length; i < len; ++i) {
if (this.options[i].is(arg)) {
return this.options[i];
}
}
};
/**
* Parse options from `argv` returning `argv`
* void of these options.
*
* @param {Array} argv
* @return {Array}
* @api public
*/
Command.prototype.parseOptions = function(argv) {
var args = []
, len = argv.length
, literal
, option
, arg;
var unknownOptions = [];
// parse options
for (var i = 0; i < len; ++i) {
arg = argv[i];
// literal args after --
if ('--' == arg) {
literal = true;
continue;
}
if (literal) {
args.push(arg);
continue;
}
// find matching Option
option = this.optionFor(arg);
// option is defined
if (option) {
// requires arg
if (option.required) {
arg = argv[++i];
if (null == arg) return this.optionMissingArgument(option);
this.emit(option.name(), arg);
// optional arg
} else if (option.optional) {
arg = argv[i+1];
if (null == arg || ('-' == arg[0] && '-' != arg)) {
arg = null;
} else {
++i;
}
this.emit(option.name(), arg);
// bool
} else {
this.emit(option.name());
}
continue;
}
// looks like an option
if (arg.length > 1 && '-' == arg[0]) {
unknownOptions.push(arg);
// If the next argument looks like it might be
// an argument for this option, we pass it on.
// If it isn't, then it'll simply be ignored
if (argv[i+1] && '-' != argv[i+1][0]) {
unknownOptions.push(argv[++i]);
}
continue;
}
// arg
args.push(arg);
}
return { args: args, unknown: unknownOptions };
};
/**
* Return an object containing options as key-value pairs
*
* @return {Object}
* @api public
*/
Command.prototype.opts = function() {
var result = {}
, len = this.options.length;
for (var i = 0 ; i < len; i++) {
var key = camelcase(this.options[i].name());
result[key] = key === 'version' ? this._version : this[key];
}
return result;
};
/**
* Argument `name` is missing.
*
* @param {String} name
* @api private
*/
Command.prototype.missingArgument = function(name) {
console.error();
console.error(" error: missing required argument `%s'", name);
console.error();
process.exit(1);
};
/**
* `Option` is missing an argument, but received `flag` or nothing.
*
* @param {String} option
* @param {String} flag
* @api private
*/
Command.prototype.optionMissingArgument = function(option, flag) {
console.error();
if (flag) {
console.error(" error: option `%s' argument missing, got `%s'", option.flags, flag);
} else {
console.error(" error: option `%s' argument missing", option.flags);
}
console.error();
process.exit(1);
};
/**
* Unknown option `flag`.
*
* @param {String} flag
* @api private
*/
Command.prototype.unknownOption = function(flag) {
if (this._allowUnknownOption) return;
console.error();
console.error(" error: unknown option `%s'", flag);
console.error();
process.exit(1);
};
/**
* Variadic argument with `name` is not the last argument as required.
*
* @param {String} name
* @api private
*/
Command.prototype.variadicArgNotLast = function(name) {
console.error();
console.error(" error: variadic arguments must be last `%s'", name);
console.error();
process.exit(1);
};
/**
* Set the program version to `str`.
*
* This method auto-registers the "-V, --version" flag
* which will print the version number when passed.
*
* @param {String} str
* @param {String} flags
* @return {Command} for chaining
* @api public
*/
Command.prototype.version = function(str, flags) {
if (0 == arguments.length) return this._version;
this._version = str;
flags = flags || '-V, --version';
this.option(flags, 'output the version number');
this.on('version', function() {
process.stdout.write(str + '\n');
process.exit(0);
});
return this;
};
/**
* Set the description to `str`.
*
* @param {String} str
* @return {String|Command}
* @api public
*/
Command.prototype.description = function(str) {
if (0 === arguments.length) return this._description;
this._description = str;
return this;
};
/**
* Set an alias for the command
*
* @param {String} alias
* @return {String|Command}
* @api public
*/
Command.prototype.alias = function(alias) {
if (0 == arguments.length) return this._alias;
this._alias = alias;
return this;
};
/**
* Set / get the command usage `str`.
*
* @param {String} str
* @return {String|Command}
* @api public
*/
Command.prototype.usage = function(str) {
var args = this._args.map(function(arg) {
return humanReadableArgName(arg);
});
var usage = '[options]'
+ (this.commands.length ? ' [command]' : '')
+ (this._args.length ? ' ' + args.join(' ') : '');
if (0 == arguments.length) return this._usage || usage;
this._usage = str;
return this;
};
/**
* Get the name of the command
*
* @param {String} name
* @return {String|Command}
* @api public
*/
Command.prototype.name = function() {
return this._name;
};
/**
* Return the largest option length.
*
* @return {Number}
* @api private
*/
Command.prototype.largestOptionLength = function() {
return this.options.reduce(function(max, option) {
return Math.max(max, option.flags.length);
}, 0);
};
/**
* Return help for options.
*
* @return {String}
* @api private
*/
Command.prototype.optionHelp = function() {
var width = this.largestOptionLength();
// Prepend the help information
return [pad('-h, --help', width) + ' ' + 'output usage information']
.concat(this.options.map(function(option) {
return pad(option.flags, width) + ' ' + option.description;
}))
.join('\n');
};
/**
* Return command help documentation.
*
* @return {String}
* @api private
*/
Command.prototype.commandHelp = function() {
if (!this.commands.length) return '';
var commands = this.commands.filter(function(cmd) {
return !cmd._noHelp;
}).map(function(cmd) {
var args = cmd._args.map(function(arg) {
return humanReadableArgName(arg);
}).join(' ');
return [
cmd._name
+ (cmd._alias ? '|' + cmd._alias : '')
+ (cmd.options.length ? ' [options]' : '')
+ ' ' + args
, cmd.description()
];
});
var width = commands.reduce(function(max, command) {
return Math.max(max, command[0].length);
}, 0);
return [
''
, ' Commands:'
, ''
, commands.map(function(cmd) {
var desc = cmd[1] ? ' ' + cmd[1] : '';
return pad(cmd[0], width) + desc;
}).join('\n').replace(/^/gm, ' ')
, ''
].join('\n');
};
/**
* Return program help documentation.
*
* @return {String}
* @api private
*/
Command.prototype.helpInformation = function() {
var desc = [];
if (this._description) {
desc = [
' ' + this._description
, ''
];
}
var cmdName = this._name;
if (this._alias) {
cmdName = cmdName + '|' + this._alias;
}
var usage = [
''
,' Usage: ' + cmdName + ' ' + this.usage()
, ''
];
var cmds = [];
var commandHelp = this.commandHelp();
if (commandHelp) cmds = [commandHelp];
var options = [
' Options:'
, ''
, '' + this.optionHelp().replace(/^/gm, ' ')
, ''
, ''
];
return usage
.concat(cmds)
.concat(desc)
.concat(options)
.join('\n');
};
/**
* Output help information for this command
*
* @api public
*/
Command.prototype.outputHelp = function(cb) {
if (!cb) {
cb = function(passthru) {
return passthru;
}
}
process.stdout.write(cb(this.helpInformation()));
this.emit('--help');
};
/**
* Output help information and exit.
*
* @api public
*/
Command.prototype.help = function(cb) {
this.outputHelp(cb);
process.exit();
};
/**
* Camel-case the given `flag`
*
* @param {String} flag
* @return {String}
* @api private
*/
function camelcase(flag) {
return flag.split('-').reduce(function(str, word) {
return str + word[0].toUpperCase() + word.slice(1);
});
}
/**
* Pad `str` to `width`.
*
* @param {String} str
* @param {Number} width
* @return {String}
* @api private
*/
function pad(str, width) {
var len = Math.max(0, width - str.length);
return str + Array(len + 1).join(' ');
}
/**
* Output help information if necessary
*
* @param {Command} command to output help for
* @param {Array} array of options to search for -h or --help
* @api private
*/
function outputHelpIfNecessary(cmd, options) {
options = options || [];
for (var i = 0; i < options.length; i++) {
if (options[i] == '--help' || options[i] == '-h') {
cmd.outputHelp();
process.exit(0);
}
}
}
/**
* Takes an argument an returns its human readable equivalent for help usage.
*
* @param {Object} arg
* @return {String}
* @api private
*/
function humanReadableArgName(arg) {
var nameOutput = arg.name + (arg.variadic === true ? '...' : '');
return arg.required
? '<' + nameOutput + '>'
: '[' + nameOutput + ']'
}
// for versions before node v0.8 when there weren't `fs.existsSync`
function exists(file) {
try {
if (fs.statSync(file).isFile()) {
return true;
}
} catch (e) {
return false;
}
}
(The MIT License)
Copyright (c) 2011 TJ Holowaychuk <tj@vision-media.ca>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
{
"_args": [
[
{
"raw": "commander@^2.9.0",
"scope": null,
"escapedName": "commander",
"name": "commander",
"rawSpec": "^2.9.0",
"spec": ">=2.9.0 <3.0.0",
"type": "range"
},
"F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\har-validator"
]
],
"_from": "commander@>=2.9.0 <3.0.0",
"_id": "commander@2.9.0",
"_inCache": true,
"_location": "/commander",
"_nodeVersion": "0.12.7",
"_npmUser": {
"name": "zhiyelee",
"email": "zhiyelee@gmail.com"
},
"_npmVersion": "2.11.3",
"_phantomChildren": {},
"_requested": {
"raw": "commander@^2.9.0",
"scope": null,
"escapedName": "commander",
"name": "commander",
"rawSpec": "^2.9.0",
"spec": ">=2.9.0 <3.0.0",
"type": "range"
},
"_requiredBy": [
"/har-validator"
],
"_resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz",
"_shasum": "9c99094176e12240cb22d6c5146098400fe0f7d4",
"_shrinkwrap": null,
"_spec": "commander@^2.9.0",
"_where": "F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\har-validator",
"author": {
"name": "TJ Holowaychuk",
"email": "tj@vision-media.ca"
},
"bugs": {
"url": "https://github.com/tj/commander.js/issues"
},
"dependencies": {
"graceful-readlink": ">= 1.0.0"
},
"description": "the complete solution for node.js command-line programs",
"devDependencies": {
"should": ">= 0.0.1",
"sinon": ">=1.17.1"
},
"directories": {},
"dist": {
"shasum": "9c99094176e12240cb22d6c5146098400fe0f7d4",
"tarball": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz"
},
"engines": {
"node": ">= 0.6.x"
},
"files": [
"index.js"
],
"gitHead": "b2aad7a8471d434593a85306aa73777a526e9f75",
"homepage": "https://github.com/tj/commander.js#readme",
"keywords": [
"command",
"option",
"parser"
],
"license": "MIT",
"main": "index",
"maintainers": [
{
"name": "tjholowaychuk",
"email": "tj@vision-media.ca"
},
{
"name": "somekittens",
"email": "rkoutnik@gmail.com"
},
{
"name": "zhiyelee",
"email": "zhiyelee@gmail.com"
}
],
"name": "commander",
"optionalDependencies": {},
"readme": "ERROR: No README data found!",
"repository": {
"type": "git",
"url": "git+https://github.com/tj/commander.js.git"
},
"scripts": {
"test": "make test"
},
"version": "2.9.0"
}

Commander.js

Build Status NPM Version NPM Downloads Join the chat at https://gitter.im/tj/commander.js

The complete solution for node.js command-line interfaces, inspired by Ruby's commander.
API documentation

Installation

$ npm install commander

Option parsing

Options with commander are defined with the .option() method, also serving as documentation for the options. The example below parses args and options from process.argv, leaving remaining args as the program.args array which were not consumed by options.

#!/usr/bin/env node

/**
 * Module dependencies.
 */

var program = require('commander');

program
  .version('0.0.1')
  .option('-p, --peppers', 'Add peppers')
  .option('-P, --pineapple', 'Add pineapple')
  .option('-b, --bbq-sauce', 'Add bbq sauce')
  .option('-c, --cheese [type]', 'Add the specified type of cheese [marble]', 'marble')
  .parse(process.argv);

console.log('you ordered a pizza with:');
if (program.peppers) console.log('  - peppers');
if (program.pineapple) console.log('  - pineapple');
if (program.bbqSauce) console.log('  - bbq');
console.log('  - %s cheese', program.cheese);

Short flags may be passed as a single arg, for example -abc is equivalent to -a -b -c. Multi-word options such as "--template-engine" are camel-cased, becoming program.templateEngine etc.

Coercion

function range(val) {
  return val.split('..').map(Number);
}

function list(val) {
  return val.split(',');
}

function collect(val, memo) {
  memo.push(val);
  return memo;
}

function increaseVerbosity(v, total) {
  return total + 1;
}

program
  .version('0.0.1')
  .usage('[options] <file ...>')
  .option('-i, --integer <n>', 'An integer argument', parseInt)
  .option('-f, --float <n>', 'A float argument', parseFloat)
  .option('-r, --range <a>..<b>', 'A range', range)
  .option('-l, --list <items>', 'A list', list)
  .option('-o, --optional [value]', 'An optional value')
  .option('-c, --collect [value]', 'A repeatable value', collect, [])
  .option('-v, --verbose', 'A value that can be increased', increaseVerbosity, 0)
  .parse(process.argv);

console.log(' int: %j', program.integer);
console.log(' float: %j', program.float);
console.log(' optional: %j', program.optional);
program.range = program.range || [];
console.log(' range: %j..%j', program.range[0], program.range[1]);
console.log(' list: %j', program.list);
console.log(' collect: %j', program.collect);
console.log(' verbosity: %j', program.verbose);
console.log(' args: %j', program.args);

Regular Expression

program
  .version('0.0.1')
  .option('-s --size <size>', 'Pizza size', /^(large|medium|small)$/i, 'medium')
  .option('-d --drink [drink]', 'Drink', /^(coke|pepsi|izze)$/i)
  .parse(process.argv);
  
console.log(' size: %j', program.size);
console.log(' drink: %j', program.drink);

Variadic arguments

The last argument of a command can be variadic, and only the last argument. To make an argument variadic you have to append ... to the argument name. Here is an example:

#!/usr/bin/env node

/**
 * Module dependencies.
 */

var program = require('commander');

program
  .version('0.0.1')
  .command('rmdir <dir> [otherDirs...]')
  .action(function (dir, otherDirs) {
    console.log('rmdir %s', dir);
    if (otherDirs) {
      otherDirs.forEach(function (oDir) {
        console.log('rmdir %s', oDir);
      });
    }
  });

program.parse(process.argv);

An Array is used for the value of a variadic argument. This applies to program.args as well as the argument passed to your action as demonstrated above.

Specify the argument syntax

#!/usr/bin/env node

var program = require('../');

program
  .version('0.0.1')
  .arguments('<cmd> [env]')
  .action(function (cmd, env) {
     cmdValue = cmd;
     envValue = env;
  });

program.parse(process.argv);

if (typeof cmdValue === 'undefined') {
   console.error('no command given!');
   process.exit(1);
}
console.log('command:', cmdValue);
console.log('environment:', envValue || "no environment given");

Git-style sub-commands

// file: ./examples/pm
var program = require('..');

program
  .version('0.0.1')
  .command('install [name]', 'install one or more packages')
  .command('search [query]', 'search with optional query')
  .command('list', 'list packages installed', {isDefault: true})
  .parse(process.argv);

When .command() is invoked with a description argument, no .action(callback) should be called to handle sub-commands, otherwise there will be an error. This tells commander that you're going to use separate executables for sub-commands, much like git(1) and other popular tools.
The commander will try to search the executables in the directory of the entry script (like ./examples/pm) with the name program-command, like pm-install, pm-search.

Options can be passed with the call to .command(). Specifying true for opts.noHelp will remove the option from the generated help output. Specifying true for opts.isDefault will run the subcommand if no other subcommand is specified.

If the program is designed to be installed globally, make sure the executables have proper modes, like 755.

--harmony

You can enable --harmony option in two ways:

  • Use #! /usr/bin/env node --harmony in the sub-commands scripts. Note some os version don’t support this pattern.
  • Use the --harmony option when call the command, like node --harmony examples/pm publish. The --harmony option will be preserved when spawning sub-command process.

Automated --help

The help information is auto-generated based on the information commander already knows about your program, so the following --help info is for free:

 $ ./examples/pizza --help

   Usage: pizza [options]

   An application for pizzas ordering

   Options:

     -h, --help           output usage information
     -V, --version        output the version number
     -p, --peppers        Add peppers
     -P, --pineapple      Add pineapple
     -b, --bbq            Add bbq sauce
     -c, --cheese <type>  Add the specified type of cheese [marble]
     -C, --no-cheese      You do not want any cheese

Custom help

You can display arbitrary -h, --help information by listening for "--help". Commander will automatically exit once you are done so that the remainder of your program does not execute causing undesired behaviours, for example in the following executable "stuff" will not output when --help is used.

#!/usr/bin/env node

/**
 * Module dependencies.
 */

var program = require('commander');

program
  .version('0.0.1')
  .option('-f, --foo', 'enable some foo')
  .option('-b, --bar', 'enable some bar')
  .option('-B, --baz', 'enable some baz');

// must be before .parse() since
// node's emit() is immediate

program.on('--help', function(){
  console.log('  Examples:');
  console.log('');
  console.log('    $ custom-help --help');
  console.log('    $ custom-help -h');
  console.log('');
});

program.parse(process.argv);

console.log('stuff');

Yields the following help output when node script-name.js -h or node script-name.js --help are run:


Usage: custom-help [options]

Options:

  -h, --help     output usage information
  -V, --version  output the version number
  -f, --foo      enable some foo
  -b, --bar      enable some bar
  -B, --baz      enable some baz

Examples:

  $ custom-help --help
  $ custom-help -h

.outputHelp(cb)

Output help information without exiting. Optional callback cb allows post-processing of help text before it is displayed.

If you want to display help by default (e.g. if no command was provided), you can use something like:

var program = require('commander');
var colors = require('colors');

program
  .version('0.0.1')
  .command('getstream [url]', 'get stream URL')
  .parse(process.argv);

  if (!process.argv.slice(2).length) {
    program.outputHelp(make_red);
  }

function make_red(txt) {
  return colors.red(txt); //display the help text in red on the console
}

.help(cb)

Output help information and exit immediately. Optional callback cb allows post-processing of help text before it is displayed.

Examples

var program = require('commander');

program
  .version('0.0.1')
  .option('-C, --chdir <path>', 'change the working directory')
  .option('-c, --config <path>', 'set config path. defaults to ./deploy.conf')
  .option('-T, --no-tests', 'ignore test hook')

program
  .command('setup [env]')
  .description('run setup commands for all envs')
  .option("-s, --setup_mode [mode]", "Which setup mode to use")
  .action(function(env, options){
    var mode = options.setup_mode || "normal";
    env = env || 'all';
    console.log('setup for %s env(s) with %s mode', env, mode);
  });

program
  .command('exec <cmd>')
  .alias('ex')
  .description('execute the given remote cmd')
  .option("-e, --exec_mode <mode>", "Which exec mode to use")
  .action(function(cmd, options){
    console.log('exec "%s" using %s mode', cmd, options.exec_mode);
  }).on('--help', function() {
    console.log('  Examples:');
    console.log();
    console.log('    $ deploy exec sequential');
    console.log('    $ deploy exec async');
    console.log();
  });

program
  .command('*')
  .action(function(env){
    console.log('deploying "%s"', env);
  });

program.parse(process.argv);

More Demos can be found in the examples directory.

License

MIT

diff --git a/lib/util.js b/lib/util.js
index a03e874..9074e8e 100644
--- a/lib/util.js
+++ b/lib/util.js
@@ -19,430 +19,6 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
-var formatRegExp = /%[sdj%]/g;
-exports.format = function(f) {
- if (!isString(f)) {
- var objects = [];
- for (var i = 0; i < arguments.length; i++) {
- objects.push(inspect(arguments[i]));
- }
- return objects.join(' ');
- }
-
- var i = 1;
- var args = arguments;
- var len = args.length;
- var str = String(f).replace(formatRegExp, function(x) {
- if (x === '%%') return '%';
- if (i >= len) return x;
- switch (x) {
- case '%s': return String(args[i++]);
- case '%d': return Number(args[i++]);
- case '%j':
- try {
- return JSON.stringify(args[i++]);
- } catch (_) {
- return '[Circular]';
- }
- default:
- return x;
- }
- });
- for (var x = args[i]; i < len; x = args[++i]) {
- if (isNull(x) || !isObject(x)) {
- str += ' ' + x;
- } else {
- str += ' ' + inspect(x);
- }
- }
- return str;
-};
-
-
-// Mark that a method should not be used.
-// Returns a modified function which warns once by default.
-// If --no-deprecation is set, then it is a no-op.
-exports.deprecate = function(fn, msg) {
- // Allow for deprecating things in the process of starting up.
- if (isUndefined(global.process)) {
- return function() {
- return exports.deprecate(fn, msg).apply(this, arguments);
- };
- }
-
- if (process.noDeprecation === true) {
- return fn;
- }
-
- var warned = false;
- function deprecated() {
- if (!warned) {
- if (process.throwDeprecation) {
- throw new Error(msg);
- } else if (process.traceDeprecation) {
- console.trace(msg);
- } else {
- console.error(msg);
- }
- warned = true;
- }
- return fn.apply(this, arguments);
- }
-
- return deprecated;
-};
-
-
-var debugs = {};
-var debugEnviron;
-exports.debuglog = function(set) {
- if (isUndefined(debugEnviron))
- debugEnviron = process.env.NODE_DEBUG || '';
- set = set.toUpperCase();
- if (!debugs[set]) {
- if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) {
- var pid = process.pid;
- debugs[set] = function() {
- var msg = exports.format.apply(exports, arguments);
- console.error('%s %d: %s', set, pid, msg);
- };
- } else {
- debugs[set] = function() {};
- }
- }
- return debugs[set];
-};
-
-
-/**
- * Echos the value of a value. Trys to print the value out
- * in the best way possible given the different types.
- *
- * @param {Object} obj The object to print out.
- * @param {Object} opts Optional options object that alters the output.
- */
-/* legacy: obj, showHidden, depth, colors*/
-function inspect(obj, opts) {
- // default options
- var ctx = {
- seen: [],
- stylize: stylizeNoColor
- };
- // legacy...
- if (arguments.length >= 3) ctx.depth = arguments[2];
- if (arguments.length >= 4) ctx.colors = arguments[3];
- if (isBoolean(opts)) {
- // legacy...
- ctx.showHidden = opts;
- } else if (opts) {
- // got an "options" object
- exports._extend(ctx, opts);
- }
- // set default options
- if (isUndefined(ctx.showHidden)) ctx.showHidden = false;
- if (isUndefined(ctx.depth)) ctx.depth = 2;
- if (isUndefined(ctx.colors)) ctx.colors = false;
- if (isUndefined(ctx.customInspect)) ctx.customInspect = true;
- if (ctx.colors) ctx.stylize = stylizeWithColor;
- return formatValue(ctx, obj, ctx.depth);
-}
-exports.inspect = inspect;
-
-
-// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics
-inspect.colors = {
- 'bold' : [1, 22],
- 'italic' : [3, 23],
- 'underline' : [4, 24],
- 'inverse' : [7, 27],
- 'white' : [37, 39],
- 'grey' : [90, 39],
- 'black' : [30, 39],
- 'blue' : [34, 39],
- 'cyan' : [36, 39],
- 'green' : [32, 39],
- 'magenta' : [35, 39],
- 'red' : [31, 39],
- 'yellow' : [33, 39]
-};
-
-// Don't use 'blue' not visible on cmd.exe
-inspect.styles = {
- 'special': 'cyan',
- 'number': 'yellow',
- 'boolean': 'yellow',
- 'undefined': 'grey',
- 'null': 'bold',
- 'string': 'green',
- 'date': 'magenta',
- // "name": intentionally not styling
- 'regexp': 'red'
-};
-
-
-function stylizeWithColor(str, styleType) {
- var style = inspect.styles[styleType];
-
- if (style) {
- return '\u001b[' + inspect.colors[style][0] + 'm' + str +
- '\u001b[' + inspect.colors[style][1] + 'm';
- } else {
- return str;
- }
-}
-
-
-function stylizeNoColor(str, styleType) {
- return str;
-}
-
-
-function arrayToHash(array) {
- var hash = {};
-
- array.forEach(function(val, idx) {
- hash[val] = true;
- });
-
- return hash;
-}
-
-
-function formatValue(ctx, value, recurseTimes) {
- // Provide a hook for user-specified inspect functions.
- // Check that value is an object with an inspect function on it
- if (ctx.customInspect &&
- value &&
- isFunction(value.inspect) &&
- // Filter out the util module, it's inspect function is special
- value.inspect !== exports.inspect &&
- // Also filter out any prototype objects using the circular check.
- !(value.constructor && value.constructor.prototype === value)) {
- var ret = value.inspect(recurseTimes, ctx);
- if (!isString(ret)) {
- ret = formatValue(ctx, ret, recurseTimes);
- }
- return ret;
- }
-
- // Primitive types cannot have properties
- var primitive = formatPrimitive(ctx, value);
- if (primitive) {
- return primitive;
- }
-
- // Look up the keys of the object.
- var keys = Object.keys(value);
- var visibleKeys = arrayToHash(keys);
-
- if (ctx.showHidden) {
- keys = Object.getOwnPropertyNames(value);
- }
-
- // Some type of object without properties can be shortcutted.
- if (keys.length === 0) {
- if (isFunction(value)) {
- var name = value.name ? ': ' + value.name : '';
- return ctx.stylize('[Function' + name + ']', 'special');
- }
- if (isRegExp(value)) {
- return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
- }
- if (isDate(value)) {
- return ctx.stylize(Date.prototype.toString.call(value), 'date');
- }
- if (isError(value)) {
- return formatError(value);
- }
- }
-
- var base = '', array = false, braces = ['{', '}'];
-
- // Make Array say that they are Array
- if (isArray(value)) {
- array = true;
- braces = ['[', ']'];
- }
-
- // Make functions say that they are functions
- if (isFunction(value)) {
- var n = value.name ? ': ' + value.name : '';
- base = ' [Function' + n + ']';
- }
-
- // Make RegExps say that they are RegExps
- if (isRegExp(value)) {
- base = ' ' + RegExp.prototype.toString.call(value);
- }
-
- // Make dates with properties first say the date
- if (isDate(value)) {
- base = ' ' + Date.prototype.toUTCString.call(value);
- }
-
- // Make error with message first say the error
- if (isError(value)) {
- base = ' ' + formatError(value);
- }
-
- if (keys.length === 0 && (!array || value.length == 0)) {
- return braces[0] + base + braces[1];
- }
-
- if (recurseTimes < 0) {
- if (isRegExp(value)) {
- return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
- } else {
- return ctx.stylize('[Object]', 'special');
- }
- }
-
- ctx.seen.push(value);
-
- var output;
- if (array) {
- output = formatArray(ctx, value, recurseTimes, visibleKeys, keys);
- } else {
- output = keys.map(function(key) {
- return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array);
- });
- }
-
- ctx.seen.pop();
-
- return reduceToSingleString(output, base, braces);
-}
-
-
-function formatPrimitive(ctx, value) {
- if (isUndefined(value))
- return ctx.stylize('undefined', 'undefined');
- if (isString(value)) {
- var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '')
- .replace(/'/g, "\\'")
- .replace(/\\"/g, '"') + '\'';
- return ctx.stylize(simple, 'string');
- }
- if (isNumber(value)) {
- // Format -0 as '-0'. Strict equality won't distinguish 0 from -0,
- // so instead we use the fact that 1 / -0 < 0 whereas 1 / 0 > 0 .
- if (value === 0 && 1 / value < 0)
- return ctx.stylize('-0', 'number');
- return ctx.stylize('' + value, 'number');
- }
- if (isBoolean(value))
- return ctx.stylize('' + value, 'boolean');
- // For some reason typeof null is "object", so special case here.
- if (isNull(value))
- return ctx.stylize('null', 'null');
-}
-
-
-function formatError(value) {
- return '[' + Error.prototype.toString.call(value) + ']';
-}
-
-
-function formatArray(ctx, value, recurseTimes, visibleKeys, keys) {
- var output = [];
- for (var i = 0, l = value.length; i < l; ++i) {
- if (hasOwnProperty(value, String(i))) {
- output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
- String(i), true));
- } else {
- output.push('');
- }
- }
- keys.forEach(function(key) {
- if (!key.match(/^\d+$/)) {
- output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
- key, true));
- }
- });
- return output;
-}
-
-
-function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) {
- var name, str, desc;
- desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] };
- if (desc.get) {
- if (desc.set) {
- str = ctx.stylize('[Getter/Setter]', 'special');
- } else {
- str = ctx.stylize('[Getter]', 'special');
- }
- } else {
- if (desc.set) {
- str = ctx.stylize('[Setter]', 'special');
- }
- }
- if (!hasOwnProperty(visibleKeys, key)) {
- name = '[' + key + ']';
- }
- if (!str) {
- if (ctx.seen.indexOf(desc.value) < 0) {
- if (isNull(recurseTimes)) {
- str = formatValue(ctx, desc.value, null);
- } else {
- str = formatValue(ctx, desc.value, recurseTimes - 1);
- }
- if (str.indexOf('\n') > -1) {
- if (array) {
- str = str.split('\n').map(function(line) {
- return ' ' + line;
- }).join('\n').substr(2);
- } else {
- str = '\n' + str.split('\n').map(function(line) {
- return ' ' + line;
- }).join('\n');
- }
- }
- } else {
- str = ctx.stylize('[Circular]', 'special');
- }
- }
- if (isUndefined(name)) {
- if (array && key.match(/^\d+$/)) {
- return str;
- }
- name = JSON.stringify('' + key);
- if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) {
- name = name.substr(1, name.length - 2);
- name = ctx.stylize(name, 'name');
- } else {
- name = name.replace(/'/g, "\\'")
- .replace(/\\"/g, '"')
- .replace(/(^"|"$)/g, "'");
- name = ctx.stylize(name, 'string');
- }
- }
-
- return name + ': ' + str;
-}
-
-
-function reduceToSingleString(output, base, braces) {
- var numLinesEst = 0;
- var length = output.reduce(function(prev, cur) {
- numLinesEst++;
- if (cur.indexOf('\n') >= 0) numLinesEst++;
- return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1;
- }, 0);
-
- if (length > 60) {
- return braces[0] +
- (base === '' ? '' : base + '\n ') +
- ' ' +
- output.join(',\n ') +
- ' ' +
- braces[1];
- }
-
- return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1];
-}
-
-
// NOTE: These type checking functions intentionally don't use `instanceof`
// because it is fragile and can be easily faked with `Object.create()`.
function isArray(ar) {
@@ -522,166 +98,10 @@ function isPrimitive(arg) {
exports.isPrimitive = isPrimitive;
function isBuffer(arg) {
- return arg instanceof Buffer;
+ return Buffer.isBuffer(arg);
}
exports.isBuffer = isBuffer;
function objectToString(o) {
return Object.prototype.toString.call(o);
-}
-
-
-function pad(n) {
- return n < 10 ? '0' + n.toString(10) : n.toString(10);
-}
-
-
-var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep',
- 'Oct', 'Nov', 'Dec'];
-
-// 26 Feb 16:19:34
-function timestamp() {
- var d = new Date();
- var time = [pad(d.getHours()),
- pad(d.getMinutes()),
- pad(d.getSeconds())].join(':');
- return [d.getDate(), months[d.getMonth()], time].join(' ');
-}
-
-
-// log is just a thin wrapper to console.log that prepends a timestamp
-exports.log = function() {
- console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments));
-};
-
-
-/**
- * Inherit the prototype methods from one constructor into another.
- *
- * The Function.prototype.inherits from lang.js rewritten as a standalone
- * function (not on Function.prototype). NOTE: If this file is to be loaded
- * during bootstrapping this function needs to be rewritten using some native
- * functions as prototype setup using normal JavaScript does not work as
- * expected during bootstrapping (see mirror.js in r114903).
- *
- * @param {function} ctor Constructor function which needs to inherit the
- * prototype.
- * @param {function} superCtor Constructor function to inherit prototype from.
- */
-exports.inherits = function(ctor, superCtor) {
- ctor.super_ = superCtor;
- ctor.prototype = Object.create(superCtor.prototype, {
- constructor: {
- value: ctor,
- enumerable: false,
- writable: true,
- configurable: true
- }
- });
-};
-
-exports._extend = function(origin, add) {
- // Don't do anything if add isn't an object
- if (!add || !isObject(add)) return origin;
-
- var keys = Object.keys(add);
- var i = keys.length;
- while (i--) {
- origin[keys[i]] = add[keys[i]];
- }
- return origin;
-};
-
-function hasOwnProperty(obj, prop) {
- return Object.prototype.hasOwnProperty.call(obj, prop);
-}
-
-
-// Deprecated old stuff.
-
-exports.p = exports.deprecate(function() {
- for (var i = 0, len = arguments.length; i < len; ++i) {
- console.error(exports.inspect(arguments[i]));
- }
-}, 'util.p: Use console.error() instead');
-
-
-exports.exec = exports.deprecate(function() {
- return require('child_process').exec.apply(this, arguments);
-}, 'util.exec is now called `child_process.exec`.');
-
-
-exports.print = exports.deprecate(function() {
- for (var i = 0, len = arguments.length; i < len; ++i) {
- process.stdout.write(String(arguments[i]));
- }
-}, 'util.print: Use console.log instead');
-
-
-exports.puts = exports.deprecate(function() {
- for (var i = 0, len = arguments.length; i < len; ++i) {
- process.stdout.write(arguments[i] + '\n');
- }
-}, 'util.puts: Use console.log instead');
-
-
-exports.debug = exports.deprecate(function(x) {
- process.stderr.write('DEBUG: ' + x + '\n');
-}, 'util.debug: Use console.error instead');
-
-
-exports.error = exports.deprecate(function(x) {
- for (var i = 0, len = arguments.length; i < len; ++i) {
- process.stderr.write(arguments[i] + '\n');
- }
-}, 'util.error: Use console.error instead');
-
-
-exports.pump = exports.deprecate(function(readStream, writeStream, callback) {
- var callbackCalled = false;
-
- function call(a, b, c) {
- if (callback && !callbackCalled) {
- callback(a, b, c);
- callbackCalled = true;
- }
- }
-
- readStream.addListener('data', function(chunk) {
- if (writeStream.write(chunk) === false) readStream.pause();
- });
-
- writeStream.addListener('drain', function() {
- readStream.resume();
- });
-
- readStream.addListener('end', function() {
- writeStream.end();
- });
-
- readStream.addListener('close', function() {
- call();
- });
-
- readStream.addListener('error', function(err) {
- writeStream.end();
- call(err);
- });
-
- writeStream.addListener('error', function(err) {
- readStream.destroy();
- call(err);
- });
-}, 'util.pump(): Use readableStream.pipe() instead');
-
-
-var uv;
-exports._errnoException = function(err, syscall) {
- if (isUndefined(uv)) uv = process.binding('uv');
- var errname = uv.errname(err);
- var e = new Error(syscall + ' ' + errname);
- e.code = errname;
- e.errno = errname;
- e.syscall = syscall;
- return e;
-};
+}
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
// NOTE: These type checking functions intentionally don't use `instanceof`
// because it is fragile and can be easily faked with `Object.create()`.
function isArray(arg) {
if (Array.isArray) {
return Array.isArray(arg);
}
return objectToString(arg) === '[object Array]';
}
exports.isArray = isArray;
function isBoolean(arg) {
return typeof arg === 'boolean';
}
exports.isBoolean = isBoolean;
function isNull(arg) {
return arg === null;
}
exports.isNull = isNull;
function isNullOrUndefined(arg) {
return arg == null;
}
exports.isNullOrUndefined = isNullOrUndefined;
function isNumber(arg) {
return typeof arg === 'number';
}
exports.isNumber = isNumber;
function isString(arg) {
return typeof arg === 'string';
}
exports.isString = isString;
function isSymbol(arg) {
return typeof arg === 'symbol';
}
exports.isSymbol = isSymbol;
function isUndefined(arg) {
return arg === void 0;
}
exports.isUndefined = isUndefined;
function isRegExp(re) {
return objectToString(re) === '[object RegExp]';
}
exports.isRegExp = isRegExp;
function isObject(arg) {
return typeof arg === 'object' && arg !== null;
}
exports.isObject = isObject;
function isDate(d) {
return objectToString(d) === '[object Date]';
}
exports.isDate = isDate;
function isError(e) {
return (objectToString(e) === '[object Error]' || e instanceof Error);
}
exports.isError = isError;
function isFunction(arg) {
return typeof arg === 'function';
}
exports.isFunction = isFunction;
function isPrimitive(arg) {
return arg === null ||
typeof arg === 'boolean' ||
typeof arg === 'number' ||
typeof arg === 'string' ||
typeof arg === 'symbol' || // ES6 symbol
typeof arg === 'undefined';
}
exports.isPrimitive = isPrimitive;
exports.isBuffer = Buffer.isBuffer;
function objectToString(o) {
return Object.prototype.toString.call(o);
}
Copyright Node.js contributors. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
{
"_args": [
[
{
"raw": "core-util-is@~1.0.0",
"scope": null,
"escapedName": "core-util-is",
"name": "core-util-is",
"rawSpec": "~1.0.0",
"spec": ">=1.0.0 <1.1.0",
"type": "range"
},
"F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\readable-stream"
]
],
"_from": "core-util-is@>=1.0.0 <1.1.0",
"_id": "core-util-is@1.0.2",
"_inCache": true,
"_location": "/core-util-is",
"_nodeVersion": "4.0.0",
"_npmUser": {
"name": "isaacs",
"email": "i@izs.me"
},
"_npmVersion": "3.3.2",
"_phantomChildren": {},
"_requested": {
"raw": "core-util-is@~1.0.0",
"scope": null,
"escapedName": "core-util-is",
"name": "core-util-is",
"rawSpec": "~1.0.0",
"spec": ">=1.0.0 <1.1.0",
"type": "range"
},
"_requiredBy": [
"/readable-stream"
],
"_resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"_shasum": "b5fd54220aa2bc5ab57aab7140c940754503c1a7",
"_shrinkwrap": null,
"_spec": "core-util-is@~1.0.0",
"_where": "F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\readable-stream",
"author": {
"name": "Isaac Z. Schlueter",
"email": "i@izs.me",
"url": "http://blog.izs.me/"
},
"bugs": {
"url": "https://github.com/isaacs/core-util-is/issues"
},
"dependencies": {},
"description": "The `util.is*` functions introduced in Node v0.12.",
"devDependencies": {
"tap": "^2.3.0"
},
"directories": {},
"dist": {
"shasum": "b5fd54220aa2bc5ab57aab7140c940754503c1a7",
"tarball": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz"
},
"gitHead": "a177da234df5638b363ddc15fa324619a38577c8",
"homepage": "https://github.com/isaacs/core-util-is#readme",
"keywords": [
"util",
"isBuffer",
"isArray",
"isNumber",
"isString",
"isRegExp",
"isThis",
"isThat",
"polyfill"
],
"license": "MIT",
"main": "lib/util.js",
"maintainers": [
{
"name": "isaacs",
"email": "i@izs.me"
}
],
"name": "core-util-is",
"optionalDependencies": {},
"readme": "ERROR: No README data found!",
"repository": {
"type": "git",
"url": "git://github.com/isaacs/core-util-is.git"
},
"scripts": {
"test": "tap test.js"
},
"version": "1.0.2"
}

core-util-is

The util.is* functions introduced in Node v0.12.

var assert = require('tap');
var t = require('./lib/util');
assert.equal(t.isArray([]), true);
assert.equal(t.isArray({}), false);
assert.equal(t.isBoolean(null), false);
assert.equal(t.isBoolean(true), true);
assert.equal(t.isBoolean(false), true);
assert.equal(t.isNull(null), true);
assert.equal(t.isNull(undefined), false);
assert.equal(t.isNull(false), false);
assert.equal(t.isNull(), false);
assert.equal(t.isNullOrUndefined(null), true);
assert.equal(t.isNullOrUndefined(undefined), true);
assert.equal(t.isNullOrUndefined(false), false);
assert.equal(t.isNullOrUndefined(), true);
assert.equal(t.isNumber(null), false);
assert.equal(t.isNumber('1'), false);
assert.equal(t.isNumber(1), true);
assert.equal(t.isString(null), false);
assert.equal(t.isString('1'), true);
assert.equal(t.isString(1), false);
assert.equal(t.isSymbol(null), false);
assert.equal(t.isSymbol('1'), false);
assert.equal(t.isSymbol(1), false);
assert.equal(t.isSymbol(Symbol()), true);
assert.equal(t.isUndefined(null), false);
assert.equal(t.isUndefined(undefined), true);
assert.equal(t.isUndefined(false), false);
assert.equal(t.isUndefined(), true);
assert.equal(t.isRegExp(null), false);
assert.equal(t.isRegExp('1'), false);
assert.equal(t.isRegExp(new RegExp()), true);
assert.equal(t.isObject({}), true);
assert.equal(t.isObject([]), true);
assert.equal(t.isObject(new RegExp()), true);
assert.equal(t.isObject(new Date()), true);
assert.equal(t.isDate(null), false);
assert.equal(t.isDate('1'), false);
assert.equal(t.isDate(new Date()), true);
assert.equal(t.isError(null), false);
assert.equal(t.isError({ err: true }), false);
assert.equal(t.isError(new Error()), true);
assert.equal(t.isFunction(null), false);
assert.equal(t.isFunction({ }), false);
assert.equal(t.isFunction(function() {}), true);
assert.equal(t.isPrimitive(null), true);
assert.equal(t.isPrimitive(''), true);
assert.equal(t.isPrimitive(0), true);
assert.equal(t.isPrimitive(new Date()), false);
assert.equal(t.isBuffer(null), false);
assert.equal(t.isBuffer({}), false);
assert.equal(t.isBuffer(new Buffer(0)), true);
.idea
*.iml
npm-debug.log
dump.rdb
node_modules
results.tap
results.xml
npm-shrinkwrap.json
config.json
.DS_Store
*/.DS_Store
*/*/.DS_Store
._*
*/._*
*/*/._*
coverage.*
lib-cov
language: node_js
node_js:
- 0.10
- 4.0
sudo: false
// Load modules
var Crypto = require('crypto');
var Boom = require('boom');
// Declare internals
var internals = {};
// Generate a cryptographically strong pseudo-random data
exports.randomString = function (size) {
var buffer = exports.randomBits((size + 1) * 6);
if (buffer instanceof Error) {
return buffer;
}
var string = buffer.toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/\=/g, '');
return string.slice(0, size);
};
exports.randomBits = function (bits) {
if (!bits ||
bits < 0) {
return Boom.internal('Invalid random bits count');
}
var bytes = Math.ceil(bits / 8);
try {
return Crypto.randomBytes(bytes);
}
catch (err) {
return Boom.internal('Failed generating random bits: ' + err.message);
}
};
// Compare two strings using fixed time algorithm (to prevent time-based analysis of MAC digest match)
exports.fixedTimeComparison = function (a, b) {
if (typeof a !== 'string' ||
typeof b !== 'string') {
return false;
}
var mismatch = (a.length === b.length ? 0 : 1);
if (mismatch) {
b = a;
}
for (var i = 0, il = a.length; i < il; ++i) {
var ac = a.charCodeAt(i);
var bc = b.charCodeAt(i);
mismatch |= (ac ^ bc);
}
return (mismatch === 0);
};
Copyright (c) 2014, Eran Hammer and other contributors.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* The names of any contributors may not be used to endorse or promote
products derived from this software without specific prior written
permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* * *
The complete list of contributors can be found at: https://github.com/hueniverse/cryptiles/graphs/contributors
{
"_args": [
[
{
"raw": "cryptiles@2.x.x",
"scope": null,
"escapedName": "cryptiles",
"name": "cryptiles",
"rawSpec": "2.x.x",
"spec": ">=2.0.0 <3.0.0",
"type": "range"
},
"F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\hawk"
]
],
"_from": "cryptiles@>=2.0.0 <3.0.0",
"_id": "cryptiles@2.0.5",
"_inCache": true,
"_location": "/cryptiles",
"_nodeVersion": "4.0.0",
"_npmUser": {
"name": "hueniverse",
"email": "eran@hammer.io"
},
"_npmVersion": "2.14.2",
"_phantomChildren": {},
"_requested": {
"raw": "cryptiles@2.x.x",
"scope": null,
"escapedName": "cryptiles",
"name": "cryptiles",
"rawSpec": "2.x.x",
"spec": ">=2.0.0 <3.0.0",
"type": "range"
},
"_requiredBy": [
"/hawk"
],
"_resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz",
"_shasum": "3bdfecdc608147c1c67202fa291e7dca59eaa3b8",
"_shrinkwrap": null,
"_spec": "cryptiles@2.x.x",
"_where": "F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\hawk",
"bugs": {
"url": "https://github.com/hapijs/cryptiles/issues"
},
"dependencies": {
"boom": "2.x.x"
},
"description": "General purpose crypto utilities",
"devDependencies": {
"code": "1.x.x",
"lab": "5.x.x"
},
"directories": {},
"dist": {
"shasum": "3bdfecdc608147c1c67202fa291e7dca59eaa3b8",
"tarball": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz"
},
"engines": {
"node": ">=0.10.40"
},
"gitHead": "9bc5a852f01cd51e615814e1cb255fe2df810649",
"homepage": "https://github.com/hapijs/cryptiles#readme",
"keywords": [
"cryptography",
"security",
"utilites"
],
"license": "BSD-3-Clause",
"main": "lib/index.js",
"maintainers": [
{
"name": "hueniverse",
"email": "eran@hueniverse.com"
},
{
"name": "ceejbot",
"email": "ceejceej@gmail.com"
}
],
"name": "cryptiles",
"optionalDependencies": {},
"readme": "ERROR: No README data found!",
"repository": {
"type": "git",
"url": "git://github.com/hapijs/cryptiles.git"
},
"scripts": {
"test": "lab -a code -t 100 -L",
"test-cov-html": "lab -a code -r html -o coverage.html"
},
"version": "2.0.5"
}

cryptiles

General purpose crypto utilities

Build Status

Lead Maintainer - C J Silverio

Methods

randomString(<Number> size)

Returns a cryptographically strong pseudo-random data string. Takes a size argument for the length of the string.

fixedTimeComparison(<String> a, <String> b)

Compare two strings using fixed time algorithm (to prevent time-based analysis of MAC digest match). Returns true if the strings match, false if they differ.

// Load modules
var Code = require('code');
var Cryptiles = require('..');
var Lab = require('lab');
// Declare internals
var internals = {};
// Test shortcuts
var lab = exports.lab = Lab.script();
var describe = lab.describe;
var it = lab.it;
var expect = Code.expect;
describe('randomString()', function () {
it('should generate the right length string', function (done) {
for (var i = 1; i <= 1000; ++i) {
expect(Cryptiles.randomString(i).length).to.equal(i);
}
done();
});
it('returns an error on invalid bits size', function (done) {
expect(Cryptiles.randomString(99999999999999999999).message).to.match(/Failed generating random bits/);
done();
});
});
describe('randomBits()', function () {
it('returns an error on invalid input', function (done) {
expect(Cryptiles.randomBits(0).message).to.equal('Invalid random bits count');
done();
});
});
describe('fixedTimeComparison()', function () {
var a = Cryptiles.randomString(50000);
var b = Cryptiles.randomString(150000);
it('should take the same amount of time comparing different string sizes', function (done) {
var now = Date.now();
Cryptiles.fixedTimeComparison(b, a);
var t1 = Date.now() - now;
now = Date.now();
Cryptiles.fixedTimeComparison(b, b);
var t2 = Date.now() - now;
expect(t2 - t1).to.be.within(-20, 20);
done();
});
it('should return true for equal strings', function (done) {
expect(Cryptiles.fixedTimeComparison(a, a)).to.equal(true);
done();
});
it('should return false for different strings (size, a < b)', function (done) {
expect(Cryptiles.fixedTimeComparison(a, a + 'x')).to.equal(false);
done();
});
it('should return false for different strings (size, a > b)', function (done) {
expect(Cryptiles.fixedTimeComparison(a + 'x', a)).to.equal(false);
done();
});
it('should return false for different strings (size, a = b)', function (done) {
expect(Cryptiles.fixedTimeComparison(a + 'x', a + 'y')).to.equal(false);
done();
});
it('should return false when not a string', function (done) {
expect(Cryptiles.fixedTimeComparison('x', null)).to.equal(false);
done();
});
it('should return false when not a string (left)', function (done) {
expect(Cryptiles.fixedTimeComparison(null, 'x')).to.equal(false);
done();
});
});
"use strict";
module.exports = CSSselect;
var Pseudos = require("./lib/pseudos.js"),
DomUtils = require("domutils"),
findOne = DomUtils.findOne,
findAll = DomUtils.findAll,
getChildren = DomUtils.getChildren,
removeSubsets = DomUtils.removeSubsets,
falseFunc = require("boolbase").falseFunc,
compile = require("./lib/compile.js"),
compileUnsafe = compile.compileUnsafe,
compileToken = compile.compileToken;
function getSelectorFunc(searchFunc){
return function select(query, elems, options){
if(typeof query !== "function") query = compileUnsafe(query, options, elems);
if(!Array.isArray(elems)) elems = getChildren(elems);
else elems = removeSubsets(elems);
return searchFunc(query, elems);
};
}
var selectAll = getSelectorFunc(function selectAll(query, elems){
return (query === falseFunc || !elems || elems.length === 0) ? [] : findAll(query, elems);
});
var selectOne = getSelectorFunc(function selectOne(query, elems){
return (query === falseFunc || !elems || elems.length === 0) ? null : findOne(query, elems);
});
function is(elem, query, options){
return (typeof query === "function" ? query : compile(query, options))(elem);
}
/*
the exported interface
*/
function CSSselect(query, elems, options){
return selectAll(query, elems, options);
}
CSSselect.compile = compile;
CSSselect.filters = Pseudos.filters;
CSSselect.pseudos = Pseudos.pseudos;
CSSselect.selectAll = selectAll;
CSSselect.selectOne = selectOne;
CSSselect.is = is;
//legacy methods (might be removed)
CSSselect.parse = compile;
CSSselect.iterate = selectAll;
//hooks
CSSselect._compileUnsafe = compileUnsafe;
CSSselect._compileToken = compileToken;
var DomUtils = require("domutils"),
hasAttrib = DomUtils.hasAttrib,
getAttributeValue = DomUtils.getAttributeValue,
falseFunc = require("boolbase").falseFunc;
//https://github.com/slevithan/XRegExp/blob/master/src/xregexp.js#L469
var reChars = /[-[\]{}()*+?.,\\^$|#\s]/g;
/*
attribute selectors
*/
var attributeRules = {
__proto__: null,
equals: function(next, data){
var name = data.name,
value = data.value;
if(data.ignoreCase){
value = value.toLowerCase();
return function equalsIC(elem){
var attr = getAttributeValue(elem, name);
return attr != null && attr.toLowerCase() === value && next(elem);
};
}
return function equals(elem){
return getAttributeValue(elem, name) === value && next(elem);
};
},
hyphen: function(next, data){
var name = data.name,
value = data.value,
len = value.length;
if(data.ignoreCase){
value = value.toLowerCase();
return function hyphenIC(elem){
var attr = getAttributeValue(elem, name);
return attr != null &&
(attr.length === len || attr.charAt(len) === "-") &&
attr.substr(0, len).toLowerCase() === value &&
next(elem);
};
}
return function hyphen(elem){
var attr = getAttributeValue(elem, name);
return attr != null &&
attr.substr(0, len) === value &&
(attr.length === len || attr.charAt(len) === "-") &&
next(elem);
};
},
element: function(next, data){
var name = data.name,
value = data.value;
if(/\s/.test(value)){
return falseFunc;
}
value = value.replace(reChars, "\\$&");
var pattern = "(?:^|\\s)" + value + "(?:$|\\s)",
flags = data.ignoreCase ? "i" : "",
regex = new RegExp(pattern, flags);
return function element(elem){
var attr = getAttributeValue(elem, name);
return attr != null && regex.test(attr) && next(elem);
};
},
exists: function(next, data){
var name = data.name;
return function exists(elem){
return hasAttrib(elem, name) && next(elem);
};
},
start: function(next, data){
var name = data.name,
value = data.value,
len = value.length;
if(len === 0){
return falseFunc;
}
if(data.ignoreCase){
value = value.toLowerCase();
return function startIC(elem){
var attr = getAttributeValue(elem, name);
return attr != null && attr.substr(0, len).toLowerCase() === value && next(elem);
};
}
return function start(elem){
var attr = getAttributeValue(elem, name);
return attr != null && attr.substr(0, len) === value && next(elem);
};
},
end: function(next, data){
var name = data.name,
value = data.value,
len = -value.length;
if(len === 0){
return falseFunc;
}
if(data.ignoreCase){
value = value.toLowerCase();
return function endIC(elem){
var attr = getAttributeValue(elem, name);
return attr != null && attr.substr(len).toLowerCase() === value && next(elem);
};
}
return function end(elem){
var attr = getAttributeValue(elem, name);
return attr != null && attr.substr(len) === value && next(elem);
};
},
any: function(next, data){
var name = data.name,
value = data.value;
if(value === ""){
return falseFunc;
}
if(data.ignoreCase){
var regex = new RegExp(value.replace(reChars, "\\$&"), "i");
return function anyIC(elem){
var attr = getAttributeValue(elem, name);
return attr != null && regex.test(attr) && next(elem);
};
}
return function any(elem){
var attr = getAttributeValue(elem, name);
return attr != null && attr.indexOf(value) >= 0 && next(elem);
};
},
not: function(next, data){
var name = data.name,
value = data.value;
if(value === ""){
return function notEmpty(elem){
return !!getAttributeValue(elem, name) && next(elem);
};
} else if(data.ignoreCase){
value = value.toLowerCase();
return function notIC(elem){
var attr = getAttributeValue(elem, name);
return attr != null && attr.toLowerCase() !== value && next(elem);
};
}
return function not(elem){
return getAttributeValue(elem, name) !== value && next(elem);
};
}
};
module.exports = {
compile: function(next, data, options){
if(options && options.strict && (
data.ignoreCase || data.action === "not"
)) throw SyntaxError("Unsupported attribute selector");
return attributeRules[data.action](next, data);
},
rules: attributeRules
};
/*
compiles a selector to an executable function
*/
module.exports = compile;
module.exports.compileUnsafe = compileUnsafe;
module.exports.compileToken = compileToken;
var parse = require("css-what"),
DomUtils = require("domutils"),
isTag = DomUtils.isTag,
Rules = require("./general.js"),
sortRules = require("./sort.js"),
BaseFuncs = require("boolbase"),
trueFunc = BaseFuncs.trueFunc,
falseFunc = BaseFuncs.falseFunc,
procedure = require("./procedure.json");
function compile(selector, options, context){
var next = compileUnsafe(selector, options, context);
return wrap(next);
}
function wrap(next){
return function base(elem){
return isTag(elem) && next(elem);
};
}
function compileUnsafe(selector, options, context){
var token = parse(selector, options);
return compileToken(token, options, context);
}
function includesScopePseudo(t){
return t.type === "pseudo" && (
t.name === "scope" || (
Array.isArray(t.data) &&
t.data.some(function(data){
return data.some(includesScopePseudo);
})
)
);
}
var DESCENDANT_TOKEN = {type: "descendant"},
SCOPE_TOKEN = {type: "pseudo", name: "scope"},
PLACEHOLDER_ELEMENT = {},
getParent = DomUtils.getParent;
//CSS 4 Spec (Draft): 3.3.1. Absolutizing a Scope-relative Selector
//http://www.w3.org/TR/selectors4/#absolutizing
function absolutize(token, context){
//TODO better check if context is document
var hasContext = !!context && !!context.length && context.every(function(e){
return e === PLACEHOLDER_ELEMENT || !!getParent(e);
});
token.forEach(function(t){
if(t.length > 0 && isTraversal(t[0]) && t[0].type !== "descendant"){
//don't return in else branch
} else if(hasContext && !includesScopePseudo(t)){
t.unshift(DESCENDANT_TOKEN);
} else {
return;
}
t.unshift(SCOPE_TOKEN);
});
}
function compileToken(token, options, context){
token = token.filter(function(t){ return t.length > 0; });
token.forEach(sortRules);
var isArrayContext = Array.isArray(context);
context = (options && options.context) || context;
if(context && !isArrayContext) context = [context];
absolutize(token, context);
return token
.map(function(rules){ return compileRules(rules, options, context, isArrayContext); })
.reduce(reduceRules, falseFunc);
}
function isTraversal(t){
return procedure[t.type] < 0;
}
function compileRules(rules, options, context, isArrayContext){
var acceptSelf = (isArrayContext && rules[0].name === "scope" && rules[1].type === "descendant");
return rules.reduce(function(func, rule, index){
if(func === falseFunc) return func;
return Rules[rule.type](func, rule, options, context, acceptSelf && index === 1);
}, options && options.rootFunc || trueFunc);
}
function reduceRules(a, b){
if(b === falseFunc || a === trueFunc){
return a;
}
if(a === falseFunc || b === trueFunc){
return b;
}
return function combine(elem){
return a(elem) || b(elem);
};
}
//:not, :has and :matches have to compile selectors
//doing this in lib/pseudos.js would lead to circular dependencies,
//so we add them here
var Pseudos = require("./pseudos.js"),
filters = Pseudos.filters,
existsOne = DomUtils.existsOne,
isTag = DomUtils.isTag,
getChildren = DomUtils.getChildren;
function containsTraversal(t){
return t.some(isTraversal);
}
filters.not = function(next, token, options, context){
var opts = {
xmlMode: !!(options && options.xmlMode),
strict: !!(options && options.strict)
};
if(opts.strict){
if(token.length > 1 || token.some(containsTraversal)){
throw new SyntaxError("complex selectors in :not aren't allowed in strict mode");
}
}
var func = compileToken(token, opts, context);
if(func === falseFunc) return next;
if(func === trueFunc) return falseFunc;
return function(elem){
return !func(elem) && next(elem);
};
};
filters.has = function(next, token, options){
var opts = {
xmlMode: !!(options && options.xmlMode),
strict: !!(options && options.strict)
};
//FIXME: Uses an array as a pointer to the current element (side effects)
var context = token.some(containsTraversal) ? [PLACEHOLDER_ELEMENT] : null;
var func = compileToken(token, opts, context);
if(func === falseFunc) return falseFunc;
if(func === trueFunc) return function(elem){
return getChildren(elem).some(isTag) && next(elem);
};
func = wrap(func);
if(context){
return function has(elem){
return next(elem) && (
(context[0] = elem), existsOne(func, getChildren(elem))
);
};
}
return function has(elem){
return next(elem) && existsOne(func, getChildren(elem));
};
};
filters.matches = function(next, token, options, context){
var opts = {
xmlMode: !!(options && options.xmlMode),
strict: !!(options && options.strict),
rootFunc: next
};
return compileToken(token, opts, context);
};
var DomUtils = require("domutils"),
isTag = DomUtils.isTag,
getParent = DomUtils.getParent,
getChildren = DomUtils.getChildren,
getSiblings = DomUtils.getSiblings,
getName = DomUtils.getName;
/*
all available rules
*/
module.exports = {
__proto__: null,
attribute: require("./attributes.js").compile,
pseudo: require("./pseudos.js").compile,
//tags
tag: function(next, data){
var name = data.name;
return function tag(elem){
return getName(elem) === name && next(elem);
};
},
//traversal
descendant: function(next, rule, options, context, acceptSelf){
return function descendant(elem){
if (acceptSelf && next(elem)) return true;
var found = false;
while(!found && (elem = getParent(elem))){
found = next(elem);
}
return found;
};
},
parent: function(next, data, options){
if(options && options.strict) throw SyntaxError("Parent selector isn't part of CSS3");
return function parent(elem){
return getChildren(elem).some(test);
};
function test(elem){
return isTag(elem) && next(elem);
}
},
child: function(next){
return function child(elem){
var parent = getParent(elem);
return !!parent && next(parent);
};
},
sibling: function(next){
return function sibling(elem){
var siblings = getSiblings(elem);
for(var i = 0; i < siblings.length; i++){
if(isTag(siblings[i])){
if(siblings[i] === elem) break;
if(next(siblings[i])) return true;
}
}
return false;
};
},
adjacent: function(next){
return function adjacent(elem){
var siblings = getSiblings(elem),
lastElement;
for(var i = 0; i < siblings.length; i++){
if(isTag(siblings[i])){
if(siblings[i] === elem) break;
lastElement = siblings[i];
}
}
return !!lastElement && next(lastElement);
};
},
universal: function(next){
return next;
}
};
{
"universal": 50,
"tag": 30,
"attribute": 1,
"pseudo": 0,
"descendant": -1,
"child": -1,
"parent": -1,
"sibling": -1,
"adjacent": -1
}
/*
pseudo selectors
---
they are available in two forms:
* filters called when the selector
is compiled and return a function
that needs to return next()
* pseudos get called on execution
they need to return a boolean
*/
var DomUtils = require("domutils"),
isTag = DomUtils.isTag,
getText = DomUtils.getText,
getParent = DomUtils.getParent,
getChildren = DomUtils.getChildren,
getSiblings = DomUtils.getSiblings,
hasAttrib = DomUtils.hasAttrib,
getName = DomUtils.getName,
getAttribute= DomUtils.getAttributeValue,
getNCheck = require("nth-check"),
checkAttrib = require("./attributes.js").rules.equals,
BaseFuncs = require("boolbase"),
trueFunc = BaseFuncs.trueFunc,
falseFunc = BaseFuncs.falseFunc;
//helper methods
function getFirstElement(elems){
for(var i = 0; elems && i < elems.length; i++){
if(isTag(elems[i])) return elems[i];
}
}
function getAttribFunc(name, value){
var data = {name: name, value: value};
return function attribFunc(next){
return checkAttrib(next, data);
};
}
function getChildFunc(next){
return function(elem){
return !!getParent(elem) && next(elem);
};
}
var filters = {
contains: function(next, text){
return function contains(elem){
return next(elem) && getText(elem).indexOf(text) >= 0;
};
},
icontains: function(next, text){
var itext = text.toLowerCase();
return function icontains(elem){
return next(elem) &&
getText(elem).toLowerCase().indexOf(itext) >= 0;
};
},
//location specific methods
"nth-child": function(next, rule){
var func = getNCheck(rule);
if(func === falseFunc) return func;
if(func === trueFunc) return getChildFunc(next);
return function nthChild(elem){
var siblings = getSiblings(elem);
for(var i = 0, pos = 0; i < siblings.length; i++){
if(isTag(siblings[i])){
if(siblings[i] === elem) break;
else pos++;
}
}
return func(pos) && next(elem);
};
},
"nth-last-child": function(next, rule){
var func = getNCheck(rule);
if(func === falseFunc) return func;
if(func === trueFunc) return getChildFunc(next);
return function nthLastChild(elem){
var siblings = getSiblings(elem);
for(var pos = 0, i = siblings.length - 1; i >= 0; i--){
if(isTag(siblings[i])){
if(siblings[i] === elem) break;
else pos++;
}
}
return func(pos) && next(elem);
};
},
"nth-of-type": function(next, rule){
var func = getNCheck(rule);
if(func === falseFunc) return func;
if(func === trueFunc) return getChildFunc(next);
return function nthOfType(elem){
var siblings = getSiblings(elem);
for(var pos = 0, i = 0; i < siblings.length; i++){
if(isTag(siblings[i])){
if(siblings[i] === elem) break;
if(getName(siblings[i]) === getName(elem)) pos++;
}
}
return func(pos) && next(elem);
};
},
"nth-last-of-type": function(next, rule){
var func = getNCheck(rule);
if(func === falseFunc) return func;
if(func === trueFunc) return getChildFunc(next);
return function nthLastOfType(elem){
var siblings = getSiblings(elem);
for(var pos = 0, i = siblings.length - 1; i >= 0; i--){
if(isTag(siblings[i])){
if(siblings[i] === elem) break;
if(getName(siblings[i]) === getName(elem)) pos++;
}
}
return func(pos) && next(elem);
};
},
//TODO determine the actual root element
root: function(next){
return function(elem){
return !getParent(elem) && next(elem);
};
},
scope: function(next, rule, options, context){
if(!context || context.length === 0){
//equivalent to :root
return filters.root(next);
}
if(context.length === 1){
//NOTE: can't be unpacked, as :has uses this for side-effects
return function(elem){
return context[0] === elem && next(elem);
};
}
return function(elem){
return context.indexOf(elem) >= 0 && next(elem);
};
},
//jQuery extensions (others follow as pseudos)
checkbox: getAttribFunc("type", "checkbox"),
file: getAttribFunc("type", "file"),
password: getAttribFunc("type", "password"),
radio: getAttribFunc("type", "radio"),
reset: getAttribFunc("type", "reset"),
image: getAttribFunc("type", "image"),
submit: getAttribFunc("type", "submit")
};
//while filters are precompiled, pseudos get called when they are needed
var pseudos = {
empty: function(elem){
return !getChildren(elem).some(function(elem){
return isTag(elem) || elem.type === "text";
});
},
"first-child": function(elem){
return getFirstElement(getSiblings(elem)) === elem;
},
"last-child": function(elem){
var siblings = getSiblings(elem);
for(var i = siblings.length - 1; i >= 0; i--){
if(siblings[i] === elem) return true;
if(isTag(siblings[i])) break;
}
return false;
},
"first-of-type": function(elem){
var siblings = getSiblings(elem);
for(var i = 0; i < siblings.length; i++){
if(isTag(siblings[i])){
if(siblings[i] === elem) return true;
if(getName(siblings[i]) === getName(elem)) break;
}
}
return false;
},
"last-of-type": function(elem){
var siblings = getSiblings(elem);
for(var i = siblings.length-1; i >= 0; i--){
if(isTag(siblings[i])){
if(siblings[i] === elem) return true;
if(getName(siblings[i]) === getName(elem)) break;
}
}
return false;
},
"only-of-type": function(elem){
var siblings = getSiblings(elem);
for(var i = 0, j = siblings.length; i < j; i++){
if(isTag(siblings[i])){
if(siblings[i] === elem) continue;
if(getName(siblings[i]) === getName(elem)) return false;
}
}
return true;
},
"only-child": function(elem){
var siblings = getSiblings(elem);
for(var i = 0; i < siblings.length; i++){
if(isTag(siblings[i]) && siblings[i] !== elem) return false;
}
return true;
},
//:matches(a, area, link)[href]
link: function(elem){
return hasAttrib(elem, "href");
},
visited: falseFunc, //seems to be a valid implementation
//TODO: :any-link once the name is finalized (as an alias of :link)
//forms
//to consider: :target
//:matches([selected], select:not([multiple]):not(> option[selected]) > option:first-of-type)
selected: function(elem){
if(hasAttrib(elem, "selected")) return true;
else if(getName(elem) !== "option") return false;
//the first <option> in a <select> is also selected
var parent = getParent(elem);
if(
!parent ||
getName(parent) !== "select" ||
hasAttrib(parent, "multiple")
) return false;
var siblings = getChildren(parent),
sawElem = false;
for(var i = 0; i < siblings.length; i++){
if(isTag(siblings[i])){
if(siblings[i] === elem){
sawElem = true;
} else if(!sawElem){
return false;
} else if(hasAttrib(siblings[i], "selected")){
return false;
}
}
}
return sawElem;
},
//https://html.spec.whatwg.org/multipage/scripting.html#disabled-elements
//:matches(
// :matches(button, input, select, textarea, menuitem, optgroup, option)[disabled],
// optgroup[disabled] > option),
// fieldset[disabled] * //TODO not child of first <legend>
//)
disabled: function(elem){
return hasAttrib(elem, "disabled");
},
enabled: function(elem){
return !hasAttrib(elem, "disabled");
},
//:matches(:matches(:radio, :checkbox)[checked], :selected) (TODO menuitem)
checked: function(elem){
return hasAttrib(elem, "checked") || pseudos.selected(elem);
},
//:matches(input, select, textarea)[required]
required: function(elem){
return hasAttrib(elem, "required");
},
//:matches(input, select, textarea):not([required])
optional: function(elem){
return !hasAttrib(elem, "required");
},
//jQuery extensions
//:not(:empty)
parent: function(elem){
return !pseudos.empty(elem);
},
//:matches(h1, h2, h3, h4, h5, h6)
header: function(elem){
var name = getName(elem);
return name === "h1" ||
name === "h2" ||
name === "h3" ||
name === "h4" ||
name === "h5" ||
name === "h6";
},
//:matches(button, input[type=button])
button: function(elem){
var name = getName(elem);
return name === "button" ||
name === "input" &&
getAttribute(elem, "type") === "button";
},
//:matches(input, textarea, select, button)
input: function(elem){
var name = getName(elem);
return name === "input" ||
name === "textarea" ||
name === "select" ||
name === "button";
},
//input:matches(:not([type!='']), [type='text' i])
text: function(elem){
var attr;
return getName(elem) === "input" && (
!(attr = getAttribute(elem, "type")) ||
attr.toLowerCase() === "text"
);
}
};
function verifyArgs(func, name, subselect){
if(subselect === null){
if(func.length > 1 && name !== "scope"){
throw new SyntaxError("pseudo-selector :" + name + " requires an argument");
}
} else {
if(func.length === 1){
throw new SyntaxError("pseudo-selector :" + name + " doesn't have any arguments");
}
}
}
//FIXME this feels hacky
var re_CSS3 = /^(?:(?:nth|last|first|only)-(?:child|of-type)|root|empty|(?:en|dis)abled|checked|not)$/;
module.exports = {
compile: function(next, data, options, context){
var name = data.name,
subselect = data.data;
if(options && options.strict && !re_CSS3.test(name)){
throw SyntaxError(":" + name + " isn't part of CSS3");
}
if(typeof filters[name] === "function"){
verifyArgs(filters[name], name, subselect);
return filters[name](next, subselect, options, context);
} else if(typeof pseudos[name] === "function"){
var func = pseudos[name];
verifyArgs(func, name, subselect);
if(next === trueFunc) return func;
return function pseudoArgs(elem){
return func(elem, subselect) && next(elem);
};
} else {
throw new SyntaxError("unmatched pseudo-class :" + name);
}
},
filters: filters,
pseudos: pseudos
};
module.exports = sortByProcedure;
/*
sort the parts of the passed selector,
as there is potential for optimization
(some types of selectors are faster than others)
*/
var procedure = require("./procedure.json");
var attributes = {
__proto__: null,
exists: 10,
equals: 8,
not: 7,
start: 6,
end: 6,
any: 5,
hyphen: 4,
element: 4
};
function sortByProcedure(arr){
var procs = arr.map(getProcedure);
for(var i = 1; i < arr.length; i++){
var procNew = procs[i];
if(procNew < 0) continue;
for(var j = i - 1; j >= 0 && procNew < procs[j]; j--){
var token = arr[j + 1];
arr[j + 1] = arr[j];
arr[j] = token;
procs[j + 1] = procs[j];
procs[j] = procNew;
}
}
}
function getProcedure(token){
var proc = procedure[token.type];
if(proc === procedure.attribute){
proc = attributes[token.action];
if(proc === attributes.equals && token.name === "id"){
//prefer ID selectors (eg. #ID)
proc = 9;
}
if(token.ignoreCase){
//ignoreCase adds some overhead, prefer "normal" token
//this is a binary operation, to ensure it's still an int
proc >>= 1;
}
} else if(proc === procedure.pseudo){
if(!token.data){
proc = 3;
} else if(token.name === "has" || token.name === "contains"){
proc = 0; //expensive in any case
} else if(token.name === "matches" || token.name === "not"){
proc = 0;
for(var i = 0; i < token.data.length; i++){
//TODO better handling of complex selectors
if(token.data[i].length !== 1) continue;
var cur = getProcedure(token.data[i][0]);
//avoid executing :has or :contains
if(cur === 0){
proc = 0;
break;
}
if(cur > proc) proc = cur;
}
if(token.data.length > 1 && proc > 0) proc -= 1;
} else {
proc = 1;
}
}
return proc;
}
Copyright (c) Felix Böhm
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{
"_args": [
[
{
"raw": "css-select@~1.2.0",
"scope": null,
"escapedName": "css-select",
"name": "css-select",
"rawSpec": "~1.2.0",
"spec": ">=1.2.0 <1.3.0",
"type": "range"
},
"F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\cheerio"
]
],
"_from": "css-select@>=1.2.0 <1.3.0",
"_id": "css-select@1.2.0",
"_inCache": true,
"_location": "/css-select",
"_nodeVersion": "5.0.0",
"_npmUser": {
"name": "feedic",
"email": "me@feedic.com"
},
"_npmVersion": "3.3.9",
"_phantomChildren": {},
"_requested": {
"raw": "css-select@~1.2.0",
"scope": null,
"escapedName": "css-select",
"name": "css-select",
"rawSpec": "~1.2.0",
"spec": ">=1.2.0 <1.3.0",
"type": "range"
},
"_requiredBy": [
"/cheerio"
],
"_resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz",
"_shasum": "2b3a110539c5355f1cd8d314623e870b121ec858",
"_shrinkwrap": null,
"_spec": "css-select@~1.2.0",
"_where": "F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\cheerio",
"author": {
"name": "Felix Boehm",
"email": "me@feedic.com"
},
"bugs": {
"url": "https://github.com/fb55/css-select/issues"
},
"dependencies": {
"boolbase": "~1.0.0",
"css-what": "2.1",
"domutils": "1.5.1",
"nth-check": "~1.0.1"
},
"description": "a CSS selector compiler/engine",
"devDependencies": {
"cheerio-soupselect": "*",
"coveralls": "*",
"expect.js": "*",
"htmlparser2": "*",
"istanbul": "*",
"jshint": "2",
"mocha": "*",
"mocha-lcov-reporter": "*"
},
"directories": {},
"dist": {
"shasum": "2b3a110539c5355f1cd8d314623e870b121ec858",
"tarball": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz"
},
"files": [
"index.js",
"lib"
],
"gitHead": "09c405d8296bd97a660256604d8cdfb23fca47b6",
"homepage": "https://github.com/fb55/css-select#readme",
"jshintConfig": {
"eqeqeq": true,
"freeze": true,
"latedef": "nofunc",
"noarg": true,
"nonbsp": true,
"quotmark": "double",
"undef": true,
"unused": true,
"trailing": true,
"eqnull": true,
"proto": true,
"smarttabs": true,
"node": true,
"globals": {
"describe": true,
"it": true
}
},
"keywords": [
"css",
"selector",
"sizzle"
],
"license": "BSD-like",
"maintainers": [
{
"name": "feedic",
"email": "me@feedic.com"
}
],
"name": "css-select",
"optionalDependencies": {},
"readme": "ERROR: No README data found!",
"repository": {
"type": "git",
"url": "git://github.com/fb55/css-select.git"
},
"scripts": {
"coveralls": "npm run lint && npm run lcov && (cat coverage/lcov.info | coveralls || exit 0)",
"lcov": "istanbul cover _mocha --report lcovonly -- -R spec",
"lint": "jshint index.js lib/*.js test/*.js",
"test": "mocha && npm run lint"
},
"version": "1.2.0"
}

css-select NPM version Build Status Downloads Coverage

a CSS selector compiler/engine

What?

css-select turns CSS selectors into functions that tests if elements match them. When searching for elements, testing is executed "from the top", similar to how browsers execute CSS selectors.

In its default configuration, css-select queries the DOM structure of the domhandler module (also known as htmlparser2 DOM).

Features:

  • Full implementation of CSS3 selectors
  • Partial implementation of jQuery/Sizzle extensions
  • Very high test coverage
  • Pretty good performance

Why?

The traditional approach of executing CSS selectors, named left-to-right execution, is to execute every component of the selector in order, from left to right (duh). The execution of the selector a b for example will first query for a elements, then search these for b elements. (That's the approach of eg. Sizzle, nwmatcher and qwery.)

While this works, it has some downsides: Children of as will be checked multiple times; first, to check if they are also as, then, for every superior a once, if they are bs. Using Big O notation, that would be O(n^(k+1)), where k is the number of descendant selectors (that's the space in the example above).

The far more efficient approach is to first look for b elements, then check if they have superior a elements: Using big O notation again, that would be O(n). That's called right-to-left execution.

And that's what css-select does – and why it's quite performant.

How does it work?

By building a stack of functions.

Wait, what?

Okay, so let's suppose we want to compile the selector a b again, for right-to-left execution. We start by parsing the selector, which means we turn the selector into an array of the building-blocks of the selector, so we can distinguish them easily. That's what the css-what module is for, if you want to have a look.

Anyway, after parsing, we end up with an array like this one:

[
  { type: 'tag', name: 'a' },
  { type: 'descendant' },
  { type: 'tag', name: 'b' }
]

Actually, this array is wrapped in another array, but that's another story (involving commas in selectors).

Now that we know the meaning of every part of the selector, we can compile it. That's where it becomes interesting.

The basic idea is to turn every part of the selector into a function, which takes an element as its only argument. The function checks whether a passed element matches its part of the selector: If it does, the element is passed to the next turned-into-a-function part of the selector, which does the same. If an element is accepted by all parts of the selector, it matches the selector and double rainbow ALL THE WAY.

As said before, we want to do right-to-left execution with all the big O improvements nonsense, so elements are passed from the rightmost part of the selector (b in our example) to the leftmost (which would be c of course a).

//TODO: More in-depth description. Implementation details. Build a spaceship.

API

var CSSselect = require("css-select");

CSSselect(query, elems, options)

Queries elems, returns an array containing all matches.

  • query can be either a CSS selector or a function.
  • elems can be either an array of elements, or a single element. If it is an element, its children will be queried.
  • options is described below.

Aliases: CSSselect.selectAll(query, elems), CSSselect.iterate(query, elems).

CSSselect.compile(query)

Compiles the query, returns a function.

CSSselect.is(elem, query, options)

Tests whether or not an element is matched by query. query can be either a CSS selector or a function.

CSSselect.selectOne(query, elems, options)

Arguments are the same as for CSSselect(query, elems). Only returns the first match, or null if there was no match.

Options

  • xmlMode: When enabled, tag names will be case-sensitive. Default: false.
  • strict: Limits the module to only use CSS3 selectors. Default: false.
  • rootFunc: The last function in the stack, will be called with the last element that's looked at. Should return true.

Supported selectors

As defined by CSS 4 and / or jQuery.

  • Universal (*)
  • Tag (<tagname>)
  • Descendant ( )
  • Child (>)
  • Parent (<) *
  • Sibling (+)
  • Adjacent (~)
  • Attribute ([attr=foo]), with supported comparisons:
    • [attr] (existential)
    • =
    • ~=
    • |=
    • *=
    • ^=
    • $=
    • != *
    • Also, i can be added after the comparison to make the comparison case-insensitive (eg. [attr=foo i]) *
  • Pseudos:
    • :not
    • :contains *
    • :icontains * (case-insensitive version of :contains)
    • :has *
    • :root
    • :empty
    • :parent *
    • :[first|last]-child[-of-type]
    • :only-of-type, :only-child
    • :nth-[last-]child[-of-type]
    • :link, :visited (the latter doesn't match any elements)
    • :selected *, :checked
    • :enabled, :disabled
    • :required, :optional
    • :header, :button, :input, :text, :checkbox, :file, :password, :reset, :radio etc. *
    • :matches *

*: Not part of CSS3


License: BSD-like

"use strict";
module.exports = parse;
var re_name = /^(?:\\.|[\w\-\u00c0-\uFFFF])+/,
re_escape = /\\([\da-f]{1,6}\s?|(\s)|.)/ig,
//modified version of https://github.com/jquery/sizzle/blob/master/src/sizzle.js#L87
re_attr = /^\s*((?:\\.|[\w\u00c0-\uFFFF\-])+)\s*(?:(\S?)=\s*(?:(['"])(.*?)\3|(#?(?:\\.|[\w\u00c0-\uFFFF\-])*)|)|)\s*(i)?\]/;
var actionTypes = {
__proto__: null,
"undefined": "exists",
"": "equals",
"~": "element",
"^": "start",
"$": "end",
"*": "any",
"!": "not",
"|": "hyphen"
};
var simpleSelectors = {
__proto__: null,
">": "child",
"<": "parent",
"~": "sibling",
"+": "adjacent"
};
var attribSelectors = {
__proto__: null,
"#": ["id", "equals"],
".": ["class", "element"]
};
//pseudos, whose data-property is parsed as well
var unpackPseudos = {
__proto__: null,
"has": true,
"not": true,
"matches": true
};
var stripQuotesFromPseudos = {
__proto__: null,
"contains": true,
"icontains": true
};
var quotes = {
__proto__: null,
"\"": true,
"'": true
};
//unescape function taken from https://github.com/jquery/sizzle/blob/master/src/sizzle.js#L139
function funescape( _, escaped, escapedWhitespace ) {
var high = "0x" + escaped - 0x10000;
// NaN means non-codepoint
// Support: Firefox
// Workaround erroneous numeric interpretation of +"0x"
return high !== high || escapedWhitespace ?
escaped :
// BMP codepoint
high < 0 ?
String.fromCharCode( high + 0x10000 ) :
// Supplemental Plane codepoint (surrogate pair)
String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
}
function unescapeCSS(str){
return str.replace(re_escape, funescape);
}
function isWhitespace(c){
return c === " " || c === "\n" || c === "\t" || c === "\f" || c === "\r";
}
function parse(selector, options){
var subselects = [];
selector = parseSelector(subselects, selector + "", options);
if(selector !== ""){
throw new SyntaxError("Unmatched selector: " + selector);
}
return subselects;
}
function parseSelector(subselects, selector, options){
var tokens = [],
sawWS = false,
data, firstChar, name, quot;
function getName(){
var sub = selector.match(re_name)[0];
selector = selector.substr(sub.length);
return unescapeCSS(sub);
}
function stripWhitespace(start){
while(isWhitespace(selector.charAt(start))) start++;
selector = selector.substr(start);
}
stripWhitespace(0);
while(selector !== ""){
firstChar = selector.charAt(0);
if(isWhitespace(firstChar)){
sawWS = true;
stripWhitespace(1);
} else if(firstChar in simpleSelectors){
tokens.push({type: simpleSelectors[firstChar]});
sawWS = false;
stripWhitespace(1);
} else if(firstChar === ","){
if(tokens.length === 0){
throw new SyntaxError("empty sub-selector");
}
subselects.push(tokens);
tokens = [];
sawWS = false;
stripWhitespace(1);
} else {
if(sawWS){
if(tokens.length > 0){
tokens.push({type: "descendant"});
}
sawWS = false;
}
if(firstChar === "*"){
selector = selector.substr(1);
tokens.push({type: "universal"});
} else if(firstChar in attribSelectors){
selector = selector.substr(1);
tokens.push({
type: "attribute",
name: attribSelectors[firstChar][0],
action: attribSelectors[firstChar][1],
value: getName(),
ignoreCase: false
});
} else if(firstChar === "["){
selector = selector.substr(1);
data = selector.match(re_attr);
if(!data){
throw new SyntaxError("Malformed attribute selector: " + selector);
}
selector = selector.substr(data[0].length);
name = unescapeCSS(data[1]);
if(
!options || (
"lowerCaseAttributeNames" in options ?
options.lowerCaseAttributeNames :
!options.xmlMode
)
){
name = name.toLowerCase();
}
tokens.push({
type: "attribute",
name: name,
action: actionTypes[data[2]],
value: unescapeCSS(data[4] || data[5] || ""),
ignoreCase: !!data[6]
});
} else if(firstChar === ":"){
if(selector.charAt(1) === ":"){
selector = selector.substr(2);
tokens.push({type: "pseudo-element", name: getName().toLowerCase()});
continue;
}
selector = selector.substr(1);
name = getName().toLowerCase();
data = null;
if(selector.charAt(0) === "("){
if(name in unpackPseudos){
quot = selector.charAt(1);
var quoted = quot in quotes;
selector = selector.substr(quoted + 1);
data = [];
selector = parseSelector(data, selector, options);
if(quoted){
if(selector.charAt(0) !== quot){
throw new SyntaxError("unmatched quotes in :" + name);
} else {
selector = selector.substr(1);
}
}
if(selector.charAt(0) !== ")"){
throw new SyntaxError("missing closing parenthesis in :" + name + " " + selector);
}
selector = selector.substr(1);
} else {
var pos = 1, counter = 1;
for(; counter > 0 && pos < selector.length; pos++){
if(selector.charAt(pos) === "(") counter++;
else if(selector.charAt(pos) === ")") counter--;
}
if(counter){
throw new SyntaxError("parenthesis not matched");
}
data = selector.substr(1, pos - 2);
selector = selector.substr(pos);
if(name in stripQuotesFromPseudos){
quot = data.charAt(0);
if(quot === data.slice(-1) && quot in quotes){
data = data.slice(1, -1);
}
data = unescapeCSS(data);
}
}
}
tokens.push({type: "pseudo", name: name, data: data});
} else if(re_name.test(selector)){
name = getName();
if(!options || ("lowerCaseTags" in options ? options.lowerCaseTags : !options.xmlMode)){
name = name.toLowerCase();
}
tokens.push({type: "tag", name: name});
} else {
if(tokens.length && tokens[tokens.length - 1].type === "descendant"){
tokens.pop();
}
addToken(subselects, tokens);
return selector;
}
}
}
addToken(subselects, tokens);
return selector;
}
function addToken(subselects, tokens){
if(subselects.length > 0 && tokens.length === 0){
throw new SyntaxError("empty sub-selector");
}
subselects.push(tokens);
}
Copyright (c) Felix Böhm
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{
"_args": [
[
{
"raw": "css-what@2.1",
"scope": null,
"escapedName": "css-what",
"name": "css-what",
"rawSpec": "2.1",
"spec": ">=2.1.0 <2.2.0",
"type": "range"
},
"F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\css-select"
]
],
"_from": "css-what@>=2.1.0 <2.2.0",
"_id": "css-what@2.1.0",
"_inCache": true,
"_location": "/css-what",
"_nodeVersion": "5.0.0",
"_npmUser": {
"name": "feedic",
"email": "me@feedic.com"
},
"_npmVersion": "3.3.9",
"_phantomChildren": {},
"_requested": {
"raw": "css-what@2.1",
"scope": null,
"escapedName": "css-what",
"name": "css-what",
"rawSpec": "2.1",
"spec": ">=2.1.0 <2.2.0",
"type": "range"
},
"_requiredBy": [
"/css-select"
],
"_resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.0.tgz",
"_shasum": "9467d032c38cfaefb9f2d79501253062f87fa1bd",
"_shrinkwrap": null,
"_spec": "css-what@2.1",
"_where": "F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\css-select",
"author": {
"name": "Felix Böhm",
"email": "me@feedic.com",
"url": "http://feedic.com"
},
"bugs": {
"url": "https://github.com/fb55/css-what/issues"
},
"dependencies": {},
"description": "a CSS selector parser",
"devDependencies": {
"jshint": "2"
},
"directories": {},
"dist": {
"shasum": "9467d032c38cfaefb9f2d79501253062f87fa1bd",
"tarball": "https://registry.npmjs.org/css-what/-/css-what-2.1.0.tgz"
},
"engines": {
"node": "*"
},
"files": [
"index.js"
],
"gitHead": "fd6b9f62146efec8e17ee80ddaebdfb6ede21d7b",
"homepage": "https://github.com/fb55/css-what#readme",
"jshintConfig": {
"eqeqeq": true,
"freeze": true,
"latedef": "nofunc",
"noarg": true,
"nonbsp": true,
"quotmark": "double",
"undef": true,
"unused": true,
"trailing": true,
"eqnull": true,
"proto": true,
"smarttabs": true,
"node": true,
"globals": {
"describe": true,
"it": true
}
},
"license": "BSD-like",
"main": "./index.js",
"maintainers": [
{
"name": "feedic",
"email": "me@feedic.com"
}
],
"name": "css-what",
"optionalDependencies": {},
"readme": "ERROR: No README data found!",
"repository": {
"url": "git+https://github.com/fb55/css-what.git"
},
"scripts": {
"test": "node tests/test.js && jshint *.js"
},
"version": "2.1.0"
}

css-what Build Status

a CSS selector parser

Example

require('css-what')('foo[bar]:baz')

~> [ [ { type: 'tag', name: 'foo' },
    { type: 'attribute',
      name: 'bar',
      action: 'exists',
      value: '',
      ignoreCase: false },
    { type: 'pseudo',
      name: 'baz',
      data: null } ] ]

API

CSSwhat(selector, options) - Parses str, with the passed options.

The function returns a two-dimensional array. The first array represents selectors separated by commas (eg. sub1, sub2), the second contains the relevant tokens for that selector. Possible token types are:

name attributes example output
tag name div { type: 'tag', name: 'div' }
universal - * { type: 'universal' }
pseudo name, data :name(data) { type: 'pseudo', name: 'name', data: 'data' }
pseudo name, data :name { type: 'pseudo', name: 'name', data: null }
attribute name, action, value, ignoreCase [attr] { type: 'attribute', name: 'attr', action: 'exists', value: '', ignoreCase: false }
attribute name, action, value, ignoreCase [attr=val] { type: 'attribute', name: 'attr', action: 'equals', value: 'val', ignoreCase: false }
attribute name, action, value, ignoreCase [attr^=val] { type: 'attribute', name: 'attr', action: 'start', value: 'val', ignoreCase: false }
attribute name, action, value, ignoreCase [attr$=val] { type: 'attribute', name: 'attr', action: 'end', value: 'val', ignoreCase: false }

//TODO complete list

Options:

  • xmlMode: When enabled, tag names will be case-sensitive (meaning they won't be lowercased).

License: BSD-like

node-dashdash changelog

not yet released

(nothing yet)

1.14.1

  • [issue #30] Change the output used by dashdash's Bash completion support to indicate "there are no completions for this argument" to cope with different sorting rules on different Bash/platforms. For example:

      $ triton -v -p test2 package get <TAB>          # before
      ##-no -tritonpackage- completions-##
    
      $ triton -v -p test2 package get <TAB>          # after
      ##-no-completion- -results-##
    

1.14.0

  • New synopsisFromOpt(<option spec>) function. This will be used by node-cmdln to put together a synopsis of options for a command. Some examples:

      > synopsisFromOpt({names: ['help', 'h'], type: 'bool'});
      '[ --help | -h ]'
      > synopsisFromOpt({name: 'file', type: 'string', helpArg: 'FILE'});
      '[ --file=FILE ]'
    

1.13.1

  • [issue #20] bashCompletionSpecFromOptions breaks on an options array with an empty-string group.

1.13.0

  • Update assert-plus dep to 1.x to get recent fixes (particularly for assert.optional*).

  • Drop testing (and official support in packages.json#engines) for node 0.8.x. Add testing against node 5.x and 4.x with make testall.

  • [pull #16] Change the positiveInteger type to NOT accept zero (0). For those who might need the old behaviour, see "examples/custom-option-intGteZero.js". (By Dave Pacheco.)

1.12.2

  • Bash completion: Add argtypes to specify the types of positional args. E.g. this would allow you to have an ssh command with argtypes = ['host', 'cmd'] for bash completion. You then have to provide Bash functions to handle completing those types via the specExtra arg. See "examples/ddcompletion.js" for an example.

  • Bash completion: Tweak so that options or only offered as completions when there is a leading '-'. E.g. mytool <TAB> does NOT offer options, mytool -<TAB> does. Without this, a tool with options would never be able to fallback to Bash's "default" completion. For example ls <TAB> wouldn't result in filename completion. Now it will.

  • Bash completion: A workaround for not being able to explicitly have no completion results. Because dashdash's completion uses complete -o default, we fallback to Bash's "default" completion (typically for filename completion). Before this change, an attempt to explicitly say "there are no completions that match" would unintentionally trigger filename completion. Instead as a workaround we return:

      $ ddcompletion --none <TAB>         # the 'none' argtype
      ##-no           completions-##
    
      $ ddcompletion                      # a custom 'fruit' argtype
      apple   banana  orange
      $ ddcompletion z
      ##-no           -fruit-         completions-##
    

    This is a bit of a hack, but IMO a better experience than the surprise of matching a local filename beginning with 'z', which isn't, in this case, a "fruit".

1.12.1

  • Bash completion: Document <option spec>.completionType. Add includeHidden option to bashCompletionSpecFromOptions(). Add support for dealing with hidden subcmds.

1.12.0

  • Support for generating Bash completion files. See the "Bash completion" section of the README.md and "examples/ddcompletion.js" for an example.

1.11.0

  • Add the arrayFlatten boolean option to dashdash.addOptionType used for custom option types. This allows one to create an arrayOf... option type where each usage of the option can return multiple results. For example:

      node mytool.js --foo a,b --foo c
    

    We could define an option type for --foo such that opts.foo = ['a', 'b', 'c']. See "examples/custom-option-arrayOfCommaSepString.js" for an example.

1.10.1

  • Trim the published package to the minimal bits. Before: 24K tarball, 144K unpacked. After: 12K tarball, 48K unpacked. npm won't let me drop the README.md. :)

1.10.0

  • [issue #9] Support includeDefault in help config (similar to includeEnv) to have a note of an option's default value, if any, in help output.
  • [issue #11] Fix option group breakage introduced in v1.9.0.

1.9.0

  • [issue #10] Custom option types added with addOptionType can specify a "default" value. See "examples/custom-option-fruit.js".

1.8.0

  • Support hidden: true in an option spec to have help output exclude this option.

1.7.3

  • [issue #8] Fix parsing of a short option group when one of the option takes an argument. For example, consider tail with a -f boolean option and a -n option that takes a number argument. This should parse:

      tail -fn5
    

    Before this change, that would not parse correctly. It is suspected that this was introduced in version 1.4.0 (with commit 656fa8bc71c372ebddad0a7026bd71611e2ec99a).

1.7.2

  • Known issues: #8

  • Exclude 'tools/' dir in packages published to npm.

1.7.1

  • Known issues: #8

  • Support an option group empty string value:

      ...
      { group: '' },
      ...
    

    to render as a blank line in option help. This can help separate loosely related sets of options without resorting to a title for option groups.

1.7.0

  • Known issues: #8

  • [pull #7] Support for <parser>.help({helpWrap: false, ...}) option to be able to fully control the formatting for option help (by Patrick Mooney) helpWrap: false can also be set on individual options in the option objects, e.g.:

      var options = [
          {
            names: ['foo'],
            type: 'string',
            helpWrap: false,
            help: 'long help with\n  newlines' +
              '\n  spaces\n  and such\nwill render correctly'
          },
          ...
      ];
    

1.6.0

  • Known issues: #8

  • [pull #6] Support headings between groups of options (by Joshua M. Clulow) so that this code:

      var options = [
          { group: 'Armament Options' },
          { names: [ 'weapon', 'w' ], type: 'string' },
          { group: 'General Options' },
          { names: [ 'help', 'h' ], type: 'bool' }
      ];
      ...
    

    will give you this help output:

      ...
        Armament Options:
          -w, --weapon
    
        General Options:
          -h, --help
      ...
    

1.5.0

  • Known issues: #8

  • Add support for adding custom option types. "examples/custom-option-duration.js" shows an example adding a "duration" option type.

      $ node custom-option-duration.js -t 1h
      duration: 3600000 ms
      $ node custom-option-duration.js -t 1s
      duration: 1000 ms
      $ node custom-option-duration.js -t 5d
      duration: 432000000 ms
      $ node custom-option-duration.js -t bogus
      custom-option-duration.js: error: arg for "-t" is not a valid duration: "bogus"
    

    A custom option type is added via:

      var dashdash = require('dashdash');
      dashdash.addOptionType({
          name: '...',
          takesArg: true,
          helpArg: '...',
          parseArg: function (option, optstr, arg) {
              ...
          }
      });
    
  • [issue #4] Add date and arrayOfDate option types. They accept these date formats: epoch second times (e.g. 1396031701) and ISO 8601 format: YYYY-MM-DD[THH:MM:SS[.sss][Z]] (e.g. "2014-03-28", "2014-03-28T18:35:01.489Z"). See "examples/date.js" for an example usage.

      $ node examples/date.js -s 2014-01-01 -e $(date +%s)
      start at 2014-01-01T00:00:00.000Z
      end at 2014-03-29T04:26:18.000Z
    

1.4.0

  • Known issues: #8

  • [pull #2, pull #3] Add a allowUnknown: true option on createParser to allow unknown options to be passed through as opts._args instead of parsing throwing an exception (by https://github.com/isaacs).

    See 'allowUnknown' in the README for a subtle caveat.

1.3.2

  • Fix a subtlety where a bool option using both env and default didn't work exactly correctly. If default: false then all was fine (by luck). However, if you had an option like this:

      options: [ {
          names: ['verbose', 'v'],
          env: 'FOO_VERBOSE',
          'default': true,    // <--- this
          type: 'bool'
      } ],
    

    wanted FOO_VERBOSE=0 to make the option false, then you need the fix in this version of dashdash.

1.3.1

  • [issue #1] Fix an envvar not winning over an option 'default'. Previously an option with both default and env would never take a value from the environment variable. E.g. FOO_FILE would never work here:

      options: [ {
          names: ['file', 'f'],
          env: 'FOO_FILE',
          'default': 'default.file',
          type: 'string'
      } ],
    

1.3.0

  • [Backward incompatible change for boolean envvars] Change the interpretation of environment variables for boolean options to consider '0' to be false. Previous to this any value to the envvar was considered true -- which was quite misleading. Example:

      $ FOO_VERBOSE=0 node examples/foo.js
      # opts: { verbose: [ false ],
        _order: [ { key: 'verbose', value: false, from: 'env' } ],
        _args: [] }
      # args: []
    

1.2.1

  • Fix for parse.help({includeEnv: true, ...}) handling to ensure that an option with an env but no help still has the "Environment: ..." output. E.g.:

      { names: ['foo'], type: 'string', env: 'FOO' }
    
      ...
    
      --foo=ARG      Environment: FOO=ARG
    

1.2.0

  • Transform the option key on the opts object returned from <parser>.parse() for convenience. Currently this is just s/-/_/g, e.g. '--dry-run' -> opts.dry_run. This allow one to use hyphen in option names (common) but not have to do silly things like opt["dry-run"] to access the parsed results.

1.1.0

  • Environment variable integration. Envvars can be associated with an option, then option processing will fallback to using that envvar if defined and if the option isn't specified in argv. See the "Environment variable integration" section in the README.

  • Change the <parser>.parse() signature to take a single object with keys for arguments. The old signature is still supported.

  • dashdash.createParser(CONFIG) alternative to new dashdash.Parser(CONFIG) a la many node-land APIs.

1.0.2

  • Add "positiveInteger" and "arrayOfPositiveInteger" option types that only accept positive integers.

  • Add "integer" and "arrayOfInteger" option types that accepts only integers. Note that, for better or worse, these do NOT accept: "0x42" (hex), "1e2" (with exponent) or "1.", "3.0" (floats).

1.0.1

  • Fix not modifying the given option spec objects (which breaks creating a Parser with them more than once).

1.0.0

First release.

#!/bin/bash
#
# Bash completion generated for '{{name}}' at {{date}}.
#
# The original template lives here:
# https://github.com/trentm/node-dashdash/blob/master/etc/dashdash.bash_completion.in
#
#
# Copyright 2016 Trent Mick
# Copyright 2016 Joyent, Inc.
#
#
# A generic Bash completion driver script.
#
# This is meant to provide a re-usable chunk of Bash to use for
# "etc/bash_completion.d/" files for individual tools. Only the "Configuration"
# section with tool-specific info need differ. Features:
#
# - support for short and long opts
# - support for knowing which options take arguments
# - support for subcommands (e.g. 'git log <TAB>' to show just options for the
# log subcommand)
# - does the right thing with "--" to stop options
# - custom optarg and arg types for custom completions
# - (TODO) support for shells other than Bash (tcsh, zsh, fish?, etc.)
#
#
# Examples/design:
#
# 1. Bash "default" completion. By default Bash's 'complete -o default' is
# enabled. That means when there are no completions (e.g. if no opts match
# the current word), then you'll get Bash's default completion. Most notably
# that means you get filename completion. E.g.:
# $ tool ./<TAB>
# $ tool READ<TAB>
#
# 2. all opts and subcmds:
# $ tool <TAB>
# $ tool -v <TAB> # assuming '-v' doesn't take an arg
# $ tool -<TAB> # matching opts
# $ git lo<TAB> # matching subcmds
#
# Long opt completions are given *without* the '=', i.e. we prefer space
# separated because that's easier for good completions.
#
# 3. long opt arg with '='
# $ tool --file=<TAB>
# $ tool --file=./d<TAB>
# We maintain the "--file=" prefix. Limitation: With the attached prefix
# the 'complete -o filenames' doesn't know to do dirname '/' suffixing. Meh.
#
# 4. envvars:
# $ tool $<TAB>
# $ tool $P<TAB>
# Limitation: Currently only getting exported vars, so we miss "PS1" and
# others.
#
# 5. Defer to other completion in a subshell:
# $ tool --file $(cat ./<TAB>
# We get this from 'complete -o default ...'.
#
# 6. Custom completion types from a provided bash function.
# $ tool --profile <TAB> # complete available "profiles"
#
#
# Dev Notes:
# - compgen notes, from http://unix.stackexchange.com/questions/151118/understand-compgen-builtin-command
# - https://www.gnu.org/software/bash/manual/html_node/Programmable-Completion-Builtins.html
#
# Debugging this completion:
# 1. Uncomment the "_{{name}}_log_file=..." line.
# 2. 'tail -f /var/tmp/dashdash-completion.log' in one terminal.
# 3. Re-source this bash completion file.
#_{{name}}_log=/var/tmp/dashdash-completion.log
function _{{name}}_completer {
# ---- cmd definition
{{spec}}
# ---- locals
declare -a argv
# ---- support functions
function trace {
[[ -n "$_{{name}}_log" ]] && echo "$*" >&2
}
function _dashdash_complete {
local idx context
idx=$1
context=$2
local shortopts longopts optargs subcmds allsubcmds argtypes
shortopts="$(eval "echo \${cmd${context}_shortopts}")"
longopts="$(eval "echo \${cmd${context}_longopts}")"
optargs="$(eval "echo \${cmd${context}_optargs}")"
subcmds="$(eval "echo \${cmd${context}_subcmds}")"
allsubcmds="$(eval "echo \${cmd${context}_allsubcmds}")"
IFS=', ' read -r -a argtypes <<< "$(eval "echo \${cmd${context}_argtypes}")"
trace ""
trace "_dashdash_complete(idx=$idx, context=$context)"
trace " shortopts: $shortopts"
trace " longopts: $longopts"
trace " optargs: $optargs"
trace " subcmds: $subcmds"
trace " allsubcmds: $allsubcmds"
# Get 'state' of option parsing at this COMP_POINT.
# Copying "dashdash.js#parse()" behaviour here.
local state=
local nargs=0
local i=$idx
local argtype
local optname
local prefix
local word
local dashdashseen=
while [[ $i -lt $len && $i -le $COMP_CWORD ]]; do
argtype=
optname=
prefix=
word=
arg=${argv[$i]}
trace " consider argv[$i]: '$arg'"
if [[ "$arg" == "--" && $i -lt $COMP_CWORD ]]; then
trace " dashdash seen"
dashdashseen=yes
state=arg
word=$arg
elif [[ -z "$dashdashseen" && "${arg:0:2}" == "--" ]]; then
arg=${arg:2}
if [[ "$arg" == *"="* ]]; then
optname=${arg%%=*}
val=${arg##*=}
trace " long opt: optname='$optname' val='$val'"
state=arg
argtype=$(echo "$optargs" | awk -F "-$optname=" '{print $2}' | cut -d' ' -f1)
word=$val
prefix="--$optname="
else
optname=$arg
val=
trace " long opt: optname='$optname'"
state=longopt
word=--$optname
if [[ "$optargs" == *"-$optname="* && $i -lt $COMP_CWORD ]]; then
i=$(( $i + 1 ))
state=arg
argtype=$(echo "$optargs" | awk -F "-$optname=" '{print $2}' | cut -d' ' -f1)
word=${argv[$i]}
trace " takes arg (consume argv[$i], word='$word')"
fi
fi
elif [[ -z "$dashdashseen" && "${arg:0:1}" == "-" ]]; then
trace " short opt group"
state=shortopt
word=$arg
local j=1
while [[ $j -lt ${#arg} ]]; do
optname=${arg:$j:1}
trace " consider index $j: optname '$optname'"
if [[ "$optargs" == *"-$optname="* ]]; then
argtype=$(echo "$optargs" | awk -F "-$optname=" '{print $2}' | cut -d' ' -f1)
if [[ $(( $j + 1 )) -lt ${#arg} ]]; then
state=arg
word=${arg:$(( $j + 1 ))}
trace " takes arg (rest of this arg, word='$word', argtype='$argtype')"
elif [[ $i -lt $COMP_CWORD ]]; then
state=arg
i=$(( $i + 1 ))
word=${argv[$i]}
trace " takes arg (word='$word', argtype='$argtype')"
fi
break
fi
j=$(( $j + 1 ))
done
elif [[ $i -lt $COMP_CWORD && -n "$arg" ]] && $(echo "$allsubcmds" | grep -w "$arg" >/dev/null); then
trace " complete subcmd: recurse _dashdash_complete"
_dashdash_complete $(( $i + 1 )) "${context}__${arg/-/_}"
return
else
trace " not an opt or a complete subcmd"
state=arg
word=$arg
nargs=$(( $nargs + 1 ))
if [[ ${#argtypes[@]} -gt 0 ]]; then
argtype="${argtypes[$(( $nargs - 1 ))]}"
if [[ -z "$argtype" ]]; then
# If we have more args than argtypes, we use the
# last type.
argtype="${argtypes[@]: -1:1}"
fi
fi
fi
trace " state=$state prefix='$prefix' word='$word'"
i=$(( $i + 1 ))
done
trace " parsed: state=$state optname='$optname' argtype='$argtype' prefix='$prefix' word='$word' dashdashseen=$dashdashseen"
local compgen_opts=
if [[ -n "$prefix" ]]; then
compgen_opts="$compgen_opts -P $prefix"
fi
case $state in
shortopt)
compgen $compgen_opts -W "$shortopts $longopts" -- "$word"
;;
longopt)
compgen $compgen_opts -W "$longopts" -- "$word"
;;
arg)
# If we don't know what completion to do, then emit nothing. We
# expect that we are running with:
# complete -o default ...
# where "default" means: "Use Readline's default completion if
# the compspec generates no matches." This gives us the good filename
# completion, completion in subshells/backticks.
#
# We cannot support an argtype="directory" because
# compgen -S '/' -A directory -- "$word"
# doesn't give a satisfying result. It doesn't stop at the trailing '/'
# so you cannot descend into dirs.
if [[ "${word:0:1}" == '$' ]]; then
# By default, Bash will complete '$<TAB>' to all envvars. Apparently
# 'complete -o default' does *not* give us that. The following
# gets *close* to the same completions: '-A export' misses envvars
# like "PS1".
trace " completing envvars"
compgen $compgen_opts -P '$' -A export -- "${word:1}"
elif [[ -z "$argtype" ]]; then
# Only include opts in completions if $word is not empty.
# This is to avoid completing the leading '-', which foils
# using 'default' completion.
if [[ -n "$dashdashseen" ]]; then
trace " completing subcmds, if any (no argtype, dashdash seen)"
compgen $compgen_opts -W "$subcmds" -- "$word"
elif [[ -z "$word" ]]; then
trace " completing subcmds, if any (no argtype, empty word)"
compgen $compgen_opts -W "$subcmds" -- "$word"
else
trace " completing opts & subcmds (no argtype)"
compgen $compgen_opts -W "$shortopts $longopts $subcmds" -- "$word"
fi
elif [[ $argtype == "none" ]]; then
# We want *no* completions, i.e. some way to get the active
# 'complete -o default' to not do filename completion.
trace " completing 'none' (hack to imply no completions)"
echo "##-no-completion- -results-##"
elif [[ $argtype == "file" ]]; then
# 'complete -o default' gives the best filename completion, at least
# on Mac.
trace " completing 'file' (let 'complete -o default' handle it)"
echo ""
elif ! type complete_$argtype 2>/dev/null >/dev/null; then
trace " completing '$argtype' (fallback to default b/c complete_$argtype is unknown)"
echo ""
else
trace " completing custom '$argtype'"
completions=$(complete_$argtype "$word")
if [[ -z "$completions" ]]; then
trace " no custom '$argtype' completions"
# These are in ascii and "dictionary" order so they sort
# correctly.
echo "##-no-completion- -results-##"
else
echo $completions
fi
fi
;;
*)
trace " unknown state: $state"
;;
esac
}
trace ""
trace "-- $(date)"
#trace "\$IFS: '$IFS'"
#trace "\$@: '$@'"
#trace "COMP_WORDBREAKS: '$COMP_WORDBREAKS'"
trace "COMP_CWORD: '$COMP_CWORD'"
trace "COMP_LINE: '$COMP_LINE'"
trace "COMP_POINT: $COMP_POINT"
# Guard against negative COMP_CWORD. This is a Bash bug at least on
# Mac 10.10.4's bash. See
# <https://lists.gnu.org/archive/html/bug-bash/2009-07/msg00125.html>.
if [[ $COMP_CWORD -lt 0 ]]; then
trace "abort on negative COMP_CWORD"
exit 1;
fi
# I don't know how to do array manip on argv vars,
# so copy over to argv array to work on them.
shift # the leading '--'
i=0
len=$#
while [[ $# -gt 0 ]]; do
argv[$i]=$1
shift;
i=$(( $i + 1 ))
done
trace "argv: '${argv[@]}'"
trace "argv[COMP_CWORD-1]: '${argv[$(( $COMP_CWORD - 1 ))]}'"
trace "argv[COMP_CWORD]: '${argv[$COMP_CWORD]}'"
trace "argv len: '$len'"
_dashdash_complete 1 ""
}
# ---- mainline
# Note: This if-block to help work with 'compdef' and 'compctl' is
# adapted from 'npm completion'.
if type complete &>/dev/null; then
function _{{name}}_completion {
local _log_file=/dev/null
[[ -z "$_{{name}}_log" ]] || _log_file="$_{{name}}_log"
COMPREPLY=($(COMP_CWORD="$COMP_CWORD" \
COMP_LINE="$COMP_LINE" \
COMP_POINT="$COMP_POINT" \
_{{name}}_completer -- "${COMP_WORDS[@]}" \
2>$_log_file)) || return $?
}
complete -o default -F _{{name}}_completion {{name}}
elif type compdef &>/dev/null; then
function _{{name}}_completion {
local _log_file=/dev/null
[[ -z "$_{{name}}_log" ]] || _log_file="$_{{name}}_log"
compadd -- $(COMP_CWORD=$((CURRENT-1)) \
COMP_LINE=$BUFFER \
COMP_POINT=0 \
_{{name}}_completer -- "${words[@]}" \
2>$_log_file)
}
compdef _{{name}}_completion {{name}}
elif type compctl &>/dev/null; then
function _{{name}}_completion {
local cword line point words si
read -Ac words
read -cn cword
let cword-=1
read -l line
read -ln point
local _log_file=/dev/null
[[ -z "$_{{name}}_log" ]] || _log_file="$_{{name}}_log"
reply=($(COMP_CWORD="$cword" \
COMP_LINE="$line" \
COMP_POINT="$point" \
_{{name}}_completer -- "${words[@]}" \
2>$_log_file)) || return $?
}
compctl -K _{{name}}_completion {{name}}
fi
##
## This is a Bash completion file for the '{{name}}' command. You can install
## with either:
##
## cp FILE /usr/local/etc/bash_completion.d/{{name}} # Mac
## cp FILE /etc/bash_completion.d/{{name}} # Linux
##
## or:
##
## cp FILE > ~/.{{name}}.completion
## echo "source ~/.{{name}}.completion" >> ~/.bashrc
##
/**
* dashdash - A light, featureful and explicit option parsing library for
* node.js.
*/
// vim: set ts=4 sts=4 sw=4 et:
var assert = require('assert-plus');
var format = require('util').format;
var fs = require('fs');
var path = require('path');
var DEBUG = true;
if (DEBUG) {
var debug = console.warn;
} else {
var debug = function () {};
}
// ---- internal support stuff
// Replace {{variable}} in `s` with the template data in `d`.
function renderTemplate(s, d) {
return s.replace(/{{([a-zA-Z]+)}}/g, function (match, key) {
return d.hasOwnProperty(key) ? d[key] : match;
});
}
/**
* Return a shallow copy of the given object;
*/
function shallowCopy(obj) {
if (!obj) {
return (obj);
}
var copy = {};
Object.keys(obj).forEach(function (k) {
copy[k] = obj[k];
});
return (copy);
}
function space(n) {
var s = '';
for (var i = 0; i < n; i++) {
s += ' ';
}
return s;
}
function makeIndent(arg, deflen, name) {
if (arg === null || arg === undefined)
return space(deflen);
else if (typeof (arg) === 'number')
return space(arg);
else if (typeof (arg) === 'string')
return arg;
else
assert.fail('invalid "' + name + '": not a string or number: ' + arg);
}
/**
* Return an array of lines wrapping the given text to the given width.
* This splits on whitespace. Single tokens longer than `width` are not
* broken up.
*/
function textwrap(s, width) {
var words = s.trim().split(/\s+/);
var lines = [];
var line = '';
words.forEach(function (w) {
var newLength = line.length + w.length;
if (line.length > 0)
newLength += 1;
if (newLength > width) {
lines.push(line);
line = '';
}
if (line.length > 0)
line += ' ';
line += w;
});
lines.push(line);
return lines;
}
/**
* Transform an option name to a "key" that is used as the field
* on the `opts` object returned from `<parser>.parse()`.
*
* Transformations:
* - '-' -> '_': This allow one to use hyphen in option names (common)
* but not have to do silly things like `opt["dry-run"]` to access the
* parsed results.
*/
function optionKeyFromName(name) {
return name.replace(/-/g, '_');
}
// ---- Option types
function parseBool(option, optstr, arg) {
return Boolean(arg);
}
function parseString(option, optstr, arg) {
assert.string(arg, 'arg');
return arg;
}
function parseNumber(option, optstr, arg) {
assert.string(arg, 'arg');
var num = Number(arg);
if (isNaN(num)) {
throw new Error(format('arg for "%s" is not a number: "%s"',
optstr, arg));
}
return num;
}
function parseInteger(option, optstr, arg) {
assert.string(arg, 'arg');
var num = Number(arg);
if (!/^[0-9-]+$/.test(arg) || isNaN(num)) {
throw new Error(format('arg for "%s" is not an integer: "%s"',
optstr, arg));
}
return num;
}
function parsePositiveInteger(option, optstr, arg) {
assert.string(arg, 'arg');
var num = Number(arg);
if (!/^[0-9]+$/.test(arg) || isNaN(num) || num === 0) {
throw new Error(format('arg for "%s" is not a positive integer: "%s"',
optstr, arg));
}
return num;
}
/**
* Supported date args:
* - epoch second times (e.g. 1396031701)
* - ISO 8601 format: YYYY-MM-DD[THH:MM:SS[.sss][Z]]
* 2014-03-28T18:35:01.489Z
* 2014-03-28T18:35:01.489
* 2014-03-28T18:35:01Z
* 2014-03-28T18:35:01
* 2014-03-28
*/
function parseDate(option, optstr, arg) {
assert.string(arg, 'arg');
var date;
if (/^\d+$/.test(arg)) {
// epoch seconds
date = new Date(Number(arg) * 1000);
/* JSSTYLED */
} else if (/^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2}(\.\d+)?Z?)?$/i.test(arg)) {
// ISO 8601 format
date = new Date(arg);
} else {
throw new Error(format('arg for "%s" is not a valid date format: "%s"',
optstr, arg));
}
if (date.toString() === 'Invalid Date') {
throw new Error(format('arg for "%s" is an invalid date: "%s"',
optstr, arg));
}
return date;
}
var optionTypes = {
bool: {
takesArg: false,
parseArg: parseBool
},
string: {
takesArg: true,
helpArg: 'ARG',
parseArg: parseString
},
number: {
takesArg: true,
helpArg: 'NUM',
parseArg: parseNumber
},
integer: {
takesArg: true,
helpArg: 'INT',
parseArg: parseInteger
},
positiveInteger: {
takesArg: true,
helpArg: 'INT',
parseArg: parsePositiveInteger
},
date: {
takesArg: true,
helpArg: 'DATE',
parseArg: parseDate
},
arrayOfBool: {
takesArg: false,
array: true,
parseArg: parseBool
},
arrayOfString: {
takesArg: true,
helpArg: 'ARG',
array: true,
parseArg: parseString
},
arrayOfNumber: {
takesArg: true,
helpArg: 'NUM',
array: true,
parseArg: parseNumber
},
arrayOfInteger: {
takesArg: true,
helpArg: 'INT',
array: true,
parseArg: parseInteger
},
arrayOfPositiveInteger: {
takesArg: true,
helpArg: 'INT',
array: true,
parseArg: parsePositiveInteger
},
arrayOfDate: {
takesArg: true,
helpArg: 'INT',
array: true,
parseArg: parseDate
},
};
// ---- Parser
/**
* Parser constructor.
*
* @param config {Object} The parser configuration
* - options {Array} Array of option specs. See the README for how to
* specify each option spec.
* - allowUnknown {Boolean} Default false. Whether to throw on unknown
* options. If false, then unknown args are included in the _args array.
* - interspersed {Boolean} Default true. Whether to allow interspersed
* arguments (non-options) and options. E.g.:
* node tool.js arg1 arg2 -v
* '-v' is after some args here. If `interspersed: false` then '-v'
* would not be parsed out. Note that regardless of `interspersed`
* the presence of '--' will stop option parsing, as all good
* option parsers should.
*/
function Parser(config) {
assert.object(config, 'config');
assert.arrayOfObject(config.options, 'config.options');
assert.optionalBool(config.interspersed, 'config.interspersed');
var self = this;
// Allow interspersed arguments (true by default).
this.interspersed = (config.interspersed !== undefined
? config.interspersed : true);
// Don't allow unknown flags (true by default).
this.allowUnknown = (config.allowUnknown !== undefined
? config.allowUnknown : false);
this.options = config.options.map(function (o) { return shallowCopy(o); });
this.optionFromName = {};
this.optionFromEnv = {};
for (var i = 0; i < this.options.length; i++) {
var o = this.options[i];
if (o.group !== undefined && o.group !== null) {
assert.optionalString(o.group,
format('config.options.%d.group', i));
continue;
}
assert.ok(optionTypes[o.type],
format('invalid config.options.%d.type: "%s" in %j',
i, o.type, o));
assert.optionalString(o.name, format('config.options.%d.name', i));
assert.optionalArrayOfString(o.names,
format('config.options.%d.names', i));
assert.ok((o.name || o.names) && !(o.name && o.names),
format('exactly one of "name" or "names" required: %j', o));
assert.optionalString(o.help, format('config.options.%d.help', i));
var env = o.env || [];
if (typeof (env) === 'string') {
env = [env];
}
assert.optionalArrayOfString(env, format('config.options.%d.env', i));
assert.optionalString(o.helpGroup,
format('config.options.%d.helpGroup', i));
assert.optionalBool(o.helpWrap,
format('config.options.%d.helpWrap', i));
assert.optionalBool(o.hidden, format('config.options.%d.hidden', i));
if (o.name) {
o.names = [o.name];
} else {
assert.string(o.names[0],
format('config.options.%d.names is empty', i));
}
o.key = optionKeyFromName(o.names[0]);
o.names.forEach(function (n) {
if (self.optionFromName[n]) {
throw new Error(format(
'option name collision: "%s" used in %j and %j',
n, self.optionFromName[n], o));
}
self.optionFromName[n] = o;
});
env.forEach(function (n) {
if (self.optionFromEnv[n]) {
throw new Error(format(
'option env collision: "%s" used in %j and %j',
n, self.optionFromEnv[n], o));
}
self.optionFromEnv[n] = o;
});
}
}
Parser.prototype.optionTakesArg = function optionTakesArg(option) {
return optionTypes[option.type].takesArg;
};
/**
* Parse options from the given argv.
*
* @param inputs {Object} Optional.
* - argv {Array} Optional. The argv to parse. Defaults to
* `process.argv`.
* - slice {Number} The index into argv at which options/args begin.
* Default is 2, as appropriate for `process.argv`.
* - env {Object} Optional. The env to use for 'env' entries in the
* option specs. Defaults to `process.env`.
* @returns {Object} Parsed `opts`. It has special keys `_args` (the
* remaining args from `argv`) and `_order` (gives the order that
* options were specified).
*/
Parser.prototype.parse = function parse(inputs) {
var self = this;
// Old API was `parse([argv, [slice]])`
if (Array.isArray(arguments[0])) {
inputs = {argv: arguments[0], slice: arguments[1]};
}
assert.optionalObject(inputs, 'inputs');
if (!inputs) {
inputs = {};
}
assert.optionalArrayOfString(inputs.argv, 'inputs.argv');
//assert.optionalNumber(slice, 'slice');
var argv = inputs.argv || process.argv;
var slice = inputs.slice !== undefined ? inputs.slice : 2;
var args = argv.slice(slice);
var env = inputs.env || process.env;
var opts = {};
var _order = [];
function addOpt(option, optstr, key, val, from) {
var type = optionTypes[option.type];
var parsedVal = type.parseArg(option, optstr, val);
if (type.array) {
if (!opts[key]) {
opts[key] = [];
}
if (type.arrayFlatten && Array.isArray(parsedVal)) {
for (var i = 0; i < parsedVal.length; i++) {
opts[key].push(parsedVal[i]);
}
} else {
opts[key].push(parsedVal);
}
} else {
opts[key] = parsedVal;
}
var item = { key: key, value: parsedVal, from: from };
_order.push(item);
}
// Parse args.
var _args = [];
var i = 0;
outer: while (i < args.length) {
var arg = args[i];
// End of options marker.
if (arg === '--') {
i++;
break;
// Long option
} else if (arg.slice(0, 2) === '--') {
var name = arg.slice(2);
var val = null;
var idx = name.indexOf('=');
if (idx !== -1) {
val = name.slice(idx + 1);
name = name.slice(0, idx);
}
var option = this.optionFromName[name];
if (!option) {
if (!this.allowUnknown)
throw new Error(format('unknown option: "--%s"', name));
else if (this.interspersed)
_args.push(arg);
else
break outer;
} else {
var takesArg = this.optionTakesArg(option);
if (val !== null && !takesArg) {
throw new Error(format('argument given to "--%s" option '
+ 'that does not take one: "%s"', name, arg));
}
if (!takesArg) {
addOpt(option, '--'+name, option.key, true, 'argv');
} else if (val !== null) {
addOpt(option, '--'+name, option.key, val, 'argv');
} else if (i + 1 >= args.length) {
throw new Error(format('do not have enough args for "--%s" '
+ 'option', name));
} else {
addOpt(option, '--'+name, option.key, args[i + 1], 'argv');
i++;
}
}
// Short option
} else if (arg[0] === '-' && arg.length > 1) {
var j = 1;
var allFound = true;
while (j < arg.length) {
var name = arg[j];
var option = this.optionFromName[name];
if (!option) {
allFound = false;
if (this.allowUnknown) {
if (this.interspersed) {
_args.push(arg);
break;
} else
break outer;
} else if (arg.length > 2) {
throw new Error(format(
'unknown option: "-%s" in "%s" group',
name, arg));
} else {
throw new Error(format('unknown option: "-%s"', name));
}
} else if (this.optionTakesArg(option)) {
break;
}
j++;
}
j = 1;
while (allFound && j < arg.length) {
var name = arg[j];
var val = arg.slice(j + 1); // option val if it takes an arg
var option = this.optionFromName[name];
var takesArg = this.optionTakesArg(option);
if (!takesArg) {
addOpt(option, '-'+name, option.key, true, 'argv');
} else if (val) {
addOpt(option, '-'+name, option.key, val, 'argv');
break;
} else {
if (i + 1 >= args.length) {
throw new Error(format('do not have enough args '
+ 'for "-%s" option', name));
}
addOpt(option, '-'+name, option.key, args[i + 1], 'argv');
i++;
break;
}
j++;
}
// An interspersed arg
} else if (this.interspersed) {
_args.push(arg);
// An arg and interspersed args are not allowed, so done options.
} else {
break outer;
}
i++;
}
_args = _args.concat(args.slice(i));
// Parse environment.
Object.keys(this.optionFromEnv).forEach(function (envname) {
var val = env[envname];
if (val === undefined)
return;
var option = self.optionFromEnv[envname];
if (opts[option.key] !== undefined)
return;
var takesArg = self.optionTakesArg(option);
if (takesArg) {
addOpt(option, envname, option.key, val, 'env');
} else if (val !== '') {
// Boolean envvar handling:
// - VAR=<empty-string> not set (as if the VAR was not set)
// - VAR=0 false
// - anything else true
addOpt(option, envname, option.key, (val !== '0'), 'env');
}
});
// Apply default values.
this.options.forEach(function (o) {
if (opts[o.key] === undefined) {
if (o.default !== undefined) {
opts[o.key] = o.default;
} else if (o.type && optionTypes[o.type].default !== undefined) {
opts[o.key] = optionTypes[o.type].default;
}
}
});
opts._order = _order;
opts._args = _args;
return opts;
};
/**
* Return help output for the current options.
*
* E.g.: if the current options are:
* [{names: ['help', 'h'], type: 'bool', help: 'Show help and exit.'}]
* then this would return:
* ' -h, --help Show help and exit.\n'
*
* @param config {Object} Config for controlling the option help output.
* - indent {Number|String} Default 4. An indent/prefix to use for
* each option line.
* - nameSort {String} Default is 'length'. By default the names are
* sorted to put the short opts first (i.e. '-h, --help' preferred
* to '--help, -h'). Set to 'none' to not do this sorting.
* - maxCol {Number} Default 80. Note that long tokens in a help string
* can go past this.
* - helpCol {Number} Set to specify a specific column at which
* option help will be aligned. By default this is determined
* automatically.
* - minHelpCol {Number} Default 20.
* - maxHelpCol {Number} Default 40.
* - includeEnv {Boolean} Default false. If true, a note stating the `env`
* envvar (if specified for this option) will be appended to the help
* output.
* - includeDefault {Boolean} Default false. If true, a note stating
* the `default` for this option, if any, will be appended to the help
* output.
* - helpWrap {Boolean} Default true. Wrap help text in helpCol..maxCol
* bounds.
* @returns {String}
*/
Parser.prototype.help = function help(config) {
config = config || {};
assert.object(config, 'config');
var indent = makeIndent(config.indent, 4, 'config.indent');
var headingIndent = makeIndent(config.headingIndent,
Math.round(indent.length / 2), 'config.headingIndent');
assert.optionalString(config.nameSort, 'config.nameSort');
var nameSort = config.nameSort || 'length';
assert.ok(~['length', 'none'].indexOf(nameSort),
'invalid "config.nameSort"');
assert.optionalNumber(config.maxCol, 'config.maxCol');
assert.optionalNumber(config.maxHelpCol, 'config.maxHelpCol');
assert.optionalNumber(config.minHelpCol, 'config.minHelpCol');
assert.optionalNumber(config.helpCol, 'config.helpCol');
assert.optionalBool(config.includeEnv, 'config.includeEnv');
assert.optionalBool(config.includeDefault, 'config.includeDefault');
assert.optionalBool(config.helpWrap, 'config.helpWrap');
var maxCol = config.maxCol || 80;
var minHelpCol = config.minHelpCol || 20;
var maxHelpCol = config.maxHelpCol || 40;
var lines = [];
var maxWidth = 0;
this.options.forEach(function (o) {
if (o.hidden) {
return;
}
if (o.group !== undefined && o.group !== null) {
// We deal with groups in the next pass
lines.push(null);
return;
}
var type = optionTypes[o.type];
var arg = o.helpArg || type.helpArg || 'ARG';
var line = '';
var names = o.names.slice();
if (nameSort === 'length') {
names.sort(function (a, b) {
if (a.length < b.length)
return -1;
else if (b.length < a.length)
return 1;
else
return 0;
})
}
names.forEach(function (name, i) {
if (i > 0)
line += ', ';
if (name.length === 1) {
line += '-' + name
if (type.takesArg)
line += ' ' + arg;
} else {
line += '--' + name
if (type.takesArg)
line += '=' + arg;
}
});
maxWidth = Math.max(maxWidth, line.length);
lines.push(line);
});
// Add help strings.
var helpCol = config.helpCol;
if (!helpCol) {
helpCol = maxWidth + indent.length + 2;
helpCol = Math.min(Math.max(helpCol, minHelpCol), maxHelpCol);
}
var i = -1;
this.options.forEach(function (o) {
if (o.hidden) {
return;
}
i++;
if (o.group !== undefined && o.group !== null) {
if (o.group === '') {
// Support a empty string "group" to have a blank line between
// sets of options.
lines[i] = '';
} else {
// Render the group heading with the heading-specific indent.
lines[i] = (i === 0 ? '' : '\n') + headingIndent +
o.group + ':';
}
return;
}
var helpDefault;
if (config.includeDefault) {
if (o.default !== undefined) {
helpDefault = format('Default: %j', o.default);
} else if (o.type && optionTypes[o.type].default !== undefined) {
helpDefault = format('Default: %j',
optionTypes[o.type].default);
}
}
var line = lines[i] = indent + lines[i];
if (!o.help && !(config.includeEnv && o.env) && !helpDefault) {
return;
}
var n = helpCol - line.length;
if (n >= 0) {
line += space(n);
} else {
line += '\n' + space(helpCol);
}
var helpEnv = '';
if (o.env && o.env.length && config.includeEnv) {
helpEnv += 'Environment: ';
var type = optionTypes[o.type];
var arg = o.helpArg || type.helpArg || 'ARG';
var envs = (Array.isArray(o.env) ? o.env : [o.env]).map(
function (e) {
if (type.takesArg) {
return e + '=' + arg;
} else {
return e + '=1';
}
}
);
helpEnv += envs.join(', ');
}
var help = (o.help || '').trim();
if (o.helpWrap !== false && config.helpWrap !== false) {
// Wrap help description normally.
if (help.length && !~'.!?"\''.indexOf(help.slice(-1))) {
help += '.';
}
if (help.length) {
help += ' ';
}
help += helpEnv;
if (helpDefault) {
if (helpEnv) {
help += '. ';
}
help += helpDefault;
}
line += textwrap(help, maxCol - helpCol).join(
'\n' + space(helpCol));
} else {
// Do not wrap help description, but indent newlines appropriately.
var helpLines = help.split('\n').filter(
function (ln) { return ln.length });
if (helpEnv !== '') {
helpLines.push(helpEnv);
}
if (helpDefault) {
helpLines.push(helpDefault);
}
line += helpLines.join('\n' + space(helpCol));
}
lines[i] = line;
});
var rv = '';
if (lines.length > 0) {
rv = lines.join('\n') + '\n';
}
return rv;
};
/**
* Return a string suitable for a Bash completion file for this tool.
*
* @param args.name {String} The tool name.
* @param args.specExtra {String} Optional. Extra Bash code content to add
* to the end of the "spec". Typically this is used to append Bash
* "complete_TYPE" functions for custom option types. See
* "examples/ddcompletion.js" for an example.
* @param args.argtypes {Array} Optional. Array of completion types for
* positional args (i.e. non-options). E.g.
* argtypes = ['fruit', 'veggie', 'file']
* will result in completion of fruits for the first arg, veggies for the
* second, and filenames for the third and subsequent positional args.
* If not given, positional args will use Bash's 'default' completion.
* See `specExtra` for providing Bash `complete_TYPE` functions, e.g.
* `complete_fruit` and `complete_veggie` in this example.
*/
Parser.prototype.bashCompletion = function bashCompletion(args) {
assert.object(args, 'args');
assert.string(args.name, 'args.name');
assert.optionalString(args.specExtra, 'args.specExtra');
assert.optionalArrayOfString(args.argtypes, 'args.argtypes');
return bashCompletionFromOptions({
name: args.name,
specExtra: args.specExtra,
argtypes: args.argtypes,
options: this.options
});
};
// ---- Bash completion
const BASH_COMPLETION_TEMPLATE_PATH = path.join(
__dirname, '../etc/dashdash.bash_completion.in');
/**
* Return the Bash completion "spec" (the string value for the "{{spec}}"
* var in the "dashdash.bash_completion.in" template) for this tool.
*
* The "spec" is Bash code that defines the CLI options and subcmds for
* the template's completion code. It looks something like this:
*
* local cmd_shortopts="-J ..."
* local cmd_longopts="--help ..."
* local cmd_optargs="-p=tritonprofile ..."
*
* @param args.options {Array} The array of dashdash option specs.
* @param args.context {String} Optional. A context string for the "local cmd*"
* vars in the spec. By default it is the empty string. When used to
* scope for completion on a *sub-command* (e.g. for "git log" on a "git"
* tool), then it would have a value (e.g. "__log"). See
* <http://github.com/trentm/node-cmdln> Bash completion for details.
* @param opts.includeHidden {Boolean} Optional. Default false. By default
* hidden options and subcmds are "excluded". Here excluded means they
* won't be offered as a completion, but if used, their argument type
* will be completed. "Hidden" options and subcmds are ones with the
* `hidden: true` attribute to exclude them from default help output.
* @param args.argtypes {Array} Optional. Array of completion types for
* positional args (i.e. non-options). E.g.
* argtypes = ['fruit', 'veggie', 'file']
* will result in completion of fruits for the first arg, veggies for the
* second, and filenames for the third and subsequent positional args.
* If not given, positional args will use Bash's 'default' completion.
* See `specExtra` for providing Bash `complete_TYPE` functions, e.g.
* `complete_fruit` and `complete_veggie` in this example.
*/
function bashCompletionSpecFromOptions(args) {
assert.object(args, 'args');
assert.object(args.options, 'args.options');
assert.optionalString(args.context, 'args.context');
assert.optionalBool(args.includeHidden, 'args.includeHidden');
assert.optionalArrayOfString(args.argtypes, 'args.argtypes');
var context = args.context || '';
var includeHidden = (args.includeHidden === undefined
? false : args.includeHidden);
var spec = [];
var shortopts = [];
var longopts = [];
var optargs = [];
(args.options || []).forEach(function (o) {
if (o.group !== undefined && o.group !== null) {
// Skip group headers.
return;
}
var optNames = o.names || [o.name];
var optType = getOptionType(o.type);
if (optType.takesArg) {
var completionType = o.completionType ||
optType.completionType || o.type;
optNames.forEach(function (optName) {
if (optName.length === 1) {
if (includeHidden || !o.hidden) {
shortopts.push('-' + optName);
}
// Include even hidden options in `optargs` so that bash
// completion of its arg still works.
optargs.push('-' + optName + '=' + completionType);
} else {
if (includeHidden || !o.hidden) {
longopts.push('--' + optName);
}
optargs.push('--' + optName + '=' + completionType);
}
});
} else {
optNames.forEach(function (optName) {
if (includeHidden || !o.hidden) {
if (optName.length === 1) {
shortopts.push('-' + optName);
} else {
longopts.push('--' + optName);
}
}
});
}
});
spec.push(format('local cmd%s_shortopts="%s"',
context, shortopts.sort().join(' ')));
spec.push(format('local cmd%s_longopts="%s"',
context, longopts.sort().join(' ')));
spec.push(format('local cmd%s_optargs="%s"',
context, optargs.sort().join(' ')));
if (args.argtypes) {
spec.push(format('local cmd%s_argtypes="%s"',
context, args.argtypes.join(' ')));
}
return spec.join('\n');
}
/**
* Return a string suitable for a Bash completion file for this tool.
*
* @param args.name {String} The tool name.
* @param args.options {Array} The array of dashdash option specs.
* @param args.specExtra {String} Optional. Extra Bash code content to add
* to the end of the "spec". Typically this is used to append Bash
* "complete_TYPE" functions for custom option types. See
* "examples/ddcompletion.js" for an example.
* @param args.argtypes {Array} Optional. Array of completion types for
* positional args (i.e. non-options). E.g.
* argtypes = ['fruit', 'veggie', 'file']
* will result in completion of fruits for the first arg, veggies for the
* second, and filenames for the third and subsequent positional args.
* If not given, positional args will use Bash's 'default' completion.
* See `specExtra` for providing Bash `complete_TYPE` functions, e.g.
* `complete_fruit` and `complete_veggie` in this example.
*/
function bashCompletionFromOptions(args) {
assert.object(args, 'args');
assert.object(args.options, 'args.options');
assert.string(args.name, 'args.name');
assert.optionalString(args.specExtra, 'args.specExtra');
assert.optionalArrayOfString(args.argtypes, 'args.argtypes');
// Gather template data.
var data = {
name: args.name,
date: new Date(),
spec: bashCompletionSpecFromOptions({
options: args.options,
argtypes: args.argtypes
}),
};
if (args.specExtra) {
data.spec += '\n\n' + args.specExtra;
}
// Render template.
var template = fs.readFileSync(BASH_COMPLETION_TEMPLATE_PATH, 'utf8');
return renderTemplate(template, data);
}
// ---- exports
function createParser(config) {
return new Parser(config);
}
/**
* Parse argv with the given options.
*
* @param config {Object} A merge of all the available fields from
* `dashdash.Parser` and `dashdash.Parser.parse`: options, interspersed,
* argv, env, slice.
*/
function parse(config) {
assert.object(config, 'config');
assert.optionalArrayOfString(config.argv, 'config.argv');
assert.optionalObject(config.env, 'config.env');
var config = shallowCopy(config);
var argv = config.argv;
delete config.argv;
var env = config.env;
delete config.env;
var parser = new Parser(config);
return parser.parse({argv: argv, env: env});
}
/**
* Add a new option type.
*
* @params optionType {Object}:
* - name {String} Required.
* - takesArg {Boolean} Required. Whether this type of option takes an
* argument on process.argv. Typically this is true for all but the
* "bool" type.
* - helpArg {String} Required iff `takesArg === true`. The string to
* show in generated help for options of this type.
* - parseArg {Function} Require. `function (option, optstr, arg)` parser
* that takes a string argument and returns an instance of the
* appropriate type, or throws an error if the arg is invalid.
* - array {Boolean} Optional. Set to true if this is an 'arrayOf' type
* that collects multiple usages of the option in process.argv and
* puts results in an array.
* - arrayFlatten {Boolean} Optional. XXX
* - default Optional. Default value for options of this type, if no
* default is specified in the option type usage.
*/
function addOptionType(optionType) {
assert.object(optionType, 'optionType');
assert.string(optionType.name, 'optionType.name');
assert.bool(optionType.takesArg, 'optionType.takesArg');
if (optionType.takesArg) {
assert.string(optionType.helpArg, 'optionType.helpArg');
}
assert.func(optionType.parseArg, 'optionType.parseArg');
assert.optionalBool(optionType.array, 'optionType.array');
assert.optionalBool(optionType.arrayFlatten, 'optionType.arrayFlatten');
optionTypes[optionType.name] = {
takesArg: optionType.takesArg,
helpArg: optionType.helpArg,
parseArg: optionType.parseArg,
array: optionType.array,
arrayFlatten: optionType.arrayFlatten,
default: optionType.default
}
}
function getOptionType(name) {
assert.string(name, 'name');
return optionTypes[name];
}
/**
* Return a synopsis string for the given option spec.
*
* Examples:
* > synopsisFromOpt({names: ['help', 'h'], type: 'bool'});
* '[ --help | -h ]'
* > synopsisFromOpt({name: 'file', type: 'string', helpArg: 'FILE'});
* '[ --file=FILE ]'
*/
function synopsisFromOpt(o) {
assert.object(o, 'o');
if (o.hasOwnProperty('group')) {
return null;
}
var names = o.names || [o.name];
// `type` here could be undefined if, for example, the command has a
// dashdash option spec with a bogus 'type'.
var type = getOptionType(o.type);
var helpArg = o.helpArg || (type && type.helpArg) || 'ARG';
var parts = [];
names.forEach(function (name) {
var part = (name.length === 1 ? '-' : '--') + name;
if (type && type.takesArg) {
part += (name.length === 1 ? ' ' + helpArg : '=' + helpArg);
}
parts.push(part);
});
return ('[ ' + parts.join(' | ') + ' ]');
};
module.exports = {
createParser: createParser,
Parser: Parser,
parse: parse,
addOptionType: addOptionType,
getOptionType: getOptionType,
synopsisFromOpt: synopsisFromOpt,
// Bash completion-related exports
BASH_COMPLETION_TEMPLATE_PATH: BASH_COMPLETION_TEMPLATE_PATH,
bashCompletionFromOptions: bashCompletionFromOptions,
bashCompletionSpecFromOptions: bashCompletionSpecFromOptions,
// Export the parseFoo parsers because they might be useful as primitives
// for custom option types.
parseBool: parseBool,
parseString: parseString,
parseNumber: parseNumber,
parseInteger: parseInteger,
parsePositiveInteger: parsePositiveInteger,
parseDate: parseDate
};
# This is the MIT license
Copyright (c) 2013 Trent Mick. All rights reserved.
Copyright (c) 2013 Joyent Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// Copyright (c) 2012, Mark Cavage. All rights reserved.
// Copyright 2015 Joyent, Inc.
var assert = require('assert');
var Stream = require('stream').Stream;
var util = require('util');
///--- Globals
/* JSSTYLED */
var UUID_REGEXP = /^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$/;
///--- Internal
function _capitalize(str) {
return (str.charAt(0).toUpperCase() + str.slice(1));
}
function _toss(name, expected, oper, arg, actual) {
throw new assert.AssertionError({
message: util.format('%s (%s) is required', name, expected),
actual: (actual === undefined) ? typeof (arg) : actual(arg),
expected: expected,
operator: oper || '===',
stackStartFunction: _toss.caller
});
}
function _getClass(arg) {
return (Object.prototype.toString.call(arg).slice(8, -1));
}
function noop() {
// Why even bother with asserts?
}
///--- Exports
var types = {
bool: {
check: function (arg) { return typeof (arg) === 'boolean'; }
},
func: {
check: function (arg) { return typeof (arg) === 'function'; }
},
string: {
check: function (arg) { return typeof (arg) === 'string'; }
},
object: {
check: function (arg) {
return typeof (arg) === 'object' && arg !== null;
}
},
number: {
check: function (arg) {
return typeof (arg) === 'number' && !isNaN(arg);
}
},
finite: {
check: function (arg) {
return typeof (arg) === 'number' && !isNaN(arg) && isFinite(arg);
}
},
buffer: {
check: function (arg) { return Buffer.isBuffer(arg); },
operator: 'Buffer.isBuffer'
},
array: {
check: function (arg) { return Array.isArray(arg); },
operator: 'Array.isArray'
},
stream: {
check: function (arg) { return arg instanceof Stream; },
operator: 'instanceof',
actual: _getClass
},
date: {
check: function (arg) { return arg instanceof Date; },
operator: 'instanceof',
actual: _getClass
},
regexp: {
check: function (arg) { return arg instanceof RegExp; },
operator: 'instanceof',
actual: _getClass
},
uuid: {
check: function (arg) {
return typeof (arg) === 'string' && UUID_REGEXP.test(arg);
},
operator: 'isUUID'
}
};
function _setExports(ndebug) {
var keys = Object.keys(types);
var out;
/* re-export standard assert */
if (process.env.NODE_NDEBUG) {
out = noop;
} else {
out = function (arg, msg) {
if (!arg) {
_toss(msg, 'true', arg);
}
};
}
/* standard checks */
keys.forEach(function (k) {
if (ndebug) {
out[k] = noop;
return;
}
var type = types[k];
out[k] = function (arg, msg) {
if (!type.check(arg)) {
_toss(msg, k, type.operator, arg, type.actual);
}
};
});
/* optional checks */
keys.forEach(function (k) {
var name = 'optional' + _capitalize(k);
if (ndebug) {
out[name] = noop;
return;
}
var type = types[k];
out[name] = function (arg, msg) {
if (arg === undefined || arg === null) {
return;
}
if (!type.check(arg)) {
_toss(msg, k, type.operator, arg, type.actual);
}
};
});
/* arrayOf checks */
keys.forEach(function (k) {
var name = 'arrayOf' + _capitalize(k);
if (ndebug) {
out[name] = noop;
return;
}
var type = types[k];
var expected = '[' + k + ']';
out[name] = function (arg, msg) {
if (!Array.isArray(arg)) {
_toss(msg, expected, type.operator, arg, type.actual);
}
var i;
for (i = 0; i < arg.length; i++) {
if (!type.check(arg[i])) {
_toss(msg, expected, type.operator, arg, type.actual);
}
}
};
});
/* optionalArrayOf checks */
keys.forEach(function (k) {
var name = 'optionalArrayOf' + _capitalize(k);
if (ndebug) {
out[name] = noop;
return;
}
var type = types[k];
var expected = '[' + k + ']';
out[name] = function (arg, msg) {
if (arg === undefined || arg === null) {
return;
}
if (!Array.isArray(arg)) {
_toss(msg, expected, type.operator, arg, type.actual);
}
var i;
for (i = 0; i < arg.length; i++) {
if (!type.check(arg[i])) {
_toss(msg, expected, type.operator, arg, type.actual);
}
}
};
});
/* re-export built-in assertions */
Object.keys(assert).forEach(function (k) {
if (k === 'AssertionError') {
out[k] = assert[k];
return;
}
if (ndebug) {
out[k] = noop;
return;
}
out[k] = assert[k];
});
/* export ourselves (for unit tests _only_) */
out._setExports = _setExports;
return out;
}
module.exports = _setExports(process.env.NODE_NDEBUG);
Dave Eddy <dave@daveeddy.com>
Fred Kuo <fred.kuo@joyent.com>
Lars-Magnus Skog <ralphtheninja@riseup.net>
Mark Cavage <mcavage@gmail.com>
Patrick Mooney <pmooney@pfmooney.com>
Rob Gulewich <robert.gulewich@joyent.com>

assert-plus Changelog

1.0.0

  • BREAKING assert.number (and derivatives) now accept Infinity as valid input
  • Add assert.finite check. Previous assert.number callers should use this if they expect Infinity inputs to throw.

0.2.0

  • Fix assert.object(null) so it throws
  • Fix optional/arrayOf exports for non-type-of asserts
  • Add optiona/arrayOf exports for Stream/Date/Regex/uuid
  • Add basic unit test coverage
{
"_args": [
[
{
"raw": "assert-plus@^1.0.0",
"scope": null,
"escapedName": "assert-plus",
"name": "assert-plus",
"rawSpec": "^1.0.0",
"spec": ">=1.0.0 <2.0.0",
"type": "range"
},
"F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\dashdash"
]
],
"_from": "assert-plus@>=1.0.0 <2.0.0",
"_id": "assert-plus@1.0.0",
"_inCache": true,
"_location": "/dashdash/assert-plus",
"_nodeVersion": "0.10.40",
"_npmUser": {
"name": "pfmooney",
"email": "patrick.f.mooney@gmail.com"
},
"_npmVersion": "3.3.9",
"_phantomChildren": {},
"_requested": {
"raw": "assert-plus@^1.0.0",
"scope": null,
"escapedName": "assert-plus",
"name": "assert-plus",
"rawSpec": "^1.0.0",
"spec": ">=1.0.0 <2.0.0",
"type": "range"
},
"_requiredBy": [
"/dashdash"
],
"_resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
"_shasum": "f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525",
"_shrinkwrap": null,
"_spec": "assert-plus@^1.0.0",
"_where": "F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\dashdash",
"author": {
"name": "Mark Cavage",
"email": "mcavage@gmail.com"
},
"bugs": {
"url": "https://github.com/mcavage/node-assert-plus/issues"
},
"contributors": [
{
"name": "Dave Eddy",
"email": "dave@daveeddy.com"
},
{
"name": "Fred Kuo",
"email": "fred.kuo@joyent.com"
},
{
"name": "Lars-Magnus Skog",
"email": "ralphtheninja@riseup.net"
},
{
"name": "Mark Cavage",
"email": "mcavage@gmail.com"
},
{
"name": "Patrick Mooney",
"email": "pmooney@pfmooney.com"
},
{
"name": "Rob Gulewich",
"email": "robert.gulewich@joyent.com"
}
],
"dependencies": {},
"description": "Extra assertions on top of node's assert module",
"devDependencies": {
"faucet": "0.0.1",
"tape": "4.2.2"
},
"directories": {},
"dist": {
"shasum": "f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525",
"tarball": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz"
},
"engines": {
"node": ">=0.8"
},
"homepage": "https://github.com/mcavage/node-assert-plus#readme",
"license": "MIT",
"main": "./assert.js",
"maintainers": [
{
"name": "mcavage",
"email": "mcavage@gmail.com"
},
{
"name": "pfmooney",
"email": "patrick.f.mooney@gmail.com"
}
],
"name": "assert-plus",
"optionalDependencies": {},
"readme": "ERROR: No README data found!",
"repository": {
"type": "git",
"url": "git+https://github.com/mcavage/node-assert-plus.git"
},
"scripts": {
"test": "tape tests/*.js | ./node_modules/.bin/faucet"
},
"version": "1.0.0"
}

assert-plus

This library is a super small wrapper over node's assert module that has two things: (1) the ability to disable assertions with the environment variable NODE_NDEBUG, and (2) some API wrappers for argument testing. Like assert.string(myArg, 'myArg'). As a simple example, most of my code looks like this:

    var assert = require('assert-plus');

    function fooAccount(options, callback) {
        assert.object(options, 'options');
        assert.number(options.id, 'options.id');
        assert.bool(options.isManager, 'options.isManager');
        assert.string(options.name, 'options.name');
        assert.arrayOfString(options.email, 'options.email');
        assert.func(callback, 'callback');

        // Do stuff
        callback(null, {});
    }

API

All methods that aren't part of node's core assert API are simply assumed to take an argument, and then a string 'name' that's not a message; AssertionError will be thrown if the assertion fails with a message like:

AssertionError: foo (string) is required
at test (/home/mark/work/foo/foo.js:3:9)
at Object.<anonymous> (/home/mark/work/foo/foo.js:15:1)
at Module._compile (module.js:446:26)
at Object..js (module.js:464:10)
at Module.load (module.js:353:31)
at Function._load (module.js:311:12)
at Array.0 (module.js:484:10)
at EventEmitter._tickCallback (node.js:190:38)

from:

    function test(foo) {
        assert.string(foo, 'foo');
    }

There you go. You can check that arrays are of a homogeneous type with Arrayof$Type:

    function test(foo) {
        assert.arrayOfString(foo, 'foo');
    }

You can assert IFF an argument is not undefined (i.e., an optional arg):

    assert.optionalString(foo, 'foo');

Lastly, you can opt-out of assertion checking altogether by setting the environment variable NODE_NDEBUG=1. This is pseudo-useful if you have lots of assertions, and don't want to pay typeof () taxes to v8 in production. Be advised: The standard functions re-exported from assert are also disabled in assert-plus if NDEBUG is specified. Using them directly from the assert module avoids this behavior.

The complete list of APIs is:

  • assert.array
  • assert.bool
  • assert.buffer
  • assert.func
  • assert.number
  • assert.finite
  • assert.object
  • assert.string
  • assert.stream
  • assert.date
  • assert.regexp
  • assert.uuid
  • assert.arrayOfArray
  • assert.arrayOfBool
  • assert.arrayOfBuffer
  • assert.arrayOfFunc
  • assert.arrayOfNumber
  • assert.arrayOfFinite
  • assert.arrayOfObject
  • assert.arrayOfString
  • assert.arrayOfStream
  • assert.arrayOfDate
  • assert.arrayOfRegexp
  • assert.arrayOfUuid
  • assert.optionalArray
  • assert.optionalBool
  • assert.optionalBuffer
  • assert.optionalFunc
  • assert.optionalNumber
  • assert.optionalFinite
  • assert.optionalObject
  • assert.optionalString
  • assert.optionalStream
  • assert.optionalDate
  • assert.optionalRegexp
  • assert.optionalUuid
  • assert.optionalArrayOfArray
  • assert.optionalArrayOfBool
  • assert.optionalArrayOfBuffer
  • assert.optionalArrayOfFunc
  • assert.optionalArrayOfNumber
  • assert.optionalArrayOfFinite
  • assert.optionalArrayOfObject
  • assert.optionalArrayOfString
  • assert.optionalArrayOfStream
  • assert.optionalArrayOfDate
  • assert.optionalArrayOfRegexp
  • assert.optionalArrayOfUuid
  • assert.AssertionError
  • assert.fail
  • assert.ok
  • assert.equal
  • assert.notEqual
  • assert.deepEqual
  • assert.notDeepEqual
  • assert.strictEqual
  • assert.notStrictEqual
  • assert.throws
  • assert.doesNotThrow
  • assert.ifError

Installation

npm install assert-plus

License

The MIT License (MIT) Copyright (c) 2012 Mark Cavage

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Bugs

See https://github.com/mcavage/node-assert-plus/issues.

{
"_args": [
[
{
"raw": "dashdash@^1.12.0",
"scope": null,
"escapedName": "dashdash",
"name": "dashdash",
"rawSpec": "^1.12.0",
"spec": ">=1.12.0 <2.0.0",
"type": "range"
},
"F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\sshpk"
]
],
"_from": "dashdash@>=1.12.0 <2.0.0",
"_id": "dashdash@1.14.1",
"_inCache": true,
"_location": "/dashdash",
"_nodeVersion": "4.6.1",
"_npmOperationalInternal": {
"host": "packages-12-west.internal.npmjs.com",
"tmp": "tmp/dashdash-1.14.1.tgz_1479854020349_0.731718891998753"
},
"_npmUser": {
"name": "trentm",
"email": "trentm@gmail.com"
},
"_npmVersion": "2.15.9",
"_phantomChildren": {},
"_requested": {
"raw": "dashdash@^1.12.0",
"scope": null,
"escapedName": "dashdash",
"name": "dashdash",
"rawSpec": "^1.12.0",
"spec": ">=1.12.0 <2.0.0",
"type": "range"
},
"_requiredBy": [
"/sshpk"
],
"_resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
"_shasum": "853cfa0f7cbe2fed5de20326b8dd581035f6e2f0",
"_shrinkwrap": null,
"_spec": "dashdash@^1.12.0",
"_where": "F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\sshpk",
"author": {
"name": "Trent Mick",
"email": "trentm@gmail.com",
"url": "http://trentm.com"
},
"bugs": {
"url": "https://github.com/trentm/node-dashdash/issues"
},
"contributors": [
{
"name": "Trent Mick",
"email": "trentm@gmail.com",
"url": "http://trentm.com"
},
{
"name": "Isaac Schlueter",
"url": "https://github.com/isaacs"
},
{
"name": "Joshua M. Clulow",
"url": "https://github.com/jclulow"
},
{
"name": "Patrick Mooney",
"url": "https://github.com/pfmooney"
},
{
"name": "Dave Pacheco",
"url": "https://github.com/davepacheco"
}
],
"dependencies": {
"assert-plus": "^1.0.0"
},
"description": "A light, featureful and explicit option parsing library.",
"devDependencies": {
"nodeunit": "0.9.x"
},
"directories": {},
"dist": {
"shasum": "853cfa0f7cbe2fed5de20326b8dd581035f6e2f0",
"tarball": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz"
},
"engines": {
"node": ">=0.10"
},
"gitHead": "1dd7379640462a21ca6d92502803de830b4acfa2",
"homepage": "https://github.com/trentm/node-dashdash#readme",
"keywords": [
"option",
"parser",
"parsing",
"cli",
"command",
"args",
"bash",
"completion"
],
"license": "MIT",
"main": "./lib/dashdash.js",
"maintainers": [
{
"name": "trentm",
"email": "trentm@gmail.com"
}
],
"name": "dashdash",
"optionalDependencies": {},
"readme": "ERROR: No README data found!",
"repository": {
"type": "git",
"url": "git://github.com/trentm/node-dashdash.git"
},
"scripts": {
"test": "nodeunit test/*.test.js"
},
"version": "1.14.1"
}

A light, featureful and explicit option parsing library for node.js.

Why another one? See below. tl;dr: The others I've tried are one of too loosey goosey (not explicit), too big/too many deps, or ill specified. YMMV.

Follow @trentmick for updates to node-dashdash.

Install

npm install dashdash

Usage

var dashdash = require('dashdash');

// Specify the options. Minimally `name` (or `names`) and `type`
// must be given for each.
var options = [
    {
        // `names` or a single `name`. First element is the `opts.KEY`.
        names: ['help', 'h'],
        // See "Option specs" below for types.
        type: 'bool',
        help: 'Print this help and exit.'
    }
];

// Shortcut form. As called it infers `process.argv`. See below for
// the longer form to use methods like `.help()` on the Parser object.
var opts = dashdash.parse({options: options});

console.log("opts:", opts);
console.log("args:", opts._args);

Longer Example

A more realistic starter script "foo.js" is as follows. This also shows using parser.help() for formatted option help.

var dashdash = require('./lib/dashdash');

var options = [
    {
        name: 'version',
        type: 'bool',
        help: 'Print tool version and exit.'
    },
    {
        names: ['help', 'h'],
        type: 'bool',
        help: 'Print this help and exit.'
    },
    {
        names: ['verbose', 'v'],
        type: 'arrayOfBool',
        help: 'Verbose output. Use multiple times for more verbose.'
    },
    {
        names: ['file', 'f'],
        type: 'string',
        help: 'File to process',
        helpArg: 'FILE'
    }
];

var parser = dashdash.createParser({options: options});
try {
    var opts = parser.parse(process.argv);
} catch (e) {
    console.error('foo: error: %s', e.message);
    process.exit(1);
}

console.log("# opts:", opts);
console.log("# args:", opts._args);

// Use `parser.help()` for formatted options help.
if (opts.help) {
    var help = parser.help({includeEnv: true}).trimRight();
    console.log('usage: node foo.js [OPTIONS]\n'
                + 'options:\n'
                + help);
    process.exit(0);
}

// ...

Some example output from this script (foo.js):

$ node foo.js -h
# opts: { help: true,
  _order: [ { name: 'help', value: true, from: 'argv' } ],
  _args: [] }
# args: []
usage: node foo.js [OPTIONS]
options:
    --version             Print tool version and exit.
    -h, --help            Print this help and exit.
    -v, --verbose         Verbose output. Use multiple times for more verbose.
    -f FILE, --file=FILE  File to process

$ node foo.js -v
# opts: { verbose: [ true ],
  _order: [ { name: 'verbose', value: true, from: 'argv' } ],
  _args: [] }
# args: []

$ node foo.js --version arg1
# opts: { version: true,
  _order: [ { name: 'version', value: true, from: 'argv' } ],
  _args: [ 'arg1' ] }
# args: [ 'arg1' ]

$ node foo.js -f bar.txt
# opts: { file: 'bar.txt',
  _order: [ { name: 'file', value: 'bar.txt', from: 'argv' } ],
  _args: [] }
# args: []

$ node foo.js -vvv --file=blah
# opts: { verbose: [ true, true, true ],
  file: 'blah',
  _order:
   [ { name: 'verbose', value: true, from: 'argv' },
     { name: 'verbose', value: true, from: 'argv' },
     { name: 'verbose', value: true, from: 'argv' },
     { name: 'file', value: 'blah', from: 'argv' } ],
  _args: [] }
# args: []

See the "examples" dir for a number of starter examples using some of dashdash's features.

Environment variable integration

If you want to allow environment variables to specify options to your tool, dashdash makes this easy. We can change the 'verbose' option in the example above to include an 'env' field:

    {
        names: ['verbose', 'v'],
        type: 'arrayOfBool',
        env: 'FOO_VERBOSE',         // <--- add this line
        help: 'Verbose output. Use multiple times for more verbose.'
    },

then the "FOO_VERBOSE" environment variable can be used to set this option:

$ FOO_VERBOSE=1 node foo.js
# opts: { verbose: [ true ],
  _order: [ { name: 'verbose', value: true, from: 'env' } ],
  _args: [] }
# args: []

Boolean options will interpret the empty string as unset, '0' as false and anything else as true.

$ FOO_VERBOSE= node examples/foo.js                 # not set
# opts: { _order: [], _args: [] }
# args: []

$ FOO_VERBOSE=0 node examples/foo.js                # '0' is false
# opts: { verbose: [ false ],
  _order: [ { key: 'verbose', value: false, from: 'env' } ],
  _args: [] }
# args: []

$ FOO_VERBOSE=1 node examples/foo.js                # true
# opts: { verbose: [ true ],
  _order: [ { key: 'verbose', value: true, from: 'env' } ],
  _args: [] }
# args: []

$ FOO_VERBOSE=boogabooga node examples/foo.js       # true
# opts: { verbose: [ true ],
  _order: [ { key: 'verbose', value: true, from: 'env' } ],
  _args: [] }
# args: []

Non-booleans can be used as well. Strings:

$ FOO_FILE=data.txt node examples/foo.js
# opts: { file: 'data.txt',
  _order: [ { key: 'file', value: 'data.txt', from: 'env' } ],
  _args: [] }
# args: []

Numbers:

$ FOO_TIMEOUT=5000 node examples/foo.js
# opts: { timeout: 5000,
  _order: [ { key: 'timeout', value: 5000, from: 'env' } ],
  _args: [] }
# args: []

$ FOO_TIMEOUT=blarg node examples/foo.js
foo: error: arg for "FOO_TIMEOUT" is not a positive integer: "blarg"

With the includeEnv: true config to parser.help() the environment variable can also be included in help output:

usage: node foo.js [OPTIONS]
options:
    --version             Print tool version and exit.
    -h, --help            Print this help and exit.
    -v, --verbose         Verbose output. Use multiple times for more verbose.
                          Environment: FOO_VERBOSE=1
    -f FILE, --file=FILE  File to process

Bash completion

Dashdash provides a simple way to create a Bash completion file that you can place in your "bash_completion.d" directory -- sometimes that is "/usr/local/etc/bash_completion.d/"). Features:

  • Support for short and long opts
  • Support for knowing which options take arguments
  • Support for subcommands (e.g. 'git log ' to show just options for the log subcommand). See node-cmdln for how to integrate that.
  • Does the right thing with "--" to stop options.
  • Custom optarg and arg types for custom completions.

Dashdash will return bash completion file content given a parser instance:

var parser = dashdash.createParser({options: options});
console.log( parser.bashCompletion({name: 'mycli'}) );

or directly from a options array of options specs:

var code = dashdash.bashCompletionFromOptions({
    name: 'mycli',
    options: OPTIONS
});

Write that content to "/usr/local/etc/bash_completion.d/mycli" and you will have Bash completions for mycli. Alternatively you can write it to any file (e.g. "~/.bashrc") and source it.

You could add a --completion hidden option to your tool that emits the completion content and document for your users to call that to install Bash completions.

See examples/ddcompletion.js for a complete example, including how one can define bash functions for completion of custom option types. Also see node-cmdln for how it uses this for Bash completion for full multi-subcommand tools.

  • TODO: document specExtra
  • TODO: document includeHidden
  • TODO: document custom types, function complete\_FOO guide, completionType
  • TODO: document argtypes

Parser config

Parser construction (i.e. dashdash.createParser(CONFIG)) takes the following fields:

  • options (Array of option specs). Required. See the Option specs section below.

  • interspersed (Boolean). Optional. Default is true. If true this allows interspersed arguments and options. I.e.:

      node ./tool.js -v arg1 arg2 -h   # '-h' is after interspersed args
    

    Set it to false to have '-h' not get parsed as an option in the above example.

  • allowUnknown (Boolean). Optional. Default is false. If false, this causes unknown arguments to throw an error. I.e.:

      node ./tool.js -v arg1 --afe8asefksjefhas
    

    Set it to true to treat the unknown option as a positional argument.

    Caveat: When a shortopt group, such as -xaz contains a mix of known and unknown options, the entire group is passed through unmolested as a positional argument.

    Consider if you have a known short option -a, and parse the following command line:

      node ./tool.js -xaz
    

    where -x and -z are unknown. There are multiple ways to interpret this:

    1. -x takes a value: {x: 'az'}
    2. -x and -z are both booleans: {x:true,a:true,z:true}

    Since dashdash does not know what -x and -z are, it can't know if you'd prefer to receive {a:true,_args:['-x','-z']} or {x:'az'}, or {_args:['-xaz']}. Leaving the positional arg unprocessed is the easiest mistake for the user to recover from.

Option specs

Example using all fields (required fields are noted):

{
    names: ['file', 'f'],       // Required (one of `names` or `name`).
    type: 'string',             // Required.
    completionType: 'filename',
    env: 'MYTOOL_FILE',
    help: 'Config file to load before running "mytool"',
    helpArg: 'PATH',
    helpWrap: false,
    default: path.resolve(process.env.HOME, '.mytoolrc')
}

Each option spec in the options array must/can have the following fields:

  • name (String) or names (Array). Required. These give the option name and aliases. The first name (if more than one given) is the key for the parsed opts object.

  • type (String). Required. One of:

    • bool
    • string
    • number
    • integer
    • positiveInteger
    • date (epoch seconds, e.g. 1396031701, or ISO 8601 format YYYY-MM-DD[THH:MM:SS[.sss][Z]], e.g. "2014-03-28T18:35:01.489Z")
    • arrayOfBool
    • arrayOfString
    • arrayOfNumber
    • arrayOfInteger
    • arrayOfPositiveInteger
    • arrayOfDate

    FWIW, these names attempt to match with asserts on assert-plus. You can add your own custom option types with dashdash.addOptionType. See below.

  • completionType (String). Optional. This is used for Bash completion for an option argument. If not specified, then the value of type is used. Any string may be specified, but only the following values have meaning:

    • none: Provide no completions.
    • file: Bash's default completion (i.e. complete -o default), which includes filenames.
    • Any string FOO for which a function complete_FOO Bash function is defined. This is for custom completions for a given tool. Typically these custom functions are provided in the specExtra argument to dashdash.bashCompletionFromOptions(). See "examples/ddcompletion.js" for an example.
  • env (String or Array of String). Optional. An environment variable name (or names) that can be used as a fallback for this option. For example, given a "foo.js" like this:

      var options = [{names: ['dry-run', 'n'], env: 'FOO_DRY_RUN'}];
      var opts = dashdash.parse({options: options});
    

    Both node foo.js --dry-run and FOO_DRY_RUN=1 node foo.js would result in opts.dry_run = true.

    An environment variable is only used as a fallback, i.e. it is ignored if the associated option is given in argv.

  • help (String). Optional. Used for parser.help() output.

  • helpArg (String). Optional. Used in help output as the placeholder for the option argument, e.g. the "PATH" in:

      ...
      -f PATH, --file=PATH    File to process
      ...
    
  • helpWrap (Boolean). Optional, default true. Set this to false to have that option's help not be text wrapped in <parser>.help() output.

  • default. Optional. A default value used for this option, if the option isn't specified in argv.

  • hidden (Boolean). Optional, default false. If true, help output will not include this option. See also the includeHidden option to bashCompletionFromOptions() for Bash completion.

Option group headings

You can add headings between option specs in the options array. To do so, simply add an object with only a group property -- the string to print as the heading for the subsequent options in the array. For example:

var options = [
    {
        group: 'Armament Options'
    },
    {
        names: [ 'weapon', 'w' ],
        type: 'string'
    },
    {
        group: 'General Options'
    },
    {
        names: [ 'help', 'h' ],
        type: 'bool'
    }
];
...

Note: You can use an empty string, {group: ''}, to get a blank line in help output between groups of options.

Help config

The parser.help(...) function is configurable as follows:

    Options:
      Armament Options:
    ^^  -w WEAPON, --weapon=WEAPON  Weapon with which to crush. One of: |
   /                                sword, spear, maul                  |
  /   General Options:                                                  |
 /      -h, --help                  Print this help and exit.           |
/   ^^^^                            ^                                   |
\       `-- indent                   `-- helpCol              maxCol ---'
 `-- headingIndent
  • indent (Number or String). Default 4. Set to a number (for that many spaces) or a string for the literal indent.
  • headingIndent (Number or String). Default half length of indent. Set to a number (for that many spaces) or a string for the literal indent. This indent applies to group heading lines, between normal option lines.
  • nameSort (String). Default is 'length'. By default the names are sorted to put the short opts first (i.e. '-h, --help' preferred to '--help, -h'). Set to 'none' to not do this sorting.
  • maxCol (Number). Default 80. Note that reflow is just done on whitespace so a long token in the option help can overflow maxCol.
  • helpCol (Number). If not set a reasonable value will be determined between minHelpCol and maxHelpCol.
  • minHelpCol (Number). Default 20.
  • maxHelpCol (Number). Default 40.
  • helpWrap (Boolean). Default true. Set to false to have option help strings not be textwrapped to the helpCol..maxCol range.
  • includeEnv (Boolean). Default false. If the option has associated environment variables (via the env option spec attribute), then append mentioned of those envvars to the help string.
  • includeDefault (Boolean). Default false. If the option has a default value (via the default option spec attribute, or a default on the option's type), then a "Default: VALUE" string will be appended to the help string.

Custom option types

Dashdash includes a good starter set of option types that it will parse for you. However, you can add your own via:

var dashdash = require('dashdash');
dashdash.addOptionType({
    name: '...',
    takesArg: true,
    helpArg: '...',
    parseArg: function (option, optstr, arg) {
        ...
    },
    array: false,  // optional
    arrayFlatten: false,  // optional
    default: ...,   // optional
    completionType: ...  // optional
});

For example, a simple option type that accepts 'yes', 'y', 'no' or 'n' as a boolean argument would look like:

var dashdash = require('dashdash');

function parseYesNo(option, optstr, arg) {
    var argLower = arg.toLowerCase()
    if (~['yes', 'y'].indexOf(argLower)) {
        return true;
    } else if (~['no', 'n'].indexOf(argLower)) {
        return false;
    } else {
        throw new Error(format(
            'arg for "%s" is not "yes" or "no": "%s"',
            optstr, arg));
    }
}

dashdash.addOptionType({
    name: 'yesno'
    takesArg: true,
    helpArg: '<yes|no>',
    parseArg: parseYesNo
});

var options = {
    {names: ['answer', 'a'], type: 'yesno'}
};
var opts = dashdash.parse({options: options});

See "examples/custom-option-*.js" for other examples. See the addOptionType block comment in "lib/dashdash.js" for more details. Please let me know with an issue if you write a generally useful one.

Why

Why another node.js option parsing lib?

  • nopt really is just for "tools like npm". Implicit opts (e.g. '--no-foo' works for every '--foo'). Can't disable abbreviated opts. Can't do multiple usages of same opt, e.g. '-vvv' (I think). Can't do grouped short opts.

  • optimist has surprise interpretation of options (at least to me). Implicit opts mean ambiguities and poor error handling for fat-fingering. process.exit calls makes it hard to use as a libary.

  • optparse Incomplete docs. Is this an attempted clone of Python's optparse. Not clear. Some divergence. parser.on("name", ...) API is weird.

  • argparse Dep on underscore. No thanks just for option processing. find lib | wc -l -> 26. Overkill. Argparse is a bit different anyway. Not sure I want that.

  • posix-getopt No type validation. Though that isn't a killer. AFAIK can't have a long opt without a short alias. I.e. no getopt_long semantics. Also, no whizbang features like generated help output.

  • "commander.js": I wrote a critique a while back. It seems fine, but last I checked had an outstanding bug that would prevent me from using it.

License

MIT. See LICENSE.txt.

var Stream = require('stream').Stream;
var util = require('util');
module.exports = DelayedStream;
function DelayedStream() {
this.source = null;
this.dataSize = 0;
this.maxDataSize = 1024 * 1024;
this.pauseStream = true;
this._maxDataSizeExceeded = false;
this._released = false;
this._bufferedEvents = [];
}
util.inherits(DelayedStream, Stream);
DelayedStream.create = function(source, options) {
var delayedStream = new this();
options = options || {};
for (var option in options) {
delayedStream[option] = options[option];
}
delayedStream.source = source;
var realEmit = source.emit;
source.emit = function() {
delayedStream._handleEmit(arguments);
return realEmit.apply(source, arguments);
};
source.on('error', function() {});
if (delayedStream.pauseStream) {
source.pause();
}
return delayedStream;
};
Object.defineProperty(DelayedStream.prototype, 'readable', {
configurable: true,
enumerable: true,
get: function() {
return this.source.readable;
}
});
DelayedStream.prototype.setEncoding = function() {
return this.source.setEncoding.apply(this.source, arguments);
};
DelayedStream.prototype.resume = function() {
if (!this._released) {
this.release();
}
this.source.resume();
};
DelayedStream.prototype.pause = function() {
this.source.pause();
};
DelayedStream.prototype.release = function() {
this._released = true;
this._bufferedEvents.forEach(function(args) {
this.emit.apply(this, args);
}.bind(this));
this._bufferedEvents = [];
};
DelayedStream.prototype.pipe = function() {
var r = Stream.prototype.pipe.apply(this, arguments);
this.resume();
return r;
};
DelayedStream.prototype._handleEmit = function(args) {
if (this._released) {
this.emit.apply(this, args);
return;
}
if (args[0] === 'data') {
this.dataSize += args[1].length;
this._checkIfMaxDataSizeExceeded();
}
this._bufferedEvents.push(args);
};
DelayedStream.prototype._checkIfMaxDataSizeExceeded = function() {
if (this._maxDataSizeExceeded) {
return;
}
if (this.dataSize <= this.maxDataSize) {
return;
}
this._maxDataSizeExceeded = true;
var message =
'DelayedStream#maxDataSize of ' + this.maxDataSize + ' bytes exceeded.'
this.emit('error', new Error(message));
};
Copyright (c) 2011 Debuggable Limited <felix@debuggable.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
SHELL := /bin/bash
test:
@./test/run.js
.PHONY: test
{
"_args": [
[
{
"raw": "delayed-stream@~1.0.0",
"scope": null,
"escapedName": "delayed-stream",
"name": "delayed-stream",
"rawSpec": "~1.0.0",
"spec": ">=1.0.0 <1.1.0",
"type": "range"
},
"F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\combined-stream"
]
],
"_from": "delayed-stream@>=1.0.0 <1.1.0",
"_id": "delayed-stream@1.0.0",
"_inCache": true,
"_location": "/delayed-stream",
"_nodeVersion": "1.6.4",
"_npmUser": {
"name": "apechimp",
"email": "apeherder@gmail.com"
},
"_npmVersion": "2.8.3",
"_phantomChildren": {},
"_requested": {
"raw": "delayed-stream@~1.0.0",
"scope": null,
"escapedName": "delayed-stream",
"name": "delayed-stream",
"rawSpec": "~1.0.0",
"spec": ">=1.0.0 <1.1.0",
"type": "range"
},
"_requiredBy": [
"/combined-stream"
],
"_resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"_shasum": "df3ae199acadfb7d440aaae0b29e2272b24ec619",
"_shrinkwrap": null,
"_spec": "delayed-stream@~1.0.0",
"_where": "F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\combined-stream",
"author": {
"name": "Felix Geisendörfer",
"email": "felix@debuggable.com",
"url": "http://debuggable.com/"
},
"bugs": {
"url": "https://github.com/felixge/node-delayed-stream/issues"
},
"contributors": [
{
"name": "Mike Atkins",
"email": "apeherder@gmail.com"
}
],
"dependencies": {},
"description": "Buffers events from a stream until you are ready to handle them.",
"devDependencies": {
"fake": "0.2.0",
"far": "0.0.1"
},
"directories": {},
"dist": {
"shasum": "df3ae199acadfb7d440aaae0b29e2272b24ec619",
"tarball": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz"
},
"engines": {
"node": ">=0.4.0"
},
"gitHead": "07a9dc99fb8f1a488160026b9ad77493f766fb84",
"homepage": "https://github.com/felixge/node-delayed-stream",
"license": "MIT",
"main": "./lib/delayed_stream",
"maintainers": [
{
"name": "felixge",
"email": "felix@debuggable.com"
},
{
"name": "apechimp",
"email": "apeherder@gmail.com"
}
],
"name": "delayed-stream",
"optionalDependencies": {},
"readme": "ERROR: No README data found!",
"repository": {
"type": "git",
"url": "git://github.com/felixge/node-delayed-stream.git"
},
"scripts": {
"test": "make test"
},
"version": "1.0.0"
}

delayed-stream

Buffers events from a stream until you are ready to handle them.

Installation

npm install delayed-stream

Usage

The following example shows how to write a http echo server that delays its response by 1000 ms.

var DelayedStream = require('delayed-stream');
var http = require('http');

http.createServer(function(req, res) {
  var delayed = DelayedStream.create(req);

  setTimeout(function() {
    res.writeHead(200);
    delayed.pipe(res);
  }, 1000);
});

If you are not using Stream#pipe, you can also manually release the buffered events by calling delayedStream.resume():

var delayed = DelayedStream.create(req);

setTimeout(function() {
  // Emit all buffered events and resume underlaying source
  delayed.resume();
}, 1000);

Implementation

In order to use this meta stream properly, here are a few things you should know about the implementation.

Event Buffering / Proxying

All events of the source stream are hijacked by overwriting the source.emit method. Until node implements a catch-all event listener, this is the only way.

However, delayed-stream still continues to emit all events it captures on the source, regardless of whether you have released the delayed stream yet or not.

Upon creation, delayed-stream captures all source events and stores them in an internal event buffer. Once delayedStream.release() is called, all buffered events are emitted on the delayedStream, and the event buffer is cleared. After that, delayed-stream merely acts as a proxy for the underlaying source.

Error handling

Error events on source are buffered / proxied just like any other events. However, delayedStream.create attaches a no-op 'error' listener to the source. This way you only have to handle errors on the delayedStream object, rather than in two places.

Buffer limits

delayed-stream provides a maxDataSize property that can be used to limit the amount of data being buffered. In order to protect you from bad source streams that don't react to source.pause(), this feature is enabled by default.

API

DelayedStream.create(source, [options])

Returns a new delayedStream. Available options are:

  • pauseStream
  • maxDataSize

The description for those properties can be found below.

delayedStream.source

The source stream managed by this object. This is useful if you are passing your delayedStream around, and you still want to access properties on the source object.

delayedStream.pauseStream = true

Whether to pause the underlaying source when calling DelayedStream.create(). Modifying this property afterwards has no effect.

delayedStream.maxDataSize = 1024 * 1024

The amount of data to buffer before emitting an error.

If the underlaying source is emitting Buffer objects, the maxDataSize refers to bytes.

If the underlaying source is emitting JavaScript strings, the size refers to characters.

If you know what you are doing, you can set this property to Infinity to disable this feature. You can also modify this property during runtime.

delayedStream.dataSize = 0

The amount of data buffered so far.

delayedStream.readable

An ECMA5 getter that returns the value of source.readable.

delayedStream.resume()

If the delayedStream has not been released so far, delayedStream.release() is called.

In either case, source.resume() is called.

delayedStream.pause()

Calls source.pause().

delayedStream.pipe(dest)

Calls delayedStream.resume() and then proxies the arguments to source.pipe.

delayedStream.release()

Emits and clears all events that have been buffered up so far. This does not resume the underlaying source, use delayedStream.resume() instead.

License

delayed-stream is licensed under the MIT license.

/*
Module dependencies
*/
var ElementType = require('domelementtype');
var entities = require('entities');
/*
Boolean Attributes
*/
var booleanAttributes = {
__proto__: null,
allowfullscreen: true,
async: true,
autofocus: true,
autoplay: true,
checked: true,
controls: true,
default: true,
defer: true,
disabled: true,
hidden: true,
ismap: true,
loop: true,
multiple: true,
muted: true,
open: true,
readonly: true,
required: true,
reversed: true,
scoped: true,
seamless: true,
selected: true,
typemustmatch: true
};
var unencodedElements = {
__proto__: null,
style: true,
script: true,
xmp: true,
iframe: true,
noembed: true,
noframes: true,
plaintext: true,
noscript: true
};
/*
Format attributes
*/
function formatAttrs(attributes, opts) {
if (!attributes) return;
var output = '',
value;
// Loop through the attributes
for (var key in attributes) {
value = attributes[key];
if (output) {
output += ' ';
}
if (!value && booleanAttributes[key]) {
output += key;
} else {
output += key + '="' + (opts.decodeEntities ? entities.encodeXML(value) : value) + '"';
}
}
return output;
}
/*
Self-enclosing tags (stolen from node-htmlparser)
*/
var singleTag = {
__proto__: null,
area: true,
base: true,
basefont: true,
br: true,
col: true,
command: true,
embed: true,
frame: true,
hr: true,
img: true,
input: true,
isindex: true,
keygen: true,
link: true,
meta: true,
param: true,
source: true,
track: true,
wbr: true,
};
var render = module.exports = function(dom, opts) {
if (!Array.isArray(dom) && !dom.cheerio) dom = [dom];
opts = opts || {};
var output = '';
for(var i = 0; i < dom.length; i++){
var elem = dom[i];
if (elem.type === 'root')
output += render(elem.children, opts);
else if (ElementType.isTag(elem))
output += renderTag(elem, opts);
else if (elem.type === ElementType.Directive)
output += renderDirective(elem);
else if (elem.type === ElementType.Comment)
output += renderComment(elem);
else if (elem.type === ElementType.CDATA)
output += renderCdata(elem);
else
output += renderText(elem, opts);
}
return output;
};
function renderTag(elem, opts) {
// Handle SVG
if (elem.name === "svg") opts = {decodeEntities: opts.decodeEntities, xmlMode: true};
var tag = '<' + elem.name,
attribs = formatAttrs(elem.attribs, opts);
if (attribs) {
tag += ' ' + attribs;
}
if (
opts.xmlMode
&& (!elem.children || elem.children.length === 0)
) {
tag += '/>';
} else {
tag += '>';
if (elem.children) {
tag += render(elem.children, opts);
}
if (!singleTag[elem.name] || opts.xmlMode) {
tag += '</' + elem.name + '>';
}
}
return tag;
}
function renderDirective(elem) {
return '<' + elem.data + '>';
}
function renderText(elem, opts) {
var data = elem.data || '';
// if entities weren't decoded, no need to encode them back
if (opts.decodeEntities && !(elem.parent && elem.parent.name in unencodedElements)) {
data = entities.encodeXML(data);
}
return data;
}
function renderCdata(elem) {
return '<![CDATA[' + elem.children[0].data + ']]>';
}
function renderComment(elem) {
return '<!--' + elem.data + '-->';
}
License
(The MIT License)
Copyright (c) 2014 The cheeriojs contributors
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//Types of elements found in the DOM
module.exports = {
Text: "text", //Text
Directive: "directive", //<? ... ?>
Comment: "comment", //<!-- ... -->
Script: "script", //<script> tags
Style: "style", //<style> tags
Tag: "tag", //Any tag
CDATA: "cdata", //<![CDATA[ ... ]]>
isTag: function(elem){
return elem.type === "tag" || elem.type === "script" || elem.type === "style";
}
};
Copyright (c) Felix Böhm
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{
"_args": [
[
{
"raw": "domelementtype@~1.1.1",
"scope": null,
"escapedName": "domelementtype",
"name": "domelementtype",
"rawSpec": "~1.1.1",
"spec": ">=1.1.1 <1.2.0",
"type": "range"
},
"F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\dom-serializer"
]
],
"_from": "domelementtype@>=1.1.1 <1.2.0",
"_id": "domelementtype@1.1.3",
"_inCache": true,
"_location": "/dom-serializer/domelementtype",
"_nodeVersion": "0.10.32",
"_npmUser": {
"name": "feedic",
"email": "me@feedic.com"
},
"_npmVersion": "2.1.5",
"_phantomChildren": {},
"_requested": {
"raw": "domelementtype@~1.1.1",
"scope": null,
"escapedName": "domelementtype",
"name": "domelementtype",
"rawSpec": "~1.1.1",
"spec": ">=1.1.1 <1.2.0",
"type": "range"
},
"_requiredBy": [
"/dom-serializer"
],
"_resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz",
"_shasum": "bd28773e2642881aec51544924299c5cd822185b",
"_shrinkwrap": null,
"_spec": "domelementtype@~1.1.1",
"_where": "F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\dom-serializer",
"author": {
"name": "Felix Boehm",
"email": "me@feedic.com"
},
"bugs": {
"url": "https://github.com/FB55/domelementtype/issues"
},
"dependencies": {},
"description": "all the types of nodes in htmlparser2's dom",
"devDependencies": {},
"directories": {},
"dist": {
"shasum": "bd28773e2642881aec51544924299c5cd822185b",
"tarball": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz"
},
"gitHead": "012a97a1d38737e096de2045b2b5f28768d8187e",
"homepage": "https://github.com/FB55/domelementtype",
"keywords": [
"dom",
"htmlparser2"
],
"main": "index.js",
"maintainers": [
{
"name": "feedic",
"email": "me@feedic.com"
}
],
"name": "domelementtype",
"optionalDependencies": {},
"readme": "ERROR: No README data found!",
"repository": {
"type": "git",
"url": "git://github.com/FB55/domelementtype.git"
},
"scripts": {},
"version": "1.1.3"
}
{
"_args": [
[
{
"raw": "dom-serializer@~0.1.0",
"scope": null,
"escapedName": "dom-serializer",
"name": "dom-serializer",
"rawSpec": "~0.1.0",
"spec": ">=0.1.0 <0.2.0",
"type": "range"
},
"F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\cheerio"
]
],
"_from": "dom-serializer@>=0.1.0 <0.2.0",
"_id": "dom-serializer@0.1.0",
"_inCache": true,
"_location": "/dom-serializer",
"_nodeVersion": "1.2.0",
"_npmUser": {
"name": "feedic",
"email": "me@feedic.com"
},
"_npmVersion": "2.4.1",
"_phantomChildren": {},
"_requested": {
"raw": "dom-serializer@~0.1.0",
"scope": null,
"escapedName": "dom-serializer",
"name": "dom-serializer",
"rawSpec": "~0.1.0",
"spec": ">=0.1.0 <0.2.0",
"type": "range"
},
"_requiredBy": [
"/cheerio",
"/domutils"
],
"_resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz",
"_shasum": "073c697546ce0780ce23be4a28e293e40bc30c82",
"_shrinkwrap": null,
"_spec": "dom-serializer@~0.1.0",
"_where": "F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\cheerio",
"author": {
"name": "Felix Boehm",
"email": "me@feedic.com"
},
"bugs": {
"url": "https://github.com/cheeriojs/dom-renderer/issues"
},
"dependencies": {
"domelementtype": "~1.1.1",
"entities": "~1.1.1"
},
"description": "render dom nodes to string",
"devDependencies": {
"cheerio": "*",
"expect.js": "~0.3.1",
"jshint": "~2.3.0",
"lodash": "~2.4.1",
"mocha": "*",
"xyz": "0.4.x"
},
"directories": {},
"dist": {
"shasum": "073c697546ce0780ce23be4a28e293e40bc30c82",
"tarball": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz"
},
"files": [
"index.js"
],
"gitHead": "249b9a921e6ba318c52b87de21e8475bcb4050e5",
"homepage": "https://github.com/cheeriojs/dom-renderer",
"keywords": [
"html",
"xml",
"render"
],
"license": "MIT",
"main": "./index.js",
"maintainers": [
{
"name": "feedic",
"email": "me@feedic.com"
},
{
"name": "davidchambers",
"email": "dc@davidchambers.me"
},
{
"name": "mattmueller",
"email": "mattmuelle@gmail.com"
}
],
"name": "dom-serializer",
"optionalDependencies": {},
"readme": "ERROR: No README data found!",
"repository": {
"type": "git",
"url": "git://github.com/cheeriojs/dom-renderer.git"
},
"scripts": {
"test": "mocha test.js"
},
"version": "0.1.0"
}
//Types of elements found in the DOM
module.exports = {
Text: "text", //Text
Directive: "directive", //<? ... ?>
Comment: "comment", //<!-- ... -->
Script: "script", //<script> tags
Style: "style", //<style> tags
Tag: "tag", //Any tag
CDATA: "cdata", //<![CDATA[ ... ]]>
Doctype: "doctype",
isTag: function(elem){
return elem.type === "tag" || elem.type === "script" || elem.type === "style";
}
};
Copyright (c) Felix Böhm
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{
"_args": [
[
{
"raw": "domelementtype@1",
"scope": null,
"escapedName": "domelementtype",
"name": "domelementtype",
"rawSpec": "1",
"spec": ">=1.0.0 <2.0.0",
"type": "range"
},
"F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\domutils"
]
],
"_from": "domelementtype@>=1.0.0 <2.0.0",
"_id": "domelementtype@1.3.0",
"_inCache": true,
"_location": "/domelementtype",
"_nodeVersion": "1.4.2",
"_npmUser": {
"name": "feedic",
"email": "me@feedic.com"
},
"_npmVersion": "2.6.1",
"_phantomChildren": {},
"_requested": {
"raw": "domelementtype@1",
"scope": null,
"escapedName": "domelementtype",
"name": "domelementtype",
"rawSpec": "1",
"spec": ">=1.0.0 <2.0.0",
"type": "range"
},
"_requiredBy": [
"/domhandler",
"/domutils",
"/htmlparser2"
],
"_resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz",
"_shasum": "b17aed82e8ab59e52dd9c19b1756e0fc187204c2",
"_shrinkwrap": null,
"_spec": "domelementtype@1",
"_where": "F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\domutils",
"author": {
"name": "Felix Boehm",
"email": "me@feedic.com"
},
"bugs": {
"url": "https://github.com/FB55/domelementtype/issues"
},
"dependencies": {},
"description": "all the types of nodes in htmlparser2's dom",
"devDependencies": {},
"directories": {},
"dist": {
"shasum": "b17aed82e8ab59e52dd9c19b1756e0fc187204c2",
"tarball": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz"
},
"gitHead": "2a95eed4c829ef479a88984d117cb5f4b379e6e8",
"homepage": "https://github.com/FB55/domelementtype",
"keywords": [
"dom",
"htmlparser2"
],
"main": "index.js",
"maintainers": [
{
"name": "feedic",
"email": "me@feedic.com"
}
],
"name": "domelementtype",
"optionalDependencies": {},
"readme": "ERROR: No README data found!",
"repository": {
"type": "git",
"url": "git://github.com/FB55/domelementtype.git"
},
"scripts": {},
"version": "1.3.0"
}

all the types of nodes in htmlparser2's dom

before_install:
- '[ "${TRAVIS_NODE_VERSION}" != "0.8" ] || npm install -g npm@1.4.28'
- npm install -g npm@latest
language: node_js
node_js:
- 0.8
- 0.10
var ElementType = require("domelementtype");
var re_whitespace = /\s+/g;
var NodePrototype = require("./lib/node");
var ElementPrototype = require("./lib/element");
function DomHandler(callback, options, elementCB){
if(typeof callback === "object"){
elementCB = options;
options = callback;
callback = null;
} else if(typeof options === "function"){
elementCB = options;
options = defaultOpts;
}
this._callback = callback;
this._options = options || defaultOpts;
this._elementCB = elementCB;
this.dom = [];
this._done = false;
this._tagStack = [];
this._parser = this._parser || null;
}
//default options
var defaultOpts = {
normalizeWhitespace: false, //Replace all whitespace with single spaces
withStartIndices: false, //Add startIndex properties to nodes
};
DomHandler.prototype.onparserinit = function(parser){
this._parser = parser;
};
//Resets the handler back to starting state
DomHandler.prototype.onreset = function(){
DomHandler.call(this, this._callback, this._options, this._elementCB);
};
//Signals the handler that parsing is done
DomHandler.prototype.onend = function(){
if(this._done) return;
this._done = true;
this._parser = null;
this._handleCallback(null);
};
DomHandler.prototype._handleCallback =
DomHandler.prototype.onerror = function(error){
if(typeof this._callback === "function"){
this._callback(error, this.dom);
} else {
if(error) throw error;
}
};
DomHandler.prototype.onclosetag = function(){
//if(this._tagStack.pop().name !== name) this._handleCallback(Error("Tagname didn't match!"));
var elem = this._tagStack.pop();
if(this._elementCB) this._elementCB(elem);
};
DomHandler.prototype._addDomElement = function(element){
var parent = this._tagStack[this._tagStack.length - 1];
var siblings = parent ? parent.children : this.dom;
var previousSibling = siblings[siblings.length - 1];
element.next = null;
if(this._options.withStartIndices){
element.startIndex = this._parser.startIndex;
}
if (this._options.withDomLvl1) {
element.__proto__ = element.type === "tag" ? ElementPrototype : NodePrototype;
}
if(previousSibling){
element.prev = previousSibling;
previousSibling.next = element;
} else {
element.prev = null;
}
siblings.push(element);
element.parent = parent || null;
};
DomHandler.prototype.onopentag = function(name, attribs){
var element = {
type: name === "script" ? ElementType.Script : name === "style" ? ElementType.Style : ElementType.Tag,
name: name,
attribs: attribs,
children: []
};
this._addDomElement(element);
this._tagStack.push(element);
};
DomHandler.prototype.ontext = function(data){
//the ignoreWhitespace is officially dropped, but for now,
//it's an alias for normalizeWhitespace
var normalize = this._options.normalizeWhitespace || this._options.ignoreWhitespace;
var lastTag;
if(!this._tagStack.length && this.dom.length && (lastTag = this.dom[this.dom.length-1]).type === ElementType.Text){
if(normalize){
lastTag.data = (lastTag.data + data).replace(re_whitespace, " ");
} else {
lastTag.data += data;
}
} else {
if(
this._tagStack.length &&
(lastTag = this._tagStack[this._tagStack.length - 1]) &&
(lastTag = lastTag.children[lastTag.children.length - 1]) &&
lastTag.type === ElementType.Text
){
if(normalize){
lastTag.data = (lastTag.data + data).replace(re_whitespace, " ");
} else {
lastTag.data += data;
}
} else {
if(normalize){
data = data.replace(re_whitespace, " ");
}
this._addDomElement({
data: data,
type: ElementType.Text
});
}
}
};
DomHandler.prototype.oncomment = function(data){
var lastTag = this._tagStack[this._tagStack.length - 1];
if(lastTag && lastTag.type === ElementType.Comment){
lastTag.data += data;
return;
}
var element = {
data: data,
type: ElementType.Comment
};
this._addDomElement(element);
this._tagStack.push(element);
};
DomHandler.prototype.oncdatastart = function(){
var element = {
children: [{
data: "",
type: ElementType.Text
}],
type: ElementType.CDATA
};
this._addDomElement(element);
this._tagStack.push(element);
};
DomHandler.prototype.oncommentend = DomHandler.prototype.oncdataend = function(){
this._tagStack.pop();
};
DomHandler.prototype.onprocessinginstruction = function(name, data){
this._addDomElement({
name: name,
data: data,
type: ElementType.Directive
});
};
module.exports = DomHandler;
// DOM-Level-1-compliant structure
var NodePrototype = require('./node');
var ElementPrototype = module.exports = Object.create(NodePrototype);
var domLvl1 = {
tagName: "name"
};
Object.keys(domLvl1).forEach(function(key) {
var shorthand = domLvl1[key];
Object.defineProperty(ElementPrototype, key, {
get: function() {
return this[shorthand] || null;
},
set: function(val) {
this[shorthand] = val;
return val;
}
});
});
// This object will be used as the prototype for Nodes when creating a
// DOM-Level-1-compliant structure.
var NodePrototype = module.exports = {
get firstChild() {
var children = this.children;
return children && children[0] || null;
},
get lastChild() {
var children = this.children;
return children && children[children.length - 1] || null;
},
get nodeType() {
return nodeTypes[this.type] || nodeTypes.element;
}
};
var domLvl1 = {
tagName: "name",
childNodes: "children",
parentNode: "parent",
previousSibling: "prev",
nextSibling: "next",
nodeValue: "data"
};
var nodeTypes = {
element: 1,
text: 3,
cdata: 4,
comment: 8
};
Object.keys(domLvl1).forEach(function(key) {
var shorthand = domLvl1[key];
Object.defineProperty(NodePrototype, key, {
get: function() {
return this[shorthand] || null;
},
set: function(val) {
this[shorthand] = val;
return val;
}
});
});
Copyright (c) Felix Böhm
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{
"_args": [
[
{
"raw": "domhandler@^2.3.0",
"scope": null,
"escapedName": "domhandler",
"name": "domhandler",
"rawSpec": "^2.3.0",
"spec": ">=2.3.0 <3.0.0",
"type": "range"
},
"F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\htmlparser2"
]
],
"_from": "domhandler@>=2.3.0 <3.0.0",
"_id": "domhandler@2.3.0",
"_inCache": true,
"_location": "/domhandler",
"_nodeVersion": "0.10.32",
"_npmUser": {
"name": "feedic",
"email": "me@feedic.com"
},
"_npmVersion": "2.1.5",
"_phantomChildren": {},
"_requested": {
"raw": "domhandler@^2.3.0",
"scope": null,
"escapedName": "domhandler",
"name": "domhandler",
"rawSpec": "^2.3.0",
"spec": ">=2.3.0 <3.0.0",
"type": "range"
},
"_requiredBy": [
"/htmlparser2"
],
"_resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz",
"_shasum": "2de59a0822d5027fabff6f032c2b25a2a8abe738",
"_shrinkwrap": null,
"_spec": "domhandler@^2.3.0",
"_where": "F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\htmlparser2",
"author": {
"name": "Felix Boehm",
"email": "me@feedic.com"
},
"bugs": {
"url": "https://github.com/fb55/DomHandler/issues"
},
"dependencies": {
"domelementtype": "1"
},
"description": "handler for htmlparser2 that turns pages into a dom",
"devDependencies": {
"htmlparser2": "3.8",
"jshint": "~2.3.0",
"mocha": "1"
},
"directories": {
"test": "tests"
},
"dist": {
"shasum": "2de59a0822d5027fabff6f032c2b25a2a8abe738",
"tarball": "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz"
},
"gitHead": "9c224be43a43bc54ebfc2d2e47ab3b9f97836cb2",
"homepage": "https://github.com/fb55/DomHandler",
"jshintConfig": {
"quotmark": "double",
"trailing": true,
"unused": true,
"undef": true,
"node": true,
"proto": true,
"globals": {
"it": true
}
},
"keywords": [
"dom",
"htmlparser2"
],
"main": "index.js",
"maintainers": [
{
"name": "feedic",
"email": "me@feedic.com"
}
],
"name": "domhandler",
"optionalDependencies": {},
"readme": "ERROR: No README data found!",
"repository": {
"type": "git",
"url": "git://github.com/fb55/DomHandler.git"
},
"scripts": {
"test": "mocha -R list && jshint index.js test/"
},
"version": "2.3.0"
}

#DOMHandler Build Status

The DOM handler (formally known as DefaultHandler) creates a tree containing all nodes of a page. The tree may be manipulated using the DOMUtils library.

##Usage

var handler = new DomHandler([ <func> callback(err, dom), ] [ <obj> options ]);
// var parser = new Parser(handler[, options]);

##Example

var htmlparser = require("htmlparser2");
var rawHtml = "Xyz <script language= javascript>var foo = '<<bar>>';< /  script><!--<!-- Waah! -- -->";
var handler = new htmlparser.DomHandler(function (error, dom) {
    if (error)
    	[...do something for errors...]
    else
    	[...parsing done, do something...]
        console.log(dom);
});
var parser = new htmlparser.Parser(handler);
parser.write(rawHtml);
parser.done();

Output:

[{
    data: 'Xyz ',
    type: 'text'
}, {
    type: 'script',
    name: 'script',
    attribs: {
    	language: 'javascript'
    },
    children: [{
    	data: 'var foo = \'<bar>\';<',
    	type: 'text'
    }]
}, {
    data: '<!-- Waah! -- ',
    type: 'comment'
}]

##Option: normalizeWhitespace Indicates whether the whitespace in text nodes should be normalized (= all whitespace should be replaced with single spaces). The default value is "false".

The following HTML will be used:

<font>
	<br>this is the text
<font>

###Example: true

[{
    type: 'tag',
    name: 'font',
    children: [{
    	data: ' ',
    	type: 'text'
    }, {
    	type: 'tag',
    	name: 'br'
    }, {
    	data: 'this is the text ',
    	type: 'text'
    }, {
    	type: 'tag',
    	name: 'font'
    }]
}]

###Example: false

[{
    type: 'tag',
    name: 'font',
    children: [{
    	data: '\n\t',
    	type: 'text'
    }, {
    	type: 'tag',
    	name: 'br'
    }, {
    	data: 'this is the text\n',
    	type: 'text'
    }, {
    	type: 'tag',
    	name: 'font'
    }]
}]

##Option: withStartIndices Indicates whether a startIndex property will be added to nodes. When the parser is used in a non-streaming fashion, startIndex is an integer indicating the position of the start of the node in the document. The default value is "false".

{
"name": "Basic test",
"options": {},
"html": "<!DOCTYPE html><html><title>The Title</title><body>Hello world</body></html>",
"expected": [
{
"name": "!doctype",
"data": "!DOCTYPE html",
"type": "directive"
},
{
"type": "tag",
"name": "html",
"attribs": {},
"parent": null,
"children": [
{
"type": "tag",
"name": "title",
"attribs": {},
"parent": {
"type": "tag",
"name": "html",
"attribs": {}
},
"children": [
{
"data": "The Title",
"type": "text",
"parent": {
"type": "tag",
"name": "title",
"attribs": {}
}
}
]
},
{
"type": "tag",
"name": "body",
"attribs": {},
"children": [
{
"data": "Hello world",
"type": "text"
}
],
"prev": {
"type": "tag",
"name": "title",
"attribs": {}
}
}
]
}
]
}
{
"name": "Single Tag 1",
"options": {},
"html": "<br>text</br>",
"expected": [
{
"type": "tag",
"name": "br",
"attribs": {}
},
{
"data": "text",
"type": "text"
},
{
"type": "tag",
"name": "br",
"attribs": {}
}
]
}
{
"name": "Single Tag 2",
"options": {},
"html": "<br>text<br>",
"expected": [
{
"type": "tag",
"name": "br",
"attribs": {}
},
{
"data": "text",
"type": "text"
},
{
"type": "tag",
"name": "br",
"attribs": {}
}
]
}
{
"name": "Unescaped chars in script",
"options": {},
"html": "<head><script language=\"Javascript\">var foo = \"<bar>\"; alert(2 > foo); var baz = 10 << 2; var zip = 10 >> 1; var yap = \"<<>>>><<\";</script></head>",
"expected": [
{
"type": "tag",
"name": "head",
"attribs": {},
"children": [
{
"type": "script",
"name": "script",
"attribs": {
"language": "Javascript"
},
"children": [
{
"data": "var foo = \"<bar>\"; alert(2 > foo); var baz = 10 << 2; var zip = 10 >> 1; var yap = \"<<>>>><<\";",
"type": "text"
}
]
}
]
}
]
}
{
"name": "Special char in comment",
"options": {},
"html": "<head><!-- commented out tags <title>Test</title>--></head>",
"expected": [
{
"type": "tag",
"name": "head",
"attribs": {},
"children": [
{
"data": " commented out tags <title>Test</title>",
"type": "comment"
}
]
}
]
}
{
"name": "Script source in comment",
"options": {},
"html": "<script><!--var foo = 1;--></script>",
"expected": [
{
"type": "script",
"name": "script",
"attribs": {},
"children": [
{
"data": "<!--var foo = 1;-->",
"type": "text"
}
]
}
]
}
{
"name": "Unescaped chars in style",
"options": {},
"html": "<style type=\"text/css\">\n body > p\n\t{ font-weight: bold; }</style>",
"expected": [
{
"type": "style",
"name": "style",
"attribs": {
"type": "text/css"
},
"children": [
{
"data": "\n body > p\n\t{ font-weight: bold; }",
"type": "text"
}
]
}
]
}
{
"name": "Extra spaces in tag",
"options": {},
"html": "<font\t\n size='14' \n>the text</\t\nfont\t \n>",
"expected": [
{
"type": "tag",
"name": "font",
"attribs": {
"size": "14"
},
"children": [
{
"data": "the text",
"type": "text"
}
]
}
]
}
{
"name": "Unquoted attributes",
"options": {},
"html": "<font size= 14>the text</font>",
"expected": [
{
"type": "tag",
"name": "font",
"attribs": {
"size": "14"
},
"children": [
{
"data": "the text",
"type": "text"
}
]
}
]
}
{
"name": "Singular attribute",
"options": {},
"html": "<option value='foo' selected>",
"expected": [
{
"type": "tag",
"name": "option",
"attribs": {
"value": "foo",
"selected": ""
}
}
]
}
{
"name": "Text outside tags",
"options": {},
"html": "Line one\n<br>\nline two",
"expected": [
{
"data": "Line one\n",
"type": "text",
"prev": null,
"next": {
"type": "tag",
"name": "br",
"attribs": {}
}
},
{
"type": "tag",
"name": "br",
"attribs": {},
"prev": {
"data": "Line one\n",
"type": "text"
},
"next": {
"data": "\nline two",
"type": "text"
}
},
{
"data": "\nline two",
"type": "text",
"prev": {
"type": "tag",
"name": "br",
"attribs": {}
},
"next": null
}
]
}
{
"name": "Only text",
"options": {},
"html": "this is the text",
"expected": [
{
"data": "this is the text",
"type": "text"
}
]
}
{
"name": "Comment within text",
"options": {},
"html": "this is <!-- the comment --> the text",
"expected": [
{
"data": "this is ",
"type": "text"
},
{
"data": " the comment ",
"type": "comment"
},
{
"data": " the text",
"type": "text"
}
]
}
{
"name": "Comment within text within script",
"options": {},
"html": "<script>this is <!-- the comment --> the text</script>",
"expected": [
{
"type": "script",
"name": "script",
"attribs": {},
"children": [
{
"data": "this is <!-- the comment --> the text",
"type": "text"
}
]
}
]
}
{
"name": "Option 'verbose' set to 'false'",
"options": {
"verbose": false
},
"html": "<font\t\n size='14' \n>the text</\t\nfont\t \n>",
"expected": [
{
"type": "tag",
"name": "font",
"attribs": {
"size": "14"
},
"children": [
{
"data": "the text",
"type": "text"
}
]
}
]
}
{
"name": "Normalize whitespace",
"options": {
"normalizeWhitespace": true
},
"html": "Line one\n<br>\t \r\n\f <br>\nline two<font><br> x </font>",
"expected": [
{
"data": "Line one ",
"type": "text"
},
{
"type": "tag",
"name": "br",
"attribs": {}
},
{
"data": " ",
"type": "text"
},
{
"type": "tag",
"name": "br",
"attribs": {}
},
{
"data": " line two",
"type": "text"
},
{
"type": "tag",
"name": "font",
"attribs": {},
"children": [
{
"type": "tag",
"name": "br",
"attribs": {}
},
{
"data": " x ",
"type": "text"
}
]
}
]
}
{
"name": "XML Namespace",
"options": {},
"html": "<ns:tag>text</ns:tag>",
"expected": [
{
"type": "tag",
"name": "ns:tag",
"attribs": {},
"children": [
{
"data": "text",
"type": "text"
}
]
}
]
}
{
"name": "Enforce empty tags",
"options": {},
"html": "<link>text</link>",
"expected": [
{
"type": "tag",
"name": "link",
"attribs": {}
},
{
"data": "text",
"type": "text"
}
]
}
{
"name": "Ignore empty tags (xml mode)",
"options": {
"xmlMode": true
},
"html": "<link>text</link>",
"expected": [
{
"type": "tag",
"name": "link",
"attribs": {},
"children": [
{
"data": "text",
"type": "text"
}
]
}
]
}
{
"name": "Template script tags",
"options": {},
"html": "<script type=\"text/template\"><h1>Heading1</h1></script>",
"expected": [
{
"type": "script",
"name": "script",
"attribs": {
"type": "text/template"
},
"children": [
{
"data": "<h1>Heading1</h1>",
"type": "text"
}
]
}
]
}
{
"name": "Conditional comments",
"options": {},
"html": "<!--[if lt IE 7]> <html class='no-js ie6 oldie' lang='en'> <![endif]--><!--[if lt IE 7]> <html class='no-js ie6 oldie' lang='en'> <![endif]-->",
"expected": [
{
"data": "[if lt IE 7]> <html class='no-js ie6 oldie' lang='en'> <![endif]",
"type": "comment"
},
{
"data": "[if lt IE 7]> <html class='no-js ie6 oldie' lang='en'> <![endif]",
"type": "comment"
}
]
}
{
"name": "lowercase tags",
"options": {},
"html": "<!DOCTYPE html><HTML><TITLE>The Title</title><BODY>Hello world</body></html>",
"expected": [
{
"name": "!doctype",
"data": "!DOCTYPE html",
"type": "directive"
},
{
"type": "tag",
"name": "html",
"attribs": {},
"children": [
{
"type": "tag",
"name": "title",
"attribs": {},
"children": [
{
"data": "The Title",
"type": "text"
}
]
},
{
"type": "tag",
"name": "body",
"attribs": {},
"children": [
{
"data": "Hello world",
"type": "text"
}
]
}
]
}
]
}
{
"name": "DOM level 1",
"options": { "withDomLvl1": true },
"html": "<div>some stray text<h1>Hello, world.</h1><!-- comment node -->more stray text</div>",
"expected": [
{
"type": "tag",
"nodeType": 1,
"name": "div",
"tagName": "div",
"attribs": {},
"nodeValue": null,
"children": [
{
"type": "text",
"nodeType": 3,
"tagName": null,
"data": "some stray text",
"nodeValue": "some stray text",
"childNodes": null,
"firstChild": null,
"lastChild": null
},
{
"type": "tag",
"nodeType": 1,
"name": "h1",
"tagName": "h1",
"nodeValue": null,
"attribs": {},
"children": [
{
"type": "text",
"nodeType": 3,
"tagName": null,
"data": "Hello, world.",
"nodeValue": "Hello, world.",
"childNodes": null,
"firstChild": null,
"lastChild": null
}
],
"firstChild": {
"type": "text",
"nodeType": 3,
"tagName": null,
"data": "Hello, world.",
"nodeValue": "Hello, world.",
"childNodes": null,
"firstChild": null,
"lastChild": null
},
"lastChild": {
"type": "text",
"nodeType": 3,
"tagName": null,
"data": "Hello, world.",
"nodeValue": "Hello, world.",
"childNodes": null,
"firstChild": null,
"lastChild": null
}
},
{
"type": "comment",
"nodeType": 8,
"tagName": null,
"data": " comment node ",
"nodeValue": " comment node ",
"childNodes": null,
"firstChild": null,
"lastChild": null,
"prev": {
"type": "tag",
"name": "h1",
"nodeValue": null,
"attribs": {}
},
"previousSibling": {
"type": "tag",
"name": "h1",
"nodeValue": null,
"attribs": {}
},
"next": {
"type": "text",
"tagName": null,
"data": "more stray text"
},
"nextSibling": {
"type": "text",
"tagName": null,
"data": "more stray text"
}
},
{
"type": "text",
"nodeType": 3,
"tagName": null,
"data": "more stray text",
"nodeValue": "more stray text",
"childNodes": null,
"firstChild": null,
"lastChild": null,
"next": null,
"nextSibling": null
}
],
"firstChild": {
"type": "text",
"nodeType": 3,
"tagName": null,
"data": "some stray text",
"nodeValue": "some stray text",
"childNodes": null,
"firstChild": null,
"lastChild": null
},
"lastChild": {
"type": "text",
"nodeType": 3,
"tagName": null,
"data": "more stray text",
"nodeValue": "more stray text",
"childNodes": null,
"firstChild": null,
"lastChild": null
}
}
]
}
{
"name": "withStartIndices adds correct startIndex properties",
"options": {"withStartIndices": true},
"streaming": false,
"html": "<!DOCTYPE html> <html> <title>The Title</title> <body class='foo'>Hello world <p></p></body> <!-- the comment --> </html> ",
"expected": [
{
"startIndex": 0,
"name": "!doctype",
"data": "!DOCTYPE html",
"type": "directive"
},
{
"type": "text",
"data": " "
},
{
"startIndex": 16,
"type": "tag",
"name": "html",
"attribs": {},
"parent": null,
"children": [
{
"startIndex": 22,
"type": "text",
"data": " "
},
{
"startIndex": 23,
"type": "tag",
"name": "title",
"attribs": {},
"children": [
{
"startIndex": 30,
"data": "The Title",
"type": "text"
}
]
},
{
"startIndex": 47,
"type": "text",
"data": " "
},
{
"startIndex": 48,
"type": "tag",
"name": "body",
"attribs": {"class": "foo"},
"children": [
{
"startIndex": 66,
"data": "Hello world ",
"type": "text"
},
{
"startIndex": 78,
"type": "tag",
"name": "p",
"attribs": {},
"children": []
}
]
},
{
"startIndex": 92,
"type": "text",
"data": " "
},
{
"startIndex": 93,
"type": "comment",
"data": " the comment "
},
{
"startIndex": 113,
"type": "text",
"data": " "
}
]
}
]
}
var fs = require("fs"),
path = require("path"),
assert = require("assert"),
util = require("util"),
Parser = require("htmlparser2").Parser,
Handler = require("../");
var basePath = path.resolve(__dirname, "cases"),
inspectOpts = { showHidden: true, depth: null };
fs
.readdirSync(basePath)
.filter(RegExp.prototype.test, /\.json$/) //only allow .json files
.map(function(name){
return path.resolve(basePath, name);
})
.map(require)
.forEach(function(test){
it(test.name, function(){
var expected = test.expected;
var handler = new Handler(function(err, actual){
assert.ifError(err);
try {
compare(expected, actual);
} catch(e){
e.expected = util.inspect(expected, inspectOpts);
e.actual = util.inspect(actual, inspectOpts);
throw e;
}
}, test.options);
var data = test.html;
var parser = new Parser(handler, test.options);
//first, try to run the test via chunks
if (test.streaming || test.streaming === undefined){
for(var i = 0; i < data.length; i++){
parser.write(data.charAt(i));
}
parser.done();
}
//then parse everything
parser.parseComplete(data);
});
});
function compare(expected, result){
assert.equal(typeof expected, typeof result, "types didn't match");
if(typeof expected !== "object" || expected === null){
assert.strictEqual(expected, result, "result doesn't equal expected");
} else {
for(var prop in expected){
assert.ok(prop in result, "result didn't contain property " + prop);
compare(expected[prop], result[prop]);
}
}
}
var DomUtils = module.exports;
[
require("./lib/stringify"),
require("./lib/traversal"),
require("./lib/manipulation"),
require("./lib/querying"),
require("./lib/legacy"),
require("./lib/helpers")
].forEach(function(ext){
Object.keys(ext).forEach(function(key){
DomUtils[key] = ext[key].bind(DomUtils);
});
});
// removeSubsets
// Given an array of nodes, remove any member that is contained by another.
exports.removeSubsets = function(nodes) {
var idx = nodes.length, node, ancestor, replace;
// Check if each node (or one of its ancestors) is already contained in the
// array.
while (--idx > -1) {
node = ancestor = nodes[idx];
// Temporarily remove the node under consideration
nodes[idx] = null;
replace = true;
while (ancestor) {
if (nodes.indexOf(ancestor) > -1) {
replace = false;
nodes.splice(idx, 1);
break;
}
ancestor = ancestor.parent;
}
// If the node has been found to be unique, re-insert it.
if (replace) {
nodes[idx] = node;
}
}
return nodes;
};
// Source: http://dom.spec.whatwg.org/#dom-node-comparedocumentposition
var POSITION = {
DISCONNECTED: 1,
PRECEDING: 2,
FOLLOWING: 4,
CONTAINS: 8,
CONTAINED_BY: 16
};
// Compare the position of one node against another node in any other document.
// The return value is a bitmask with the following values:
//
// document order:
// > There is an ordering, document order, defined on all the nodes in the
// > document corresponding to the order in which the first character of the
// > XML representation of each node occurs in the XML representation of the
// > document after expansion of general entities. Thus, the document element
// > node will be the first node. Element nodes occur before their children.
// > Thus, document order orders element nodes in order of the occurrence of
// > their start-tag in the XML (after expansion of entities). The attribute
// > nodes of an element occur after the element and before its children. The
// > relative order of attribute nodes is implementation-dependent./
// Source:
// http://www.w3.org/TR/DOM-Level-3-Core/glossary.html#dt-document-order
//
// @argument {Node} nodaA The first node to use in the comparison
// @argument {Node} nodeB The second node to use in the comparison
//
// @return {Number} A bitmask describing the input nodes' relative position.
// See http://dom.spec.whatwg.org/#dom-node-comparedocumentposition for
// a description of these values.
var comparePos = exports.compareDocumentPosition = function(nodeA, nodeB) {
var aParents = [];
var bParents = [];
var current, sharedParent, siblings, aSibling, bSibling, idx;
if (nodeA === nodeB) {
return 0;
}
current = nodeA;
while (current) {
aParents.unshift(current);
current = current.parent;
}
current = nodeB;
while (current) {
bParents.unshift(current);
current = current.parent;
}
idx = 0;
while (aParents[idx] === bParents[idx]) {
idx++;
}
if (idx === 0) {
return POSITION.DISCONNECTED;
}
sharedParent = aParents[idx - 1];
siblings = sharedParent.children;
aSibling = aParents[idx];
bSibling = bParents[idx];
if (siblings.indexOf(aSibling) > siblings.indexOf(bSibling)) {
if (sharedParent === nodeB) {
return POSITION.FOLLOWING | POSITION.CONTAINED_BY;
}
return POSITION.FOLLOWING;
} else {
if (sharedParent === nodeA) {
return POSITION.PRECEDING | POSITION.CONTAINS;
}
return POSITION.PRECEDING;
}
};
// Sort an array of nodes based on their relative position in the document and
// remove any duplicate nodes. If the array contains nodes that do not belong
// to the same document, sort order is unspecified.
//
// @argument {Array} nodes Array of DOM nodes
//
// @returns {Array} collection of unique nodes, sorted in document order
exports.uniqueSort = function(nodes) {
var idx = nodes.length, node, position;
nodes = nodes.slice();
while (--idx > -1) {
node = nodes[idx];
position = nodes.indexOf(node);
if (position > -1 && position < idx) {
nodes.splice(idx, 1);
}
}
nodes.sort(function(a, b) {
var relative = comparePos(a, b);
if (relative & POSITION.PRECEDING) {
return -1;
} else if (relative & POSITION.FOLLOWING) {
return 1;
}
return 0;
});
return nodes;
};
var ElementType = require("domelementtype");
var isTag = exports.isTag = ElementType.isTag;
exports.testElement = function(options, element){
for(var key in options){
if(!options.hasOwnProperty(key));
else if(key === "tag_name"){
if(!isTag(element) || !options.tag_name(element.name)){
return false;
}
} else if(key === "tag_type"){
if(!options.tag_type(element.type)) return false;
} else if(key === "tag_contains"){
if(isTag(element) || !options.tag_contains(element.data)){
return false;
}
} else if(!element.attribs || !options[key](element.attribs[key])){
return false;
}
}
return true;
};
var Checks = {
tag_name: function(name){
if(typeof name === "function"){
return function(elem){ return isTag(elem) && name(elem.name); };
} else if(name === "*"){
return isTag;
} else {
return function(elem){ return isTag(elem) && elem.name === name; };
}
},
tag_type: function(type){
if(typeof type === "function"){
return function(elem){ return type(elem.type); };
} else {
return function(elem){ return elem.type === type; };
}
},
tag_contains: function(data){
if(typeof data === "function"){
return function(elem){ return !isTag(elem) && data(elem.data); };
} else {
return function(elem){ return !isTag(elem) && elem.data === data; };
}
}
};
function getAttribCheck(attrib, value){
if(typeof value === "function"){
return function(elem){ return elem.attribs && value(elem.attribs[attrib]); };
} else {
return function(elem){ return elem.attribs && elem.attribs[attrib] === value; };
}
}
function combineFuncs(a, b){
return function(elem){
return a(elem) || b(elem);
};
}
exports.getElements = function(options, element, recurse, limit){
var funcs = Object.keys(options).map(function(key){
var value = options[key];
return key in Checks ? Checks[key](value) : getAttribCheck(key, value);
});
return funcs.length === 0 ? [] : this.filter(
funcs.reduce(combineFuncs),
element, recurse, limit
);
};
exports.getElementById = function(id, element, recurse){
if(!Array.isArray(element)) element = [element];
return this.findOne(getAttribCheck("id", id), element, recurse !== false);
};
exports.getElementsByTagName = function(name, element, recurse, limit){
return this.filter(Checks.tag_name(name), element, recurse, limit);
};
exports.getElementsByTagType = function(type, element, recurse, limit){
return this.filter(Checks.tag_type(type), element, recurse, limit);
};
exports.removeElement = function(elem){
if(elem.prev) elem.prev.next = elem.next;
if(elem.next) elem.next.prev = elem.prev;
if(elem.parent){
var childs = elem.parent.children;
childs.splice(childs.lastIndexOf(elem), 1);
}
};
exports.replaceElement = function(elem, replacement){
var prev = replacement.prev = elem.prev;
if(prev){
prev.next = replacement;
}
var next = replacement.next = elem.next;
if(next){
next.prev = replacement;
}
var parent = replacement.parent = elem.parent;
if(parent){
var childs = parent.children;
childs[childs.lastIndexOf(elem)] = replacement;
}
};
exports.appendChild = function(elem, child){
child.parent = elem;
if(elem.children.push(child) !== 1){
var sibling = elem.children[elem.children.length - 2];
sibling.next = child;
child.prev = sibling;
child.next = null;
}
};
exports.append = function(elem, next){
var parent = elem.parent,
currNext = elem.next;
next.next = currNext;
next.prev = elem;
elem.next = next;
next.parent = parent;
if(currNext){
currNext.prev = next;
if(parent){
var childs = parent.children;
childs.splice(childs.lastIndexOf(currNext), 0, next);
}
} else if(parent){
parent.children.push(next);
}
};
exports.prepend = function(elem, prev){
var parent = elem.parent;
if(parent){
var childs = parent.children;
childs.splice(childs.lastIndexOf(elem), 0, prev);
}
if(elem.prev){
elem.prev.next = prev;
}
prev.parent = parent;
prev.prev = elem.prev;
prev.next = elem;
elem.prev = prev;
};
var isTag = require("domelementtype").isTag;
module.exports = {
filter: filter,
find: find,
findOneChild: findOneChild,
findOne: findOne,
existsOne: existsOne,
findAll: findAll
};
function filter(test, element, recurse, limit){
if(!Array.isArray(element)) element = [element];
if(typeof limit !== "number" || !isFinite(limit)){
limit = Infinity;
}
return find(test, element, recurse !== false, limit);
}
function find(test, elems, recurse, limit){
var result = [], childs;
for(var i = 0, j = elems.length; i < j; i++){
if(test(elems[i])){
result.push(elems[i]);
if(--limit <= 0) break;
}
childs = elems[i].children;
if(recurse && childs && childs.length > 0){
childs = find(test, childs, recurse, limit);
result = result.concat(childs);
limit -= childs.length;
if(limit <= 0) break;
}
}
return result;
}
function findOneChild(test, elems){
for(var i = 0, l = elems.length; i < l; i++){
if(test(elems[i])) return elems[i];
}
return null;
}
function findOne(test, elems){
var elem = null;
for(var i = 0, l = elems.length; i < l && !elem; i++){
if(!isTag(elems[i])){
continue;
} else if(test(elems[i])){
elem = elems[i];
} else if(elems[i].children.length > 0){
elem = findOne(test, elems[i].children);
}
}
return elem;
}
function existsOne(test, elems){
for(var i = 0, l = elems.length; i < l; i++){
if(
isTag(elems[i]) && (
test(elems[i]) || (
elems[i].children.length > 0 &&
existsOne(test, elems[i].children)
)
)
){
return true;
}
}
return false;
}
function findAll(test, elems){
var result = [];
for(var i = 0, j = elems.length; i < j; i++){
if(!isTag(elems[i])) continue;
if(test(elems[i])) result.push(elems[i]);
if(elems[i].children.length > 0){
result = result.concat(findAll(test, elems[i].children));
}
}
return result;
}
var ElementType = require("domelementtype"),
getOuterHTML = require("dom-serializer"),
isTag = ElementType.isTag;
module.exports = {
getInnerHTML: getInnerHTML,
getOuterHTML: getOuterHTML,
getText: getText
};
function getInnerHTML(elem, opts){
return elem.children ? elem.children.map(function(elem){
return getOuterHTML(elem, opts);
}).join("") : "";
}
function getText(elem){
if(Array.isArray(elem)) return elem.map(getText).join("");
if(isTag(elem) || elem.type === ElementType.CDATA) return getText(elem.children);
if(elem.type === ElementType.Text) return elem.data;
return "";
}
var getChildren = exports.getChildren = function(elem){
return elem.children;
};
var getParent = exports.getParent = function(elem){
return elem.parent;
};
exports.getSiblings = function(elem){
var parent = getParent(elem);
return parent ? getChildren(parent) : [elem];
};
exports.getAttributeValue = function(elem, name){
return elem.attribs && elem.attribs[name];
};
exports.hasAttrib = function(elem, name){
return !!elem.attribs && hasOwnProperty.call(elem.attribs, name);
};
exports.getName = function(elem){
return elem.name;
};
Copyright (c) Felix Böhm
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{
"_args": [
[
{
"raw": "domutils@1.5.1",
"scope": null,
"escapedName": "domutils",
"name": "domutils",
"rawSpec": "1.5.1",
"spec": "1.5.1",
"type": "version"
},
"F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\css-select"
]
],
"_from": "domutils@1.5.1",
"_id": "domutils@1.5.1",
"_inCache": true,
"_location": "/domutils",
"_nodeVersion": "1.0.4",
"_npmUser": {
"name": "feedic",
"email": "me@feedic.com"
},
"_npmVersion": "2.3.0",
"_phantomChildren": {},
"_requested": {
"raw": "domutils@1.5.1",
"scope": null,
"escapedName": "domutils",
"name": "domutils",
"rawSpec": "1.5.1",
"spec": "1.5.1",
"type": "version"
},
"_requiredBy": [
"/css-select",
"/htmlparser2"
],
"_resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz",
"_shasum": "dcd8488a26f563d61079e48c9f7b7e32373682cf",
"_shrinkwrap": null,
"_spec": "domutils@1.5.1",
"_where": "F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\css-select",
"author": {
"name": "Felix Boehm",
"email": "me@feedic.com"
},
"bugs": {
"url": "https://github.com/FB55/domutils/issues"
},
"dependencies": {
"dom-serializer": "0",
"domelementtype": "1"
},
"description": "utilities for working with htmlparser2's dom",
"devDependencies": {
"domhandler": "2",
"htmlparser2": "~3.3.0",
"jshint": "~2.3.0",
"mocha": "~1.15.1"
},
"directories": {
"test": "tests"
},
"dist": {
"shasum": "dcd8488a26f563d61079e48c9f7b7e32373682cf",
"tarball": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz"
},
"gitHead": "7d4bd16cd36ffce62362ef91616806ea27e30d95",
"homepage": "https://github.com/FB55/domutils",
"jshintConfig": {
"proto": true,
"unused": true,
"eqnull": true,
"undef": true,
"quotmark": "double",
"eqeqeq": true,
"trailing": true,
"node": true,
"globals": {
"describe": true,
"it": true,
"beforeEach": true
}
},
"keywords": [
"dom",
"htmlparser2"
],
"main": "index.js",
"maintainers": [
{
"name": "feedic",
"email": "me@feedic.com"
}
],
"name": "domutils",
"optionalDependencies": {},
"readme": "ERROR: No README data found!",
"repository": {
"type": "git",
"url": "git://github.com/FB55/domutils.git"
},
"scripts": {
"test": "mocha test/tests/**.js && jshint index.js test/**/*.js lib/*.js"
},
"version": "1.5.1"
}

utilities for working with htmlparser2's dom

var makeDom = require("./utils").makeDom;
var markup = Array(21).join(
"<?xml><tag1 id='asdf'> <script>text</script> <!-- comment --> <tag2> text </tag1>"
);
module.exports = makeDom(markup);
var makeDom = require("../utils").makeDom;
var helpers = require("../..");
var assert = require("assert");
describe("helpers", function() {
describe("removeSubsets", function() {
var removeSubsets = helpers.removeSubsets;
var dom = makeDom("<div><p><span></span></p><p></p></div>")[0];
it("removes identical trees", function() {
var matches = removeSubsets([dom, dom]);
assert.equal(matches.length, 1);
});
it("Removes subsets found first", function() {
var matches = removeSubsets([dom, dom.children[0].children[0]]);
assert.equal(matches.length, 1);
});
it("Removes subsets found last", function() {
var matches = removeSubsets([dom.children[0], dom]);
assert.equal(matches.length, 1);
});
it("Does not remove unique trees", function() {
var matches = removeSubsets([dom.children[0], dom.children[1]]);
assert.equal(matches.length, 2);
});
});
describe("compareDocumentPosition", function() {
var compareDocumentPosition = helpers.compareDocumentPosition;
var markup = "<div><p><span></span></p><a></a></div>";
var dom = makeDom(markup)[0];
var p = dom.children[0];
var span = p.children[0];
var a = dom.children[1];
it("reports when the first node occurs before the second indirectly", function() {
assert.equal(compareDocumentPosition(span, a), 2);
});
it("reports when the first node contains the second", function() {
assert.equal(compareDocumentPosition(p, span), 10);
});
it("reports when the first node occurs after the second indirectly", function() {
assert.equal(compareDocumentPosition(a, span), 4);
});
it("reports when the first node is contained by the second", function() {
assert.equal(compareDocumentPosition(span, p), 20);
});
it("reports when the nodes belong to separate documents", function() {
var other = makeDom(markup)[0].children[0].children[0];
assert.equal(compareDocumentPosition(span, other), 1);
});
it("reports when the nodes are identical", function() {
assert.equal(compareDocumentPosition(span, span), 0);
});
});
describe("uniqueSort", function() {
var uniqueSort = helpers.uniqueSort;
var dom, p, span, a;
beforeEach(function() {
dom = makeDom("<div><p><span></span></p><a></a></div>")[0];
p = dom.children[0];
span = p.children[0];
a = dom.children[1];
});
it("leaves unique elements untouched", function() {
assert.deepEqual(uniqueSort([p, a]), [p, a]);
});
it("removes duplicate elements", function() {
assert.deepEqual(uniqueSort([p, a, p]), [p, a]);
});
it("sorts nodes in document order", function() {
assert.deepEqual(uniqueSort([a, dom, span, p]), [dom, p, span, a]);
});
});
});
var DomUtils = require("../..");
var fixture = require("../fixture");
var assert = require("assert");
// Set up expected structures
var expected = {
idAsdf: fixture[1],
tag2: [],
typeScript: []
};
for (var idx = 0; idx < 20; ++idx) {
expected.tag2.push(fixture[idx*2 + 1].children[5]);
expected.typeScript.push(fixture[idx*2 + 1].children[1]);
}
describe("legacy", function() {
describe("getElements", function() {
var getElements = DomUtils.getElements;
it("returns the node with the specified ID", function() {
assert.deepEqual(
getElements({ id: "asdf" }, fixture, true, 1),
[expected.idAsdf]
);
});
it("returns empty array for unknown IDs", function() {
assert.deepEqual(getElements({ id: "asdfs" }, fixture, true), []);
});
it("returns the nodes with the specified tag name", function() {
assert.deepEqual(
getElements({ tag_name:"tag2" }, fixture, true),
expected.tag2
);
});
it("returns empty array for unknown tag names", function() {
assert.deepEqual(
getElements({ tag_name : "asdfs" }, fixture, true),
[]
);
});
it("returns the nodes with the specified tag type", function() {
assert.deepEqual(
getElements({ tag_type: "script" }, fixture, true),
expected.typeScript
);
});
it("returns empty array for unknown tag types", function() {
assert.deepEqual(
getElements({ tag_type: "video" }, fixture, true),
[]
);
});
});
describe("getElementById", function() {
var getElementById = DomUtils.getElementById;
it("returns the specified node", function() {
assert.equal(
expected.idAsdf,
getElementById("asdf", fixture, true)
);
});
it("returns `null` for unknown IDs", function() {
assert.equal(null, getElementById("asdfs", fixture, true));
});
});
describe("getElementsByTagName", function() {
var getElementsByTagName = DomUtils.getElementsByTagName;
it("returns the specified nodes", function() {
assert.deepEqual(
getElementsByTagName("tag2", fixture, true),
expected.tag2
);
});
it("returns empty array for unknown tag names", function() {
assert.deepEqual(
getElementsByTagName("tag23", fixture, true),
[]
);
});
});
describe("getElementsByTagType", function() {
var getElementsByTagType = DomUtils.getElementsByTagType;
it("returns the specified nodes", function() {
assert.deepEqual(
getElementsByTagType("script", fixture, true),
expected.typeScript
);
});
it("returns empty array for unknown tag types", function() {
assert.deepEqual(
getElementsByTagType("video", fixture, true),
[]
);
});
});
describe("getOuterHTML", function() {
var getOuterHTML = DomUtils.getOuterHTML;
it("Correctly renders the outer HTML", function() {
assert.equal(
getOuterHTML(fixture[1]),
"<tag1 id=\"asdf\"> <script>text</script> <!-- comment --> <tag2> text </tag2></tag1>"
);
});
});
describe("getInnerHTML", function() {
var getInnerHTML = DomUtils.getInnerHTML;
it("Correctly renders the inner HTML", function() {
assert.equal(
getInnerHTML(fixture[1]),
" <script>text</script> <!-- comment --> <tag2> text </tag2>"
);
});
});
});
var makeDom = require("../utils").makeDom;
var traversal = require("../..");
var assert = require("assert");
describe("traversal", function() {
describe("hasAttrib", function() {
var hasAttrib = traversal.hasAttrib;
it("doesn't throw on text nodes", function() {
var dom = makeDom("textnode");
assert.doesNotThrow(function() {
hasAttrib(dom[0], "some-attrib");
});
});
});
});
var htmlparser = require("htmlparser2");
exports.makeDom = function(markup) {
var handler = new htmlparser.DomHandler(),
parser = new htmlparser.Parser(handler);
parser.write(markup);
parser.done();
return handler.dom;
};
lib-cov
*.seed
*.log
*.csv
*.dat
*.out
*.pid
*.gz
pids
logs
results
npm-debug.log
node_modules
var crypto = require("crypto");
var BigInteger = require("jsbn").BigInteger;
var ECPointFp = require("./lib/ec.js").ECPointFp;
exports.ECCurves = require("./lib/sec.js");
// zero prepad
function unstupid(hex,len)
{
return (hex.length >= len) ? hex : unstupid("0"+hex,len);
}
exports.ECKey = function(curve, key, isPublic)
{
var priv;
var c = curve();
var n = c.getN();
var bytes = Math.floor(n.bitLength()/8);
if(key)
{
if(isPublic)
{
var curve = c.getCurve();
// var x = key.slice(1,bytes+1); // skip the 04 for uncompressed format
// var y = key.slice(bytes+1);
// this.P = new ECPointFp(curve,
// curve.fromBigInteger(new BigInteger(x.toString("hex"), 16)),
// curve.fromBigInteger(new BigInteger(y.toString("hex"), 16)));
this.P = curve.decodePointHex(key.toString("hex"));
}else{
if(key.length != bytes) return false;
priv = new BigInteger(key.toString("hex"), 16);
}
}else{
var n1 = n.subtract(BigInteger.ONE);
var r = new BigInteger(crypto.randomBytes(n.bitLength()));
priv = r.mod(n1).add(BigInteger.ONE);
this.P = c.getG().multiply(priv);
}
if(this.P)
{
// var pubhex = unstupid(this.P.getX().toBigInteger().toString(16),bytes*2)+unstupid(this.P.getY().toBigInteger().toString(16),bytes*2);
// this.PublicKey = new Buffer("04"+pubhex,"hex");
this.PublicKey = new Buffer(c.getCurve().encodeCompressedPointHex(this.P),"hex");
}
if(priv)
{
this.PrivateKey = new Buffer(unstupid(priv.toString(16),bytes*2),"hex");
this.deriveSharedSecret = function(key)
{
if(!key || !key.P) return false;
var S = key.P.multiply(priv);
return new Buffer(unstupid(S.getX().toBigInteger().toString(16),bytes*2),"hex");
}
}
}
// Basic Javascript Elliptic Curve implementation
// Ported loosely from BouncyCastle's Java EC code
// Only Fp curves implemented for now
// Requires jsbn.js and jsbn2.js
var BigInteger = require('jsbn').BigInteger
var Barrett = BigInteger.prototype.Barrett
// ----------------
// ECFieldElementFp
// constructor
function ECFieldElementFp(q,x) {
this.x = x;
// TODO if(x.compareTo(q) >= 0) error
this.q = q;
}
function feFpEquals(other) {
if(other == this) return true;
return (this.q.equals(other.q) && this.x.equals(other.x));
}
function feFpToBigInteger() {
return this.x;
}
function feFpNegate() {
return new ECFieldElementFp(this.q, this.x.negate().mod(this.q));
}
function feFpAdd(b) {
return new ECFieldElementFp(this.q, this.x.add(b.toBigInteger()).mod(this.q));
}
function feFpSubtract(b) {
return new ECFieldElementFp(this.q, this.x.subtract(b.toBigInteger()).mod(this.q));
}
function feFpMultiply(b) {
return new ECFieldElementFp(this.q, this.x.multiply(b.toBigInteger()).mod(this.q));
}
function feFpSquare() {
return new ECFieldElementFp(this.q, this.x.square().mod(this.q));
}
function feFpDivide(b) {
return new ECFieldElementFp(this.q, this.x.multiply(b.toBigInteger().modInverse(this.q)).mod(this.q));
}
ECFieldElementFp.prototype.equals = feFpEquals;
ECFieldElementFp.prototype.toBigInteger = feFpToBigInteger;
ECFieldElementFp.prototype.negate = feFpNegate;
ECFieldElementFp.prototype.add = feFpAdd;
ECFieldElementFp.prototype.subtract = feFpSubtract;
ECFieldElementFp.prototype.multiply = feFpMultiply;
ECFieldElementFp.prototype.square = feFpSquare;
ECFieldElementFp.prototype.divide = feFpDivide;
// ----------------
// ECPointFp
// constructor
function ECPointFp(curve,x,y,z) {
this.curve = curve;
this.x = x;
this.y = y;
// Projective coordinates: either zinv == null or z * zinv == 1
// z and zinv are just BigIntegers, not fieldElements
if(z == null) {
this.z = BigInteger.ONE;
}
else {
this.z = z;
}
this.zinv = null;
//TODO: compression flag
}
function pointFpGetX() {
if(this.zinv == null) {
this.zinv = this.z.modInverse(this.curve.q);
}
var r = this.x.toBigInteger().multiply(this.zinv);
this.curve.reduce(r);
return this.curve.fromBigInteger(r);
}
function pointFpGetY() {
if(this.zinv == null) {
this.zinv = this.z.modInverse(this.curve.q);
}
var r = this.y.toBigInteger().multiply(this.zinv);
this.curve.reduce(r);
return this.curve.fromBigInteger(r);
}
function pointFpEquals(other) {
if(other == this) return true;
if(this.isInfinity()) return other.isInfinity();
if(other.isInfinity()) return this.isInfinity();
var u, v;
// u = Y2 * Z1 - Y1 * Z2
u = other.y.toBigInteger().multiply(this.z).subtract(this.y.toBigInteger().multiply(other.z)).mod(this.curve.q);
if(!u.equals(BigInteger.ZERO)) return false;
// v = X2 * Z1 - X1 * Z2
v = other.x.toBigInteger().multiply(this.z).subtract(this.x.toBigInteger().multiply(other.z)).mod(this.curve.q);
return v.equals(BigInteger.ZERO);
}
function pointFpIsInfinity() {
if((this.x == null) && (this.y == null)) return true;
return this.z.equals(BigInteger.ZERO) && !this.y.toBigInteger().equals(BigInteger.ZERO);
}
function pointFpNegate() {
return new ECPointFp(this.curve, this.x, this.y.negate(), this.z);
}
function pointFpAdd(b) {
if(this.isInfinity()) return b;
if(b.isInfinity()) return this;
// u = Y2 * Z1 - Y1 * Z2
var u = b.y.toBigInteger().multiply(this.z).subtract(this.y.toBigInteger().multiply(b.z)).mod(this.curve.q);
// v = X2 * Z1 - X1 * Z2
var v = b.x.toBigInteger().multiply(this.z).subtract(this.x.toBigInteger().multiply(b.z)).mod(this.curve.q);
if(BigInteger.ZERO.equals(v)) {
if(BigInteger.ZERO.equals(u)) {
return this.twice(); // this == b, so double
}
return this.curve.getInfinity(); // this = -b, so infinity
}
var THREE = new BigInteger("3");
var x1 = this.x.toBigInteger();
var y1 = this.y.toBigInteger();
var x2 = b.x.toBigInteger();
var y2 = b.y.toBigInteger();
var v2 = v.square();
var v3 = v2.multiply(v);
var x1v2 = x1.multiply(v2);
var zu2 = u.square().multiply(this.z);
// x3 = v * (z2 * (z1 * u^2 - 2 * x1 * v^2) - v^3)
var x3 = zu2.subtract(x1v2.shiftLeft(1)).multiply(b.z).subtract(v3).multiply(v).mod(this.curve.q);
// y3 = z2 * (3 * x1 * u * v^2 - y1 * v^3 - z1 * u^3) + u * v^3
var y3 = x1v2.multiply(THREE).multiply(u).subtract(y1.multiply(v3)).subtract(zu2.multiply(u)).multiply(b.z).add(u.multiply(v3)).mod(this.curve.q);
// z3 = v^3 * z1 * z2
var z3 = v3.multiply(this.z).multiply(b.z).mod(this.curve.q);
return new ECPointFp(this.curve, this.curve.fromBigInteger(x3), this.curve.fromBigInteger(y3), z3);
}
function pointFpTwice() {
if(this.isInfinity()) return this;
if(this.y.toBigInteger().signum() == 0) return this.curve.getInfinity();
// TODO: optimized handling of constants
var THREE = new BigInteger("3");
var x1 = this.x.toBigInteger();
var y1 = this.y.toBigInteger();
var y1z1 = y1.multiply(this.z);
var y1sqz1 = y1z1.multiply(y1).mod(this.curve.q);
var a = this.curve.a.toBigInteger();
// w = 3 * x1^2 + a * z1^2
var w = x1.square().multiply(THREE);
if(!BigInteger.ZERO.equals(a)) {
w = w.add(this.z.square().multiply(a));
}
w = w.mod(this.curve.q);
//this.curve.reduce(w);
// x3 = 2 * y1 * z1 * (w^2 - 8 * x1 * y1^2 * z1)
var x3 = w.square().subtract(x1.shiftLeft(3).multiply(y1sqz1)).shiftLeft(1).multiply(y1z1).mod(this.curve.q);
// y3 = 4 * y1^2 * z1 * (3 * w * x1 - 2 * y1^2 * z1) - w^3
var y3 = w.multiply(THREE).multiply(x1).subtract(y1sqz1.shiftLeft(1)).shiftLeft(2).multiply(y1sqz1).subtract(w.square().multiply(w)).mod(this.curve.q);
// z3 = 8 * (y1 * z1)^3
var z3 = y1z1.square().multiply(y1z1).shiftLeft(3).mod(this.curve.q);
return new ECPointFp(this.curve, this.curve.fromBigInteger(x3), this.curve.fromBigInteger(y3), z3);
}
// Simple NAF (Non-Adjacent Form) multiplication algorithm
// TODO: modularize the multiplication algorithm
function pointFpMultiply(k) {
if(this.isInfinity()) return this;
if(k.signum() == 0) return this.curve.getInfinity();
var e = k;
var h = e.multiply(new BigInteger("3"));
var neg = this.negate();
var R = this;
var i;
for(i = h.bitLength() - 2; i > 0; --i) {
R = R.twice();
var hBit = h.testBit(i);
var eBit = e.testBit(i);
if (hBit != eBit) {
R = R.add(hBit ? this : neg);
}
}
return R;
}
// Compute this*j + x*k (simultaneous multiplication)
function pointFpMultiplyTwo(j,x,k) {
var i;
if(j.bitLength() > k.bitLength())
i = j.bitLength() - 1;
else
i = k.bitLength() - 1;
var R = this.curve.getInfinity();
var both = this.add(x);
while(i >= 0) {
R = R.twice();
if(j.testBit(i)) {
if(k.testBit(i)) {
R = R.add(both);
}
else {
R = R.add(this);
}
}
else {
if(k.testBit(i)) {
R = R.add(x);
}
}
--i;
}
return R;
}
ECPointFp.prototype.getX = pointFpGetX;
ECPointFp.prototype.getY = pointFpGetY;
ECPointFp.prototype.equals = pointFpEquals;
ECPointFp.prototype.isInfinity = pointFpIsInfinity;
ECPointFp.prototype.negate = pointFpNegate;
ECPointFp.prototype.add = pointFpAdd;
ECPointFp.prototype.twice = pointFpTwice;
ECPointFp.prototype.multiply = pointFpMultiply;
ECPointFp.prototype.multiplyTwo = pointFpMultiplyTwo;
// ----------------
// ECCurveFp
// constructor
function ECCurveFp(q,a,b) {
this.q = q;
this.a = this.fromBigInteger(a);
this.b = this.fromBigInteger(b);
this.infinity = new ECPointFp(this, null, null);
this.reducer = new Barrett(this.q);
}
function curveFpGetQ() {
return this.q;
}
function curveFpGetA() {
return this.a;
}
function curveFpGetB() {
return this.b;
}
function curveFpEquals(other) {
if(other == this) return true;
return(this.q.equals(other.q) && this.a.equals(other.a) && this.b.equals(other.b));
}
function curveFpGetInfinity() {
return this.infinity;
}
function curveFpFromBigInteger(x) {
return new ECFieldElementFp(this.q, x);
}
function curveReduce(x) {
this.reducer.reduce(x);
}
// for now, work with hex strings because they're easier in JS
function curveFpDecodePointHex(s) {
switch(parseInt(s.substr(0,2), 16)) { // first byte
case 0:
return this.infinity;
case 2:
case 3:
// point compression not supported yet
return null;
case 4:
case 6:
case 7:
var len = (s.length - 2) / 2;
var xHex = s.substr(2, len);
var yHex = s.substr(len+2, len);
return new ECPointFp(this,
this.fromBigInteger(new BigInteger(xHex, 16)),
this.fromBigInteger(new BigInteger(yHex, 16)));
default: // unsupported
return null;
}
}
function curveFpEncodePointHex(p) {
if (p.isInfinity()) return "00";
var xHex = p.getX().toBigInteger().toString(16);
var yHex = p.getY().toBigInteger().toString(16);
var oLen = this.getQ().toString(16).length;
if ((oLen % 2) != 0) oLen++;
while (xHex.length < oLen) {
xHex = "0" + xHex;
}
while (yHex.length < oLen) {
yHex = "0" + yHex;
}
return "04" + xHex + yHex;
}
ECCurveFp.prototype.getQ = curveFpGetQ;
ECCurveFp.prototype.getA = curveFpGetA;
ECCurveFp.prototype.getB = curveFpGetB;
ECCurveFp.prototype.equals = curveFpEquals;
ECCurveFp.prototype.getInfinity = curveFpGetInfinity;
ECCurveFp.prototype.fromBigInteger = curveFpFromBigInteger;
ECCurveFp.prototype.reduce = curveReduce;
//ECCurveFp.prototype.decodePointHex = curveFpDecodePointHex;
ECCurveFp.prototype.encodePointHex = curveFpEncodePointHex;
// from: https://github.com/kaielvin/jsbn-ec-point-compression
ECCurveFp.prototype.decodePointHex = function(s)
{
var yIsEven;
switch(parseInt(s.substr(0,2), 16)) { // first byte
case 0:
return this.infinity;
case 2:
yIsEven = false;
case 3:
if(yIsEven == undefined) yIsEven = true;
var len = s.length - 2;
var xHex = s.substr(2, len);
var x = this.fromBigInteger(new BigInteger(xHex,16));
var alpha = x.multiply(x.square().add(this.getA())).add(this.getB());
var beta = alpha.sqrt();
if (beta == null) throw "Invalid point compression";
var betaValue = beta.toBigInteger();
if (betaValue.testBit(0) != yIsEven)
{
// Use the other root
beta = this.fromBigInteger(this.getQ().subtract(betaValue));
}
return new ECPointFp(this,x,beta);
case 4:
case 6:
case 7:
var len = (s.length - 2) / 2;
var xHex = s.substr(2, len);
var yHex = s.substr(len+2, len);
return new ECPointFp(this,
this.fromBigInteger(new BigInteger(xHex, 16)),
this.fromBigInteger(new BigInteger(yHex, 16)));
default: // unsupported
return null;
}
}
ECCurveFp.prototype.encodeCompressedPointHex = function(p)
{
if (p.isInfinity()) return "00";
var xHex = p.getX().toBigInteger().toString(16);
var oLen = this.getQ().toString(16).length;
if ((oLen % 2) != 0) oLen++;
while (xHex.length < oLen)
xHex = "0" + xHex;
var yPrefix;
if(p.getY().toBigInteger().isEven()) yPrefix = "02";
else yPrefix = "03";
return yPrefix + xHex;
}
ECFieldElementFp.prototype.getR = function()
{
if(this.r != undefined) return this.r;
this.r = null;
var bitLength = this.q.bitLength();
if (bitLength > 128)
{
var firstWord = this.q.shiftRight(bitLength - 64);
if (firstWord.intValue() == -1)
{
this.r = BigInteger.ONE.shiftLeft(bitLength).subtract(this.q);
}
}
return this.r;
}
ECFieldElementFp.prototype.modMult = function(x1,x2)
{
return this.modReduce(x1.multiply(x2));
}
ECFieldElementFp.prototype.modReduce = function(x)
{
if (this.getR() != null)
{
var qLen = q.bitLength();
while (x.bitLength() > (qLen + 1))
{
var u = x.shiftRight(qLen);
var v = x.subtract(u.shiftLeft(qLen));
if (!this.getR().equals(BigInteger.ONE))
{
u = u.multiply(this.getR());
}
x = u.add(v);
}
while (x.compareTo(q) >= 0)
{
x = x.subtract(q);
}
}
else
{
x = x.mod(q);
}
return x;
}
ECFieldElementFp.prototype.sqrt = function()
{
if (!this.q.testBit(0)) throw "unsupported";
// p mod 4 == 3
if (this.q.testBit(1))
{
var z = new ECFieldElementFp(this.q,this.x.modPow(this.q.shiftRight(2).add(BigInteger.ONE),this.q));
return z.square().equals(this) ? z : null;
}
// p mod 4 == 1
var qMinusOne = this.q.subtract(BigInteger.ONE);
var legendreExponent = qMinusOne.shiftRight(1);
if (!(this.x.modPow(legendreExponent, this.q).equals(BigInteger.ONE)))
{
return null;
}
var u = qMinusOne.shiftRight(2);
var k = u.shiftLeft(1).add(BigInteger.ONE);
var Q = this.x;
var fourQ = modDouble(modDouble(Q));
var U, V;
do
{
var P;
do
{
P = new BigInteger(this.q.bitLength(), new SecureRandom());
}
while (P.compareTo(this.q) >= 0
|| !(P.multiply(P).subtract(fourQ).modPow(legendreExponent, this.q).equals(qMinusOne)));
var result = this.lucasSequence(P, Q, k);
U = result[0];
V = result[1];
if (this.modMult(V, V).equals(fourQ))
{
// Integer division by 2, mod q
if (V.testBit(0))
{
V = V.add(q);
}
V = V.shiftRight(1);
return new ECFieldElementFp(q,V);
}
}
while (U.equals(BigInteger.ONE) || U.equals(qMinusOne));
return null;
}
ECFieldElementFp.prototype.lucasSequence = function(P,Q,k)
{
var n = k.bitLength();
var s = k.getLowestSetBit();
var Uh = BigInteger.ONE;
var Vl = BigInteger.TWO;
var Vh = P;
var Ql = BigInteger.ONE;
var Qh = BigInteger.ONE;
for (var j = n - 1; j >= s + 1; --j)
{
Ql = this.modMult(Ql, Qh);
if (k.testBit(j))
{
Qh = this.modMult(Ql, Q);
Uh = this.modMult(Uh, Vh);
Vl = this.modReduce(Vh.multiply(Vl).subtract(P.multiply(Ql)));
Vh = this.modReduce(Vh.multiply(Vh).subtract(Qh.shiftLeft(1)));
}
else
{
Qh = Ql;
Uh = this.modReduce(Uh.multiply(Vl).subtract(Ql));
Vh = this.modReduce(Vh.multiply(Vl).subtract(P.multiply(Ql)));
Vl = this.modReduce(Vl.multiply(Vl).subtract(Ql.shiftLeft(1)));
}
}
Ql = this.modMult(Ql, Qh);
Qh = this.modMult(Ql, Q);
Uh = this.modReduce(Uh.multiply(Vl).subtract(Ql));
Vl = this.modReduce(Vh.multiply(Vl).subtract(P.multiply(Ql)));
Ql = this.modMult(Ql, Qh);
for (var j = 1; j <= s; ++j)
{
Uh = this.modMult(Uh, Vl);
Vl = this.modReduce(Vl.multiply(Vl).subtract(Ql.shiftLeft(1)));
Ql = this.modMult(Ql, Ql);
}
return [ Uh, Vl ];
}
var exports = {
ECCurveFp: ECCurveFp,
ECPointFp: ECPointFp,
ECFieldElementFp: ECFieldElementFp
}
module.exports = exports
Licensing
---------
This software is covered under the following copyright:
/*
* Copyright (c) 2003-2005 Tom Wu
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
* EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
* WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
*
* IN NO EVENT SHALL TOM WU BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
* INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
* THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* In addition, the following condition applies:
*
* All redistributions must retain an intact copy of this copyright notice
* and disclaimer.
*/
Address all questions regarding this license to:
Tom Wu
tjw@cs.Stanford.EDU
// Named EC curves
// Requires ec.js, jsbn.js, and jsbn2.js
var BigInteger = require('jsbn').BigInteger
var ECCurveFp = require('./ec.js').ECCurveFp
// ----------------
// X9ECParameters
// constructor
function X9ECParameters(curve,g,n,h) {
this.curve = curve;
this.g = g;
this.n = n;
this.h = h;
}
function x9getCurve() {
return this.curve;
}
function x9getG() {
return this.g;
}
function x9getN() {
return this.n;
}
function x9getH() {
return this.h;
}
X9ECParameters.prototype.getCurve = x9getCurve;
X9ECParameters.prototype.getG = x9getG;
X9ECParameters.prototype.getN = x9getN;
X9ECParameters.prototype.getH = x9getH;
// ----------------
// SECNamedCurves
function fromHex(s) { return new BigInteger(s, 16); }
function secp128r1() {
// p = 2^128 - 2^97 - 1
var p = fromHex("FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF");
var a = fromHex("FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFC");
var b = fromHex("E87579C11079F43DD824993C2CEE5ED3");
//byte[] S = Hex.decode("000E0D4D696E6768756151750CC03A4473D03679");
var n = fromHex("FFFFFFFE0000000075A30D1B9038A115");
var h = BigInteger.ONE;
var curve = new ECCurveFp(p, a, b);
var G = curve.decodePointHex("04"
+ "161FF7528B899B2D0C28607CA52C5B86"
+ "CF5AC8395BAFEB13C02DA292DDED7A83");
return new X9ECParameters(curve, G, n, h);
}
function secp160k1() {
// p = 2^160 - 2^32 - 2^14 - 2^12 - 2^9 - 2^8 - 2^7 - 2^3 - 2^2 - 1
var p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73");
var a = BigInteger.ZERO;
var b = fromHex("7");
//byte[] S = null;
var n = fromHex("0100000000000000000001B8FA16DFAB9ACA16B6B3");
var h = BigInteger.ONE;
var curve = new ECCurveFp(p, a, b);
var G = curve.decodePointHex("04"
+ "3B4C382CE37AA192A4019E763036F4F5DD4D7EBB"
+ "938CF935318FDCED6BC28286531733C3F03C4FEE");
return new X9ECParameters(curve, G, n, h);
}
function secp160r1() {
// p = 2^160 - 2^31 - 1
var p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF");
var a = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFC");
var b = fromHex("1C97BEFC54BD7A8B65ACF89F81D4D4ADC565FA45");
//byte[] S = Hex.decode("1053CDE42C14D696E67687561517533BF3F83345");
var n = fromHex("0100000000000000000001F4C8F927AED3CA752257");
var h = BigInteger.ONE;
var curve = new ECCurveFp(p, a, b);
var G = curve.decodePointHex("04"
+ "4A96B5688EF573284664698968C38BB913CBFC82"
+ "23A628553168947D59DCC912042351377AC5FB32");
return new X9ECParameters(curve, G, n, h);
}
function secp192k1() {
// p = 2^192 - 2^32 - 2^12 - 2^8 - 2^7 - 2^6 - 2^3 - 1
var p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFEE37");
var a = BigInteger.ZERO;
var b = fromHex("3");
//byte[] S = null;
var n = fromHex("FFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8D");
var h = BigInteger.ONE;
var curve = new ECCurveFp(p, a, b);
var G = curve.decodePointHex("04"
+ "DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D"
+ "9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D");
return new X9ECParameters(curve, G, n, h);
}
function secp192r1() {
// p = 2^192 - 2^64 - 1
var p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF");
var a = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC");
var b = fromHex("64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1");
//byte[] S = Hex.decode("3045AE6FC8422F64ED579528D38120EAE12196D5");
var n = fromHex("FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831");
var h = BigInteger.ONE;
var curve = new ECCurveFp(p, a, b);
var G = curve.decodePointHex("04"
+ "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012"
+ "07192B95FFC8DA78631011ED6B24CDD573F977A11E794811");
return new X9ECParameters(curve, G, n, h);
}
function secp224r1() {
// p = 2^224 - 2^96 + 1
var p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001");
var a = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE");
var b = fromHex("B4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4");
//byte[] S = Hex.decode("BD71344799D5C7FCDC45B59FA3B9AB8F6A948BC5");
var n = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D");
var h = BigInteger.ONE;
var curve = new ECCurveFp(p, a, b);
var G = curve.decodePointHex("04"
+ "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21"
+ "BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34");
return new X9ECParameters(curve, G, n, h);
}
function secp256r1() {
// p = 2^224 (2^32 - 1) + 2^192 + 2^96 - 1
var p = fromHex("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF");
var a = fromHex("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC");
var b = fromHex("5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B");
//byte[] S = Hex.decode("C49D360886E704936A6678E1139D26B7819F7E90");
var n = fromHex("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551");
var h = BigInteger.ONE;
var curve = new ECCurveFp(p, a, b);
var G = curve.decodePointHex("04"
+ "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296"
+ "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5");
return new X9ECParameters(curve, G, n, h);
}
// TODO: make this into a proper hashtable
function getSECCurveByName(name) {
if(name == "secp128r1") return secp128r1();
if(name == "secp160k1") return secp160k1();
if(name == "secp160r1") return secp160r1();
if(name == "secp192k1") return secp192k1();
if(name == "secp192r1") return secp192r1();
if(name == "secp224r1") return secp224r1();
if(name == "secp256r1") return secp256r1();
return null;
}
module.exports = {
"secp128r1":secp128r1,
"secp160k1":secp160k1,
"secp160r1":secp160r1,
"secp192k1":secp192k1,
"secp192r1":secp192r1,
"secp224r1":secp224r1,
"secp256r1":secp256r1
}
The MIT License (MIT)
Copyright (c) 2014 Jeremie Miller
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
{
"_args": [
[
{
"raw": "ecc-jsbn@~0.1.1",
"scope": null,
"escapedName": "ecc-jsbn",
"name": "ecc-jsbn",
"rawSpec": "~0.1.1",
"spec": ">=0.1.1 <0.2.0",
"type": "range"
},
"F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\sshpk"
]
],
"_from": "ecc-jsbn@>=0.1.1 <0.2.0",
"_id": "ecc-jsbn@0.1.1",
"_inCache": true,
"_location": "/ecc-jsbn",
"_nodeVersion": "0.12.6",
"_npmUser": {
"name": "quartzjer",
"email": "jeremie@jabber.org"
},
"_npmVersion": "2.11.2",
"_phantomChildren": {},
"_requested": {
"raw": "ecc-jsbn@~0.1.1",
"scope": null,
"escapedName": "ecc-jsbn",
"name": "ecc-jsbn",
"rawSpec": "~0.1.1",
"spec": ">=0.1.1 <0.2.0",
"type": "range"
},
"_requiredBy": [
"/sshpk"
],
"_resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz",
"_shasum": "0fc73a9ed5f0d53c38193398523ef7e543777505",
"_shrinkwrap": null,
"_spec": "ecc-jsbn@~0.1.1",
"_where": "F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\sshpk",
"author": {
"name": "Jeremie Miller",
"email": "jeremie@jabber.org",
"url": "http://jeremie.com/"
},
"bugs": {
"url": "https://github.com/quartzjer/ecc-jsbn/issues"
},
"dependencies": {
"jsbn": "~0.1.0"
},
"description": "ECC JS code based on JSBN",
"devDependencies": {},
"directories": {},
"dist": {
"shasum": "0fc73a9ed5f0d53c38193398523ef7e543777505",
"tarball": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz"
},
"gitHead": "d35a360352496721030da645e8054f07efc22487",
"homepage": "https://github.com/quartzjer/ecc-jsbn",
"keywords": [
"jsbn",
"ecc",
"browserify"
],
"license": "MIT",
"main": "index.js",
"maintainers": [
{
"name": "quartzjer",
"email": "jeremie@jabber.org"
},
{
"name": "rynomad",
"email": "nomad.ry@gmail.com"
}
],
"name": "ecc-jsbn",
"optionalDependencies": {},
"readme": "ERROR: No README data found!",
"repository": {
"type": "git",
"url": "git+https://github.com/quartzjer/ecc-jsbn.git"
},
"scripts": {},
"version": "0.1.1"
}
var ecc = require("./index.js");
var key1 = new ecc.ECKey(ecc.ECCurves.secp160r1);
var key2 = new ecc.ECKey(ecc.ECCurves.secp160r1);
console.log(key1.deriveSharedSecret(key2));
var key3 = new ecc.ECKey(ecc.ECCurves.secp160r1,key1.PrivateKey);
var key4 = new ecc.ECKey(ecc.ECCurves.secp160r1,key2.PublicKey,true);
console.log(key3.deriveSharedSecret(key4));
var key1 = new ecc.ECKey(ecc.ECCurves.secp256r1);
var key2 = new ecc.ECKey(ecc.ECCurves.secp256r1);
console.log(key1.deriveSharedSecret(key2));
var key3 = new ecc.ECKey(ecc.ECCurves.secp256r1,key1.PrivateKey);
var key4 = new ecc.ECKey(ecc.ECCurves.secp256r1,key2.PublicKey,true);
console.log(key3.deriveSharedSecret(key4));
language: node_js
node_js:
- 0.8
- "0.10"
- 0.11
script: npm run coveralls
var encode = require("./lib/encode.js"),
decode = require("./lib/decode.js");
exports.decode = function(data, level){
return (!level || level <= 0 ? decode.XML : decode.HTML)(data);
};
exports.decodeStrict = function(data, level){
return (!level || level <= 0 ? decode.XML : decode.HTMLStrict)(data);
};
exports.encode = function(data, level){
return (!level || level <= 0 ? encode.XML : encode.HTML)(data);
};
exports.encodeXML = encode.XML;
exports.encodeHTML4 =
exports.encodeHTML5 =
exports.encodeHTML = encode.HTML;
exports.decodeXML =
exports.decodeXMLStrict = decode.XML;
exports.decodeHTML4 =
exports.decodeHTML5 =
exports.decodeHTML = decode.HTML;
exports.decodeHTML4Strict =
exports.decodeHTML5Strict =
exports.decodeHTMLStrict = decode.HTMLStrict;
exports.escape = encode.escape;
var entityMap = require("../maps/entities.json"),
legacyMap = require("../maps/legacy.json"),
xmlMap = require("../maps/xml.json"),
decodeCodePoint = require("./decode_codepoint.js");
var decodeXMLStrict = getStrictDecoder(xmlMap),
decodeHTMLStrict = getStrictDecoder(entityMap);
function getStrictDecoder(map){
var keys = Object.keys(map).join("|"),
replace = getReplacer(map);
keys += "|#[xX][\\da-fA-F]+|#\\d+";
var re = new RegExp("&(?:" + keys + ");", "g");
return function(str){
return String(str).replace(re, replace);
};
}
var decodeHTML = (function(){
var legacy = Object.keys(legacyMap)
.sort(sorter);
var keys = Object.keys(entityMap)
.sort(sorter);
for(var i = 0, j = 0; i < keys.length; i++){
if(legacy[j] === keys[i]){
keys[i] += ";?";
j++;
} else {
keys[i] += ";";
}
}
var re = new RegExp("&(?:" + keys.join("|") + "|#[xX][\\da-fA-F]+;?|#\\d+;?)", "g"),
replace = getReplacer(entityMap);
function replacer(str){
if(str.substr(-1) !== ";") str += ";";
return replace(str);
}
//TODO consider creating a merged map
return function(str){
return String(str).replace(re, replacer);
};
}());
function sorter(a, b){
return a < b ? 1 : -1;
}
function getReplacer(map){
return function replace(str){
if(str.charAt(1) === "#"){
if(str.charAt(2) === "X" || str.charAt(2) === "x"){
return decodeCodePoint(parseInt(str.substr(3), 16));
}
return decodeCodePoint(parseInt(str.substr(2), 10));
}
return map[str.slice(1, -1)];
};
}
module.exports = {
XML: decodeXMLStrict,
HTML: decodeHTML,
HTMLStrict: decodeHTMLStrict
};
var decodeMap = require("../maps/decode.json");
module.exports = decodeCodePoint;
// modified version of https://github.com/mathiasbynens/he/blob/master/src/he.js#L94-L119
function decodeCodePoint(codePoint){
if((codePoint >= 0xD800 && codePoint <= 0xDFFF) || codePoint > 0x10FFFF){
return "\uFFFD";
}
if(codePoint in decodeMap){
codePoint = decodeMap[codePoint];
}
var output = "";
if(codePoint > 0xFFFF){
codePoint -= 0x10000;
output += String.fromCharCode(codePoint >>> 10 & 0x3FF | 0xD800);
codePoint = 0xDC00 | codePoint & 0x3FF;
}
output += String.fromCharCode(codePoint);
return output;
}
var inverseXML = getInverseObj(require("../maps/xml.json")),
xmlReplacer = getInverseReplacer(inverseXML);
exports.XML = getInverse(inverseXML, xmlReplacer);
var inverseHTML = getInverseObj(require("../maps/entities.json")),
htmlReplacer = getInverseReplacer(inverseHTML);
exports.HTML = getInverse(inverseHTML, htmlReplacer);
function getInverseObj(obj){
return Object.keys(obj).sort().reduce(function(inverse, name){
inverse[obj[name]] = "&" + name + ";";
return inverse;
}, {});
}
function getInverseReplacer(inverse){
var single = [],
multiple = [];
Object.keys(inverse).forEach(function(k){
if(k.length === 1){
single.push("\\" + k);
} else {
multiple.push(k);
}
});
//TODO add ranges
multiple.unshift("[" + single.join("") + "]");
return new RegExp(multiple.join("|"), "g");
}
var re_nonASCII = /[^\0-\x7F]/g,
re_astralSymbols = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
function singleCharReplacer(c){
return "&#x" + c.charCodeAt(0).toString(16).toUpperCase() + ";";
}
function astralReplacer(c){
// http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
var high = c.charCodeAt(0);
var low = c.charCodeAt(1);
var codePoint = (high - 0xD800) * 0x400 + low - 0xDC00 + 0x10000;
return "&#x" + codePoint.toString(16).toUpperCase() + ";";
}
function getInverse(inverse, re){
function func(name){
return inverse[name];
}
return function(data){
return data
.replace(re, func)
.replace(re_astralSymbols, astralReplacer)
.replace(re_nonASCII, singleCharReplacer);
};
}
var re_xmlChars = getInverseReplacer(inverseXML);
function escapeXML(data){
return data
.replace(re_xmlChars, singleCharReplacer)
.replace(re_astralSymbols, astralReplacer)
.replace(re_nonASCII, singleCharReplacer);
}
exports.escape = escapeXML;
Copyright (c) Felix Böhm
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{"0":65533,"128":8364,"130":8218,"131":402,"132":8222,"133":8230,"134":8224,"135":8225,"136":710,"137":8240,"138":352,"139":8249,"140":338,"142":381,"145":8216,"146":8217,"147":8220,"148":8221,"149":8226,"150":8211,"151":8212,"152":732,"153":8482,"154":353,"155":8250,"156":339,"158":382,"159":376}
{"Aacute":"\u00C1","aacute":"\u00E1","Abreve":"\u0102","abreve":"\u0103","ac":"\u223E","acd":"\u223F","acE":"\u223E\u0333","Acirc":"\u00C2","acirc":"\u00E2","acute":"\u00B4","Acy":"\u0410","acy":"\u0430","AElig":"\u00C6","aelig":"\u00E6","af":"\u2061","Afr":"\uD835\uDD04","afr":"\uD835\uDD1E","Agrave":"\u00C0","agrave":"\u00E0","alefsym":"\u2135","aleph":"\u2135","Alpha":"\u0391","alpha":"\u03B1","Amacr":"\u0100","amacr":"\u0101","amalg":"\u2A3F","amp":"&","AMP":"&","andand":"\u2A55","And":"\u2A53","and":"\u2227","andd":"\u2A5C","andslope":"\u2A58","andv":"\u2A5A","ang":"\u2220","ange":"\u29A4","angle":"\u2220","angmsdaa":"\u29A8","angmsdab":"\u29A9","angmsdac":"\u29AA","angmsdad":"\u29AB","angmsdae":"\u29AC","angmsdaf":"\u29AD","angmsdag":"\u29AE","angmsdah":"\u29AF","angmsd":"\u2221","angrt":"\u221F","angrtvb":"\u22BE","angrtvbd":"\u299D","angsph":"\u2222","angst":"\u00C5","angzarr":"\u237C","Aogon":"\u0104","aogon":"\u0105","Aopf":"\uD835\uDD38","aopf":"\uD835\uDD52","apacir":"\u2A6F","ap":"\u2248","apE":"\u2A70","ape":"\u224A","apid":"\u224B","apos":"'","ApplyFunction":"\u2061","approx":"\u2248","approxeq":"\u224A","Aring":"\u00C5","aring":"\u00E5","Ascr":"\uD835\uDC9C","ascr":"\uD835\uDCB6","Assign":"\u2254","ast":"*","asymp":"\u2248","asympeq":"\u224D","Atilde":"\u00C3","atilde":"\u00E3","Auml":"\u00C4","auml":"\u00E4","awconint":"\u2233","awint":"\u2A11","backcong":"\u224C","backepsilon":"\u03F6","backprime":"\u2035","backsim":"\u223D","backsimeq":"\u22CD","Backslash":"\u2216","Barv":"\u2AE7","barvee":"\u22BD","barwed":"\u2305","Barwed":"\u2306","barwedge":"\u2305","bbrk":"\u23B5","bbrktbrk":"\u23B6","bcong":"\u224C","Bcy":"\u0411","bcy":"\u0431","bdquo":"\u201E","becaus":"\u2235","because":"\u2235","Because":"\u2235","bemptyv":"\u29B0","bepsi":"\u03F6","bernou":"\u212C","Bernoullis":"\u212C","Beta":"\u0392","beta":"\u03B2","beth":"\u2136","between":"\u226C","Bfr":"\uD835\uDD05","bfr":"\uD835\uDD1F","bigcap":"\u22C2","bigcirc":"\u25EF","bigcup":"\u22C3","bigodot":"\u2A00","bigoplus":"\u2A01","bigotimes":"\u2A02","bigsqcup":"\u2A06","bigstar":"\u2605","bigtriangledown":"\u25BD","bigtriangleup":"\u25B3","biguplus":"\u2A04","bigvee":"\u22C1","bigwedge":"\u22C0","bkarow":"\u290D","blacklozenge":"\u29EB","blacksquare":"\u25AA","blacktriangle":"\u25B4","blacktriangledown":"\u25BE","blacktriangleleft":"\u25C2","blacktriangleright":"\u25B8","blank":"\u2423","blk12":"\u2592","blk14":"\u2591","blk34":"\u2593","block":"\u2588","bne":"=\u20E5","bnequiv":"\u2261\u20E5","bNot":"\u2AED","bnot":"\u2310","Bopf":"\uD835\uDD39","bopf":"\uD835\uDD53","bot":"\u22A5","bottom":"\u22A5","bowtie":"\u22C8","boxbox":"\u29C9","boxdl":"\u2510","boxdL":"\u2555","boxDl":"\u2556","boxDL":"\u2557","boxdr":"\u250C","boxdR":"\u2552","boxDr":"\u2553","boxDR":"\u2554","boxh":"\u2500","boxH":"\u2550","boxhd":"\u252C","boxHd":"\u2564","boxhD":"\u2565","boxHD":"\u2566","boxhu":"\u2534","boxHu":"\u2567","boxhU":"\u2568","boxHU":"\u2569","boxminus":"\u229F","boxplus":"\u229E","boxtimes":"\u22A0","boxul":"\u2518","boxuL":"\u255B","boxUl":"\u255C","boxUL":"\u255D","boxur":"\u2514","boxuR":"\u2558","boxUr":"\u2559","boxUR":"\u255A","boxv":"\u2502","boxV":"\u2551","boxvh":"\u253C","boxvH":"\u256A","boxVh":"\u256B","boxVH":"\u256C","boxvl":"\u2524","boxvL":"\u2561","boxVl":"\u2562","boxVL":"\u2563","boxvr":"\u251C","boxvR":"\u255E","boxVr":"\u255F","boxVR":"\u2560","bprime":"\u2035","breve":"\u02D8","Breve":"\u02D8","brvbar":"\u00A6","bscr":"\uD835\uDCB7","Bscr":"\u212C","bsemi":"\u204F","bsim":"\u223D","bsime":"\u22CD","bsolb":"\u29C5","bsol":"\\","bsolhsub":"\u27C8","bull":"\u2022","bullet":"\u2022","bump":"\u224E","bumpE":"\u2AAE","bumpe":"\u224F","Bumpeq":"\u224E","bumpeq":"\u224F","Cacute":"\u0106","cacute":"\u0107","capand":"\u2A44","capbrcup":"\u2A49","capcap":"\u2A4B","cap":"\u2229","Cap":"\u22D2","capcup":"\u2A47","capdot":"\u2A40","CapitalDifferentialD":"\u2145","caps":"\u2229\uFE00","caret":"\u2041","caron":"\u02C7","Cayleys":"\u212D","ccaps":"\u2A4D","Ccaron":"\u010C","ccaron":"\u010D","Ccedil":"\u00C7","ccedil":"\u00E7","Ccirc":"\u0108","ccirc":"\u0109","Cconint":"\u2230","ccups":"\u2A4C","ccupssm":"\u2A50","Cdot":"\u010A","cdot":"\u010B","cedil":"\u00B8","Cedilla":"\u00B8","cemptyv":"\u29B2","cent":"\u00A2","centerdot":"\u00B7","CenterDot":"\u00B7","cfr":"\uD835\uDD20","Cfr":"\u212D","CHcy":"\u0427","chcy":"\u0447","check":"\u2713","checkmark":"\u2713","Chi":"\u03A7","chi":"\u03C7","circ":"\u02C6","circeq":"\u2257","circlearrowleft":"\u21BA","circlearrowright":"\u21BB","circledast":"\u229B","circledcirc":"\u229A","circleddash":"\u229D","CircleDot":"\u2299","circledR":"\u00AE","circledS":"\u24C8","CircleMinus":"\u2296","CirclePlus":"\u2295","CircleTimes":"\u2297","cir":"\u25CB","cirE":"\u29C3","cire":"\u2257","cirfnint":"\u2A10","cirmid":"\u2AEF","cirscir":"\u29C2","ClockwiseContourIntegral":"\u2232","CloseCurlyDoubleQuote":"\u201D","CloseCurlyQuote":"\u2019","clubs":"\u2663","clubsuit":"\u2663","colon":":","Colon":"\u2237","Colone":"\u2A74","colone":"\u2254","coloneq":"\u2254","comma":",","commat":"@","comp":"\u2201","compfn":"\u2218","complement":"\u2201","complexes":"\u2102","cong":"\u2245","congdot":"\u2A6D","Congruent":"\u2261","conint":"\u222E","Conint":"\u222F","ContourIntegral":"\u222E","copf":"\uD835\uDD54","Copf":"\u2102","coprod":"\u2210","Coproduct":"\u2210","copy":"\u00A9","COPY":"\u00A9","copysr":"\u2117","CounterClockwiseContourIntegral":"\u2233","crarr":"\u21B5","cross":"\u2717","Cross":"\u2A2F","Cscr":"\uD835\uDC9E","cscr":"\uD835\uDCB8","csub":"\u2ACF","csube":"\u2AD1","csup":"\u2AD0","csupe":"\u2AD2","ctdot":"\u22EF","cudarrl":"\u2938","cudarrr":"\u2935","cuepr":"\u22DE","cuesc":"\u22DF","cularr":"\u21B6","cularrp":"\u293D","cupbrcap":"\u2A48","cupcap":"\u2A46","CupCap":"\u224D","cup":"\u222A","Cup":"\u22D3","cupcup":"\u2A4A","cupdot":"\u228D","cupor":"\u2A45","cups":"\u222A\uFE00","curarr":"\u21B7","curarrm":"\u293C","curlyeqprec":"\u22DE","curlyeqsucc":"\u22DF","curlyvee":"\u22CE","curlywedge":"\u22CF","curren":"\u00A4","curvearrowleft":"\u21B6","curvearrowright":"\u21B7","cuvee":"\u22CE","cuwed":"\u22CF","cwconint":"\u2232","cwint":"\u2231","cylcty":"\u232D","dagger":"\u2020","Dagger":"\u2021","daleth":"\u2138","darr":"\u2193","Darr":"\u21A1","dArr":"\u21D3","dash":"\u2010","Dashv":"\u2AE4","dashv":"\u22A3","dbkarow":"\u290F","dblac":"\u02DD","Dcaron":"\u010E","dcaron":"\u010F","Dcy":"\u0414","dcy":"\u0434","ddagger":"\u2021","ddarr":"\u21CA","DD":"\u2145","dd":"\u2146","DDotrahd":"\u2911","ddotseq":"\u2A77","deg":"\u00B0","Del":"\u2207","Delta":"\u0394","delta":"\u03B4","demptyv":"\u29B1","dfisht":"\u297F","Dfr":"\uD835\uDD07","dfr":"\uD835\uDD21","dHar":"\u2965","dharl":"\u21C3","dharr":"\u21C2","DiacriticalAcute":"\u00B4","DiacriticalDot":"\u02D9","DiacriticalDoubleAcute":"\u02DD","DiacriticalGrave":"`","DiacriticalTilde":"\u02DC","diam":"\u22C4","diamond":"\u22C4","Diamond":"\u22C4","diamondsuit":"\u2666","diams":"\u2666","die":"\u00A8","DifferentialD":"\u2146","digamma":"\u03DD","disin":"\u22F2","div":"\u00F7","divide":"\u00F7","divideontimes":"\u22C7","divonx":"\u22C7","DJcy":"\u0402","djcy":"\u0452","dlcorn":"\u231E","dlcrop":"\u230D","dollar":"$","Dopf":"\uD835\uDD3B","dopf":"\uD835\uDD55","Dot":"\u00A8","dot":"\u02D9","DotDot":"\u20DC","doteq":"\u2250","doteqdot":"\u2251","DotEqual":"\u2250","dotminus":"\u2238","dotplus":"\u2214","dotsquare":"\u22A1","doublebarwedge":"\u2306","DoubleContourIntegral":"\u222F","DoubleDot":"\u00A8","DoubleDownArrow":"\u21D3","DoubleLeftArrow":"\u21D0","DoubleLeftRightArrow":"\u21D4","DoubleLeftTee":"\u2AE4","DoubleLongLeftArrow":"\u27F8","DoubleLongLeftRightArrow":"\u27FA","DoubleLongRightArrow":"\u27F9","DoubleRightArrow":"\u21D2","DoubleRightTee":"\u22A8","DoubleUpArrow":"\u21D1","DoubleUpDownArrow":"\u21D5","DoubleVerticalBar":"\u2225","DownArrowBar":"\u2913","downarrow":"\u2193","DownArrow":"\u2193","Downarrow":"\u21D3","DownArrowUpArrow":"\u21F5","DownBreve":"\u0311","downdownarrows":"\u21CA","downharpoonleft":"\u21C3","downharpoonright":"\u21C2","DownLeftRightVector":"\u2950","DownLeftTeeVector":"\u295E","DownLeftVectorBar":"\u2956","DownLeftVector":"\u21BD","DownRightTeeVector":"\u295F","DownRightVectorBar":"\u2957","DownRightVector":"\u21C1","DownTeeArrow":"\u21A7","DownTee":"\u22A4","drbkarow":"\u2910","drcorn":"\u231F","drcrop":"\u230C","Dscr":"\uD835\uDC9F","dscr":"\uD835\uDCB9","DScy":"\u0405","dscy":"\u0455","dsol":"\u29F6","Dstrok":"\u0110","dstrok":"\u0111","dtdot":"\u22F1","dtri":"\u25BF","dtrif":"\u25BE","duarr":"\u21F5","duhar":"\u296F","dwangle":"\u29A6","DZcy":"\u040F","dzcy":"\u045F","dzigrarr":"\u27FF","Eacute":"\u00C9","eacute":"\u00E9","easter":"\u2A6E","Ecaron":"\u011A","ecaron":"\u011B","Ecirc":"\u00CA","ecirc":"\u00EA","ecir":"\u2256","ecolon":"\u2255","Ecy":"\u042D","ecy":"\u044D","eDDot":"\u2A77","Edot":"\u0116","edot":"\u0117","eDot":"\u2251","ee":"\u2147","efDot":"\u2252","Efr":"\uD835\uDD08","efr":"\uD835\uDD22","eg":"\u2A9A","Egrave":"\u00C8","egrave":"\u00E8","egs":"\u2A96","egsdot":"\u2A98","el":"\u2A99","Element":"\u2208","elinters":"\u23E7","ell":"\u2113","els":"\u2A95","elsdot":"\u2A97","Emacr":"\u0112","emacr":"\u0113","empty":"\u2205","emptyset":"\u2205","EmptySmallSquare":"\u25FB","emptyv":"\u2205","EmptyVerySmallSquare":"\u25AB","emsp13":"\u2004","emsp14":"\u2005","emsp":"\u2003","ENG":"\u014A","eng":"\u014B","ensp":"\u2002","Eogon":"\u0118","eogon":"\u0119","Eopf":"\uD835\uDD3C","eopf":"\uD835\uDD56","epar":"\u22D5","eparsl":"\u29E3","eplus":"\u2A71","epsi":"\u03B5","Epsilon":"\u0395","epsilon":"\u03B5","epsiv":"\u03F5","eqcirc":"\u2256","eqcolon":"\u2255","eqsim":"\u2242","eqslantgtr":"\u2A96","eqslantless":"\u2A95","Equal":"\u2A75","equals":"=","EqualTilde":"\u2242","equest":"\u225F","Equilibrium":"\u21CC","equiv":"\u2261","equivDD":"\u2A78","eqvparsl":"\u29E5","erarr":"\u2971","erDot":"\u2253","escr":"\u212F","Escr":"\u2130","esdot":"\u2250","Esim":"\u2A73","esim":"\u2242","Eta":"\u0397","eta":"\u03B7","ETH":"\u00D0","eth":"\u00F0","Euml":"\u00CB","euml":"\u00EB","euro":"\u20AC","excl":"!","exist":"\u2203","Exists":"\u2203","expectation":"\u2130","exponentiale":"\u2147","ExponentialE":"\u2147","fallingdotseq":"\u2252","Fcy":"\u0424","fcy":"\u0444","female":"\u2640","ffilig":"\uFB03","fflig":"\uFB00","ffllig":"\uFB04","Ffr":"\uD835\uDD09","ffr":"\uD835\uDD23","filig":"\uFB01","FilledSmallSquare":"\u25FC","FilledVerySmallSquare":"\u25AA","fjlig":"fj","flat":"\u266D","fllig":"\uFB02","fltns":"\u25B1","fnof":"\u0192","Fopf":"\uD835\uDD3D","fopf":"\uD835\uDD57","forall":"\u2200","ForAll":"\u2200","fork":"\u22D4","forkv":"\u2AD9","Fouriertrf":"\u2131","fpartint":"\u2A0D","frac12":"\u00BD","frac13":"\u2153","frac14":"\u00BC","frac15":"\u2155","frac16":"\u2159","frac18":"\u215B","frac23":"\u2154","frac25":"\u2156","frac34":"\u00BE","frac35":"\u2157","frac38":"\u215C","frac45":"\u2158","frac56":"\u215A","frac58":"\u215D","frac78":"\u215E","frasl":"\u2044","frown":"\u2322","fscr":"\uD835\uDCBB","Fscr":"\u2131","gacute":"\u01F5","Gamma":"\u0393","gamma":"\u03B3","Gammad":"\u03DC","gammad":"\u03DD","gap":"\u2A86","Gbreve":"\u011E","gbreve":"\u011F","Gcedil":"\u0122","Gcirc":"\u011C","gcirc":"\u011D","Gcy":"\u0413","gcy":"\u0433","Gdot":"\u0120","gdot":"\u0121","ge":"\u2265","gE":"\u2267","gEl":"\u2A8C","gel":"\u22DB","geq":"\u2265","geqq":"\u2267","geqslant":"\u2A7E","gescc":"\u2AA9","ges":"\u2A7E","gesdot":"\u2A80","gesdoto":"\u2A82","gesdotol":"\u2A84","gesl":"\u22DB\uFE00","gesles":"\u2A94","Gfr":"\uD835\uDD0A","gfr":"\uD835\uDD24","gg":"\u226B","Gg":"\u22D9","ggg":"\u22D9","gimel":"\u2137","GJcy":"\u0403","gjcy":"\u0453","gla":"\u2AA5","gl":"\u2277","glE":"\u2A92","glj":"\u2AA4","gnap":"\u2A8A","gnapprox":"\u2A8A","gne":"\u2A88","gnE":"\u2269","gneq":"\u2A88","gneqq":"\u2269","gnsim":"\u22E7","Gopf":"\uD835\uDD3E","gopf":"\uD835\uDD58","grave":"`","GreaterEqual":"\u2265","GreaterEqualLess":"\u22DB","GreaterFullEqual":"\u2267","GreaterGreater":"\u2AA2","GreaterLess":"\u2277","GreaterSlantEqual":"\u2A7E","GreaterTilde":"\u2273","Gscr":"\uD835\uDCA2","gscr":"\u210A","gsim":"\u2273","gsime":"\u2A8E","gsiml":"\u2A90","gtcc":"\u2AA7","gtcir":"\u2A7A","gt":">","GT":">","Gt":"\u226B","gtdot":"\u22D7","gtlPar":"\u2995","gtquest":"\u2A7C","gtrapprox":"\u2A86","gtrarr":"\u2978","gtrdot":"\u22D7","gtreqless":"\u22DB","gtreqqless":"\u2A8C","gtrless":"\u2277","gtrsim":"\u2273","gvertneqq":"\u2269\uFE00","gvnE":"\u2269\uFE00","Hacek":"\u02C7","hairsp":"\u200A","half":"\u00BD","hamilt":"\u210B","HARDcy":"\u042A","hardcy":"\u044A","harrcir":"\u2948","harr":"\u2194","hArr":"\u21D4","harrw":"\u21AD","Hat":"^","hbar":"\u210F","Hcirc":"\u0124","hcirc":"\u0125","hearts":"\u2665","heartsuit":"\u2665","hellip":"\u2026","hercon":"\u22B9","hfr":"\uD835\uDD25","Hfr":"\u210C","HilbertSpace":"\u210B","hksearow":"\u2925","hkswarow":"\u2926","hoarr":"\u21FF","homtht":"\u223B","hookleftarrow":"\u21A9","hookrightarrow":"\u21AA","hopf":"\uD835\uDD59","Hopf":"\u210D","horbar":"\u2015","HorizontalLine":"\u2500","hscr":"\uD835\uDCBD","Hscr":"\u210B","hslash":"\u210F","Hstrok":"\u0126","hstrok":"\u0127","HumpDownHump":"\u224E","HumpEqual":"\u224F","hybull":"\u2043","hyphen":"\u2010","Iacute":"\u00CD","iacute":"\u00ED","ic":"\u2063","Icirc":"\u00CE","icirc":"\u00EE","Icy":"\u0418","icy":"\u0438","Idot":"\u0130","IEcy":"\u0415","iecy":"\u0435","iexcl":"\u00A1","iff":"\u21D4","ifr":"\uD835\uDD26","Ifr":"\u2111","Igrave":"\u00CC","igrave":"\u00EC","ii":"\u2148","iiiint":"\u2A0C","iiint":"\u222D","iinfin":"\u29DC","iiota":"\u2129","IJlig":"\u0132","ijlig":"\u0133","Imacr":"\u012A","imacr":"\u012B","image":"\u2111","ImaginaryI":"\u2148","imagline":"\u2110","imagpart":"\u2111","imath":"\u0131","Im":"\u2111","imof":"\u22B7","imped":"\u01B5","Implies":"\u21D2","incare":"\u2105","in":"\u2208","infin":"\u221E","infintie":"\u29DD","inodot":"\u0131","intcal":"\u22BA","int":"\u222B","Int":"\u222C","integers":"\u2124","Integral":"\u222B","intercal":"\u22BA","Intersection":"\u22C2","intlarhk":"\u2A17","intprod":"\u2A3C","InvisibleComma":"\u2063","InvisibleTimes":"\u2062","IOcy":"\u0401","iocy":"\u0451","Iogon":"\u012E","iogon":"\u012F","Iopf":"\uD835\uDD40","iopf":"\uD835\uDD5A","Iota":"\u0399","iota":"\u03B9","iprod":"\u2A3C","iquest":"\u00BF","iscr":"\uD835\uDCBE","Iscr":"\u2110","isin":"\u2208","isindot":"\u22F5","isinE":"\u22F9","isins":"\u22F4","isinsv":"\u22F3","isinv":"\u2208","it":"\u2062","Itilde":"\u0128","itilde":"\u0129","Iukcy":"\u0406","iukcy":"\u0456","Iuml":"\u00CF","iuml":"\u00EF","Jcirc":"\u0134","jcirc":"\u0135","Jcy":"\u0419","jcy":"\u0439","Jfr":"\uD835\uDD0D","jfr":"\uD835\uDD27","jmath":"\u0237","Jopf":"\uD835\uDD41","jopf":"\uD835\uDD5B","Jscr":"\uD835\uDCA5","jscr":"\uD835\uDCBF","Jsercy":"\u0408","jsercy":"\u0458","Jukcy":"\u0404","jukcy":"\u0454","Kappa":"\u039A","kappa":"\u03BA","kappav":"\u03F0","Kcedil":"\u0136","kcedil":"\u0137","Kcy":"\u041A","kcy":"\u043A","Kfr":"\uD835\uDD0E","kfr":"\uD835\uDD28","kgreen":"\u0138","KHcy":"\u0425","khcy":"\u0445","KJcy":"\u040C","kjcy":"\u045C","Kopf":"\uD835\uDD42","kopf":"\uD835\uDD5C","Kscr":"\uD835\uDCA6","kscr":"\uD835\uDCC0","lAarr":"\u21DA","Lacute":"\u0139","lacute":"\u013A","laemptyv":"\u29B4","lagran":"\u2112","Lambda":"\u039B","lambda":"\u03BB","lang":"\u27E8","Lang":"\u27EA","langd":"\u2991","langle":"\u27E8","lap":"\u2A85","Laplacetrf":"\u2112","laquo":"\u00AB","larrb":"\u21E4","larrbfs":"\u291F","larr":"\u2190","Larr":"\u219E","lArr":"\u21D0","larrfs":"\u291D","larrhk":"\u21A9","larrlp":"\u21AB","larrpl":"\u2939","larrsim":"\u2973","larrtl":"\u21A2","latail":"\u2919","lAtail":"\u291B","lat":"\u2AAB","late":"\u2AAD","lates":"\u2AAD\uFE00","lbarr":"\u290C","lBarr":"\u290E","lbbrk":"\u2772","lbrace":"{","lbrack":"[","lbrke":"\u298B","lbrksld":"\u298F","lbrkslu":"\u298D","Lcaron":"\u013D","lcaron":"\u013E","Lcedil":"\u013B","lcedil":"\u013C","lceil":"\u2308","lcub":"{","Lcy":"\u041B","lcy":"\u043B","ldca":"\u2936","ldquo":"\u201C","ldquor":"\u201E","ldrdhar":"\u2967","ldrushar":"\u294B","ldsh":"\u21B2","le":"\u2264","lE":"\u2266","LeftAngleBracket":"\u27E8","LeftArrowBar":"\u21E4","leftarrow":"\u2190","LeftArrow":"\u2190","Leftarrow":"\u21D0","LeftArrowRightArrow":"\u21C6","leftarrowtail":"\u21A2","LeftCeiling":"\u2308","LeftDoubleBracket":"\u27E6","LeftDownTeeVector":"\u2961","LeftDownVectorBar":"\u2959","LeftDownVector":"\u21C3","LeftFloor":"\u230A","leftharpoondown":"\u21BD","leftharpoonup":"\u21BC","leftleftarrows":"\u21C7","leftrightarrow":"\u2194","LeftRightArrow":"\u2194","Leftrightarrow":"\u21D4","leftrightarrows":"\u21C6","leftrightharpoons":"\u21CB","leftrightsquigarrow":"\u21AD","LeftRightVector":"\u294E","LeftTeeArrow":"\u21A4","LeftTee":"\u22A3","LeftTeeVector":"\u295A","leftthreetimes":"\u22CB","LeftTriangleBar":"\u29CF","LeftTriangle":"\u22B2","LeftTriangleEqual":"\u22B4","LeftUpDownVector":"\u2951","LeftUpTeeVector":"\u2960","LeftUpVectorBar":"\u2958","LeftUpVector":"\u21BF","LeftVectorBar":"\u2952","LeftVector":"\u21BC","lEg":"\u2A8B","leg":"\u22DA","leq":"\u2264","leqq":"\u2266","leqslant":"\u2A7D","lescc":"\u2AA8","les":"\u2A7D","lesdot":"\u2A7F","lesdoto":"\u2A81","lesdotor":"\u2A83","lesg":"\u22DA\uFE00","lesges":"\u2A93","lessapprox":"\u2A85","lessdot":"\u22D6","lesseqgtr":"\u22DA","lesseqqgtr":"\u2A8B","LessEqualGreater":"\u22DA","LessFullEqual":"\u2266","LessGreater":"\u2276","lessgtr":"\u2276","LessLess":"\u2AA1","lesssim":"\u2272","LessSlantEqual":"\u2A7D","LessTilde":"\u2272","lfisht":"\u297C","lfloor":"\u230A","Lfr":"\uD835\uDD0F","lfr":"\uD835\uDD29","lg":"\u2276","lgE":"\u2A91","lHar":"\u2962","lhard":"\u21BD","lharu":"\u21BC","lharul":"\u296A","lhblk":"\u2584","LJcy":"\u0409","ljcy":"\u0459","llarr":"\u21C7","ll":"\u226A","Ll":"\u22D8","llcorner":"\u231E","Lleftarrow":"\u21DA","llhard":"\u296B","lltri":"\u25FA","Lmidot":"\u013F","lmidot":"\u0140","lmoustache":"\u23B0","lmoust":"\u23B0","lnap":"\u2A89","lnapprox":"\u2A89","lne":"\u2A87","lnE":"\u2268","lneq":"\u2A87","lneqq":"\u2268","lnsim":"\u22E6","loang":"\u27EC","loarr":"\u21FD","lobrk":"\u27E6","longleftarrow":"\u27F5","LongLeftArrow":"\u27F5","Longleftarrow":"\u27F8","longleftrightarrow":"\u27F7","LongLeftRightArrow":"\u27F7","Longleftrightarrow":"\u27FA","longmapsto":"\u27FC","longrightarrow":"\u27F6","LongRightArrow":"\u27F6","Longrightarrow":"\u27F9","looparrowleft":"\u21AB","looparrowright":"\u21AC","lopar":"\u2985","Lopf":"\uD835\uDD43","lopf":"\uD835\uDD5D","loplus":"\u2A2D","lotimes":"\u2A34","lowast":"\u2217","lowbar":"_","LowerLeftArrow":"\u2199","LowerRightArrow":"\u2198","loz":"\u25CA","lozenge":"\u25CA","lozf":"\u29EB","lpar":"(","lparlt":"\u2993","lrarr":"\u21C6","lrcorner":"\u231F","lrhar":"\u21CB","lrhard":"\u296D","lrm":"\u200E","lrtri":"\u22BF","lsaquo":"\u2039","lscr":"\uD835\uDCC1","Lscr":"\u2112","lsh":"\u21B0","Lsh":"\u21B0","lsim":"\u2272","lsime":"\u2A8D","lsimg":"\u2A8F","lsqb":"[","lsquo":"\u2018","lsquor":"\u201A","Lstrok":"\u0141","lstrok":"\u0142","ltcc":"\u2AA6","ltcir":"\u2A79","lt":"<","LT":"<","Lt":"\u226A","ltdot":"\u22D6","lthree":"\u22CB","ltimes":"\u22C9","ltlarr":"\u2976","ltquest":"\u2A7B","ltri":"\u25C3","ltrie":"\u22B4","ltrif":"\u25C2","ltrPar":"\u2996","lurdshar":"\u294A","luruhar":"\u2966","lvertneqq":"\u2268\uFE00","lvnE":"\u2268\uFE00","macr":"\u00AF","male":"\u2642","malt":"\u2720","maltese":"\u2720","Map":"\u2905","map":"\u21A6","mapsto":"\u21A6","mapstodown":"\u21A7","mapstoleft":"\u21A4","mapstoup":"\u21A5","marker":"\u25AE","mcomma":"\u2A29","Mcy":"\u041C","mcy":"\u043C","mdash":"\u2014","mDDot":"\u223A","measuredangle":"\u2221","MediumSpace":"\u205F","Mellintrf":"\u2133","Mfr":"\uD835\uDD10","mfr":"\uD835\uDD2A","mho":"\u2127","micro":"\u00B5","midast":"*","midcir":"\u2AF0","mid":"\u2223","middot":"\u00B7","minusb":"\u229F","minus":"\u2212","minusd":"\u2238","minusdu":"\u2A2A","MinusPlus":"\u2213","mlcp":"\u2ADB","mldr":"\u2026","mnplus":"\u2213","models":"\u22A7","Mopf":"\uD835\uDD44","mopf":"\uD835\uDD5E","mp":"\u2213","mscr":"\uD835\uDCC2","Mscr":"\u2133","mstpos":"\u223E","Mu":"\u039C","mu":"\u03BC","multimap":"\u22B8","mumap":"\u22B8","nabla":"\u2207","Nacute":"\u0143","nacute":"\u0144","nang":"\u2220\u20D2","nap":"\u2249","napE":"\u2A70\u0338","napid":"\u224B\u0338","napos":"\u0149","napprox":"\u2249","natural":"\u266E","naturals":"\u2115","natur":"\u266E","nbsp":"\u00A0","nbump":"\u224E\u0338","nbumpe":"\u224F\u0338","ncap":"\u2A43","Ncaron":"\u0147","ncaron":"\u0148","Ncedil":"\u0145","ncedil":"\u0146","ncong":"\u2247","ncongdot":"\u2A6D\u0338","ncup":"\u2A42","Ncy":"\u041D","ncy":"\u043D","ndash":"\u2013","nearhk":"\u2924","nearr":"\u2197","neArr":"\u21D7","nearrow":"\u2197","ne":"\u2260","nedot":"\u2250\u0338","NegativeMediumSpace":"\u200B","NegativeThickSpace":"\u200B","NegativeThinSpace":"\u200B","NegativeVeryThinSpace":"\u200B","nequiv":"\u2262","nesear":"\u2928","nesim":"\u2242\u0338","NestedGreaterGreater":"\u226B","NestedLessLess":"\u226A","NewLine":"\n","nexist":"\u2204","nexists":"\u2204","Nfr":"\uD835\uDD11","nfr":"\uD835\uDD2B","ngE":"\u2267\u0338","nge":"\u2271","ngeq":"\u2271","ngeqq":"\u2267\u0338","ngeqslant":"\u2A7E\u0338","nges":"\u2A7E\u0338","nGg":"\u22D9\u0338","ngsim":"\u2275","nGt":"\u226B\u20D2","ngt":"\u226F","ngtr":"\u226F","nGtv":"\u226B\u0338","nharr":"\u21AE","nhArr":"\u21CE","nhpar":"\u2AF2","ni":"\u220B","nis":"\u22FC","nisd":"\u22FA","niv":"\u220B","NJcy":"\u040A","njcy":"\u045A","nlarr":"\u219A","nlArr":"\u21CD","nldr":"\u2025","nlE":"\u2266\u0338","nle":"\u2270","nleftarrow":"\u219A","nLeftarrow":"\u21CD","nleftrightarrow":"\u21AE","nLeftrightarrow":"\u21CE","nleq":"\u2270","nleqq":"\u2266\u0338","nleqslant":"\u2A7D\u0338","nles":"\u2A7D\u0338","nless":"\u226E","nLl":"\u22D8\u0338","nlsim":"\u2274","nLt":"\u226A\u20D2","nlt":"\u226E","nltri":"\u22EA","nltrie":"\u22EC","nLtv":"\u226A\u0338","nmid":"\u2224","NoBreak":"\u2060","NonBreakingSpace":"\u00A0","nopf":"\uD835\uDD5F","Nopf":"\u2115","Not":"\u2AEC","not":"\u00AC","NotCongruent":"\u2262","NotCupCap":"\u226D","NotDoubleVerticalBar":"\u2226","NotElement":"\u2209","NotEqual":"\u2260","NotEqualTilde":"\u2242\u0338","NotExists":"\u2204","NotGreater":"\u226F","NotGreaterEqual":"\u2271","NotGreaterFullEqual":"\u2267\u0338","NotGreaterGreater":"\u226B\u0338","NotGreaterLess":"\u2279","NotGreaterSlantEqual":"\u2A7E\u0338","NotGreaterTilde":"\u2275","NotHumpDownHump":"\u224E\u0338","NotHumpEqual":"\u224F\u0338","notin":"\u2209","notindot":"\u22F5\u0338","notinE":"\u22F9\u0338","notinva":"\u2209","notinvb":"\u22F7","notinvc":"\u22F6","NotLeftTriangleBar":"\u29CF\u0338","NotLeftTriangle":"\u22EA","NotLeftTriangleEqual":"\u22EC","NotLess":"\u226E","NotLessEqual":"\u2270","NotLessGreater":"\u2278","NotLessLess":"\u226A\u0338","NotLessSlantEqual":"\u2A7D\u0338","NotLessTilde":"\u2274","NotNestedGreaterGreater":"\u2AA2\u0338","NotNestedLessLess":"\u2AA1\u0338","notni":"\u220C","notniva":"\u220C","notnivb":"\u22FE","notnivc":"\u22FD","NotPrecedes":"\u2280","NotPrecedesEqual":"\u2AAF\u0338","NotPrecedesSlantEqual":"\u22E0","NotReverseElement":"\u220C","NotRightTriangleBar":"\u29D0\u0338","NotRightTriangle":"\u22EB","NotRightTriangleEqual":"\u22ED","NotSquareSubset":"\u228F\u0338","NotSquareSubsetEqual":"\u22E2","NotSquareSuperset":"\u2290\u0338","NotSquareSupersetEqual":"\u22E3","NotSubset":"\u2282\u20D2","NotSubsetEqual":"\u2288","NotSucceeds":"\u2281","NotSucceedsEqual":"\u2AB0\u0338","NotSucceedsSlantEqual":"\u22E1","NotSucceedsTilde":"\u227F\u0338","NotSuperset":"\u2283\u20D2","NotSupersetEqual":"\u2289","NotTilde":"\u2241","NotTildeEqual":"\u2244","NotTildeFullEqual":"\u2247","NotTildeTilde":"\u2249","NotVerticalBar":"\u2224","nparallel":"\u2226","npar":"\u2226","nparsl":"\u2AFD\u20E5","npart":"\u2202\u0338","npolint":"\u2A14","npr":"\u2280","nprcue":"\u22E0","nprec":"\u2280","npreceq":"\u2AAF\u0338","npre":"\u2AAF\u0338","nrarrc":"\u2933\u0338","nrarr":"\u219B","nrArr":"\u21CF","nrarrw":"\u219D\u0338","nrightarrow":"\u219B","nRightarrow":"\u21CF","nrtri":"\u22EB","nrtrie":"\u22ED","nsc":"\u2281","nsccue":"\u22E1","nsce":"\u2AB0\u0338","Nscr":"\uD835\uDCA9","nscr":"\uD835\uDCC3","nshortmid":"\u2224","nshortparallel":"\u2226","nsim":"\u2241","nsime":"\u2244","nsimeq":"\u2244","nsmid":"\u2224","nspar":"\u2226","nsqsube":"\u22E2","nsqsupe":"\u22E3","nsub":"\u2284","nsubE":"\u2AC5\u0338","nsube":"\u2288","nsubset":"\u2282\u20D2","nsubseteq":"\u2288","nsubseteqq":"\u2AC5\u0338","nsucc":"\u2281","nsucceq":"\u2AB0\u0338","nsup":"\u2285","nsupE":"\u2AC6\u0338","nsupe":"\u2289","nsupset":"\u2283\u20D2","nsupseteq":"\u2289","nsupseteqq":"\u2AC6\u0338","ntgl":"\u2279","Ntilde":"\u00D1","ntilde":"\u00F1","ntlg":"\u2278","ntriangleleft":"\u22EA","ntrianglelefteq":"\u22EC","ntriangleright":"\u22EB","ntrianglerighteq":"\u22ED","Nu":"\u039D","nu":"\u03BD","num":"#","numero":"\u2116","numsp":"\u2007","nvap":"\u224D\u20D2","nvdash":"\u22AC","nvDash":"\u22AD","nVdash":"\u22AE","nVDash":"\u22AF","nvge":"\u2265\u20D2","nvgt":">\u20D2","nvHarr":"\u2904","nvinfin":"\u29DE","nvlArr":"\u2902","nvle":"\u2264\u20D2","nvlt":"<\u20D2","nvltrie":"\u22B4\u20D2","nvrArr":"\u2903","nvrtrie":"\u22B5\u20D2","nvsim":"\u223C\u20D2","nwarhk":"\u2923","nwarr":"\u2196","nwArr":"\u21D6","nwarrow":"\u2196","nwnear":"\u2927","Oacute":"\u00D3","oacute":"\u00F3","oast":"\u229B","Ocirc":"\u00D4","ocirc":"\u00F4","ocir":"\u229A","Ocy":"\u041E","ocy":"\u043E","odash":"\u229D","Odblac":"\u0150","odblac":"\u0151","odiv":"\u2A38","odot":"\u2299","odsold":"\u29BC","OElig":"\u0152","oelig":"\u0153","ofcir":"\u29BF","Ofr":"\uD835\uDD12","ofr":"\uD835\uDD2C","ogon":"\u02DB","Ograve":"\u00D2","ograve":"\u00F2","ogt":"\u29C1","ohbar":"\u29B5","ohm":"\u03A9","oint":"\u222E","olarr":"\u21BA","olcir":"\u29BE","olcross":"\u29BB","oline":"\u203E","olt":"\u29C0","Omacr":"\u014C","omacr":"\u014D","Omega":"\u03A9","omega":"\u03C9","Omicron":"\u039F","omicron":"\u03BF","omid":"\u29B6","ominus":"\u2296","Oopf":"\uD835\uDD46","oopf":"\uD835\uDD60","opar":"\u29B7","OpenCurlyDoubleQuote":"\u201C","OpenCurlyQuote":"\u2018","operp":"\u29B9","oplus":"\u2295","orarr":"\u21BB","Or":"\u2A54","or":"\u2228","ord":"\u2A5D","order":"\u2134","orderof":"\u2134","ordf":"\u00AA","ordm":"\u00BA","origof":"\u22B6","oror":"\u2A56","orslope":"\u2A57","orv":"\u2A5B","oS":"\u24C8","Oscr":"\uD835\uDCAA","oscr":"\u2134","Oslash":"\u00D8","oslash":"\u00F8","osol":"\u2298","Otilde":"\u00D5","otilde":"\u00F5","otimesas":"\u2A36","Otimes":"\u2A37","otimes":"\u2297","Ouml":"\u00D6","ouml":"\u00F6","ovbar":"\u233D","OverBar":"\u203E","OverBrace":"\u23DE","OverBracket":"\u23B4","OverParenthesis":"\u23DC","para":"\u00B6","parallel":"\u2225","par":"\u2225","parsim":"\u2AF3","parsl":"\u2AFD","part":"\u2202","PartialD":"\u2202","Pcy":"\u041F","pcy":"\u043F","percnt":"%","period":".","permil":"\u2030","perp":"\u22A5","pertenk":"\u2031","Pfr":"\uD835\uDD13","pfr":"\uD835\uDD2D","Phi":"\u03A6","phi":"\u03C6","phiv":"\u03D5","phmmat":"\u2133","phone":"\u260E","Pi":"\u03A0","pi":"\u03C0","pitchfork":"\u22D4","piv":"\u03D6","planck":"\u210F","planckh":"\u210E","plankv":"\u210F","plusacir":"\u2A23","plusb":"\u229E","pluscir":"\u2A22","plus":"+","plusdo":"\u2214","plusdu":"\u2A25","pluse":"\u2A72","PlusMinus":"\u00B1","plusmn":"\u00B1","plussim":"\u2A26","plustwo":"\u2A27","pm":"\u00B1","Poincareplane":"\u210C","pointint":"\u2A15","popf":"\uD835\uDD61","Popf":"\u2119","pound":"\u00A3","prap":"\u2AB7","Pr":"\u2ABB","pr":"\u227A","prcue":"\u227C","precapprox":"\u2AB7","prec":"\u227A","preccurlyeq":"\u227C","Precedes":"\u227A","PrecedesEqual":"\u2AAF","PrecedesSlantEqual":"\u227C","PrecedesTilde":"\u227E","preceq":"\u2AAF","precnapprox":"\u2AB9","precneqq":"\u2AB5","precnsim":"\u22E8","pre":"\u2AAF","prE":"\u2AB3","precsim":"\u227E","prime":"\u2032","Prime":"\u2033","primes":"\u2119","prnap":"\u2AB9","prnE":"\u2AB5","prnsim":"\u22E8","prod":"\u220F","Product":"\u220F","profalar":"\u232E","profline":"\u2312","profsurf":"\u2313","prop":"\u221D","Proportional":"\u221D","Proportion":"\u2237","propto":"\u221D","prsim":"\u227E","prurel":"\u22B0","Pscr":"\uD835\uDCAB","pscr":"\uD835\uDCC5","Psi":"\u03A8","psi":"\u03C8","puncsp":"\u2008","Qfr":"\uD835\uDD14","qfr":"\uD835\uDD2E","qint":"\u2A0C","qopf":"\uD835\uDD62","Qopf":"\u211A","qprime":"\u2057","Qscr":"\uD835\uDCAC","qscr":"\uD835\uDCC6","quaternions":"\u210D","quatint":"\u2A16","quest":"?","questeq":"\u225F","quot":"\"","QUOT":"\"","rAarr":"\u21DB","race":"\u223D\u0331","Racute":"\u0154","racute":"\u0155","radic":"\u221A","raemptyv":"\u29B3","rang":"\u27E9","Rang":"\u27EB","rangd":"\u2992","range":"\u29A5","rangle":"\u27E9","raquo":"\u00BB","rarrap":"\u2975","rarrb":"\u21E5","rarrbfs":"\u2920","rarrc":"\u2933","rarr":"\u2192","Rarr":"\u21A0","rArr":"\u21D2","rarrfs":"\u291E","rarrhk":"\u21AA","rarrlp":"\u21AC","rarrpl":"\u2945","rarrsim":"\u2974","Rarrtl":"\u2916","rarrtl":"\u21A3","rarrw":"\u219D","ratail":"\u291A","rAtail":"\u291C","ratio":"\u2236","rationals":"\u211A","rbarr":"\u290D","rBarr":"\u290F","RBarr":"\u2910","rbbrk":"\u2773","rbrace":"}","rbrack":"]","rbrke":"\u298C","rbrksld":"\u298E","rbrkslu":"\u2990","Rcaron":"\u0158","rcaron":"\u0159","Rcedil":"\u0156","rcedil":"\u0157","rceil":"\u2309","rcub":"}","Rcy":"\u0420","rcy":"\u0440","rdca":"\u2937","rdldhar":"\u2969","rdquo":"\u201D","rdquor":"\u201D","rdsh":"\u21B3","real":"\u211C","realine":"\u211B","realpart":"\u211C","reals":"\u211D","Re":"\u211C","rect":"\u25AD","reg":"\u00AE","REG":"\u00AE","ReverseElement":"\u220B","ReverseEquilibrium":"\u21CB","ReverseUpEquilibrium":"\u296F","rfisht":"\u297D","rfloor":"\u230B","rfr":"\uD835\uDD2F","Rfr":"\u211C","rHar":"\u2964","rhard":"\u21C1","rharu":"\u21C0","rharul":"\u296C","Rho":"\u03A1","rho":"\u03C1","rhov":"\u03F1","RightAngleBracket":"\u27E9","RightArrowBar":"\u21E5","rightarrow":"\u2192","RightArrow":"\u2192","Rightarrow":"\u21D2","RightArrowLeftArrow":"\u21C4","rightarrowtail":"\u21A3","RightCeiling":"\u2309","RightDoubleBracket":"\u27E7","RightDownTeeVector":"\u295D","RightDownVectorBar":"\u2955","RightDownVector":"\u21C2","RightFloor":"\u230B","rightharpoondown":"\u21C1","rightharpoonup":"\u21C0","rightleftarrows":"\u21C4","rightleftharpoons":"\u21CC","rightrightarrows":"\u21C9","rightsquigarrow":"\u219D","RightTeeArrow":"\u21A6","RightTee":"\u22A2","RightTeeVector":"\u295B","rightthreetimes":"\u22CC","RightTriangleBar":"\u29D0","RightTriangle":"\u22B3","RightTriangleEqual":"\u22B5","RightUpDownVector":"\u294F","RightUpTeeVector":"\u295C","RightUpVectorBar":"\u2954","RightUpVector":"\u21BE","RightVectorBar":"\u2953","RightVector":"\u21C0","ring":"\u02DA","risingdotseq":"\u2253","rlarr":"\u21C4","rlhar":"\u21CC","rlm":"\u200F","rmoustache":"\u23B1","rmoust":"\u23B1","rnmid":"\u2AEE","roang":"\u27ED","roarr":"\u21FE","robrk":"\u27E7","ropar":"\u2986","ropf":"\uD835\uDD63","Ropf":"\u211D","roplus":"\u2A2E","rotimes":"\u2A35","RoundImplies":"\u2970","rpar":")","rpargt":"\u2994","rppolint":"\u2A12","rrarr":"\u21C9","Rrightarrow":"\u21DB","rsaquo":"\u203A","rscr":"\uD835\uDCC7","Rscr":"\u211B","rsh":"\u21B1","Rsh":"\u21B1","rsqb":"]","rsquo":"\u2019","rsquor":"\u2019","rthree":"\u22CC","rtimes":"\u22CA","rtri":"\u25B9","rtrie":"\u22B5","rtrif":"\u25B8","rtriltri":"\u29CE","RuleDelayed":"\u29F4","ruluhar":"\u2968","rx":"\u211E","Sacute":"\u015A","sacute":"\u015B","sbquo":"\u201A","scap":"\u2AB8","Scaron":"\u0160","scaron":"\u0161","Sc":"\u2ABC","sc":"\u227B","sccue":"\u227D","sce":"\u2AB0","scE":"\u2AB4","Scedil":"\u015E","scedil":"\u015F","Scirc":"\u015C","scirc":"\u015D","scnap":"\u2ABA","scnE":"\u2AB6","scnsim":"\u22E9","scpolint":"\u2A13","scsim":"\u227F","Scy":"\u0421","scy":"\u0441","sdotb":"\u22A1","sdot":"\u22C5","sdote":"\u2A66","searhk":"\u2925","searr":"\u2198","seArr":"\u21D8","searrow":"\u2198","sect":"\u00A7","semi":";","seswar":"\u2929","setminus":"\u2216","setmn":"\u2216","sext":"\u2736","Sfr":"\uD835\uDD16","sfr":"\uD835\uDD30","sfrown":"\u2322","sharp":"\u266F","SHCHcy":"\u0429","shchcy":"\u0449","SHcy":"\u0428","shcy":"\u0448","ShortDownArrow":"\u2193","ShortLeftArrow":"\u2190","shortmid":"\u2223","shortparallel":"\u2225","ShortRightArrow":"\u2192","ShortUpArrow":"\u2191","shy":"\u00AD","Sigma":"\u03A3","sigma":"\u03C3","sigmaf":"\u03C2","sigmav":"\u03C2","sim":"\u223C","simdot":"\u2A6A","sime":"\u2243","simeq":"\u2243","simg":"\u2A9E","simgE":"\u2AA0","siml":"\u2A9D","simlE":"\u2A9F","simne":"\u2246","simplus":"\u2A24","simrarr":"\u2972","slarr":"\u2190","SmallCircle":"\u2218","smallsetminus":"\u2216","smashp":"\u2A33","smeparsl":"\u29E4","smid":"\u2223","smile":"\u2323","smt":"\u2AAA","smte":"\u2AAC","smtes":"\u2AAC\uFE00","SOFTcy":"\u042C","softcy":"\u044C","solbar":"\u233F","solb":"\u29C4","sol":"/","Sopf":"\uD835\uDD4A","sopf":"\uD835\uDD64","spades":"\u2660","spadesuit":"\u2660","spar":"\u2225","sqcap":"\u2293","sqcaps":"\u2293\uFE00","sqcup":"\u2294","sqcups":"\u2294\uFE00","Sqrt":"\u221A","sqsub":"\u228F","sqsube":"\u2291","sqsubset":"\u228F","sqsubseteq":"\u2291","sqsup":"\u2290","sqsupe":"\u2292","sqsupset":"\u2290","sqsupseteq":"\u2292","square":"\u25A1","Square":"\u25A1","SquareIntersection":"\u2293","SquareSubset":"\u228F","SquareSubsetEqual":"\u2291","SquareSuperset":"\u2290","SquareSupersetEqual":"\u2292","SquareUnion":"\u2294","squarf":"\u25AA","squ":"\u25A1","squf":"\u25AA","srarr":"\u2192","Sscr":"\uD835\uDCAE","sscr":"\uD835\uDCC8","ssetmn":"\u2216","ssmile":"\u2323","sstarf":"\u22C6","Star":"\u22C6","star":"\u2606","starf":"\u2605","straightepsilon":"\u03F5","straightphi":"\u03D5","strns":"\u00AF","sub":"\u2282","Sub":"\u22D0","subdot":"\u2ABD","subE":"\u2AC5","sube":"\u2286","subedot":"\u2AC3","submult":"\u2AC1","subnE":"\u2ACB","subne":"\u228A","subplus":"\u2ABF","subrarr":"\u2979","subset":"\u2282","Subset":"\u22D0","subseteq":"\u2286","subseteqq":"\u2AC5","SubsetEqual":"\u2286","subsetneq":"\u228A","subsetneqq":"\u2ACB","subsim":"\u2AC7","subsub":"\u2AD5","subsup":"\u2AD3","succapprox":"\u2AB8","succ":"\u227B","succcurlyeq":"\u227D","Succeeds":"\u227B","SucceedsEqual":"\u2AB0","SucceedsSlantEqual":"\u227D","SucceedsTilde":"\u227F","succeq":"\u2AB0","succnapprox":"\u2ABA","succneqq":"\u2AB6","succnsim":"\u22E9","succsim":"\u227F","SuchThat":"\u220B","sum":"\u2211","Sum":"\u2211","sung":"\u266A","sup1":"\u00B9","sup2":"\u00B2","sup3":"\u00B3","sup":"\u2283","Sup":"\u22D1","supdot":"\u2ABE","supdsub":"\u2AD8","supE":"\u2AC6","supe":"\u2287","supedot":"\u2AC4","Superset":"\u2283","SupersetEqual":"\u2287","suphsol":"\u27C9","suphsub":"\u2AD7","suplarr":"\u297B","supmult":"\u2AC2","supnE":"\u2ACC","supne":"\u228B","supplus":"\u2AC0","supset":"\u2283","Supset":"\u22D1","supseteq":"\u2287","supseteqq":"\u2AC6","supsetneq":"\u228B","supsetneqq":"\u2ACC","supsim":"\u2AC8","supsub":"\u2AD4","supsup":"\u2AD6","swarhk":"\u2926","swarr":"\u2199","swArr":"\u21D9","swarrow":"\u2199","swnwar":"\u292A","szlig":"\u00DF","Tab":"\t","target":"\u2316","Tau":"\u03A4","tau":"\u03C4","tbrk":"\u23B4","Tcaron":"\u0164","tcaron":"\u0165","Tcedil":"\u0162","tcedil":"\u0163","Tcy":"\u0422","tcy":"\u0442","tdot":"\u20DB","telrec":"\u2315","Tfr":"\uD835\uDD17","tfr":"\uD835\uDD31","there4":"\u2234","therefore":"\u2234","Therefore":"\u2234","Theta":"\u0398","theta":"\u03B8","thetasym":"\u03D1","thetav":"\u03D1","thickapprox":"\u2248","thicksim":"\u223C","ThickSpace":"\u205F\u200A","ThinSpace":"\u2009","thinsp":"\u2009","thkap":"\u2248","thksim":"\u223C","THORN":"\u00DE","thorn":"\u00FE","tilde":"\u02DC","Tilde":"\u223C","TildeEqual":"\u2243","TildeFullEqual":"\u2245","TildeTilde":"\u2248","timesbar":"\u2A31","timesb":"\u22A0","times":"\u00D7","timesd":"\u2A30","tint":"\u222D","toea":"\u2928","topbot":"\u2336","topcir":"\u2AF1","top":"\u22A4","Topf":"\uD835\uDD4B","topf":"\uD835\uDD65","topfork":"\u2ADA","tosa":"\u2929","tprime":"\u2034","trade":"\u2122","TRADE":"\u2122","triangle":"\u25B5","triangledown":"\u25BF","triangleleft":"\u25C3","trianglelefteq":"\u22B4","triangleq":"\u225C","triangleright":"\u25B9","trianglerighteq":"\u22B5","tridot":"\u25EC","trie":"\u225C","triminus":"\u2A3A","TripleDot":"\u20DB","triplus":"\u2A39","trisb":"\u29CD","tritime":"\u2A3B","trpezium":"\u23E2","Tscr":"\uD835\uDCAF","tscr":"\uD835\uDCC9","TScy":"\u0426","tscy":"\u0446","TSHcy":"\u040B","tshcy":"\u045B","Tstrok":"\u0166","tstrok":"\u0167","twixt":"\u226C","twoheadleftarrow":"\u219E","twoheadrightarrow":"\u21A0","Uacute":"\u00DA","uacute":"\u00FA","uarr":"\u2191","Uarr":"\u219F","uArr":"\u21D1","Uarrocir":"\u2949","Ubrcy":"\u040E","ubrcy":"\u045E","Ubreve":"\u016C","ubreve":"\u016D","Ucirc":"\u00DB","ucirc":"\u00FB","Ucy":"\u0423","ucy":"\u0443","udarr":"\u21C5","Udblac":"\u0170","udblac":"\u0171","udhar":"\u296E","ufisht":"\u297E","Ufr":"\uD835\uDD18","ufr":"\uD835\uDD32","Ugrave":"\u00D9","ugrave":"\u00F9","uHar":"\u2963","uharl":"\u21BF","uharr":"\u21BE","uhblk":"\u2580","ulcorn":"\u231C","ulcorner":"\u231C","ulcrop":"\u230F","ultri":"\u25F8","Umacr":"\u016A","umacr":"\u016B","uml":"\u00A8","UnderBar":"_","UnderBrace":"\u23DF","UnderBracket":"\u23B5","UnderParenthesis":"\u23DD","Union":"\u22C3","UnionPlus":"\u228E","Uogon":"\u0172","uogon":"\u0173","Uopf":"\uD835\uDD4C","uopf":"\uD835\uDD66","UpArrowBar":"\u2912","uparrow":"\u2191","UpArrow":"\u2191","Uparrow":"\u21D1","UpArrowDownArrow":"\u21C5","updownarrow":"\u2195","UpDownArrow":"\u2195","Updownarrow":"\u21D5","UpEquilibrium":"\u296E","upharpoonleft":"\u21BF","upharpoonright":"\u21BE","uplus":"\u228E","UpperLeftArrow":"\u2196","UpperRightArrow":"\u2197","upsi":"\u03C5","Upsi":"\u03D2","upsih":"\u03D2","Upsilon":"\u03A5","upsilon":"\u03C5","UpTeeArrow":"\u21A5","UpTee":"\u22A5","upuparrows":"\u21C8","urcorn":"\u231D","urcorner":"\u231D","urcrop":"\u230E","Uring":"\u016E","uring":"\u016F","urtri":"\u25F9","Uscr":"\uD835\uDCB0","uscr":"\uD835\uDCCA","utdot":"\u22F0","Utilde":"\u0168","utilde":"\u0169","utri":"\u25B5","utrif":"\u25B4","uuarr":"\u21C8","Uuml":"\u00DC","uuml":"\u00FC","uwangle":"\u29A7","vangrt":"\u299C","varepsilon":"\u03F5","varkappa":"\u03F0","varnothing":"\u2205","varphi":"\u03D5","varpi":"\u03D6","varpropto":"\u221D","varr":"\u2195","vArr":"\u21D5","varrho":"\u03F1","varsigma":"\u03C2","varsubsetneq":"\u228A\uFE00","varsubsetneqq":"\u2ACB\uFE00","varsupsetneq":"\u228B\uFE00","varsupsetneqq":"\u2ACC\uFE00","vartheta":"\u03D1","vartriangleleft":"\u22B2","vartriangleright":"\u22B3","vBar":"\u2AE8","Vbar":"\u2AEB","vBarv":"\u2AE9","Vcy":"\u0412","vcy":"\u0432","vdash":"\u22A2","vDash":"\u22A8","Vdash":"\u22A9","VDash":"\u22AB","Vdashl":"\u2AE6","veebar":"\u22BB","vee":"\u2228","Vee":"\u22C1","veeeq":"\u225A","vellip":"\u22EE","verbar":"|","Verbar":"\u2016","vert":"|","Vert":"\u2016","VerticalBar":"\u2223","VerticalLine":"|","VerticalSeparator":"\u2758","VerticalTilde":"\u2240","VeryThinSpace":"\u200A","Vfr":"\uD835\uDD19","vfr":"\uD835\uDD33","vltri":"\u22B2","vnsub":"\u2282\u20D2","vnsup":"\u2283\u20D2","Vopf":"\uD835\uDD4D","vopf":"\uD835\uDD67","vprop":"\u221D","vrtri":"\u22B3","Vscr":"\uD835\uDCB1","vscr":"\uD835\uDCCB","vsubnE":"\u2ACB\uFE00","vsubne":"\u228A\uFE00","vsupnE":"\u2ACC\uFE00","vsupne":"\u228B\uFE00","Vvdash":"\u22AA","vzigzag":"\u299A","Wcirc":"\u0174","wcirc":"\u0175","wedbar":"\u2A5F","wedge":"\u2227","Wedge":"\u22C0","wedgeq":"\u2259","weierp":"\u2118","Wfr":"\uD835\uDD1A","wfr":"\uD835\uDD34","Wopf":"\uD835\uDD4E","wopf":"\uD835\uDD68","wp":"\u2118","wr":"\u2240","wreath":"\u2240","Wscr":"\uD835\uDCB2","wscr":"\uD835\uDCCC","xcap":"\u22C2","xcirc":"\u25EF","xcup":"\u22C3","xdtri":"\u25BD","Xfr":"\uD835\uDD1B","xfr":"\uD835\uDD35","xharr":"\u27F7","xhArr":"\u27FA","Xi":"\u039E","xi":"\u03BE","xlarr":"\u27F5","xlArr":"\u27F8","xmap":"\u27FC","xnis":"\u22FB","xodot":"\u2A00","Xopf":"\uD835\uDD4F","xopf":"\uD835\uDD69","xoplus":"\u2A01","xotime":"\u2A02","xrarr":"\u27F6","xrArr":"\u27F9","Xscr":"\uD835\uDCB3","xscr":"\uD835\uDCCD","xsqcup":"\u2A06","xuplus":"\u2A04","xutri":"\u25B3","xvee":"\u22C1","xwedge":"\u22C0","Yacute":"\u00DD","yacute":"\u00FD","YAcy":"\u042F","yacy":"\u044F","Ycirc":"\u0176","ycirc":"\u0177","Ycy":"\u042B","ycy":"\u044B","yen":"\u00A5","Yfr":"\uD835\uDD1C","yfr":"\uD835\uDD36","YIcy":"\u0407","yicy":"\u0457","Yopf":"\uD835\uDD50","yopf":"\uD835\uDD6A","Yscr":"\uD835\uDCB4","yscr":"\uD835\uDCCE","YUcy":"\u042E","yucy":"\u044E","yuml":"\u00FF","Yuml":"\u0178","Zacute":"\u0179","zacute":"\u017A","Zcaron":"\u017D","zcaron":"\u017E","Zcy":"\u0417","zcy":"\u0437","Zdot":"\u017B","zdot":"\u017C","zeetrf":"\u2128","ZeroWidthSpace":"\u200B","Zeta":"\u0396","zeta":"\u03B6","zfr":"\uD835\uDD37","Zfr":"\u2128","ZHcy":"\u0416","zhcy":"\u0436","zigrarr":"\u21DD","zopf":"\uD835\uDD6B","Zopf":"\u2124","Zscr":"\uD835\uDCB5","zscr":"\uD835\uDCCF","zwj":"\u200D","zwnj":"\u200C"}
{"Aacute":"\u00C1","aacute":"\u00E1","Acirc":"\u00C2","acirc":"\u00E2","acute":"\u00B4","AElig":"\u00C6","aelig":"\u00E6","Agrave":"\u00C0","agrave":"\u00E0","amp":"&","AMP":"&","Aring":"\u00C5","aring":"\u00E5","Atilde":"\u00C3","atilde":"\u00E3","Auml":"\u00C4","auml":"\u00E4","brvbar":"\u00A6","Ccedil":"\u00C7","ccedil":"\u00E7","cedil":"\u00B8","cent":"\u00A2","copy":"\u00A9","COPY":"\u00A9","curren":"\u00A4","deg":"\u00B0","divide":"\u00F7","Eacute":"\u00C9","eacute":"\u00E9","Ecirc":"\u00CA","ecirc":"\u00EA","Egrave":"\u00C8","egrave":"\u00E8","ETH":"\u00D0","eth":"\u00F0","Euml":"\u00CB","euml":"\u00EB","frac12":"\u00BD","frac14":"\u00BC","frac34":"\u00BE","gt":">","GT":">","Iacute":"\u00CD","iacute":"\u00ED","Icirc":"\u00CE","icirc":"\u00EE","iexcl":"\u00A1","Igrave":"\u00CC","igrave":"\u00EC","iquest":"\u00BF","Iuml":"\u00CF","iuml":"\u00EF","laquo":"\u00AB","lt":"<","LT":"<","macr":"\u00AF","micro":"\u00B5","middot":"\u00B7","nbsp":"\u00A0","not":"\u00AC","Ntilde":"\u00D1","ntilde":"\u00F1","Oacute":"\u00D3","oacute":"\u00F3","Ocirc":"\u00D4","ocirc":"\u00F4","Ograve":"\u00D2","ograve":"\u00F2","ordf":"\u00AA","ordm":"\u00BA","Oslash":"\u00D8","oslash":"\u00F8","Otilde":"\u00D5","otilde":"\u00F5","Ouml":"\u00D6","ouml":"\u00F6","para":"\u00B6","plusmn":"\u00B1","pound":"\u00A3","quot":"\"","QUOT":"\"","raquo":"\u00BB","reg":"\u00AE","REG":"\u00AE","sect":"\u00A7","shy":"\u00AD","sup1":"\u00B9","sup2":"\u00B2","sup3":"\u00B3","szlig":"\u00DF","THORN":"\u00DE","thorn":"\u00FE","times":"\u00D7","Uacute":"\u00DA","uacute":"\u00FA","Ucirc":"\u00DB","ucirc":"\u00FB","Ugrave":"\u00D9","ugrave":"\u00F9","uml":"\u00A8","Uuml":"\u00DC","uuml":"\u00FC","Yacute":"\u00DD","yacute":"\u00FD","yen":"\u00A5","yuml":"\u00FF"}
{"amp":"&","apos":"'","gt":">","lt":"<","quot":"\""}
{
"_args": [
[
{
"raw": "entities@~1.1.1",
"scope": null,
"escapedName": "entities",
"name": "entities",
"rawSpec": "~1.1.1",
"spec": ">=1.1.1 <1.2.0",
"type": "range"
},
"F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\cheerio"
]
],
"_from": "entities@>=1.1.1 <1.2.0",
"_id": "entities@1.1.1",
"_inCache": true,
"_location": "/entities",
"_npmUser": {
"name": "feedic",
"email": "me@feedic.com"
},
"_npmVersion": "1.4.6",
"_phantomChildren": {},
"_requested": {
"raw": "entities@~1.1.1",
"scope": null,
"escapedName": "entities",
"name": "entities",
"rawSpec": "~1.1.1",
"spec": ">=1.1.1 <1.2.0",
"type": "range"
},
"_requiredBy": [
"/cheerio",
"/dom-serializer",
"/htmlparser2"
],
"_resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz",
"_shasum": "6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0",
"_shrinkwrap": null,
"_spec": "entities@~1.1.1",
"_where": "F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\cheerio",
"author": {
"name": "Felix Boehm",
"email": "me@feedic.com"
},
"bugs": {
"url": "https://github.com/fb55/node-entities/issues"
},
"dependencies": {},
"description": "Encode & decode XML/HTML entities with ease",
"devDependencies": {
"coveralls": "*",
"istanbul": "*",
"jshint": "2",
"mocha": "1",
"mocha-lcov-reporter": "*"
},
"directories": {
"test": "test"
},
"dist": {
"shasum": "6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0",
"tarball": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz"
},
"homepage": "https://github.com/fb55/node-entities",
"jshintConfig": {
"eqeqeq": true,
"freeze": true,
"latedef": "nofunc",
"noarg": true,
"nonbsp": true,
"quotmark": "double",
"undef": true,
"unused": true,
"trailing": true,
"eqnull": true,
"proto": true,
"smarttabs": true,
"node": true,
"globals": {
"describe": true,
"it": true
}
},
"keywords": [
"html",
"xml",
"entity",
"encoding"
],
"license": "BSD-like",
"main": "./index.js",
"maintainers": [
{
"name": "feedic",
"email": "me@feedic.com"
}
],
"name": "entities",
"optionalDependencies": {},
"readme": "ERROR: No README data found!",
"repository": {
"type": "git",
"url": "git://github.com/fb55/node-entities.git"
},
"scripts": {
"coveralls": "npm run lint && npm run lcov && (cat coverage/lcov.info | coveralls || exit 0)",
"lcov": "istanbul cover _mocha --report lcovonly -- -R spec",
"lint": "jshint index.js lib/*.js test/*.js",
"test": "mocha && npm run lint"
},
"version": "1.1.1"
}

#entities NPM version Downloads Build Status Coverage

En- & decoder for XML/HTML entities.

##How to…

###…install entities

npm i entities

###…use entities

var entities = require("entities");
//encoding
entities.encodeXML("&#38;");  // "&amp;#38;"
entities.encodeHTML("&#38;"); // "&amp;&num;38&semi;"
//decoding
entities.decodeXML("asdf &amp; &#xFF; &#xFC; &apos;");  // "asdf & ÿ ü '"
entities.decodeHTML("asdf &amp; &yuml; &uuml; &apos;"); // "asdf & ÿ ü '"

License: BSD-like

var assert = require("assert"),
path = require("path"),
entities = require("../");
describe("Encode->decode test", function(){
var testcases = [
{
input: "asdf & ÿ ü '",
xml: "asdf &amp; &#xFF; &#xFC; &apos;",
html: "asdf &amp; &yuml; &uuml; &apos;"
}, {
input: "&#38;",
xml: "&amp;#38;",
html: "&amp;&num;38&semi;"
},
];
testcases.forEach(function(tc) {
var encodedXML = entities.encodeXML(tc.input);
it("should XML encode " + tc.input, function(){
assert.equal(encodedXML, tc.xml);
});
it("should default to XML encode " + tc.input, function(){
assert.equal(entities.encode(tc.input), tc.xml);
});
it("should XML decode " + encodedXML, function(){
assert.equal(entities.decodeXML(encodedXML), tc.input);
});
it("should default to XML encode " + encodedXML, function(){
assert.equal(entities.decode(encodedXML), tc.input);
});
it("should default strict to XML encode " + encodedXML, function(){
assert.equal(entities.decodeStrict(encodedXML), tc.input);
});
var encodedHTML5 = entities.encodeHTML5(tc.input);
it("should HTML5 encode " + tc.input, function(){
assert.equal(encodedHTML5, tc.html);
});
it("should HTML5 decode " + encodedHTML5, function(){
assert.equal(entities.decodeHTML(encodedHTML5), tc.input);
});
});
it("should encode data URIs (issue 16)", function(){
var data = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAALAAABAAEAAAIBRAA7";
assert.equal(entities.decode(entities.encode(data)), data);
});
});
describe("Decode test", function(){
var testcases = [
{ input: "&amp;amp;", output: "&amp;" },
{ input: "&amp;#38;", output: "&#38;" },
{ input: "&amp;#x26;", output: "&#x26;" },
{ input: "&amp;#X26;", output: "&#X26;" },
{ input: "&#38;#38;", output: "&#38;" },
{ input: "&#x26;#38;", output: "&#38;" },
{ input: "&#X26;#38;", output: "&#38;" },
{ input: "&#x3a;", output: ":" },
{ input: "&#x3A;", output: ":" },
{ input: "&#X3a;", output: ":" },
{ input: "&#X3A;", output: ":" }
];
testcases.forEach(function(tc) {
it("should XML decode " + tc.input, function(){
assert.equal(entities.decodeXML(tc.input), tc.output);
});
it("should HTML4 decode " + tc.input, function(){
assert.equal(entities.decodeHTML(tc.input), tc.output);
});
it("should HTML5 decode " + tc.input, function(){
assert.equal(entities.decodeHTML(tc.input), tc.output);
});
});
});
var levels = ["xml", "entities"];
describe("Documents", function(){
levels
.map(function(n){ return path.join("..", "maps", n); })
.map(require)
.forEach(function(doc, i){
describe("Decode", function(){
it(levels[i], function(){
Object.keys(doc).forEach(function(e){
for(var l = i; l < levels.length; l++){
assert.equal(entities.decode("&" + e + ";", l), doc[e]);
}
});
});
});
describe("Decode strict", function(){
it(levels[i], function(){
Object.keys(doc).forEach(function(e){
for(var l = i; l < levels.length; l++){
assert.equal(entities.decodeStrict("&" + e + ";", l), doc[e]);
}
});
});
});
describe("Encode", function(){
it(levels[i], function(){
Object.keys(doc).forEach(function(e){
for(var l = i; l < levels.length; l++){
assert.equal(entities.decode(entities.encode(doc[e], l), l), doc[e]);
}
});
});
});
});
var legacy = require("../maps/legacy.json");
describe("Legacy", function(){
it("should decode", runLegacy);
});
function runLegacy(){
Object.keys(legacy).forEach(function(e){
assert.equal(entities.decodeHTML("&" + e), legacy[e]);
});
}
});
var astral = {
"1D306": "\uD834\uDF06",
"1D11E": "\uD834\uDD1E"
};
var astralSpecial = {
"80": "\u20AC",
"110000": "\uFFFD"
};
describe("Astral entities", function(){
Object.keys(astral).forEach(function(c){
it("should decode " + astral[c], function(){
assert.equal(entities.decode("&#x" + c + ";"), astral[c]);
});
it("should encode " + astral[c], function(){
assert.equal(entities.encode(astral[c]), "&#x" + c + ";");
});
it("should escape " + astral[c], function(){
assert.equal(entities.escape(astral[c]), "&#x" + c + ";");
});
});
Object.keys(astralSpecial).forEach(function(c){
it("special should decode \\u" + c, function(){
assert.equal(entities.decode("&#x" + c + ";"), astralSpecial[c]);
});
});
});
describe("Escape", function(){
it("should always decode ASCII chars", function(){
for(var i = 0; i < 0x7F; i++){
var c = String.fromCharCode(i);
assert.equal(entities.decodeXML(entities.escape(c)), c);
}
});
});
'use strict';
var matchOperatorsRe = /[|\\{}()[\]^$+*?.]/g;
module.exports = function (str) {
if (typeof str !== 'string') {
throw new TypeError('Expected a string');
}
return str.replace(matchOperatorsRe, '\\$&');
};
The MIT License (MIT)
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
{
"_args": [
[
{
"raw": "escape-string-regexp@^1.0.2",
"scope": null,
"escapedName": "escape-string-regexp",
"name": "escape-string-regexp",
"rawSpec": "^1.0.2",
"spec": ">=1.0.2 <2.0.0",
"type": "range"
},
"F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\chalk"
]
],
"_from": "escape-string-regexp@>=1.0.2 <2.0.0",
"_id": "escape-string-regexp@1.0.5",
"_inCache": true,
"_location": "/escape-string-regexp",
"_nodeVersion": "4.2.6",
"_npmOperationalInternal": {
"host": "packages-9-west.internal.npmjs.com",
"tmp": "tmp/escape-string-regexp-1.0.5.tgz_1456059312074_0.7245344955008477"
},
"_npmUser": {
"name": "jbnicolai",
"email": "jappelman@xebia.com"
},
"_npmVersion": "2.14.12",
"_phantomChildren": {},
"_requested": {
"raw": "escape-string-regexp@^1.0.2",
"scope": null,
"escapedName": "escape-string-regexp",
"name": "escape-string-regexp",
"rawSpec": "^1.0.2",
"spec": ">=1.0.2 <2.0.0",
"type": "range"
},
"_requiredBy": [
"/chalk"
],
"_resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"_shasum": "1b61c0562190a8dff6ae3bb2cf0200ca130b86d4",
"_shrinkwrap": null,
"_spec": "escape-string-regexp@^1.0.2",
"_where": "F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\chalk",
"author": {
"name": "Sindre Sorhus",
"email": "sindresorhus@gmail.com",
"url": "sindresorhus.com"
},
"bugs": {
"url": "https://github.com/sindresorhus/escape-string-regexp/issues"
},
"dependencies": {},
"description": "Escape RegExp special characters",
"devDependencies": {
"ava": "*",
"xo": "*"
},
"directories": {},
"dist": {
"shasum": "1b61c0562190a8dff6ae3bb2cf0200ca130b86d4",
"tarball": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz"
},
"engines": {
"node": ">=0.8.0"
},
"files": [
"index.js"
],
"gitHead": "db124a3e1aae9d692c4899e42a5c6c3e329eaa20",
"homepage": "https://github.com/sindresorhus/escape-string-regexp",
"keywords": [
"escape",
"regex",
"regexp",
"re",
"regular",
"expression",
"string",
"str",
"special",
"characters"
],
"license": "MIT",
"maintainers": [
{
"name": "sindresorhus",
"email": "sindresorhus@gmail.com"
},
{
"name": "jbnicolai",
"email": "jappelman@xebia.com"
}
],
"name": "escape-string-regexp",
"optionalDependencies": {},
"readme": "ERROR: No README data found!",
"repository": {
"type": "git",
"url": "git+https://github.com/sindresorhus/escape-string-regexp.git"
},
"scripts": {
"test": "xo && ava"
},
"version": "1.0.5"
}

escape-string-regexp Build Status

Escape RegExp special characters

Install

$ npm install --save escape-string-regexp

Usage

const escapeStringRegexp = require('escape-string-regexp');

const escapedString = escapeStringRegexp('how much $ for a unicorn?');
//=> 'how much \$ for a unicorn\?'

new RegExp(escapedString);

License

MIT © Sindre Sorhus

{
"env": {
"browser": false,
"node": true,
"amd": false,
"mocha": false,
"jasmine": false
},
"rules": {
"accessor-pairs": [2, { getWithoutSet: false, setWithoutGet: true }],
"array-bracket-spacing": [2, "never", {
"singleValue": false,
"objectsInArrays": false,
"arraysInArrays": false
}],
"block-scoped-var": [0],
"brace-style": [2, "1tbs", { "allowSingleLine": true }],
"camelcase": [2],
"comma-dangle": [2, "never"],
"comma-spacing": [2],
"comma-style": [2, "last"],
"complexity": [2, 15],
"computed-property-spacing": [2, "never"],
"consistent-return": [2],
"consistent-this": [0, "that"],
"constructor-super": [2],
"curly": [2, "all"],
"default-case": [2],
"dot-notation": [2, { "allowKeywords": true }],
"eol-last": [2],
"eqeqeq": [2],
"func-names": [0],
"func-style": [2, "expression"],
"generator-star-spacing": [2, { "before": false, "after": true }],
"global-strict": [0, "never"],
"guard-for-in": [0],
"handle-callback-err": [0],
"key-spacing": [2, { "beforeColon": false, "afterColon": true }],
"linebreak-style": [2, "unix"],
"lines-around-comment": [2, {
"beforeBlockComment": false,
"afterBlockComment": false,
"beforeLineComment": false,
"beforeLineComment": false,
"allowBlockStart": true,
"allowBlockEnd": true
}],
"quotes": [2, "single", "avoid-escape"],
"max-depth": [1, 4],
"max-len": [0, 80, 4],
"max-nested-callbacks": [2, 2],
"max-params": [2, 2],
"max-statements": [2, 21],
"new-parens": [2],
"new-cap": [2],
"newline-after-var": [0],
"no-alert": [2],
"no-array-constructor": [2],
"no-bitwise": [0],
"no-caller": [2],
"no-catch-shadow": [2],
"no-cond-assign": [2],
"no-console": [2],
"no-constant-condition": [2],
"no-continue": [2],
"no-control-regex": [2],
"no-debugger": [2],
"no-delete-var": [2],
"no-div-regex": [0],
"no-dupe-args": [2],
"no-dupe-keys": [2],
"no-duplicate-case": [2],
"no-else-return": [0],
"no-empty": [2],
"no-empty-character-class": [2],
"no-empty-label": [2],
"no-eq-null": [0],
"no-eval": [2],
"no-ex-assign": [2],
"no-extend-native": [2],
"no-extra-bind": [2],
"no-extra-boolean-cast": [2],
"no-extra-parens": [0],
"no-extra-semi": [2],
"no-fallthrough": [2],
"no-floating-decimal": [2],
"no-func-assign": [2],
"no-implied-eval": [2],
"no-inline-comments": [0],
"no-inner-declarations": [2, "functions"],
"no-invalid-regexp": [2],
"no-irregular-whitespace": [2],
"no-iterator": [2],
"no-label-var": [2],
"no-labels": [2],
"no-lone-blocks": [2],
"no-lonely-if": [2],
"no-loop-func": [2],
"no-mixed-requires": [0, false],
"no-mixed-spaces-and-tabs": [2, false],
"no-multi-spaces": [2],
"no-multi-str": [2],
"no-multiple-empty-lines": [2, {"max": 1}],
"no-native-reassign": [2],
"no-negated-in-lhs": [2],
"no-nested-ternary": [0],
"no-new": [2],
"no-new-func": [2],
"no-new-object": [2],
"no-new-require": [0],
"no-new-wrappers": [2],
"no-obj-calls": [2],
"no-octal": [2],
"no-octal-escape": [2],
"no-param-reassign": [2],
"no-path-concat": [0],
"no-plusplus": [0],
"no-process-env": [0],
"no-process-exit": [2],
"no-proto": [2],
"no-redeclare": [2],
"no-regex-spaces": [2],
"no-reserved-keys": [2],
"no-restricted-modules": [0],
"no-return-assign": [2, "always"],
"no-script-url": [2],
"no-self-compare": [0],
"no-sequences": [2],
"no-shadow": [2],
"no-shadow-restricted-names": [2],
"no-space-before-semi": [2],
"no-spaced-func": [2],
"no-sparse-arrays": [2],
"no-sync": [0],
"no-ternary": [0],
"no-this-before-super": [2],
"no-throw-literal": [2],
"no-trailing-spaces": [2, { "skipBlankLines": false }],
"no-undef": [2],
"no-undef-init": [2],
"no-undefined": [0],
"no-underscore-dangle": [2],
"no-unexpected-multiline": [2],
"no-unneeded-ternary": [2],
"no-unreachable": [2],
"no-unused-expressions": [2],
"no-unused-vars": [2, { "vars": "all", "args": "after-used" }],
"no-use-before-define": [2],
"no-void": [0],
"no-warning-comments": [0, { "terms": ["todo", "fixme", "xxx"], "location": "start" }],
"no-with": [2],
"no-wrap-func": [2],
"object-curly-spacing": [2, "always"],
"object-shorthand": [2, "never"],
"one-var": [0],
"operator-assignment": [0, "always"],
"operator-linebreak": [2, "none"],
"padded-blocks": [0],
"prefer-const": [0],
"quote-props": [0],
"radix": [0],
"semi": [2],
"semi-spacing": [2, { "before": false, "after": true }],
"sort-vars": [0],
"space-after-keywords": [2, "always"],
"space-before-function-paren": [2, { "anonymous": "always", "named": "never" }],
"space-before-blocks": [0, "always"],
"space-in-brackets": [0, "never", {
"singleValue": true,
"arraysInArrays": false,
"arraysInObjects": false,
"objectsInArrays": true,
"objectsInObjects": true,
"propertyName": false
}],
"space-in-parens": [2, "never"],
"space-infix-ops": [2],
"space-return-throw-case": [2],
"space-unary-ops": [2, { "words": true, "nonwords": false }],
"spaced-comment": [2, "always"],
"spaced-line-comment": [0, "always"],
"strict": [2, "global"],
"use-isnan": [2],
"valid-jsdoc": [0],
"valid-typeof": [2],
"vars-on-top": [0],
"wrap-iife": [2],
"wrap-regex": [2],
"yoda": [2, "never", { "exceptRange": true, "onlyEquality": false }]
}
}
{
"additionalRules": [],
"requireSemicolons": true,
"disallowMultipleSpaces": true,
"disallowIdentifierNames": [],
"requireCurlyBraces": ["if", "else", "for", "while", "do", "try", "catch"],
"requireSpaceAfterKeywords": ["if", "else", "for", "while", "do", "switch", "return", "try", "catch", "function"],
"disallowSpaceAfterKeywords": [],
"requireSpacesInAnonymousFunctionExpression": { "beforeOpeningRoundBrace": true, "beforeOpeningCurlyBrace": true },
"requireSpacesInNamedFunctionExpression": { "beforeOpeningCurlyBrace": true },
"disallowSpacesInNamedFunctionExpression": { "beforeOpeningRoundBrace": true },
"requireSpacesInFunctionDeclaration": { "beforeOpeningCurlyBrace": true },
"disallowSpacesInFunctionDeclaration": { "beforeOpeningRoundBrace": true },
"requireSpaceBetweenArguments": true,
"disallowSpacesInsideParentheses": true,
"disallowSpacesInsideArrayBrackets": true,
"disallowQuotedKeysInObjects": "allButReserved",
"disallowSpaceAfterObjectKeys": true,
"requireCommaBeforeLineBreak": true,
"disallowSpaceAfterPrefixUnaryOperators": ["++", "--", "+", "-", "~", "!"],
"requireSpaceAfterPrefixUnaryOperators": [],
"disallowSpaceBeforePostfixUnaryOperators": ["++", "--"],
"requireSpaceBeforePostfixUnaryOperators": [],
"disallowSpaceBeforeBinaryOperators": [],
"requireSpaceBeforeBinaryOperators": ["+", "-", "/", "*", "=", "==", "===", "!=", "!=="],
"requireSpaceAfterBinaryOperators": ["+", "-", "/", "*", "=", "==", "===", "!=", "!=="],
"disallowSpaceAfterBinaryOperators": [],
"disallowImplicitTypeConversion": ["binary", "string"],
"disallowKeywords": ["with", "eval"],
"requireKeywordsOnNewLine": [],
"disallowKeywordsOnNewLine": ["else"],
"requireLineFeedAtFileEnd": true,
"disallowTrailingWhitespace": true,
"disallowTrailingComma": true,
"excludeFiles": ["node_modules/**", "vendor/**"],
"disallowMultipleLineStrings": true,
"requireDotNotation": true,
"requireParenthesesAroundIIFE": true,
"validateLineBreaks": "LF",
"validateQuoteMarks": {
"escape": true,
"mark": "'"
},
"disallowOperatorBeforeLineBreak": [],
"requireSpaceBeforeKeywords": [
"do",
"for",
"if",
"else",
"switch",
"case",
"try",
"catch",
"finally",
"while",
"with",
"return"
],
"validateAlignedFunctionParameters": {
"lineBreakAfterOpeningBraces": true,
"lineBreakBeforeClosingBraces": true
},
"requirePaddingNewLinesBeforeExport": true,
"validateNewlineAfterArrayElements": {
"maximum": 6
},
"requirePaddingNewLinesAfterUseStrict": true
}
language: node_js
node_js:
- "iojs-v2.3"
- "iojs-v2.2"
- "iojs-v2.1"
- "iojs-v2.0"
- "iojs-v1.8"
- "iojs-v1.7"
- "iojs-v1.6"
- "iojs-v1.5"
- "iojs-v1.4"
- "iojs-v1.3"
- "iojs-v1.2"
- "iojs-v1.1"
- "iojs-v1.0"
- "0.12"
- "0.11"
- "0.10"
- "0.9"
- "0.8"
- "0.6"
- "0.4"
before_install:
- '[ "${TRAVIS_NODE_VERSION}" = "0.6" ] || npm install -g npm@1.4.28 && npm install -g npm'
sudo: false
matrix:
fast_finish: true
allow_failures:
- node_js: "iojs-v2.2"
- node_js: "iojs-v2.1"
- node_js: "iojs-v2.0"
- node_js: "iojs-v1.7"
- node_js: "iojs-v1.6"
- node_js: "iojs-v1.5"
- node_js: "iojs-v1.4"
- node_js: "iojs-v1.3"
- node_js: "iojs-v1.2"
- node_js: "iojs-v1.1"
- node_js: "iojs-v1.0"
- node_js: "0.11"
- node_js: "0.9"
- node_js: "0.8"
- node_js: "0.6"
- node_js: "0.4"

3.0.0 / 2015-07-01

  • [Possible breaking change] Use global "strict" directive (#32)
  • [Tests] int is an ES3 reserved word
  • [Tests] Test up to io.js v2.3
  • [Tests] Add npm run eslint
  • [Dev Deps] Update covert, jscs

2.0.1 / 2015-04-25

  • Use an inline isArray check, for ES3 browsers. (#27)
  • Some old browsers fail when an identifier is toString
  • Test latest node and io.js versions on travis-ci; speed up builds
  • Add license info to package.json (#25)
  • Update tape, jscs
  • Adding a CHANGELOG

2.0.0 / 2014-10-01

  • Increase code coverage to 100%; run code coverage as part of tests
  • Add npm run lint; Run linter as part of tests
  • Remove nodeType and setInterval checks in isPlainObject
  • Updating tape, jscs, covert
  • General style and README cleanup

1.3.0 / 2014-06-20

  • Add component.json for browser support (#18)
  • Use SVG for badges in README (#16)
  • Updating tape, covert
  • Updating travis-ci to work with multiple node versions
  • Fix deep === false bug (returning target as {}) (#14)
  • Fixing constructor checks in isPlainObject
  • Adding additional test coverage
  • Adding npm run coverage
  • Add LICENSE (#13)
  • Adding a warning about false, per #11
  • General style and whitespace cleanup

1.2.1 / 2013-09-14

  • Fixing hasOwnProperty bugs that would only have shown up in specific browsers. Fixes #8
  • Updating tape

1.2.0 / 2013-09-02

  • Updating the README: add badges
  • Adding a missing variable reference.
  • Using tape instead of buster for tests; add more tests (#7)
  • Adding node 0.10 to Travis CI (#6)
  • Enabling "npm test" and cleaning up package.json (#5)
  • Add Travis CI.

1.1.3 / 2012-12-06

  • Added unit tests.
  • Ensure extend function is named. (Looks nicer in a stack trace.)
  • README cleanup.

1.1.1 / 2012-11-07

  • README cleanup.
  • Added installation instructions.
  • Added a missing semicolon

1.0.0 / 2012-04-08

  • Initial commit
{
"name": "extend",
"author": "Stefan Thomas <justmoon@members.fsf.org> (http://www.justmoon.net)",
"version": "3.0.0",
"description": "Port of jQuery.extend for node.js and the browser.",
"scripts": [
"index.js"
],
"contributors": [
{
"name": "Jordan Harband",
"url": "https://github.com/ljharb"
}
],
"keywords": [
"extend",
"clone",
"merge"
],
"repository" : {
"type": "git",
"url": "https://github.com/justmoon/node-extend.git"
},
"dependencies": {
},
"devDependencies": {
"tape" : "~3.0.0",
"covert": "~0.4.0",
"jscs": "~1.6.2"
}
}
'use strict';
var hasOwn = Object.prototype.hasOwnProperty;
var toStr = Object.prototype.toString;
var isArray = function isArray(arr) {
if (typeof Array.isArray === 'function') {
return Array.isArray(arr);
}
return toStr.call(arr) === '[object Array]';
};
var isPlainObject = function isPlainObject(obj) {
if (!obj || toStr.call(obj) !== '[object Object]') {
return false;
}
var hasOwnConstructor = hasOwn.call(obj, 'constructor');
var hasIsPrototypeOf = obj.constructor && obj.constructor.prototype && hasOwn.call(obj.constructor.prototype, 'isPrototypeOf');
// Not own constructor property must be Object
if (obj.constructor && !hasOwnConstructor && !hasIsPrototypeOf) {
return false;
}
// Own properties are enumerated firstly, so to speed up,
// if last one is own, then all properties are own.
var key;
for (key in obj) {/**/}
return typeof key === 'undefined' || hasOwn.call(obj, key);
};
module.exports = function extend() {
var options, name, src, copy, copyIsArray, clone,
target = arguments[0],
i = 1,
length = arguments.length,
deep = false;
// Handle a deep copy situation
if (typeof target === 'boolean') {
deep = target;
target = arguments[1] || {};
// skip the boolean and the target
i = 2;
} else if ((typeof target !== 'object' && typeof target !== 'function') || target == null) {
target = {};
}
for (; i < length; ++i) {
options = arguments[i];
// Only deal with non-null/undefined values
if (options != null) {
// Extend the base object
for (name in options) {
src = target[name];
copy = options[name];
// Prevent never-ending loop
if (target !== copy) {
// Recurse if we're merging plain objects or arrays
if (deep && copy && (isPlainObject(copy) || (copyIsArray = isArray(copy)))) {
if (copyIsArray) {
copyIsArray = false;
clone = src && isArray(src) ? src : [];
} else {
clone = src && isPlainObject(src) ? src : {};
}
// Never move original objects, clone them
target[name] = extend(deep, clone, copy);
// Don't bring in undefined values
} else if (typeof copy !== 'undefined') {
target[name] = copy;
}
}
}
}
}
// Return the modified object
return target;
};
The MIT License (MIT)
Copyright (c) 2014 Stefan Thomas
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
{
"_args": [
[
{
"raw": "extend@~3.0.0",
"scope": null,
"escapedName": "extend",
"name": "extend",
"rawSpec": "~3.0.0",
"spec": ">=3.0.0 <3.1.0",
"type": "range"
},
"F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\request"
]
],
"_from": "extend@>=3.0.0 <3.1.0",
"_id": "extend@3.0.0",
"_inCache": true,
"_location": "/extend",
"_nodeVersion": "2.3.1",
"_npmUser": {
"name": "ljharb",
"email": "ljharb@gmail.com"
},
"_npmVersion": "2.11.3",
"_phantomChildren": {},
"_requested": {
"raw": "extend@~3.0.0",
"scope": null,
"escapedName": "extend",
"name": "extend",
"rawSpec": "~3.0.0",
"spec": ">=3.0.0 <3.1.0",
"type": "range"
},
"_requiredBy": [
"/request"
],
"_resolved": "https://registry.npmjs.org/extend/-/extend-3.0.0.tgz",
"_shasum": "5a474353b9f3353ddd8176dfd37b91c83a46f1d4",
"_shrinkwrap": null,
"_spec": "extend@~3.0.0",
"_where": "F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\request",
"author": {
"name": "Stefan Thomas",
"email": "justmoon@members.fsf.org",
"url": "http://www.justmoon.net"
},
"bugs": {
"url": "https://github.com/justmoon/node-extend/issues"
},
"contributors": [
{
"name": "Jordan Harband",
"url": "https://github.com/ljharb"
}
],
"dependencies": {},
"description": "Port of jQuery.extend for node.js and the browser",
"devDependencies": {
"covert": "^1.1.0",
"eslint": "^0.24.0",
"jscs": "^1.13.1",
"tape": "^4.0.0"
},
"directories": {},
"dist": {
"shasum": "5a474353b9f3353ddd8176dfd37b91c83a46f1d4",
"tarball": "https://registry.npmjs.org/extend/-/extend-3.0.0.tgz"
},
"gitHead": "148e7270cab2e9413af2cd0cab147070d755ed6d",
"homepage": "https://github.com/justmoon/node-extend#readme",
"keywords": [
"extend",
"clone",
"merge"
],
"license": "MIT",
"main": "index",
"maintainers": [
{
"name": "justmoon",
"email": "justmoon@members.fsf.org"
},
{
"name": "ljharb",
"email": "ljharb@gmail.com"
}
],
"name": "extend",
"optionalDependencies": {},
"readme": "ERROR: No README data found!",
"repository": {
"type": "git",
"url": "git+https://github.com/justmoon/node-extend.git"
},
"scripts": {
"coverage": "covert test/index.js",
"coverage-quiet": "covert test/index.js --quiet",
"eslint": "eslint *.js */*.js",
"jscs": "jscs *.js */*.js",
"lint": "npm run jscs && npm run eslint",
"test": "npm run lint && node test/index.js && npm run coverage-quiet"
},
"version": "3.0.0"
}

Build Status dependency status dev dependency status

extend() for Node.js Version Badge

node-extend is a port of the classic extend() method from jQuery. It behaves as you expect. It is simple, tried and true.

Installation

This package is available on npm as: extend

npm install extend

Usage

Syntax: extend ( [deep], target, object1, [objectN] )

Extend one object with one or more others, returning the modified object.

Keep in mind that the target object will be modified, and will be returned from extend().

If a boolean true is specified as the first argument, extend performs a deep copy, recursively copying any objects it finds. Otherwise, the copy will share structure with the original object(s). Undefined properties are not copied. However, properties inherited from the object's prototype will be copied over. Warning: passing false as the first argument is not supported.

Arguments

  • deep Boolean (optional) If set, the merge becomes recursive (i.e. deep copy).
  • target Object The object to extend.
  • object1 Object The object that will be merged into the first.
  • objectN Object (Optional) More objects to merge into the first.

License

node-extend is licensed under the MIT License.

Acknowledgements

All credit to the jQuery authors for perfecting this amazing utility.

Ported to Node.js by Stefan Thomas with contributions by Jonathan Buchanan and Jordan Harband.

[submodule "deps/jsstyle"]
path = deps/jsstyle
url = git://github.com/davepacheco/jsstyle
[submodule "deps/javascriptlint"]
path = deps/javascriptlint
url = git://github.com/davepacheco/javascriptlint
var mod_extsprintf = require('extsprintf');
console.log(mod_extsprintf.sprintf('hello %25s', 'world'));
#
# Configuration File for JavaScript Lint
#
# This configuration file can be used to lint a collection of scripts, or to enable
# or disable warnings for scripts that are linted via the command line.
#
### Warnings
# Enable or disable warnings based on requirements.
# Use "+WarningName" to display or "-WarningName" to suppress.
#
+ambiguous_else_stmt # the else statement could be matched with one of multiple if statements (use curly braces to indicate intent
+ambiguous_nested_stmt # block statements containing block statements should use curly braces to resolve ambiguity
+ambiguous_newline # unexpected end of line; it is ambiguous whether these lines are part of the same statement
+anon_no_return_value # anonymous function does not always return value
+assign_to_function_call # assignment to a function call
-block_without_braces # block statement without curly braces
+comma_separated_stmts # multiple statements separated by commas (use semicolons?)
+comparison_type_conv # comparisons against null, 0, true, false, or an empty string allowing implicit type conversion (use === or !==)
+default_not_at_end # the default case is not at the end of the switch statement
+dup_option_explicit # duplicate "option explicit" control comment
+duplicate_case_in_switch # duplicate case in switch statement
+duplicate_formal # duplicate formal argument {name}
+empty_statement # empty statement or extra semicolon
+identifier_hides_another # identifer {name} hides an identifier in a parent scope
-inc_dec_within_stmt # increment (++) and decrement (--) operators used as part of greater statement
+incorrect_version # Expected /*jsl:content-type*/ control comment. The script was parsed with the wrong version.
+invalid_fallthru # unexpected "fallthru" control comment
+invalid_pass # unexpected "pass" control comment
+jsl_cc_not_understood # couldn't understand control comment using /*jsl:keyword*/ syntax
+leading_decimal_point # leading decimal point may indicate a number or an object member
+legacy_cc_not_understood # couldn't understand control comment using /*@keyword@*/ syntax
+meaningless_block # meaningless block; curly braces have no impact
+mismatch_ctrl_comments # mismatched control comment; "ignore" and "end" control comments must have a one-to-one correspondence
+misplaced_regex # regular expressions should be preceded by a left parenthesis, assignment, colon, or comma
+missing_break # missing break statement
+missing_break_for_last_case # missing break statement for last case in switch
+missing_default_case # missing default case in switch statement
+missing_option_explicit # the "option explicit" control comment is missing
+missing_semicolon # missing semicolon
+missing_semicolon_for_lambda # missing semicolon for lambda assignment
+multiple_plus_minus # unknown order of operations for successive plus (e.g. x+++y) or minus (e.g. x---y) signs
+nested_comment # nested comment
+no_return_value # function {name} does not always return a value
+octal_number # leading zeros make an octal number
+parseint_missing_radix # parseInt missing radix parameter
+partial_option_explicit # the "option explicit" control comment, if used, must be in the first script tag
+redeclared_var # redeclaration of {name}
+trailing_comma_in_array # extra comma is not recommended in array initializers
+trailing_decimal_point # trailing decimal point may indicate a number or an object member
+undeclared_identifier # undeclared identifier: {name}
+unreachable_code # unreachable code
-unreferenced_argument # argument declared but never referenced: {name}
-unreferenced_function # function is declared but never referenced: {name}
+unreferenced_variable # variable is declared but never referenced: {name}
+unsupported_version # JavaScript {version} is not supported
+use_of_label # use of label
+useless_assign # useless assignment
+useless_comparison # useless comparison; comparing identical expressions
-useless_quotes # the quotation marks are unnecessary
+useless_void # use of the void type may be unnecessary (void is always undefined)
+var_hides_arg # variable {name} hides argument
+want_assign_or_call # expected an assignment or function call
+with_statement # with statement hides undeclared variables; use temporary variable instead
### Output format
# Customize the format of the error message.
# __FILE__ indicates current file path
# __FILENAME__ indicates current file name
# __LINE__ indicates current line
# __COL__ indicates current column
# __ERROR__ indicates error message (__ERROR_PREFIX__: __ERROR_MSG__)
# __ERROR_NAME__ indicates error name (used in configuration file)
# __ERROR_PREFIX__ indicates error prefix
# __ERROR_MSG__ indicates error message
#
# For machine-friendly output, the output format can be prefixed with
# "encode:". If specified, all items will be encoded with C-slashes.
#
# Visual Studio syntax (default):
+output-format __FILE__(__LINE__): __ERROR__
# Alternative syntax:
#+output-format __FILE__:__LINE__: __ERROR__
### Context
# Show the in-line position of the error.
# Use "+context" to display or "-context" to suppress.
#
+context
### Control Comments
# Both JavaScript Lint and the JScript interpreter confuse each other with the syntax for
# the /*@keyword@*/ control comments and JScript conditional comments. (The latter is
# enabled in JScript with @cc_on@). The /*jsl:keyword*/ syntax is preferred for this reason,
# although legacy control comments are enabled by default for backward compatibility.
#
-legacy_control_comments
### Defining identifiers
# By default, "option explicit" is enabled on a per-file basis.
# To enable this for all files, use "+always_use_option_explicit"
-always_use_option_explicit
# Define certain identifiers of which the lint is not aware.
# (Use this in conjunction with the "undeclared identifier" warning.)
#
# Common uses for webpages might be:
+define __dirname
+define clearInterval
+define clearTimeout
+define console
+define exports
+define global
+define process
+define require
+define setInterval
+define setTimeout
+define Buffer
+define JSON
+define Math
### JavaScript Version
# To change the default JavaScript version:
#+default-type text/javascript;version=1.5
#+default-type text/javascript;e4x=1
### Files
# Specify which files to lint
# Use "+recurse" to enable recursion (disabled by default).
# To add a set of files, use "+process FileName", "+process Folder\Path\*.js",
# or "+process Folder\Path\*.htm".
#
/*
* extsprintf.js: extended POSIX-style sprintf
*/
var mod_assert = require('assert');
var mod_util = require('util');
/*
* Public interface
*/
exports.sprintf = jsSprintf;
/*
* Stripped down version of s[n]printf(3c). We make a best effort to throw an
* exception when given a format string we don't understand, rather than
* ignoring it, so that we won't break existing programs if/when we go implement
* the rest of this.
*
* This implementation currently supports specifying
* - field alignment ('-' flag),
* - zero-pad ('0' flag)
* - always show numeric sign ('+' flag),
* - field width
* - conversions for strings, decimal integers, and floats (numbers).
* - argument size specifiers. These are all accepted but ignored, since
* Javascript has no notion of the physical size of an argument.
*
* Everything else is currently unsupported, most notably precision, unsigned
* numbers, non-decimal numbers, and characters.
*/
function jsSprintf(fmt)
{
var regex = [
'([^%]*)', /* normal text */
'%', /* start of format */
'([\'\\-+ #0]*?)', /* flags (optional) */
'([1-9]\\d*)?', /* width (optional) */
'(\\.([1-9]\\d*))?', /* precision (optional) */
'[lhjztL]*?', /* length mods (ignored) */
'([diouxXfFeEgGaAcCsSp%jr])' /* conversion */
].join('');
var re = new RegExp(regex);
var args = Array.prototype.slice.call(arguments, 1);
var flags, width, precision, conversion;
var left, pad, sign, arg, match;
var ret = '';
var argn = 1;
mod_assert.equal('string', typeof (fmt));
while ((match = re.exec(fmt)) !== null) {
ret += match[1];
fmt = fmt.substring(match[0].length);
flags = match[2] || '';
width = match[3] || 0;
precision = match[4] || '';
conversion = match[6];
left = false;
sign = false;
pad = ' ';
if (conversion == '%') {
ret += '%';
continue;
}
if (args.length === 0)
throw (new Error('too few args to sprintf'));
arg = args.shift();
argn++;
if (flags.match(/[\' #]/))
throw (new Error(
'unsupported flags: ' + flags));
if (precision.length > 0)
throw (new Error(
'non-zero precision not supported'));
if (flags.match(/-/))
left = true;
if (flags.match(/0/))
pad = '0';
if (flags.match(/\+/))
sign = true;
switch (conversion) {
case 's':
if (arg === undefined || arg === null)
throw (new Error('argument ' + argn +
': attempted to print undefined or null ' +
'as a string'));
ret += doPad(pad, width, left, arg.toString());
break;
case 'd':
arg = Math.floor(arg);
/*jsl:fallthru*/
case 'f':
sign = sign && arg > 0 ? '+' : '';
ret += sign + doPad(pad, width, left,
arg.toString());
break;
case 'j': /* non-standard */
if (width === 0)
width = 10;
ret += mod_util.inspect(arg, false, width);
break;
case 'r': /* non-standard */
ret += dumpException(arg);
break;
default:
throw (new Error('unsupported conversion: ' +
conversion));
}
}
ret += fmt;
return (ret);
}
function doPad(chr, width, left, str)
{
var ret = str;
while (ret.length < width) {
if (left)
ret += chr;
else
ret = chr + ret;
}
return (ret);
}
/*
* This function dumps long stack traces for exceptions having a cause() method.
* See node-verror for an example.
*/
function dumpException(ex)
{
var ret;
if (!(ex instanceof Error))
throw (new Error(jsSprintf('invalid type for %%r: %j', ex)));
/* Note that V8 prepends "ex.stack" with ex.toString(). */
ret = 'EXCEPTION: ' + ex.constructor.name + ': ' + ex.stack;
if (ex.cause && typeof (ex.cause) === 'function') {
var cex = ex.cause();
if (cex) {
ret += '\nCaused by: ' + dumpException(cex);
}
}
return (ret);
}
Copyright (c) 2012, Joyent, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE
#
# Copyright (c) 2012, Joyent, Inc. All rights reserved.
#
# Makefile: top-level Makefile
#
# This Makefile contains only repo-specific logic and uses included makefiles
# to supply common targets (javascriptlint, jsstyle, restdown, etc.), which are
# used by other repos as well.
#
#
# Files
#
JS_FILES := $(shell find lib -name '*.js')
JSL_FILES_NODE = $(JS_FILES)
JSSTYLE_FILES = $(JS_FILES)
JSL_CONF_NODE = jsl.node.conf
# Default target is "check"
check:
include ./Makefile.deps
include ./Makefile.targ
# -*- mode: makefile -*-
#
# Copyright (c) 2012, Joyent, Inc. All rights reserved.
#
# Makefile.deps: Makefile for including common tools as dependencies
#
# NOTE: This makefile comes from the "eng" repo. It's designed to be dropped
# into other repos as-is without requiring any modifications. If you find
# yourself changing this file, you should instead update the original copy in
# eng.git and then update your repo to use the new version.
#
# This file is separate from Makefile.targ so that teams can choose
# independently whether to use the common targets in Makefile.targ and the
# common tools here.
#
#
# javascriptlint
#
JSL_EXEC ?= deps/javascriptlint/build/install/jsl
JSL ?= python2.6 $(JSL_EXEC)
$(JSL_EXEC): | deps/javascriptlint/.git
cd deps/javascriptlint && make install
#
# jsstyle
#
JSSTYLE_EXEC ?= deps/jsstyle/jsstyle
JSSTYLE ?= $(JSSTYLE_EXEC)
$(JSSTYLE_EXEC): | deps/jsstyle/.git
#
# restdown
#
RESTDOWN_EXEC ?= deps/restdown/bin/restdown
RESTDOWN ?= python2.6 $(RESTDOWN_EXEC)
$(RESTDOWN_EXEC): | deps/restdown/.git
# -*- mode: makefile -*-
#
# Copyright (c) 2012, Joyent, Inc. All rights reserved.
#
# Makefile.targ: common targets.
#
# NOTE: This makefile comes from the "eng" repo. It's designed to be dropped
# into other repos as-is without requiring any modifications. If you find
# yourself changing this file, you should instead update the original copy in
# eng.git and then update your repo to use the new version.
#
# This Makefile defines several useful targets and rules. You can use it by
# including it from a Makefile that specifies some of the variables below.
#
# Targets defined in this Makefile:
#
# check Checks JavaScript files for lint and style
# Checks bash scripts for syntax
# Checks SMF manifests for validity against the SMF DTD
#
# clean Removes built files
#
# docs Builds restdown documentation in docs/
#
# prepush Depends on "check" and "test"
#
# test Does nothing (you should override this)
#
# xref Generates cscope (source cross-reference index)
#
# For details on what these targets are supposed to do, see the Joyent
# Engineering Guide.
#
# To make use of these targets, you'll need to set some of these variables. Any
# variables left unset will simply not be used.
#
# BASH_FILES Bash scripts to check for syntax
# (paths relative to top-level Makefile)
#
# CLEAN_FILES Files to remove as part of the "clean" target. Note
# that files generated by targets in this Makefile are
# automatically included in CLEAN_FILES. These include
# restdown-generated HTML and JSON files.
#
# DOC_FILES Restdown (documentation source) files. These are
# assumed to be contained in "docs/", and must NOT
# contain the "docs/" prefix.
#
# JSL_CONF_NODE Specify JavaScriptLint configuration files
# JSL_CONF_WEB (paths relative to top-level Makefile)
#
# Node.js and Web configuration files are separate
# because you'll usually want different global variable
# configurations. If no file is specified, none is given
# to jsl, which causes it to use a default configuration,
# which probably isn't what you want.
#
# JSL_FILES_NODE JavaScript files to check with Node config file.
# JSL_FILES_WEB JavaScript files to check with Web config file.
#
# You can also override these variables:
#
# BASH Path to bash (default: bash)
#
# CSCOPE_DIRS Directories to search for source files for the cscope
# index. (default: ".")
#
# JSL Path to JavaScriptLint (default: "jsl")
#
# JSL_FLAGS_NODE Additional flags to pass through to JSL
# JSL_FLAGS_WEB
# JSL_FLAGS
#
# JSSTYLE Path to jsstyle (default: jsstyle)
#
# JSSTYLE_FLAGS Additional flags to pass through to jsstyle
#
#
# Defaults for the various tools we use.
#
BASH ?= bash
BASHSTYLE ?= tools/bashstyle
CP ?= cp
CSCOPE ?= cscope
CSCOPE_DIRS ?= .
JSL ?= jsl
JSSTYLE ?= jsstyle
MKDIR ?= mkdir -p
MV ?= mv
RESTDOWN_FLAGS ?=
RMTREE ?= rm -rf
JSL_FLAGS ?= --nologo --nosummary
ifeq ($(shell uname -s),SunOS)
TAR ?= gtar
else
TAR ?= tar
endif
#
# Defaults for other fixed values.
#
BUILD = build
DISTCLEAN_FILES += $(BUILD)
DOC_BUILD = $(BUILD)/docs/public
#
# Configure JSL_FLAGS_{NODE,WEB} based on JSL_CONF_{NODE,WEB}.
#
ifneq ($(origin JSL_CONF_NODE), undefined)
JSL_FLAGS_NODE += --conf=$(JSL_CONF_NODE)
endif
ifneq ($(origin JSL_CONF_WEB), undefined)
JSL_FLAGS_WEB += --conf=$(JSL_CONF_WEB)
endif
#
# Targets. For descriptions on what these are supposed to do, see the
# Joyent Engineering Guide.
#
#
# Instruct make to keep around temporary files. We have rules below that
# automatically update git submodules as needed, but they employ a deps/*/.git
# temporary file. Without this directive, make tries to remove these .git
# directories after the build has completed.
#
.SECONDARY: $($(wildcard deps/*):%=%/.git)
#
# This rule enables other rules that use files from a git submodule to have
# those files depend on deps/module/.git and have "make" automatically check
# out the submodule as needed.
#
deps/%/.git:
git submodule update --init deps/$*
#
# These recipes make heavy use of dynamically-created phony targets. The parent
# Makefile defines a list of input files like BASH_FILES. We then say that each
# of these files depends on a fake target called filename.bashchk, and then we
# define a pattern rule for those targets that runs bash in check-syntax-only
# mode. This mechanism has the nice properties that if you specify zero files,
# the rule becomes a noop (unlike a single rule to check all bash files, which
# would invoke bash with zero files), and you can check individual files from
# the command line with "make filename.bashchk".
#
.PHONY: check-bash
check-bash: $(BASH_FILES:%=%.bashchk) $(BASH_FILES:%=%.bashstyle)
%.bashchk: %
$(BASH) -n $^
%.bashstyle: %
$(BASHSTYLE) $^
.PHONY: check-jsl check-jsl-node check-jsl-web
check-jsl: check-jsl-node check-jsl-web
check-jsl-node: $(JSL_FILES_NODE:%=%.jslnodechk)
check-jsl-web: $(JSL_FILES_WEB:%=%.jslwebchk)
%.jslnodechk: % $(JSL_EXEC)
$(JSL) $(JSL_FLAGS) $(JSL_FLAGS_NODE) $<
%.jslwebchk: % $(JSL_EXEC)
$(JSL) $(JSL_FLAGS) $(JSL_FLAGS_WEB) $<
.PHONY: check-jsstyle
check-jsstyle: $(JSSTYLE_FILES:%=%.jsstylechk)
%.jsstylechk: % $(JSSTYLE_EXEC)
$(JSSTYLE) $(JSSTYLE_FLAGS) $<
.PHONY: check
check: check-jsl check-jsstyle check-bash
@echo check ok
.PHONY: clean
clean::
-$(RMTREE) $(CLEAN_FILES)
.PHONY: distclean
distclean:: clean
-$(RMTREE) $(DISTCLEAN_FILES)
CSCOPE_FILES = cscope.in.out cscope.out cscope.po.out
CLEAN_FILES += $(CSCOPE_FILES)
.PHONY: xref
xref: cscope.files
$(CSCOPE) -bqR
.PHONY: cscope.files
cscope.files:
find $(CSCOPE_DIRS) -name '*.c' -o -name '*.h' -o -name '*.cc' \
-o -name '*.js' -o -name '*.s' -o -name '*.cpp' > $@
#
# The "docs" target is complicated because we do several things here:
#
# (1) Use restdown to build HTML and JSON files from each of DOC_FILES.
#
# (2) Copy these files into $(DOC_BUILD) (build/docs/public), which
# functions as a complete copy of the documentation that could be
# mirrored or served over HTTP.
#
# (3) Then copy any directories and media from docs/media into
# $(DOC_BUILD)/media. This allows projects to include their own media,
# including files that will override same-named files provided by
# restdown.
#
# Step (3) is the surprisingly complex part: in order to do this, we need to
# identify the subdirectories in docs/media, recreate them in
# $(DOC_BUILD)/media, then do the same with the files.
#
DOC_MEDIA_DIRS := $(shell find docs/media -type d 2>/dev/null | grep -v "^docs/media$$")
DOC_MEDIA_DIRS := $(DOC_MEDIA_DIRS:docs/media/%=%)
DOC_MEDIA_DIRS_BUILD := $(DOC_MEDIA_DIRS:%=$(DOC_BUILD)/media/%)
DOC_MEDIA_FILES := $(shell find docs/media -type f 2>/dev/null)
DOC_MEDIA_FILES := $(DOC_MEDIA_FILES:docs/media/%=%)
DOC_MEDIA_FILES_BUILD := $(DOC_MEDIA_FILES:%=$(DOC_BUILD)/media/%)
#
# Like the other targets, "docs" just depends on the final files we want to
# create in $(DOC_BUILD), leveraging other targets and recipes to define how
# to get there.
#
.PHONY: docs
docs: \
$(DOC_FILES:%.restdown=$(DOC_BUILD)/%.html) \
$(DOC_FILES:%.restdown=$(DOC_BUILD)/%.json) \
$(DOC_MEDIA_FILES_BUILD)
#
# We keep the intermediate files so that the next build can see whether the
# files in DOC_BUILD are up to date.
#
.PRECIOUS: \
$(DOC_FILES:%.restdown=docs/%.html) \
$(DOC_FILES:%.restdown=docs/%json)
#
# We do clean those intermediate files, as well as all of DOC_BUILD.
#
CLEAN_FILES += \
$(DOC_BUILD) \
$(DOC_FILES:%.restdown=docs/%.html) \
$(DOC_FILES:%.restdown=docs/%.json)
#
# Before installing the files, we must make sure the directories exist. The |
# syntax tells make that the dependency need only exist, not be up to date.
# Otherwise, it might try to rebuild spuriously because the directory itself
# appears out of date.
#
$(DOC_MEDIA_FILES_BUILD): | $(DOC_MEDIA_DIRS_BUILD)
$(DOC_BUILD)/%: docs/% | $(DOC_BUILD)
$(CP) $< $@
docs/%.json docs/%.html: docs/%.restdown | $(DOC_BUILD) $(RESTDOWN_EXEC)
$(RESTDOWN) $(RESTDOWN_FLAGS) -m $(DOC_BUILD) $<
$(DOC_BUILD):
$(MKDIR) $@
$(DOC_MEDIA_DIRS_BUILD):
$(MKDIR) $@
#
# The default "test" target does nothing. This should usually be overridden by
# the parent Makefile. It's included here so we can define "prepush" without
# requiring the repo to define "test".
#
.PHONY: test
test:
.PHONY: prepush
prepush: check test
{
"_args": [
[
{
"raw": "extsprintf@1.0.2",
"scope": null,
"escapedName": "extsprintf",
"name": "extsprintf",
"rawSpec": "1.0.2",
"spec": "1.0.2",
"type": "version"
},
"F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\jsprim"
]
],
"_from": "extsprintf@1.0.2",
"_id": "extsprintf@1.0.2",
"_inCache": true,
"_location": "/extsprintf",
"_npmUser": {
"name": "dap",
"email": "dap@cs.brown.edu"
},
"_npmVersion": "1.1.65",
"_phantomChildren": {},
"_requested": {
"raw": "extsprintf@1.0.2",
"scope": null,
"escapedName": "extsprintf",
"name": "extsprintf",
"rawSpec": "1.0.2",
"spec": "1.0.2",
"type": "version"
},
"_requiredBy": [
"/jsprim",
"/verror"
],
"_resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz",
"_shasum": "e1080e0658e300b06294990cc70e1502235fd550",
"_shrinkwrap": null,
"_spec": "extsprintf@1.0.2",
"_where": "F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\jsprim",
"bugs": {
"url": "https://github.com/davepacheco/node-extsprintf/issues"
},
"dependencies": {},
"description": "extended POSIX-style sprintf",
"devDependencies": {},
"directories": {},
"dist": {
"shasum": "e1080e0658e300b06294990cc70e1502235fd550",
"tarball": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz"
},
"engines": [
"node >=0.6.0"
],
"homepage": "https://github.com/davepacheco/node-extsprintf#readme",
"main": "./lib/extsprintf.js",
"maintainers": [
{
"name": "dap",
"email": "dap@cs.brown.edu"
}
],
"name": "extsprintf",
"optionalDependencies": {},
"readme": "ERROR: No README data found!",
"repository": {
"type": "git",
"url": "git://github.com/davepacheco/node-extsprintf.git"
},
"version": "1.0.2"
}

extsprintf: extended POSIX-style sprintf

Stripped down version of s[n]printf(3c). We make a best effort to throw an exception when given a format string we don't understand, rather than ignoring it, so that we won't break existing programs if/when we go implement the rest of this.

This implementation currently supports specifying

  • field alignment ('-' flag),
  • zero-pad ('0' flag)
  • always show numeric sign ('+' flag),
  • field width
  • conversions for strings, decimal integers, and floats (numbers).
  • argument size specifiers. These are all accepted but ignored, since Javascript has no notion of the physical size of an argument.

Everything else is currently unsupported, most notably: precision, unsigned numbers, non-decimal numbers, and characters.

Besides the usual POSIX conversions, this implementation supports:

  • %j: pretty-print a JSON object (using node's "inspect")
  • %r: pretty-print an Error object

Example

First, install it:

# npm install extsprintf

Now, use it:

var mod_extsprintf = require('extsprintf');
console.log(mod_extsprintf.sprintf('hello %25s', 'world'));

outputs:

hello                     world
module.exports = ForeverAgent
ForeverAgent.SSL = ForeverAgentSSL
var util = require('util')
, Agent = require('http').Agent
, net = require('net')
, tls = require('tls')
, AgentSSL = require('https').Agent
function getConnectionName(host, port) {
var name = ''
if (typeof host === 'string') {
name = host + ':' + port
} else {
// For node.js v012.0 and iojs-v1.5.1, host is an object. And any existing localAddress is part of the connection name.
name = host.host + ':' + host.port + ':' + (host.localAddress ? (host.localAddress + ':') : ':')
}
return name
}
function ForeverAgent(options) {
var self = this
self.options = options || {}
self.requests = {}
self.sockets = {}
self.freeSockets = {}
self.maxSockets = self.options.maxSockets || Agent.defaultMaxSockets
self.minSockets = self.options.minSockets || ForeverAgent.defaultMinSockets
self.on('free', function(socket, host, port) {
var name = getConnectionName(host, port)
if (self.requests[name] && self.requests[name].length) {
self.requests[name].shift().onSocket(socket)
} else if (self.sockets[name].length < self.minSockets) {
if (!self.freeSockets[name]) self.freeSockets[name] = []
self.freeSockets[name].push(socket)
// if an error happens while we don't use the socket anyway, meh, throw the socket away
var onIdleError = function() {
socket.destroy()
}
socket._onIdleError = onIdleError
socket.on('error', onIdleError)
} else {
// If there are no pending requests just destroy the
// socket and it will get removed from the pool. This
// gets us out of timeout issues and allows us to
// default to Connection:keep-alive.
socket.destroy()
}
})
}
util.inherits(ForeverAgent, Agent)
ForeverAgent.defaultMinSockets = 5
ForeverAgent.prototype.createConnection = net.createConnection
ForeverAgent.prototype.addRequestNoreuse = Agent.prototype.addRequest
ForeverAgent.prototype.addRequest = function(req, host, port) {
var name = getConnectionName(host, port)
if (typeof host !== 'string') {
var options = host
port = options.port
host = options.host
}
if (this.freeSockets[name] && this.freeSockets[name].length > 0 && !req.useChunkedEncodingByDefault) {
var idleSocket = this.freeSockets[name].pop()
idleSocket.removeListener('error', idleSocket._onIdleError)
delete idleSocket._onIdleError
req._reusedSocket = true
req.onSocket(idleSocket)
} else {
this.addRequestNoreuse(req, host, port)
}
}
ForeverAgent.prototype.removeSocket = function(s, name, host, port) {
if (this.sockets[name]) {
var index = this.sockets[name].indexOf(s)
if (index !== -1) {
this.sockets[name].splice(index, 1)
}
} else if (this.sockets[name] && this.sockets[name].length === 0) {
// don't leak
delete this.sockets[name]
delete this.requests[name]
}
if (this.freeSockets[name]) {
var index = this.freeSockets[name].indexOf(s)
if (index !== -1) {
this.freeSockets[name].splice(index, 1)
if (this.freeSockets[name].length === 0) {
delete this.freeSockets[name]
}
}
}
if (this.requests[name] && this.requests[name].length) {
// If we have pending requests and a socket gets closed a new one
// needs to be created to take over in the pool for the one that closed.
this.createSocket(name, host, port).emit('free')
}
}
function ForeverAgentSSL (options) {
ForeverAgent.call(this, options)
}
util.inherits(ForeverAgentSSL, ForeverAgent)
ForeverAgentSSL.prototype.createConnection = createConnectionSSL
ForeverAgentSSL.prototype.addRequestNoreuse = AgentSSL.prototype.addRequest
function createConnectionSSL (port, host, options) {
if (typeof port === 'object') {
options = port;
} else if (typeof host === 'object') {
options = host;
} else if (typeof options === 'object') {
options = options;
} else {
options = {};
}
if (typeof port === 'number') {
options.port = port;
}
if (typeof host === 'string') {
options.host = host;
}
return tls.connect(options);
}
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
You must give any other recipients of the Work or Derivative Works a copy of this License; and
You must cause any modified files to carry prominent notices stating that You changed the files; and
You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
{
"_args": [
[
{
"raw": "forever-agent@~0.6.1",
"scope": null,
"escapedName": "forever-agent",
"name": "forever-agent",
"rawSpec": "~0.6.1",
"spec": ">=0.6.1 <0.7.0",
"type": "range"
},
"F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\request"
]
],
"_from": "forever-agent@>=0.6.1 <0.7.0",
"_id": "forever-agent@0.6.1",
"_inCache": true,
"_location": "/forever-agent",
"_npmUser": {
"name": "simov",
"email": "simeonvelichkov@gmail.com"
},
"_npmVersion": "1.4.28",
"_phantomChildren": {},
"_requested": {
"raw": "forever-agent@~0.6.1",
"scope": null,
"escapedName": "forever-agent",
"name": "forever-agent",
"rawSpec": "~0.6.1",
"spec": ">=0.6.1 <0.7.0",
"type": "range"
},
"_requiredBy": [
"/request"
],
"_resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
"_shasum": "fbc71f0c41adeb37f96c577ad1ed42d8fdacca91",
"_shrinkwrap": null,
"_spec": "forever-agent@~0.6.1",
"_where": "F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\request",
"author": {
"name": "Mikeal Rogers",
"email": "mikeal.rogers@gmail.com",
"url": "http://www.futurealoof.com"
},
"bugs": {
"url": "https://github.com/mikeal/forever-agent/issues"
},
"dependencies": {},
"description": "HTTP Agent that keeps socket connections alive between keep-alive requests. Formerly part of mikeal/request, now a standalone module.",
"devDependencies": {},
"directories": {},
"dist": {
"shasum": "fbc71f0c41adeb37f96c577ad1ed42d8fdacca91",
"tarball": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz"
},
"engines": {
"node": "*"
},
"gitHead": "1b3b6163f2b3c2c4122bbfa288c1325c0df9871d",
"homepage": "https://github.com/mikeal/forever-agent",
"license": "Apache-2.0",
"main": "index.js",
"maintainers": [
{
"name": "mikeal",
"email": "mikeal.rogers@gmail.com"
},
{
"name": "nylen",
"email": "jnylen@gmail.com"
},
{
"name": "simov",
"email": "simeonvelichkov@gmail.com"
}
],
"name": "forever-agent",
"optionalDependencies": {},
"readme": "ERROR: No README data found!",
"repository": {
"url": "git+https://github.com/mikeal/forever-agent.git"
},
"scripts": {},
"version": "0.6.1"
}

forever-agent

HTTP Agent that keeps socket connections alive between keep-alive requests. Formerly part of mikeal/request, now a standalone module.

/* eslint-env browser */
module.exports = typeof self == 'object' ? self.FormData : window.FormData;
var CombinedStream = require('combined-stream');
var util = require('util');
var path = require('path');
var http = require('http');
var https = require('https');
var parseUrl = require('url').parse;
var fs = require('fs');
var mime = require('mime-types');
var asynckit = require('asynckit');
var populate = require('./populate.js');
// Public API
module.exports = FormData;
// make it a Stream
util.inherits(FormData, CombinedStream);
/**
* Create readable "multipart/form-data" streams.
* Can be used to submit forms
* and file uploads to other web applications.
*
* @constructor
*/
function FormData() {
if (!(this instanceof FormData)) {
return new FormData();
}
this._overheadLength = 0;
this._valueLength = 0;
this._valuesToMeasure = [];
CombinedStream.call(this);
}
FormData.LINE_BREAK = '\r\n';
FormData.DEFAULT_CONTENT_TYPE = 'application/octet-stream';
FormData.prototype.append = function(field, value, options) {
options = options || {};
// allow filename as single option
if (typeof options == 'string') {
options = {filename: options};
}
var append = CombinedStream.prototype.append.bind(this);
// all that streamy business can't handle numbers
if (typeof value == 'number') {
value = '' + value;
}
// https://github.com/felixge/node-form-data/issues/38
if (util.isArray(value)) {
// Please convert your array into string
// the way web server expects it
this._error(new Error('Arrays are not supported.'));
return;
}
var header = this._multiPartHeader(field, value, options);
var footer = this._multiPartFooter();
append(header);
append(value);
append(footer);
// pass along options.knownLength
this._trackLength(header, value, options);
};
FormData.prototype._trackLength = function(header, value, options) {
var valueLength = 0;
// used w/ getLengthSync(), when length is known.
// e.g. for streaming directly from a remote server,
// w/ a known file a size, and not wanting to wait for
// incoming file to finish to get its size.
if (options.knownLength != null) {
valueLength += +options.knownLength;
} else if (Buffer.isBuffer(value)) {
valueLength = value.length;
} else if (typeof value === 'string') {
valueLength = Buffer.byteLength(value);
}
this._valueLength += valueLength;
// @check why add CRLF? does this account for custom/multiple CRLFs?
this._overheadLength +=
Buffer.byteLength(header) +
FormData.LINE_BREAK.length;
// empty or either doesn't have path or not an http response
if (!value || ( !value.path && !(value.readable && value.hasOwnProperty('httpVersion')) )) {
return;
}
// no need to bother with the length
if (!options.knownLength) {
this._valuesToMeasure.push(value);
}
};
FormData.prototype._lengthRetriever = function(value, callback) {
if (value.hasOwnProperty('fd')) {
// take read range into a account
// `end` = Infinity –> read file till the end
//
// TODO: Looks like there is bug in Node fs.createReadStream
// it doesn't respect `end` options without `start` options
// Fix it when node fixes it.
// https://github.com/joyent/node/issues/7819
if (value.end != undefined && value.end != Infinity && value.start != undefined) {
// when end specified
// no need to calculate range
// inclusive, starts with 0
callback(null, value.end + 1 - (value.start ? value.start : 0));
// not that fast snoopy
} else {
// still need to fetch file size from fs
fs.stat(value.path, function(err, stat) {
var fileSize;
if (err) {
callback(err);
return;
}
// update final size based on the range options
fileSize = stat.size - (value.start ? value.start : 0);
callback(null, fileSize);
});
}
// or http response
} else if (value.hasOwnProperty('httpVersion')) {
callback(null, +value.headers['content-length']);
// or request stream http://github.com/mikeal/request
} else if (value.hasOwnProperty('httpModule')) {
// wait till response come back
value.on('response', function(response) {
value.pause();
callback(null, +response.headers['content-length']);
});
value.resume();
// something else
} else {
callback('Unknown stream');
}
};
FormData.prototype._multiPartHeader = function(field, value, options) {
// custom header specified (as string)?
// it becomes responsible for boundary
// (e.g. to handle extra CRLFs on .NET servers)
if (typeof options.header == 'string') {
return options.header;
}
var contentDisposition = this._getContentDisposition(value, options);
var contentType = this._getContentType(value, options);
var contents = '';
var headers = {
// add custom disposition as third element or keep it two elements if not
'Content-Disposition': ['form-data', 'name="' + field + '"'].concat(contentDisposition || []),
// if no content type. allow it to be empty array
'Content-Type': [].concat(contentType || [])
};
// allow custom headers.
if (typeof options.header == 'object') {
populate(headers, options.header);
}
var header;
for (var prop in headers) {
header = headers[prop];
// skip nullish headers.
if (header == null) {
continue;
}
// convert all headers to arrays.
if (!Array.isArray(header)) {
header = [header];
}
// add non-empty headers.
if (header.length) {
contents += prop + ': ' + header.join('; ') + FormData.LINE_BREAK;
}
}
return '--' + this.getBoundary() + FormData.LINE_BREAK + contents + FormData.LINE_BREAK;
};
FormData.prototype._getContentDisposition = function(value, options) {
var contentDisposition;
// custom filename takes precedence
// fs- and request- streams have path property
// formidable and the browser add a name property.
var filename = options.filename || value.name || value.path;
// or try http response
if (!filename && value.readable && value.hasOwnProperty('httpVersion')) {
filename = value.client._httpMessage.path;
}
if (filename) {
contentDisposition = 'filename="' + path.basename(filename) + '"';
}
return contentDisposition;
};
FormData.prototype._getContentType = function(value, options) {
// use custom content-type above all
var contentType = options.contentType;
// or try `name` from formidable, browser
if (!contentType && value.name) {
contentType = mime.lookup(value.name);
}
// or try `path` from fs-, request- streams
if (!contentType && value.path) {
contentType = mime.lookup(value.path);
}
// or if it's http-reponse
if (!contentType && value.readable && value.hasOwnProperty('httpVersion')) {
contentType = value.headers['content-type'];
}
// or guess it from the filename
if (!contentType && options.filename) {
contentType = mime.lookup(options.filename);
}
// fallback to the default content type if `value` is not simple value
if (!contentType && typeof value == 'object') {
contentType = FormData.DEFAULT_CONTENT_TYPE;
}
return contentType;
};
FormData.prototype._multiPartFooter = function() {
return function(next) {
var footer = FormData.LINE_BREAK;
var lastPart = (this._streams.length === 0);
if (lastPart) {
footer += this._lastBoundary();
}
next(footer);
}.bind(this);
};
FormData.prototype._lastBoundary = function() {
return '--' + this.getBoundary() + '--' + FormData.LINE_BREAK;
};
FormData.prototype.getHeaders = function(userHeaders) {
var header;
var formHeaders = {
'content-type': 'multipart/form-data; boundary=' + this.getBoundary()
};
for (header in userHeaders) {
if (userHeaders.hasOwnProperty(header)) {
formHeaders[header.toLowerCase()] = userHeaders[header];
}
}
return formHeaders;
};
FormData.prototype.getBoundary = function() {
if (!this._boundary) {
this._generateBoundary();
}
return this._boundary;
};
FormData.prototype._generateBoundary = function() {
// This generates a 50 character boundary similar to those used by Firefox.
// They are optimized for boyer-moore parsing.
var boundary = '--------------------------';
for (var i = 0; i < 24; i++) {
boundary += Math.floor(Math.random() * 10).toString(16);
}
this._boundary = boundary;
};
// Note: getLengthSync DOESN'T calculate streams length
// As workaround one can calculate file size manually
// and add it as knownLength option
FormData.prototype.getLengthSync = function() {
var knownLength = this._overheadLength + this._valueLength;
// Don't get confused, there are 3 "internal" streams for each keyval pair
// so it basically checks if there is any value added to the form
if (this._streams.length) {
knownLength += this._lastBoundary().length;
}
// https://github.com/form-data/form-data/issues/40
if (!this.hasKnownLength()) {
// Some async length retrievers are present
// therefore synchronous length calculation is false.
// Please use getLength(callback) to get proper length
this._error(new Error('Cannot calculate proper length in synchronous way.'));
}
return knownLength;
};
// Public API to check if length of added values is known
// https://github.com/form-data/form-data/issues/196
// https://github.com/form-data/form-data/issues/262
FormData.prototype.hasKnownLength = function() {
var hasKnownLength = true;
if (this._valuesToMeasure.length) {
hasKnownLength = false;
}
return hasKnownLength;
};
FormData.prototype.getLength = function(cb) {
var knownLength = this._overheadLength + this._valueLength;
if (this._streams.length) {
knownLength += this._lastBoundary().length;
}
if (!this._valuesToMeasure.length) {
process.nextTick(cb.bind(this, null, knownLength));
return;
}
asynckit.parallel(this._valuesToMeasure, this._lengthRetriever, function(err, values) {
if (err) {
cb(err);
return;
}
values.forEach(function(length) {
knownLength += length;
});
cb(null, knownLength);
});
};
FormData.prototype.submit = function(params, cb) {
var request
, options
, defaults = {method: 'post'}
;
// parse provided url if it's string
// or treat it as options object
if (typeof params == 'string') {
params = parseUrl(params);
options = populate({
port: params.port,
path: params.pathname,
host: params.hostname
}, defaults);
// use custom params
} else {
options = populate(params, defaults);
// if no port provided use default one
if (!options.port) {
options.port = options.protocol == 'https:' ? 443 : 80;
}
}
// put that good code in getHeaders to some use
options.headers = this.getHeaders(params.headers);
// https if specified, fallback to http in any other case
if (options.protocol == 'https:') {
request = https.request(options);
} else {
request = http.request(options);
}
// get content length and fire away
this.getLength(function(err, length) {
if (err) {
this._error(err);
return;
}
// add content length
request.setHeader('Content-Length', length);
this.pipe(request);
if (cb) {
request.on('error', cb);
request.on('response', cb.bind(this, null));
}
}.bind(this));
return request;
};
FormData.prototype._error = function(err) {
if (!this.error) {
this.error = err;
this.pause();
this.emit('error', err);
}
};
// populates missing values
module.exports = function(dst, src) {
Object.keys(src).forEach(function(prop)
{
dst[prop] = dst[prop] || src[prop];
});
return dst;
};
Copyright (c) 2012 Felix Geisendörfer (felix@debuggable.com) and contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
{
"_args": [
[
{
"raw": "form-data@~2.1.1",
"scope": null,
"escapedName": "form-data",
"name": "form-data",
"rawSpec": "~2.1.1",
"spec": ">=2.1.1 <2.2.0",
"type": "range"
},
"F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\request"
]
],
"_from": "form-data@>=2.1.1 <2.2.0",
"_id": "form-data@2.1.2",
"_inCache": true,
"_location": "/form-data",
"_nodeVersion": "6.4.0",
"_npmOperationalInternal": {
"host": "packages-12-west.internal.npmjs.com",
"tmp": "tmp/form-data-2.1.2.tgz_1478577739404_0.6574864208232611"
},
"_npmUser": {
"name": "alexindigo",
"email": "iam@alexindigo.com"
},
"_npmVersion": "3.10.3",
"_phantomChildren": {},
"_requested": {
"raw": "form-data@~2.1.1",
"scope": null,
"escapedName": "form-data",
"name": "form-data",
"rawSpec": "~2.1.1",
"spec": ">=2.1.1 <2.2.0",
"type": "range"
},
"_requiredBy": [
"/request"
],
"_resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.2.tgz",
"_shasum": "89c3534008b97eada4cbb157d58f6f5df025eae4",
"_shrinkwrap": null,
"_spec": "form-data@~2.1.1",
"_where": "F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\request",
"author": {
"name": "Felix Geisendörfer",
"email": "felix@debuggable.com",
"url": "http://debuggable.com/"
},
"browser": "./lib/browser",
"bugs": {
"url": "https://github.com/form-data/form-data/issues"
},
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.5",
"mime-types": "^2.1.12"
},
"description": "A library to create readable \"multipart/form-data\" streams. Can be used to submit forms and file uploads to other web applications.",
"devDependencies": {
"browserify": "^13.1.1",
"browserify-istanbul": "^2.0.0",
"coveralls": "^2.11.14",
"cross-spawn": "^4.0.2",
"eslint": "^3.9.1",
"fake": "^0.2.2",
"far": "^0.0.7",
"formidable": "^1.0.17",
"in-publish": "^2.0.0",
"is-node-modern": "^1.0.0",
"istanbul": "^0.4.5",
"obake": "^0.1.2",
"phantomjs-prebuilt": "^2.1.13",
"pkgfiles": "^2.3.0",
"pre-commit": "^1.1.3",
"request": "2.76.0",
"rimraf": "^2.5.4",
"tape": "^4.6.2"
},
"directories": {},
"dist": {
"shasum": "89c3534008b97eada4cbb157d58f6f5df025eae4",
"tarball": "https://registry.npmjs.org/form-data/-/form-data-2.1.2.tgz"
},
"engines": {
"node": ">= 0.12"
},
"gitHead": "03444d21961a7a44cdc2eae11ee3630f6969023d",
"homepage": "https://github.com/form-data/form-data#readme",
"license": "MIT",
"main": "./lib/form_data",
"maintainers": [
{
"name": "alexindigo",
"email": "iam@alexindigo.com"
},
{
"name": "dylanpiercey",
"email": "pierceydylan@gmail.com"
},
{
"name": "felixge",
"email": "felix@debuggable.com"
},
{
"name": "mikeal",
"email": "mikeal.rogers@gmail.com"
}
],
"name": "form-data",
"optionalDependencies": {},
"pre-commit": [
"lint",
"ci-test",
"check"
],
"readme": "ERROR: No README data found!",
"repository": {
"type": "git",
"url": "git://github.com/form-data/form-data.git"
},
"scripts": {
"browser": "browserify -t browserify-istanbul test/run-browser.js | obake --coverage",
"check": "istanbul check-coverage coverage/coverage*.json",
"ci-lint": "is-node-modern 6 && npm run lint || is-node-not-modern 6",
"ci-test": "npm run test && npm run browser && npm run report",
"debug": "verbose=1 ./test/run.js",
"files": "pkgfiles --sort=name",
"get-version": "node -e \"console.log(require('./package.json').version)\"",
"lint": "eslint lib/*.js test/*.js test/integration/*.js",
"postpublish": "npm run restore-readme",
"posttest": "istanbul report lcov text",
"predebug": "rimraf coverage test/tmp",
"prepublish": "in-publish && npm run update-readme || not-in-publish",
"pretest": "rimraf coverage test/tmp",
"report": "istanbul report lcov text",
"restore-readme": "mv README.md.bak README.md",
"test": "istanbul cover test/run.js",
"update-readme": "sed -i.bak 's/\\/master\\.svg/\\/v'$(npm --silent run get-version)'.svg/g' README.md"
},
"version": "2.1.2"
}

Form-Data NPM Module Join the chat at https://gitter.im/form-data/form-data

A library to create readable "multipart/form-data" streams. Can be used to submit forms and file uploads to other web applications.

The API of this library is inspired by the XMLHttpRequest-2 FormData Interface.

Linux Build MacOS Build Windows Build

Coverage Status Dependency Status bitHound Overall Score

Install

npm install --save form-data

Usage

In this example we are constructing a form with 3 fields that contain a string, a buffer and a file stream.

var FormData = require('form-data');
var fs = require('fs');

var form = new FormData();
form.append('my_field', 'my value');
form.append('my_buffer', new Buffer(10));
form.append('my_file', fs.createReadStream('/foo/bar.jpg'));

Also you can use http-response stream:

var FormData = require('form-data');
var http = require('http');

var form = new FormData();

http.request('http://nodejs.org/images/logo.png', function(response) {
  form.append('my_field', 'my value');
  form.append('my_buffer', new Buffer(10));
  form.append('my_logo', response);
});

Or @mikeal's request stream:

var FormData = require('form-data');
var request = require('request');

var form = new FormData();

form.append('my_field', 'my value');
form.append('my_buffer', new Buffer(10));
form.append('my_logo', request('http://nodejs.org/images/logo.png'));

In order to submit this form to a web application, call submit(url, [callback]) method:

form.submit('http://example.org/', function(err, res) {
  // res – response object (http.IncomingMessage)  //
  res.resume();
});

For more advanced request manipulations submit() method returns http.ClientRequest object, or you can choose from one of the alternative submission methods.

Alternative submission methods

You can use node's http client interface:

var http = require('http');

var request = http.request({
  method: 'post',
  host: 'example.org',
  path: '/upload',
  headers: form.getHeaders()
});

form.pipe(request);

request.on('response', function(res) {
  console.log(res.statusCode);
});

Or if you would prefer the 'Content-Length' header to be set for you:

form.submit('example.org/upload', function(err, res) {
  console.log(res.statusCode);
});

To use custom headers and pre-known length in parts:

var CRLF = '\r\n';
var form = new FormData();

var options = {
  header: CRLF + '--' + form.getBoundary() + CRLF + 'X-Custom-Header: 123' + CRLF + CRLF,
  knownLength: 1
};

form.append('my_buffer', buffer, options);

form.submit('http://example.com/', function(err, res) {
  if (err) throw err;
  console.log('Done');
});

Form-Data can recognize and fetch all the required information from common types of streams (fs.readStream, http.response and mikeal's request), for some other types of streams you'd need to provide "file"-related information manually:

someModule.stream(function(err, stdout, stderr) {
  if (err) throw err;

  var form = new FormData();

  form.append('file', stdout, {
    filename: 'unicycle.jpg',
    contentType: 'image/jpg',
    knownLength: 19806
  });

  form.submit('http://example.com/', function(err, res) {
    if (err) throw err;
    console.log('Done');
  });
});

For edge cases, like POST request to URL with query string or to pass HTTP auth credentials, object can be passed to form.submit() as first parameter:

form.submit({
  host: 'example.com',
  path: '/probably.php?extra=params',
  auth: 'username:password'
}, function(err, res) {
  console.log(res.statusCode);
});

In case you need to also send custom HTTP headers with the POST request, you can use the headers key in first parameter of form.submit():

form.submit({
  host: 'example.com',
  path: '/surelynot.php',
  headers: {'x-test-header': 'test-header-value'}
}, function(err, res) {
  console.log(res.statusCode);
});

Integration with other libraries

Request

Form submission using request:

var formData = {
  my_field: 'my_value',
  my_file: fs.createReadStream(__dirname + '/unicycle.jpg'),
};

request.post({url:'http://service.com/upload', formData: formData}, function(err, httpResponse, body) {
  if (err) {
    return console.error('upload failed:', err);
  }
  console.log('Upload successful!  Server responded with:', body);
});

For more details see request readme.

node-fetch

You can also submit a form using node-fetch:

var form = new FormData();

form.append('a', 1);

fetch('http://example.com', { method: 'POST', body: form })
    .then(function(res) {
        return res.json();
    }).then(function(json) {
        console.log(json);
    });

Notes

  • getLengthSync() method DOESN'T calculate length for streams, use knownLength options as workaround.
  • Starting version 2.x FormData has dropped support for node@0.10.x.

License

Form-Data is released under the MIT license.

var genfun = require('./')
var multiply = function(a, b) {
return a * b
}
var addAndMultiplyNumber = function(val) {
var fn = genfun()
('function(n) {')
('if (typeof n !== "number") {') // ending a line with { will indent the source
('throw new Error("argument should be a number")')
('}')
('var result = multiply(%d, n+%d)', val, val)
('return result')
('}')
// use fn.toString() if you want to see the generated source
return fn.toFunction({
multiply: multiply
})
}
var addAndMultiply2 = addAndMultiplyNumber(2)
console.log(addAndMultiply2.toString())
console.log('(3 + 2) * 2 =', addAndMultiply2(3))
var util = require('util')
var INDENT_START = /[\{\[]/
var INDENT_END = /[\}\]]/
module.exports = function() {
var lines = []
var indent = 0
var push = function(str) {
var spaces = ''
while (spaces.length < indent*2) spaces += ' '
lines.push(spaces+str)
}
var line = function(fmt) {
if (!fmt) return line
if (INDENT_END.test(fmt.trim()[0]) && INDENT_START.test(fmt[fmt.length-1])) {
indent--
push(util.format.apply(util, arguments))
indent++
return line
}
if (INDENT_START.test(fmt[fmt.length-1])) {
push(util.format.apply(util, arguments))
indent++
return line
}
if (INDENT_END.test(fmt.trim()[0])) {
indent--
push(util.format.apply(util, arguments))
return line
}
push(util.format.apply(util, arguments))
return line
}
line.toString = function() {
return lines.join('\n')
}
line.toFunction = function(scope) {
var src = 'return ('+line.toString()+')'
var keys = Object.keys(scope || {}).map(function(key) {
return key
})
var vals = keys.map(function(key) {
return scope[key]
})
return Function.apply(null, keys.concat(src)).apply(null, vals)
}
if (arguments.length) line.apply(null, arguments)
return line
}
{
"_args": [
[
{
"raw": "generate-function@^2.0.0",
"scope": null,
"escapedName": "generate-function",
"name": "generate-function",
"rawSpec": "^2.0.0",
"spec": ">=2.0.0 <3.0.0",
"type": "range"
},
"F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\is-my-json-valid"
]
],
"_from": "generate-function@>=2.0.0 <3.0.0",
"_id": "generate-function@2.0.0",
"_inCache": true,
"_location": "/generate-function",
"_npmUser": {
"name": "mafintosh",
"email": "mathiasbuus@gmail.com"
},
"_npmVersion": "1.4.23",
"_phantomChildren": {},
"_requested": {
"raw": "generate-function@^2.0.0",
"scope": null,
"escapedName": "generate-function",
"name": "generate-function",
"rawSpec": "^2.0.0",
"spec": ">=2.0.0 <3.0.0",
"type": "range"
},
"_requiredBy": [
"/is-my-json-valid"
],
"_resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz",
"_shasum": "6858fe7c0969b7d4e9093337647ac79f60dfbe74",
"_shrinkwrap": null,
"_spec": "generate-function@^2.0.0",
"_where": "F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\is-my-json-valid",
"author": {
"name": "Mathias Buus"
},
"bugs": {
"url": "https://github.com/mafintosh/generate-function/issues"
},
"dependencies": {},
"description": "Module that helps you write generated functions in Node",
"devDependencies": {
"tape": "^2.13.4"
},
"directories": {},
"dist": {
"shasum": "6858fe7c0969b7d4e9093337647ac79f60dfbe74",
"tarball": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz"
},
"gitHead": "3d5fc8de5859be95f58e3af9bfb5f663edd95149",
"homepage": "https://github.com/mafintosh/generate-function",
"keywords": [
"generate",
"code",
"generation",
"function",
"performance"
],
"license": "MIT",
"main": "index.js",
"maintainers": [
{
"name": "mafintosh",
"email": "mathiasbuus@gmail.com"
}
],
"name": "generate-function",
"optionalDependencies": {},
"readme": "ERROR: No README data found!",
"repository": {
"type": "git",
"url": "git+https://github.com/mafintosh/generate-function.git"
},
"scripts": {
"test": "tape test.js"
},
"version": "2.0.0"
}

generate-function

Module that helps you write generated functions in Node

npm install generate-function

build status

Disclamer

Writing code that generates code is hard. You should only use this if you really, really, really need this for performance reasons (like schema validators / parsers etc).

Usage

var genfun = require('generate-function')

var addNumber = function(val) {
  var fn = genfun()
    ('function add(n) {')
      ('return n + %d', val) // supports format strings to insert values
    ('}')

  return fn.toFunction() // will compile the function
}

var add2 = addNumber(2)

console.log('1+2=', add2(1))
console.log(add2.toString()) // prints the generated function

If you need to close over variables in your generated function pass them to toFunction(scope)

var multiply = function(a, b) {
  return a * b
}

var addAndMultiplyNumber = function(val) {
  var fn = genfun()
    ('function(n) {')
      ('if (typeof n !== "number") {') // ending a line with { will indent the source
        ('throw new Error("argument should be a number")')
      ('}')
      ('var result = multiply(%d, n+%d)', val, val)
      ('return result')
    ('}')

  // use fn.toString() if you want to see the generated source

  return fn.toFunction({
    multiply: multiply
  })
}

var addAndMultiply2 = addAndMultiplyNumber(2)

console.log('(3 + 2) * 2 =', addAndMultiply2(3))

Related

See generate-object-property if you need to safely generate code that can be used to reference an object property

License

MIT

var tape = require('tape')
var genfun = require('./')
tape('generate add function', function(t) {
var fn = genfun()
('function add(n) {')
('return n + %d', 42)
('}')
t.same(fn.toString(), 'function add(n) {\n return n + 42\n}', 'code is indented')
t.same(fn.toFunction()(10), 52, 'function works')
t.end()
})
tape('generate function + closed variables', function(t) {
var fn = genfun()
('function add(n) {')
('return n + %d + number', 42)
('}')
var notGood = fn.toFunction()
var good = fn.toFunction({number:10})
try {
notGood(10)
t.ok(false, 'function should not work')
} catch (err) {
t.same(err.message, 'number is not defined', 'throws reference error')
}
t.same(good(11), 63, 'function with closed var works')
t.end()
})
var isProperty = require('is-property')
var gen = function(obj, prop) {
return isProperty(prop) ? obj+'.'+prop : obj+'['+JSON.stringify(prop)+']'
}
gen.valid = isProperty
gen.property = function (prop) {
return isProperty(prop) ? prop : JSON.stringify(prop)
}
module.exports = gen
The MIT License (MIT)
Copyright (c) 2014 Mathias Buus
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
{
"_args": [
[
{
"raw": "generate-object-property@^1.1.0",
"scope": null,
"escapedName": "generate-object-property",
"name": "generate-object-property",
"rawSpec": "^1.1.0",
"spec": ">=1.1.0 <2.0.0",
"type": "range"
},
"F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\is-my-json-valid"
]
],
"_from": "generate-object-property@>=1.1.0 <2.0.0",
"_id": "generate-object-property@1.2.0",
"_inCache": true,
"_location": "/generate-object-property",
"_nodeVersion": "2.0.1",
"_npmUser": {
"name": "mafintosh",
"email": "mathiasbuus@gmail.com"
},
"_npmVersion": "2.9.0",
"_phantomChildren": {},
"_requested": {
"raw": "generate-object-property@^1.1.0",
"scope": null,
"escapedName": "generate-object-property",
"name": "generate-object-property",
"rawSpec": "^1.1.0",
"spec": ">=1.1.0 <2.0.0",
"type": "range"
},
"_requiredBy": [
"/is-my-json-valid"
],
"_resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz",
"_shasum": "9c0e1c40308ce804f4783618b937fa88f99d50d0",
"_shrinkwrap": null,
"_spec": "generate-object-property@^1.1.0",
"_where": "F:\\piweb\\web scraping\\test\\crawlerByTimos\\node_modules\\is-my-json-valid",
"author": {
"name": "Mathias Buus",
"url": "@mafintosh"
},
"bugs": {
"url": "https://github.com/mafintosh/generate-object-property/issues"
},
"dependencies": {
"is-property": "^1.0.0"
},
"description": "Generate safe JS code that can used to reference a object property",
"devDependencies": {
"tape": "^2.13.0"
},
"directories": {},
"dist": {
"shasum": "9c0e1c40308ce804f4783618b937fa88f99d50d0",
"tarball": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz"
},
"gitHead": "0dd7d411018de54b2eae63b424c15b3e50bd678c",
"homepage": "https://github.com/mafintosh/generate-object-property",
"license": "MIT",
"main": "index.js",
"maintainers": [
{
"name": "mafintosh",
"email": "mathiasbuus@gmail.com"
}
],
"name": "generate-object-property",
"optionalDependencies": {},
"readme": "ERROR: No README data found!",
"repository": {
"type": "git",
"url": "git+https://github.com/mafintosh/generate-object-property.git"
},
"scripts": {
"test": "tape test.js"
},
"version": "1.2.0"
}

generate-object-property

Generate safe JS code that can used to reference a object property

npm install generate-object-property

build status

Usage

var gen = require('generate-object-property');
console.log(gen('a','b')); // prints a.b
console.log(gen('a', 'foo-bar')); // prints a["foo-bar"]

License

MIT

var tape = require('tape')
var gen = require('./')
tape('valid', function(t) {
t.same(gen('a', 'b'), 'a.b')
t.end()
})
tape('invalid', function(t) {
t.same(gen('a', '-b'), 'a["-b"]')
t.end()
})
.gitmodules
deps
docs
Makefile
node_modules
test
tools
coverage
language: node_js
node_js:
- "5.10"
- "4.4"
- "4.1"
- "0.12"
- "0.10"
before_install:
- "make check"
Copyright Joyent, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.

getpass

Get a password from the terminal. Sounds simple? Sounds like the readline module should be able to do it? NOPE.

Install and use it

npm install --save getpass
const mod_getpass = require('getpass');

API

mod_getpass.getPass([options, ]callback)

Gets a password from the terminal. If available, this uses /dev/tty to avoid interfering with any data being piped in or out of stdio.

This function prints a prompt (by default Password:) and then accepts input without echoing.

Parameters:

  • options, an Object, with properties:
    • prompt, an optional String
  • callback, a Func(error, password), with arguments:
    • error, either null (no error) or an Error instance
    • password, a String
This file has been truncated, but you can view the full file.
/*
* Copyright 2016, Joyent, Inc. All rights reserved.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment