diff --git a/.all-contributorsrc b/.all-contributorsrc index d014ad73a..8c7d7b544 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -1249,6 +1249,74 @@ "bug", "code" ] + }, + { + "login": "eltociear", + "name": "Ikko Ashimine", + "avatar_url": "https://avatars.githubusercontent.com/u/22633385?v=4", + "profile": "https://bandism.net/", + "contributions": [ + "doc" + ] + }, + { + "login": "Mudasar-Makandar", + "name": "Mudasar-Makandar", + "avatar_url": "https://avatars.githubusercontent.com/u/46401916?v=4", + "profile": "https://github.com/Mudasar-Makandar", + "contributions": [ + "bug", + "code" + ] + }, + { + "login": "amirfeqhi", + "name": "Amir Feqhi", + "avatar_url": "https://avatars.githubusercontent.com/u/26363996?v=4", + "profile": "https://github.com/amirfeqhi", + "contributions": [ + "code" + ] + }, + { + "login": "danidask", + "name": "DasK", + "avatar_url": "https://avatars.githubusercontent.com/u/9405129?v=4", + "profile": "https://github.com/danidask", + "contributions": [ + "code", + "ideas" + ] + }, + { + "login": "asvsfs", + "name": "Amir", + "avatar_url": "https://avatars.githubusercontent.com/u/119840?v=4", + "profile": "https://github.com/asvsfs", + "contributions": [ + "code", + "example" + ] + }, + { + "login": "lindapaiste", + "name": "lindapaiste", + "avatar_url": "https://avatars.githubusercontent.com/u/28965286?v=4", + "profile": "http://lindapaiste.com", + "contributions": [ + "code", + "ideas", + "bug" + ] + }, + { + "login": "emwdx", + "name": "Evan Weinberg", + "avatar_url": "https://avatars.githubusercontent.com/u/1531831?v=4", + "profile": "http://evanweinberg.com", + "contributions": [ + "doc" + ] } ], "contributorsPerLine": 7, diff --git a/README.md b/README.md index ad49e5f9b..23cb9c96e 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,14 @@ Before getting started with ml5.js, review our [Code of Conduct](https://github. + + + + + + + + @@ -63,11 +71,11 @@ Before getting started with ml5.js, review our [Code of Conduct](https://github.

-* You can use the latest version (0.9.8) by adding it to the head section of your HTML document: +* You can use the latest version (0.10.6) by adding it to the head section of your HTML document: -**v0.9.8** +**v0.10.6** - +

@@ -93,6 +101,14 @@ Before getting started with ml5.js, review our [Code of Conduct](https://github. + + + + + + + + @@ -130,11 +146,11 @@ For example: ## Resources -- [Getting Started](https://ml5js.org/getting-started/) -- [API Reference](https://ml5js.org/reference/) +- [Getting Started](https://learn.ml5js.org/) +- [API Reference](https://learn.ml5js.org/#/reference/index) - [Examples](https://github.com/ml5js/ml5-library/tree/main/examples) - [Community](https://ml5js.org/community) -- [FAQ](https://ml5js.org/getting-started/faq/) +- [FAQ](https://learn.ml5js.org/#/faq) ## Standalone Examples @@ -321,6 +337,15 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
Lauren Lee McCarthy

💻 📖
Sorin Curescu

💻
mofanke

🐛 💻 +
Ikko Ashimine

📖 +
Mudasar-Makandar

🐛 💻 +
Amir Feqhi

💻 +
DasK

💻 🤔 + + +
Amir

💻 💡 +
lindapaiste

💻 🤔 🐛 +
Evan Weinberg

📖 diff --git a/coverage/clover.xml b/coverage/clover.xml new file mode 100644 index 000000000..d0b191c6b --- /dev/null +++ b/coverage/clover.xml @@ -0,0 +1,139 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/coverage/coverage-final.json b/coverage/coverage-final.json new file mode 100644 index 000000000..275363f90 --- /dev/null +++ b/coverage/coverage-final.json @@ -0,0 +1,2 @@ +{"/Users/joeyklee-nyt/Source/joeyklee/ml5-library/src/CharRNN/index.js": {"path":"/Users/joeyklee-nyt/Source/joeyklee/ml5-library/src/CharRNN/index.js","statementMap":{"0":{"start":{"line":18,"column":18},"end":{"line":18,"column":43}},"1":{"start":{"line":19,"column":21},"end":{"line":19,"column":56}},"2":{"start":{"line":20,"column":28},"end":{"line":20,"column":39}},"3":{"start":{"line":36,"column":4},"end":{"line":36,"column":23}},"4":{"start":{"line":43,"column":4},"end":{"line":43,"column":20}},"5":{"start":{"line":44,"column":4},"end":{"line":44,"column":25}},"6":{"start":{"line":45,"column":4},"end":{"line":45,"column":20}},"7":{"start":{"line":46,"column":4},"end":{"line":46,"column":38}},"8":{"start":{"line":52,"column":4},"end":{"line":52,"column":34}},"9":{"start":{"line":53,"column":4},"end":{"line":53,"column":20}},"10":{"start":{"line":54,"column":4},"end":{"line":54,"column":23}},"11":{"start":{"line":55,"column":4},"end":{"line":55,"column":28}},"12":{"start":{"line":56,"column":4},"end":{"line":61,"column":6}},"13":{"start":{"line":63,"column":4},"end":{"line":63,"column":73}},"14":{"start":{"line":68,"column":4},"end":{"line":68,"column":32}},"15":{"start":{"line":72,"column":4},"end":{"line":72,"column":23}},"16":{"start":{"line":76,"column":4},"end":{"line":76,"column":22}},"17":{"start":{"line":80,"column":19},"end":{"line":80,"column":45}},"18":{"start":{"line":81,"column":17},"end":{"line":81,"column":47}},"19":{"start":{"line":82,"column":4},"end":{"line":99,"column":7}},"20":{"start":{"line":83,"column":6},"end":{"line":98,"column":7}},"21":{"start":{"line":84,"column":8},"end":{"line":89,"column":9}},"22":{"start":{"line":85,"column":10},"end":{"line":85,"column":68}},"23":{"start":{"line":86,"column":10},"end":{"line":86,"column":32}},"24":{"start":{"line":88,"column":10},"end":{"line":88,"column":66}},"25":{"start":{"line":90,"column":13},"end":{"line":98,"column":7}},"26":{"start":{"line":91,"column":8},"end":{"line":95,"column":9}},"27":{"start":{"line":92,"column":10},"end":{"line":92,"column":55}},"28":{"start":{"line":94,"column":10},"end":{"line":94,"column":54}},"29":{"start":{"line":97,"column":8},"end":{"line":97,"column":36}},"30":{"start":{"line":100,"column":4},"end":{"line":100,"column":31}},"31":{"start":{"line":101,"column":4},"end":{"line":101,"column":27}},"32":{"start":{"line":102,"column":4},"end":{"line":102,"column":16}},"33":{"start":{"line":106,"column":4},"end":{"line":113,"column":5}},"34":{"start":{"line":107,"column":23},"end":{"line":107,"column":60}},"35":{"start":{"line":108,"column":6},"end":{"line":108,"column":24}},"36":{"start":{"line":109,"column":6},"end":{"line":109,"column":48}},"37":{"start":{"line":110,"column":6},"end":{"line":110,"column":24}},"38":{"start":{"line":112,"column":6},"end":{"line":112,"column":17}},"39":{"start":{"line":117,"column":4},"end":{"line":117,"column":20}},"40":{"start":{"line":118,"column":4},"end":{"line":118,"column":38}},"41":{"start":{"line":119,"column":23},"end":{"line":119,"column":37}},"42":{"start":{"line":121,"column":17},"end":{"line":132,"column":5}},"43":{"start":{"line":122,"column":19},"end":{"line":130,"column":9}},"44":{"start":{"line":123,"column":8},"end":{"line":130,"column":9}},"45":{"start":{"line":131,"column":6},"end":{"line":131,"column":18}},"46":{"start":{"line":134,"column":4},"end":{"line":138,"column":5}},"47":{"start":{"line":134,"column":17},"end":{"line":134,"column":18}},"48":{"start":{"line":135,"column":6},"end":{"line":135,"column":81}},"49":{"start":{"line":136,"column":6},"end":{"line":136,"column":81}},"50":{"start":{"line":137,"column":6},"end":{"line":137,"column":31}},"51":{"start":{"line":140,"column":4},"end":{"line":140,"column":32}},"52":{"start":{"line":144,"column":4},"end":{"line":144,"column":21}},"53":{"start":{"line":145,"column":17},"end":{"line":145,"column":51}},"54":{"start":{"line":146,"column":19},"end":{"line":146,"column":58}},"55":{"start":{"line":147,"column":24},"end":{"line":147,"column":73}},"56":{"start":{"line":148,"column":21},"end":{"line":148,"column":63}},"57":{"start":{"line":149,"column":4},"end":{"line":151,"column":5}},"58":{"start":{"line":150,"column":6},"end":{"line":150,"column":34}},"59":{"start":{"line":153,"column":20},"end":{"line":153,"column":22}},"60":{"start":{"line":154,"column":22},"end":{"line":154,"column":38}},"61":{"start":{"line":155,"column":25},"end":{"line":155,"column":27}},"62":{"start":{"line":157,"column":4},"end":{"line":159,"column":7}},"63":{"start":{"line":158,"column":6},"end":{"line":158,"column":42}},"64":{"start":{"line":161,"column":16},"end":{"line":161,"column":31}},"65":{"start":{"line":162,"column":34},"end":{"line":162,"column":36}},"66":{"start":{"line":164,"column":4},"end":{"line":192,"column":5}},"67":{"start":{"line":164,"column":17},"end":{"line":164,"column":18}},"68":{"start":{"line":165,"column":27},"end":{"line":165,"column":63}},"69":{"start":{"line":166,"column":6},"end":{"line":166,"column":38}},"70":{"start":{"line":167,"column":21},"end":{"line":167,"column":44}},"71":{"start":{"line":169,"column":6},"end":{"line":174,"column":7}},"72":{"start":{"line":170,"column":25},"end":{"line":170,"column":64}},"73":{"start":{"line":171,"column":8},"end":{"line":171,"column":83}},"74":{"start":{"line":173,"column":8},"end":{"line":173,"column":81}},"75":{"start":{"line":176,"column":6},"end":{"line":176,"column":31}},"76":{"start":{"line":177,"column":6},"end":{"line":177,"column":31}},"77":{"start":{"line":179,"column":22},"end":{"line":179,"column":37}},"78":{"start":{"line":180,"column":29},"end":{"line":180,"column":81}},"79":{"start":{"line":181,"column":21},"end":{"line":181,"column":76}},"80":{"start":{"line":182,"column":22},"end":{"line":182,"column":60}},"81":{"start":{"line":183,"column":28},"end":{"line":183,"column":43}},"82":{"start":{"line":184,"column":6},"end":{"line":184,"column":90}},"83":{"start":{"line":186,"column":6},"end":{"line":191,"column":7}},"84":{"start":{"line":187,"column":8},"end":{"line":187,"column":36}},"85":{"start":{"line":189,"column":8},"end":{"line":189,"column":64}},"86":{"start":{"line":190,"column":8},"end":{"line":190,"column":28}},"87":{"start":{"line":194,"column":20},"end":{"line":194,"column":22}},"88":{"start":{"line":195,"column":4},"end":{"line":200,"column":7}},"89":{"start":{"line":196,"column":21},"end":{"line":196,"column":82}},"90":{"start":{"line":196,"column":57},"end":{"line":196,"column":81}},"91":{"start":{"line":197,"column":6},"end":{"line":199,"column":7}},"92":{"start":{"line":198,"column":8},"end":{"line":198,"column":28}},"93":{"start":{"line":201,"column":4},"end":{"line":201,"column":49}},"94":{"start":{"line":202,"column":4},"end":{"line":205,"column":6}},"95":{"start":{"line":212,"column":4},"end":{"line":212,"column":32}},"96":{"start":{"line":235,"column":4},"end":{"line":235,"column":17}},"97":{"start":{"line":236,"column":4},"end":{"line":236,"column":66}},"98":{"start":{"line":248,"column":34},"end":{"line":248,"column":36}},"99":{"start":{"line":249,"column":24},"end":{"line":249,"column":45}},"100":{"start":{"line":250,"column":20},"end":{"line":250,"column":35}},"101":{"start":{"line":251,"column":27},"end":{"line":251,"column":79}},"102":{"start":{"line":252,"column":19},"end":{"line":252,"column":74}},"103":{"start":{"line":253,"column":20},"end":{"line":253,"column":58}},"104":{"start":{"line":254,"column":26},"end":{"line":254,"column":41}},"105":{"start":{"line":255,"column":4},"end":{"line":255,"column":88}},"106":{"start":{"line":257,"column":19},"end":{"line":257,"column":66}},"107":{"start":{"line":258,"column":19},"end":{"line":258,"column":82}},"108":{"start":{"line":258,"column":55},"end":{"line":258,"column":81}},"109":{"start":{"line":259,"column":4},"end":{"line":259,"column":49}},"110":{"start":{"line":260,"column":4},"end":{"line":262,"column":5}},"111":{"start":{"line":261,"column":6},"end":{"line":261,"column":23}},"112":{"start":{"line":264,"column":15},"end":{"line":267,"column":7}},"113":{"start":{"line":264,"column":49},"end":{"line":267,"column":5}},"114":{"start":{"line":268,"column":4},"end":{"line":271,"column":6}},"115":{"start":{"line":282,"column":4},"end":{"line":282,"column":21}},"116":{"start":{"line":283,"column":17},"end":{"line":283,"column":38}},"117":{"start":{"line":284,"column":25},"end":{"line":284,"column":27}},"118":{"start":{"line":286,"column":4},"end":{"line":288,"column":7}},"119":{"start":{"line":287,"column":6},"end":{"line":287,"column":42}},"120":{"start":{"line":290,"column":16},"end":{"line":290,"column":31}},"121":{"start":{"line":291,"column":4},"end":{"line":305,"column":5}},"122":{"start":{"line":291,"column":17},"end":{"line":291,"column":18}},"123":{"start":{"line":292,"column":27},"end":{"line":292,"column":63}},"124":{"start":{"line":293,"column":6},"end":{"line":293,"column":38}},"125":{"start":{"line":294,"column":21},"end":{"line":294,"column":44}},"126":{"start":{"line":296,"column":6},"end":{"line":301,"column":7}},"127":{"start":{"line":297,"column":25},"end":{"line":297,"column":64}},"128":{"start":{"line":298,"column":8},"end":{"line":298,"column":83}},"129":{"start":{"line":300,"column":8},"end":{"line":300,"column":81}},"130":{"start":{"line":302,"column":6},"end":{"line":302,"column":31}},"131":{"start":{"line":303,"column":6},"end":{"line":303,"column":31}},"132":{"start":{"line":304,"column":6},"end":{"line":304,"column":30}},"133":{"start":{"line":306,"column":4},"end":{"line":308,"column":5}},"134":{"start":{"line":307,"column":6},"end":{"line":307,"column":17}},"135":{"start":{"line":312,"column":16},"end":{"line":312,"column":80}},"136":{"start":{"line":312,"column":48},"end":{"line":312,"column":80}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":30,"column":2},"end":{"line":30,"column":3}},"loc":{"start":{"line":30,"column":35},"end":{"line":65,"column":3}},"line":30},"1":{"name":"(anonymous_1)","decl":{"start":{"line":67,"column":2},"end":{"line":67,"column":3}},"loc":{"start":{"line":67,"column":15},"end":{"line":69,"column":3}},"line":67},"2":{"name":"(anonymous_2)","decl":{"start":{"line":71,"column":2},"end":{"line":71,"column":3}},"loc":{"start":{"line":71,"column":18},"end":{"line":73,"column":3}},"line":71},"3":{"name":"(anonymous_3)","decl":{"start":{"line":75,"column":2},"end":{"line":75,"column":3}},"loc":{"start":{"line":75,"column":13},"end":{"line":77,"column":3}},"line":75},"4":{"name":"(anonymous_4)","decl":{"start":{"line":79,"column":2},"end":{"line":79,"column":3}},"loc":{"start":{"line":79,"column":30},"end":{"line":103,"column":3}},"line":79},"5":{"name":"(anonymous_5)","decl":{"start":{"line":82,"column":30},"end":{"line":82,"column":31}},"loc":{"start":{"line":82,"column":37},"end":{"line":99,"column":5}},"line":82},"6":{"name":"(anonymous_6)","decl":{"start":{"line":105,"column":2},"end":{"line":105,"column":3}},"loc":{"start":{"line":105,"column":24},"end":{"line":114,"column":3}},"line":105},"7":{"name":"(anonymous_7)","decl":{"start":{"line":116,"column":2},"end":{"line":116,"column":3}},"loc":{"start":{"line":116,"column":20},"end":{"line":141,"column":3}},"line":116},"8":{"name":"(anonymous_8)","decl":{"start":{"line":121,"column":17},"end":{"line":121,"column":18}},"loc":{"start":{"line":121,"column":22},"end":{"line":132,"column":5}},"line":121},"9":{"name":"(anonymous_9)","decl":{"start":{"line":122,"column":19},"end":{"line":122,"column":20}},"loc":{"start":{"line":123,"column":8},"end":{"line":130,"column":9}},"line":123},"10":{"name":"(anonymous_10)","decl":{"start":{"line":143,"column":2},"end":{"line":143,"column":3}},"loc":{"start":{"line":143,"column":34},"end":{"line":206,"column":3}},"line":143},"11":{"name":"(anonymous_11)","decl":{"start":{"line":157,"column":22},"end":{"line":157,"column":23}},"loc":{"start":{"line":157,"column":30},"end":{"line":159,"column":5}},"line":157},"12":{"name":"(anonymous_12)","decl":{"start":{"line":195,"column":20},"end":{"line":195,"column":21}},"loc":{"start":{"line":195,"column":28},"end":{"line":200,"column":5}},"line":195},"13":{"name":"(anonymous_13)","decl":{"start":{"line":196,"column":50},"end":{"line":196,"column":51}},"loc":{"start":{"line":196,"column":57},"end":{"line":196,"column":81}},"line":196},"14":{"name":"(anonymous_14)","decl":{"start":{"line":211,"column":2},"end":{"line":211,"column":3}},"loc":{"start":{"line":211,"column":10},"end":{"line":213,"column":3}},"line":211},"15":{"name":"(anonymous_15)","decl":{"start":{"line":234,"column":2},"end":{"line":234,"column":3}},"loc":{"start":{"line":234,"column":36},"end":{"line":237,"column":3}},"line":234},"16":{"name":"(anonymous_16)","decl":{"start":{"line":247,"column":2},"end":{"line":247,"column":3}},"loc":{"start":{"line":247,"column":32},"end":{"line":272,"column":3}},"line":247},"17":{"name":"(anonymous_17)","decl":{"start":{"line":258,"column":48},"end":{"line":258,"column":49}},"loc":{"start":{"line":258,"column":55},"end":{"line":258,"column":81}},"line":258},"18":{"name":"(anonymous_18)","decl":{"start":{"line":264,"column":43},"end":{"line":264,"column":44}},"loc":{"start":{"line":264,"column":49},"end":{"line":267,"column":5}},"line":264},"19":{"name":"(anonymous_19)","decl":{"start":{"line":281,"column":2},"end":{"line":281,"column":3}},"loc":{"start":{"line":281,"column":34},"end":{"line":309,"column":3}},"line":281},"20":{"name":"(anonymous_20)","decl":{"start":{"line":286,"column":17},"end":{"line":286,"column":18}},"loc":{"start":{"line":286,"column":25},"end":{"line":288,"column":5}},"line":286},"21":{"name":"(anonymous_21)","decl":{"start":{"line":312,"column":16},"end":{"line":312,"column":17}},"loc":{"start":{"line":312,"column":48},"end":{"line":312,"column":80}},"line":312}},"branchMap":{"0":{"loc":{"start":{"line":83,"column":6},"end":{"line":98,"column":7}},"type":"if","locations":[{"start":{"line":83,"column":6},"end":{"line":98,"column":7}},{"start":{"line":90,"column":13},"end":{"line":98,"column":7}}],"line":83},"1":{"loc":{"start":{"line":84,"column":8},"end":{"line":89,"column":9}},"type":"if","locations":[{"start":{"line":84,"column":8},"end":{"line":89,"column":9}},{"start":{"line":87,"column":15},"end":{"line":89,"column":9}}],"line":84},"2":{"loc":{"start":{"line":90,"column":13},"end":{"line":98,"column":7}},"type":"if","locations":[{"start":{"line":90,"column":13},"end":{"line":98,"column":7}},{"start":{"line":96,"column":13},"end":{"line":98,"column":7}}],"line":90},"3":{"loc":{"start":{"line":91,"column":8},"end":{"line":95,"column":9}},"type":"if","locations":[{"start":{"line":91,"column":8},"end":{"line":95,"column":9}},{"start":{"line":93,"column":15},"end":{"line":95,"column":9}}],"line":91},"4":{"loc":{"start":{"line":145,"column":17},"end":{"line":145,"column":51}},"type":"binary-expr","locations":[{"start":{"line":145,"column":17},"end":{"line":145,"column":29}},{"start":{"line":145,"column":33},"end":{"line":145,"column":51}}],"line":145},"5":{"loc":{"start":{"line":146,"column":19},"end":{"line":146,"column":58}},"type":"binary-expr","locations":[{"start":{"line":146,"column":19},"end":{"line":146,"column":34}},{"start":{"line":146,"column":38},"end":{"line":146,"column":58}}],"line":146},"6":{"loc":{"start":{"line":147,"column":24},"end":{"line":147,"column":73}},"type":"binary-expr","locations":[{"start":{"line":147,"column":24},"end":{"line":147,"column":44}},{"start":{"line":147,"column":48},"end":{"line":147,"column":73}}],"line":147},"7":{"loc":{"start":{"line":148,"column":21},"end":{"line":148,"column":63}},"type":"binary-expr","locations":[{"start":{"line":148,"column":21},"end":{"line":148,"column":37}},{"start":{"line":148,"column":41},"end":{"line":148,"column":63}}],"line":148},"8":{"loc":{"start":{"line":149,"column":4},"end":{"line":151,"column":5}},"type":"if","locations":[{"start":{"line":149,"column":4},"end":{"line":151,"column":5}},{"start":{},"end":{}}],"line":149},"9":{"loc":{"start":{"line":169,"column":6},"end":{"line":174,"column":7}},"type":"if","locations":[{"start":{"line":169,"column":6},"end":{"line":174,"column":7}},{"start":{"line":172,"column":13},"end":{"line":174,"column":7}}],"line":169},"10":{"loc":{"start":{"line":186,"column":6},"end":{"line":191,"column":7}},"type":"if","locations":[{"start":{"line":186,"column":6},"end":{"line":191,"column":7}},{"start":{"line":188,"column":13},"end":{"line":191,"column":7}}],"line":186},"11":{"loc":{"start":{"line":197,"column":6},"end":{"line":199,"column":7}},"type":"if","locations":[{"start":{"line":197,"column":6},"end":{"line":199,"column":7}},{"start":{},"end":{}}],"line":197},"12":{"loc":{"start":{"line":249,"column":24},"end":{"line":249,"column":45}},"type":"cond-expr","locations":[{"start":{"line":249,"column":35},"end":{"line":249,"column":39}},{"start":{"line":249,"column":42},"end":{"line":249,"column":45}}],"line":249},"13":{"loc":{"start":{"line":260,"column":4},"end":{"line":262,"column":5}},"type":"if","locations":[{"start":{"line":260,"column":4},"end":{"line":262,"column":5}},{"start":{},"end":{}}],"line":260},"14":{"loc":{"start":{"line":296,"column":6},"end":{"line":301,"column":7}},"type":"if","locations":[{"start":{"line":296,"column":6},"end":{"line":301,"column":7}},{"start":{"line":299,"column":13},"end":{"line":301,"column":7}}],"line":296},"15":{"loc":{"start":{"line":306,"column":4},"end":{"line":308,"column":5}},"type":"if","locations":[{"start":{"line":306,"column":4},"end":{"line":308,"column":5}},{"start":{},"end":{}}],"line":306},"16":{"loc":{"start":{"line":312,"column":17},"end":{"line":312,"column":33}},"type":"default-arg","locations":[{"start":{"line":312,"column":29},"end":{"line":312,"column":33}}],"line":312}},"s":{"0":1,"1":1,"2":1,"3":1,"4":1,"5":1,"6":1,"7":1,"8":1,"9":1,"10":1,"11":1,"12":1,"13":1,"14":0,"15":0,"16":0,"17":1,"18":1,"19":1,"20":8,"21":4,"22":2,"23":2,"24":2,"25":4,"26":2,"27":1,"28":1,"29":2,"30":1,"31":1,"32":1,"33":1,"34":1,"35":1,"36":1,"37":1,"38":0,"39":1,"40":1,"41":1,"42":1,"43":2,"44":108,"45":2,"46":1,"47":1,"48":2,"49":2,"50":2,"51":1,"52":2,"53":2,"54":2,"55":2,"56":2,"57":2,"58":2,"59":2,"60":2,"61":2,"62":2,"63":26,"64":2,"65":2,"66":2,"67":2,"68":54,"69":54,"70":54,"71":54,"72":54,"73":54,"74":0,"75":54,"76":54,"77":54,"78":54,"79":54,"80":54,"81":54,"82":54,"83":54,"84":24,"85":30,"86":30,"87":2,"88":2,"89":30,"90":1861,"91":30,"92":30,"93":2,"94":2,"95":2,"96":2,"97":2,"98":0,"99":0,"100":0,"101":0,"102":0,"103":0,"104":0,"105":0,"106":0,"107":0,"108":0,"109":0,"110":0,"111":0,"112":0,"113":0,"114":0,"115":0,"116":0,"117":0,"118":0,"119":0,"120":0,"121":0,"122":0,"123":0,"124":0,"125":0,"126":0,"127":0,"128":0,"129":0,"130":0,"131":0,"132":0,"133":0,"134":0,"135":1,"136":1},"f":{"0":1,"1":0,"2":0,"3":0,"4":1,"5":8,"6":1,"7":1,"8":2,"9":108,"10":2,"11":26,"12":30,"13":1861,"14":2,"15":2,"16":0,"17":0,"18":0,"19":0,"20":0,"21":1},"b":{"0":[4,4],"1":[2,2],"2":[2,2],"3":[1,1],"4":[2,1],"5":[2,1],"6":[2,1],"7":[2,2],"8":[2,0],"9":[54,0],"10":[24,30],"11":[30,0],"12":[0,0],"13":[0,0],"14":[0,0],"15":[0,0],"16":[0]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"2dcd353da921bd16b99f55884619d506852a5916"} +} diff --git a/coverage/lcov-report/base.css b/coverage/lcov-report/base.css new file mode 100644 index 000000000..f418035b4 --- /dev/null +++ b/coverage/lcov-report/base.css @@ -0,0 +1,224 @@ +body, html { + margin:0; padding: 0; + height: 100%; +} +body { + font-family: Helvetica Neue, Helvetica, Arial; + font-size: 14px; + color:#333; +} +.small { font-size: 12px; } +*, *:after, *:before { + -webkit-box-sizing:border-box; + -moz-box-sizing:border-box; + box-sizing:border-box; + } +h1 { font-size: 20px; margin: 0;} +h2 { font-size: 14px; } +pre { + font: 12px/1.4 Consolas, "Liberation Mono", Menlo, Courier, monospace; + margin: 0; + padding: 0; + -moz-tab-size: 2; + -o-tab-size: 2; + tab-size: 2; +} +a { color:#0074D9; text-decoration:none; } +a:hover { text-decoration:underline; } +.strong { font-weight: bold; } +.space-top1 { padding: 10px 0 0 0; } +.pad2y { padding: 20px 0; } +.pad1y { padding: 10px 0; } +.pad2x { padding: 0 20px; } +.pad2 { padding: 20px; } +.pad1 { padding: 10px; } +.space-left2 { padding-left:55px; } +.space-right2 { padding-right:20px; } +.center { text-align:center; } +.clearfix { display:block; } +.clearfix:after { + content:''; + display:block; + height:0; + clear:both; + visibility:hidden; + } +.fl { float: left; } +@media only screen and (max-width:640px) { + .col3 { width:100%; max-width:100%; } + .hide-mobile { display:none!important; } +} + +.quiet { + color: #7f7f7f; + color: rgba(0,0,0,0.5); +} +.quiet a { opacity: 0.7; } + +.fraction { + font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; + font-size: 10px; + color: #555; + background: #E8E8E8; + padding: 4px 5px; + border-radius: 3px; + vertical-align: middle; +} + +div.path a:link, div.path a:visited { color: #333; } +table.coverage { + border-collapse: collapse; + margin: 10px 0 0 0; + padding: 0; +} + +table.coverage td { + margin: 0; + padding: 0; + vertical-align: top; +} +table.coverage td.line-count { + text-align: right; + padding: 0 5px 0 20px; +} +table.coverage td.line-coverage { + text-align: right; + padding-right: 10px; + min-width:20px; +} + +table.coverage td span.cline-any { + display: inline-block; + padding: 0 5px; + width: 100%; +} +.missing-if-branch { + display: inline-block; + margin-right: 5px; + border-radius: 3px; + position: relative; + padding: 0 4px; + background: #333; + color: yellow; +} + +.skip-if-branch { + display: none; + margin-right: 10px; + position: relative; + padding: 0 4px; + background: #ccc; + color: white; +} +.missing-if-branch .typ, .skip-if-branch .typ { + color: inherit !important; +} +.coverage-summary { + border-collapse: collapse; + width: 100%; +} +.coverage-summary tr { border-bottom: 1px solid #bbb; } +.keyline-all { border: 1px solid #ddd; } +.coverage-summary td, .coverage-summary th { padding: 10px; } +.coverage-summary tbody { border: 1px solid #bbb; } +.coverage-summary td { border-right: 1px solid #bbb; } +.coverage-summary td:last-child { border-right: none; } +.coverage-summary th { + text-align: left; + font-weight: normal; + white-space: nowrap; +} +.coverage-summary th.file { border-right: none !important; } +.coverage-summary th.pct { } +.coverage-summary th.pic, +.coverage-summary th.abs, +.coverage-summary td.pct, +.coverage-summary td.abs { text-align: right; } +.coverage-summary td.file { white-space: nowrap; } +.coverage-summary td.pic { min-width: 120px !important; } +.coverage-summary tfoot td { } + +.coverage-summary .sorter { + height: 10px; + width: 7px; + display: inline-block; + margin-left: 0.5em; + background: url(sort-arrow-sprite.png) no-repeat scroll 0 0 transparent; +} +.coverage-summary .sorted .sorter { + background-position: 0 -20px; +} +.coverage-summary .sorted-desc .sorter { + background-position: 0 -10px; +} +.status-line { height: 10px; } +/* yellow */ +.cbranch-no { background: yellow !important; color: #111; } +/* dark red */ +.red.solid, .status-line.low, .low .cover-fill { background:#C21F39 } +.low .chart { border:1px solid #C21F39 } +.highlighted, +.highlighted .cstat-no, .highlighted .fstat-no, .highlighted .cbranch-no{ + background: #C21F39 !important; +} +/* medium red */ +.cstat-no, .fstat-no, .cbranch-no, .cbranch-no { background:#F6C6CE } +/* light red */ +.low, .cline-no { background:#FCE1E5 } +/* light green */ +.high, .cline-yes { background:rgb(230,245,208) } +/* medium green */ +.cstat-yes { background:rgb(161,215,106) } +/* dark green */ +.status-line.high, .high .cover-fill { background:rgb(77,146,33) } +.high .chart { border:1px solid rgb(77,146,33) } +/* dark yellow (gold) */ +.status-line.medium, .medium .cover-fill { background: #f9cd0b; } +.medium .chart { border:1px solid #f9cd0b; } +/* light yellow */ +.medium { background: #fff4c2; } + +.cstat-skip { background: #ddd; color: #111; } +.fstat-skip { background: #ddd; color: #111 !important; } +.cbranch-skip { background: #ddd !important; color: #111; } + +span.cline-neutral { background: #eaeaea; } + +.coverage-summary td.empty { + opacity: .5; + padding-top: 4px; + padding-bottom: 4px; + line-height: 1; + color: #888; +} + +.cover-fill, .cover-empty { + display:inline-block; + height: 12px; +} +.chart { + line-height: 0; +} +.cover-empty { + background: white; +} +.cover-full { + border-right: none !important; +} +pre.prettyprint { + border: none !important; + padding: 0 !important; + margin: 0 !important; +} +.com { color: #999 !important; } +.ignore-none { color: #999; font-weight: normal; } + +.wrapper { + min-height: 100%; + height: auto !important; + height: 100%; + margin: 0 auto -48px; +} +.footer, .push { + height: 48px; +} diff --git a/coverage/lcov-report/block-navigation.js b/coverage/lcov-report/block-navigation.js new file mode 100644 index 000000000..cc1213023 --- /dev/null +++ b/coverage/lcov-report/block-navigation.js @@ -0,0 +1,87 @@ +/* eslint-disable */ +var jumpToCode = (function init() { + // Classes of code we would like to highlight in the file view + var missingCoverageClasses = ['.cbranch-no', '.cstat-no', '.fstat-no']; + + // Elements to highlight in the file listing view + var fileListingElements = ['td.pct.low']; + + // We don't want to select elements that are direct descendants of another match + var notSelector = ':not(' + missingCoverageClasses.join('):not(') + ') > '; // becomes `:not(a):not(b) > ` + + // Selecter that finds elements on the page to which we can jump + var selector = + fileListingElements.join(', ') + + ', ' + + notSelector + + missingCoverageClasses.join(', ' + notSelector); // becomes `:not(a):not(b) > a, :not(a):not(b) > b` + + // The NodeList of matching elements + var missingCoverageElements = document.querySelectorAll(selector); + + var currentIndex; + + function toggleClass(index) { + missingCoverageElements + .item(currentIndex) + .classList.remove('highlighted'); + missingCoverageElements.item(index).classList.add('highlighted'); + } + + function makeCurrent(index) { + toggleClass(index); + currentIndex = index; + missingCoverageElements.item(index).scrollIntoView({ + behavior: 'smooth', + block: 'center', + inline: 'center' + }); + } + + function goToPrevious() { + var nextIndex = 0; + if (typeof currentIndex !== 'number' || currentIndex === 0) { + nextIndex = missingCoverageElements.length - 1; + } else if (missingCoverageElements.length > 1) { + nextIndex = currentIndex - 1; + } + + makeCurrent(nextIndex); + } + + function goToNext() { + var nextIndex = 0; + + if ( + typeof currentIndex === 'number' && + currentIndex < missingCoverageElements.length - 1 + ) { + nextIndex = currentIndex + 1; + } + + makeCurrent(nextIndex); + } + + return function jump(event) { + if ( + document.getElementById('fileSearch') === document.activeElement && + document.activeElement != null + ) { + // if we're currently focused on the search input, we don't want to navigate + return; + } + + switch (event.which) { + case 78: // n + case 74: // j + goToNext(); + break; + case 66: // b + case 75: // k + case 80: // p + goToPrevious(); + break; + } + }; +})(); +window.addEventListener('keydown', jumpToCode); diff --git a/coverage/lcov-report/favicon.png b/coverage/lcov-report/favicon.png new file mode 100644 index 000000000..669181783 Binary files /dev/null and b/coverage/lcov-report/favicon.png differ diff --git a/coverage/lcov-report/index.html b/coverage/lcov-report/index.html new file mode 100644 index 000000000..ddec29596 --- /dev/null +++ b/coverage/lcov-report/index.html @@ -0,0 +1,116 @@ + + + + + + Code coverage report for All files + + + + + + + + + +
+
+

All files

+
+ +
+ 69.34% + Statements + 95/137 +
+ + +
+ 63.63% + Branches + 21/33 +
+ + +
+ 63.63% + Functions + 14/22 +
+ + +
+ 70% + Lines + 91/130 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
index.js +
+
69.34%95/13763.63%21/3363.63%14/2270%91/130
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/index.js.html b/coverage/lcov-report/index.js.html new file mode 100644 index 000000000..87e7cf884 --- /dev/null +++ b/coverage/lcov-report/index.js.html @@ -0,0 +1,1027 @@ + + + + + + Code coverage report for index.js + + + + + + + + + +
+
+

All files index.js

+
+ +
+ 69.34% + Statements + 95/137 +
+ + +
+ 63.63% + Branches + 21/33 +
+ + +
+ 63.63% + Functions + 14/22 +
+ + +
+ 70% + Lines + 91/130 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284 +285 +286 +287 +288 +289 +290 +291 +292 +293 +294 +295 +296 +297 +298 +299 +300 +301 +302 +303 +304 +305 +306 +307 +308 +309 +310 +311 +312 +313 +314 +315  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +1x +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +1x +1x +1x +1x +  +  +  +  +  +1x +1x +1x +1x +1x +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +1x +1x +8x +4x +2x +2x +  +2x +  +4x +2x +1x +  +1x +  +  +2x +  +  +1x +1x +1x +  +  +  +1x +1x +1x +1x +1x +  +  +  +  +  +  +1x +1x +1x +  +1x +2x +108x +  +  +  +  +  +  +  +2x +  +  +1x +2x +2x +2x +  +  +1x +  +  +  +2x +2x +2x +2x +2x +2x +2x +  +  +2x +2x +2x +  +2x +26x +  +  +2x +2x +  +2x +54x +54x +54x +  +54x +54x +54x +  +  +  +  +54x +54x +  +54x +54x +54x +54x +54x +54x +  +54x +24x +  +30x +30x +  +  +  +2x +2x +1861x +30x +30x +  +  +2x +2x +  +  +  +  +  +  +  +  +  +2x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +2x +2x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  + 
// Copyright (c) 2018 ml5
+//
+// This software is released under the MIT License.
+// https://opensource.org/licenses/MIT
+ 
+/* eslint prefer-destructuring: ["error", {AssignmentExpression: {array: false}}] */
+/* eslint no-await-in-loop: "off" */
+/*
+A LSTM Generator: Run inference mode for a pre-trained LSTM.
+*/
+ 
+import * as tf from "@tensorflow/tfjs";
+import axios from "axios";
+import sampleFromDistribution from "./../utils/sample";
+import CheckpointLoader from "../utils/checkpointLoader";
+import callCallback from "../utils/callcallback";
+ 
+const regexCell = /cell_[0-9]|lstm_[0-9]/gi;
+const regexWeights = /weights|weight|kernel|kernels|w/gi;
+const regexFullyConnected = /softmax/gi;
+ 
+class CharRNN {
+  /**
+   * Create a CharRNN.
+   * @param {String} modelPath - The path to the trained charRNN model.
+   * @param {function} callback  - Optional. A callback to be called once
+   *    the model has loaded. If no callback is provided, it will return a
+   *    promise that will be resolved once the model has loaded.
+   */
+  constructor(modelPath, callback) {
+    /**
+     * Boolean value that specifies if the model has loaded.
+     * @type {boolean}
+     * @public
+     */
+    this.ready = false;
+ 
+    /**
+     * The pre-trained charRNN model.
+     * @type {model}
+     * @public
+     */
+    this.model = {};
+    this.cellsAmount = 0;
+    this.cells = [];
+    this.zeroState = { c: [], h: [] };
+    /**
+     * The vocabulary size (or total number of possible characters).
+     * @type {c: Array, h: Array}
+     * @public
+     */
+    this.state = { c: [], h: [] };
+    this.vocab = {};
+    this.vocabSize = 0;
+    this.probabilities = [];
+    this.defaults = {
+      seed: "a", // TODO: use no seed by default
+      length: 20,
+      temperature: 0.5,
+      stateful: false,
+    };
+ 
+    this.ready = callCallback(this.loadCheckpoints(modelPath), callback);
+    // this.then = this.ready.then.bind(this.ready);
+  }
+ 
+  resetState() {
+    this.state = this.zeroState;
+  }
+ 
+  setState(state) {
+    this.state = state;
+  }
+ 
+  getState() {
+    return this.state;
+  }
+ 
+  async loadCheckpoints(path) {
+    const reader = new CheckpointLoader(path);
+    const vars = await reader.getAllVariables();
+    Object.keys(vars).forEach(key => {
+      if (key.match(regexCell)) {
+        if (key.match(regexWeights)) {
+          this.model[`Kernel_${key.match(/[0-9]/)[0]}`] = vars[key];
+          this.cellsAmount += 1;
+        } else {
+          this.model[`Bias_${key.match(/[0-9]/)[0]}`] = vars[key];
+        }
+      } else if (key.match(regexFullyConnected)) {
+        if (key.match(regexWeights)) {
+          this.model.fullyConnectedWeights = vars[key];
+        } else {
+          this.model.fullyConnectedBiases = vars[key];
+        }
+      } else {
+        this.model[key] = vars[key];
+      }
+    });
+    await this.loadVocab(path);
+    await this.initCells();
+    return this;
+  }
+ 
+  async loadVocab(path) {
+    try {
+      const { data } = await axios.get(`${path}/vocab.json`);
+      this.vocab = data;
+      this.vocabSize = Object.keys(data).length;
+      return this.vocab;
+    } catch (err) {
+      return err;
+    }
+  }
+ 
+  async initCells() {
+    this.cells = [];
+    this.zeroState = { c: [], h: [] };
+    const forgetBias = tf.tensor(1.0);
+ 
+    const lstm = i => {
+      const cell = (DATA, C, H) =>
+        tf.basicLSTMCell(
+          forgetBias,
+          this.model[`Kernel_${i}`],
+          this.model[`Bias_${i}`],
+          DATA,
+          C,
+          H,
+        );
+      return cell;
+    };
+ 
+    for (let i = 0; i < this.cellsAmount; i += 1) {
+      this.zeroState.c.push(tf.zeros([1, this.model[`Bias_${i}`].shape[0] / 4]));
+      this.zeroState.h.push(tf.zeros([1, this.model[`Bias_${i}`].shape[0] / 4]));
+      this.cells.push(lstm(i));
+    }
+ 
+    this.state = this.zeroState;
+  }
+ 
+  async generateInternal(options) {
+    await this.ready;
+    const seed = options.seed || this.defaults.seed;
+    const length = +options.length || this.defaults.length;
+    const temperature = +options.temperature || this.defaults.temperature;
+    const stateful = options.stateful || this.defaults.stateful;
+    if (!stateful) {
+      this.state = this.zeroState;
+    }
+ 
+    const results = [];
+    const userInput = Array.from(seed);
+    const encodedInput = [];
+ 
+    userInput.forEach(char => {
+      encodedInput.push(this.vocab[char]);
+    });
+ 
+    let input = encodedInput[0];
+    let probabilitiesNormalized = []; // will contain final probabilities (normalized)
+ 
+    for (let i = 0; i < userInput.length + length + -1; i += 1) {
+      const onehotBuffer = await tf.buffer([1, this.vocabSize]);
+      onehotBuffer.set(1.0, 0, input);
+      const onehot = onehotBuffer.toTensor();
+      let output;
+      if (this.model.embedding) {
+        const embedded = tf.matMul(onehot, this.model.embedding);
+        output = tf.multiRNNCell(this.cells, embedded, this.state.c, this.state.h);
+      } else E{
+        output = tf.multiRNNCell(this.cells, onehot, this.state.c, this.state.h);
+      }
+ 
+      this.state.c = output[0];
+      this.state.h = output[1];
+ 
+      const outputH = this.state.h[1];
+      const weightedResult = tf.matMul(outputH, this.model.fullyConnectedWeights);
+      const logits = tf.add(weightedResult, this.model.fullyConnectedBiases);
+      const divided = tf.div(logits, tf.tensor(temperature));
+      const probabilities = tf.exp(divided);
+      probabilitiesNormalized = await tf.div(probabilities, tf.sum(probabilities)).data();
+ 
+      if (i < userInput.length - 1) {
+        input = encodedInput[i + 1];
+      } else {
+        input = sampleFromDistribution(probabilitiesNormalized);
+        results.push(input);
+      }
+    }
+ 
+    let generated = "";
+    results.forEach(char => {
+      const mapped = Object.keys(this.vocab).find(key => this.vocab[key] === char);
+      if (mapped) {
+        generated += mapped;
+      }
+    });
+    this.probabilities = probabilitiesNormalized;
+    return {
+      sample: generated,
+      state: this.state,
+    };
+  }
+ 
+  /**
+   * Reset the model state.
+   */
+  reset() {
+    this.state = this.zeroState;
+  }
+ 
+  /**
+   * @typedef {Object} options
+   * @property {String} seed
+   * @property {number} length
+   * @property {number} temperature
+   */
+ 
+  // stateless
+  /**
+   * Generates content in a stateless manner, based on some initial text
+   *    (known as a "seed"). Returns a string.
+   * @param {options} options - An object specifying the input parameters of
+   *    seed, length and temperature. Default length is 20, temperature is 0.5
+   *    and seed is a random character from the model. The object should look like
+   *    this:
+   * @param {function} callback - Optional. A function to be called when the model
+   *    has generated content. If no callback is provided, it will return a promise
+   *    that will be resolved once the model has generated new content.
+   */
+  async generate(options, callback) {
+    this.reset();
+    return callCallback(this.generateInternal(options), callback);
+  }
+ 
+  // stateful
+  /**
+   * Predict the next character based on the model's current state.
+   * @param {number} temp
+   * @param {function} callback - Optional. A function to be called when the
+   *    model finished adding the seed. If no callback is provided, it will
+   *    return a promise that will be resolved once the prediction has been generated.
+   */
+  async predict(temp, callback) {
+    let probabilitiesNormalized = [];
+    const temperature = temp > 0 ? temp : 0.1;
+    const outputH = this.state.h[1];
+    const weightedResult = tf.matMul(outputH, this.model.fullyConnectedWeights);
+    const logits = tf.add(weightedResult, this.model.fullyConnectedBiases);
+    const divided = tf.div(logits, tf.tensor(temperature));
+    const probabilities = tf.exp(divided);
+    probabilitiesNormalized = await tf.div(probabilities, tf.sum(probabilities)).data();
+ 
+    const sample = sampleFromDistribution(probabilitiesNormalized);
+    const result = Object.keys(this.vocab).find(key => this.vocab[key] === sample);
+    this.probabilities = probabilitiesNormalized;
+    if (callback) {
+      callback(result);
+    }
+    /* eslint max-len: ["error", { "code": 180 }] */
+    const pm = Object.keys(this.vocab).map(c => ({
+      char: c,
+      probability: this.probabilities[this.vocab[c]],
+    }));
+    return {
+      sample: result,
+      probabilities: pm,
+    };
+  }
+ 
+  /**
+   * Feed a string of characters to the model state.
+   * @param {String} inputSeed - A string to feed the charRNN model state.
+   * @param {function} callback  - Optional. A function to be called when
+   *    the model finished adding the seed. If no callback is provided, it
+   *    will return a promise that will be resolved once seed has been fed.
+   */
+  async feed(inputSeed, callback) {
+    await this.ready;
+    const seed = Array.from(inputSeed);
+    const encodedInput = [];
+ 
+    seed.forEach(char => {
+      encodedInput.push(this.vocab[char]);
+    });
+ 
+    let input = encodedInput[0];
+    for (let i = 0; i < seed.length; i += 1) {
+      const onehotBuffer = await tf.buffer([1, this.vocabSize]);
+      onehotBuffer.set(1.0, 0, input);
+      const onehot = onehotBuffer.toTensor();
+      let output;
+      if (this.model.embedding) {
+        const embedded = tf.matMul(onehot, this.model.embedding);
+        output = tf.multiRNNCell(this.cells, embedded, this.state.c, this.state.h);
+      } else {
+        output = tf.multiRNNCell(this.cells, onehot, this.state.c, this.state.h);
+      }
+      this.state.c = output[0];
+      this.state.h = output[1];
+      input = encodedInput[i];
+    }
+    if (callback) {
+      callback();
+    }
+  }
+}
+ 
+const charRNN = (modelPath = "./", callback) => new CharRNN(modelPath, callback);
+ 
+export default charRNN;
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/prettify.css b/coverage/lcov-report/prettify.css new file mode 100644 index 000000000..b317a7cda --- /dev/null +++ b/coverage/lcov-report/prettify.css @@ -0,0 +1 @@ +.pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee} diff --git a/coverage/lcov-report/prettify.js b/coverage/lcov-report/prettify.js new file mode 100644 index 000000000..b3225238f --- /dev/null +++ b/coverage/lcov-report/prettify.js @@ -0,0 +1,2 @@ +/* eslint-disable */ +window.PR_SHOULD_USE_CONTINUATION=true;(function(){var h=["break,continue,do,else,for,if,return,while"];var u=[h,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"];var p=[u,"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"];var l=[p,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"];var x=[p,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"];var R=[x,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"];var r="all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes";var w=[p,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"];var s="caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END";var I=[h,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"];var f=[h,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"];var H=[h,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"];var A=[l,R,w,s+I,f,H];var e=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/;var C="str";var z="kwd";var j="com";var O="typ";var G="lit";var L="pun";var F="pln";var m="tag";var E="dec";var J="src";var P="atn";var n="atv";var N="nocode";var M="(?:^^\\.?|[+-]|\\!|\\!=|\\!==|\\#|\\%|\\%=|&|&&|&&=|&=|\\(|\\*|\\*=|\\+=|\\,|\\-=|\\->|\\/|\\/=|:|::|\\;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|\\?|\\@|\\[|\\^|\\^=|\\^\\^|\\^\\^=|\\{|\\||\\|=|\\|\\||\\|\\|=|\\~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*";function k(Z){var ad=0;var S=false;var ac=false;for(var V=0,U=Z.length;V122)){if(!(al<65||ag>90)){af.push([Math.max(65,ag)|32,Math.min(al,90)|32])}if(!(al<97||ag>122)){af.push([Math.max(97,ag)&~32,Math.min(al,122)&~32])}}}}af.sort(function(av,au){return(av[0]-au[0])||(au[1]-av[1])});var ai=[];var ap=[NaN,NaN];for(var ar=0;arat[0]){if(at[1]+1>at[0]){an.push("-")}an.push(T(at[1]))}}an.push("]");return an.join("")}function W(al){var aj=al.source.match(new RegExp("(?:\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]|\\\\u[A-Fa-f0-9]{4}|\\\\x[A-Fa-f0-9]{2}|\\\\[0-9]+|\\\\[^ux0-9]|\\(\\?[:!=]|[\\(\\)\\^]|[^\\x5B\\x5C\\(\\)\\^]+)","g"));var ah=aj.length;var an=[];for(var ak=0,am=0;ak=2&&ai==="["){aj[ak]=X(ag)}else{if(ai!=="\\"){aj[ak]=ag.replace(/[a-zA-Z]/g,function(ao){var ap=ao.charCodeAt(0);return"["+String.fromCharCode(ap&~32,ap|32)+"]"})}}}}return aj.join("")}var aa=[];for(var V=0,U=Z.length;V=0;){S[ac.charAt(ae)]=Y}}var af=Y[1];var aa=""+af;if(!ag.hasOwnProperty(aa)){ah.push(af);ag[aa]=null}}ah.push(/[\0-\uffff]/);V=k(ah)})();var X=T.length;var W=function(ah){var Z=ah.sourceCode,Y=ah.basePos;var ad=[Y,F];var af=0;var an=Z.match(V)||[];var aj={};for(var ae=0,aq=an.length;ae=5&&"lang-"===ap.substring(0,5);if(am&&!(ai&&typeof ai[1]==="string")){am=false;ap=J}if(!am){aj[ag]=ap}}var ab=af;af+=ag.length;if(!am){ad.push(Y+ab,ap)}else{var al=ai[1];var ak=ag.indexOf(al);var ac=ak+al.length;if(ai[2]){ac=ag.length-ai[2].length;ak=ac-al.length}var ar=ap.substring(5);B(Y+ab,ag.substring(0,ak),W,ad);B(Y+ab+ak,al,q(ar,al),ad);B(Y+ab+ac,ag.substring(ac),W,ad)}}ah.decorations=ad};return W}function i(T){var W=[],S=[];if(T.tripleQuotedStrings){W.push([C,/^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,null,"'\""])}else{if(T.multiLineStrings){W.push([C,/^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,null,"'\"`"])}else{W.push([C,/^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,null,"\"'"])}}if(T.verbatimStrings){S.push([C,/^@\"(?:[^\"]|\"\")*(?:\"|$)/,null])}var Y=T.hashComments;if(Y){if(T.cStyleComments){if(Y>1){W.push([j,/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,null,"#"])}else{W.push([j,/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\r\n]*)/,null,"#"])}S.push([C,/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,null])}else{W.push([j,/^#[^\r\n]*/,null,"#"])}}if(T.cStyleComments){S.push([j,/^\/\/[^\r\n]*/,null]);S.push([j,/^\/\*[\s\S]*?(?:\*\/|$)/,null])}if(T.regexLiterals){var X=("/(?=[^/*])(?:[^/\\x5B\\x5C]|\\x5C[\\s\\S]|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+/");S.push(["lang-regex",new RegExp("^"+M+"("+X+")")])}var V=T.types;if(V){S.push([O,V])}var U=(""+T.keywords).replace(/^ | $/g,"");if(U.length){S.push([z,new RegExp("^(?:"+U.replace(/[\s,]+/g,"|")+")\\b"),null])}W.push([F,/^\s+/,null," \r\n\t\xA0"]);S.push([G,/^@[a-z_$][a-z_$@0-9]*/i,null],[O,/^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\w+_t\b)/,null],[F,/^[a-z_$][a-z_$@0-9]*/i,null],[G,new RegExp("^(?:0x[a-f0-9]+|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)(?:e[+\\-]?\\d+)?)[a-z]*","i"),null,"0123456789"],[F,/^\\[\s\S]?/,null],[L,/^.[^\s\w\.$@\'\"\`\/\#\\]*/,null]);return g(W,S)}var K=i({keywords:A,hashComments:true,cStyleComments:true,multiLineStrings:true,regexLiterals:true});function Q(V,ag){var U=/(?:^|\s)nocode(?:\s|$)/;var ab=/\r\n?|\n/;var ac=V.ownerDocument;var S;if(V.currentStyle){S=V.currentStyle.whiteSpace}else{if(window.getComputedStyle){S=ac.defaultView.getComputedStyle(V,null).getPropertyValue("white-space")}}var Z=S&&"pre"===S.substring(0,3);var af=ac.createElement("LI");while(V.firstChild){af.appendChild(V.firstChild)}var W=[af];function ae(al){switch(al.nodeType){case 1:if(U.test(al.className)){break}if("BR"===al.nodeName){ad(al);if(al.parentNode){al.parentNode.removeChild(al)}}else{for(var an=al.firstChild;an;an=an.nextSibling){ae(an)}}break;case 3:case 4:if(Z){var am=al.nodeValue;var aj=am.match(ab);if(aj){var ai=am.substring(0,aj.index);al.nodeValue=ai;var ah=am.substring(aj.index+aj[0].length);if(ah){var ak=al.parentNode;ak.insertBefore(ac.createTextNode(ah),al.nextSibling)}ad(al);if(!ai){al.parentNode.removeChild(al)}}}break}}function ad(ak){while(!ak.nextSibling){ak=ak.parentNode;if(!ak){return}}function ai(al,ar){var aq=ar?al.cloneNode(false):al;var ao=al.parentNode;if(ao){var ap=ai(ao,1);var an=al.nextSibling;ap.appendChild(aq);for(var am=an;am;am=an){an=am.nextSibling;ap.appendChild(am)}}return aq}var ah=ai(ak.nextSibling,0);for(var aj;(aj=ah.parentNode)&&aj.nodeType===1;){ah=aj}W.push(ah)}for(var Y=0;Y=S){ah+=2}if(V>=ap){Z+=2}}}var t={};function c(U,V){for(var S=V.length;--S>=0;){var T=V[S];if(!t.hasOwnProperty(T)){t[T]=U}else{if(window.console){console.warn("cannot override language handler %s",T)}}}}function q(T,S){if(!(T&&t.hasOwnProperty(T))){T=/^\s*]*(?:>|$)/],[j,/^<\!--[\s\S]*?(?:-\->|$)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],[L,/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),["default-markup","htm","html","mxml","xhtml","xml","xsl"]);c(g([[F,/^[\s]+/,null," \t\r\n"],[n,/^(?:\"[^\"]*\"?|\'[^\']*\'?)/,null,"\"'"]],[[m,/^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],[P,/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],[L,/^[=<>\/]+/],["lang-js",/^on\w+\s*=\s*\"([^\"]+)\"/i],["lang-js",/^on\w+\s*=\s*\'([^\']+)\'/i],["lang-js",/^on\w+\s*=\s*([^\"\'>\s]+)/i],["lang-css",/^style\s*=\s*\"([^\"]+)\"/i],["lang-css",/^style\s*=\s*\'([^\']+)\'/i],["lang-css",/^style\s*=\s*([^\"\'>\s]+)/i]]),["in.tag"]);c(g([],[[n,/^[\s\S]+/]]),["uq.val"]);c(i({keywords:l,hashComments:true,cStyleComments:true,types:e}),["c","cc","cpp","cxx","cyc","m"]);c(i({keywords:"null,true,false"}),["json"]);c(i({keywords:R,hashComments:true,cStyleComments:true,verbatimStrings:true,types:e}),["cs"]);c(i({keywords:x,cStyleComments:true}),["java"]);c(i({keywords:H,hashComments:true,multiLineStrings:true}),["bsh","csh","sh"]);c(i({keywords:I,hashComments:true,multiLineStrings:true,tripleQuotedStrings:true}),["cv","py"]);c(i({keywords:s,hashComments:true,multiLineStrings:true,regexLiterals:true}),["perl","pl","pm"]);c(i({keywords:f,hashComments:true,multiLineStrings:true,regexLiterals:true}),["rb"]);c(i({keywords:w,cStyleComments:true,regexLiterals:true}),["js"]);c(i({keywords:r,hashComments:3,cStyleComments:true,multilineStrings:true,tripleQuotedStrings:true,regexLiterals:true}),["coffee"]);c(g([],[[C,/^[\s\S]+/]]),["regex"]);function d(V){var U=V.langExtension;try{var S=a(V.sourceNode);var T=S.sourceCode;V.sourceCode=T;V.spans=S.spans;V.basePos=0;q(U,T)(V);D(V)}catch(W){if("console" in window){console.log(W&&W.stack?W.stack:W)}}}function y(W,V,U){var S=document.createElement("PRE");S.innerHTML=W;if(U){Q(S,U)}var T={langExtension:V,numberLines:U,sourceNode:S};d(T);return S.innerHTML}function b(ad){function Y(af){return document.getElementsByTagName(af)}var ac=[Y("pre"),Y("code"),Y("xmp")];var T=[];for(var aa=0;aa=0){var ah=ai.match(ab);var am;if(!ah&&(am=o(aj))&&"CODE"===am.tagName){ah=am.className.match(ab)}if(ah){ah=ah[1]}var al=false;for(var ak=aj.parentNode;ak;ak=ak.parentNode){if((ak.tagName==="pre"||ak.tagName==="code"||ak.tagName==="xmp")&&ak.className&&ak.className.indexOf("prettyprint")>=0){al=true;break}}if(!al){var af=aj.className.match(/\blinenums\b(?::(\d+))?/);af=af?af[1]&&af[1].length?+af[1]:true:false;if(af){Q(aj,af)}S={langExtension:ah,sourceNode:aj,numberLines:af};d(S)}}}if(X]*(?:>|$)/],[PR.PR_COMMENT,/^<\!--[\s\S]*?(?:-\->|$)/],[PR.PR_PUNCTUATION,/^(?:<[%?]|[%?]>)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-handlebars",/^]*type\s*=\s*['"]?text\/x-handlebars-template['"]?\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i],[PR.PR_DECLARATION,/^{{[#^>/]?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{&?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{{>?\s*[\w.][^}]*}}}/],[PR.PR_COMMENT,/^{{![^}]*}}/]]),["handlebars","hbs"]);PR.registerLangHandler(PR.createSimpleLexer([[PR.PR_PLAIN,/^[ \t\r\n\f]+/,null," \t\r\n\f"]],[[PR.PR_STRING,/^\"(?:[^\n\r\f\\\"]|\\(?:\r\n?|\n|\f)|\\[\s\S])*\"/,null],[PR.PR_STRING,/^\'(?:[^\n\r\f\\\']|\\(?:\r\n?|\n|\f)|\\[\s\S])*\'/,null],["lang-css-str",/^url\(([^\)\"\']*)\)/i],[PR.PR_KEYWORD,/^(?:url|rgb|\!important|@import|@page|@media|@charset|inherit)(?=[^\-\w]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|(?:\\[0-9a-f]+ ?))(?:[_a-z0-9\-]|\\(?:\\[0-9a-f]+ ?))*)\s*:/i],[PR.PR_COMMENT,/^\/\*[^*]*\*+(?:[^\/*][^*]*\*+)*\//],[PR.PR_COMMENT,/^(?:)/],[PR.PR_LITERAL,/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],[PR.PR_LITERAL,/^#(?:[0-9a-f]{3}){1,2}/i],[PR.PR_PLAIN,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i],[PR.PR_PUNCTUATION,/^[^\s\w\'\"]+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_KEYWORD,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_STRING,/^[^\)\"\']+/]]),["css-str"]); diff --git a/coverage/lcov-report/sort-arrow-sprite.png b/coverage/lcov-report/sort-arrow-sprite.png new file mode 100644 index 000000000..03f704a60 Binary files /dev/null and b/coverage/lcov-report/sort-arrow-sprite.png differ diff --git a/coverage/lcov-report/sorter.js b/coverage/lcov-report/sorter.js new file mode 100644 index 000000000..2bb296a8c --- /dev/null +++ b/coverage/lcov-report/sorter.js @@ -0,0 +1,196 @@ +/* eslint-disable */ +var addSorting = (function() { + 'use strict'; + var cols, + currentSort = { + index: 0, + desc: false + }; + + // returns the summary table element + function getTable() { + return document.querySelector('.coverage-summary'); + } + // returns the thead element of the summary table + function getTableHeader() { + return getTable().querySelector('thead tr'); + } + // returns the tbody element of the summary table + function getTableBody() { + return getTable().querySelector('tbody'); + } + // returns the th element for nth column + function getNthColumn(n) { + return getTableHeader().querySelectorAll('th')[n]; + } + + function onFilterInput() { + const searchValue = document.getElementById('fileSearch').value; + const rows = document.getElementsByTagName('tbody')[0].children; + for (let i = 0; i < rows.length; i++) { + const row = rows[i]; + if ( + row.textContent + .toLowerCase() + .includes(searchValue.toLowerCase()) + ) { + row.style.display = ''; + } else { + row.style.display = 'none'; + } + } + } + + // loads the search box + function addSearchBox() { + var template = document.getElementById('filterTemplate'); + var templateClone = template.content.cloneNode(true); + templateClone.getElementById('fileSearch').oninput = onFilterInput; + template.parentElement.appendChild(templateClone); + } + + // loads all columns + function loadColumns() { + var colNodes = getTableHeader().querySelectorAll('th'), + colNode, + cols = [], + col, + i; + + for (i = 0; i < colNodes.length; i += 1) { + colNode = colNodes[i]; + col = { + key: colNode.getAttribute('data-col'), + sortable: !colNode.getAttribute('data-nosort'), + type: colNode.getAttribute('data-type') || 'string' + }; + cols.push(col); + if (col.sortable) { + col.defaultDescSort = col.type === 'number'; + colNode.innerHTML = + colNode.innerHTML + ''; + } + } + return cols; + } + // attaches a data attribute to every tr element with an object + // of data values keyed by column name + function loadRowData(tableRow) { + var tableCols = tableRow.querySelectorAll('td'), + colNode, + col, + data = {}, + i, + val; + for (i = 0; i < tableCols.length; i += 1) { + colNode = tableCols[i]; + col = cols[i]; + val = colNode.getAttribute('data-value'); + if (col.type === 'number') { + val = Number(val); + } + data[col.key] = val; + } + return data; + } + // loads all row data + function loadData() { + var rows = getTableBody().querySelectorAll('tr'), + i; + + for (i = 0; i < rows.length; i += 1) { + rows[i].data = loadRowData(rows[i]); + } + } + // sorts the table using the data for the ith column + function sortByIndex(index, desc) { + var key = cols[index].key, + sorter = function(a, b) { + a = a.data[key]; + b = b.data[key]; + return a < b ? -1 : a > b ? 1 : 0; + }, + finalSorter = sorter, + tableBody = document.querySelector('.coverage-summary tbody'), + rowNodes = tableBody.querySelectorAll('tr'), + rows = [], + i; + + if (desc) { + finalSorter = function(a, b) { + return -1 * sorter(a, b); + }; + } + + for (i = 0; i < rowNodes.length; i += 1) { + rows.push(rowNodes[i]); + tableBody.removeChild(rowNodes[i]); + } + + rows.sort(finalSorter); + + for (i = 0; i < rows.length; i += 1) { + tableBody.appendChild(rows[i]); + } + } + // removes sort indicators for current column being sorted + function removeSortIndicators() { + var col = getNthColumn(currentSort.index), + cls = col.className; + + cls = cls.replace(/ sorted$/, '').replace(/ sorted-desc$/, ''); + col.className = cls; + } + // adds sort indicators for current column being sorted + function addSortIndicators() { + getNthColumn(currentSort.index).className += currentSort.desc + ? ' sorted-desc' + : ' sorted'; + } + // adds event listeners for all sorter widgets + function enableUI() { + var i, + el, + ithSorter = function ithSorter(i) { + var col = cols[i]; + + return function() { + var desc = col.defaultDescSort; + + if (currentSort.index === i) { + desc = !currentSort.desc; + } + sortByIndex(i, desc); + removeSortIndicators(); + currentSort.index = i; + currentSort.desc = desc; + addSortIndicators(); + }; + }; + for (i = 0; i < cols.length; i += 1) { + if (cols[i].sortable) { + // add the click event handler on the th so users + // dont have to click on those tiny arrows + el = getNthColumn(i).querySelector('.sorter').parentElement; + if (el.addEventListener) { + el.addEventListener('click', ithSorter(i)); + } else { + el.attachEvent('onclick', ithSorter(i)); + } + } + } + } + // adds sorting functionality to the UI + return function() { + if (!getTable()) { + return; + } + cols = loadColumns(); + loadData(); + addSearchBox(); + addSortIndicators(); + enableUI(); + }; +})(); + +window.addEventListener('load', addSorting); diff --git a/coverage/lcov.info b/coverage/lcov.info new file mode 100644 index 000000000..c2fb89544 --- /dev/null +++ b/coverage/lcov.info @@ -0,0 +1,216 @@ +TN: +SF:src/CharRNN/index.js +FN:30,(anonymous_0) +FN:67,(anonymous_1) +FN:71,(anonymous_2) +FN:75,(anonymous_3) +FN:79,(anonymous_4) +FN:82,(anonymous_5) +FN:105,(anonymous_6) +FN:116,(anonymous_7) +FN:121,(anonymous_8) +FN:122,(anonymous_9) +FN:143,(anonymous_10) +FN:157,(anonymous_11) +FN:195,(anonymous_12) +FN:196,(anonymous_13) +FN:211,(anonymous_14) +FN:234,(anonymous_15) +FN:247,(anonymous_16) +FN:258,(anonymous_17) +FN:264,(anonymous_18) +FN:281,(anonymous_19) +FN:286,(anonymous_20) +FN:312,(anonymous_21) +FNF:22 +FNH:14 +FNDA:1,(anonymous_0) +FNDA:0,(anonymous_1) +FNDA:0,(anonymous_2) +FNDA:0,(anonymous_3) +FNDA:1,(anonymous_4) +FNDA:8,(anonymous_5) +FNDA:1,(anonymous_6) +FNDA:1,(anonymous_7) +FNDA:2,(anonymous_8) +FNDA:108,(anonymous_9) +FNDA:2,(anonymous_10) +FNDA:26,(anonymous_11) +FNDA:30,(anonymous_12) +FNDA:1861,(anonymous_13) +FNDA:2,(anonymous_14) +FNDA:2,(anonymous_15) +FNDA:0,(anonymous_16) +FNDA:0,(anonymous_17) +FNDA:0,(anonymous_18) +FNDA:0,(anonymous_19) +FNDA:0,(anonymous_20) +FNDA:1,(anonymous_21) +DA:18,1 +DA:19,1 +DA:20,1 +DA:36,1 +DA:43,1 +DA:44,1 +DA:45,1 +DA:46,1 +DA:52,1 +DA:53,1 +DA:54,1 +DA:55,1 +DA:56,1 +DA:63,1 +DA:68,0 +DA:72,0 +DA:76,0 +DA:80,1 +DA:81,1 +DA:82,1 +DA:83,8 +DA:84,4 +DA:85,2 +DA:86,2 +DA:88,2 +DA:90,4 +DA:91,2 +DA:92,1 +DA:94,1 +DA:97,2 +DA:100,1 +DA:101,1 +DA:102,1 +DA:106,1 +DA:107,1 +DA:108,1 +DA:109,1 +DA:110,1 +DA:112,0 +DA:117,1 +DA:118,1 +DA:119,1 +DA:121,1 +DA:122,2 +DA:123,108 +DA:131,2 +DA:134,1 +DA:135,2 +DA:136,2 +DA:137,2 +DA:140,1 +DA:144,2 +DA:145,2 +DA:146,2 +DA:147,2 +DA:148,2 +DA:149,2 +DA:150,2 +DA:153,2 +DA:154,2 +DA:155,2 +DA:157,2 +DA:158,26 +DA:161,2 +DA:162,2 +DA:164,2 +DA:165,54 +DA:166,54 +DA:167,54 +DA:169,54 +DA:170,54 +DA:171,54 +DA:173,0 +DA:176,54 +DA:177,54 +DA:179,54 +DA:180,54 +DA:181,54 +DA:182,54 +DA:183,54 +DA:184,54 +DA:186,54 +DA:187,24 +DA:189,30 +DA:190,30 +DA:194,2 +DA:195,2 +DA:196,1861 +DA:197,30 +DA:198,30 +DA:201,2 +DA:202,2 +DA:212,2 +DA:235,2 +DA:236,2 +DA:248,0 +DA:249,0 +DA:250,0 +DA:251,0 +DA:252,0 +DA:253,0 +DA:254,0 +DA:255,0 +DA:257,0 +DA:258,0 +DA:259,0 +DA:260,0 +DA:261,0 +DA:264,0 +DA:268,0 +DA:282,0 +DA:283,0 +DA:284,0 +DA:286,0 +DA:287,0 +DA:290,0 +DA:291,0 +DA:292,0 +DA:293,0 +DA:294,0 +DA:296,0 +DA:297,0 +DA:298,0 +DA:300,0 +DA:302,0 +DA:303,0 +DA:304,0 +DA:306,0 +DA:307,0 +DA:312,1 +LF:130 +LH:91 +BRDA:83,0,0,4 +BRDA:83,0,1,4 +BRDA:84,1,0,2 +BRDA:84,1,1,2 +BRDA:90,2,0,2 +BRDA:90,2,1,2 +BRDA:91,3,0,1 +BRDA:91,3,1,1 +BRDA:145,4,0,2 +BRDA:145,4,1,1 +BRDA:146,5,0,2 +BRDA:146,5,1,1 +BRDA:147,6,0,2 +BRDA:147,6,1,1 +BRDA:148,7,0,2 +BRDA:148,7,1,2 +BRDA:149,8,0,2 +BRDA:149,8,1,0 +BRDA:169,9,0,54 +BRDA:169,9,1,0 +BRDA:186,10,0,24 +BRDA:186,10,1,30 +BRDA:197,11,0,30 +BRDA:197,11,1,0 +BRDA:249,12,0,0 +BRDA:249,12,1,0 +BRDA:260,13,0,0 +BRDA:260,13,1,0 +BRDA:296,14,0,0 +BRDA:296,14,1,0 +BRDA:306,15,0,0 +BRDA:306,15,1,0 +BRDA:312,16,0,0 +BRF:33 +BRH:21 +end_of_record diff --git a/docs/reference/charrnn.md b/docs/reference/charrnn.md index 6c3822303..5f560ef89 100644 --- a/docs/reference/charrnn.md +++ b/docs/reference/charrnn.md @@ -159,9 +159,11 @@ charrnn.reset(); **p5 web editor** -* [CharRNN_Interactive](https://editor.p5js.org/ml5/sketches/CharRNN_Interactive) +Please be advised, that due to an incompatibility of the p5 web-editor and the weights that are used in this example, this example does not work in the p5 we-editor. +Please use the p5.js example locally. Learn more about how to run examples locally [here.](https://github.com/ml5js/ml5-library/blob/main/examples/README.md#setup) + **plain javascript** * [CharRNN_Interactive](https://github.com/ml5js/ml5-library/tree/main/examples/javascript/CharRNN/CharRNN_Interactive) diff --git a/docs/styleguide/maintenance-notes.md b/docs/styleguide/maintenance-notes.md index 99b934fd7..5d41c3caf 100644 --- a/docs/styleguide/maintenance-notes.md +++ b/docs/styleguide/maintenance-notes.md @@ -6,30 +6,28 @@ 1. make sure to tag it with one of the following in the PR: - SEMVER/patch + - e.g. `SEMVER/patch`: `0.8.11` would become -> `0.8.12` - SEMVER/minor + - e.g. `SEMVER/minor`: `0.8.11` would become -> `0.9.0` - SEMVER/major + - e.g. `SEMVER/major`: `0.8.11` would become -> `1.0.0` -## Before tagging a release releasing: bump the package version -1. open a PR to bump the package version: e.g. `git checkout -b v0.8.12` -2. bump the package version number that matches the `SEMVER/patch | SEMVER/minor | SEMVER/major` - - e.g. `SEMVER/patch`: `0.8.11` would become -> `0.8.12` - - e.g. `SEMVER/minor`: `0.8.11` would become -> `0.9.00` - - e.g. `SEMVER/major`: `0.8.11` would become -> `1.0.0` -3. run `npm i` <--- this makes sure your bumped package version makes it into the `package-lock.json` -4. run `npm run update:readme` <----- captures the version bump in the readme -5. run `git add .` -6. run `git commit -m "chore: bumps package"` -7. push this to your feature branch. -8. make a PR and merge to `main` +NOTE: if you are unsure quite likely it will be a `SEMVER/patch` for "...when you make backwards compatible bug fixes.". You can learn more about [Semantic Versioning](https://semver.org/). ## Once we merge the PR to `main`: + 1. simply go to the `releases` sidebar > Screen Shot 2022-01-21 at 12 58 26 PM 2. go to the latest draft and click the edit button Screen Shot 2022-01-21 at 12 58 31 PM -3. click: publish the release - - +3. click: publish the release -- this will trigger a github workflow that will: + * get the latest tag version + * update the package.json + * update the readme with the latest version (pulled from the package.json) + * run npm install + * add, commit, and push those changes to `main` + * build the library + * and publish to npm *** diff --git a/examples/CONTRIBUTING.md b/examples/CONTRIBUTING.md index d7353f77a..f12f2d8d2 100644 --- a/examples/CONTRIBUTING.md +++ b/examples/CONTRIBUTING.md @@ -24,7 +24,7 @@ Please refer to [#1](https://github.com/ml5js/ml5-examples/issues/1) (thanks [@d ## Organizing Examples of different features -If you're interested to make example, you can organize them as heirarchy like so: +If you're interested to make example, you can organize them as hierarchy like so: ``` /FeatureName diff --git a/examples/d3/KMeans/KMeans_GaussianClusterDemo/data/gaussian2d_3clusters.csv b/examples/d3/DBSCAN/DBSCAN_Cluster/data/gaussian2d_1.55clusters.csv similarity index 99% rename from examples/d3/KMeans/KMeans_GaussianClusterDemo/data/gaussian2d_3clusters.csv rename to examples/d3/DBSCAN/DBSCAN_Cluster/data/gaussian2d_1.55clusters.csv index 3976c0e52..072b7adac 100644 --- a/examples/d3/KMeans/KMeans_GaussianClusterDemo/data/gaussian2d_3clusters.csv +++ b/examples/d3/DBSCAN/DBSCAN_Cluster/data/gaussian2d_1.55clusters.csv @@ -1,4 +1,4 @@ -x1,x2 +x,y -7.849704268160314,-8.674808581953744 -8.69664575596503,-7.692212927859845 -1.0359915243020554,6.827713353515913 diff --git a/examples/d3/KMeans/KMeans_GaussianClusterDemo/data/gaussian2d_4clusters.csv b/examples/d3/DBSCAN/DBSCAN_Cluster/data/gaussian2d_1.56clusters.csv similarity index 99% rename from examples/d3/KMeans/KMeans_GaussianClusterDemo/data/gaussian2d_4clusters.csv rename to examples/d3/DBSCAN/DBSCAN_Cluster/data/gaussian2d_1.56clusters.csv index ae1b83fa1..789ee683f 100644 --- a/examples/d3/KMeans/KMeans_GaussianClusterDemo/data/gaussian2d_4clusters.csv +++ b/examples/d3/DBSCAN/DBSCAN_Cluster/data/gaussian2d_1.56clusters.csv @@ -1,4 +1,4 @@ -x1,x2 +x,y -10.718663580210745,9.900472871349784 -7.9399489058067685,10.718096194668659 -9.199206305612545,6.923022960440686 diff --git a/examples/d3/KMeans/KMeans_GaussianClusterDemo/data/gaussian2d_2clusters.csv b/examples/d3/DBSCAN/DBSCAN_Cluster/data/gaussian2d_2clusters.csv similarity index 99% rename from examples/d3/KMeans/KMeans_GaussianClusterDemo/data/gaussian2d_2clusters.csv rename to examples/d3/DBSCAN/DBSCAN_Cluster/data/gaussian2d_2clusters.csv index 9abaa0cd6..d25fe19cf 100644 --- a/examples/d3/KMeans/KMeans_GaussianClusterDemo/data/gaussian2d_2clusters.csv +++ b/examples/d3/DBSCAN/DBSCAN_Cluster/data/gaussian2d_2clusters.csv @@ -1,4 +1,4 @@ -x1,x2 +x,y 2.498895550686414,1.1683342316471301 5.073222450036444,0.8623713271387572 4.672790880324094,2.6418773621498803 diff --git a/examples/d3/KMeans/KMeans_GaussianClusterDemo/data/gaussian2d_circleclusters.csv b/examples/d3/DBSCAN/DBSCAN_Cluster/data/gaussian2d_circleclusters.csv similarity index 99% rename from examples/d3/KMeans/KMeans_GaussianClusterDemo/data/gaussian2d_circleclusters.csv rename to examples/d3/DBSCAN/DBSCAN_Cluster/data/gaussian2d_circleclusters.csv index efbf5fb70..e22dddb59 100644 --- a/examples/d3/KMeans/KMeans_GaussianClusterDemo/data/gaussian2d_circleclusters.csv +++ b/examples/d3/DBSCAN/DBSCAN_Cluster/data/gaussian2d_circleclusters.csv @@ -1,4 +1,4 @@ -x1,x2 +x,y -0.9914878645939103,0.12004373871846165 -0.8064234011393798,-0.5891152116668836 -0.4265373027932866,-0.6749570357883385 diff --git a/examples/d3/KMeans/KMeans_GaussianClusterDemo/data/gaussian2d_moonclusters.csv b/examples/d3/DBSCAN/DBSCAN_Cluster/data/gaussian2d_moonclusters.csv similarity index 99% rename from examples/d3/KMeans/KMeans_GaussianClusterDemo/data/gaussian2d_moonclusters.csv rename to examples/d3/DBSCAN/DBSCAN_Cluster/data/gaussian2d_moonclusters.csv index ad01d28a1..32dc2344d 100644 --- a/examples/d3/KMeans/KMeans_GaussianClusterDemo/data/gaussian2d_moonclusters.csv +++ b/examples/d3/DBSCAN/DBSCAN_Cluster/data/gaussian2d_moonclusters.csv @@ -1,4 +1,4 @@ -x1,x2 +x,y 2.001164955520126,0.43029947571735944 -0.6744557747817002,0.7365153394030783 0.13616835175111489,1.0001429333017973 diff --git a/examples/d3/DBSCAN/DBSCAN_Cluster/index.html b/examples/d3/DBSCAN/DBSCAN_Cluster/index.html new file mode 100644 index 000000000..876aa1575 --- /dev/null +++ b/examples/d3/DBSCAN/DBSCAN_Cluster/index.html @@ -0,0 +1,22 @@ + + + ml5.js DBSCAN example + + + + +
+

DBSCAN Example

+

DBSCAN is a density-based clustering non-parametric algorithm: given a set of points in some space, it groups together points that are closely packed together (points with many nearby neighbors), + marking as outliers points that lie alone in low-density regions (whose nearest neighbors are too far away). + DBSCAN is one of the most common clustering algorithms and also most cited in scientific literature. +

+
+ +
+
+
+
+ + + \ No newline at end of file diff --git a/examples/d3/DBSCAN/DBSCAN_Cluster/sketch.js b/examples/d3/DBSCAN/DBSCAN_Cluster/sketch.js new file mode 100644 index 000000000..9529ff098 --- /dev/null +++ b/examples/d3/DBSCAN/DBSCAN_Cluster/sketch.js @@ -0,0 +1,115 @@ +let dbscanModel; +const width = 640; +const height = 480; +const colDict = { + 0: "skyblue", + 1: "coral", + 2: "olive", + 3: "tan", + 4: "grey", +}; + +// ----- Initialize the example: ------ // +function init() { + // make all those nice buttons + createButtons(); + // start with 3 cluster + make(1.55); +} +init(); + +// STEP 1: +// create all the buttons +function createButtons() { + addClusterButton(1.55); + addClusterButton(1.56); + addClusterButton(2); + addClusterButton("circle"); + addClusterButton("moon"); +} + +// STEP 2: +// create the model +function make(eps) { + const options = { + eps: eps, + minPts: 3, + }; + // if moon or circle data, set the options to 0.1 and 0.16 eps + if (eps === "moon") { + options.eps = 0.1; + } else if (eps === "circle") { + options.eps = 0.16; + } + console.log(eps, options.eps); + + // get the path to the data in our data folder dynamically + const dataPath = `data/gaussian2d_${eps}clusters.csv`; + // create a new dbscan clustering each time on make() + dbscanModel = ml5.dbscan(dataPath, options, modelReady); +} + +// Step 3: +// when the model is ready, make the chart +function modelReady() { + console.log(dbscanModel.dataset); + makeChart(); +} + +// Step 4: +// use the fancy d3 to make magic +function makeChart() { + const { dataset } = dbscanModel; + // clear the chart each time + // less efficient, but simple + d3.select("svg").remove(); + + // reappend the svg to the chart area + const svg = d3 + .select("#chart") + .append("svg") + .attr("width", width) + .attr("height", height); + + // d[0] is for the x value in the array + const xScale = d3 + .scaleLinear() + .domain(d3.extent(dataset, d => d[0])) + .range([10, width - 100]); + + // d[1] is for the y value in the array + const yScale = d3 + .scaleLinear() + .domain(d3.extent(dataset, d => d[1])) + .range([height - 50, 20]); + + svg + .selectAll("circle") + .data(dataset) + .enter() + .append("circle") + .attr("cx", d => xScale(d[0])) + .attr("cy", d => yScale(d[1])) + .attr("r", 6) + .attr("fill", "black"); + + d3.select("svg") + .selectAll("circle") + .transition() + .attr("fill", (d, i) => colDict[dataset[i].clusterid]); +} + +// adds the buttons for the respective cluster data +// we could also use d3.append() and d3.select() here :) +function addClusterButton(eps, minPts = 3) { + const btn = document.createElement("BUTTON"); + btn.innerText = `cluster: ${eps} & minPts: ${minPts}`; + + btn.addEventListener("click", function(e) { + make(eps); + }); + + document.querySelector("#buttons").appendChild(btn); + + return btn; +} diff --git a/examples/examples.json b/examples/examples.json index 055009231..12ead0dc5 100644 --- a/examples/examples.json +++ b/examples/examples.json @@ -1 +1 @@ -{"BodyPix":{"p5js":[{"name":"BodyPix_Image","url":"../p5js/BodyPix/BodyPix_Image"},{"name":"BodyPix_Webcam","url":"../p5js/BodyPix/BodyPix_Webcam"},{"name":"BodyPix_Webcam_Parts","url":"../p5js/BodyPix/BodyPix_Webcam_Parts"}],"p5webeditor":[{"name":"BodyPix_Image","url":"https://editor.p5js.org/ml5/sketches/BodyPix_Image"},{"name":"BodyPix_Webcam","url":"https://editor.p5js.org/ml5/sketches/BodyPix_Webcam"},{"name":"BodyPix_Webcam_Parts","url":"https://editor.p5js.org/ml5/sketches/BodyPix_Webcam_Parts"}],"javascript":[{"name":"BodyPix_Image","url":"../javascript/BodyPix/BodyPix_Image"},{"name":"BodyPix_Webcam","url":"../javascript/BodyPix/BodyPix_Webcam"},{"name":"BodyPix_Webcam_Parts","url":"../javascript/BodyPix/BodyPix_Webcam_Parts"}]},"CVAE":{"p5js":[{"name":"CVAE_QuickDraw","url":"../p5js/CVAE/CVAE_QuickDraw"}],"p5webeditor":[{"name":"CVAE_QuickDraw","url":"https://editor.p5js.org/ml5/sketches/CVAE_QuickDraw"}],"javascript":[{"name":"CVAE_QuickDraw","url":"../javascript/CVAE/CVAE_QuickDraw"}]},"CartoonGAN":{"p5js":[{"name":"CartoonGan_Basic","url":"../p5js/CartoonGAN/CartoonGan_Basic"},{"name":"CartoonGan_LoadModel","url":"../p5js/CartoonGAN/CartoonGan_LoadModel"},{"name":"CartoonGan_WebCam","url":"../p5js/CartoonGAN/CartoonGan_WebCam"}],"p5webeditor":[{"name":"CartoonGan_Basic","url":"https://editor.p5js.org/ml5/sketches/CartoonGan_Basic"},{"name":"CartoonGan_LoadModel","url":"https://editor.p5js.org/ml5/sketches/CartoonGan_LoadModel"},{"name":"CartoonGan_WebCam","url":"https://editor.p5js.org/ml5/sketches/CartoonGan_WebCam"}]},"CharRNN":{"p5js":[{"name":"CharRNN_Interactive","url":"../p5js/CharRNN/CharRNN_Interactive"},{"name":"CharRNN_Text","url":"../p5js/CharRNN/CharRNN_Text"},{"name":"CharRNN_Text_Stateful","url":"../p5js/CharRNN/CharRNN_Text_Stateful"}],"p5webeditor":[{"name":"CharRNN_Interactive","url":"https://editor.p5js.org/ml5/sketches/CharRNN_Interactive"},{"name":"CharRNN_Text","url":"https://editor.p5js.org/ml5/sketches/CharRNN_Text"},{"name":"CharRNN_Text_Stateful","url":"https://editor.p5js.org/ml5/sketches/CharRNN_Text_Stateful"}],"javascript":[{"name":"CharRNN_Interactive","url":"../javascript/CharRNN/CharRNN_Interactive"},{"name":"CharRNN_Text","url":"../javascript/CharRNN/CharRNN_Text"},{"name":"CharRNN_Text_Stateful","url":"../javascript/CharRNN/CharRNN_Text_Stateful"}]},"DCGAN":{"p5js":[{"name":"DCGAN_LatentVector_RandomWalk","url":"../p5js/DCGAN/DCGAN_LatentVector_RandomWalk"},{"name":"DCGAN_LatentVector_Slider","url":"../p5js/DCGAN/DCGAN_LatentVector_Slider"},{"name":"DCGAN_Random","url":"../p5js/DCGAN/DCGAN_Random"}],"p5webeditor":[{"name":"DCGAN_LatentVector_RandomWalk","url":"https://editor.p5js.org/ml5/sketches/DCGAN_LatentVector_RandomWalk"},{"name":"DCGAN_LatentVector_Slider","url":"https://editor.p5js.org/ml5/sketches/DCGAN_LatentVector_Slider"},{"name":"DCGAN_Random","url":"https://editor.p5js.org/ml5/sketches/DCGAN_Random"}],"javascript":[{"name":"DCGAN_Random","url":"../javascript/DCGAN/DCGAN_Random"}]},"FaceApi":{"p5js":[{"name":"FaceApi_Image_Landmarks","url":"../p5js/FaceApi/FaceApi_Image_Landmarks"},{"name":"FaceApi_Video_Landmarks","url":"../p5js/FaceApi/FaceApi_Video_Landmarks"},{"name":"FaceApi_Video_Landmarks_LocalModels","url":"../p5js/FaceApi/FaceApi_Video_Landmarks_LocalModels"}],"p5webeditor":[{"name":"FaceApi_Image_Landmarks","url":"https://editor.p5js.org/ml5/sketches/FaceApi_Image_Landmarks"},{"name":"FaceApi_Video_Landmarks","url":"https://editor.p5js.org/ml5/sketches/FaceApi_Video_Landmarks"},{"name":"FaceApi_Video_Landmarks_LocalModels","url":"https://editor.p5js.org/ml5/sketches/FaceApi_Video_Landmarks_LocalModels"}],"javascript":[{"name":"FaceApi_Image_Landmarks","url":"../javascript/FaceApi/FaceApi_Image_Landmarks"},{"name":"FaceApi_Video_Landmarks","url":"../javascript/FaceApi/FaceApi_Video_Landmarks"},{"name":"FaceApi_Video_Landmarks_LocalModels","url":"../javascript/FaceApi/FaceApi_Video_Landmarks_LocalModels"}]},"Facemesh":{"p5js":[{"name":"Facemesh_Image","url":"../p5js/Facemesh/Facemesh_Image"},{"name":"Facemesh_Webcam","url":"../p5js/Facemesh/Facemesh_Webcam"}],"p5webeditor":[{"name":"Facemesh_Image","url":"https://editor.p5js.org/ml5/sketches/Facemesh_Image"},{"name":"Facemesh_Webcam","url":"https://editor.p5js.org/ml5/sketches/Facemesh_Webcam"}]},"FeatureExtractor":{"p5js":[{"name":"FeatureExtractor_Image_Classification","url":"../p5js/FeatureExtractor/FeatureExtractor_Image_Classification"},{"name":"FeatureExtractor_Image_Regression","url":"../p5js/FeatureExtractor/FeatureExtractor_Image_Regression"}],"p5webeditor":[{"name":"FeatureExtractor_Image_Classification","url":"https://editor.p5js.org/ml5/sketches/FeatureExtractor_Image_Classification"},{"name":"FeatureExtractor_Image_Regression","url":"https://editor.p5js.org/ml5/sketches/FeatureExtractor_Image_Regression"}],"javascript":[{"name":"FeatureExtractor_Image_Classification","url":"../javascript/FeatureExtractor/FeatureExtractor_Image_Classification"},{"name":"FeatureExtractor_Image_Regression","url":"../javascript/FeatureExtractor/FeatureExtractor_Image_Regression"}]},"Handpose":{"p5js":[{"name":"Handpose_Image","url":"../p5js/Handpose/Handpose_Image"},{"name":"Handpose_Webcam","url":"../p5js/Handpose/Handpose_Webcam"}],"p5webeditor":[{"name":"Handpose_Image","url":"https://editor.p5js.org/ml5/sketches/Handpose_Image"},{"name":"Handpose_Webcam","url":"https://editor.p5js.org/ml5/sketches/Handpose_Webcam"}]},"ImageClassification":{"p5js":[{"name":"ImageClassification","url":"../p5js/ImageClassification/ImageClassification"},{"name":"ImageClassification_DoodleNet_Canvas","url":"../p5js/ImageClassification/ImageClassification_DoodleNet_Canvas"},{"name":"ImageClassification_DoodleNet_Video","url":"../p5js/ImageClassification/ImageClassification_DoodleNet_Video"},{"name":"ImageClassification_MultipleImages","url":"../p5js/ImageClassification/ImageClassification_MultipleImages"},{"name":"ImageClassification_Video","url":"../p5js/ImageClassification/ImageClassification_Video"},{"name":"ImageClassification_VideoScavengerHunt","url":"../p5js/ImageClassification/ImageClassification_VideoScavengerHunt"},{"name":"ImageClassification_VideoSound","url":"../p5js/ImageClassification/ImageClassification_VideoSound"},{"name":"ImageClassification_VideoSoundTranslate","url":"../p5js/ImageClassification/ImageClassification_VideoSoundTranslate"},{"name":"ImageClassification_Video_Load","url":"../p5js/ImageClassification/ImageClassification_Video_Load"}],"p5webeditor":[{"name":"ImageClassification","url":"https://editor.p5js.org/ml5/sketches/ImageClassification"},{"name":"ImageClassification_DoodleNet_Canvas","url":"https://editor.p5js.org/ml5/sketches/ImageClassification_DoodleNet_Canvas"},{"name":"ImageClassification_DoodleNet_Video","url":"https://editor.p5js.org/ml5/sketches/ImageClassification_DoodleNet_Video"},{"name":"ImageClassification_MultipleImages","url":"https://editor.p5js.org/ml5/sketches/ImageClassification_MultipleImages"},{"name":"ImageClassification_Video","url":"https://editor.p5js.org/ml5/sketches/ImageClassification_Video"},{"name":"ImageClassification_VideoScavengerHunt","url":"https://editor.p5js.org/ml5/sketches/ImageClassification_VideoScavengerHunt"},{"name":"ImageClassification_VideoSound","url":"https://editor.p5js.org/ml5/sketches/ImageClassification_VideoSound"},{"name":"ImageClassification_VideoSoundTranslate","url":"https://editor.p5js.org/ml5/sketches/ImageClassification_VideoSoundTranslate"},{"name":"ImageClassification_Video_Load","url":"https://editor.p5js.org/ml5/sketches/ImageClassification_Video_Load"}],"javascript":[{"name":"ImageClassification","url":"../javascript/ImageClassification/ImageClassification"},{"name":"ImageClassification_DoodleNet_Canvas","url":"../javascript/ImageClassification/ImageClassification_DoodleNet_Canvas"},{"name":"ImageClassification_DoodleNet_Video","url":"../javascript/ImageClassification/ImageClassification_DoodleNet_Video"},{"name":"ImageClassification_MultipleImages","url":"../javascript/ImageClassification/ImageClassification_MultipleImages"},{"name":"ImageClassification_Video","url":"../javascript/ImageClassification/ImageClassification_Video"},{"name":"ImageClassification_VideoScavengerHunt","url":"../javascript/ImageClassification/ImageClassification_VideoScavengerHunt"},{"name":"ImageClassification_VideoSound","url":"../javascript/ImageClassification/ImageClassification_VideoSound"},{"name":"ImageClassification_Video_Load","url":"../javascript/ImageClassification/ImageClassification_Video_Load"}]},"KMeans":{"p5js":[{"name":"KMeans_imageSegmentation","url":"../p5js/KMeans/KMeans_imageSegmentation"},{"name":"KMeans_mouseClustering","url":"../p5js/KMeans/KMeans_mouseClustering"}],"p5webeditor":[{"name":"KMeans_imageSegmentation","url":"https://editor.p5js.org/ml5/sketches/KMeans_imageSegmentation"},{"name":"KMeans_mouseClustering","url":"https://editor.p5js.org/ml5/sketches/KMeans_mouseClustering"}],"d3":[{"name":"KMeans_GaussianClusterDemo","url":"../d3/KMeans/KMeans_GaussianClusterDemo"}]},"KNNClassification":{"p5js":[{"name":"KNNClassification_PoseNet","url":"../p5js/KNNClassification/KNNClassification_PoseNet"},{"name":"KNNClassification_Video","url":"../p5js/KNNClassification/KNNClassification_Video"},{"name":"KNNClassification_VideoSound","url":"../p5js/KNNClassification/KNNClassification_VideoSound"},{"name":"KNNClassification_VideoSquare","url":"../p5js/KNNClassification/KNNClassification_VideoSquare"}],"p5webeditor":[{"name":"KNNClassification_PoseNet","url":"https://editor.p5js.org/ml5/sketches/KNNClassification_PoseNet"},{"name":"KNNClassification_Video","url":"https://editor.p5js.org/ml5/sketches/KNNClassification_Video"},{"name":"KNNClassification_VideoSound","url":"https://editor.p5js.org/ml5/sketches/KNNClassification_VideoSound"},{"name":"KNNClassification_VideoSquare","url":"https://editor.p5js.org/ml5/sketches/KNNClassification_VideoSquare"}],"javascript":[{"name":"KNNClassification_PoseNet","url":"../javascript/KNNClassification/KNNClassification_PoseNet"},{"name":"KNNClassification_Video","url":"../javascript/KNNClassification/KNNClassification_Video"},{"name":"KNNClassification_VideoSound","url":"../javascript/KNNClassification/KNNClassification_VideoSound"},{"name":"KNNClassification_VideoSquare","url":"../javascript/KNNClassification/KNNClassification_VideoSquare"}]},"NeuralNetwork":{"p5js":[{"name":"NeuralNetwork_ImageClassifier_Colors","url":"../p5js/NeuralNetwork/NeuralNetwork_ImageClassifier_Colors"},{"name":"NeuralNetwork_ImageClassifier_Letters","url":"../p5js/NeuralNetwork/NeuralNetwork_ImageClassifier_Letters"},{"name":"NeuralNetwork_ImageClassifier_Video","url":"../p5js/NeuralNetwork/NeuralNetwork_ImageClassifier_Video"},{"name":"NeuralNetwork_Interactive_Regression","url":"../p5js/NeuralNetwork/NeuralNetwork_Interactive_Regression"},{"name":"NeuralNetwork_Simple_AorB","url":"../p5js/NeuralNetwork/NeuralNetwork_Simple_AorB"},{"name":"NeuralNetwork_Simple_Classification","url":"../p5js/NeuralNetwork/NeuralNetwork_Simple_Classification"},{"name":"NeuralNetwork_Simple_Regression","url":"../p5js/NeuralNetwork/NeuralNetwork_Simple_Regression"},{"name":"NeuralNetwork_XOR","url":"../p5js/NeuralNetwork/NeuralNetwork_XOR"},{"name":"NeuralNetwork_basics","url":"../p5js/NeuralNetwork/NeuralNetwork_basics"},{"name":"NeuralNetwork_co2net","url":"../p5js/NeuralNetwork/NeuralNetwork_co2net"},{"name":"NeuralNetwork_color_classifier","url":"../p5js/NeuralNetwork/NeuralNetwork_color_classifier"},{"name":"NeuralNetwork_load_model","url":"../p5js/NeuralNetwork/NeuralNetwork_load_model"},{"name":"NeuralNetwork_load_saved_data","url":"../p5js/NeuralNetwork/NeuralNetwork_load_saved_data"},{"name":"NeuralNetwork_lowres_pixels","url":"../p5js/NeuralNetwork/NeuralNetwork_lowres_pixels"},{"name":"NeuralNetwork_multiple_layers","url":"../p5js/NeuralNetwork/NeuralNetwork_multiple_layers"},{"name":"NeuralNetwork_musical_face","url":"../p5js/NeuralNetwork/NeuralNetwork_musical_face"},{"name":"NeuralNetwork_musical_mouse","url":"../p5js/NeuralNetwork/NeuralNetwork_musical_mouse"},{"name":"NeuralNetwork_pose_classifier","url":"../p5js/NeuralNetwork/NeuralNetwork_pose_classifier"},{"name":"NeuralNetwork_titanic","url":"../p5js/NeuralNetwork/NeuralNetwork_titanic"},{"name":"NeuralNetwork_xy_classifier","url":"../p5js/NeuralNetwork/NeuralNetwork_xy_classifier"},{"name":"NeuroEvolution_FlappyBird","url":"../p5js/NeuralNetwork/NeuroEvolution_FlappyBird"},{"name":"NeuroEvolution_Path","url":"../p5js/NeuralNetwork/NeuroEvolution_Path"},{"name":"NeuroEvolution_testing","url":"../p5js/NeuralNetwork/NeuroEvolution_testing"}],"p5webeditor":[{"name":"NeuralNetwork_ImageClassifier_Colors","url":"https://editor.p5js.org/ml5/sketches/NeuralNetwork_ImageClassifier_Colors"},{"name":"NeuralNetwork_ImageClassifier_Letters","url":"https://editor.p5js.org/ml5/sketches/NeuralNetwork_ImageClassifier_Letters"},{"name":"NeuralNetwork_ImageClassifier_Video","url":"https://editor.p5js.org/ml5/sketches/NeuralNetwork_ImageClassifier_Video"},{"name":"NeuralNetwork_Interactive_Regression","url":"https://editor.p5js.org/ml5/sketches/NeuralNetwork_Interactive_Regression"},{"name":"NeuralNetwork_Simple_AorB","url":"https://editor.p5js.org/ml5/sketches/NeuralNetwork_Simple_AorB"},{"name":"NeuralNetwork_Simple_Classification","url":"https://editor.p5js.org/ml5/sketches/NeuralNetwork_Simple_Classification"},{"name":"NeuralNetwork_Simple_Regression","url":"https://editor.p5js.org/ml5/sketches/NeuralNetwork_Simple_Regression"},{"name":"NeuralNetwork_XOR","url":"https://editor.p5js.org/ml5/sketches/NeuralNetwork_XOR"},{"name":"NeuralNetwork_basics","url":"https://editor.p5js.org/ml5/sketches/NeuralNetwork_basics"},{"name":"NeuralNetwork_co2net","url":"https://editor.p5js.org/ml5/sketches/NeuralNetwork_co2net"},{"name":"NeuralNetwork_color_classifier","url":"https://editor.p5js.org/ml5/sketches/NeuralNetwork_color_classifier"},{"name":"NeuralNetwork_load_model","url":"https://editor.p5js.org/ml5/sketches/NeuralNetwork_load_model"},{"name":"NeuralNetwork_load_saved_data","url":"https://editor.p5js.org/ml5/sketches/NeuralNetwork_load_saved_data"},{"name":"NeuralNetwork_lowres_pixels","url":"https://editor.p5js.org/ml5/sketches/NeuralNetwork_lowres_pixels"},{"name":"NeuralNetwork_multiple_layers","url":"https://editor.p5js.org/ml5/sketches/NeuralNetwork_multiple_layers"},{"name":"NeuralNetwork_musical_face","url":"https://editor.p5js.org/ml5/sketches/NeuralNetwork_musical_face"},{"name":"NeuralNetwork_musical_mouse","url":"https://editor.p5js.org/ml5/sketches/NeuralNetwork_musical_mouse"},{"name":"NeuralNetwork_pose_classifier","url":"https://editor.p5js.org/ml5/sketches/NeuralNetwork_pose_classifier"},{"name":"NeuralNetwork_titanic","url":"https://editor.p5js.org/ml5/sketches/NeuralNetwork_titanic"},{"name":"NeuralNetwork_xy_classifier","url":"https://editor.p5js.org/ml5/sketches/NeuralNetwork_xy_classifier"},{"name":"NeuroEvolution_FlappyBird","url":"https://editor.p5js.org/ml5/sketches/NeuroEvolution_FlappyBird"},{"name":"NeuroEvolution_Path","url":"https://editor.p5js.org/ml5/sketches/NeuroEvolution_Path"},{"name":"NeuroEvolution_testing","url":"https://editor.p5js.org/ml5/sketches/NeuroEvolution_testing"}]},"ObjectDetector":{"p5js":[{"name":"ObjectDetector_COCOSSD_Video","url":"../p5js/ObjectDetector/ObjectDetector_COCOSSD_Video"},{"name":"ObjectDetector_COCOSSD_single_image","url":"../p5js/ObjectDetector/ObjectDetector_COCOSSD_single_image"}],"p5webeditor":[{"name":"ObjectDetector_COCOSSD_Video","url":"https://editor.p5js.org/ml5/sketches/ObjectDetector_COCOSSD_Video"},{"name":"ObjectDetector_COCOSSD_single_image","url":"https://editor.p5js.org/ml5/sketches/ObjectDetector_COCOSSD_single_image"}],"javascript":[{"name":"COCOSSD_single_image","url":"../javascript/ObjectDetector/COCOSSD_single_image"},{"name":"COCOSSD_webcam","url":"../javascript/ObjectDetector/COCOSSD_webcam"},{"name":"YOLO_single_image","url":"../javascript/ObjectDetector/YOLO_single_image"},{"name":"YOLO_webcam","url":"../javascript/ObjectDetector/YOLO_webcam"}]},"PitchDetection":{"p5js":[{"name":"PitchDetection","url":"../p5js/PitchDetection/PitchDetection"},{"name":"PitchDetection_Game","url":"../p5js/PitchDetection/PitchDetection_Game"},{"name":"PitchDetection_Piano","url":"../p5js/PitchDetection/PitchDetection_Piano"}],"p5webeditor":[{"name":"PitchDetection","url":"https://editor.p5js.org/ml5/sketches/PitchDetection"},{"name":"PitchDetection_Game","url":"https://editor.p5js.org/ml5/sketches/PitchDetection_Game"},{"name":"PitchDetection_Piano","url":"https://editor.p5js.org/ml5/sketches/PitchDetection_Piano"}],"javascript":[{"name":"PitchDetection","url":"../javascript/PitchDetection/PitchDetection"},{"name":"PitchDetection_Game","url":"../javascript/PitchDetection/PitchDetection_Game"},{"name":"PitchDetection_Piano","url":"../javascript/PitchDetection/PitchDetection_Piano"}]},"Pix2Pix":{"p5js":[{"name":"Pix2Pix_callback","url":"../p5js/Pix2Pix/Pix2Pix_callback"},{"name":"Pix2Pix_promise","url":"../p5js/Pix2Pix/Pix2Pix_promise"}],"p5webeditor":[{"name":"Pix2Pix_callback","url":"https://editor.p5js.org/ml5/sketches/Pix2Pix_callback"},{"name":"Pix2Pix_promise","url":"https://editor.p5js.org/ml5/sketches/Pix2Pix_promise"}],"javascript":[{"name":"Pix2Pix_callback","url":"../javascript/Pix2Pix/Pix2Pix_callback"},{"name":"Pix2Pix_promise","url":"../javascript/Pix2Pix/Pix2Pix_promise"}]},"PoseNet":{"p5js":[{"name":"PoseNet_image_single","url":"../p5js/PoseNet/PoseNet_image_single"},{"name":"PoseNet_part_selection","url":"../p5js/PoseNet/PoseNet_part_selection"},{"name":"PoseNet_webcam","url":"../p5js/PoseNet/PoseNet_webcam"}],"p5webeditor":[{"name":"PoseNet_image_single","url":"https://editor.p5js.org/ml5/sketches/PoseNet_image_single"},{"name":"PoseNet_part_selection","url":"https://editor.p5js.org/ml5/sketches/PoseNet_part_selection"},{"name":"PoseNet_webcam","url":"https://editor.p5js.org/ml5/sketches/PoseNet_webcam"}],"javascript":[{"name":"PoseNet_image_single","url":"../javascript/PoseNet/PoseNet_image_single"},{"name":"PoseNet_part_selection","url":"../javascript/PoseNet/PoseNet_part_selection"},{"name":"PoseNet_webcam","url":"../javascript/PoseNet/PoseNet_webcam"}]},"Sentiment":{"p5js":[{"name":"Sentiment_Interactive","url":"../p5js/Sentiment/Sentiment_Interactive"}],"p5webeditor":[{"name":"Sentiment_Interactive","url":"https://editor.p5js.org/ml5/sketches/Sentiment_Interactive"}],"javascript":[{"name":"Sentiment_Interactive","url":"../javascript/Sentiment/Sentiment_Interactive"}]},"SketchRNN":{"p5js":[{"name":"SketchRNN_basic","url":"../p5js/SketchRNN/SketchRNN_basic"},{"name":"SketchRNN_interactive","url":"../p5js/SketchRNN/SketchRNN_interactive"}],"p5webeditor":[{"name":"SketchRNN_basic","url":"https://editor.p5js.org/ml5/sketches/SketchRNN_basic"},{"name":"SketchRNN_interactive","url":"https://editor.p5js.org/ml5/sketches/SketchRNN_interactive"}],"javascript":[{"name":"SketchRNN_basic","url":"../javascript/SketchRNN/SketchRNN_basic"},{"name":"SketchRNN_interactive","url":"../javascript/SketchRNN/SketchRNN_interactive"}]},"SoundClassification":{"p5js":[{"name":"SoundClassification_speechcommand","url":"../p5js/SoundClassification/SoundClassification_speechcommand"},{"name":"SoundClassification_speechcommand_load","url":"../p5js/SoundClassification/SoundClassification_speechcommand_load"}],"p5webeditor":[{"name":"SoundClassification_speechcommand","url":"https://editor.p5js.org/ml5/sketches/SoundClassification_speechcommand"},{"name":"SoundClassification_speechcommand_load","url":"https://editor.p5js.org/ml5/sketches/SoundClassification_speechcommand_load"}],"javascript":[{"name":"SoundClassification_speechcommand","url":"../javascript/SoundClassification/SoundClassification_speechcommand"},{"name":"SoundClassification_speechcommand_load","url":"../javascript/SoundClassification/SoundClassification_speechcommand_load"}]},"StyleTransfer":{"p5js":[{"name":"StyleTransfer_Image","url":"../p5js/StyleTransfer/StyleTransfer_Image"},{"name":"StyleTransfer_Video","url":"../p5js/StyleTransfer/StyleTransfer_Video"}],"p5webeditor":[{"name":"StyleTransfer_Image","url":"https://editor.p5js.org/ml5/sketches/StyleTransfer_Image"},{"name":"StyleTransfer_Video","url":"https://editor.p5js.org/ml5/sketches/StyleTransfer_Video"}],"javascript":[{"name":"StyleTransfer_Image","url":"../javascript/StyleTransfer/StyleTransfer_Image"},{"name":"StyleTransfer_Video","url":"../javascript/StyleTransfer/StyleTransfer_Video"}]},"TeachableMachine":{"p5js":[{"name":"ImageModel_TM","url":"../p5js/TeachableMachine/ImageModel_TM"},{"name":"SoundModel_TM","url":"../p5js/TeachableMachine/SoundModel_TM"}],"p5webeditor":[{"name":"ImageModel_TM","url":"https://editor.p5js.org/ml5/sketches/ImageModel_TM"},{"name":"SoundModel_TM","url":"https://editor.p5js.org/ml5/sketches/SoundModel_TM"}]},"UNET":{"p5js":[{"name":"UNET_webcam","url":"../p5js/UNET/UNET_webcam"}],"p5webeditor":[{"name":"UNET_webcam","url":"https://editor.p5js.org/ml5/sketches/UNET_webcam"}],"javascript":[{"name":"UNET_webcam","url":"../javascript/UNET/UNET_webcam"}]},"UniversalSentenceEncoder":{"p5js":[{"name":"UniversalSentenceEncoder_Basic","url":"../p5js/UniversalSentenceEncoder/UniversalSentenceEncoder_Basic"},{"name":"UniversalSentenceEncoder_WithTokenizer","url":"../p5js/UniversalSentenceEncoder/UniversalSentenceEncoder_WithTokenizer"}],"p5webeditor":[{"name":"UniversalSentenceEncoder_Basic","url":"https://editor.p5js.org/ml5/sketches/UniversalSentenceEncoder_Basic"},{"name":"UniversalSentenceEncoder_WithTokenizer","url":"https://editor.p5js.org/ml5/sketches/UniversalSentenceEncoder_WithTokenizer"}]},"YOLO":{"p5js":[{"name":"YOLO_single_image","url":"../p5js/YOLO/YOLO_single_image"},{"name":"YOLO_webcam","url":"../p5js/YOLO/YOLO_webcam"}],"p5webeditor":[{"name":"YOLO_single_image","url":"https://editor.p5js.org/ml5/sketches/YOLO_single_image"},{"name":"YOLO_webcam","url":"https://editor.p5js.org/ml5/sketches/YOLO_webcam"}],"javascript":[{"name":"YOLO_single_image","url":"../javascript/YOLO/YOLO_single_image"},{"name":"YOLO_webcam","url":"../javascript/YOLO/YOLO_webcam"}]},"ml5Boilerplate":{"p5js":[{"name":"ml5Boilerplate_Version","url":"../p5js/ml5Boilerplate/ml5Boilerplate_Version"}],"p5webeditor":[{"name":"ml5Boilerplate_Version","url":"https://editor.p5js.org/ml5/sketches/ml5Boilerplate_Version"}],"javascript":[{"name":"ml5Boilerplate_Version","url":"../javascript/ml5Boilerplate/ml5Boilerplate_Version"}]}} \ No newline at end of file +{"BodyPix":{"p5js":[{"name":"BodyPix_Image","url":"../p5js/BodyPix/BodyPix_Image"},{"name":"BodyPix_Webcam","url":"../p5js/BodyPix/BodyPix_Webcam"},{"name":"BodyPix_Webcam_Parts","url":"../p5js/BodyPix/BodyPix_Webcam_Parts"}],"p5webeditor":[{"name":"BodyPix_Image","url":"https://editor.p5js.org/ml5/sketches/BodyPix_Image"},{"name":"BodyPix_Webcam","url":"https://editor.p5js.org/ml5/sketches/BodyPix_Webcam"},{"name":"BodyPix_Webcam_Parts","url":"https://editor.p5js.org/ml5/sketches/BodyPix_Webcam_Parts"}],"javascript":[{"name":"BodyPix_Image","url":"../javascript/BodyPix/BodyPix_Image"},{"name":"BodyPix_Webcam","url":"../javascript/BodyPix/BodyPix_Webcam"},{"name":"BodyPix_Webcam_Parts","url":"../javascript/BodyPix/BodyPix_Webcam_Parts"}]},"CVAE":{"p5js":[{"name":"CVAE_QuickDraw","url":"../p5js/CVAE/CVAE_QuickDraw"}],"p5webeditor":[{"name":"CVAE_QuickDraw","url":"https://editor.p5js.org/ml5/sketches/CVAE_QuickDraw"}],"javascript":[{"name":"CVAE_QuickDraw","url":"../javascript/CVAE/CVAE_QuickDraw"}]},"CartoonGAN":{"p5js":[{"name":"CartoonGan_Basic","url":"../p5js/CartoonGAN/CartoonGan_Basic"},{"name":"CartoonGan_LoadModel","url":"../p5js/CartoonGAN/CartoonGan_LoadModel"},{"name":"CartoonGan_WebCam","url":"../p5js/CartoonGAN/CartoonGan_WebCam"}],"p5webeditor":[{"name":"CartoonGan_Basic","url":"https://editor.p5js.org/ml5/sketches/CartoonGan_Basic"},{"name":"CartoonGan_LoadModel","url":"https://editor.p5js.org/ml5/sketches/CartoonGan_LoadModel"},{"name":"CartoonGan_WebCam","url":"https://editor.p5js.org/ml5/sketches/CartoonGan_WebCam"}]},"CharRNN":{"p5js":[{"name":"CharRNN_Interactive","url":"../p5js/CharRNN/CharRNN_Interactive"},{"name":"CharRNN_Text","url":"../p5js/CharRNN/CharRNN_Text"},{"name":"CharRNN_Text_Stateful","url":"../p5js/CharRNN/CharRNN_Text_Stateful"}],"p5webeditor":[{"name":"CharRNN_Interactive","url":"https://editor.p5js.org/ml5/sketches/CharRNN_Interactive"},{"name":"CharRNN_Text","url":"https://editor.p5js.org/ml5/sketches/CharRNN_Text"},{"name":"CharRNN_Text_Stateful","url":"https://editor.p5js.org/ml5/sketches/CharRNN_Text_Stateful"}],"javascript":[{"name":"CharRNN_Interactive","url":"../javascript/CharRNN/CharRNN_Interactive"},{"name":"CharRNN_Text","url":"../javascript/CharRNN/CharRNN_Text"},{"name":"CharRNN_Text_Stateful","url":"../javascript/CharRNN/CharRNN_Text_Stateful"}]},"DBSCAN":{"p5js":[],"p5webeditor":[],"d3":[{"name":"DBSCAN_Cluster","url":"../d3/DBSCAN/DBSCAN_Cluster"}]},"DCGAN":{"p5js":[{"name":"DCGAN_LatentVector_RandomWalk","url":"../p5js/DCGAN/DCGAN_LatentVector_RandomWalk"},{"name":"DCGAN_LatentVector_Slider","url":"../p5js/DCGAN/DCGAN_LatentVector_Slider"},{"name":"DCGAN_Random","url":"../p5js/DCGAN/DCGAN_Random"}],"p5webeditor":[{"name":"DCGAN_LatentVector_RandomWalk","url":"https://editor.p5js.org/ml5/sketches/DCGAN_LatentVector_RandomWalk"},{"name":"DCGAN_LatentVector_Slider","url":"https://editor.p5js.org/ml5/sketches/DCGAN_LatentVector_Slider"},{"name":"DCGAN_Random","url":"https://editor.p5js.org/ml5/sketches/DCGAN_Random"}],"javascript":[{"name":"DCGAN_Random","url":"../javascript/DCGAN/DCGAN_Random"}]},"FaceApi":{"p5js":[{"name":"FaceApi_Image_Landmarks","url":"../p5js/FaceApi/FaceApi_Image_Landmarks"},{"name":"FaceApi_Video_Landmarks","url":"../p5js/FaceApi/FaceApi_Video_Landmarks"},{"name":"FaceApi_Video_Landmarks_LocalModels","url":"../p5js/FaceApi/FaceApi_Video_Landmarks_LocalModels"}],"p5webeditor":[{"name":"FaceApi_Image_Landmarks","url":"https://editor.p5js.org/ml5/sketches/FaceApi_Image_Landmarks"},{"name":"FaceApi_Video_Landmarks","url":"https://editor.p5js.org/ml5/sketches/FaceApi_Video_Landmarks"},{"name":"FaceApi_Video_Landmarks_LocalModels","url":"https://editor.p5js.org/ml5/sketches/FaceApi_Video_Landmarks_LocalModels"}],"javascript":[{"name":"FaceApi_Image_Landmarks","url":"../javascript/FaceApi/FaceApi_Image_Landmarks"},{"name":"FaceApi_Video_Landmarks","url":"../javascript/FaceApi/FaceApi_Video_Landmarks"},{"name":"FaceApi_Video_Landmarks_LocalModels","url":"../javascript/FaceApi/FaceApi_Video_Landmarks_LocalModels"}]},"Facemesh":{"p5js":[{"name":"Facemesh_Image","url":"../p5js/Facemesh/Facemesh_Image"},{"name":"Facemesh_Webcam","url":"../p5js/Facemesh/Facemesh_Webcam"}],"p5webeditor":[{"name":"Facemesh_Image","url":"https://editor.p5js.org/ml5/sketches/Facemesh_Image"},{"name":"Facemesh_Webcam","url":"https://editor.p5js.org/ml5/sketches/Facemesh_Webcam"}]},"FeatureExtractor":{"p5js":[{"name":"FeatureExtractor_Image_Classification","url":"../p5js/FeatureExtractor/FeatureExtractor_Image_Classification"},{"name":"FeatureExtractor_Image_Regression","url":"../p5js/FeatureExtractor/FeatureExtractor_Image_Regression"}],"p5webeditor":[{"name":"FeatureExtractor_Image_Classification","url":"https://editor.p5js.org/ml5/sketches/FeatureExtractor_Image_Classification"},{"name":"FeatureExtractor_Image_Regression","url":"https://editor.p5js.org/ml5/sketches/FeatureExtractor_Image_Regression"}],"javascript":[{"name":"FeatureExtractor_Image_Classification","url":"../javascript/FeatureExtractor/FeatureExtractor_Image_Classification"},{"name":"FeatureExtractor_Image_Regression","url":"../javascript/FeatureExtractor/FeatureExtractor_Image_Regression"}]},"Handpose":{"p5js":[{"name":"Handpose_Image","url":"../p5js/Handpose/Handpose_Image"},{"name":"Handpose_Part_Selection","url":"../p5js/Handpose/Handpose_Part_Selection"},{"name":"Handpose_Webcam","url":"../p5js/Handpose/Handpose_Webcam"}],"p5webeditor":[{"name":"Handpose_Image","url":"https://editor.p5js.org/ml5/sketches/Handpose_Image"},{"name":"Handpose_Part_Selection","url":"https://editor.p5js.org/ml5/sketches/Handpose_Part_Selection"},{"name":"Handpose_Webcam","url":"https://editor.p5js.org/ml5/sketches/Handpose_Webcam"}]},"ImageClassification":{"p5js":[{"name":"ImageClassification","url":"../p5js/ImageClassification/ImageClassification"},{"name":"ImageClassification_DoodleNet_Canvas","url":"../p5js/ImageClassification/ImageClassification_DoodleNet_Canvas"},{"name":"ImageClassification_DoodleNet_Video","url":"../p5js/ImageClassification/ImageClassification_DoodleNet_Video"},{"name":"ImageClassification_MultipleImages","url":"../p5js/ImageClassification/ImageClassification_MultipleImages"},{"name":"ImageClassification_Video","url":"../p5js/ImageClassification/ImageClassification_Video"},{"name":"ImageClassification_VideoScavengerHunt","url":"../p5js/ImageClassification/ImageClassification_VideoScavengerHunt"},{"name":"ImageClassification_VideoSound","url":"../p5js/ImageClassification/ImageClassification_VideoSound"},{"name":"ImageClassification_VideoSoundTranslate","url":"../p5js/ImageClassification/ImageClassification_VideoSoundTranslate"},{"name":"ImageClassification_Video_Load","url":"../p5js/ImageClassification/ImageClassification_Video_Load"}],"p5webeditor":[{"name":"ImageClassification","url":"https://editor.p5js.org/ml5/sketches/ImageClassification"},{"name":"ImageClassification_DoodleNet_Canvas","url":"https://editor.p5js.org/ml5/sketches/ImageClassification_DoodleNet_Canvas"},{"name":"ImageClassification_DoodleNet_Video","url":"https://editor.p5js.org/ml5/sketches/ImageClassification_DoodleNet_Video"},{"name":"ImageClassification_MultipleImages","url":"https://editor.p5js.org/ml5/sketches/ImageClassification_MultipleImages"},{"name":"ImageClassification_Video","url":"https://editor.p5js.org/ml5/sketches/ImageClassification_Video"},{"name":"ImageClassification_VideoScavengerHunt","url":"https://editor.p5js.org/ml5/sketches/ImageClassification_VideoScavengerHunt"},{"name":"ImageClassification_VideoSound","url":"https://editor.p5js.org/ml5/sketches/ImageClassification_VideoSound"},{"name":"ImageClassification_VideoSoundTranslate","url":"https://editor.p5js.org/ml5/sketches/ImageClassification_VideoSoundTranslate"},{"name":"ImageClassification_Video_Load","url":"https://editor.p5js.org/ml5/sketches/ImageClassification_Video_Load"}],"javascript":[{"name":"ImageClassification","url":"../javascript/ImageClassification/ImageClassification"},{"name":"ImageClassification_DoodleNet_Canvas","url":"../javascript/ImageClassification/ImageClassification_DoodleNet_Canvas"},{"name":"ImageClassification_DoodleNet_Video","url":"../javascript/ImageClassification/ImageClassification_DoodleNet_Video"},{"name":"ImageClassification_MultipleImages","url":"../javascript/ImageClassification/ImageClassification_MultipleImages"},{"name":"ImageClassification_Video","url":"../javascript/ImageClassification/ImageClassification_Video"},{"name":"ImageClassification_VideoScavengerHunt","url":"../javascript/ImageClassification/ImageClassification_VideoScavengerHunt"},{"name":"ImageClassification_VideoSound","url":"../javascript/ImageClassification/ImageClassification_VideoSound"},{"name":"ImageClassification_Video_Load","url":"../javascript/ImageClassification/ImageClassification_Video_Load"}]},"KMeans":{"p5js":[{"name":"KMeans_imageSegmentation","url":"../p5js/KMeans/KMeans_imageSegmentation"},{"name":"KMeans_mouseClustering","url":"../p5js/KMeans/KMeans_mouseClustering"}],"p5webeditor":[{"name":"KMeans_imageSegmentation","url":"https://editor.p5js.org/ml5/sketches/KMeans_imageSegmentation"},{"name":"KMeans_mouseClustering","url":"https://editor.p5js.org/ml5/sketches/KMeans_mouseClustering"}],"d3":[{"name":"KMeans_GaussianClusterDemo","url":"../d3/KMeans/KMeans_GaussianClusterDemo"}]},"KNNClassification":{"p5js":[{"name":"KNNClassification_PoseNet","url":"../p5js/KNNClassification/KNNClassification_PoseNet"},{"name":"KNNClassification_Video","url":"../p5js/KNNClassification/KNNClassification_Video"},{"name":"KNNClassification_VideoSound","url":"../p5js/KNNClassification/KNNClassification_VideoSound"},{"name":"KNNClassification_VideoSquare","url":"../p5js/KNNClassification/KNNClassification_VideoSquare"}],"p5webeditor":[{"name":"KNNClassification_PoseNet","url":"https://editor.p5js.org/ml5/sketches/KNNClassification_PoseNet"},{"name":"KNNClassification_Video","url":"https://editor.p5js.org/ml5/sketches/KNNClassification_Video"},{"name":"KNNClassification_VideoSound","url":"https://editor.p5js.org/ml5/sketches/KNNClassification_VideoSound"},{"name":"KNNClassification_VideoSquare","url":"https://editor.p5js.org/ml5/sketches/KNNClassification_VideoSquare"}],"javascript":[{"name":"KNNClassification_PoseNet","url":"../javascript/KNNClassification/KNNClassification_PoseNet"},{"name":"KNNClassification_Video","url":"../javascript/KNNClassification/KNNClassification_Video"},{"name":"KNNClassification_VideoSound","url":"../javascript/KNNClassification/KNNClassification_VideoSound"},{"name":"KNNClassification_VideoSquare","url":"../javascript/KNNClassification/KNNClassification_VideoSquare"}]},"NeuralNetwork":{"p5js":[{"name":"NeuralNetwork_ImageClassifier_Colors","url":"../p5js/NeuralNetwork/NeuralNetwork_ImageClassifier_Colors"},{"name":"NeuralNetwork_ImageClassifier_Letters","url":"../p5js/NeuralNetwork/NeuralNetwork_ImageClassifier_Letters"},{"name":"NeuralNetwork_ImageClassifier_Video","url":"../p5js/NeuralNetwork/NeuralNetwork_ImageClassifier_Video"},{"name":"NeuralNetwork_Interactive_Regression","url":"../p5js/NeuralNetwork/NeuralNetwork_Interactive_Regression"},{"name":"NeuralNetwork_Simple_AorB","url":"../p5js/NeuralNetwork/NeuralNetwork_Simple_AorB"},{"name":"NeuralNetwork_Simple_Classification","url":"../p5js/NeuralNetwork/NeuralNetwork_Simple_Classification"},{"name":"NeuralNetwork_Simple_Regression","url":"../p5js/NeuralNetwork/NeuralNetwork_Simple_Regression"},{"name":"NeuralNetwork_XOR","url":"../p5js/NeuralNetwork/NeuralNetwork_XOR"},{"name":"NeuralNetwork_basics","url":"../p5js/NeuralNetwork/NeuralNetwork_basics"},{"name":"NeuralNetwork_co2net","url":"../p5js/NeuralNetwork/NeuralNetwork_co2net"},{"name":"NeuralNetwork_color_classifier","url":"../p5js/NeuralNetwork/NeuralNetwork_color_classifier"},{"name":"NeuralNetwork_load_model","url":"../p5js/NeuralNetwork/NeuralNetwork_load_model"},{"name":"NeuralNetwork_load_saved_data","url":"../p5js/NeuralNetwork/NeuralNetwork_load_saved_data"},{"name":"NeuralNetwork_lowres_pixels","url":"../p5js/NeuralNetwork/NeuralNetwork_lowres_pixels"},{"name":"NeuralNetwork_multiple_layers","url":"../p5js/NeuralNetwork/NeuralNetwork_multiple_layers"},{"name":"NeuralNetwork_musical_face","url":"../p5js/NeuralNetwork/NeuralNetwork_musical_face"},{"name":"NeuralNetwork_musical_mouse","url":"../p5js/NeuralNetwork/NeuralNetwork_musical_mouse"},{"name":"NeuralNetwork_pose_classifier","url":"../p5js/NeuralNetwork/NeuralNetwork_pose_classifier"},{"name":"NeuralNetwork_titanic","url":"../p5js/NeuralNetwork/NeuralNetwork_titanic"},{"name":"NeuralNetwork_xy_classifier","url":"../p5js/NeuralNetwork/NeuralNetwork_xy_classifier"},{"name":"NeuroEvolution_FlappyBird","url":"../p5js/NeuralNetwork/NeuroEvolution_FlappyBird"},{"name":"NeuroEvolution_Path","url":"../p5js/NeuralNetwork/NeuroEvolution_Path"},{"name":"NeuroEvolution_testing","url":"../p5js/NeuralNetwork/NeuroEvolution_testing"}],"p5webeditor":[{"name":"NeuralNetwork_ImageClassifier_Colors","url":"https://editor.p5js.org/ml5/sketches/NeuralNetwork_ImageClassifier_Colors"},{"name":"NeuralNetwork_ImageClassifier_Letters","url":"https://editor.p5js.org/ml5/sketches/NeuralNetwork_ImageClassifier_Letters"},{"name":"NeuralNetwork_ImageClassifier_Video","url":"https://editor.p5js.org/ml5/sketches/NeuralNetwork_ImageClassifier_Video"},{"name":"NeuralNetwork_Interactive_Regression","url":"https://editor.p5js.org/ml5/sketches/NeuralNetwork_Interactive_Regression"},{"name":"NeuralNetwork_Simple_AorB","url":"https://editor.p5js.org/ml5/sketches/NeuralNetwork_Simple_AorB"},{"name":"NeuralNetwork_Simple_Classification","url":"https://editor.p5js.org/ml5/sketches/NeuralNetwork_Simple_Classification"},{"name":"NeuralNetwork_Simple_Regression","url":"https://editor.p5js.org/ml5/sketches/NeuralNetwork_Simple_Regression"},{"name":"NeuralNetwork_XOR","url":"https://editor.p5js.org/ml5/sketches/NeuralNetwork_XOR"},{"name":"NeuralNetwork_basics","url":"https://editor.p5js.org/ml5/sketches/NeuralNetwork_basics"},{"name":"NeuralNetwork_co2net","url":"https://editor.p5js.org/ml5/sketches/NeuralNetwork_co2net"},{"name":"NeuralNetwork_color_classifier","url":"https://editor.p5js.org/ml5/sketches/NeuralNetwork_color_classifier"},{"name":"NeuralNetwork_load_model","url":"https://editor.p5js.org/ml5/sketches/NeuralNetwork_load_model"},{"name":"NeuralNetwork_load_saved_data","url":"https://editor.p5js.org/ml5/sketches/NeuralNetwork_load_saved_data"},{"name":"NeuralNetwork_lowres_pixels","url":"https://editor.p5js.org/ml5/sketches/NeuralNetwork_lowres_pixels"},{"name":"NeuralNetwork_multiple_layers","url":"https://editor.p5js.org/ml5/sketches/NeuralNetwork_multiple_layers"},{"name":"NeuralNetwork_musical_face","url":"https://editor.p5js.org/ml5/sketches/NeuralNetwork_musical_face"},{"name":"NeuralNetwork_musical_mouse","url":"https://editor.p5js.org/ml5/sketches/NeuralNetwork_musical_mouse"},{"name":"NeuralNetwork_pose_classifier","url":"https://editor.p5js.org/ml5/sketches/NeuralNetwork_pose_classifier"},{"name":"NeuralNetwork_titanic","url":"https://editor.p5js.org/ml5/sketches/NeuralNetwork_titanic"},{"name":"NeuralNetwork_xy_classifier","url":"https://editor.p5js.org/ml5/sketches/NeuralNetwork_xy_classifier"},{"name":"NeuroEvolution_FlappyBird","url":"https://editor.p5js.org/ml5/sketches/NeuroEvolution_FlappyBird"},{"name":"NeuroEvolution_Path","url":"https://editor.p5js.org/ml5/sketches/NeuroEvolution_Path"},{"name":"NeuroEvolution_testing","url":"https://editor.p5js.org/ml5/sketches/NeuroEvolution_testing"}]},"ObjectDetector":{"p5js":[{"name":"ObjectDetector_COCOSSD_Video","url":"../p5js/ObjectDetector/ObjectDetector_COCOSSD_Video"},{"name":"ObjectDetector_COCOSSD_single_image","url":"../p5js/ObjectDetector/ObjectDetector_COCOSSD_single_image"}],"p5webeditor":[{"name":"ObjectDetector_COCOSSD_Video","url":"https://editor.p5js.org/ml5/sketches/ObjectDetector_COCOSSD_Video"},{"name":"ObjectDetector_COCOSSD_single_image","url":"https://editor.p5js.org/ml5/sketches/ObjectDetector_COCOSSD_single_image"}],"javascript":[{"name":"COCOSSD_single_image","url":"../javascript/ObjectDetector/COCOSSD_single_image"},{"name":"COCOSSD_webcam","url":"../javascript/ObjectDetector/COCOSSD_webcam"},{"name":"YOLO_single_image","url":"../javascript/ObjectDetector/YOLO_single_image"},{"name":"YOLO_webcam","url":"../javascript/ObjectDetector/YOLO_webcam"}]},"PitchDetection":{"p5js":[{"name":"PitchDetection","url":"../p5js/PitchDetection/PitchDetection"},{"name":"PitchDetection_Game","url":"../p5js/PitchDetection/PitchDetection_Game"},{"name":"PitchDetection_Piano","url":"../p5js/PitchDetection/PitchDetection_Piano"}],"p5webeditor":[{"name":"PitchDetection","url":"https://editor.p5js.org/ml5/sketches/PitchDetection"},{"name":"PitchDetection_Game","url":"https://editor.p5js.org/ml5/sketches/PitchDetection_Game"},{"name":"PitchDetection_Piano","url":"https://editor.p5js.org/ml5/sketches/PitchDetection_Piano"}],"javascript":[{"name":"PitchDetection","url":"../javascript/PitchDetection/PitchDetection"},{"name":"PitchDetection_Game","url":"../javascript/PitchDetection/PitchDetection_Game"},{"name":"PitchDetection_Piano","url":"../javascript/PitchDetection/PitchDetection_Piano"}]},"Pix2Pix":{"p5js":[{"name":"Pix2Pix_callback","url":"../p5js/Pix2Pix/Pix2Pix_callback"},{"name":"Pix2Pix_promise","url":"../p5js/Pix2Pix/Pix2Pix_promise"}],"p5webeditor":[{"name":"Pix2Pix_callback","url":"https://editor.p5js.org/ml5/sketches/Pix2Pix_callback"},{"name":"Pix2Pix_promise","url":"https://editor.p5js.org/ml5/sketches/Pix2Pix_promise"}],"javascript":[{"name":"Pix2Pix_callback","url":"../javascript/Pix2Pix/Pix2Pix_callback"},{"name":"Pix2Pix_promise","url":"../javascript/Pix2Pix/Pix2Pix_promise"}]},"PoseNet":{"p5js":[{"name":"PoseNet_image_single","url":"../p5js/PoseNet/PoseNet_image_single"},{"name":"PoseNet_part_selection","url":"../p5js/PoseNet/PoseNet_part_selection"},{"name":"PoseNet_webcam","url":"../p5js/PoseNet/PoseNet_webcam"}],"p5webeditor":[{"name":"PoseNet_image_single","url":"https://editor.p5js.org/ml5/sketches/PoseNet_image_single"},{"name":"PoseNet_part_selection","url":"https://editor.p5js.org/ml5/sketches/PoseNet_part_selection"},{"name":"PoseNet_webcam","url":"https://editor.p5js.org/ml5/sketches/PoseNet_webcam"}],"javascript":[{"name":"PoseNet_image_single","url":"../javascript/PoseNet/PoseNet_image_single"},{"name":"PoseNet_part_selection","url":"../javascript/PoseNet/PoseNet_part_selection"},{"name":"PoseNet_webcam","url":"../javascript/PoseNet/PoseNet_webcam"}]},"Sentiment":{"p5js":[{"name":"Sentiment_Interactive","url":"../p5js/Sentiment/Sentiment_Interactive"}],"p5webeditor":[{"name":"Sentiment_Interactive","url":"https://editor.p5js.org/ml5/sketches/Sentiment_Interactive"}],"javascript":[{"name":"Sentiment_Interactive","url":"../javascript/Sentiment/Sentiment_Interactive"}]},"SketchRNN":{"p5js":[{"name":"SketchRNN_basic","url":"../p5js/SketchRNN/SketchRNN_basic"},{"name":"SketchRNN_interactive","url":"../p5js/SketchRNN/SketchRNN_interactive"}],"p5webeditor":[{"name":"SketchRNN_basic","url":"https://editor.p5js.org/ml5/sketches/SketchRNN_basic"},{"name":"SketchRNN_interactive","url":"https://editor.p5js.org/ml5/sketches/SketchRNN_interactive"}],"javascript":[{"name":"SketchRNN_basic","url":"../javascript/SketchRNN/SketchRNN_basic"},{"name":"SketchRNN_interactive","url":"../javascript/SketchRNN/SketchRNN_interactive"}]},"SoundClassification":{"p5js":[{"name":"SoundClassification_speechcommand","url":"../p5js/SoundClassification/SoundClassification_speechcommand"},{"name":"SoundClassification_speechcommand_load","url":"../p5js/SoundClassification/SoundClassification_speechcommand_load"}],"p5webeditor":[{"name":"SoundClassification_speechcommand","url":"https://editor.p5js.org/ml5/sketches/SoundClassification_speechcommand"},{"name":"SoundClassification_speechcommand_load","url":"https://editor.p5js.org/ml5/sketches/SoundClassification_speechcommand_load"}],"javascript":[{"name":"SoundClassification_speechcommand","url":"../javascript/SoundClassification/SoundClassification_speechcommand"},{"name":"SoundClassification_speechcommand_load","url":"../javascript/SoundClassification/SoundClassification_speechcommand_load"}]},"StyleTransfer":{"p5js":[{"name":"StyleTransfer_Image","url":"../p5js/StyleTransfer/StyleTransfer_Image"},{"name":"StyleTransfer_Video","url":"../p5js/StyleTransfer/StyleTransfer_Video"}],"p5webeditor":[{"name":"StyleTransfer_Image","url":"https://editor.p5js.org/ml5/sketches/StyleTransfer_Image"},{"name":"StyleTransfer_Video","url":"https://editor.p5js.org/ml5/sketches/StyleTransfer_Video"}],"javascript":[{"name":"StyleTransfer_Image","url":"../javascript/StyleTransfer/StyleTransfer_Image"},{"name":"StyleTransfer_Video","url":"../javascript/StyleTransfer/StyleTransfer_Video"}]},"TeachableMachine":{"p5js":[{"name":"ImageModel_TM","url":"../p5js/TeachableMachine/ImageModel_TM"},{"name":"SoundModel_TM","url":"../p5js/TeachableMachine/SoundModel_TM"}],"p5webeditor":[{"name":"ImageModel_TM","url":"https://editor.p5js.org/ml5/sketches/ImageModel_TM"},{"name":"SoundModel_TM","url":"https://editor.p5js.org/ml5/sketches/SoundModel_TM"}]},"UNET":{"p5js":[{"name":"UNET_webcam","url":"../p5js/UNET/UNET_webcam"}],"p5webeditor":[{"name":"UNET_webcam","url":"https://editor.p5js.org/ml5/sketches/UNET_webcam"}],"javascript":[{"name":"UNET_webcam","url":"../javascript/UNET/UNET_webcam"}]},"UniversalSentenceEncoder":{"p5js":[{"name":"UniversalSentenceEncoder_Basic","url":"../p5js/UniversalSentenceEncoder/UniversalSentenceEncoder_Basic"},{"name":"UniversalSentenceEncoder_WithTokenizer","url":"../p5js/UniversalSentenceEncoder/UniversalSentenceEncoder_WithTokenizer"}],"p5webeditor":[{"name":"UniversalSentenceEncoder_Basic","url":"https://editor.p5js.org/ml5/sketches/UniversalSentenceEncoder_Basic"},{"name":"UniversalSentenceEncoder_WithTokenizer","url":"https://editor.p5js.org/ml5/sketches/UniversalSentenceEncoder_WithTokenizer"}]},"YOLO":{"p5js":[{"name":"YOLO_single_image","url":"../p5js/YOLO/YOLO_single_image"},{"name":"YOLO_webcam","url":"../p5js/YOLO/YOLO_webcam"}],"p5webeditor":[{"name":"YOLO_single_image","url":"https://editor.p5js.org/ml5/sketches/YOLO_single_image"},{"name":"YOLO_webcam","url":"https://editor.p5js.org/ml5/sketches/YOLO_webcam"}],"javascript":[{"name":"YOLO_single_image","url":"../javascript/YOLO/YOLO_single_image"},{"name":"YOLO_webcam","url":"../javascript/YOLO/YOLO_webcam"}]},"ml5Boilerplate":{"p5js":[{"name":"ml5Boilerplate_Version","url":"../p5js/ml5Boilerplate/ml5Boilerplate_Version"}],"p5webeditor":[{"name":"ml5Boilerplate_Version","url":"https://editor.p5js.org/ml5/sketches/ml5Boilerplate_Version"}],"javascript":[{"name":"ml5Boilerplate_Version","url":"../javascript/ml5Boilerplate/ml5Boilerplate_Version"}]}} \ No newline at end of file diff --git a/examples/p5js/DBSCAN/.gitkeep b/examples/p5js/DBSCAN/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/examples/p5js/PoseNet/PoseNet_image_single/sketch.js b/examples/p5js/PoseNet/PoseNet_image_single/sketch.js index 1a896b22f..ed79b3408 100644 --- a/examples/p5js/PoseNet/PoseNet_image_single/sketch.js +++ b/examples/p5js/PoseNet/PoseNet_image_single/sketch.js @@ -1,66 +1,41 @@ let img; let poseNet; -let poses = []; -function setup() { - createCanvas(640, 360); - - // create an image using the p5 dom library - // call modelReady() when it is loaded - img = createImg("data/runner.jpg", imageReady); - // set the image size to the size of the canvas - img.size(width, height); - - img.hide(); // hide the image in the browser - frameRate(1); // set the frameRate to 1 since we don't need it to be running quickly in this case +function preload() { + // load an image for pose detection + img = loadImage('data/runner.jpg'); } -// when the image is ready, then load up poseNet -function imageReady() { - // set some options - const options = { - minConfidence: 0.1, - inputResolution: { width, height }, - }; - - // assign poseNet - poseNet = ml5.poseNet(modelReady, options); - // This sets up an event that listens to 'pose' events - poseNet.on("pose", function(results) { - poses = results; - }); +function setup() { + createCanvas(640, 360); + image(img, 0, 0); + poseNet = ml5.poseNet(modelReady); } // when poseNet is ready, do the detection function modelReady() { - select("#status").html("Model Loaded"); - + select('#status').html('Model Loaded'); + // If/When a pose is detected, poseNet.on('pose', ...) will be listening for the detection results + poseNet.on('pose', function (poses) { + if (poses.length > 0) { + drawSkeleton(poses); + drawKeypoints(poses); + } + }); // When the model is ready, run the singlePose() function... - // If/When a pose is detected, poseNet.on('pose', ...) will be listening for the detection results - // in the draw() loop, if there are any poses, then carry out the draw commands poseNet.singlePose(img); } -// draw() will not show anything until poses are found -function draw() { - if (poses.length > 0) { - image(img, 0, 0, width, height); - drawSkeleton(poses); - drawKeypoints(poses); - noLoop(); // stop looping when the poses are estimated - } -} - // The following comes from https://ml5js.org/docs/posenet-webcam // A function to draw ellipses over the detected keypoints -function drawKeypoints() { +function drawKeypoints(poses) { // Loop through all the poses detected - for (let i = 0; i < poses.length; i += 1) { + for (let i = 0; i < poses.length; i++) { // For each pose detected, loop through all the keypoints - const pose = poses[i].pose; - for (let j = 0; j < pose.keypoints.length; j += 1) { + let pose = poses[i].pose; + for (let j = 0; j < pose.keypoints.length; j++) { // A keypoint is an object describing a body part (like rightArm or leftShoulder) - const keypoint = pose.keypoints[j]; + let keypoint = pose.keypoints[j]; // Only draw an ellipse is the pose probability is bigger than 0.2 if (keypoint.score > 0.2) { fill(255); @@ -73,17 +48,17 @@ function drawKeypoints() { } // A function to draw the skeletons -function drawSkeleton() { +function drawSkeleton(poses) { // Loop through all the skeletons detected - for (let i = 0; i < poses.length; i += 1) { - const skeleton = poses[i].skeleton; + for (let i = 0; i < poses.length; i++) { + let skeleton = poses[i].skeleton; // For every skeleton, loop through all body connections - for (let j = 0; j < skeleton.length; j += 1) { - const partA = skeleton[j][0]; - const partB = skeleton[j][1]; + for (let j = 0; j < skeleton.length; j++) { + let partA = skeleton[j][0]; + let partB = skeleton[j][1]; stroke(255); strokeWeight(1); line(partA.position.x, partA.position.y, partB.position.x, partB.position.y); } } -} +} \ No newline at end of file diff --git a/karma.conf.js b/karma.conf.js index 1d952d06d..9ca2f9f27 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -11,11 +11,13 @@ module.exports = config => { frameworks: ["jasmine"], files: [ "src/index.js", + "src/utils/*_test.js", `src/${config.model ? config.model : "**"}/*_test.js`, `src/${config.model ? config.model : "**"}/**/*_test.js`, ], preprocessors: { "src/index.js": ["webpack"], + "src/utils/*.js": ["webpack"], }, webpack: { // TODO: This is duplication of the webpack.common.babel.js file, but they diff --git a/package-lock.json b/package-lock.json index 5901424ad..157b37453 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "ml5", - "version": "0.9.8", + "version": "0.10.6", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index afd8350fc..79ec807df 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ml5", - "version": "0.9.8", + "version": "0.10.6", "description": "A friendly machine learning library for the web.", "main": "dist/ml5.min.js", "directories": { diff --git a/src/BodyPix/index.js b/src/BodyPix/index.js index 57deedc07..1433485ba 100644 --- a/src/BodyPix/index.js +++ b/src/BodyPix/index.js @@ -90,14 +90,13 @@ class BodyPix { bodyPartsSpec(colorOptions) { const result = colorOptions !== undefined || Object.keys(colorOptions).length >= 24 ? colorOptions : this.config.palette; - // Check if we're getting p5 colors, make sure they are rgb - if (p5Utils.checkP5() && result !== undefined && Object.keys(result).length >= 24) { + // Check if we're getting p5 colors, make sure they are rgb + const p5 = p5Utils.p5Instance; + if (p5 && result !== undefined && Object.keys(result).length >= 24) { // Ensure the p5Color object is an RGB array Object.keys(result).forEach(part => { - if (result[part].color instanceof window.p5.Color) { + if (result[part].color instanceof p5.Color) { result[part].color = this.p5Color2RGB(result[part].color); - } else { - result[part].color = result[part].color; } }); } @@ -452,4 +451,4 @@ const bodyPix = (videoOrOptionsOrCallback, optionsOrCallback, cb) => { return callback ? instance : instance.ready; } -export default bodyPix; \ No newline at end of file +export default bodyPix; diff --git a/src/DBSCAN/index.js b/src/DBSCAN/index.js new file mode 100644 index 000000000..af99840cc --- /dev/null +++ b/src/DBSCAN/index.js @@ -0,0 +1,180 @@ +// Copyright (c) 2020 ml5 +// +// This software is released under the MIT License. +// https://opensource.org/licenses/MIT + +/* eslint "no-param-reassign": [2, { "props": false }] */ +/* +DBSCAN Algorithm (with Euclidian distance). Influenced By jDBSCAN +*/ + +import * as tf from "@tensorflow/tfjs"; +import callCallback from "../utils/callcallback"; + +/** + * Read in a csv file from a path to its location. + * @param {string} path + */ +async function readCsv(path) { + const myCsv = tf.data.csv(path); + const loadedData = await myCsv.toArray(); + return loadedData; +} + +/** + * Load and flatten an array of arrays, an array of objects, or a string + * path to a csv. + * @param {string || array || object} inputData + */ +async function loadDataset(inputData) { + let data; + if (typeof inputData === "string") { + data = await readCsv(inputData); + } else { + data = inputData; + } + const dataFlat = data.map(d => { + return Object.values(d); + }); + return dataFlat; +} + +const DEFAULTS = { + eps: 50, + minPts: 3, +}; + +class DBSCAN { + /** + * Create a DBSCAN. + * @param {String || array || object} dataset - The dataset to cluster. in x, y format => [{x:1,y:2}] + * @param {options} options - An object describing a model's parameters: + * - eps: Minimum distance between neighbours + * - minPts: Minimum number of neighbours to count as a core point + * @param {function} callback - Optional. A callback to be called once + * the model has loaded. If no callback is provided, it will return a + * promise that will be resolved once the model has loaded. + */ + + constructor(dataset, options, callback) { + this.config = { + eps: options.eps || DEFAULTS.eps, + minPts: options.minPts || DEFAULTS.minPts, + }; + this.lastClusterId = 0; + this.status = []; + this.ready = callCallback(this.load(dataset), callback); + } + + /** + * Load dataset, and run model. + * @param {string || array || object} dataset + */ + async load(dataset) { + this.dataset = await loadDataset(dataset); + tf.tidy(() => { + this.dataTensor = tf.tensor2d(this.dataset); + this.dataset.forEach(d => { + const tensors = tf.tensor1d(Object.values(d)); + d.tensor = tensors; + }); + this.fit(); + }); + return this; + } + + /** + * Run DBSCAN algorithm. + */ + fit() { + this.dataset.forEach((d, idx) => { + if (d.status === undefined) { + d.status = 0; // initlize as a noise point + const neighboursIndices = this.getNeighboursIndices(d); + if (neighboursIndices.length < this.config.minPts) { + // Border or noise + d.status = 0; + } else { + this.incrementClusterId(); + this.extend(idx, neighboursIndices); + } + } + }); + } + + /** + * Extend cluster by running algorithm on neighbours and detect neighbours that are core points as well + * @param {number} pointIndex + * @param {number[]} neighboursIndices + */ + extend(pointIndex, neighboursIndices) { + this.dataset[pointIndex].clusterid = this.getClusterId(); + this.dataset[pointIndex].status = this.dataset[pointIndex].clusterid; + neighboursIndices.forEach(neighbourIndex => { + if (this.dataset[neighbourIndex].status === undefined) { + // Status unknown intialize as noise + this.dataset[neighbourIndex].status = 0; + const currNeighbours = this.getNeighboursIndices( + // Neighbours of this point + this.dataset[neighbourIndex], + ); + const currNumNeighbours = currNeighbours.length; + + if (currNumNeighbours >= this.config.minPts) { + // If Neighbours are above minimum we go further and add this and potential neighbours to clusterId + this.extend(neighbourIndex, currNeighbours); + } + } + if (this.dataset[neighbourIndex].status < 1) { + this.dataset[neighbourIndex].status = this.dataset[pointIndex].clusterid; + this.dataset[neighbourIndex].clusterid = this.dataset[pointIndex].clusterid; + } + }); + } + + /** + * Return last generated cluster id + */ + getClusterId() { + return this.lastClusterId; + } + /** + * increment cluster id + */ + incrementClusterId() { + this.lastClusterId += 1; + } + + /** + * Find closest neighbours to each observation. + */ + getNeighboursIndices(point) { + try { + const neighbours = tf.tidy(() => { + const { values, indices } = tf + .squaredDifference(point.tensor, this.dataTensor) + .sum(1) + .sqrt() + .topk(this.dataTensor.shape[0], true); + return tf + .stack([values.asType("float32"), indices.asType("float32")], 1) + .arraySync() + .filter(v => { + return v[0] <= this.config.eps; + }) + .reduce((prev, cur) => { + prev.push(cur[1]); + return prev; + }, []); + }); + return neighbours || []; + } catch (error) { + console.log(`error ${error}`); + } + return []; + } +} + +const dbscan = (dataset, options, callback) => new DBSCAN(dataset, options, callback); + +export default dbscan; diff --git a/src/DBSCAN/index_test.js b/src/DBSCAN/index_test.js new file mode 100644 index 000000000..7fa1e0079 --- /dev/null +++ b/src/DBSCAN/index_test.js @@ -0,0 +1,33 @@ +// Copyright (c) 2019 ml5 +// +// This software is released under the MIT License. +// https://opensource.org/licenses/MIT + +const { dbscan } = ml5; + +const DBSCAN_DEFAULTS = { + eps: 50, + minPts: 3, +}; + +describe("DBSCAN", () => { + let dbscanModel; + const dataurl = + "https://raw.githubusercontent.com/asvsfs/ml5-library/dbscan/examples/d3/DBSCAN/DBSCAN_Cluster/data/gaussian2d_1.55clusters.csv"; + + beforeAll(async () => { + jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000; + dbscanModel = await dbscan(dataurl, DBSCAN_DEFAULTS, () => {}); + await dbscanModel.load(dataurl); + }); + + it("Should create dbscan with all the defaults", async () => { + expect(dbscanModel.config.eps).toBe(DBSCAN_DEFAULTS.eps); + expect(dbscanModel.config.minPts).toBe(DBSCAN_DEFAULTS.minPts); + }); + + it("dbscanModel dataset : Should have length 300", async () => { + // await kmeansModel.load(dataurl) + expect(dbscanModel.dataset.length).toBe(300); + }); +}); diff --git a/src/FaceApi/index.js b/src/FaceApi/index.js index 27469c1d5..0ea10814f 100644 --- a/src/FaceApi/index.js +++ b/src/FaceApi/index.js @@ -5,6 +5,7 @@ /* eslint prefer-destructuring: ["error", {AssignmentExpression: {array: false}}] */ /* eslint no-await-in-loop: "off" */ +/* eslint class-methods-use-this: "off" */ /* * FaceApi: real-time face recognition, and landmark detection @@ -14,6 +15,7 @@ import * as tf from "@tensorflow/tfjs"; import * as faceapi from "face-api.js"; import callCallback from "../utils/callcallback"; +import modelLoader from "../utils/modelLoader"; const DEFAULTS = { withLandmarks: true, @@ -93,7 +95,7 @@ class FaceApiBase { Object.keys(this.config.MODEL_URLS).forEach(item => { if (modelOptions.includes(item)) { - this.config.MODEL_URLS[item] = this.getModelPath(this.config.MODEL_URLS[item]); + this.config.MODEL_URLS[item] = modelLoader.getModelPath(this.config.MODEL_URLS[item]); } }); @@ -354,18 +356,6 @@ class FaceApiBase { return _param !== undefined ? _param : _default; } - /** - * Checks if the given string is an absolute or relative path and returns - * the path to the modelJson - * @param {String} absoluteOrRelativeUrl - */ - getModelPath(absoluteOrRelativeUrl) { - const modelJsonPath = this.isAbsoluteURL(absoluteOrRelativeUrl) - ? absoluteOrRelativeUrl - : window.location.pathname + absoluteOrRelativeUrl; - return modelJsonPath; - } - /** * Sets the return options for .detect() or .detectSingle() in case any are given * @param {Object} faceApiOptions @@ -399,12 +389,6 @@ class FaceApiBase { }); } - /* eslint class-methods-use-this: "off" */ - isAbsoluteURL(str) { - const pattern = new RegExp("^(?:[a-z]+:)?//", "i"); - return !!pattern.test(str); - } - /** * get parts from landmarks * @param {*} result diff --git a/src/Facemesh/index.js b/src/Facemesh/index.js index ee0c35c37..905c4bd0d 100644 --- a/src/Facemesh/index.js +++ b/src/Facemesh/index.js @@ -3,9 +3,6 @@ // This software is released under the MIT License. // https://opensource.org/licenses/MIT -/* eslint prefer-destructuring: ["error", {AssignmentExpression: {array: false}}] */ -/* eslint no-await-in-loop: "off" */ - /* * Facemesh: Facial landmark detection in the browser * Ported and integrated from all the hard work by: https://github.com/tensorflow/tfjs-models/tree/master/facemesh @@ -19,14 +16,17 @@ import callCallback from "../utils/callcallback"; class Facemesh extends EventEmitter { /** * Create Facemesh. - * @param {HTMLVideoElement} video - An HTMLVideoElement. - * @param {object} options - An object with options. - * @param {function} callback - A callback to be called when the model is ready. + * @param {HTMLVideoElement} [video] - An HTMLVideoElement. + * @param {object} [options] - An object with options. + * @param {function} [callback] - A callback to be called when the model is ready. */ constructor(video, options, callback) { super(); this.video = video; + /** + * @type {null | facemeshCore.FaceMesh} + */ this.model = null; this.modelReady = false; this.config = options; @@ -49,18 +49,21 @@ class Facemesh extends EventEmitter { }; }); } - - this.predict(); + if (this.video) { + this.predict(); + } return this; } /** - * Load the model and set it to this.model - * @return {this} the Facemesh model. + * @return {Promise} an array of predictions. */ async predict(inputOr, callback) { const input = this.getInput(inputOr); + if (!input) { + throw new Error("No input image found."); + } const { flipHorizontal } = this.config; const predictions = await this.model.estimateFaces(input, flipHorizontal); const result = predictions; diff --git a/src/Handpose/index.js b/src/Handpose/index.js index 341a08cf7..029b43d62 100644 --- a/src/Handpose/index.js +++ b/src/Handpose/index.js @@ -3,9 +3,6 @@ // This software is released under the MIT License. // https://opensource.org/licenses/MIT -/* eslint prefer-destructuring: ["error", {AssignmentExpression: {array: false}}] */ -/* eslint no-await-in-loop: "off" */ - /* * Handpose: Palm detector and hand-skeleton finger tracking in the browser * Ported and integrated from all the hard work by: https://github.com/tensorflow/tfjs-models/tree/master/handpose @@ -19,14 +16,17 @@ import callCallback from "../utils/callcallback"; class Handpose extends EventEmitter { /** * Create Handpose. - * @param {HTMLVideoElement} video - An HTMLVideoElement. - * @param {object} options - An object with options. - * @param {function} callback - A callback to be called when the model is ready. + * @param {HTMLVideoElement} [video] - An HTMLVideoElement. + * @param {object} [options] - An object with options. + * @param {function} [callback] - A callback to be called when the model is ready. */ constructor(video, options, callback) { super(); this.video = video; + /** + * @type {null|handposeCore.HandPose} + */ this.model = null; this.modelReady = false; this.config = options; @@ -50,19 +50,20 @@ class Handpose extends EventEmitter { }); } - this.predict(); + if (this.video) { + this.predict(); + } return this; } /** - * Load the model and set it to this.model - * @return {this} the Handpose model. + * @return {Promise} an array of predictions. */ async predict(inputOr, callback) { const input = this.getInput(inputOr); if (!input) { - return []; + throw new Error("No input image found."); } const { flipHorizontal } = this.config; const predictions = await this.model.estimateHands(input, flipHorizontal); diff --git a/src/ImageClassifier/index.js b/src/ImageClassifier/index.js index 97ca5a278..b127031a2 100644 --- a/src/ImageClassifier/index.js +++ b/src/ImageClassifier/index.js @@ -65,7 +65,10 @@ class ImageClassifier { this.modelToUse = null; } } else { + // its a url, we expect to find model.json this.modelUrl = modelNameOrUrl; + // The teachablemachine urls end with a slash, so add model.json to complete the full path + if (this.modelUrl.endsWith('/')) this.modelUrl += "model.json"; } } // Load the model diff --git a/src/NeuralNetwork/NeuralNetworkData.js b/src/NeuralNetwork/NeuralNetworkData.js index 01e35ab9b..05cdb633b 100644 --- a/src/NeuralNetwork/NeuralNetworkData.js +++ b/src/NeuralNetwork/NeuralNetworkData.js @@ -955,6 +955,16 @@ class NeuralNetworkData { return parentCopy; } + + /** + * getData + * return data object's raw array + * to make getting raw data easier + */ + getData() { + const rawArray = this.data.raw; + return rawArray; + } } export default NeuralNetworkData; diff --git a/src/StyleTransfer/index.js b/src/StyleTransfer/index.js index e7835094d..0473a3479 100644 --- a/src/StyleTransfer/index.js +++ b/src/StyleTransfer/index.js @@ -54,7 +54,6 @@ class StyleTransfer extends Video { async load(model) { if (this.videoElt) { await this.loadVideo(); - this.videoReady = true; } await this.loadCheckpoints(model); return this; diff --git a/src/index.js b/src/index.js index 174e38550..c6c7fbfe7 100644 --- a/src/index.js +++ b/src/index.js @@ -30,6 +30,7 @@ import bodyPix from "./BodyPix"; import neuralNetwork from "./NeuralNetwork"; import faceApi from "./FaceApi"; import kmeans from "./KMeans"; +import dbscan from "./DBSCAN"; import cartoon from "./CartoonGAN"; import universalSentenceEncoder from "./UniversalSentenceEncoder"; import facemesh from "./Facemesh"; @@ -46,6 +47,7 @@ const withPreload = { featureExtractor, imageClassifier, kmeans, + dbscan, soundClassifier, pitchDetection, pix2pix, diff --git a/src/utils/Video.js b/src/utils/Video.js index fa297017a..f8a3767f4 100644 --- a/src/utils/Video.js +++ b/src/utils/Video.js @@ -8,22 +8,51 @@ Image and Video base class */ class Video { + /** + * @property {HTMLVideoElement} [video] + */ + + /** + * @param {HTMLVideoElement | p5.Video | null | undefined} [video] - Can pass a video + * into the constructor of the model in order to run the model on every frame of the video. + * @param {number | null | undefined} [size] - The size expected by the underlying model. + * NOT the size of the current video. The size will be used to resize the current video. + */ constructor(video, size) { + /** + * @type {HTMLVideoElement | null} + */ this.videoElt = null; + /** + * @type {number | null | undefined} + */ this.size = size; + /** + * @type {boolean} + */ this.videoReady = false; - if (video instanceof HTMLVideoElement) { - this.videoElt = video; - } else if (video !== null && typeof video === 'object' && video.elt instanceof HTMLVideoElement) { - // Handle p5.js video element - this.videoElt = video.elt; + if (typeof HTMLVideoElement !== 'undefined') { + if (video instanceof HTMLVideoElement) { + this.videoElt = video; + } else if (video !== null && typeof video === 'object' && video.elt instanceof HTMLVideoElement) { + // Handle p5.js video element + this.videoElt = video.elt; + } } } + /** + * Copies the stream from the source video into a new video element. + * The copied element is set to property `this.video` and is also returned by the function. + * @returns {Promise} + */ async loadVideo() { let stream; - return new Promise((resolve) => { + return new Promise((resolve, reject) => { + if (!this.videoElt) { + reject(new Error('No video was passed to the constructor.')); + } this.video = document.createElement('video'); const sUsrAg = navigator.userAgent; if (sUsrAg.indexOf('Firefox') > -1) { @@ -32,14 +61,17 @@ class Video { stream = this.videoElt.captureStream(); } this.video.srcObject = stream; - this.video.width = this.size; - this.video.height = this.size; + if (this.size) { + this.video.width = this.size; + this.video.height = this.size; + } this.video.autoplay = true; this.video.playsinline = true; this.video.muted = true; const playPromise = this.video.play(); if (playPromise !== undefined) { playPromise.then(() => { + this.videoReady = true; resolve(this.video); }); } diff --git a/src/utils/callcallback.js b/src/utils/callcallback.js index 3fd6dd42e..a875d033e 100644 --- a/src/utils/callcallback.js +++ b/src/utils/callcallback.js @@ -3,17 +3,38 @@ // This software is released under the MIT License. // https://opensource.org/licenses/MIT + +/** + * Most ml5 methods accept a callback function which will be + * called with the arguments (error, result). + * + * Generic type T describes the type of the result. + * @template T + * @callback ML5Callback + * @param {unknown} error - any error thrown during the execution of the function. + * @param {T} [result] - the expected result, if successful. + * @return {void} - callbacks can have side effects, but should not return a value. + */ + +/** + * Generic type T describes the type of the result, ie. the value that the Promise will resolve to. + * @template T + * @param {Promise} promise - the Promise to resolve. + * @param {ML5Callback} [callback] - optional callback function to be called + * with the result or error from the resolved Promise. + * @return {Promise} - returns the underlying Promise, which may be rejected. + */ export default function callCallback(promise, callback) { - if (callback) { + if (!callback) return promise; + return new Promise((resolve, reject) => { promise .then((result) => { callback(undefined, result); - return result; + resolve(result); }) .catch((error) => { callback(error); - return error; + reject(error); }); - } - return promise; + }); } diff --git a/src/utils/callcallback_test.js b/src/utils/callcallback_test.js new file mode 100644 index 000000000..df60a2b23 --- /dev/null +++ b/src/utils/callcallback_test.js @@ -0,0 +1,80 @@ +import callCallback from "./callcallback"; + +describe("callCallback", () => { + describe("if no arguments are passed", () => { + it("returns undefined", () => { + const result = callCallback(); + expect(result).toBe(undefined); + }); + }); + describe("if nothing is passed to the second argument", () => { + it("returns whatever is in the first argument if one exists", () => { + const mockArg = "yo"; + const result = callCallback(mockArg); + expect(result).toBe(mockArg); + }); + it("returns a promise if it passed as the first argument", async () => { + const mockFunction = greeting => + new Promise(resolve => { + resolve(greeting); + }); + const result = callCallback(mockFunction("yo")); + expect(result instanceof Promise).toBe(true); + expect(await callCallback(mockFunction("yo"))).toBe("yo"); + }); + }); + describe("if a promise object is passed as the first argument and a callback is passed as a second argument", () => { + describe("when the promise is successful", () => { + it("it calls the callback function with the result of the promise", async () => { + const mockFunction = greeting => + new Promise(resolve => { + resolve(greeting); + }); + + const mockCallback = (err, result) => { + return `hello ${result}`; + }; + + const mockUtils = { mockCallback }; + spyOn(mockUtils, "mockCallback").and.callThrough(); + + const result = callCallback(mockFunction("world"), mockUtils.mockCallback); + expect(result instanceof Promise).toBe(true); + + result.then(innerPromise => { + innerPromise.then(callbackResults => { + expect(mockUtils.mockCallback).toHaveBeenCalledTimes(1); + expect(callbackResults).toBe("hello world"); + }); + }); + }); + }); + describe("when the promise fails", () => { + it("it calls the callback function with the error", async () => { + const mockFunction = greeting => + new Promise(resolve => { + resolve(greeting); + }); + + const mockCallback = (err, result) => { + if (err) throw err; + return `hello ${result}`; + }; + + const mockUtils = { mockCallback, mockFunction }; + spyOn(mockUtils, "mockCallback").and.callThrough(); + spyOn(mockUtils, "mockFunction").and.returnValue(Promise.reject(new Error("error"))); + + const result = callCallback(mockFunction("world"), mockUtils.mockCallback); + expect(result instanceof Promise).toBe(true); + + result.then(innerPromise => { + innerPromise.catch(err => { + expect(mockUtils.mockCallback).toHaveBeenCalledTimes(1); + expect(mockUtils.mockCallback).toHaveBeenCalledOnceWith(err); + }); + }); + }); + }); + }); +}); diff --git a/src/utils/modelLoader.js b/src/utils/modelLoader.js index f4fc42514..f602d07d1 100644 --- a/src/utils/modelLoader.js +++ b/src/utils/modelLoader.js @@ -1,14 +1,28 @@ +/** + * Check if the provided URL string starts with a hostname, + * such as http://, https://, etc. + * @param {string} str + * @returns {boolean} + */ function isAbsoluteURL(str) { const pattern = new RegExp('^(?:[a-z]+:)?//', 'i'); - return !!pattern.test(str); + return pattern.test(str); } +/** + * Accepts a URL that may be a complete URL, or a relative location. + * Returns an absolute URL based on the current window location. + * @param {string} absoluteOrRelativeUrl + * @returns {string} + */ function getModelPath(absoluteOrRelativeUrl) { - const modelJsonPath = isAbsoluteURL(absoluteOrRelativeUrl) ? absoluteOrRelativeUrl : window.location.pathname + absoluteOrRelativeUrl - return modelJsonPath; + if (!isAbsoluteURL(absoluteOrRelativeUrl) && typeof window !== 'undefined') { + return window.location.pathname + absoluteOrRelativeUrl; + } + return absoluteOrRelativeUrl; } export default { isAbsoluteURL, getModelPath -} \ No newline at end of file +} diff --git a/src/utils/p5Utils.js b/src/utils/p5Utils.js index 829144faf..4c12a363b 100644 --- a/src/utils/p5Utils.js +++ b/src/utils/p5Utils.js @@ -5,21 +5,31 @@ class P5Util { constructor() { + if (typeof window !== "undefined") { + /** + * Store the window as a private property regardless of whether p5 is present. + * Can also set this property by calling method setP5Instance(). + * @property {Window | p5 | {p5: p5} | undefined} m_p5Instance + * @private + */ this.m_p5Instance = window; + } } /** - * Set p5 instance globally. - * @param {Object} p5Instance + * Set p5 instance globally in order to enable p5 features throughout ml5. + * Call this function with the p5 instance when using p5 in instance mode. + * @param {p5 | {p5: p5}} p5Instance */ setP5Instance(p5Instance) { - this.m_p5Instance = p5Instance; + this.m_p5Instance = p5Instance; } /** - * This getter will return p5, checking first if it is in - * the window and next if it is in the p5 property of this.m_p5Instance - * @returns {boolean} if it is in p5 + * Dynamic getter checks if p5 is loaded and will return undefined if p5 cannot be found, + * or will return an object containing all of the global p5 properties. + * It first checks if p5 is in the window, and then if it is in the p5 property of this.m_p5Instance. + * @returns {p5 | undefined} */ get p5Instance() { if (typeof this.m_p5Instance !== "undefined" && @@ -33,75 +43,81 @@ class P5Util { /** * This function will check if the p5 is in the environment - * Either it is in the p5Instance mode OR it is in the window - * @returns {boolean} if it is in p5 + * Either it is in the p5Instance mode OR it is in the window + * @returns {boolean} if it is in p5 */ checkP5() { return !!this.p5Instance; } /** - * Convert a canvas to Blob - * @param {HTMLCanvasElement} inputCanvas - * @returns {Blob} blob object - */ + * Convert a canvas to a Blob object. + * @param {HTMLCanvasElement} inputCanvas + * @returns {Promise} + */ /* eslint class-methods-use-this: ["error", { "exceptMethods": ["getBlob"] }] */ getBlob(inputCanvas) { - return new Promise((resolve) => { + return new Promise((resolve, reject) => { inputCanvas.toBlob((blob) => { - resolve(blob); + if (blob) { + resolve(blob); + } else { + reject(new Error('Canvas could not be converted to Blob.')); + } }); }); }; /** - * Load image in async way. - * @param {String} url - */ + * Load a p5.Image from a URL in an async way. + * @param {string} url + * @return {Promise} + */ loadAsync(url) { - return new Promise((resolve) => { + return new Promise((resolve, reject) => { this.p5Instance.loadImage(url, (img) => { resolve(img); + }, () => { + reject(new Error(`Could not load image from url ${url}`)); }); }); }; /** - * convert raw bytes to blob object - * @param {Array} raws - * @param {number} x - * @param {number} y - * @returns {Blob} - */ - async rawToBlob(raws, x, y) { + * convert raw bytes to blob object + * @param {number[] | Uint8ClampedArray | ArrayLike} raws + * @param {number} width + * @param {number} height + * @returns {Promise} + */ + async rawToBlob(raws, width, height) { const arr = Array.from(raws) const canvas = document.createElement('canvas'); // Consider using offScreenCanvas when it is ready? const ctx = canvas.getContext('2d'); - canvas.width = x; - canvas.height = y; + canvas.width = width; + canvas.height = height; - const imgData = ctx.createImageData(x, y); - const { data } = imgData; + const imgData = ctx.createImageData(width, height); + const {data} = imgData; - for (let i = 0; i < x * y * 4; i += 1 ) data[i] = arr[i]; + for (let i = 0; i < width * height * 4; i += 1) data[i] = arr[i]; ctx.putImageData(imgData, 0, 0); - const blob = await this.getBlob(canvas); - return blob; + return this.getBlob(canvas); }; /** - * Conver Blob to P5.Image - * @param {Blob} blob - * @param {Object} p5Img - */ + * Convert Blob to P5.Image + * @param {Blob} blob + * Note: may want to reject instead of returning null. + * @returns {Promise} + */ async blobToP5Image(blob) { - if (this.checkP5()) { - const p5Img = await this.loadAsync(URL.createObjectURL(blob)); - return p5Img; + if (this.checkP5() && typeof URL !== "undefined") { + return this.loadAsync(URL.createObjectURL(blob)); } - return null; + return null; }; }