├── _config.yml ├── img ├── .gitkeep ├── 00-arvo-exploded.png ├── 00-fare.png ├── 00-mangofarm.png ├── 00-urbit-all.png ├── 00-urbit-exploded.png ├── 01-header-goddard-1.png ├── 01-header-goddard-2.png ├── 01-header-goddard.png ├── 02-header-gemini-1.png ├── 02-header-gemini-2.png ├── 02-header-gemini-3.png ├── 02-lana.png ├── 02-meteor-crater.png ├── 03-header-1.png ├── 03-header-2.png ├── 03-header-3.png ├── 03-header-4.png ├── 03-header-5.png ├── 03-header-6.png ├── 05-binary-tree-128.png ├── 05-binary-tree-15.png ├── 05-binary-tree-abcdef.png ├── 05-header-mccall-1.png ├── 05-header-mccall-2.png ├── 05-header-mccall-3.png ├── 05-header-mccall-4.png ├── 05-hoon-pronunciation.png ├── 06-turk-1.png ├── 06-turk-2.png ├── 06-turk-3.png ├── 07-header-apollo-1.png ├── 07-header-apollo-2.png ├── 07-header-apollo-3.png ├── 08-mars-map.png ├── 08-nubret.png ├── 08-schiaparelli-01.png ├── 08-schiaparelli-02.png ├── 09-header-stars-1.png ├── 09-header-stars-2.png ├── 09-header-stars-3.png ├── 10-header-stars-1.png ├── 10-header-stars-2.png ├── 10-header-stars-3.png ├── 10-header-stars-4.png ├── 11-header-nasa-1.png ├── 11-header-nasa-2.png ├── 11-header-nasa-3.png ├── 12-header-voyager-1.png ├── 12-header-voyager-2.png ├── 12-header-voyager-3.png ├── 13-header-jupiter.png ├── 13-header-neptune.png ├── 13-header-saturn.png ├── 13-header-uranus.png ├── 14-header-galileo-1.png ├── 14-header-galileo-2.png ├── 14-header-galileo-3.png ├── 14-header-galileo-4.png ├── 14-header-galileo-5.png ├── 15-header-airplane.png ├── 15-header-crm114.png ├── 15-header-missiles.png ├── 15-header-turgidson.png ├── 15-header-warroom-bottom.png ├── 15-header-warroom-top.png ├── 16-header-moebius1.png ├── 16-header-moebius2.png ├── 16-header-moebius3.png ├── 16-header-moebius4.png ├── 16-header-moebius5.png ├── 16-header-moebius6.png ├── 17-header-contrail.png ├── 17-header-interceptor.jpg ├── 17-header-iron-dome.png ├── 17-header-launch.png ├── 17-header-minuteman.png ├── 18-header-verne1.png ├── 18-header-verne2.png ├── 18-header-verne3.png ├── 19-berkey-0.png ├── 19-berkey-1.png ├── 19-berkey-2.png ├── 19-berkey-3.png ├── 20-foss-0.png ├── 20-foss-1.png ├── 20-foss-2.png ├── 20-foss-3.png ├── 21-mccall-0.png ├── 21-mccall-1.png ├── 22-header-mccall-0.png ├── 22-header-mccall-1.png ├── 22-header-mccall-2.png ├── 22-header-mccall-3.png ├── 22-header-mccall-4.png ├── 23-header-mccall-0.png ├── 23-header-mccall-1.png ├── 23-header-mccall-2.png ├── 24-header.png ├── 25-header-orion-0.png ├── 25-header-orion-1.png ├── 25-header-orion-2.png ├── 25-header-orion-3.png ├── 25-header-orion-4.png ├── 25-header-orion-5.png ├── 26-header-guest-0.png ├── 26-header-nebula-0.png ├── 28-header-br0.png ├── 28-header-br1.png ├── 28-header-br2.png ├── 28-header-br3.png ├── 29-header-cyberpunk-0.png ├── 29-header-cyberpunk-1.png ├── 29-header-cyberpunk-2.png ├── 29-header-cyberpunk-3.png ├── 29-header-cyberpunk-4.png ├── 30-header-titan-0.png ├── 30-header-titan-1.png ├── 30-header-titan-2.png ├── 30-header-titan-3.png ├── 30-header-titan-4.png ├── 30-header-titan-5.png ├── 31-header-phobos-0.png ├── 31-header-phobos-1.png ├── 31-header-phobos-2.png ├── 32-header-jupiter-0.png ├── 32-header-jupiter-1.png ├── 32-header-jupiter-2.png ├── 32-header-jupiter-3.png ├── 33-header-callisto.png ├── 33-header-europa.png ├── 33-header-ganymede.png ├── 33-header-io.png ├── 34-header-comet-0.gif ├── 34-header-comet-1.gif ├── 34-header-comet-2.gif ├── 34-header-comet-3.gif ├── 35-header-comet-0.png ├── 35-header-comet-1.png ├── 35-header-comet-2.png ├── 36-37-images.odg ├── 36-arvo-road.png ├── 36-header-comet-0.gif ├── 36-header-comet-1.gif ├── 36-header-comet-2.gif ├── 37-arvo-cards.png ├── 37-header-oort-0.png ├── 37-header-oort-1.png ├── 37-header-oort-2.png ├── 38-header-neptune-0.png ├── 38-header-neptune-1.png ├── 38-header-neptune-2.png ├── 39-header-pluto-0.png ├── 39-header-pluto-1.png ├── 40-header-mars-0.png ├── 40-header-mars-1.png ├── 40-header-mars-2.png ├── 40-header-mars-3.png ├── 41-header-apollo-x.png ├── 41-header-earthrise.png ├── cash-2.png ├── dac.png ├── fosfyr.png ├── fyr.png ├── hanrep-dovres.png ├── jingleheimer.png ├── mars-atmos-hero.png ├── mars-atmos-hero.xcf ├── mars-hero.png ├── mars-landscape-hero.png ├── mars-olympus-mons-hero.png ├── mars-olympus-mons-hero.xcf ├── mars-pathfinder-hero.png ├── mars-pathfinder-hero.xcf ├── mars-rover-hero.png ├── mars-rover-hero.xcf ├── rivpyl-sidpyl-behn-2.gif ├── rivpyl-sidpyl-behn.gif ├── rivpyl-sidpyl-boot.gif ├── sigil-star.png └── winter-martyr.png ├── index.md ├── lessons ├── .gitkeep ├── lesson00-prospectus.md ├── lesson01-dojo.md ├── lesson02-azimuth-1.md ├── lesson03-generators.md ├── lesson04-aura.md ├── lesson05-syntax.md ├── lesson06-cores.md ├── lesson07-say-generators.md ├── lesson08-subject-oriented-programming.md ├── lesson09-clay-1.md ├── lesson10-libraries.md ├── lesson11-ford-1.md ├── lesson12-debugging.md ├── lesson13-ask.md ├── lesson14-typechecking.md ├── lesson15-stdlib.md ├── lesson16-containers.md ├── lesson17-gall-1.md ├── lesson18-kernel.md ├── lesson19-text-parsing.md ├── lesson20-ames.md ├── lesson21-behn.md ├── lesson22-clay-2.md ├── lesson23-polymorphism.md ├── lesson24-foundation.md ├── lesson25-gall-2.md ├── lesson26-gall-3-landscape.md ├── lesson28-eyre-iris.md ├── lesson29-gall-4-communication.md ├── lesson30-boot-process.md ├── lesson31-cli.md ├── lesson32-arvo-1.md ├── lesson33-hoon-1.md ├── lesson34-hoon-2.md ├── lesson35-vere-1.md ├── lesson36-vere-2.md ├── lesson37-arvo-2.md ├── lesson38-nock-1.md ├── lesson39-nock-2.md ├── lesson40-azimuth-2.md └── lesson41-final-thoughts.md └── resources ├── .gitkeep └── pokemon.hoon /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-minimal -------------------------------------------------------------------------------- /img/.gitkeep: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /img/00-arvo-exploded.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/00-arvo-exploded.png -------------------------------------------------------------------------------- /img/00-fare.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/00-fare.png -------------------------------------------------------------------------------- /img/00-mangofarm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/00-mangofarm.png -------------------------------------------------------------------------------- /img/00-urbit-all.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/00-urbit-all.png -------------------------------------------------------------------------------- /img/00-urbit-exploded.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/00-urbit-exploded.png -------------------------------------------------------------------------------- /img/01-header-goddard-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/01-header-goddard-1.png -------------------------------------------------------------------------------- /img/01-header-goddard-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/01-header-goddard-2.png -------------------------------------------------------------------------------- /img/01-header-goddard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/01-header-goddard.png -------------------------------------------------------------------------------- /img/02-header-gemini-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/02-header-gemini-1.png -------------------------------------------------------------------------------- /img/02-header-gemini-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/02-header-gemini-2.png -------------------------------------------------------------------------------- /img/02-header-gemini-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/02-header-gemini-3.png -------------------------------------------------------------------------------- /img/02-lana.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/02-lana.png -------------------------------------------------------------------------------- /img/02-meteor-crater.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/02-meteor-crater.png -------------------------------------------------------------------------------- /img/03-header-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/03-header-1.png -------------------------------------------------------------------------------- /img/03-header-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/03-header-2.png -------------------------------------------------------------------------------- /img/03-header-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/03-header-3.png -------------------------------------------------------------------------------- /img/03-header-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/03-header-4.png -------------------------------------------------------------------------------- /img/03-header-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/03-header-5.png -------------------------------------------------------------------------------- /img/03-header-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/03-header-6.png -------------------------------------------------------------------------------- /img/05-binary-tree-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/05-binary-tree-128.png -------------------------------------------------------------------------------- /img/05-binary-tree-15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/05-binary-tree-15.png -------------------------------------------------------------------------------- /img/05-binary-tree-abcdef.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/05-binary-tree-abcdef.png -------------------------------------------------------------------------------- /img/05-header-mccall-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/05-header-mccall-1.png -------------------------------------------------------------------------------- /img/05-header-mccall-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/05-header-mccall-2.png -------------------------------------------------------------------------------- /img/05-header-mccall-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/05-header-mccall-3.png -------------------------------------------------------------------------------- /img/05-header-mccall-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/05-header-mccall-4.png -------------------------------------------------------------------------------- /img/05-hoon-pronunciation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/05-hoon-pronunciation.png -------------------------------------------------------------------------------- /img/06-turk-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/06-turk-1.png -------------------------------------------------------------------------------- /img/06-turk-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/06-turk-2.png -------------------------------------------------------------------------------- /img/06-turk-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/06-turk-3.png -------------------------------------------------------------------------------- /img/07-header-apollo-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/07-header-apollo-1.png -------------------------------------------------------------------------------- /img/07-header-apollo-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/07-header-apollo-2.png -------------------------------------------------------------------------------- /img/07-header-apollo-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/07-header-apollo-3.png -------------------------------------------------------------------------------- /img/08-mars-map.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/08-mars-map.png -------------------------------------------------------------------------------- /img/08-nubret.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/08-nubret.png -------------------------------------------------------------------------------- /img/08-schiaparelli-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/08-schiaparelli-01.png -------------------------------------------------------------------------------- /img/08-schiaparelli-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/08-schiaparelli-02.png -------------------------------------------------------------------------------- /img/09-header-stars-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/09-header-stars-1.png -------------------------------------------------------------------------------- /img/09-header-stars-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/09-header-stars-2.png -------------------------------------------------------------------------------- /img/09-header-stars-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/09-header-stars-3.png -------------------------------------------------------------------------------- /img/10-header-stars-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/10-header-stars-1.png -------------------------------------------------------------------------------- /img/10-header-stars-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/10-header-stars-2.png -------------------------------------------------------------------------------- /img/10-header-stars-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/10-header-stars-3.png -------------------------------------------------------------------------------- /img/10-header-stars-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/10-header-stars-4.png -------------------------------------------------------------------------------- /img/11-header-nasa-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/11-header-nasa-1.png -------------------------------------------------------------------------------- /img/11-header-nasa-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/11-header-nasa-2.png -------------------------------------------------------------------------------- /img/11-header-nasa-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/11-header-nasa-3.png -------------------------------------------------------------------------------- /img/12-header-voyager-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/12-header-voyager-1.png -------------------------------------------------------------------------------- /img/12-header-voyager-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/12-header-voyager-2.png -------------------------------------------------------------------------------- /img/12-header-voyager-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/12-header-voyager-3.png -------------------------------------------------------------------------------- /img/13-header-jupiter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/13-header-jupiter.png -------------------------------------------------------------------------------- /img/13-header-neptune.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/13-header-neptune.png -------------------------------------------------------------------------------- /img/13-header-saturn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/13-header-saturn.png -------------------------------------------------------------------------------- /img/13-header-uranus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/13-header-uranus.png -------------------------------------------------------------------------------- /img/14-header-galileo-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/14-header-galileo-1.png -------------------------------------------------------------------------------- /img/14-header-galileo-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/14-header-galileo-2.png -------------------------------------------------------------------------------- /img/14-header-galileo-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/14-header-galileo-3.png -------------------------------------------------------------------------------- /img/14-header-galileo-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/14-header-galileo-4.png -------------------------------------------------------------------------------- /img/14-header-galileo-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/14-header-galileo-5.png -------------------------------------------------------------------------------- /img/15-header-airplane.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/15-header-airplane.png -------------------------------------------------------------------------------- /img/15-header-crm114.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/15-header-crm114.png -------------------------------------------------------------------------------- /img/15-header-missiles.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/15-header-missiles.png -------------------------------------------------------------------------------- /img/15-header-turgidson.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/15-header-turgidson.png -------------------------------------------------------------------------------- /img/15-header-warroom-bottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/15-header-warroom-bottom.png -------------------------------------------------------------------------------- /img/15-header-warroom-top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/15-header-warroom-top.png -------------------------------------------------------------------------------- /img/16-header-moebius1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/16-header-moebius1.png -------------------------------------------------------------------------------- /img/16-header-moebius2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/16-header-moebius2.png -------------------------------------------------------------------------------- /img/16-header-moebius3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/16-header-moebius3.png -------------------------------------------------------------------------------- /img/16-header-moebius4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/16-header-moebius4.png -------------------------------------------------------------------------------- /img/16-header-moebius5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/16-header-moebius5.png -------------------------------------------------------------------------------- /img/16-header-moebius6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/16-header-moebius6.png -------------------------------------------------------------------------------- /img/17-header-contrail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/17-header-contrail.png -------------------------------------------------------------------------------- /img/17-header-interceptor.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/17-header-interceptor.jpg -------------------------------------------------------------------------------- /img/17-header-iron-dome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/17-header-iron-dome.png -------------------------------------------------------------------------------- /img/17-header-launch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/17-header-launch.png -------------------------------------------------------------------------------- /img/17-header-minuteman.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/17-header-minuteman.png -------------------------------------------------------------------------------- /img/18-header-verne1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/18-header-verne1.png -------------------------------------------------------------------------------- /img/18-header-verne2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/18-header-verne2.png -------------------------------------------------------------------------------- /img/18-header-verne3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/18-header-verne3.png -------------------------------------------------------------------------------- /img/19-berkey-0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/19-berkey-0.png -------------------------------------------------------------------------------- /img/19-berkey-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/19-berkey-1.png -------------------------------------------------------------------------------- /img/19-berkey-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/19-berkey-2.png -------------------------------------------------------------------------------- /img/19-berkey-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/19-berkey-3.png -------------------------------------------------------------------------------- /img/20-foss-0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/20-foss-0.png -------------------------------------------------------------------------------- /img/20-foss-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/20-foss-1.png -------------------------------------------------------------------------------- /img/20-foss-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/20-foss-2.png -------------------------------------------------------------------------------- /img/20-foss-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/20-foss-3.png -------------------------------------------------------------------------------- /img/21-mccall-0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/21-mccall-0.png -------------------------------------------------------------------------------- /img/21-mccall-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/21-mccall-1.png -------------------------------------------------------------------------------- /img/22-header-mccall-0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/22-header-mccall-0.png -------------------------------------------------------------------------------- /img/22-header-mccall-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/22-header-mccall-1.png -------------------------------------------------------------------------------- /img/22-header-mccall-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/22-header-mccall-2.png -------------------------------------------------------------------------------- /img/22-header-mccall-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/22-header-mccall-3.png -------------------------------------------------------------------------------- /img/22-header-mccall-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/22-header-mccall-4.png -------------------------------------------------------------------------------- /img/23-header-mccall-0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/23-header-mccall-0.png -------------------------------------------------------------------------------- /img/23-header-mccall-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/23-header-mccall-1.png -------------------------------------------------------------------------------- /img/23-header-mccall-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/23-header-mccall-2.png -------------------------------------------------------------------------------- /img/24-header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/24-header.png -------------------------------------------------------------------------------- /img/25-header-orion-0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/25-header-orion-0.png -------------------------------------------------------------------------------- /img/25-header-orion-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/25-header-orion-1.png -------------------------------------------------------------------------------- /img/25-header-orion-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/25-header-orion-2.png -------------------------------------------------------------------------------- /img/25-header-orion-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/25-header-orion-3.png -------------------------------------------------------------------------------- /img/25-header-orion-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/25-header-orion-4.png -------------------------------------------------------------------------------- /img/25-header-orion-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/25-header-orion-5.png -------------------------------------------------------------------------------- /img/26-header-guest-0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/26-header-guest-0.png -------------------------------------------------------------------------------- /img/26-header-nebula-0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/26-header-nebula-0.png -------------------------------------------------------------------------------- /img/28-header-br0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/28-header-br0.png -------------------------------------------------------------------------------- /img/28-header-br1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/28-header-br1.png -------------------------------------------------------------------------------- /img/28-header-br2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/28-header-br2.png -------------------------------------------------------------------------------- /img/28-header-br3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/28-header-br3.png -------------------------------------------------------------------------------- /img/29-header-cyberpunk-0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/29-header-cyberpunk-0.png -------------------------------------------------------------------------------- /img/29-header-cyberpunk-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/29-header-cyberpunk-1.png -------------------------------------------------------------------------------- /img/29-header-cyberpunk-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/29-header-cyberpunk-2.png -------------------------------------------------------------------------------- /img/29-header-cyberpunk-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/29-header-cyberpunk-3.png -------------------------------------------------------------------------------- /img/29-header-cyberpunk-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/29-header-cyberpunk-4.png -------------------------------------------------------------------------------- /img/30-header-titan-0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/30-header-titan-0.png -------------------------------------------------------------------------------- /img/30-header-titan-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/30-header-titan-1.png -------------------------------------------------------------------------------- /img/30-header-titan-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/30-header-titan-2.png -------------------------------------------------------------------------------- /img/30-header-titan-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/30-header-titan-3.png -------------------------------------------------------------------------------- /img/30-header-titan-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/30-header-titan-4.png -------------------------------------------------------------------------------- /img/30-header-titan-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/30-header-titan-5.png -------------------------------------------------------------------------------- /img/31-header-phobos-0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/31-header-phobos-0.png -------------------------------------------------------------------------------- /img/31-header-phobos-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/31-header-phobos-1.png -------------------------------------------------------------------------------- /img/31-header-phobos-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/31-header-phobos-2.png -------------------------------------------------------------------------------- /img/32-header-jupiter-0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/32-header-jupiter-0.png -------------------------------------------------------------------------------- /img/32-header-jupiter-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/32-header-jupiter-1.png -------------------------------------------------------------------------------- /img/32-header-jupiter-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/32-header-jupiter-2.png -------------------------------------------------------------------------------- /img/32-header-jupiter-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/32-header-jupiter-3.png -------------------------------------------------------------------------------- /img/33-header-callisto.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/33-header-callisto.png -------------------------------------------------------------------------------- /img/33-header-europa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/33-header-europa.png -------------------------------------------------------------------------------- /img/33-header-ganymede.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/33-header-ganymede.png -------------------------------------------------------------------------------- /img/33-header-io.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/33-header-io.png -------------------------------------------------------------------------------- /img/34-header-comet-0.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/34-header-comet-0.gif -------------------------------------------------------------------------------- /img/34-header-comet-1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/34-header-comet-1.gif -------------------------------------------------------------------------------- /img/34-header-comet-2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/34-header-comet-2.gif -------------------------------------------------------------------------------- /img/34-header-comet-3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/34-header-comet-3.gif -------------------------------------------------------------------------------- /img/35-header-comet-0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/35-header-comet-0.png -------------------------------------------------------------------------------- /img/35-header-comet-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/35-header-comet-1.png -------------------------------------------------------------------------------- /img/35-header-comet-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/35-header-comet-2.png -------------------------------------------------------------------------------- /img/36-37-images.odg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/36-37-images.odg -------------------------------------------------------------------------------- /img/36-arvo-road.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/36-arvo-road.png -------------------------------------------------------------------------------- /img/36-header-comet-0.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/36-header-comet-0.gif -------------------------------------------------------------------------------- /img/36-header-comet-1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/36-header-comet-1.gif -------------------------------------------------------------------------------- /img/36-header-comet-2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/36-header-comet-2.gif -------------------------------------------------------------------------------- /img/37-arvo-cards.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/37-arvo-cards.png -------------------------------------------------------------------------------- /img/37-header-oort-0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/37-header-oort-0.png -------------------------------------------------------------------------------- /img/37-header-oort-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/37-header-oort-1.png -------------------------------------------------------------------------------- /img/37-header-oort-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/37-header-oort-2.png -------------------------------------------------------------------------------- /img/38-header-neptune-0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/38-header-neptune-0.png -------------------------------------------------------------------------------- /img/38-header-neptune-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/38-header-neptune-1.png -------------------------------------------------------------------------------- /img/38-header-neptune-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/38-header-neptune-2.png -------------------------------------------------------------------------------- /img/39-header-pluto-0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/39-header-pluto-0.png -------------------------------------------------------------------------------- /img/39-header-pluto-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/39-header-pluto-1.png -------------------------------------------------------------------------------- /img/40-header-mars-0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/40-header-mars-0.png -------------------------------------------------------------------------------- /img/40-header-mars-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/40-header-mars-1.png -------------------------------------------------------------------------------- /img/40-header-mars-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/40-header-mars-2.png -------------------------------------------------------------------------------- /img/40-header-mars-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/40-header-mars-3.png -------------------------------------------------------------------------------- /img/41-header-apollo-x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/41-header-apollo-x.png -------------------------------------------------------------------------------- /img/41-header-earthrise.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/41-header-earthrise.png -------------------------------------------------------------------------------- /img/cash-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/cash-2.png -------------------------------------------------------------------------------- /img/dac.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/dac.png -------------------------------------------------------------------------------- /img/fosfyr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/fosfyr.png -------------------------------------------------------------------------------- /img/fyr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/fyr.png -------------------------------------------------------------------------------- /img/hanrep-dovres.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/hanrep-dovres.png -------------------------------------------------------------------------------- /img/jingleheimer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/jingleheimer.png -------------------------------------------------------------------------------- /img/mars-atmos-hero.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/mars-atmos-hero.png -------------------------------------------------------------------------------- /img/mars-atmos-hero.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/mars-atmos-hero.xcf -------------------------------------------------------------------------------- /img/mars-hero.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/mars-hero.png -------------------------------------------------------------------------------- /img/mars-landscape-hero.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/mars-landscape-hero.png -------------------------------------------------------------------------------- /img/mars-olympus-mons-hero.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/mars-olympus-mons-hero.png -------------------------------------------------------------------------------- /img/mars-olympus-mons-hero.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/mars-olympus-mons-hero.xcf -------------------------------------------------------------------------------- /img/mars-pathfinder-hero.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/mars-pathfinder-hero.png -------------------------------------------------------------------------------- /img/mars-pathfinder-hero.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/mars-pathfinder-hero.xcf -------------------------------------------------------------------------------- /img/mars-rover-hero.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/mars-rover-hero.png -------------------------------------------------------------------------------- /img/mars-rover-hero.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/mars-rover-hero.xcf -------------------------------------------------------------------------------- /img/rivpyl-sidpyl-behn-2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/rivpyl-sidpyl-behn-2.gif -------------------------------------------------------------------------------- /img/rivpyl-sidpyl-behn.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/rivpyl-sidpyl-behn.gif -------------------------------------------------------------------------------- /img/rivpyl-sidpyl-boot.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/rivpyl-sidpyl-boot.gif -------------------------------------------------------------------------------- /img/sigil-star.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/sigil-star.png -------------------------------------------------------------------------------- /img/winter-martyr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davis68/martian-computing/1dda496e14f2bd32d209f77775d3e5f85b412512/img/winter-martyr.png -------------------------------------------------------------------------------- /index.md: -------------------------------------------------------------------------------- 1 | # CS 498MC • Martian Computing 2 | #### Neal Davis • Department of Computer Science • University of Illinois 3 | 4 | ![](./img/mars-landscape-hero.png) 5 | 6 | The underlying infrastructure of modern networked computing—namely Unix and its derivatives—is approaching fifty years of age. What will come to replace it? A strong competitor is the clean-slate “operating function” approach of Urbit. Jocosely branded as “computing for Martians,” Urbit provides a fresh and updated vision of what Internet computing could come to look like in future years. Featuring end-to-end encryption and true peer-to-peer routing built on a network-first operating system, Urbit fosters decentralized digital societies and stable user identities. 7 | 8 | Our primary objectives in this course are for you to be able to explain and navigate the technical layout of Urbit, as well as construct novel applications for Arvo, the Urbit operating function, using the Hoon programming language. 9 | 10 | - Understand the schematics and technical implementation of the Urbit OS kernel (Arvo and vanes). 11 | - Navigate and utilize the Urbit ID public-key infrastructure (Azimuth). 12 | - Program literately using the Hoon language, including source code conventions and interoperability. 13 | - Construct userspace apps to run on the Urbit OS platform (Gall, Landscape). 14 | 15 | **Since January 2022, I have been working with the Urbit Foundation to produce more up-to-date developer education resources. This course has largely been superseded by the [Hoon School and App School guides](https://developers.urbit.org/guides/core). I will leave it up for historical documentation, but you shouldn't rely on any part of the presentation without checking contemporary developments.** 16 | 17 | 18 | ## Audience 19 | 20 | My target audience for the course consists of graduate students and seniors in computer science and neighboring fields interested in sound computing and functional operating system design (functional-as-in-language). The course assumes an interest in functional programming but no specific experience[.](https://en.wikipedia.org/wiki/Centzon_T%C5%8Dt%C5%8Dchtin) 21 | 22 | 23 | ## Resources 24 | 25 | | What | When and Where | 26 | | -------------------- | -------------- | 27 | | **Instructor email** | [cs498mcadmin@illinois.edu](mailto:cs498mcadmin@illinois.edu?subject=CS498MC) | 28 | | **Class URL** | [go.illinois.edu/cs498mc](https://go.illinois.edu/cs498mc) | 29 | | **Class forum** | `~magbel/martian-computing` | 30 | 31 | 32 | ## Access 33 | 34 | ![](./img/mars-pathfinder-hero.png) 35 | 36 | The use of Urbit requires an [Urbit ID](https://urbit.org/using/install/). You can purchase an ID on a third-party site like [urbit.live](https://urbit.live) or [OpenSea](https://opensea.io/). You can also use a transient ID (called a "comet") as a permanent ID; these are free and can be generated on your own machine. 37 | 38 | 39 | ## Agenda 40 | 41 | ![](./img/mars-olympus-mons-hero.png) 42 | 43 | Lessons focus on conceptual or architectural aspects of Urbit, including technical discussions of Urbit’s behavior and internals. Labs are hands-on tutorials to familiarize students with operations and language features. 44 | 45 | | Wk | Date | Number | Lecture | Lab | MP | 46 | | -- | ---- | ------ | ------- | --- | -- | 47 | | 0 | 08/26 | 00 | [Prospectus](./lessons/lesson00-prospectus.md) | | | 48 | | | 08/28 | 01 | [Dojo](./lessons/lesson01-dojo.md) | | | 49 | | 1 | 08/31 | 02 | | [Azimuth I](./lessons/lesson02-azimuth-1.md) | | 50 | | | 09/02 | 03 | [Generators](./lessons/lesson03-generators.md) | | | 51 | | | 09/04 | 04 | [Auras](./lessons/lesson04-aura.md) | | | 52 | | 2 | 09/09 | 05 | [Syntax](./lessons/lesson05-syntax.md) | | | 53 | | | 09/11 | 06 | [Cores](./lessons/lesson06-cores.md) | | `mp0` | 54 | | 3 | 09/14 | 07 | | [`%say` Generators](./lessons/lesson07-say-generators.md) | | 55 | | | 09/16 | 08 | [Subject-Oriented Programming](./lessons/lesson08-subject-oriented-programming.md) | | | 56 | | | 09/18 | 09 | [Clay I](./lessons/lesson09-clay-1.md) | | | 57 | | 4 | 09/21 | 10 | | [Libraries](./lessons/lesson10-libraries.md) | | 58 | | | 09/23 | 11 | [Ford I](./lessons/lesson11-ford-1.md) | | | 59 | | | 09/25 | 12 | [Debugging Hoon](./lessons/lesson12-debugging.md) | | `mp1` | 60 | | 5 | 09/28 | 13 | | [`%ask` Generators](./lessons/lesson13-ask.md) | | 61 | | | 09/30 | 14 | [Types & Molds](./lessons/lesson14-typechecking.md) | | | 62 | | | 10/02 | 15 | [Standard Library](./lessons/lesson15-stdlib.md) | | | 63 | | 6 | 10/05 | 16 | | [Common Containers](./lessons/lesson16-containers.md) | | 64 | | | 10/07 | 17 | [Gall I](./lessons/lesson17-gall-1.md) | | | 65 | | | 10/09 | 18 | [Kernel](./lessons/lesson18-kernel.md) (Chat with `~rovnys-ricfer`) | | `mp2` | 66 | | 7 | 10/12 | 19 | | [Data & Text Parsing](./lessons/lesson19-text-parsing.md) | | 67 | | | 10/14 | 20 | [Ames](./lessons/lesson20-ames.md) | | | 68 | | | 10/16 | 21 | [Behn](./lessons/lesson21-behn.md) | | | 69 | | 8 | 10/19 | 22 | | [Clay II](./lessons/lesson22-clay-2.md) | | 70 | | | 10/21 | 23 | [Polymorphism](./lessons/lesson23-polymorphism.md) | | | 71 | | | 10/23 | 24 | [Urbit Foundation](./lessons/lesson24-foundation.md) (Chat with `~wolref-podlex`) | | `mp3` | 72 | | 9 | 10/26 | 25 | | [Gall II](./lessons/lesson25-gall-2.md) | | 73 | | | 10/28 | 26 | [Gall III](./lessons/lesson26-gall-3-landscape.md) | | | 74 | | | 10/30 | 27 | Buffer | | | 75 | | 10 | 11/02 | 28 | | [Eyre & Iris](./lessons/lesson28-eyre-iris.md) | | 76 | | | 11/04 | 29 | [Gall IV](./lessons/lesson29-gall-4-communication.md) | | | 77 | | | 11/06 | 30 | [Boot Process](./lessons/lesson30-boot-process.md) | | `mp4` | 78 | | 11 | 11/09 | 31 | | [CLI](./lessons/lesson31-cli.md) | | 79 | | | 11/11 | 32 | [Arvo I](./lessons/lesson32-arvo-1.md) | | | 80 | | | 11/13 | 33 | [Hoon I](./lessons/lesson33-hoon-1.md) | | | 81 | | 12 | 11/16 | 34 | | [Hoon II](./lessons/lesson34-hoon-2.md) | | 82 | | | 11/18 | 35 | [Vere I](./lessons/lesson35-vere-1.md) | | | 83 | | | 11/20 | 36 | [Vere II](./lessons/lesson36-vere-2.md) | | `mp5` | 84 | | 13 | 11/30 | 37 | | [Arvo II](./lessons/lesson37-arvo-2.md) | | 85 | | | 12/02 | 38 | [Nock I](./lessons/lesson38-nock-1.md) | | | 86 | | | 12/04 | 39 | [Nock II](./lessons/lesson39-nock-2.md) | | | 87 | | 14 | 12/07 | 40 | | [Azimuth II](./lessons/lesson40-azimuth-2.md) | | 88 | | | 12/09 | 41 | [Final Thoughts](./lessons/lesson41-final-thoughts.md) | | | 89 | | | 12/11 | | | | `mp6` | 90 | -------------------------------------------------------------------------------- /lessons/.gitkeep: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /lessons/lesson01-dojo.md: -------------------------------------------------------------------------------- 1 | # Entering the Dojo 2 | 3 | ![](../img/01-header-goddard.png) 4 | 5 | ## Learning Objectives 6 | 7 | - Operate dojo by entering Hoon commands. 8 | - Mount the Unix filesystem and commit changes as necessary. 9 | - Use built-in or provided tools (gates and generators). 10 | - Identify elements of Hoon such as runes, atoms, and cells. 11 | 12 | _You will need access to a Unix or Linux system to work with Urbit right now. macOS will do, being derived from BDS Unix via NeXTSTEP. Windows Subsystem for Linux is provisionally supported. You will probably get the most value out of this lesson by reading this page once, completing the questions and associated setup, then reviewing this page._ 13 | 14 | _This lesson requires you to have a running Urbit instance, preferably a "fakezod." I recommend you scan this page, then complete the first exercise to get a running fakezod. Then return and thoroughly complete this page's material._ 15 | 16 | 17 | ## Stepping Into the Dojo 18 | 19 | To run Urbit, you need the OS and an ID. In the current state of affairs, software development runs the risk of unvetted or buggy code without the possibility of recontainment. On your main ship, it can lead to drastic problems. Thus you will start working with Urbit in this lesson by creating a _fakezod_, or a "dummy ship" unconnected to the network but suitable for development. (Instructions for a creating a fakezod are included on the next page.) 20 | 21 | At this point, there are three ways to work with Urbit: Dojo, Landscape, and via an API. 22 | 23 | 1. Dojo is the command-line interface you see by default. 24 | 2. An HTTP API is supported. 25 | 3. API connections are in third-party development and supported for some languages, including [Python](https://pypi.org/project/urlock/). 26 | 4. Landscape is accessible at `localhost` in your browser if port 80 is available, or at another random port if not. (Check the boot log for the chosen port, commonly 8080 or 8888.) 27 | 28 | 29 | ## Interfacing with Unix 30 | 31 | Urbit uses the Clay vane as its "filesystem"—really a version-controlled data store. We can synchronize Clay with our Unix filesystem to edit files in using our favorite editor and share files with other users. 32 | 33 | To initialize your filesystem synchronization, run `|mount %` once. This creates a `home/` directory with a number of standard child directories. 34 | 35 | To synchronize your Unix-side changes to Clay, run `|commit %home`. 36 | 37 | ![](../img/01-header-goddard-1.png) 38 | 39 | 40 | ## Using Built-In Tools 41 | 42 | There are, of course, many helpful tools built right into Dojo. 43 | 44 | For instance, `trouble` is a troubleshooting tool frequently used when analyzing system problems. Invoke it as `+trouble`. 45 | 46 | A simple "Hello, world" tool is available as `+deco`. 47 | 48 | To see the contents of a file, use `+cat`: `+cat %/gen/deco/hoon`. 49 | 50 | To view the current filesystem on Clay, use `+ls`: `+ls %`. 51 | 52 | In general, `+` precedes generators, or standalone functions, while `|` precedes system service calls. 53 | 54 | `|mass` shows the current memory usage on the loom. (The loom is like heap + stack memory; we'll explore it later.) 55 | 56 | `|sync` checks for automatic synchronization (_over-the-air_ updates) for your ship. 57 | 58 | `|ota` configures where OTA updates to your ship come from (since Urbit is peer-to-peer). 59 | 60 | `|moon` generates a daughter point, a moon, at a random 64-bit address. 61 | 62 | You've seen `|mount` and `|commit` already, which coordinate the "external" file system (Unix) with the "internal" file system (Clay data store). 63 | 64 | 65 | ## Reading Your First Hoon 66 | 67 | As mentioned, Hoon:Urbit::C:Unix. Similar to how C compiles to assembler for execution, Hoon is a macro language on top of a simple Turing-complete language called Nock. 68 | 69 | Urbit is a "subject-oriented" system. Right now, what that means to you is that rather than an environment stack, Urbit has a nested tree of values: _everything_ in Urbit is a binary tree. The [docs](https://urbit.org/docs/hoon/hoon-school/the-subject-and-its-legs/) explain this thus: "every Hoon expression is evaluated relative to some subject, [and] roughly, the subject defines the environment in which a Hoon expression is evaluated." 70 | 71 | For a userspace program, the subject is Zuse, the standard library (which wraps around Arvo and Hoon). Dojo provides a slightly broader subject with some convenience features built in to ease programming. Any Hoon expression (or hoon) evaluates to a tree, wherein each operation is a macro reducing ultimately to Nock. Hoon is written using "runes," a lapidary composition technique which emphasizes program structure. 72 | 73 | Try each of the following single-line Hoon expressions in the Dojo. Notice that in many cases the Dojo will not let you type certain characters—Dojo parses your input in real time to enforce well-formed Hoon. 74 | 75 | (add 1 1) 76 | (add 1.000 1) 77 | (sub 1.000 1) 78 | =(5 5) 79 | =(10 0) 80 | ?: =(5 5) "equal" "unequal" 81 | :: This is a comment. 82 | 83 | Play with these expressions and figure out what you can successfully change and what not. Dojo parses input in real time and generally does a good job with preventing poorly-formed input. You may see your input never appear or immediately disappear if it is not well-formed. 84 | 85 | Runes generally have a fixed number of children: for instance, a function call using `%-` actually takes two children, a function name and a list of arguments. (We don't call these "functions," by the way, that's a concession until you're used to the terminology.) Because runes have a fixed number of children, the Lispy proliferation of parens is contained. 86 | 87 | The notation for function calls is Lisp-like. (This is actually an irregular form, available for convenience. It reduces in parsing to an equivalent formal structure.) 88 | 89 | Let's use the Dojo to define a simple gate. Copy and paste the following into your Dojo. 90 | 91 | ```hoon 92 | =add-3 |= n=@ud 93 | (add n 3) 94 | ``` 95 | 96 | This short program contains one rune (`|=`) and a function call (irregular form for `%-`): 97 | 98 | - `=` with a name is a Dojo shortcut for defining a value ("pinning a face to the [Dojo] subject"); it takes a name and a value, the value here being the entire gate 99 | - `|=` produces a "gate," thought of as a function entry point; it has two children, a list of arguments and a value, the value here being the following line 100 | - `@ud` is not a rune, but a type specifier (unsigned decimal integer) 101 | - `(add n 3)` is shorthand for a function call, which gives you Lisp-like access to the `%-` rune. 102 | 103 | Longer programs are frequently written and stored as _generators_, in the `home/gen/` folder as `.hoon` files. The most basic form of generator is Hoon that produces a "gate" definition, as below. Once you have a fakezod (next page), save the following text to a file `home/gen/mod3.hoon`, synchronize it to Urbit using `|commit %home`, and run it with `+mod3 100`. 104 | 105 | This example is a fair bit more complicated; revisit it once you're more comfortable with Hoon. 106 | 107 | ```hoon 108 | !: 109 | :: List all natural numbers below 100 that are multiples of 3. 110 | |= end=@ud 111 | =/ index=@ud 1 112 | =/ values=(list @ud) ~ 113 | :: Start "loop" (self-replacing tree structure) to build list. 114 | |- ^- (list @ud) 115 | ?: =(end index) 116 | values 117 | :: Check for modulus of index by 3 to be 0. 118 | ?: =(0 (mod index 3)) 119 | ~& index 120 | $(index (add 1 index), values (weld values ~[index])) 121 | $(index (add 1 index)) 122 | ``` 123 | 124 | Each two-character entry is a rune, analogous to a keyword in other languages. From top to bottom, we see the following runes: 125 | 126 | - `!:` turns on the debugging context; it's frequently used when developing code 127 | - `::` precedes a comment 128 | - `|=` produces a "gate," thought of as a function entry point 129 | - `@ud` is not a rune, but a type specifier (unsigned decimal integer) 130 | - `=/` defines a variable of a given type 131 | - `|-` starts a "trap," thought of here as a loop recursion point 132 | - `^-` constrains the expected type, here a list of `@ud` 133 | - `?:` tests a boolean condition 134 | - `=()` is not a rune, but a shorthand test for equality 135 | - `~` is not a rune, but nil (the end of a list) 136 | - `~&` outputs a value to the screen, basically a `printf` 137 | - `%-` is a function call, implied by the `add` and `weld` 138 | - `$()` is not a rune, but constructs a new subject `$` by re-executing the code of the current subject `$`. `$` is implicitly defined. (This is a subtle point we will revisit: I introduce it now because it will take you a while to wrap your head around it.) 139 | 140 | This gate accepts a single input argument `end` of type unsigned decimal integer. An index variable is initialized before the looping structure. The loop will return a value of type list of unsigned decimal integers. `end` is compared to `index`, and if it is equal to `index`, the entire list `values` is returned. During normal operation, though, it will not be equal yet, so the next check, of whether `index` modulo 3 is zero (i.e., the number is divisible by three). If it is, then the number is printed to the screen and the subject is replaced by an identical subject except for two changes: `index` is increased by one, and `values` is replaced by a new list fused from the old `values` and `index`. If it is not, only the `index` is changed. 141 | 142 | Hoon takes some getting used to. The upside is that similar kinds of operations are expressed using similar runes; the downside is that learning to read the runes takes time. 143 | 144 | ![](../img/01-header-goddard-2.png) 145 | 146 | 147 | ## Setting Up a Real Urbit ID 148 | 149 | Your Urbit ID is cryptographic ownership of a single piece of Urbit address space (more on that in _Azimuth 1_). Most IDs are what are called "planets," or 32-bit identities[.](https://en.wikipedia.org/wiki/Sylacauga_%28meteorite%29) 150 | 151 | In the exercises, you will access a planet and its keyfile and create a permanent online pier for accessing the planet. 152 | -------------------------------------------------------------------------------- /lessons/lesson10-libraries.md: -------------------------------------------------------------------------------- 1 | # Libraries 2 | 3 | ![](../img/10-header-stars-3.png) 4 | 5 | ## Learning Objectives 6 | 7 | - Create a library in `lib/` and call it using `/+`. 8 | - Write unit tests for the library. 9 | - Employ strategies for nested loops. 10 | - Compose Hoon that adheres to the Tlon Hoon style guide. 11 | * Produce a library. 12 | 13 | 14 | ## Libraries 15 | 16 | What makes something a library? A library, or module, or package, is a collection of optional yet useful code which coherently carries out some task. 17 | 18 | For our purposes, a library is basically a battery, no payload. It's typically constructed with a `|%` barcen rune and stored in the `lib/` folder. 19 | 20 | The Ford rune `/+` faslus imports a Hoon file into the subject from `lib/` in the current desk. (Because of the way Ford and the subject interact, you can't execute most of these things in the Dojo. I recommend making a minimal generator to import and test your functions.) 21 | 22 | ```hoon 23 | /+ bip39 24 | :- %say 25 | |= [[* eny=@uv *] ~ ~] 26 | :- %noun 27 | (to-seed:bip39 "words" "more-words") ``` 28 | 29 | Use `*` in front of the name to import the library without a face. 30 | 31 | ```hoon 32 | /+ *bip39 33 | :- %say 34 | |= [[* eny=@uv *] ~ ~] 35 | :- %noun 36 | (to-seed "words" "more-words") 37 | ``` 38 | 39 | A few other Ford runes manage builds and dependencies from other parts of Arvo; more in Ford 1. 40 | 41 | Urbit does not at the time of writing have a package management system (August 2020): there's not enough userspace code to require it yet, and everything else new has just come to live in the kernel, thereby inheriting the mantle of obsessive refinement. 42 | 43 | ### Library Composition 44 | 45 | Any file in `lib/` can be imported using `/+` faslus. It should be structured as a core, likely with `|%` barcen. Here's a more complex example of a library: 46 | 47 | ```hoon 48 | :: 49 | :::: Vector type in single-precision floating-point @rs 50 | :: 51 | |% 52 | ++ lvs 53 | ^| 54 | ~% %lvs ..is ~ 55 | |_ r/$?($n $u $d $z) :: round nearest, round up, round down, round to zero 56 | :: 57 | :: Zeroes 58 | ++ zeros 59 | ~/ %zeros 60 | |= n=@ud ^- @lvs 61 | ~_ leaf+"lagoon-fail" 62 | =/ nan 0xffff.ffff 63 | `@lvs`(not 5 +(n) (rap 5 ~[(fil 5 n nan) (not 5 1 n)])) 64 | :: 65 | :: Ones 66 | ++ ones 67 | ~/ %ones 68 | |= n=@ud ^- @lvs 69 | ~_ leaf+"lagoon-fail" 70 | =/ one (bit:rs [%f s=%.y e=-0 a=1]) 71 | =/ not-one (not 5 1 one) 72 | `@lvs`(not 5 +(n) (rap 5 ~[(fil 5 n not-one) (not 5 1 n)])) 73 | -- 74 | -- 75 | ``` 76 | 77 | There are some new runes in there, of course, but pay attention to the `|%`/`++`/`--` structure overall. 78 | 79 | (As an aside, `^|` ketbar adjusts type nesting to be contravariant; `~%` sigcen and `~/` sigfas are jet hints; and `~_` sigcab is an error annotation.) 80 | 81 | 82 | ## Traps as Nested Loops 83 | 84 | Consider a classic nested loop, as in C: 85 | 86 | ```c 87 | uint i, j; 88 | for ( i = 0; i < m; i++ ) { 89 | for ( j = 0; j < n; j++ ) { 90 | w += u[i] * v[j]; 91 | } 92 | } 93 | ``` 94 | 95 | Altogether, the code inside of these loops executes `m*n` times. 96 | 97 | Naïvely, you may suppose that you can compose a nested loop as a trap inside of a trap, something like this: 98 | 99 | ```hoon 100 | !: 101 | |= [m=@ud n=@ud] ^- @ud 102 | =/ i 1 103 | =/ j 1 104 | =/ w 0 105 | |- ^- @ud 106 | ?: =(i n) w 107 | |- ^- @ud 108 | ?: =(j n) 109 | $(i +(i), j 0, w (add w (mul i j))) 110 | $(i i, j +(j), w (add w (mul i j))) 111 | ``` 112 | 113 | The problem is that traps have a named default subject `$` which generates and replaces the subject from the first trap. This code fails because of confusion around `$`. 114 | 115 | My preferred solution is to unroll the loop: track the conditions under which each loop iteration terminates and compose a test to find those conditions. For each test, associate a `$()` regeneration point. It's a bit like rewriting a nested loop as a `while` loop in a procedural language like C or Python. 116 | 117 | ```hoon 118 | =/ i 1 119 | =/ j 1 120 | |- 121 | =(i n) w 122 | =(j n) $(i +(i), j 0, w w) 123 | $(i i, j +(j), w (add w (mul (snag i u) (snag j v)))) 124 | ``` 125 | 126 | Another solution is to "escape" the subject `$` with `^`: `^$` skips the first match of the symbol `$` and thus triggers the outer trap. This approach is used sometimes in kernel code. 127 | 128 | 129 | ## Testing Code 130 | 131 | Best coding practice recommends composing unit tests to verify the behavior of program components. A good unit test tests one thing and one thing only. 132 | 133 | The primary way to test code automatically is to use Ford's `+test` generator. This scans for arms (that conventionally begin with `++test`) in the `tests/` folder at a path otherwise corresponding to the system path. For instance, to run the unit tests for a particular library file: 134 | 135 | ```hoon 136 | > +test /lib/number-to-words 137 | OK /lib/number-to-words/test-eng-us 138 | ``` 139 | 140 | (How can you list all of the files in `tests/` from inside of Urbit?) 141 | 142 | In other words, the standard location for the unit tests for a file are at the same path _inside_ of the `tests/` directory. 143 | 144 | Here is a complete unit test file, extracted from `tests/lib/numbers-to-words.hoon`: 145 | 146 | ```hoon 147 | :: tests for number-to-words 148 | :: 149 | /+ number-to-words, *test 150 | :: 151 | |% 152 | ++ test-eng-us 153 | =+ eng-us:number-to-words 154 | ;: weld 155 | %+ expect-eq 156 | !> `(unit tape)``"zero" 157 | !> (to-words 0) 158 | :: 159 | %+ expect-eq 160 | !> `(unit tape)``"one" 161 | !> (to-words 1) 162 | :: We distinguish different aspects of the programming flaw based on their observational mode: 163 | 164 | - A _failure_ refers to the observably incorrect behavior of a program. This can include segmentation faults, erroneous output, and erratic results. 165 | 166 | - A _fault_ refers to a discrepancy in code that results in a failure. 167 | 168 | - An _error_ is the mistake in human judgment or implementation that caused the fault. Note that many errors are latent or masked. 169 | 170 | - A _latent_ error is one which will arise under conditions which have not yet been tested. 171 | 172 | - A _masked_ error is one whose effect is concealed by another aspect of the program, either another error or an aggregating feature. 173 | 174 | We casually refer to all of these as bugs. 175 | 176 | An exception is a manifestation of unexpected behavior which can give rise to a failure, but some languages—notably Python—use exceptions in normal processing as well. 177 | 178 | (If you have not encountered these concepts via dev/debugging yet, this is identical to the terminology we adopt when debugging.) 179 | 180 | 181 | %+ expect-eq 182 | !> `(unit tape)``"twelve" 183 | !> (to-words 12) 184 | :: 185 | %+ expect-eq 186 | !> `(unit tape)``"one vigintillion" 187 | !> (to-words (pow 10 63)) 188 | == 189 | -- 190 | ``` 191 | 192 | There are two library imports: the library to test and `test` (with no namespace). `test` contains two arms: `++expect-eq` and `++expect-fail`[.](https://s3-us-west-1.amazonaws.com/vocs/map.html#) 193 | 194 | As you can see above, the expected structure of a testing file introduces a couple of new runes: `;:` miccol and `%+` cenlus. 195 | 196 | - `;:` allows us to run a binary function as if it were an $n$-ary function; that is, we can string together the whole following list against the `weld` function. Since it doesn't take a specific number of runes, you have to terminate the running series with the digraph `==` tistis. 197 | - `%+` calls a gate with a cell sample. In this case, we use it to 198 | - `!>` isn't new—you saw these in Cores when we talked about vases. It wraps a noun in its type producing a vase. 199 | 200 | Most of the time, `++expect-eq` is the only arm used. `++expect-fail` works a bit differently: 201 | 202 | ```hoon 203 | ++ test-map-got ^- tang 204 | ;: weld 205 | :: Checks with non-existing key 206 | :: 207 | %- expect-fail 208 | |. (~(got by m-des) 9) 209 | == 210 | ``` 211 | 212 | `|.` bardot is like `|-` barhep but defers evaluation instead. Here we are using it to evaluate the expected failure later than compilation time. 213 | 214 | - Optional Reading: [Tlon Corporation, "Unit Testing with Ford"](https://web.archive.org/web/20200614210451/https://urbit.org/docs/tutorials/hoon/test-sets/) 215 | 216 | ![](../img/10-header-stars-2.png) 217 | 218 | 219 | ## Hoon Style 220 | 221 | It's time for you to read and absorb the [authoritative Hoon style guide](https://urbit.org/docs/hoon/reference/style). All code you produce subsequently should hew to it, particularly the informal comments. (It will take us a while yet in this course to get to the point where formal comments are worth the trouble.) 222 | 223 | It's worth noting that I have a few minor quibbles on style: 224 | 225 | 1. Breathing comments feel backwards to me. 226 | 2. I think that trap resolutions `$()` should be differently indented to make the loop more legible (most of the time); i.e., there should be flexibility in this placement. 227 | 3. Trap bodies should be indented (rather than backstepping). I admit this to be procedural recidivism on my part. 228 | 229 | For instance, here are samples from some library code I have written, which adhere to different rules for making the `$` resolution legible and indent the trap bodies. 230 | 231 | ```hoon 232 | |- ^- @lvs 233 | ?: =(count n) (make w) 234 | =/ ul (snag count uu) 235 | =/ vl (snag count vv) 236 | =/ wl `@rs`(sub:rs ul vl) 237 | $(count +(count), w (weld ~[wl] w)) 238 | ``` 239 | 240 | ```hoon 241 | ++ gauss-elimination 242 | |- ^- @lms 243 | ?: (gth i mu) `@lms`u 244 | ?: (gth j mu) $(i +(i), j 1, k k, u u) 245 | ?: (gth k nu) $(i i, j +(j), k k, u u) 246 | ?: =(i j) $(i i, j +(j), k k, u u) 247 | $(i i, j j, k +(k), u (set u j k (sub:rs (get u j k) (mul:rs (get u i k) (div:rs (get u j i) (get u i i)))))) 248 | ``` 249 | 250 | (Note that the latter is a triple-nested code fragment.) 251 | 252 | How would you rewrite these code snippets in fully-compliant style? 253 | 254 | - Reading: [Tlon Corporation, "Hoon Style Guide"](https://urbit.org/docs/hoon/reference/style) 255 | 256 | 257 | ## A Word of Encouragement 258 | 259 | > Don't embed fear in your code. Don't design systems around your fear because you don't have confidence in your system. Tools should motivate the mind, not subjugate it. (Aaron Hsu) 260 | 261 | ![](../img/10-header-stars-1.png) 262 | -------------------------------------------------------------------------------- /lessons/lesson11-ford-1.md: -------------------------------------------------------------------------------- 1 | # Ford 1 2 | 3 | ![](../img/11-header-nasa-1.png) 4 | 5 | >Computations from inputs to outputs constitute a build graph: a directed acyclic graph where individual nodes are called actions, and arcs are called dependencies. The signals are called artifacts, and, by extension, the inputs to the action that generate one of them are also called its dependencies. (François-René Rideau (Faré), ["Build Systems"](https://ngnghm.github.io/blog/2016/04/26/chapter-9-build-systems/)) 6 | 7 | ## Learning Objectives 8 | 9 | - Understand the high-level architecture and design intent of Ford. 10 | - Compose and call unit tests using Ford. 11 | - Understand top-level Ford runes: `/-`, `/+`, `/=`, `/*`. 12 | - Employ tanks and `~_` to produce error messages. 13 | 14 | 15 | ## A Build System 16 | 17 | What is a build system responsible for? Classically, a build system serves the role of compiling, linking, and testing. Examples include Make, GNU Autotools, Gradle, CMake, Meson, and Nix. 18 | 19 | The proliferation of build systems should imply to you that it's the sort of thing that many feel we haven't gotten quite right yet. For instance, [here's Eric Raymond (ESR) pining for better days ahead](http://esr.ibiblio.org/?p=8581). 20 | 21 | What do we desire in a good build system? Faré identifies four characteristics: 22 | 23 | 1. Actions are _reproducible_: they happen without side-effects. 24 | 2. Code may be _source-addressed_: you should be able to rebuild a value by re-digesting the source code. 25 | 3. The build system is _hermetic_: no source outside of source control is necessary. 26 | 4. The build should be _deterministic_. 27 | 28 | Urbit's build system, Ford, hews to this standard rather well. 29 | 30 | 31 | ## The System Formerly Known as Ford 32 | 33 | ![](../img/11-header-nasa-2.png) 34 | 35 | The build system formerly known as Ford (and now the `++ford` arm of Clay) has had one of the most productive and turbulent histories of any of the major vanes of Arvo (along with Ames and Clay). Indeed, Ford's evolution over time is an excellent demonstration of the virtues of a cooling operating system: Ford has become smaller, leaner, and more expressive even as it has shed complexity. 36 | 37 | Ford is responsible for producing the Nock cores that constitute Arvo. "Ford is capable of sequencing generic asynchronous computations. Its uses include linking source files into programs, assembling live-updating websites, and performing file-type conversions." 38 | 39 | 40 | ## OTAs 41 | 42 | > If your software needs to run in hell, build it that way from the start. (Ted Blackman) 43 | 44 | Ford is _also_ by implication responsible for one of the key properties of Urbit's evolution: managing over-the-air updates (OTAs). 45 | 46 | Urbit is divided into two layers: a binary layer which provides an interface for Arvo, and the Arvo runtime. The binary executable receives occasional updates which affect the underlying system performance, much like the JVM. The Arvo runtime receives frequent userspace and less-frequent kernelspace updates over the network from the ship's sponsor. Ford is responsible for receiving, processing, and implementing these live while your ship is running. 47 | 48 | The primary properties of an OTA are that it should be: 49 | 50 | 1. Atomic: composed a single transaction. 51 | 2. Self-contained: no dependence on previous system states. 52 | 3. Ordered: must proceed from lowest system layer to highest. 53 | 54 | - Reading: [Ted Blackman `~rovnys-ricfer`, "Ford Fusion"](https://urbit.org/blog/ford-fusion/) 55 | 56 | 57 | ## Testing Code 58 | 59 | Among its other utilities, Ford is used for testing code, as you saw in Libraries. Testing is designed to manifest failures so that faults and errors can be identified and corrected. (More on this in Debugging.) 60 | 61 | We can classify a testing regimen into various layers: 62 | 63 | 1. Fences are barriers employed to block program execution if the state isn't adequate to the intended task. Typically, these are implemented with `assert` or similar enforcement. For conditions that must succeed, the failure branch in Hoon should be `!!`, which crashes the program. 64 | 65 | 2. "Unit tests are so called because they exercise the functionality of the code by interrogating individual functions and methods. Functions and methods can often be considered the atomic units of software because they are indivisible. However, what is considered to be the smallest code unit is subjective. The body of a function can be long are short, and shorter functions are arguably more unit-like than long ones." (Katy Huff) 66 | 67 | In Python and many other languages, unit tests refer to functions, often prefixed test_, that specify (and enforce) the expected behavior of a given function. Unit tests typically contain setup, assertions, and tear-down. In academic terms, they're a grading script. 68 | 69 | In Hoon, as you've seen, the `tests/` directory contains the relevant tests for the Ford testing framework to grab and utilize. 70 | 71 | Unit tests come in two categories: 72 | 73 | 1. Positive: the function should succeed or handle a case correctly. 74 | 2. Negative: the function should fail or reject a condition. 75 | 76 | Consider an absolute value function. The positive unit tests for absolute should accomplish a few things: 77 | 78 | - Verify correct behavior for positive numeric input. 79 | - Verify correct behavior for negative numeric input. 80 | - Verify correct behavior for zero input. 81 | - Verify that the function works for int, long (Python 2.x), float, and complex (if implemented). 82 | 83 | The negative unit tests for absolute should: 84 | 85 | - Verify an exception is raised for nonnumeric input. 86 | - Verify correct exceptions are raised for various kinds of input. 87 | 88 | Note that at this point we don't care what the function looks like, only how it behaves. 89 | 90 | _In extremis_, rigorous unit testing yields test-driven development (TDD). Test-driven development refers to the practice of fully specifying desired function behavior before composing the function itself. The advantage of this approach is that it forces you to clarify ahead of time what you expect, rather than making it up on the fly. 91 | 92 | 3. Integration tests check on how well your new or updated code integrates with the broader system. These can be included in continuous integration (CI) frameworks like Circle or Travis-CI. The Arvo ecosystem isn't large enough for developers outside the kernel itself to worry about this yet. 93 | 94 | - Reading: [Tlon Corporation, "Unit Testing with Ford"](https://web.archive.org/web/20200614210451/https://urbit.org/docs/hoon/hoon-school/test-sets/) 95 | 96 | 97 | ## Ford Runes 98 | 99 | Way back in Generators, you encountered the ability to import a library using `/+` faslus. 100 | 101 | Ford has its own set of particular runes, which import data and code from various locations in Clay and insert them into the subject. 102 | 103 | - `/-` imports from `sur/` (shared structures) 104 | - `/+` imports from `lib/` (libraries) 105 | - `/=` imports user-specified path wrapped in a specified face 106 | - `/*` imports file contents converted to a mark 107 | 108 | `/+` and `/-` are the most commonly seen of these. Prefixing the imported name with `*` imports the contents without the face; one can also rename the face: 109 | 110 | ```hoon 111 | /+ larry, *curly, moe=stooge 112 | ``` 113 | 114 | Since tools like marks are commonly reused, it is inefficient to rebuild them every time they are accessed. "Since building a file is a pure function, Clay memoizes the results of all builds, including builds of marks, mark conversions, and hoon source files. These memoization results are stored along with the desk and are used by later revisions of that desk." 115 | 116 | 117 | ## Producing Error Messages 118 | 119 | Error messages in Urbit are built of tanks. "A `tang` is a list of `tank`s, and a `tank` is a structure for printing data. There are three types of `tank`: `leaf`, `palm`, and `rose`. A `leaf` is for printing a single noun, a `rose` is for printing rows of data, and a `palm` is for printing backstep-indented lists." 120 | 121 | One way to include an error message in your code is the [`~_` sigcab](https://urbit.org/docs/reference/hoon-expressions/rune/sig/#sigcab) rune, described as a "user-formatted tracing printf". What this means is that it optionally prints to the stack trace if something fails, so you can use it to contribute to the error description[:](https://upload.wikimedia.org/wikipedia/commons/a/a7/Sv-Dag_Hammarskj%C3%B6ld.ogg) 122 | 123 | ```hoon 124 | |= [a=@ud] 125 | ~_ leaf+"This code failed" 126 | !! 127 | ``` 128 | 129 | When you compose your own library functions, consider include error messages for likely failure points. We'll see more of these as we build `%ask` generators. 130 | 131 | ![](../img/11-header-nasa-3.png) 132 | -------------------------------------------------------------------------------- /lessons/lesson12-debugging.md: -------------------------------------------------------------------------------- 1 | # Debugging Hoon 2 | 3 | ![](../img/12-header-voyager-1.png) 4 | 5 | ## Learning Objectives 6 | 7 | - Learn principles for debugging Hoon code. 8 | - Enumerate the kinds of errors `mint`, `nest`, and other checks produce. 9 | - Grade code samples according to the standard Tlon A,B,C,D,E scheme. 10 | - Produce and annotate code samples to each grade above C. 11 | 12 | 13 | ## An Ontology of Error 14 | 15 | We distinguish different aspects of programming flaws based on their observational mode: 16 | 17 | - A _failure_ refers to the observably incorrect behavior of a program. This can include segmentation faults, erroneous output, and erratic results. 18 | 19 | - A _fault_ refers to a discrepancy in code that results in a failure. 20 | 21 | - An _error_ is the mistake in human judgment or implementation that caused the fault. Note that many errors are latent or masked. 22 | 23 | - A _latent_ error is one which will arise under conditions which have not yet been tested. 24 | 25 | - A _masked_ error is one whose effect is concealed by another aspect of the program, either another error or an aggregating feature. 26 | 27 | We casually refer to all of these as bugs. 28 | 29 | An exception is a manifestation of unexpected behavior which can give rise to a failure, but some languages—notably Python—use exceptions in normal processing as well. 30 | 31 | 32 | ## Error Sources 33 | 34 | ![](../img/12-header-voyager-2.png) 35 | 36 | Let's enumerate the errors we know about at this point: 37 | 38 | We know what Ford is: it's the build vane. `++ride` is the end-to-end Hoon compiler, which Ford is of course using to build the abstract syntax tree (AST). Two `%ride failed` errors are common: `"%ride failed to compute type"` and `"%ride failed to execute"`. `%slim failed` means (one kind of) type issues, typically due to `%ride` failure. `nest-fail` indicates a failure to match the expected call signature of a gate. 39 | 40 | The `mint` errors arise from typechecking errors: 41 | 42 | - `mint-vain` means a Hoon never executes. 43 | - `mint-nice` occurs with casts. 44 | - `mint-lost` means that a branch in a conditional can never be reached. 45 | 46 | For instance, conversion without casting via auras fails because 47 | 48 | ```hoon 49 | ^-(tape ~[78 97 114 110 105 97]) 50 | ``` 51 | 52 | A `fish-loop` arise when using a recursive mold definition like `list`. Alas, this fails today: 53 | 54 | ```hoon 55 | ?=((list @) ~[1 2 3 4]) 56 | ``` 57 | 58 | `generator-build-fail` most commonly results from composing code with mismatched runes (and thus the wrong children including hanging expected-but-empty slots). 59 | 60 | `mull-grow` means it's compiling the callsite of a wet gate (a generic gate; we'll see these later)[.](https://pbs.twimg.com/media/D6qAlTAUcAA1Wub.jpg) 61 | 62 | If you really crash things hard—like crash the executable itself—then it's a `bail`, which has the following modes: 63 | 64 | - `%exit`, semantic failure 65 | - `%evil`, bad crypto 66 | - `%intr`, interrupt 67 | - `%fail`, execution failure 68 | - `%foul`, assertion of failure 69 | - `%need`, network block 70 | - `%meme`, out of memory (this is the most common one in my experience) 71 | - `%time`, operation timed out 72 | - `%oops`, assertion failed (contrast with `%fail`) 73 | 74 | Finally, although hinting at darker powers not yet unleashed, you can start a debugging console with `|start %dbug` and access it at your ship's URL followed by `~debug` (e.g., `http://localhost:8080/~debug`). 75 | 76 | - Reading: [Tlon Corporation, "Hoon Errors"](https://urbit.org/docs/hoon/reference/hoon-errors) 77 | 78 | 79 | ## Debugging Strategies 80 | 81 | What are some strategies for debugging? 82 | 83 | Assuming that you are working _within_ Urbit (i.e. in or on Arvo, not in the underlying host OS), you don't have a debugger or a profiler available\*. In that case, you have the slight help of the error message (a condition indicated as promoting "moral fiber") and some standard debugging strategies: 84 | 85 | - Debugging stack. Use the `!:` zapcol rune to turn on the debugging stack, `!.` zapdot to turn it off again. 86 | 87 | - `printf` debugging. If your code will compile and run, employ `~&` frequently to make sure that your code is doing what you think it's doing. 88 | 89 | - The only wolf in Alaska. Essentially a bisection search, you split your code into smaller modules and run each part until you know where the bug arose (where the wolf howled). Then you keep fencing it in tighter and tighter until you know where it arose. 90 | 91 | - Build it again. Remove all of the complicated code from your program and add it in one line at a time. For instance, replace a complicated function with either a `~&` and `!!`, or return a known static hard-coded value instead. That way as you reintroduce lines of code or parts of expressions you can narrow down what went wrong and why. 92 | 93 | If you run the Urbit executable with `-L`, you cut off external networking. This is helpful if you want to mess with a _copy_ of your actual ship without producing remote effects. That is, if other parts of Ames don't know what you're doing, then you can delete that copy (COPY!) of your pier and continue with the original. This is an alternative to using fakezods which is occasionally helpful in debugging userspace apps in Gall. 94 | 95 | The trouble with `%sandbox` code is that only `%home` desk code gets built by `++ford` as executable. That may change someday, but it's why we prefer fakezods instead of development desks today[.](https://en.wikipedia.org/wiki/Category:Proposed_states_of_the_United_States) 96 | 97 | \* _I have found a reference to [profiling support](https://urbit.org/docs/reference/library/5g/) in the docs. [`~$` sigbuc](https://urbit.org/docs/reference/hoon-expressions/rune/sig/#sigbuc) also plays a role as a profiling hit counter but I've not seen it used in practice as it would be stripped out of kernel code before being released._ 98 | 99 | - Optional Reading: [OpenDSA Data Structures and Algorithms Modules Collection, "Programming Tutorials", section Common Debugging Methods](https://opendsa-server.cs.vt.edu/ODSA/Books/Everything/html/debugmethods.html) 100 | 101 | 102 | ## Quality Hoon 103 | 104 | Tlon suggests grading code according to certain stylistic and functional criteria: 105 | 106 | - **F** code is incomplete code: it looks like Hoon, at least partly. 107 | - **D** code is compile-worthy Hoon. 108 | - **C** code is unannotated code or code with too-strange names and formatting. 109 | - **B** code has universal symbol definition for every name. 110 | - **A** code has explanations for every necessary name and defines every constant where it is used. 111 | 112 | But don't produce A code on the first pass! Let the code mature for a while at C or B before you refine it into final form. 113 | 114 | - Reading: [Tlon Corportion, "Hoon Style Guide"](https://urbit.org/docs/hoon/reference/style), section "Grading" 115 | 116 | ![](../img/12-header-voyager-3.png) 117 | -------------------------------------------------------------------------------- /lessons/lesson13-ask.md: -------------------------------------------------------------------------------- 1 | # `%ask` Generators 2 | 3 | ![](../img/13-header-jupiter.png) 4 | 5 | ## Learning Objectives 6 | 7 | - Create an `%ask` generator. 8 | 9 | 10 | ## `%ask` Generators 11 | 12 | ![](../img/13-header-saturn.png) 13 | 14 | We use `%ask` generators to accept user input during the operation of the program, much like `input` or `scanf` in other languages. 15 | 16 | As with a `%say` generator, an `%ask` generator is a cell which Arvo interprets in a particular way[.](https://youtu.be/UaUR6u8nHoM) 17 | 18 | That is, at this point we know about three kinds of generators. Each is a core but has a characteristic shape that Arvo knows how to access[:](https://en.wikipedia.org/wiki/Italian_Unionist_Movement) 19 | 20 | 1. Naked generators are just gates. 21 | 2. `%say` generators are cells of `%say` and a `cask`. 22 | 3. `%ask` generators are cells of `%ask` and a `sole-result`. 23 | 24 | A `sole-result` is a mold builder. We haven't delved deeply into molds quite yet, but a mold is a coercive function which makes a noun match a specified type. A mold builder, therefore, takes the molds from the body of the generator and reshapes them in a characteristic way for Arvo to interpret. 25 | 26 | ```hoon 27 | /- sole 28 | /+ generators 29 | =, [sole generators] 30 | :- %ask 31 | |= * 32 | ^- (sole-result (cask tang)) 33 | %+ print leaf+"Who's on first?" 34 | %+ prompt [%& %prompt "name: "] 35 | |= t=tape 36 | %+ produce %tang 37 | ?: =(t "Yes") 38 | :~ leaf+"I mean the fellow's name." 39 | == 40 | ?: =(t "That's the man's name.") 41 | :~ leaf+"That's who's name?" 42 | == 43 | :~ leaf+"Who's on first," 44 | leaf+"What's on second," 45 | leaf+"I Don't Know is on third." 46 | == 47 | ``` 48 | 49 | New runes? New runes: 50 | 51 | - `=,` is probably the oddest one. It "exposes a namespace." In Hoon terms, this means that you can access what's inside of a core without suffixing the wing search path. Here, we use it because it is shorter than typing `sole-result` again and again. 52 | - `%+` calls a gate using a cell sample. Here, it parses `%tang` and the lists of `tape`s. 53 | - `%&` isn't a rune! `%` prefixes `@tas` values, and so `%&` is a "positive" loobean flag indicating whether a prompt should echo output. `%|` is the opposite, of course. 54 | - `:~` is a list constructor; you've used it in irregular form many a time as `~[1 2 3]`. 55 | 56 | You've seen `tang` and `leaf` before in Ford 1 when we talked about producing error messages. 57 | 58 | ![](../img/13-header-uranus.png) 59 | 60 | ### `sole-result` 61 | 62 | The `sole` structure library lives in `%home/sur/sole/hoon` (note that it is imported with `/-`). I recommend opening and reading this file. 63 | 64 | There are a lot of standard structures in `sole`; we are primarily interested in `++sole-result`, which is a conditional result (thus, dependent on input). 65 | 66 | ### `generators` 67 | 68 | The `generators` library lives in `%home/lib/generators/hoon`. Unsurprisingly, it provides some convenience functions for constructing generators. I recommend opening and reading this file. 69 | 70 | You are primarily interested in employing `++print`, `++prompt`, and `++produce`, all of which are reasonably demonstrated in the example code above and in the documentation. (Also not `++curl`.) 71 | 72 | - Reading: [Tlon Corporation, "Generators"](https://urbit.org/docs/hoon/hoon-school/generators/), section "`%ask` Generators" 73 | 74 | ![](../img/13-header-neptune.png) 75 | -------------------------------------------------------------------------------- /lessons/lesson14-typechecking.md: -------------------------------------------------------------------------------- 1 | # Type in Urbit 2 | 3 | ![](../img/14-header-galileo-1.png) 4 | 5 | ## Learning Objectives 6 | 7 | - Understand how type inference and type checking takes place. 8 | - Build more complicated bunt and mold structures. 9 | 10 | 11 | ## Molds 12 | 13 | The overarching model for type in Urbit is the _mold_, which is essentially an enforceable type signature. "A mold is an idempotent function that coerces a noun to be of a specific type or crashes." 14 | 15 | Molds are used to check type or produce certain kinds of types, whereas mold builders are used to produce suitable molds. For instance, `list` is in fact a mold builder: `(list @ud)` produces a mold via a gate `list` which acts as a mold builder. 16 | 17 | Molds are the primary way for enforcing and processing type structure in Urbit. 18 | 19 | ![](../img/14-header-galileo-2.png) 20 | 21 | There are some standard mold operations: 22 | 23 | - Each mold has a characteristic **bunt**: "The placeholder value is sometimes called a bunt value. The bunt value is determined by the input type; for atoms, `@`, the bunt value is `0`." You can get the bunt using [`*` tar or `^*` kettar](https://urbit.org/docs/reference/hoon-expressions/rune/ket/#kettar). 24 | 25 | "We do often bunt a mold: create a default or example noun. Logically, we bunt by passing the mold its default argument." (Whitepaper) 26 | 27 | - You can **clam** a mold: this means to produce a conversion gate to the target mold. See [`^:` ketcol](https://urbit.org/docs/reference/hoon-expressions/rune/ket/#ketcol). 28 | 29 | - A **fish** tests whether a value properly nests within a given mold. You can check this using [`?=` wuttis](https://urbit.org/docs/reference/hoon-expressions/rune/wut/#wuttis); note that this currently fails for recursive mold builders like `list`. 30 | 31 | - You can **whip** a mold: convert a value to the target mold. 32 | 33 | Aside from bunt, it is uncommon to see these terms used today, preferring just the description of the operation. 34 | 35 | (For comparison, please look at this circa-2016 doc excerpt: 36 | 37 | > **clam**: a tile reduction. A clam just produces a gate which executes a whip to the given tile (e.g. it produces a closure which remembers the tile you give it, as passes that to the whip reduction when it is called) 38 | 39 | The terminology and docs have come a long way. "Tile" = "mold.") 40 | 41 | Mold builders can work well applied as functions even if they fail via aura application: 42 | 43 | ```hoon 44 | > `(list @t)`~[100 101 102] 45 | /~zod/home/~2020.4.7..06.13.55..d061/sys/vane/ford:<[4.820 18].[4.820 59]> 46 | mint-nice 47 | nest-fail 48 | ford: %slim failed: 49 | ford: %ride failed to compute type: 50 | > ((list @t) ~[100 101 102]) 51 | <|d e f|> 52 | ``` 53 | 54 | - Reading: [Tlon Corporation, "Molds"](https://urbit.org/docs/hoon/hoon-school/molds/) 55 | - Reading: [Tlon Corporation, "1c Molds and Mold Builders"](https://urbit.org/docs/reference/library/1c/) 56 | - Reading: [Tlon Corporation, "Type Checking and Type Inference"](https://urbit.org/docs/hoon/hoon-school/type-checking-and-type-inference/) 57 | - Reading: [Tlon Corporation, "Structures and Complex Types"](https://urbit.org/docs/hoon/hoon-school/structures-and-complex-types/) 58 | 59 | I recommend that you review section Vases in Cores as well. 60 | 61 | 62 | ## Dry Gates 63 | 64 | ![](../img/14-header-galileo-3.png) 65 | 66 | > A dry gate (also simply a gate) is the kind that you're already familiar with by now: a one-armed core with a sample. A wet gate is also a one-armed core with a sample, but there is a difference. With a dry gate, when you pass in an argument and the code gets compiled, the type system will try to cast to the type specified by the gate; if you pass something that does not fit in the specified type, for example a cord instead of a cell you will get a nest failure. On the other hand, when you pass arguments to a wet gate, their types are preserved and type analysis is done at the definition site of the gate rather than the call site. 67 | 68 | In other words, a dry gate requires the argument type to match. A wet gate lets the arguments be "coerced" for internal purposes. However, dry gates can express type variance in several ways. 69 | 70 | Let us consult [La Wik](https://en.wikipedia.org/wiki/Covariance_and_contravariance_%28computer_science%29) on the subject of polymorphism: 71 | 72 | > Within the type system of a programming language, a typing rule or a type constructor is: 73 | > 74 | > - _covariant_ if it preserves the ordering of types (≤), which orders types from more specific to more generic; 75 | > - _contravariant_ if it reverses this ordering; 76 | > - _bivariant_ if both of these apply; 77 | > - _invariant_ or _nonvariant_ if not variant. 78 | 79 | Compare with the Urbit whitepaper: 80 | 81 | > There are two forms of polymorphism: variance and genericity. In Hoon this choice is per arm. A dry arm uses variance; a wet arm uses genericity. 82 | 83 | All of the gates we have made thus far using `|=` bartis are dry gates. In this case, we are simply checking if the payload being employed is compatible (what auras and molds do). "Dry gates", therefore, are called as if they were typical functions in most programming languages. 84 | 85 | Arguments made to dry gates must nest. More generally, dry cores must have nested types. (This differs from a language like Python, in which you can rather freely cast from one type to another, as `int` to `float`. `@ud` and `@rs` are fundamentally different auras in Hoon, although `sun` can interconvert.) 86 | 87 | > With a dry gate, when you pass in an argument and the code gets compiled, the type system will try to cast to the type specified by the gate; if you pass something that does not fit in the specified type, for example a `cord` instead of a `cell` you will get a nest failure. 88 | 89 | ![](../img/14-header-galileo-4.png) 90 | 91 | > The type check for each arm in a dry core can be understood as implementing a version of the “Liskov substitution principle.” The arm works for some (originally defined) payload type `P`. Payload type `Q` nests under `P`. Therefore the arm works for `Q` as well, though for type inference purposes the payload is treated as a `P`. The inferred type of the arm is based on the assumption that it's evaluated with a subject type exactly like that of its original parent core—i.e., whose payload is of type `P`. 92 | 93 | HOWEVER, dry cores can differ in their variance models. 94 | 95 | | Behavior | Metal | Interpretation | Example | 96 | | -------- | ----- | -------------- | ------- | 97 | | Invariant | `%gold` | Read-write payload | "when type-checking against a gold core, the target payload cannot vary at all in type. Consequently, it is type-safe to modify every part of the payload: gold cores have a read-write payload." | 98 | | Bivariant | `%lead` | Opaque payload | "There is no restriction on which payload types nest. That means, among other things, that the payload type of a lead core is both covariant and contravariant ('bivariant')." | 99 | | Covariant | `%zinc` | Write-only sample | "The sample of a zinc core is read-only. That means, among other things, that zinc cores cannot be used for function calls." | 100 | | Contravariant | `%iron` | Read-only sample | "Iron gates are particularly useful when you want to pass gates (having various payload types) to other gates." | 101 | 102 | In practice, gold and iron cores are commonly seen; I've observed far fewer zinc and lead gates in the wild. Gates constructed with `|` bar runes can be converted using some of the `&` pam runes. 103 | 104 | - Reading: [Tlon Corporation, "Type Polymorphism"](https://urbit.org/docs/hoon/hoon-school/type-polymorphism/), sections "Dry Cores" and "The Four Kinds of Cores" 105 | - Reading: [Tlon Corporation, "Advanced Types"](https://urbit.org/docs/reference/hoon-expressions/advanced/), sections on dry gates in "`%core` Advanced Polymorphism" 106 | 107 | We will discuss wet gates in Polymorphism. 108 | 109 | ![](../img/14-header-galileo-5.png) 110 | 111 | _The Moon is made of cheese, and cheese is made from mold. These are Galileo's drawings of the Moon from his early telescope experiments._ 112 | -------------------------------------------------------------------------------- /lessons/lesson15-stdlib.md: -------------------------------------------------------------------------------- 1 | # The Standard Library 2 | 3 | ![](../img/15-header-warroom-top.png) 4 | 5 | ## Learning Objectives 6 | 7 | - Explore the standard library's functionality: text parsing & processing, functional hacks, randomness, hashing, time, and so forth. 8 | 9 | 10 | ## Standard Operations 11 | 12 | ![](../img/15-header-warroom-bottom.png) 13 | 14 | Any useful programming language exposes a standard library: a set of tools and manipulations which are exposed to or importable for any program to utilize immediately. The Urbit OS standard library lives split between three aspects: Hoon itself, Arvo, and Zuse. 15 | 16 | Now, there's a bit of a challenge in sorting out which gates and molds come from Hoon and which from Zuse, and the docs generally aren't clear in defining those boundaries. So `++add` is part of Hoon, whereas `++gift` is part of each vane's material in Zuse. 17 | 18 | - Reading: [Tlon Corporation, "Standard Library (By Section)"](https://urbit.org/docs/reference/library/table-of-contents/#by-section) 19 | 20 | ## Hoon 21 | 22 | ![](../img/15-header-missiles.png) 23 | 24 | Broadly speaking, almost all of the functions and tools you've used up until today—with the exception of some of the Clay operations involved `++arch`—have been part of Hoon only. 25 | 26 | 27 | ## Arvo 28 | 29 | ![](../img/15-header-airplane.png) 30 | 31 | Arvo, at the top, is simply a gate which takes a timestamp and a structured input. Since Arvo and Arvo's vanes must communicate with each other, it behooves us to establish a standard interface for that communication. 32 | 33 | For instance, here are some of the top-level definitions which Arvo provides: 34 | 35 | ```hoon 36 | :: $arch: fundamental node 37 | :: $beak: global context 38 | :: $beam: global name 39 | :: $bone: opaque duct handle 40 | :: $case: global version 41 | :: $cage: marked vase 42 | :: +cask: marked data builder 43 | :: $desk: local workspace 44 | :: $dock: message target 45 | :: $mark: symbolic content type 46 | :: $ship: network identity 47 | :: $sink: subscription 48 | ``` 49 | 50 | The basic unit for these interactions is a `move`, which is a cell `[duct ball]`, or cause and action. (Gall calls these `[bone card]` for who knows what reason. Just think of causes and actions.) Since we will start using moves extensively when we use Gall and Clay, let's dig into them a bit. Each move can take one of several forms, but the most common and most important are these: 51 | 52 | - `%pass` moves are essentially vane calls. 53 | - `%give` moves are essentiall returns. 54 | - `%unix` moves handle Unix-facing communications. 55 | 56 | A `wire` (which is a kind of `path`) represents the list of symbols defining a particular cause. 57 | 58 | These events are handled by `duct`s, which are call stacks maintained by each vanes. 59 | 60 | You can get a notion of the kind of processing available for moves: 61 | 62 | ```hoon 63 | :: $ball: dynamic kernel action 64 | :: $card: tagged, untyped event (vane-specific) 65 | :: $curd: tagged, untyped event 66 | :: $duct: causal history 67 | :: +hobo: %soft task builder 68 | :: $goof: crash label and trace XX fail/ruin/crud/flaw/lack/miss 69 | :: $mass: memory usage 70 | :: $monk: general identity 71 | :: $move: cause and action 72 | :: $ovum: card with cause 73 | :: $scry-sample: vane +scry argument 74 | :: $vane-sample: vane wrapper-gate aargument 75 | :: +wind: kernel action builder 76 | :: $wire: event pretext 77 | :: +wite: kernel action/error builder 78 | ``` 79 | 80 | - Reading: [Tlon Corporation, "Arvo"](https://urbit.org/docs/tutorials/arvo/arvo/), sections "What is Arvo?"–"Formal Interface" (we'll dive deeper into this in Arvo 1) 81 | 82 | 83 | ## Zuse 84 | 85 | ![](../img/15-header-crm114.png) 86 | 87 | Zuse is also a major component of the standard library for Urbit. It sits midway on the subject stack, after the Hoon parser and Arvo itself, but before the vanes and the userspace apps. The goal of Zuse is to provide a minimalist set of conventional operations on cores and the like. 88 | 89 | "All vanes and userspace files depend on Zuse, which depends on the Arvo and Hoon sources." The source for `%zuse` is in `zuse.hoon`. The source code in Zuse is rather well-commented, though its accessibility is a function of familiarity with the Arvo bestiary. 90 | 91 | Indeed, the standard library `%zuse` contains two nested cores, one for data structures and the other for functions (gates, doors, etc.). Some pieces of `%zuse` define standard structures (like HTTP headers or ), while others describe standard tasks across vanes (like `%plea` "receive message via `%ames`" or `%vega`, "kernel upgraded)". 92 | 93 | For instance, `%zuse` defines vane-specific structures like the `beam` and `beak`: 94 | 95 | 96 | ```hoon 97 | ++ beam {{p/ship q/desk r/case} s/path} :: global name 98 | ++ beak {p/ship q/desk r/case} :: path prefix 99 | ``` 100 | 101 | 102 | Zuse also provides components to parse and process data structure like JSON, `++enjs` and `++dejs`, and MIME types, `++mimes`. 103 | 104 | ```hoon 105 | > (en-base58:mimes:html `@ud`'Hello, world') 106 | "2tv3tjoSwn5Qqgnuu" 107 | > (de-base58:mimes:html "2tv3tjoSwn5Qqgnuu") 108 | 31.079.605.376.604.435.891.501.163.848 109 | > `@t`(de-base58:mimes:html "2tv3tjoSwn5Qqgnuu") 110 | 'Hello, world' 111 | ``` 112 | 113 | There are some cryptography routines, time parsing, and other utilities as well. 114 | 115 | ```hoon 116 | > (dust:chrono:userlib `date`(yore now)) 117 | "Mon, 28 Sep 2020 18:53:14 +0000" 118 | > (stud:chrono:userlib 'Mon, 28 Sep 2020 18:53:14 +0000') 119 | [~ [[a=%.y y=2.020] m=9 t=[d=28 h=18 m=53 s=14 f=~]]] 120 | ``` 121 | 122 | - Optional Reading: [Tlon Corporation, `zuse.hoon`](https://github.com/urbit/urbit/blob/master/pkg/arvo/sys/zuse.hoon) 123 | 124 | ![](../img/15-header-turgidson.png) 125 | -------------------------------------------------------------------------------- /lessons/lesson16-containers.md: -------------------------------------------------------------------------------- 1 | # Common Containers 2 | 3 | ![](../img/16-header-moebius1.png) 4 | 5 | ## Learning Objectives 6 | 7 | - Identify common Hoon patterns, such as set, map, jar, and jug. 8 | - Use Sail runes to compose XML/HTML blocks. 9 | - Use the Hoon standard library Sections 2h–2k. 10 | 11 | 12 | ## Containers 13 | 14 | The most fundamental container in Hoon (and Nock) is a cell: `[* *]`. There are of course a number of specialty containers you've already seen: 15 | 16 | - `core` `[battery payload]`: thence doors, gates, etc. 17 | - `list` `~[1 2 3]` 18 | - [`vase`](https://urbit.org/docs/reference/library/4o/#vase) `!>(`@rs`.1.0)`, `!>(~)` 19 | - [`dime`](https://urbit.org/docs/reference/library/3g/#dime): atom-aura pair 20 | 21 | Containers are supported to allow the ordered retrieval of information. Fundamentally, we can separate containers by access mode (sequential and random-access). An example of a sequential container would be a list; an example of a random-access container would be an associative array or dictionary—a `map`, to Hoon. 22 | 23 | 24 | ## Lists 25 | 26 | ![](../img/16-header-moebius2.png) 27 | 28 | Lists are simply rightwards-branching null-terminated sequences. They can be irregularly constructed using `~[1 2 3]` notation or using the `:~` colsig rune: 29 | 30 | ```hoon 31 | =colormap :~ [135, 59, 97] 32 | [144, 69, 147] 33 | [131, 91, 193] 34 | [103, 123, 220] 35 | [73, 162, 218] 36 | [58, 198, 189] 37 | [71, 223, 145] 38 | [113, 231, 108] 39 | [173, 225, 95] 40 | [233, 213, 117] 41 | == 42 | ``` 43 | 44 | Access to list elements is accomplished using [`++snag`](https://urbit.org/docs/reference/library/2b/#snag) by a zero-indexed convention: 45 | 46 | ```hoon 47 | (snag 3 `(list)`colormap) 48 | ``` 49 | 50 | Sometimes the Hoon typechecker has difficulty identifying a null-terminated tuple as a list. In that case, you may need to cast using the `++list` mold builder or the [`++limo`](https://urbit.org/docs/reference/library/2b/#limo) wrapper which adds `i`/`t` faces. As always, frequently cast your expectations by mold using `^+` ketlus or `^-` kethep. 51 | 52 | There are several tools to manipulate, combine, and separate lists and list elements: `++snap`, `++weld`, etc. 53 | 54 | - Reading: [Tlon Corporation, "List Logic"](https://urbit.org/docs/reference/library/2b/) 55 | 56 | 57 | ## Maps, Sets, Jars, & Jugs 58 | 59 | ![](../img/16-header-moebius3.png) 60 | 61 | There is an ensemble of containers which are frequently used together: maps (key-value treaps); sets (ordered treaps); jars (maps of lists); and jugs (maps of sets). 62 | 63 | ### Maps 64 | 65 | If you want to look up data by key–value pairs, use the [`++my`](https://urbit.org/docs/reference/library/2m/#my) mold builder to construct a `map`. 66 | 67 | ```hoon 68 | =alphabet `(map @ta cord)`(my ~[[%alpha 'α'] [%beta 'β'] [%gamma 'γ'] [%delta 'δ']]) 69 | ``` 70 | 71 | To access a particular entry, use the `++get` arm in the following tendentious construction: 72 | 73 | ```hoon 74 | (~(get by alphabet) %alpha) 75 | ``` 76 | 77 | Notice that this returns a `unit`, which also permits a bare `~` to be returned in case the entry is empty. 78 | 79 | > What is going on with that `~(get by alphabet)` bit? 80 | > 81 | > Essentially, this lookup needs to resolve to a gate which can accept a sample (the key) and produce a value. These arms in `++by`, `++in`, etc., are doors which resolve to gates for key lookup. 82 | 83 | To change or insert an entry, use the `++put` arm: 84 | 85 | ```hoon 86 | (~(put by alphabet) [%epsilon 'ε']) 87 | ``` 88 | 89 | (This _returns_ a changed copy; it doesn't alter the original dictionary.) 90 | 91 | - Reading: [Tlon Corporation, "Trees, Sets, and Maps"](https://urbit.org/docs/hoon/hoon-school/trees-sets-and-maps/) 92 | - Reading: [Tlon Corporation, "Map Logic"](https://urbit.org/docs/reference/library/2i/) 93 | 94 | ### Sets 95 | 96 | A set is a collection of discrete objects. 97 | 98 | If you want to track set membership using a `set`, use the [`++sy`](https://urbit.org/docs/reference/library/2m/#sy) mold builder. 99 | 100 | ```hoon 101 | =fibs `(set @rs)`(sy ~[.1 .1 .2 .3 .5 .8 .13 .21]) 102 | ``` 103 | 104 | To check set membership, use `++has`: 105 | 106 | ```hoon 107 | (~(has in fibs) .34) 108 | ``` 109 | 110 | To add or remove an item from a set, use `++put` and `++del`, respectively: 111 | 112 | ```hoon 113 | (~(put in fibs) .34) 114 | (~(del in fibs) .1) 115 | ``` 116 | 117 | Slam a gate on each item in the set with `++run`: 118 | 119 | ```hoon 120 | (~(run in fibs) |=(a=@rs (add:rs .1 a))) 121 | ``` 122 | 123 | Slam a gate across all items in the set with `++rep`: 124 | 125 | ```hoon 126 | (~(rep in fibs) add:rs) 127 | ``` 128 | 129 | - Reading: [Tlon Corporation, "Set Logic"](https://urbit.org/docs/reference/library/2h/) 130 | 131 | ### Jars 132 | 133 | A jar is a map of lists. This is used internally for such operations as remembering ship names in order of preference and tracking `%unix` events. 134 | 135 | - Reading: [Tlon Corporation, "Jar and Jug Logic"](https://urbit.org/docs/reference/library/2j/) 136 | 137 | ### Jugs 138 | 139 | A jug is a map of sets. This is frequently used in the metadata store in Gall apps like Chat and Publish. 140 | 141 | - Reading: [Tlon Corporation, "Jar and Jug Logic"](https://urbit.org/docs/reference/library/2j/) 142 | 143 | ### Applications 144 | 145 | ![](../img/16-header-moebius4.png) 146 | 147 | Once you have a map or a set, what do you do with it? One common technique is to `++turn` on `a-map` by `a-gate`: 148 | 149 | ```hoon 150 | (turn ~(tap in ~(key by a-map)) a-gate) 151 | (turn ~(tap in ~(key by a-map)) a-gate) 152 | ``` 153 | 154 | That produces a list. If you want to preserve having a map, use `++urn`: 155 | 156 | ```hoon 157 | (~(urn by a-map) |=(a=(pair * *) q.a)) 158 | ``` 159 | 160 | (See also [`++stir`](https://urbit.org/docs/reference/library/4f/#stir), the parser-combinator for sequences, which acts as a Map/Reduce algorithm.) 161 | 162 | - Reading: [Tlon Corporation, "Normalizing Containers"](https://urbit.org/docs/reference/library/2o/) 163 | - Reading: [Tlon Corporation, "Container from Container"](https://urbit.org/docs/reference/library/2l/) 164 | - Reading: [Tlon Corporation, "Container from Noun"](https://urbit.org/docs/reference/library/2m/) 165 | 166 | 167 | ## Addendum 168 | 169 | ![](../img/16-header-moebius5.png) 170 | 171 | The bomb defusing exercise is a great refresher before we start on Gall next time. It also uses some of the container logic we developed above. 172 | 173 | - Reading: [Tlon Corporation, "Hoon Workbook: Bomb Defusing"](https://web.archive.org/web/20210315072208/https://urbit.org/docs/tutorials/hoon/workbook/bomb/) 174 | 175 | Dawid Ciezarkiewicz `~napter-matnep` has been working on a Hoon introduction, which may be worth your while to peruse as an alternative explanation of many elementary concepts in Hoon. 176 | 177 | - Optional Reading: [Dawid Ciezarkiewicz `~napter-matnep`, "Hoon for Regular Programmers"](https://hackmd.io/IYd4RkpBQVqQTehmJeoxRw) 178 | 179 | ![](../img/16-header-moebius6.png) 180 | 181 | _All images in this lesson copyright Moebius._ 182 | 183 | 184 | # Questions 185 | 186 | ## Creating a Map 187 | 188 | Create a map of ZIP codes, mapping the ZIP code to a city name. (You may use any source.) 189 | 190 | ## Creating a Map 191 | 192 | Create a second map of human names paired with ZIP codes (as if extracted from a database). 193 | 194 | Demonstrate looking up a human's city via their ZIP code. 195 | -------------------------------------------------------------------------------- /lessons/lesson17-gall-1.md: -------------------------------------------------------------------------------- 1 | # Gall I 2 | 3 | ![](../img/17-header-minuteman.png) 4 | 5 | ## Learning Objectives 6 | 7 | - Understand how static Gall instruments an app. 8 | * Produce a basic Gall app. 9 | 10 | 11 | ## Userspace 12 | 13 | We looked at Clay and Ford earlier; we'll see Ames and Behn and other vanes ahead. Today we start on an epic journey through userspace: Gall. 14 | 15 | The Gall vane provides a standard set of operations to interface with userspace "apps": really, state machines. Almost everything in Urbit you interact with as a user is mediated through Gall: Chat, Publish, Landscape, Dojo... 16 | 17 | 18 | ## Event Handling 19 | 20 | ![](../img/17-header-interceptor.jpg) 21 | 22 | The fundamental unit of the Urbit kernel is an event called a `++move`. Arvo is primarily an event dispatcher between moves created by vanes. Each move therefore has an address and other structured information. 23 | 24 | >A vanilla event loop scales poorly in complexity. A system event is the trigger for a cascade of internal events; each event can schedule any number of future events. This easily degenerates into “event spaghetti.” Arvo has “structured events”; it imposes a stack discipline on event causality, much like imposing subroutine structure on gotos. 25 | > 26 | >An interrupted event never happened. The computer is deterministic; an event is a transaction; the event log is a log of successful transactions. In a sense, replaying this log is not Turing complete. The log is an existence proof that every event within it terminates. (Whitepaper) 27 | 28 | Every Gall app is a door with two components in its subject: 29 | 30 | 1. `bowl:gall` for Gall-standard tools and data structures 31 | 2. App state information 32 | 33 | The older Gall system (pre-12/19), now dubbed dynamic Gall, allowed for the free definition of arms as event handlers. New Gall (static Gall) mandates a standard structure for event handlers[.](https://en.wikipedia.org/wiki/Roosevelt%E2%80%93Rondon_Scientific_Expedition) 34 | 35 | A minimalist do-nothing default Gall app could look like this: 36 | 37 | ```hoon 38 | /+ default-agent 39 | ^- agent:gall 40 | =| state=@ 41 | |_ =bowl:gall 42 | +* this . 43 | default ~(. (default-agent this %|) bowl) 44 | :: 45 | ++ on-init on-init:default 46 | ++ on-save on-save:default 47 | ++ on-load on-load:default 48 | ++ on-poke 49 | |= [=mark =vase] 50 | ~& > state=state 51 | ~& got-poked-with-data=mark 52 | =. state +(state) 53 | `this 54 | :: 55 | ++ on-watch on-watch:default 56 | ++ on-leave on-leave:default 57 | ++ on-peek on-peek:default 58 | ++ on-agent on-agent:default 59 | ++ on-arvo on-arvo:default 60 | ++ on-fail on-fail:default 61 | ``` 62 | 63 | - Reading: [Tlon Corporation, "Gall"](https://urbit.org/docs/hoon/hoon-school/gall/) 64 | - Reading: [Tlon Corporation, "Gall Tutorial"](https://urbit.org/docs/tutorials/arvo/gall/) 65 | 66 | 67 | ## Events 68 | 69 | ![](../img/17-header-contrail.png) 70 | 71 | Every vane defines its own structured events. Each unique kind of structured event has a unique, frequently whimsical, name. This can make it challenging to get used to how a particular vane behaves. 72 | 73 | For Gall, a standard move is a pair `[bone card]`. A `bone` is a cause while a `card` is an action. (`[cause action]`, it's always `[cause action]`.) A `card`, in turn, is a pair `[tag noun]`. The tag is a `@tas` token to indicate which event is being triggered while the `noun` contains any necessary information. 74 | 75 | Gall apps run like services, so they can always talk to each other. This leads to a very high potential for app interactivity rather than siloization. 76 | 77 | (Compare this to other core structures: a gate is `[battery [sample context]]`; a move is `[bone [tag noun]]`.) 78 | 79 | 80 | ## Types of Apps 81 | 82 | ![](../img/17-header-launch.png) 83 | 84 | Userspace applications are conceptually but not architecturally divided into three classes. It is recommended as a burgeoning best practice that new apps hew to this division for clarity and forward compatibility. 85 | 86 | 1. **Stores**. Independent local collections of data exposed to other apps. Think of Groups for Landscape. 87 | 2. **Hooks**. Store manipulations. Think of subscriptions. 88 | 3. **Views**. User-interface applications. Think of Landscape itself (the browser interface). 89 | 90 | - Reading: [Logan Allen, Matt, Matilde Park `~haddef-sigwen`, "Userspace Architecture"](https://docs.google.com/document/d/1hS_UuResG1S4j49_H-aSshoTOROKBnGoJAaRgOipf54/edit) 91 | 92 | ![](../img/17-header-iron-dome.png) 93 | 94 | 95 | # Questions 96 | 97 | ## Identifying Move Tokens 98 | 99 | Examine the code in `app/chat-cli.hoon`. 100 | 101 | Report the list of possible move tokens for that Gall app under the `+$command` structure arm. Note (but don't bother reporting) the associated nouns. 102 | 103 | ## A Minimalist Gall App 104 | 105 | Complete the [`egg-timer` app tutorial](https://urbit.org/docs/hoon/hoon-school/egg-timer/). 106 | 107 | You may start the Gall app using `|start %egg-timer` and poke it using a relative time such as `:egg-timer ~s10`. 108 | 109 | We will revisit this when we discuss Behn. 110 | -------------------------------------------------------------------------------- /lessons/lesson18-kernel.md: -------------------------------------------------------------------------------- 1 | # The Kernel 2 | 3 | ![](../img/18-header-verne1.png) 4 | 5 | ## Learning Objectives 6 | 7 | - Discuss foundational philosophy and directional vision for the project. 8 | 9 | 10 | ## The Kernel 11 | 12 | ![](../img/18-header-verne2.png) 13 | 14 | It's time for a philosophical fireside chat. To tie together our loose ends up to this point, and to preface our further dive into the kernel post-Gall, we need to read the Urbit Whitepaper and thoroughly discuss its perspective. We will also need to re-read and internalize the Urbit Precepts (an aesthetic of programming) and their associated discussion. 15 | 16 | - Reading: [Curtis Yarvin `~sorreg-namtyv`, Philip Monk `~wicdev-wisryt`, Anton Dyudin, and Raymond Pasco, "Urbit: A Solid-State Interpreter" ("Whitepaper")](http://media.urbit.org/whitepaper.pdf), sections 1–8, 11–15 17 | - Reading: [Philip Monk `~wicdev-wisryt`, "Urbit Precepts"](https://urbit.org/blog/precepts/) 18 | - Reading: [Philip Monk `~wicdev-wisryt`, "Urbit Precepts (Discussion)"](https://urbit.org/blog/precepts-discussion/) 19 | - Optional Reading: [Andrea O'Sullivan, "Can Urbit Reboot Computing?" (_Reason_ Magazine)](https://reason.com/2016/06/21/can-urbit-transform-the-internet/) 20 | - Optional Reading: [François-René Rideau (Faré), "Houyhnhnms vs Martians"](https://ngnghm.github.io/blog/2016/06/11/chapter-10-houyhnhnms-vs-martians/) 21 | 22 | ![](../img/18-header-verne3.png) 23 | 24 | 25 | # Questions 26 | 27 | ## Move Traces 28 | 29 | Read the [docs on processing a move in Arvo](https://urbit.org/docs/tutorials/arvo/move-trace/). 30 | -------------------------------------------------------------------------------- /lessons/lesson19-text-parsing.md: -------------------------------------------------------------------------------- 1 | # Text Parsing 2 | 3 | ![](../img/20-foss-0.png) 4 | 5 | ## Learning Objectives 6 | 7 | {{ indented_include( "lessons/19-text-parsing/objectives.yml",0 ) }} 8 | 9 | 10 | ## Text Molds and Values 11 | 12 | ![](../img/20-foss-1.png) 13 | 14 | The basic text quantities in Hoon are the atom `cord` `@t` and derivatives, and the list `tape`. 15 | 16 | ```hoon 17 | > `@t`'Excalibur' 18 | 'Excalibur' 19 | > `tape`"Excalibur" 20 | "Excalibur" 21 | ``` 22 | 23 | There are many helpful text conversion arms: 24 | 25 | - `++cass`: convert upper-case text to lower-case (`tape`→`tape`) 26 | - `++cuss`: convert lower-case text to upper-case (`tape`→`tape`) 27 | - `++crip`: convert `tape` to `cord` (`tape`→`cord`) 28 | - `++trip`: convert `cord` to `tape` (`cord`→`tape`) 29 | 30 | You can convert to and from atoms with particular auras as well: 31 | 32 | - [`++scot`](https://urbit.org/docs/reference/library/4m/#scot): render `dime` as `cord` (`dime`→`cord`) 33 | - [`++scow`](https://urbit.org/docs/reference/library/4m/#scow): render `dime` as `tape` (`dime`→`tape`) 34 | 35 | But wait: what's a `dime`? A `dime` is a pair of aura as `@ta` and a value. This helps the function know _what_ to render the value as. 36 | 37 | [`++scan`](https://urbit.org/docs/reference/library/4g/#scan) is used with a parsing rule to parse `tape` into `atom`. 38 | 39 | - [`dim:ag`](https://urbit.org/docs/reference/library/4j/#dim-ag) parses a decimal number out of a tape (`tape`→`@ud`) 40 | - [`ddm:ag`](https://urbit.org/docs/reference/library/4j/#dim-ag) parses an Urbit-style decimal number (with `1.000` dot separators) out of a tape (`tape`→`@ud`) 41 | - [`hex:ag`](https://urbit.org/docs/reference/library/4j/#hex-ag) parses a hexadecimal digit out of a tape (`tape`→`@ux`) 42 | - [`d:ne`](https://urbit.org/docs/reference/library/4j/#x-ne) renders a adecimal digit from an atom (`@ud`→`cord`) 43 | - [`x:ne`](https://urbit.org/docs/reference/library/4j/#x-ne) renders a hexadecimal digit from an atom (`@ux`→`cord`) 44 | 45 | There are many more of these, but you get the flavor of it. 46 | 47 | - Reading: [Tlon Corporation, "Text Processing"](https://urbit.org/docs/reference/library/4b/) 48 | - Reading: [Tlon Corporation, "Parsing (Bases and Base Digits)"](https://urbit.org/docs/reference/library/4j/) 49 | 50 | 51 | ## Text Structures 52 | 53 | ![](../img/20-foss-2.png) 54 | 55 | Many more advanced text structures are available. These contain metadata tags such as `%leaf` to hint to the prettyprinter and other tools how to represent and process the text data. 56 | 57 | Remember from way back when `wain` and `wall`: `wain` being a list of `cord`s and `wall` being a list of `tape`s. 58 | 59 | The primary data structure used by the prettyprinter is a [`tank`](https://urbit.org/docs/reference/library/2q/#tank), which is a nested tagged structure of `tape`s. A `tank` element can be tagged in one of three ways: 60 | 61 | - `%leaf` or `leaf+""`: a simple printed line 62 | - `%rose`: a list of tank delimited by strings 63 | - `%palm`: a list of tank delimited by strings with backsteps (least common) 64 | 65 | For instance, to make a single `%leaf` statement, you can type 66 | 67 | ```hoon 68 | leaf+"Rhongomyniad" 69 | ``` 70 | 71 | You can also us the `>1.000<` format, which converts a value to a `$tank` directly (and can be used with faces/names). 72 | 73 | A [`tang`](https://urbit.org/docs/reference/library/2q/#tang) is a list of `tank`s. It is used with [`++slog`](https://urbit.org/docs/reference/library/2n/#slog) to produce conditional error messages. 74 | 75 | 76 | ## Tokenizing and Parsing Text 77 | 78 | ![](../img/20-foss-3.png) 79 | 80 | One of the most straightforward tools to use with text is [`++trim`](https://urbit.org/docs/reference/library/4b/#trim), which splits a tape into two parts at a given index. You can use this together with [`++find`](https://urbit.org/docs/reference/library/2b/#find) to produce a simple text tokenizer. 81 | 82 | ```hoon 83 | ++ parse 84 | |= [in-words=tape] 85 | =/ out-words *(list tape) 86 | |- ^+ out-words 87 | =/ next-index (find " " in-words) 88 | ?: =(next-index ~) (weld out-words ~[in-words]) 89 | =/ values (trim +(+:next-index) in-words) 90 | ~& values 91 | $(in-words +:values, out-words (weld out-words ~[-:values])) 92 | ``` 93 | 94 | - Optional Reading: [Tlon Corporation, "Parsing Hoon"](https://urbit.org/docs/hoon/guides/parsing#parsing-arithmetic-expressions), section "Parsing Arithmetic Expressions" 95 | 96 | 97 | ### Sail & XML Parsing 98 | 99 | Let's consider abstractly manipulating XML entities. There are a number of `;` mic runes which support this. 100 | 101 | > Sail is a part of Hoon used for creating and operating on nouns that represent XML nodes. With the appropriate rendering pipeline, a Sail document can be used to generate a static website[.](https://en.wikipedia.org/wiki/Io_%28moon%29#Interaction_with_Jupiter's_magnetosphere) 102 | 103 | The Sail runes are stored as `;` mic macros. These operate on [`++manx`](https://urbit.org/docs/reference/library/5f/#manx) and [`++marl`](https://urbit.org/docs/reference/library/5f/#marl) (list of `manx`) values. A `manx` is a single XML node; XML being a superspec of HTML, therefore, Sail can be used to map and produce HTML as a function of Hoon operations. 104 | 105 | A `manx` is a single XML node, and thus 106 | 107 | ```hoon 108 | [[%p ~] [[%$ [%$ "This is the first node."] ~] ~] ~] 109 | ``` 110 | 111 | Generally, one produces and manipulates `marl`s rather than directly working with `manx`s. 112 | 113 | ```hoon 114 | ;p: This will be rendered as an XML node. 115 | ``` 116 | 117 | ```hoon 118 | =; ;p: 119 | ;p: 120 | ;p: 121 | ``` 122 | 123 | These are ultimately parsed by and from `%zuse`'s `++en-xml:html` and `++de-xml:html` arms. 124 | 125 | ```hoon 126 | `manx`+:(de-xml:html (crip "text")) 127 | ``` 128 | 129 | - Reading: [Tlon Corporation, "Molds and Mold Builders"](https://urbit.org/docs/reference/library/5f/), search for "XML" 130 | 131 | ### JSON Parsing 132 | 133 | Similar to XML/HTML, there are a number of tools (but not runes) in the `++enjs` and `++dejs` arms of `%zuse`. 134 | 135 | ```hoon 136 | > (tape:enjs:format "hello world") 137 | [%s p='hello world'] 138 | ``` 139 | 140 | ```hoon 141 | > (sa:dejs:format (tape:enjs:format "hello world")) 142 | "hello world" 143 | ``` 144 | 145 | - Reading: [`zuse.hoon`](https://github.com/urbit/urbit/blob/master/pkg/arvo/sys/zuse.hoon#L5406), `++enjs` and `++dejs` arms 146 | 147 | 148 | ## Aside on Functional Tools 149 | 150 | It is convenient when parsing (and performing many other operations) to curry a function or cork it. 151 | 152 | To _curry_ a function means to wrap one of its arguments inside of it so that it becomes a function not of $n$ variables but of $n-1$ variables. Use [`++cury`](https://urbit.org/docs/reference/library/2n/#cury) to accomplish this. 153 | 154 | ```hoon 155 | > =add-1 (add:rs .1) 156 | > (add-1 .2) 157 | .3 158 | ``` 159 | 160 | To _cork_ a function is to compose it forwards; that is, repeatedly apply it 161 | 162 | ```hoon 163 | > (:(cork dec dec dec dec dec) 1.000) 164 | 995 165 | ``` 166 | 167 | Use [`++cork`](https://urbit.org/docs/reference/library/2n/#cork) to cork a function. 168 | 169 | _Art by Chris Foss._ 170 | 171 | 172 | # Questions 173 | 174 | ## Parsing HTML 175 | 176 | Parse the following HTML block into Sail elements such as `manx`s and `marl`s: 177 | 178 | ```html 179 |

The Alliterative Morte Arthure, a Middle English poem, mentions Clarent, a sword of peace meant for knighting and ceremonies as opposed to battle, which Mordred stole and then used to kill Arthur at Camlann. The Prose Lancelot of the Vulgate Cycle mentions a sword called Seure (Sequence), or Secace in some manuscripts, which belonged to Arthur but was borrowed by Lancelot.

180 | ``` 181 | 182 | (You'll need to right-click and `Inspect Element` to get the `

` tag and its contents. Markdown and Jinja aren't playing nice with the code block.) 183 | 184 | ## Morse Code 185 | 186 | Produce an `%ask` generator which accepts a text value and produces the Morse code equivalent. You may use the following core as a point of departure for composition. 187 | 188 | You may decide how to handle spaces (omit or emit a space), but you should convert the message to lower-case first. 189 | 190 | ```hoon 191 | |% 192 | ++ en-morse !! 193 | ++ table 194 | %- my 195 | :~ :- 'a' '·-' :- 'b' '-···' :- 'c' '-·-·' :- 'd' '-··' 196 | :- 'e' '·' :- 'f' '··-·' :- 'g' '--·' :- 'h' '····' 197 | :- 'i' '··' :- 'j' '·---' :- 'k' '-·-' :- 'l' '·-··' 198 | :- 'm' '--' :- 'n' '-·' :- 'o' '---' :- 'p' '·--·' 199 | :- 'q' '--·-' :- 'r' '·-·' :- 's' '···' :- 't' '-' 200 | :- 'u' '··-' :- 'v' '···-' :- 'w' '·--' :- 'x' '-··-' 201 | :- 'y' '-·--' :- 'z' '--··' :- '0' '-----' :- '1' '·----' 202 | :- '2' '··---' :- '3' '···--' :- '4' '····-' :- '5' '·····' 203 | :- '6' '-····' :- '7' '--···' :- '8' '---··' :- '9' '----·' 204 | == 205 | -- 206 | ``` 207 | -------------------------------------------------------------------------------- /lessons/lesson20-ames.md: -------------------------------------------------------------------------------- 1 | # Ames 2 | 3 | ![](../img/19-berkey-0.png) 4 | 5 | ## Learning Objectives 6 | 7 | - Understand architecture of the Ames network and communications. 8 | 9 | 10 | Ames has probably evolved the least of any of the major vanes (except Clay) from its original whitepaper vision: 11 | 12 | >Ames is an encrypted peer-to-peer network running as an overlay over UDP. Ames does not have separate addressing and identity layers (like IP and DNS). An Ames address is an identity, mapped to a phonemic string to create a memorable pseudonym, and bound to a public key for encrypted communication. 13 | 14 | Although Ames _has_ survived several rewrites, it defines the identity of a virtual formal computer and thus is only meaningful as it provides interactivity with other Urbit ships. Thought of as a specification, it has been quite stable. 15 | 16 | A particularly salient distinction to maintain in your mind is that between a bus and a network: 17 | 18 | > There is a categorical difference between a bus, which transports commands, and a network, which transports packets. You can drop a packet but not a command; a packet is a fact and a command is an order. 19 | > 20 | > Facts are inherently idempotent; learning fact X twice is the same as learning it once. You can drop a packet, because you can ignore a fact. Orders are inherently sequential; if you get two commands to do thing X, you do thing X twice. (Whitepaper) 21 | 22 | Ames has to deal with both facts and orders, as it were: facts from the other ships on the network and orders from other vanes in Arvo. 23 | 24 | Ames refers to both the networking vane and the network itself. (Somewhat confusingly, rewrites of Ames such as the late-2019 Alef also become Ames when released.) 25 | 26 | 27 | ## Ames as Network 28 | 29 | ![](../img/19-berkey-1.png) 30 | 31 | The Ames network structure passes messages generated by the Ames vane of each ship according to a certain structure. 32 | 33 | ### Messaging 34 | 35 | The Ames vane is responsible for sending and receiving messages of arbitrary length. These are broken into MTU-sized fragments—MTU (Maximum Transmission Unit) being the largest packet size which your system can send. 36 | 37 | >Ames delivers messages of arbitrary length, broken into MTUshaped fragments. Because Urbit nodes are uniformly persistent, they maintain persistent sessions; message delivery is exactly-once. Every message is a transaction, and acknowledgments are end-to-end; the packet-level acknowledgment that completes a message also reports transaction success. 38 | > 39 | >Ames messages are typed; the type itself is not sent, just a label (like a MIME type) that the recipient must map to a local source path. Validation failure causes a silent packet drop, because its normal cause is a recipient that has not yet received a new protocol update; we want the sender to back off. Ames also silently drops packets for encryption failure; error reports are just an attack channel. 40 | 41 | An Ames message must be processed at the destination using Clay/Ford. 42 | 43 | - Reading: [Curtis Yarvin `~sorreg-namtyv`, Philip Monk `~wicdev-wisryt`, Anton Dyudin, and Raymond Pasco, "Urbit: A Solid-State Interpreter" ("Whitepaper")](http://media.urbit.org/whitepaper.pdf), sections 9–10 44 | 45 | ### UDP 46 | 47 | Ames communicates using the [User Datagram Protocol](https://en.wikipedia.org/wiki/User_Datagram_Protocol) (UDP) specification. UDP messages are "transaction oriented, and delivery and duplicate protection are not guaranteed." To compensate for this, Ames employs a unique system of acks and nacks, covered below. 48 | 49 | Each UDP message has a brief header including destination, source, length, and checksum. It's rather a "minimum viable" packet system. 50 | 51 | From [Cloudflare](https://www.cloudflare.com/learning/ddos/glossary/user-datagram-protocol-udp/): 52 | 53 | > UDP is faster but less reliable than TCP, another common transport protocol. In a TCP communication, the two computers begin by establishing a connection via an automated process called a ‘handshake.’ Only once this handshake has been completed will one computer actually transfer data packets to the other. 54 | 55 | Urbit compensates for this lower reliability by sending until receiving an appropriate ack or nack in reply. 56 | 57 | > UDP is commonly used in time-sensitive communications where occasionally dropping packets is better than waiting. Voice and video traffic are sent using this protocol because they are both time-sensitive and designed to handle some level of loss. For example VOIP (voice over IP), which is used by many internet-based telephone services, operates over UDP. This is because a staticy phone conversation is preferable to one that is crystal clear but heavily delayed. 58 | 59 | - Reading: [RFC 768](https://tools.ietf.org/html/rfc768) (UDP specification) 60 | 61 | ### Acks and Nacks 62 | 63 | >Ames receives packets as Arvo events and emits packets as Arvo effects. The runtime is responsible for transferring the bytes in an Ames packet across a physical network to another ship. (Ames Tutorial) 64 | 65 | If every message is a transaction (or event), then what is Ames acknowledging (ack) or negative-acknowledging (nack)? "A successful transaction has no result; a failed transaction is a negative ack and can contain an error dump." 66 | 67 | > Ames has an unusual system of acks and nacks ("negative acknowledgments", but not like TCP's packets of the same name; Ames nacks mean the packet was received but the message resulted in an error). In brief, each Ames packet of a message should get either an ack or a nack. In the current system, the nack may include an error message (e.g., an error code or a stack trace). ([Phillip Monk, `~wicdev-wisryt`](https://groups.google.com/a/urbit.org/g/dev/c/y_gaSpn9mxM/m/njlRhYZHBwAJ)) 68 | 69 | Ames will send messages and acks until a replying ack is received. "Ames guarantees that a message will only be delivered once to the destination vane." 70 | 71 | > When a new socket is opened, the client can resend (at-least-once delivery) or fail to resend (at-most-once). The programmer has to understand that the socket is not really a bus, and make sure the POST is actually an idempotent fact rather than an imperative command. (The idempotence problem is often punted to the human layer: “Please click only once to make your purchase.”) (Whitepaper) 72 | 73 | Because Ames and Urbit assume several nines of uptime, sessions between ships are treated as persistent. 74 | 75 | > The basic argument for including end-to-end acks (and by extension, nacks) is that they're necessary for everything except those things which we don't care whether the message was received at all. Thus, for Ames to give the guarantee that "if you give me a payload I will get it to the other side exactly once" isn't useful in itself, because no application cares about that. They either (1) don't care whether it gets there or (2) care whether the request itself was "completed", in an application-defined sense. ([Phillip Monk, `~wicdev-wisryt`](https://groups.google.com/a/urbit.org/g/dev/c/y_gaSpn9mxM/m/njlRhYZHBwAJ)) 76 | 77 | Keep in mind Postel’s law, also known as the robustness principle: "Be conservative in what you send, and liberal in what you accept." 78 | 79 | - Reading: [Tlon Corporation, "Ames"](https://urbit.org/docs/tutorials/arvo/ames/) 80 | 81 | - Optional Reading: [Saltzer, Reed, Clark, "End-to-End Arguments in System Design"](http://web.mit.edu/Saltzer/www/publications/endtoend/endtoend.pdf) 82 | 83 | 84 | ## Ames as Vane 85 | 86 | ![](../img/19-berkey-2.png) 87 | 88 | Ames arms include: 89 | 90 | ```hoon 91 | ++ call :: handle request stack 92 | ++ take :: handle response $sign 93 | ++ stay :: extract state before reload 94 | ++ load :: load in old state after reload 95 | ++ scry :: dereference namespace 96 | ``` 97 | 98 | which pretty well covers what Ames needs to do. (There is a collection of `ames-helper` cores as well to handle many specific cases for unpacking and routing messages.) 99 | 100 | Ames maintains a duct (queue) of ordered messages. These are passed to and received from the runtime, and represent Arvo events. Each message is encrypted at the source and decrypted at the destination using a symmetric public-key system. A message may be a `%plea` (sent to another ship); in response, Ames can receive zero or more `%boon`s. The ack–nack system is explained above; note that nacks are in response to event crashes. 101 | 102 | How does an Ames message work in Hoon? At the second-lowest level, you're poking a tool like `hood`. For instance, this is the source code to `|hi` in `gen/hood/hi.hoon`: 103 | 104 | ```hoon 105 | :: Helm: send message to an urbit 106 | :: 107 | :::: /hoon/hi/hood/gen 108 | :: 109 | /? 310 110 | :- %say 111 | |=({^ {who/ship mez/$@(~ {a/tape ~})} ~} helm-send-hi+[who ?~(mez ~ `a.mez)]) 112 | ``` 113 | 114 | This issues a poke to `hood`, the Gall–Dill interface app (`helm` is a component of `hood`), with a tag `%helm-send-hi`. 115 | 116 | ```hoon 117 | ++ poke 118 | |= [=mark =vase] 119 | ?+ mark ~|([%poke-helm-bad-mark mark] !!) 120 | ... 121 | %helm-reset =;(f (f !<(_+<.f vase)) poke-reset) 122 | %helm-send-hi =;(f (f !<(_+<.f vase)) poke-send-hi) 123 | %helm-serve =;(f (f !<(_+<.f vase)) poke-serve) 124 | ... 125 | == 126 | ``` 127 | 128 | The `++poke-send-hi:helm` arm: 129 | 130 | ```hoon 131 | ++ poke-send-hi 132 | |= {her/ship mes/(unit tape)} =< abet 133 | %- emit 134 | :* %pass /helm/hi/(scot %p her) 135 | %agent [her %hood] %poke 136 | %helm-hi !>(?~(mes '' (crip u.mes))) 137 | == 138 | ``` 139 | 140 | This issues a `%poke` to the target ship using the Gall API. 141 | 142 | ```hoon 143 | ++ emit |=(card this(moz [+< moz])) 144 | ``` 145 | 146 | where a `card` is `card:agent:gall`. 147 | 148 | Here at least we glimpse the lowest level of Ames operationality: direct manipulation of `card`s. We will rarely have need to compose these directly. Here is the `++agent` definition in Zuse which applies to the vanes: 149 | 150 | ```hoon 151 | ++ agent 152 | |% 153 | +$ card (wind note gift) 154 | ``` 155 | 156 | - Optional Reading: [`ames.hoon`](https://github.com/urbit/urbit/blob/master/pkg/arvo/sys/vane/ames.hoon) 157 | 158 | ![](../img/19-berkey-3.png) 159 | 160 | _Art by John Berkey._ (We're halfway through today! Have you learned anything new yet?) 161 | -------------------------------------------------------------------------------- /lessons/lesson21-behn.md: -------------------------------------------------------------------------------- 1 | # Behn 2 | 3 | ![](../img/21-mccall-0.png) 4 | 5 | ## Learning Objectives 6 | 7 | - Understand the high-level architecture and API of Behn. 8 | * Lab: Produce a stopwatch app using the Behn API. 9 | 10 | 11 | ## “A Horse, A Horse, My Kingdom for a Horse!” 12 | 13 | Behn is simple. Behn is a timer. Yes, an entire vane for a timer. 14 | 15 | > Behn … allows vanes and applications to set and timer events, which are managed in a simple priority queue. 16 | 17 | Behn is not the most critical vane (in a sense), but it is the smallest vane and thus a really good example to figure out what constitutes a vane. Behn has to deal with state a lot, clearly. 18 | 19 | > It allows vanes and applications to set and timer events, which are managed in a simple priority queue. `%behn` produces effects to start the unix timer, and when the requested `%behn` passes, Unix sends wake events to %behn, which time routes back to original sender. We don't guarantee that a timer event will happen at exactly the `%behn` it was set for, or even that it'll be particularly close. A timer event is a request to not be woken until after the given time. 20 | 21 | 22 | ## Vane Arms 23 | 24 | Behn exposes five arms to call from Arvo: 25 | 26 | ```hoon 27 | |% 28 | ++ call :: handle a +task:able:behn request 29 | ++ load :: migrate an old state to a new behn version 30 | ++ scry :: view timer state 31 | ++ stay :: return state 32 | ++ take :: produce a `%wake` event (only Behn gift) 33 | ``` 34 | 35 | `++call` talks to the `event-core` core which initiates a wait. Each call requires a token, which may be one of the following: 36 | 37 | ```hoon 38 | %wait :: set a new timer and adjust unix wakeup 39 | %wake :: wake up after corresponding event 40 | %huck :: give back immediately 41 | %born :: urbit restarted; refresh then store wakeup timer duct 42 | %rest :: cancel the timer and adjust unix wakeup 43 | ``` 44 | 45 | (There are a few more which deal with failures, kernel upgrades, etc.) 46 | 47 | It is instructive to see how `++wait` works. The entire arm is a single gate: 48 | 49 | ```hoon 50 | ++ wait |=(date=@da set-unix-wake(timers.state (set-timer [date duct]))) 51 | ``` 52 | 53 | Let's refactor that to make it clearer to scan: 54 | 55 | ```hoon 56 | ++ wait 57 | |= [date=@da] 58 | =/ timer-value (set-timer [date duct]) 59 | set-unix-wake(timers.state timer-value) 60 | ``` 61 | 62 | `++set-timer` is the arm which adds a timer to Behn's state. `++set-unix-wait` then monitors the list of Unix wakeup timers. 63 | 64 | A Gall call to `%behn` looks like this: 65 | 66 | ```hoon 67 | [%pass /egg-timer %arvo %b %wait (add now.bowl t)]~ 68 | ``` 69 | 70 | This call consists of a `%pass` token, a `wire` source address, messaged to `%arvo`'s `%b` (Behn) vane at the `%wait` arm with appropriate noun. The move proper will be more concise: recall `[cause effect]`, er, `[bone card]`; thus, `[/egg-timer [%wait time]]` or similar. 71 | 72 | Behn is used commonly in the kernel to maintain the system state, in particular in Clay: 73 | 74 | > `%eyre` uses `%behn` for timing out sessions, and `%clay` uses `%behn` for keeping track of time-specified file requests. 75 | 76 | - Reading: [Tlon Corporation, "Behn Tutorial"](https://urbit.org/docs/hoon/hoon-school/behn/) 77 | - Reading: [`behn.hoon`](https://github.com/urbit/urbit/blob/master/pkg/arvo/sys/vane/behn.hoon) 78 | 79 | ![](../img/21-mccall-1.png) 80 | 81 | _All art by Robert McCall._ 82 | 83 | 84 | # Questions 85 | 86 | ## A Minimalist Gall App 87 | 88 | Return again to the [`egg-timer` app tutorial](https://urbit.org/docs/hoon/hoon-school/egg-timer/). 89 | 90 | You may start the Gall app using `|start %egg-timer` and poke it using a relative time such as `:egg-timer ~s10`. 91 | 92 | Modify the app so that instead of printing a simple `~&` message when the timer goes off, it outputs a timestamp (in absolute time) of the current time, either as `@da` or as a `date` (see [`++yore`](https://urbit.org/docs/reference/library/3c/#yore)). 93 | -------------------------------------------------------------------------------- /lessons/lesson23-polymorphism.md: -------------------------------------------------------------------------------- 1 | # Polymorphism 2 | 3 | ![](../img/23-header-mccall-0.png) 4 | 5 | ## Learning Objectives 6 | 7 | - Distinguish wet and dry cores. 8 | - Apply type constructor arms. 9 | 10 | 11 | ## Wet Gates 12 | 13 | ![](../img/23-header-mccall-1.png) 14 | 15 | > With a dry gate, when you pass in an argument and the code gets compiled, the type system will try to cast to the type specified by the gate; if you pass something that does not fit in the specified type, for example a `cord` instead of a `cell` you will get a nest failure. On the other hand, when you pass arguments to a wet gate, their types are preserved and type analysis is done at the definition site of the gate—in our case, fold in `hoon.hoon`—rather than the call site. 16 | 17 | - Dry gate = type analysis at the call site 18 | - Wet gate = type analysis at the gate definition 19 | 20 | Wet gates are more general than dry gates: you can use a wet gate anywhere a dry gate would work. Wet gates are created with [`|*` bartar](https://urbit.org/docs/reference/hoon-expressions/rune/bar/#bartar). Wet gates behave more like a C-style macro because the argument isn't converted into the sample type but directly present. 21 | 22 | ```hoon 23 | > =dry |=([a=* b=*] [b a]) 24 | > =wet |*([a=* b=*] [b a]) 25 | > (dry .~1.0 .~~~1.0) 26 | [85.065.399.433.376.081.038.215.121.361.612.832.768 4.607.182.418.800.017.408] 27 | > (wet .~1.0 .~~~1.0) 28 | [.~~~1 .~1] 29 | ``` 30 | 31 | > It is good practice to include a cast in all gates, even wet gates. But in many cases the desired output type depends on the input type. How can we cast appropriately? Often we can cast by example, using the input values themselves. (`^+`) 32 | 33 | Thus for gates. More generally, what about cores? First, a definition of the `core` type: 34 | 35 | ```hoon 36 | [$core p=type q=coil] 37 | +$ coil 38 | $: 39 | p=[p=(unit term) q=?(%wet %dry) r=?($gold $iron $lead $zinc)] 40 | q=type 41 | r=[p=seminoun q=(map term (pair what (map term hoon))] 42 | ``` 43 | 44 | (We'll discuss the `+$` lusbuc runes below.) 45 | 46 | > The full core stores both payload types. The type that describes the payload currently in the core is `p`. The type that describes the payload the core was compiled with is `q.q`. 47 | 48 | Many functional tools like [`++turn`](https://urbit.org/docs/reference/library/2b/#turn) and [`++rep:by`](https://urbit.org/docs/reference/library/2i/#rep-by) frequently require wet gates in order to yield the intended effect. 49 | 50 | Now for dry cores: 51 | 52 | > Dry polymorphism works by substituting cores. Typically, the the programmer uses one core as an interface definition, then replaces it with another core which does something useful. 53 | 54 | In contrast, for wet cores[:](https://en.wikipedia.org/wiki/%C3%96rt%C3%B6%C3%B6) 55 | 56 | > For a wet arm, we ask: "suppose this core was actually compiled using `p` instead of `q.q`?" Would the Nock formula we generated for q.q actually work for a `p` payload? … We don't actually recompile the arm at runtime. We actually run the formula generated for the original payload, `q.q`. 57 | 58 | As a consequence, wet arms and wet cores behave a bit like C++ overloaded operators and templates or Haskell typeclasses. There aren't fully different implementations though (as in C++ overloading), though, so there's not a way to (for instance) just make `++add` and `++add:rs` compatible. (The "Lead Polymorphism" tutorial is very important in this regard.) 59 | 60 | One thing to watch is that `|%` barcen produces dry cores, thus dry arms. To produce a wet core, you need to use [`|@` barpat](https://urbit.org/docs/reference/hoon-expressions/rune/bar/#barpat) instead. 61 | 62 | - Reading: [Tlon Corporation, "Advanced Types"](https://urbit.org/docs/reference/hoon-expressions/advanced/) 63 | - Reading: [Tlon Corporation, "Iron Polymorphism"](https://urbit.org/docs/hoon/hoon-school/iron-polymorphism/) 64 | - Reading: [Tlon Corporation, "Lead Polymorphism"](https://urbit.org/docs/hoon/hoon-school/lead-polymorphism/) 65 | 66 | 67 | ## Type Constructors 68 | 69 | ![](../img/23-header-mccall-2.png) 70 | 71 | Gall apps frequently require type definitions, customarily located in a `|%` barcen core before the `|_` barcab door. Frequently these are defined and validated using type constructor arms. 72 | 73 | [`+$` lusbuc](https://urbit.org/docs/reference/hoon-expressions/rune/lus/#lusbuc) is a type constructor arm. It defines a custom type for use by the other arms in the core. It is sometimes used with the [`$%` buccen](https://urbit.org/docs/reference/hoon-expressions/rune/buc/#buccen) union definition rune (irregular form `?(%foo %bar)`). 74 | 75 | Let's imagine a Pokémon type. We'll use a simple model of Pokémon with uniform capabilities by species (evolution, kind, whatever) but per-instance attributes for hit points, attack, etc. 76 | 77 | ```hoon 78 | +$ pokemon 79 | $% id=@uw :: unique hash 80 | name=tape :: name of pokemon 81 | kind=species :: kind of pokemon 82 | hp=@ud :: current health 83 | max-hp=@ud :: normal maximum health 84 | attack=@ud :: attack 85 | defense=@ud :: defense 86 | speed=@ud :: speed 87 | == 88 | +$ species 89 | $% name=%tas :: pokemon species name as tag 90 | type=(set type) :: pokemon types 91 | moves=(set move) :: species-specific abilities 92 | == 93 | ``` 94 | 95 | We need to know what a `species` is, what a `type` is, and what an `move` is. Clearly these are limited to be chosen from a particular set of options. For instance, here is a `type` definition (in the Pokémon type sense): 96 | 97 | ```hoon 98 | +$ type ?(%bug %dragon %ice %fighting %fire %flying %grass %ghost %ground %electric %normal %poison %psychic %rock %water) 99 | ``` 100 | 101 | Now, we have a bit of a problem, which is that these types really aren't disjoint. That is, a Pokémon may have more than one of them. So _really_ what we want isn't a _type_ in the Hoon sense, but a `set` of tags. ("`$?` should only be used on types that are disjoint, i.e., which have no values in common.") The same goes for `move`. 102 | 103 | `+$` is a type constructor arm, so it doesn't make sense to define a particular `pokemon` until one has already defined a `species`, which needs `type` (as above) and `move`: 104 | 105 | ```hoon 106 | +$ type ?(%bug %dragon %ice %fighting %fire %flying %grass %ghost %ground %electric %normal %poison %psychic %rock %water) 107 | +$ move ?(%barrage %bite %bind %body-slam %comet-punch %constrict %conversion %cut %crunch %disable %dizzy-punch %double-team %growl) 108 | =/ eevee [%eevee `(set @tas)`(sy `(list @tas)`~[%normal]) `(set @tas)`(sy `(list @tas)`~[%growl %body-slam])] 109 | ``` 110 | 111 | (More realistically, we would load these from a configuration file like a JSON. We leave that exercise to the reader for the time being.) 112 | 113 | Now we're ready to build a unique Pokémon instance: 114 | 115 | ```hoon 116 | =/ unique-hash `@uw`(~(raw og eny) 60) 117 | =/ eevee-1 [unique-hash "Eevee" eevee 55 55 55 50 55] 118 | ``` 119 | 120 | [Here is a full implementation of the above as a single generator.](../resources/pokemon.hoon) 121 | 122 | - Reading: [Tlon Corporation, "Structures and Complex Types"](https://urbit.org/docs/hoon/hoon-school/structures-and-complex-types/) 123 | - Reading: [Tlon Corporation, "Type Polymorphism"](https://urbit.org/docs/hoon/hoon-school/type-polymorphism/) 124 | 125 | _All art by Robert McCall._ 126 | 127 | 128 | # Questions 129 | 130 | ## The Trapezoid Rule 131 | 132 | The [trapezoid rule](https://en.wikipedia.org/wiki/Trapezoidal_rule) solves a definite integral. It approximates the area under the curve by a trapezoid or (commonly) a series of trapezoids. 133 | 134 | ![](https://upload.wikimedia.org/wikipedia/commons/thumb/d/d1/Integration_num_trapezes_notation.svg/573px-Integration_num_trapezes_notation.svg.png) 135 | 136 | $$ 137 | \int_a^b f(x) \, dx 138 | \approx 139 | \sum_{k=1}^N \frac{f(x_{k-1}) + f(x_k)}{2} \Delta x_k 140 | = 141 | \tfrac{\Delta x}{2}\left(f(x_0) + 2f(x_1)+2f(x_2)+ 2f(x_3)+2f(x_4)+\cdots+2f(x_{N-1}) + f(x_N)\right) 142 | $$ 143 | 144 | Produce a trapezoid-rule integrator which accepts a wet gate (function of a single variable) and a list of points and yields the integral as a floating-point value (`@rs` or `@rd`). This tool should be a library. You may use the Dojo or a generator to apply it. 145 | 146 | Submit your library as a file `trapezint.hoon`. 147 | -------------------------------------------------------------------------------- /lessons/lesson24-foundation.md: -------------------------------------------------------------------------------- 1 | # Urbit Foundation 2 | 3 | ![](../img/24-header.png) 4 | 5 | ## Learning Objectives 6 | 7 | - Describe the current and prospective Urbit ecosystem. 8 | 9 | 10 | ## The Urbit Developer and User Ecosystem 11 | 12 | Urbit is currently primarily developed by the [Tlon Corporation](https://tlon.io), founded by Curtis Yarvin, Galen Wolfe-Pauly, and John Burnham in 2013. 13 | 14 | At least one other company works full-time on Urbit projects, [urbit.live](https://urbit.live), which facilitates Urbit property transfers. 15 | 16 | The plan was always to roll out a foundation to manage the Urbit community and development, much like the [Linux Foundation](https://en.wikipedia.org/wiki/Linux_Foundation). A similar model crops up in several open-source projects, such as the [Apache Foundation](). (There are also financial entities like [NumFocus](https://numfocus.org/) which provided clerical support but not administration for FOSS projects.) 17 | 18 | Foundations are useful for providing a legal vehicle to manage operations, payments, taxes, and time. Not all open-source projects end up with foundations: many are too small to worry about it, and others are sponsored by corporations or university research groups. 19 | 20 | The vision for the Urbit Foundation (colloquially; formally `urbit.org`) has evolved over time. For a while it was going to be a classical software foundation, then the Urbit Education Foundation, and now it's considered `urbit.org` or the Urbit Foundation: 21 | 22 | > Urbit is meant to be universal, ubiquitous infrastructure. Tlon exists to make that infrastructure useful and usable. We expect Urbit, as a platform, to be cared for by the community in collaboration with the emerging Urbit Foundation. We intend Tlon to become increasingly focussed on providing a great user experience for anyone interested in this new network, so the network can continue to grow and thrive. 23 | 24 | The Urbit Foundation was actually launched in August 2020, so it's now a real, slowly mitosizing organization. 25 | 26 | The Urbit Foundation is primarily concerned, at this point, with promoting the development of Urbit as a platform with the [grants and bounties program](https://grants.urbit.org/). 27 | 28 | Ultimately there is intended to be a board for the Urbit Foundation which will administer the corresponding galaxies for network infrastructure and governance votes. 29 | 30 | - Reading: [Josh Lehman `~wolref-podlex`, "First Steps Towards `urbit.org`"](https://urbit.org/blog/first-steps-towards-urbit-org/) 31 | - Optional Reading: [Stephen Walli, "The Role of FOSS Foundations"](https://www.networkworld.com/article/2221186/the-role-of-foss-foundations.html) 32 | - Optional Reading: [Erik Newton `~patnes-rigtyn`, "Governance of `urbit.org`"](https://urbit.org/blog/governance-of-urbit/) 33 | -------------------------------------------------------------------------------- /lessons/lesson25-gall-2.md: -------------------------------------------------------------------------------- 1 | # Gall II 2 | 3 | ![](../img/25-header-orion-0.png){: width=100%} 4 | 5 | ## Learning Objectives 6 | 7 | - Manage internal Gall state. 8 | - Explain scrying. 9 | * Produce an intermediate Gall app. 10 | 11 | 12 | ## Managing State 13 | 14 | ![](../img/25-header-orion-1.png){: width=100%} 15 | 16 | Basically everything we have done so far has relied on rebuilding the subject to produce a desired result. Gall apps may have long-deferred calculations, however, and it is infeasible to run apps asynchronously the same way one does with a quick computation. 17 | 18 | ### State 19 | 20 | ![](../img/25-header-orion-2.png){: width=100%} 21 | 22 | Each Gall agent (“app”) maintains a current state. One of the most common return types for Gall app arms is `(quip card _this)` or `(quip card _state)`. A [`++quip`](https://urbit.org/docs/reference/library/1c/#quip) is a tuple of `list` and mold, where we have a list of cards and the mold of the current state. This means that the arm intends to return cards (moves, events) and the changed state of the app. 23 | 24 | It's worth noting that a common convention in modern Gall programs is to define a face `this` for the current agent: 25 | 26 | ```hoon 27 | +* this . 28 | def ~(. (default-agent this %|) bowl) 29 | ``` 30 | 31 | so you'll see `(quip card _this)` more frequently. 32 | 33 | The program has two pieces of state. One is of mold `bowl:gall` (in fact, the agent is a door `|_ =bowl:gall`). A `bowl` is defined in `%zuse`: 34 | 35 | ```hoon 36 | ++ bowl :: standard app state 37 | $: $: our=ship :: host 38 | src=ship :: guest 39 | dap=term :: agent 40 | == :: 41 | $: wex=boat :: outgoing subscriptions 42 | sup=bitt :: incoming subs 43 | == :: 44 | $: act=@ud :: change number 45 | eny=@uvJ :: entropy 46 | now=@da :: current time 47 | byk=beak :: load source 48 | == == 49 | ``` 50 | 51 | An app may also maintain internal state. One idiom for updating this state is to use the [`%=` centis](https://urbit.org/docs/reference/hoon-expressions/rune/cen/#centis) rune's irregular form. (We've been doing this all along with `$()`.) 52 | 53 | ```hoon 54 | :: Delete a chat message 55 | state(inbox (~(del by inbox) path.action)) 56 | ``` 57 | 58 | Another option is to use a delayed monadic binding, as demonstrated below. 59 | 60 | Many Gall apps are now intended to use [`graph-store`](https://github.com/urbit/urbit/pull/3110), a backend data storage format and database that both provides internally consistent data and external API communications endpoints. (This is new as of summer 2020.) 61 | 62 | `graph-store` handles data access perms at the hook level, not at the store level. 63 | 64 | Ultimately, all the existing Tlon-supported apps will be migrated to `graph-store`. Here is [an example](https://gist.github.com/matildepark/268c758c079d6cf83fd1541b2430ff7f) showing the difference between the old JSON format and the new JSON `graph-store` format. 65 | 66 | - Reading: [Tlon Corporation, "Gall Tutorial"](https://urbit.org/docs/reference/vane-apis/gall/) 67 | - Optional Reading: [Logan Allen `~tacryt-socryp`, "Graph Store Proposal"](https://docs.google.com/document/d/1-Gwfg442kV3cdfG7NnWPEf2TMa3uLUTAKkZD70ALZkE/edit) 68 | 69 | ### Monads 70 | 71 | ![](../img/25-header-orion-3.png){: width=100%} 72 | 73 | Functional programming languages and platforms prefer pure functions, meaning that these functions don't emit effects. Hoon cheats a little bit with `~&` sigpam for output, but in general is quite functional-as-in-language. Many functional languages introduce the [_monad_](https://en.wikipedia.org/wiki/Monad_%28functional_programming%29) as a way of tracking state (including input/output): 74 | 75 | > A state monad allows a programmer to attach state information of any type to a calculation. Given any value type, the corresponding type in the state monad is a function which accepts a state, then outputs a new state along with a return value. 76 | 77 | Hoon provides three monad/monad-adjacent runes for producing pipelines of computations: 78 | 79 | - [`=^` tisket](https://urbit.org/docs/reference/hoon-expressions/rune/tis/#tisket) is used to chain state from a result back into the state machine 80 | - [`;~` micsig](https://urbit.org/docs/reference/hoon-expressions/rune/mic/#micsig) is used to glue a pipeline together (that is, there is internal state of the functions and results which is retained by the structure) 81 | - `;<` micgal similarly glues a pipeline together (as a monadic bind) (this rune is undocumented at the current time); in other words, run an asynchronous function or event 82 | 83 | (These are not used in every Gall app, but they can be helpful when deferring parts of a computation based on external data.) 84 | 85 | For instance, here is a `;<` pipeline: 86 | 87 | ```hoon 88 | ;< =state bind:m (handle-poke %noun 'fetch') 89 | ``` 90 | 91 | A generic `;<` pipeline 92 | 93 | ```hoon 94 | ;< a=@ bind:m c d 95 | ``` 96 | 97 | means to run `c` giving an output of type `a` and pass it to `d`. 98 | 99 | Here, the `state` is an app-local structure (defined with `+$`); `m` is a `tapp-async` thread with a `++bind` arm to a `strand` (Arvo thread). 100 | 101 | `grep` the Urbit source code for examples of these three runes in use. 102 | 103 | - Reading: [`~timluc-miptev`, "The Complete Guide to Gall"](https://github.com/timlucmiptev/gall-guide/blob/master/overview.md) (this will be part of your exercises today) 104 | - Optional Reading: [Logan Allen, Matt, Matilde Park `~haddef-sigwen`, "Userspace Architecture"](https://docs.google.com/document/d/1hS_UuResG1S4j49_H-aSshoTOROKBnGoJAaRgOipf54/edit) 105 | 106 | ### Scrying 107 | 108 | ![](../img/25-header-orion-4.png){: width=100%} 109 | 110 | One of the key operations in Gall (and Clay) is _scrying_ (`++on-peek` handler). To scry is to request data from anywhere in the global immutable namespace. A scry produces a `(unit (unit cage))` (recall that a `unit` lets us distinguish empty/missing data from zero data). 111 | 112 | Scrying is accomplished with the [`.^` dotket](https://urbit.org/docs/reference/hoon-expressions/rune/dot/#dotket) rune. This accepts a mold (to cast the response), a tag (like `%cx`, as you saw with Clay), and a noun (the path to query). Basically, think of a `.^` scry as a way of finding out things that aren't in your subject. 113 | 114 | Check the [reference agent Gall example](https://urbit.org/docs/reference/vane-apis/gall/) for a good example of how scrying works in the `++on-peek` arm. 115 | 116 | ```hoon 117 | ++ on-peek 118 | |= =path 119 | ^- (unit (unit cage)) 120 | ?+ path [~ ~] 121 | [%x %local ~] :: local counter request 122 | ``[%atom !>(local)] :: produce local counter 123 | [%x %remote who=@ta ~] :: remote counter request 124 | =* location i.t.t.path 125 | =/ res (~(got by remote) (slav %p location)) 126 | ``[%atom !>(res)] :: produce remote counter 127 | [%y %remote ~] :: list of remote counters request 128 | =/ dir=(map @ta ~) 129 | %- molt %+ turn ~(tap by remote) 130 | |= [who=@p *] [(scot %p who) ~] 131 | ``[%arch !>(`arch`[~ dir])] :: produce list of remote counters 132 | == 133 | ``` 134 | 135 | ([`?+` wutlus](https://urbit.org/docs/reference/hoon-expressions/rune/wut/#wutlus) is a `switch` statement.) 136 | 137 | This would be used in the following ways: 138 | 139 | ```hoon 140 | .^(@ %gx /=example-gall=/local/atom) :: produce local counter 141 | .^(@ %gx /=example-gall=/remote/~zod/atom) :: produce counter for ~zod 142 | .^(arch %gy /=example-gall=/remote) :: produce current list 143 | ``` 144 | 145 | To access data on a remote ship, you can't just scry. What you actually do is to subscribe to data, and when the remote agent updates, it will send the information to subscribers. 146 | 147 | ![](../img/25-header-orion-5.png){: width=100%} 148 | -------------------------------------------------------------------------------- /lessons/lesson26-gall-3-landscape.md: -------------------------------------------------------------------------------- 1 | # Gall III: Landscape 2 | 3 | ![](../img/26-header-nebula-0.png){: width=100%} 4 | 5 | ## Learning Objectives 6 | 7 | - Understand how static Gall instruments a Landscape tile. 8 | * Lab: Produce a basic Landscape tile. 9 | 10 | 11 | ## Landscape 12 | 13 | Landscape is a browser-facing Gall agent and its concomitant Javascript components. As a platform, it is among the more complex components of userspace. 14 | 15 | > Landscape is a graphical web interface for your ship. Right now, Landscape allows for social networking functions, such as participating in IRC-like chats, subscribing to forum-like pages of other ships, and messaging other ships directly. It also has weather and clock apps. Landscape is an alternative messaging interface to the command-line app Chat. 16 | 17 | Landscape is a proof of concept for a world beyond the command line. It has since become the primary interface for many, probably most, users. 18 | 19 | ![](https://media.urbit.org/site/posts/essays/landscape-a-portrait-1.png){: width=100%} 20 | 21 | _The 2019 Landscape landing page._ 22 | 23 | ![](https://blog.vaexperience.com/wp-content/uploads/2020/03/urbit-os.png){: width=100%} 24 | 25 | _The 2020 OS1 Landscape landing page._ 26 | 27 | - Optional Reading: [Matilde Park `~haddef-sigwen`, "Landscape: A Portrait"](https://urbit.org/blog/landscape-a-portrait/) 28 | - Optional Reading: [Galen Wolfe-Pauly `~ravmel-ropdyl`, "The State of Landscape"](https://urbit.org/blog/the-state-of-landscape/) 29 | 30 | ### Examples 31 | 32 | Besides the built-in agents like Chat and Publish, there have been a number of community contributions recently: 33 | 34 | - [Jose `~norsyr-torryn` (`yosoyubik`), `canvas` Group Drawing App](https://github.com/yosoyubik/canvas) 35 | - [Luke Champine `~watter-parter`, `rote` Flashcard App](https://github.com/lukechampine/rote), particularly [the line-by-line explanation](https://github.com/lukechampine/rote/blob/master/urbit/app/rote.hoon) 36 | - [`~littel-wolfur`, `srrs` Spaced Repetition Repetition System](https://github.com/ryjm/srrs) 37 | - [Pyry Kovanen `~dinleb-rambep`, Books](https://github.com/pkova/urbit/tree/books/pkg/interface/books) 38 | - [John Franklin `~dirwex-dosrev`, Notes](https://github.com/jfranklin9000/notes/) 39 | 40 | ### Operations 41 | 42 | Landscape uses a React-derived [Indigo](https://github.com/urbit/indigo-react) framework front-end. (This implements [Tlon's design language](https://www.figma.com/community/file/822953707012850361).) 43 | 44 | You'll have something like the following file structure when building a Landscape app: 45 | 46 | ```bash 47 | . 48 | ├── app 49 | │   ├── myapp.hoon 50 | │   └── myapp 51 | │      ├── css 52 | │      │   └── index.css 53 | │      ├── index.html 54 | │      └── js 55 | │      ├── index.js 56 | │      └── tile.js 57 | ├── lib 58 | │   └── myapp.hoon 59 | ├── sur 60 | |   └── myapp.hoon 61 | └── tests 62 |    └── myapp.hoon 63 | ``` 64 | 65 | depending on which components you need to implement. 66 | 67 | Since React is a JS framework, it will generate a lot of the necessary code already and you won't have to do very much JS programming to get things to work. For instance, the entire `index.js` file could look like this: 68 | 69 | ```js 70 | import React from 'react'; 71 | import ReactDOM from 'react-dom'; 72 | import { Root } from './js/components/root.js'; 73 | import { api } from './js/api.js'; 74 | import { subscription } from "./js/subscription.js"; 75 | 76 | import './css/indigo-static.css'; 77 | import './css/fonts.css'; 78 | import './css/custom.css'; 79 | 80 | api.setAuthTokens({ 81 | ship: window.ship 82 | }); 83 | 84 | window.urb = new window.channel(); 85 | 86 | subscription.start(); 87 | 88 | ReactDOM.render(( 89 | 90 | ), document.querySelectorAll("#root")[0]); 91 | ``` 92 | 93 | An event handler in your JS code could look like this: 94 | 95 | ```js 96 | api.action('myapp', 'json', {myvalue: Number(this.state.value)}); 97 | ``` 98 | 99 | and the state could be referred to as 100 | 101 | ```js 102 |

{this.props.data.myvalue}

103 | ``` 104 | 105 | If you work on Landscape apps, you'll need to make decisions regarding which parts of the state and logic should live in Gall and which in the browser. Since you don't need to handle authentication and you have a database ready to hand, you also don't need to worry so much about storing session data like cookies. 106 | 107 | So what's going on with all this Javascript? Gall (Urbit in general, in fact) doesn't know about Javascript or your browser. You can interact with your ship through certain formalized processes though. In essence, JS is creating moves that get passed to Arvo/Gall the same way that other moves get handled internally. The only difference is the outside world (other ship v. browser client). 108 | -------------------------------------------------------------------------------- /lessons/lesson29-gall-4-communication.md: -------------------------------------------------------------------------------- 1 | # Gall IV 2 | 3 | ![](../img/29-header-cyberpunk-0.png){: width=100%} 4 | 5 | ## Learning Objectives 6 | 7 | - Understand how static Gall retrieves data. 8 | - Explain the role of imps as transient threads in Arvo. 9 | 10 | 11 | ## “The Gall of It All” 12 | 13 | ![](../img/29-header-cyberpunk-2.png){: width=100%} 14 | 15 | Let's take one last wistful look into `%gall`. As with other vanes, it lives split between [`gall.hoon`](https://github.com/urbit/urbit/blob/master/pkg/arvo/sys/vane/gall.hoon) and [`zuse.hoon`](https://github.com/urbit/urbit/blob/master/pkg/arvo/sys/zuse.hoon). 16 | 17 | What I'd like to particularly examine at this point is how Gall communicates with webpages. This primarily takes place today via Landscape, but there's nothing in Gall that ties it to Landscape specifically: it's just one more agent. 18 | 19 | A Gall agent and a webpage communicate via a `++channel`. `PUT` requests along a path represent subscriptions and pokes, while `GET` requests represent event sources. 20 | 21 | ```hoon 22 | +$ channel 23 | $: :: channel-state: the duct currently listening 24 | state=(each timer duct) 25 | :: next-id: next sequence number to use 26 | next-id=@ud 27 | :: events: unacknowledged events 28 | events=(qeu [id=@ud lines=wall]) 29 | :: subscriptions: gall subscriptions 30 | subscriptions=(map wire [ship=@p app=term =path duc=duct]) 31 | :: heartbeat: sse heartbeat timer 32 | heartbeat=(unit timer) 33 | == 34 | ``` 35 | 36 | I've elided `%heartbeat` in our previous looks at Gall, but they're worth mentioning: a `%heartbeat` is a periodic timer to check on a duct or channel. `%eyre` and `%gall` are the primary consumers of `%heartbeat`s since they use them to check on webpage or agent state. For instance, here is `%eyre`'s channel timeout arm: 37 | 38 | ```hoon 39 | ++ set-timeout-move 40 | |= [channel-id=@t expiration-time=@da] 41 | ^- move 42 | [duct %pass /channel/timeout/[channel-id] %b %wait expiration-time] 43 | ``` 44 | 45 | (This is uncharacteristically straightforward; it always makes me jumpy when the names make sense in Arvo!) 46 | 47 | 48 | ## A Deep Dive into `weather.hoon` 49 | 50 | ![](../img/29-header-cyberpunk-1.png){: width=100%} 51 | 52 | Let's take an annotated look at the `weather.hoon` Landscape app. This app needs to do three things: retain state (location); pull weather data; and pass information to subscribers (the Javascript-based Landscape tile). 53 | 54 | ```hoon 55 | /+ *server, default-agent, verb, dbug 56 | =, format 57 | ``` 58 | 59 | The app will use the following libraries: 60 | 61 | - `server`, which provides helpful handlers for handling MIME data, authorization, URL parsing, and the like 62 | - `default-agent`, which wraps your agent with crash information 63 | - `verb`, which wraps your agent with logging 64 | - `dbug`, which wraps your agent with debugging tools 65 | 66 | The `format` namespace is exposed for the `%zuse` format parsers to be more readily available. 67 | 68 | ```hoon 69 | |% 70 | :: 71 | +$ card card:agent:gall 72 | +$ versioned-state 73 | $% state-zero 74 | == 75 | +$ state-zero [%0 data=json time=@da location=@t timer=(unit @da)] 76 | -- 77 | =| state-zero 78 | =* state - 79 | %+ verb | 80 | %- agent:dbug 81 | ^- agent:gall 82 | ``` 83 | 84 | The main core has standard boilerplate: `+$card` is aliased, the versioned state is provisioned, and the wrappers imported earlier are set up. This is followed by a `=<` tisgal which reverses the order of the following two daughter branches, so let's look at the auxiliary tools first: 85 | 86 | ```hoon 87 | |_ bol=bowl:gall 88 | ++ poke-json 89 | ++ request-darksky 90 | ++ http-response 91 | ++ wake 92 | -- 93 | ``` 94 | 95 | - `++poke-json` requests weather information and initiates a heartbeat 96 | - `++request-darksky` builds and issues a `GET` request to the DarkSky API for weather information; this will return a JSON 97 | - `++http-response` parses the JSON weather information into state 98 | - `++wake` is the heartbeat vane used to check on the current request status 99 | 100 | It is worth your while to read each of these carefully. 101 | 102 | The main agent core has the following arrangement: 103 | 104 | ```hoon 105 | |_ bol=bowl:gall 106 | +* this . 107 | weather-core +> 108 | wc ~(. weather-core bol) 109 | def ~(. (default-agent this %|) bol) 110 | ++ on-init [~ this] 111 | ++ on-save !>(state) 112 | ++ on-load 113 | ++ on-poke 114 | ++ on-watch 115 | ++ on-arvo 116 | ++ on-leave on-leave:def 117 | ++ on-peek on-peek:def 118 | ++ on-agent on-agent:def 119 | ++ on-fail on-fail:def 120 | -- 121 | ``` 122 | 123 | As you can see, there are some aliases for commonly used but abstruse locations in the subject, followed by “sufficiently interesting” code in four arms. Note especially how `weather-core` is defined and referred to subsequently; this is a very helpful style for complex agents, particularly if they shadow names. 124 | 125 | - `++on-load` binds the `~weather` endpoint to the current agent via Eyre 126 | - `++on-poke` triggers the JSON handler `++poke-json` 127 | - `++on-watch` responds to subscription requests 128 | - `++on-arvo` handles responses made to Eyre (to bind); to Iris (with information on the HTTP request); or to wake the agent. 129 | 130 | 131 | ## Spiders and Imps 132 | 133 | ![](../img/29-header-cyberpunk-3.png){: width=100%} 134 | 135 | At the bottom of our conceptual map of Arvo and userspace sat the transient daemons that instrument certain agents, known as imps. 136 | 137 | 1. “Runtime (Nock interpreter, persistence engine, IO drivers, jets) 138 | 2. “Kernel vanes (managed by Arvo) 139 | 3. “Userspace agents (managed by Gall, permanent state) 140 | 4. “Userspace imps (managed by Spider, transient state)” 141 | 142 | The `spider` structure can be shown briefly in full: 143 | 144 | ```hoon 145 | /+ libstrand=strand 146 | =, strand=strand:libstrand 147 | |% 148 | +$ thread $-(vase _*form:(strand ,vase)) 149 | +$ input [=tid =cage] 150 | +$ tid tid:strand 151 | +$ bowl bowl:strand 152 | +$ http-error 153 | $? %bad-request :: 400 154 | %forbidden :: 403 155 | %nonexistent :: 404 156 | %offline :: 504 157 | == 158 | -- 159 | ``` 160 | 161 | These are interfaces to track the evolution of particular strands. A strand is an asynchronous transaction monad: 162 | 163 | ```hoon 164 | ++ strand 165 | |% 166 | :: Output of strand computation 167 | ++ output (strand-output-raw a) 168 | :: Type of strand computation 169 | ++ form (strand-form-raw a) 170 | :: Monadic pure: identity computation for bind 171 | ++ pure 172 | :: Monadic bind. Combines two computations, associatively. 173 | ++ bind 174 | :: Take a new sign and evaluate the strand against it 175 | ++ eval 176 | -- 177 | ``` 178 | 179 | Now we are closer to the heart of what our transient threads are doing: they are async monads to let us progressively update the state of a computation based on periodically checking process status. 180 | 181 | A common pattern in Arvo is to have a user-facing generator or Gall agent which spins up transient imps for each call. Consider, for instance, `|hi`: 182 | 183 | `gen/hi.hoon`: 184 | 185 | ```hoon 186 | /? 310 187 | :- %say 188 | |=({^ {who/ship mez/$@(~ {a/tape ~})} ~} helm-send-hi+[who ?~(mez ~ `a.mez)]) 189 | ``` 190 | 191 | `gen/helm.hoon`: 192 | 193 | ```hoon 194 | :: this token comes in 195 | %helm-send-hi =;(f (f !<(_+<.f vase)) poke-send-hi) 196 | :: which passes through a number of arms to eventually land at 197 | ``` 198 | 199 | `ted/hi.hoon`: 200 | 201 | ```hoon 202 | /- spider 203 | /+ strandio 204 | =, strand=strand:spider 205 | ^- thread:spider 206 | |= arg=vase 207 | =/ m (strand ,vase) 208 | ^- form:m 209 | =+ !<([who=ship mez=$@(~ [=tape ~])] arg) 210 | =/ message ?~(mez '' (crip tape.mez)) 211 | ;< ~ bind:m (poke:strandio [who %hood] %helm-hi !>(message)) 212 | (pure:m !>("hi {} successful")) 213 | ``` 214 | 215 | You can see many more examples of the transient imp processes in `ted/`. 216 | 217 | Any time you are dispatching multiple processes which have to wait on asynchronous calculations, it's worth considering setting up Spider. 218 | 219 | - Optional Reading: [Tlon Corporation, "Move Traces"](https://urbit.org/docs/tutorials/arvo/move-trace/) 220 | 221 | ![](../img/29-header-cyberpunk-4.png){: width=100%} 222 | -------------------------------------------------------------------------------- /lessons/lesson31-cli.md: -------------------------------------------------------------------------------- 1 | # Command-Line Interface 2 | 3 | ![](../img/31-header-phobos-0.png){: width=100%} 4 | 5 | ## Learning Objectives 6 | 7 | - Diagram how `%dill` instruments terminal events. 8 | - Produce a command-line interface app using `sole` and `shoe`. 9 | 10 | Urbit traffics only in events. Every occurrence or action in any part of the system must become an event to be legible to Arvo. A command-line interface is conventionally a text user interface (TUI) (although not all TUIs are CLIs and vice versa). 11 | 12 | A command line like Dojo is useful for instrumenting and interacting with agents interactively. A long-running agent or a graphical interface (like Landscape) is preferred for more complex or alternatively more asynchronous interactions. 13 | 14 | `%dojo` is the main interface for the command-line user; since all events are well-formed Hoonish, if you know an agent's interface you can always accomplish anything on a ship in Dojo that you can do through Landscape. (The trick, of course, is knowing the arcana, which at this point in history frequently requires recourse to [GitHub issues](https://github.com/urbit/urbit/issues).) 15 | 16 | Even in Dojo, however, you can change your CLI. By pressing `Ctrl`+`X`, you can cycle through CLI interfaces: at least `%chat-cli` and `%dojo` are running on your ship now. There is also `%shoe`, which is an illustrative example of a Gall agent CLI. 17 | 18 | - Optional Reading: [Tlon Corporation, `chat-cli.hoon`](https://github.com/urbit/urbit/blob/master/pkg/arvo/app/chat-cli.hoon) 19 | 20 | 21 | ## Building a CLI Agent 22 | 23 | ![](../img/31-header-phobos-1.png){: width=100%} 24 | 25 | ### `sole` Library 26 | 27 | We previously examined `sole`, which provided some structures useful in `%say` and `%ask` generators. Let's recap on `%sole`. 28 | 29 | `sole` mold builders are designed to produce structured results or events. Their purpose is to provide a standard way of interfacing agent and generator components, both to other agents/generators and to Arvo. 30 | 31 | ```hoon 32 | |% 33 | ++ sole-action :: sole to app 34 | ++ sole-buffer :: command state 35 | ++ sole-change :: network change 36 | ++ sole-clock :: vector clock 37 | ++ sole-edit :: shared state change 38 | ++ sole-effect :: app to sole 39 | $% {$bel ~} :: beep 40 | {$blk p/@ud q/@c} :: blink+match char at 41 | {$clr ~} :: clear screen 42 | {$det sole-change} :: edit command 43 | {$err p/@ud} :: error point 44 | {$klr p/styx} :: styled text line 45 | {$mor p/(list sole-effect)} :: multiple effects 46 | {$nex ~} :: save clear command 47 | {$pro sole-prompt} :: set prompt 48 | {$sag p/path q/*} :: save to jamfile 49 | {$sav p/path q/@} :: save to file 50 | {$tab p/(list {=cord =tank})} :: tab-complete list 51 | {$tan p/(list tank)} :: classic tank 52 | {$txt p/tape} :: text line 53 | {$url p/@t} :: activate url 54 | == :: 55 | ++ sole-command :: command state 56 | ++ sole-prompt :: prompt definition 57 | ++ sole-share :: symmetric state 58 | ++ sole-dialog :: standard dialog 59 | ++ sole-input :: prompt input 60 | ++ sole-result :: conditional result 61 | ++ sole-product :: success result 62 | ++ sole-args :: generator arguments 63 | ``` 64 | 65 | In the past, we've only used `++sole-result` explicitly, although [`lib/generators.hoon`](https://github.com/urbit/urbit/blob/master/pkg/arvo/lib/generators.hoon) used other pieces such as `++sole-prompt` and `++sole-input` internally. 66 | 67 | We still don't need most of these to start a CLI agent, but you can see the breadth of options available to you. 68 | 69 | - Reading: [Tlon Corporation, `sur/sole.hoon`](https://github.com/urbit/urbit/blob/master/pkg/arvo/sur/sole.hoon) 70 | - Optional Reading: [Tlon Corporation, `lib/sole.hoon`](https://github.com/urbit/urbit/blob/master/pkg/arvo/lib/sole.hoon) 71 | 72 | ### `shoe` Library 73 | 74 | [`lib/shoe.hoon`](https://github.com/urbit/urbit/blob/master/pkg/arvo/lib/shoe.hoon) provides everything _besides_ text rendering for CLI apps. 75 | 76 | `shoe` produces either Gall cards or formatted `shoe-effect` cards that are intended for direct passing to all connected `shoe` apps. The `shoe-effect` cards can, for instance, pass `sole-effect`s (`%bel`, `%pro`, `%txt`, etc.). 77 | 78 | ```hoon 79 | |% 80 | :: $card: standard gall cards plus shoe effects 81 | +$ card 82 | :: $shoe-effect: easier sole-effects 83 | +$ shoe-effect 84 | $% :: %sole: raw sole-effect 85 | [%sole effect=sole-effect] 86 | :: %table: sortable, filterable data, with suggested column char widths 87 | [%table head=(list dime) wide=(list @ud) rows=(list (list dime))] 88 | :: %row: line sections with suggested char widths 89 | [%row wide=(list @ud) cols=(list dime)] 90 | == 91 | :: +shoe: gall agent core with extra arms 92 | ++ shoe 93 | :: +default: bare-minimum implementations of shoe arms 94 | ++ default 95 | |_ =bowl:gall 96 | ++ command-parser :: input parser, per-session 97 | ++ tab-list :: tab autocompletion options 98 | ++ on-command :: called on valid command 99 | ++ can-connect :: determines if session can connect 100 | ++ on-connect :: initialization on session connection 101 | ++ on-disconnect :: shutdown when session disconnects 102 | -- 103 | :: +agent: creates wrapper core that handles sole events and calls shoe arms 104 | ++ agent 105 | ++ draw 106 | |% 107 | ++ row 108 | ++ col-as-lines 109 | ++ col-as-text 110 | ++ alignment 111 | ++ break-sets 112 | ++ break 113 | ++ pad 114 | -- 115 | -- 116 | ``` 117 | 118 | `++command-parser` is where a lot of the magic takes place; it relies thoroughly on your ability to parse text. (We saw this some in Text Processing; we'll see more in Hoon I.) It can be a fairly sophisticated arm, as the `++parser` arm in `app/chat-cli.hoon`. 119 | 120 | A simple command parser could look like this: 121 | 122 | ```hoon 123 | ++ command-parser 124 | |= sole-id=@ta 125 | ^+ |~(nail *(like [? command])) 126 | %+ stag & 127 | (perk %demo %row %table ~) 128 | ``` 129 | 130 | `nail`, `++like`, `stag`, and `++perk` are all parsing rule concepts. Parsing rules are complex but can be reviewed in the [text parsing tutorial](https://urbit.org/docs/hoon/guides/parsing). 131 | 132 | Once you have a working app, you can use `|link` to connect to it at the console. Switch to it using `Ctrl`+`X`. (`|unlink` does the opposite.) 133 | 134 | What could you make with a command-line app? Some ideas: 135 | 136 | - Games like Yahtzee or poker or 42 (for which you already have some library code ready) 137 | - Automation language like a simple variant of `sh` or PowerShell 138 | - Command-line editor like Nano or Vim or [`ed`](https://github.com/crides/ed.hoon) 139 | - Dungeon game like Zork or a roguelike 140 | 141 | The sky's the limit! 142 | 143 | - Reading: [Tlon Corporation, "CLI apps"](https://urbit.org/docs/hoon/guides/cli-tutorial) 144 | - Optional Reading: [Tlon Corporation, `lib/shoe.hoon`](https://github.com/urbit/urbit/blob/master/pkg/arvo/lib/shoe.hoon) 145 | - Optional Reading: [`~hosbud-socbur`, `ed`](https://github.com/crides/ed.hoon) 146 | 147 | 148 | ## Unicode 149 | 150 | ![](../img/31-header-phobos-2.png){: width=100%} 151 | 152 | The `@c` aura denotes an arbitrary-length UTF-32 value. This is used extensively in the console subsystems like `%dill` and `drum`, but is frequently not used elsewhere (`@t` suffices). Most Unicode handling in Urbit is just passing data around rather than processing it, so compatibility is fairly straightforward. (Codepoints less than 32, however, are manually excluded for some reason, except for `\n` newline 0x0A.) 153 | 154 | [`++tuba`](https://urbit.org/docs/reference/library/4b/#tuba) and [`++tufa`](https://urbit.org/docs/reference/library/4b/#tufa) convert a `(list @t)` (`tape`) to `(list @c)` and back again. We call a list of individual codepoints `(list @c)` a `tour`. 155 | -------------------------------------------------------------------------------- /lessons/lesson34-hoon-2.md: -------------------------------------------------------------------------------- 1 | # `hoon.hoon` 2 | 3 | ![](../img/34-header-comet-0.gif){: width=100%} 4 | 5 | ## Learning Objectives 6 | 7 | - Deep dive through `hoon.hoon`. 8 | 9 | 10 | In this lesson, we will examine some other interesting aspects of `hoon.hoon` besides the parser. `hoon.hoon` is relatively old code stylistically; its organization corresponds to the documentation in having chapters like [`4m: formatting functions`](https://urbit.org/docs/reference/library/4m/). 11 | 12 | ## The Base Types of Hoon 13 | 14 | ![](../img/34-header-comet-1.gif){: width=100%} 15 | 16 | The Hoon type system recognizes only a few core types. `+$type` (formerly `$span`) encompasses important specific types for parsing and representing data in the ASTs. 17 | 18 | ```hoon 19 | +$ type $~ %noun :: 20 | $@ $? $noun :: any nouns 21 | $void :: no noun 22 | == :: 23 | $% {$atom p/term q/(unit @)} :: atom / constant 24 | {$cell p/type q/type} :: ordered pair 25 | {$core p/type q/coil} :: object 26 | {$face p/$@(term tune) q/type} :: namespace 27 | {$fork p/(set type)} :: union 28 | {$hint p/(pair type note) q/type} :: annotation 29 | {$hold p/type q/hoon} :: lazy evaluation 30 | == :: 31 | ``` 32 | 33 | These are: 34 | 35 | - `noun` 36 | - `void` 37 | - `atom` with text aura 38 | - `cell` of `+$type` and `+$type` 39 | - `core` of environment `+$type` and `coil` mapping core name to `garb` (name, wet/dry, and variance), context, and chapters 40 | - `face` of name wrapping `+$type` 41 | - `fork` of `+$type`s 42 | - `hint` annotating subject and `+$type` 43 | - `hold` of subject `+$type` and continuation AST for lazy (deferred) evaluation 44 | 45 | If there are other types you encounter in `hoon.hoon` which are opaque to you, consult `+$hoon` for a catalogue. 46 | 47 | 48 | ## Prettyprinting 49 | 50 | ![](../img/34-header-comet-2.gif){: width=100%} 51 | 52 | Prettyprinting is the process of rendering internal data in a legible way for the user or for other programs. The `++ut` arm of the compiler in `hoon.hoon` provides prettyprinter support. 53 | 54 | Hoon adopts a convention whereby any atom is uniquely determined by its representation; that is, `~.1`, `.1`, and `.~~~1` are all different floating-point numbers and it is easy to tell which kind. There is no ambiguity in either parsing or printing these values. 55 | 56 | To pretty-print an atom, the aura is of course taken into account. Hoon supports a lot of this, but of course the Dojo stack contributes as well. 57 | 58 | To pretty-print a value, Hoon generates a `+$plum`: 59 | 60 | ```hoon 61 | +$ plum 62 | $@ cord 63 | $% [%para prefix=tile lines=(list @t)] 64 | [%tree fmt=plumfmt kids=(list plum)] 65 | [%sbrk kid=plum] 66 | == 67 | ``` 68 | 69 | which may be a simple cord; a wrappable paragraph; a formatted plum tree; and an indication of a nested subexpression. Then standard `tang`, `tank`, etc. are used to produce the output, just as with other structured output. Ultimately, these are output by `++plume`, the prettyprinter itself. 70 | 71 | ```hoon 72 | ++ plume 73 | |_ =plum 74 | +$ line [indent=@ud text=tape] :: a line, indented by `indent` spaces 75 | +$ block (list line) :: a sequence of indented lines 76 | ++ flat :: print as a single line 77 | ++ tall :: print as multiple lines 78 | ++ adjust :: adjust lines to right 79 | ++ prepend-spaces :: prepend `n` spaces to tape 80 | ++ window :: print as list of tabbed lines 81 | ?@ plum [0 (trip plum)]~ :: trivial text 82 | ?- -.plum 83 | %para :: line-wrappable paragraph 84 | %sbrk :: nested subexpression 85 | %tree :: render text tree in tall mode 86 | == 87 | ++ backstep :: render using backstep indentation 88 | ++ rune-inline-with-block :: 89 | ++ running :: render tall hoon w/ running indentation 90 | ++ core-like :: prefix by tape 91 | ++ linear :: render onto single line 92 | ?@ plum :: just a cord 93 | ?- -.plum :: 94 | %sbrk :: wide mode 95 | %para :: wrappable text paragraph to line 96 | %tree :: render text tree to single line 97 | == 98 | -- 99 | ``` 100 | 101 | For instance, to pretty-print a single-precision floating-point `@rs`, the [Dragon-4 algorithm](http://www.ryanjuckett.com/programming/printing-floating-point-numbers/part-2/) is used to convert to a decimal representation: 102 | 103 | ```hoon 104 | > (@ub .3.1415926535) 105 | 0b100.0000.0100.1001.0000.1111.1101.1011 106 | > (@ux .3.1415926535) 107 | 0x4049.0fdb 108 | > (rlys .3.1415926535) 109 | [%d s=%.y e=-7 a=31.415.927] 110 | ``` 111 | 112 | This is then consumed by `++plume` to produce the atom form. 113 | 114 | 115 | ## Other Blocks 116 | 117 | There are some other chapters of interest in `hoon.hoon`. Take a look at the following: 118 | 119 | - `2n: functional hacks` 120 | - `3c: urbit time` 121 | - `4n: virtualization` (best read after Vere and Nock sections) 122 | 123 | ![](../img/34-header-comet-3.gif){: width=100%} 124 | -------------------------------------------------------------------------------- /lessons/lesson35-vere-1.md: -------------------------------------------------------------------------------- 1 | # Vere I 2 | 3 | ![](../img/35-header-comet-0.png){: width=100%} 4 | 5 | ## Learning Objectives 6 | 7 | - Understand how Nock is instrumented on top of Unix processes as a virtual machine. 8 | - Distinguish king and serf responsibilities. 9 | 10 | 11 | ## The Binary Executable 12 | 13 | ![](../img/35-header-comet-1.png){: width=100%} 14 | 15 | Urbit is a virtual machine running on a host OS. In practice, this means that there must be a substrate: an implementation which executes Nock into machine instructions, manages memory, handles `%unix` events from Arvo, and so forth. 16 | 17 | Vere serves as the reference C implementation of the Urbit binary. (There is also a Haskell version, [King Haskell](https://groups.google.com/a/urbit.org/g/dev/c/9BAG1TbA3nI/m/lWFhr4C3BwAJ), available.) 18 | 19 | From Cores: 20 | 21 | > You can think of the binary as being like a VMWare or Virtual Box server, which holds all of the Urbit data in a single memory block called the loom. OTAs live in the Urbit system software inside of that memory block. 22 | > 23 | > The worker or "serf" carries out Nock and jet computations for an Arvo-shaped noun. The daemon or "king" maintains the event log and interacts with the outside world (via Ames, Eyre, etc.). 24 | 25 | Nock implementations abound, but on their own they aren't instrumented to manage the entire subject efficiently. 26 | 27 | So what does the binary do? Let's take a look at the C code of Vere. You will find it helpful to clone [the current Urbit repo](https://github.com/urbit/urbit/). We will be examining the files in `pkg/urbit/vere`. 28 | 29 | ### Prolegomena 30 | 31 | > `u3` is the C library that makes Urbit work. 32 | 33 | As such, it is incumbent upon us to learn to speak u3 C. It's a very particular style of C, including manual reference counting. Mostly you only need to know it when composing jets, but as Vere uses it internally we need to venture forth. 34 | 35 | Everything in Nock is a noun, which is either an unsigned integer or a cell. Thus Vere need only process unsigned integers. To combat the problem of underspecified C integer types, u3 `typedef`s standard values, which include: 36 | 37 | ```c 38 | typedef uint32_t c3_w; // word 39 | typedef int32_t c3_ws; // signed word 40 | typedef uint8_t c3_y; // byte 41 | typedef int8_t c3_ys; // signed byte 42 | typedef uint8_t c3_b; // bit 43 | typedef uint8_t c3_t; // boolean 44 | typedef uint8_t c3_o; // loobean 45 | ``` 46 | 47 | These yield internal structures for Vere that look like this: 48 | 49 | ```c 50 | /* u3_hhed: http header. 51 | */ 52 | typedef struct _u3_hhed { 53 | struct _u3_hhed* nex_u; 54 | c3_w nam_w; 55 | c3_c* nam_c; 56 | c3_w val_w; 57 | c3_c* val_c; 58 | } u3_hhed; 59 | ``` 60 | 61 | which corresponds to a less verbose, non-Hungarian C: 62 | 63 | ```c 64 | /* header: http header. 65 | */ 66 | typedef struct _header { 67 | struct _header* next; 68 | uint32_t name; 69 | char* name_array; 70 | uint32_t value; 71 | char* value_array; 72 | } header; 73 | ``` 74 | 75 | u3 conventions take a little while to get used to but the consistency of the C code is refreshing once you are. 76 | 77 | - Reading: [Tlon Corporation, "u3: Noun Processing in C"](https://github.com/urbit/urbit/blob/master/doc/spec/u3.md), section "c3: C in Urbit" 78 | 79 | ### The King (`king.c`) 80 | 81 | The king is responsible for implementing the actual event log that Arvo uses to establish state. The actual state is tracked using the `u3_host` `struct`: 82 | 83 | ```c 84 | /* u3_host: entire host. 85 | */ 86 | typedef struct _u3_host { 87 | c3_w kno_w; // current executing stage 88 | c3_c* dir_c; // pier path (no trailing /) 89 | c3_c* wrk_c; // worker executable path 90 | c3_d now_d; // event tick 91 | uv_loop_t* lup_u; // libuv event loop 92 | u3_usig* sig_u; // signal list 93 | u3_utty* uty_u; // linked terminal list 94 | u3_opts ops_u; // commandline options 95 | c3_i xit_i; // exit code for shutdown 96 | u3_trac tra_u; // tracing information 97 | void (*bot_f)(); // call when chis is up 98 | } u3_host; // host == computer == process 99 | ``` 100 | 101 | The main event loop runs as a [daemon](https://en.wikipedia.org/wiki/Daemon_%28computing%29) for handling Arvo events. The main loop setup and process looks like this: 102 | 103 | ```c 104 | /* u3_king_commence(): start the daemon 105 | */ 106 | void 107 | u3_king_commence() 108 | { 109 | u3_Host.lup_u = uv_default_loop(); 110 | 111 | // initialize top-level timer 112 | // 113 | uv_timer_init(u3L, &u3K.tim_u); 114 | 115 | // start up a "fast-compile" arvo for internal use only 116 | // (with hashboard always disabled) 117 | // 118 | sag_w = u3C.wag_w; 119 | u3C.wag_w |= u3o_hashless; 120 | 121 | u3m_boot_lite(); 122 | 123 | // boot the ivory pill 124 | // 125 | { 126 | u3_noun lit; 127 | 128 | if ( 0 != u3_Host.ops_u.lit_c ) { 129 | lit = u3m_file(u3_Host.ops_u.lit_c); 130 | } 131 | else { 132 | lit = u3i_bytes(u3_Ivory_pill_len, u3_Ivory_pill); 133 | } 134 | 135 | if ( c3n == u3v_boot_lite(lit)) { 136 | u3l_log("lite: boot failed\r\n"); 137 | exit(1); 138 | } 139 | } 140 | 141 | // run the loop 142 | // 143 | _king_loop_init(); 144 | uv_run(u3L, UV_RUN_DEFAULT); 145 | _king_loop_exit(); 146 | } 147 | ``` 148 | 149 | `uv_run` is a service of [`libuv`](https://github.com/libuv/libuv) for asynchronous input and output processes. 150 | 151 | `u3L` is a macro alias for `u3_Host.lup_u`, defined at the first line as the main loop. 152 | 153 | 154 | ### The Serf (`serf.c`) 155 | 156 | The serf evaluates Nock and matches jets. The worker-process state is: 157 | 158 | ```c 159 | /* u3_serf: worker-process state 160 | */ 161 | typedef struct _u3_serf { 162 | c3_d key_d[4]; // disk key 163 | c3_c* dir_c; // execution directory (pier) 164 | c3_d sen_d; // last event requested 165 | c3_d dun_d; // last event processed 166 | c3_l mug_l; // hash of state 167 | c3_o pac_o; // pack kernel 168 | c3_o rec_o; // reclaim cache 169 | c3_o mut_o; // mutated kerne 170 | u3_noun sac; // space measurementl 171 | } u3_serf; 172 | 173 | ``` 174 | 175 | For instance, the serf processes an event thus: 176 | 177 | ```c 178 | /* u3_serf_work(): apply event, producing effects. 179 | */ 180 | u3_noun 181 | u3_serf_work(u3_serf* sef_u, c3_w mil_w, u3_noun job) 182 | { 183 | c3_t tac_t = ( 0 != u3_Host.tra_u.fil_u ); 184 | c3_c lab_c[2056]; 185 | u3_noun pro; 186 | 187 | // XX refactor tracing 188 | // 189 | if ( tac_t ) { 190 | u3_noun wir = u3h(u3t(job)); 191 | u3_noun cad = u3h(u3t(u3t(job))); 192 | 193 | { 194 | c3_c* cad_c = u3m_pretty(cad); 195 | c3_c* wir_c = u3m_pretty_path(wir); 196 | snprintf(lab_c, 2056, "work [%s %s]", wir_c, cad_c); 197 | c3_free(cad_c); 198 | c3_free(wir_c); 199 | } 200 | 201 | u3t_event_trace(lab_c, 'B'); 202 | } 203 | 204 | // %work must be performed against an extant kernel 205 | // 206 | c3_assert( 0 != sef_u->mug_l); 207 | 208 | pro = u3nc(c3__work, _serf_work(sef_u, mil_w, job)); 209 | 210 | if ( tac_t ) { 211 | u3t_event_trace(lab_c, 'E'); 212 | } 213 | 214 | return pro; 215 | } 216 | ``` 217 | 218 | I recommend perusing the files of `pkg/urbit` more generally to get a feel for how things interrelate, including the `include` header files. 219 | 220 | Jet code is matched against `tree.c`; we will examine this later on. 221 | 222 | ![](../img/35-header-comet-2.png){: width=100%} 223 | -------------------------------------------------------------------------------- /lessons/lesson36-vere-2.md: -------------------------------------------------------------------------------- 1 | # Vere II 2 | 3 | ![](../img/36-header-comet-0.gif){: width=100%} 4 | 5 | ## Learning Objectives 6 | 7 | - Explain the noun memory model of Vere, including the road. 8 | - Identify the Application Binary Interface (ABI) of Arvo. 9 | 10 | 11 | ## The Loom 12 | 13 | ![](../img/36-header-comet-1.gif){: width=100%} 14 | 15 | One of the intriguing nuggets buried within Urbit is the _loom_, a unique memory management model. The loom divides memory into stack and heap, as conventional, but then layers stack and heap inside of spawned processes in a surprising but convenient way. 16 | 17 | > A road is a normal heap-stack system, except that the heap and stack can point in either direction. Therefore, inside a road, we can nest another road in the opposite direction. 18 | > 19 | > When the opposite road completes, its heap is left on top of the opposite heap's stack. It's no more than the normal behavior of a stack machine for all subcomputations to push their results on the stack. 20 | > 21 | > The performance tradeoff of "leaping" - reversing directions in the road - is that if the outer computation wants to preserve the results of the inner one, not just use them for temporary purposes, it has to copy them. 22 | > 23 | > This is a trivial cost in some cases, a prohibitive cost in others. The upside, of course, is that all garbage accrued in the inner computation is discarded at zero cost. 24 | 25 | ![](../img/36-arvo-road.png){: width=100%} 26 | 27 | You lose context on which layered road a particular process is running on, and you have to use wrapped `malloc` methods, but the automatic garbage collection in C is very nice. 28 | 29 | u3 in general needs you to count references, though, which is obnoxious even if good discipline. So why the road model? 30 | 31 | > The key is that we don't update refcounts in senior memory. A pointer from an inner road to an outer road is not counted. Also, the outmost, or surface road, is the only part of the image that gets checkpointed. 32 | 33 | This means that inner road computations can be aborted without consequence to the outer road. This is key to maintaining the atomicity of Arvo events. 34 | 35 | > Any significant computation with nouns, certainly anything Turing complete, should be run (a) virtualized and (b) in an inner road. 36 | 37 | - Reading: [Tlon Corporation, "u3: Noun Processing in C"](https://github.com/urbit/urbit/blob/master/doc/spec/u3.md#u3-the-road-model), section "u3: The Road Model" 38 | - Optional Reading: [Tlon Corporation, "Vere Tutorial"](https://urbit.org/docs/tutorials/vere/) 39 | 40 | 41 | ## The Application Binary Interface 42 | 43 | ![](../img/36-header-comet-2.gif){: width=100%} 44 | 45 | As you will see in Arvo 2 (and saw briefly at the end of Arvo 1), the Arvo core is an event handler. This is hard-coded into contact with the C code of the binary. (In `tree.c`, for instance, you can find references such as `static u3j_hood _141_pen_ho[] = { {"ap", 86}, {"ut", 342}, { } };`, indicating the arms within Arvo.) 46 | 47 | What sorts of things are directly managed by the binary? That is, what kinds of operations are there? Just looking at the function and service prefixes tells you a lot: 48 | 49 | | Prefix | Purpose | 50 | | ------ | ------- | 51 | | `u3a` | allocation | 52 | | `u3e` | persistence | 53 | | `u3h` | hashtables | 54 | | `u3i` | noun construction | 55 | | `u3j` | jet control | 56 | | `u3m` | system management | 57 | | `u3n` | nock computation | 58 | | `u3r` | noun access (error returns) | 59 | | `u3t` | profiling | 60 | | `u3v` | arvo | 61 | | `u3x` | noun access (error crashes) | 62 | | `u3z` | memoization | 63 | | `u3k[a-g]` | jets (transfer, C args) | 64 | | `u3q[a-g]` | jets (retain, C args) | 65 | | `u3w[a-g]` | jets (retain, nock core) | 66 | 67 | Many of these are too specific to concern us now, but let's particularly examine a couple of cases. 68 | 69 | ### `u3m` System Management 70 | 71 | For Urbit, “virtualization” can mean either the binary itself running Nock or running Nock on Nock (`++mock`). Here we are concerned with the process of running the binary virtual Nock machine. 72 | 73 | `u3m` wraps the system so that Unix and Nock errors can be handled within a unified framework. It also handles loading files, the road memory model, prettyprinting, and garbage collection. 74 | 75 | - Reading: [Tlon Corporation, "Vere API Overview by Prefix"](https://urbit.org/docs/tutorials/vere/api/), section `u3m` 76 | 77 | ### `u3v` Arvo ABI 78 | 79 | `u3v` instruments the Arvo event handler: 80 | 81 | 1. `u3v` interfaces directly with the `++wish` arm of the Arvo kernel 82 | 2. `u3v` processes ova (`ovum`s), which are typeless cards that are compatible with Unix events 83 | 3. `u3v` parses and produces messages (`tank`s, etc.) 84 | 85 | It also manages compacting the Arvo kernel and caches to manage and reclaim memory. 86 | 87 | - Reading: [Tlon Corporation, "Vere API Overview by Prefix"](https://urbit.org/docs/tutorials/vere/api/), section `u3v` 88 | 89 | We defer a detailed discussion of jets until Nock 2. 90 | 91 | Ultimately, the Vere C implementation of the Nock interpreter is intended to be replaced with [Jacque, a Java implementation](https://urbit.org/docs/glossary/jacque/). 92 | -------------------------------------------------------------------------------- /lessons/lesson37-arvo-2.md: -------------------------------------------------------------------------------- 1 | # Arvo II 2 | 3 | ![](../img/37-header-oort-0.png){: width=100%} 4 | 5 | ## Learning Objectives 6 | 7 | - Describe the Arvo event handler, cards, and ducts. 8 | 9 | 10 | ## The Core Arvo 11 | 12 | ### The Event Handler 13 | 14 | ```hoon 15 | :: arvo: structural interface core 16 | ++ arvo 17 | |% 18 | ++ come |= [@ @ @ pram vise pone] 19 | (come:soul +<) 20 | ++ load |= [@ @ @ pram vase pane] 21 | (load:soul +<) 22 | ++ peek |= * 23 | =/ rob (^peek ;;([@da path] +<)) 24 | ?~ rob ~ 25 | ?~ u.rob ~ 26 | [~ u.u.rob] 27 | ++ poke |= * 28 | => .(+< ;;([now=@da ovo=ovum] +<)) 29 | (poke:soul now ovo) 30 | ++ wish |=(* (^wish ;;(@ta +<))) 31 | -- 32 | ``` 33 | 34 | - `++poke` is the only arm which can transition Arvo from one state to another. It is a typed transactional message. 35 | - `++peek` provides a globally referential `scry` namespace 36 | - `++wish` parses a core with `%zuse` 37 | - `++load` upgrades the kernel 38 | - `++come` is used with a new kernel 39 | 40 | Altogether, Arvo is remarkably straightforward (as an event handler should be) and has the surprising ability to upgrade itself in-place. 41 | 42 | - [Tlon Corporation, "Arvo Tutorial"](https://urbit.org/docs/tutorials/arvo/arvo/#the-state), section "The State" 43 | 44 | ### The State 45 | 46 | The Arvo state is represented as a structure: 47 | 48 | ```hoon 49 | =/ pit=vase !>(..is) :: 50 | =/ vil=vile (viol p.pit) :: cached reflexives 51 | =| $: lac=_& :: laconic bit 52 | eny=@ :: entropy 53 | our=ship :: identity 54 | bud=vase :: %zuse 55 | vanes=(list [label=@tas =vane]) :: modules 56 | == :: 57 | ++ card {p/@tas q/*} :: typeless card 58 | ++ ovum {p/wire q/card} :: Arvo event 59 | ++ wire path :: event cause 60 | ``` 61 | 62 | > Arvo is a core with these six arms. To use these arms, we hardcode the axis of the formula (11, 4, 86, etc) into the C code that calls Arvo, because otherwise we'd need type metadata - which we can get, by calling Arvo. 63 | 64 | - `pit` represents the part of Arvo which only changes in an update 65 | - `vil` is a cache of types which shouldn't be recompiled regularly due to frequency of use: `type`, `duct`, `vase` 66 | - `lac` is the verbosity of the kernel 67 | - `eny` is system entropy 68 | - `our` is the ship's identity 69 | - `bud` is the standard library 70 | - `vanes` is the list of vanes with internal state 71 | 72 | One of the most salient system calls is to obtain entropy, or random generated numeric noice. Ultimately, entropy must be drawn from the Unix system via an `ovum` (see below): 73 | 74 | ```hoon 75 | %wack 76 | ?> ?=(@ q.q.ovo) 77 | =. eny (shaz (cat 3 eny q.q.ovo)) 78 | ``` 79 | 80 | The flip side of this call may be found in `urbit/vere/io/fore.c`, 81 | 82 | ```c 83 | // inject fresh entropy 84 | // 85 | c3_w eny_w[16]; 86 | c3_rand(eny_w); 87 | 88 | wir = u3nc(c3__arvo, u3_nul); 89 | cad = u3nc(c3__wack, u3i_words(16, eny_w)); 90 | 91 | u3_auto_plan(car_u, u3_ovum_init(0, u3_blip, wir, cad)); 92 | ``` 93 | 94 | where it is obtained from the system via `urbit/vere/pier.c`: 95 | 96 | ```c 97 | /* c3_rand(): fill a 512-bit (16-word) buffer. 98 | */ 99 | void 100 | c3_rand(c3_w* rad_w) 101 | { 102 | ent_getentropy(rad_w, 64) ) 103 | } 104 | ``` 105 | 106 | > `libent` is a cross-platform wrapper around `getentropy(2)`. It exports one symbol, `ent_getentropy`. If `getentropy` is available, then it's just a shim around that. Otherwise, it uses `getrandom(2)` (available since kernel 3.17) on Linux, or `/dev/urandom` on other \*nix. 107 | 108 | - [Tlon Corporation, "Arvo Tutorial"](https://urbit.org/docs/tutorials/arvo/arvo/#the-state), section "The State" 109 | 110 | ## Ducts 111 | 112 | ![](../img/37-header-oort-1.png){: width=100%} 113 | 114 | Arvo orchestrates vane activities using cards, but a card isn't sent naked. It is accompanied by a `duct`, or list of causal events as a `(list wire)`. 115 | 116 | Arvo mandates that each vane maintain a queue of causal events. Vanes coordinate their duct/call stacks as queues (`++to` arm, common name `qeu`). 117 | 118 | > The Arvo causal stack is called a `duct`. This is represented simply as a `list` of `path`s, where each `path` represents a step in the causal chain. The first element in the `path` is the first letter of whichever vane handled that step in the computation, or the empty span for Unix. 119 | > 120 | > This is a call stack, with a crucial feature: the stack is a first-class citizen. You can respond over a `duct` zero, one, or many times. You can save `duct`s for later use. 121 | 122 | An incoming card is placed in a vane's queue, with the provenance indicated in case errors or `gift`s need to be sent back along the call path. 123 | 124 | There are four kinds of cards: 125 | 126 | > In other words, there are only four ways of seeing a move: 127 | > 128 | > 1. as a request seen by the caller, which is a `note`; 129 | > 2. that same request as seen by the callee, a `task`; 130 | > 3. the response to that first request as seen by the callee, a `gift`; 131 | > 4. the response to the first request as seen by the caller, a `sign`. 132 | 133 | ![](../img/37-arvo-cards.png){: width=50%} 134 | 135 | The system also frequently deals in the `ovum` type, 136 | 137 | ```hoon 138 | +$ ovum (pair wire curd) 139 | ``` 140 | 141 | which is a "card with a cause," or a way of passing steps and actions into Arvo that is also compatible with `%unix` cards. 142 | 143 | > For input events, this is the module that caused the event; for output actions, it's the module that performs the action. 144 | 145 | - Reading: [Tlon Corporation, "Vere API Overview by Prefix"](https://urbit.org/docs/tutorials/vere/api/), section "u3v: the Arvo kernel" 146 | 147 | ![](../img/37-header-oort-2.png){: width=100%} 148 | -------------------------------------------------------------------------------- /lessons/lesson40-azimuth-2.md: -------------------------------------------------------------------------------- 1 | # Azimuth II 2 | 3 | ![](../img/40-header-mars-0.png){: width=100%} 4 | 5 | ## Learning Objectives 6 | 7 | - Explain the application of keys from the Urbit Hierarchical Deterministic (Urbit HD) wallet. 8 | - Explain how Bridge works with Azimuth PKI. 9 | 10 | 11 | Formally, Azimuth provides the following services: 12 | 13 | - “**Azimuth**: contains all on-chain state for azimuth. Most notably, ownership and public keys. Can't be modified directly, you must use the Ecliptic. 14 | - “**Ecliptic**: is used as an interface for interacting with your points on-chain. Allows you to configure keys, transfer ownership, etc. 15 | - “**Polls**: registers votes by the Galactic Senate on proposals. These can be either static documents or Ecliptic upgrades. 16 | - “**Linear Star Release**: facilitates the release of blocks of stars to their owners over a period of time. 17 | - “**Conditional Star Release**: facilitates the release of blocks of stars to their owners based on milestones. 18 | - “**Claims**: allows point owners to make claims about (for example) their identity, and associate that with their point. 19 | - “**Censures**: simple reputation management, allowing galaxies and stars to flag points for negative reputation. 20 | - “**Delegated Sending**: enables network-effect like distributing of planets. 21 | - “**Planet Sale**: gives an example of a way in which stars could sell planets on-chain.” 22 | 23 | These are mostly operated through the Bridge client. 24 | 25 | 26 | ## Urbit HD Wallet 27 | 28 | ![](../img/40-header-mars-1.png){: width=100%} 29 | 30 | You own your Urbit. But how can you verify this to others? And can you allow others to operate your services without betraying your ownership keys? The answers lie in the operations of Azimuth and Jael. `%jael` was already discussed in Arvo I, where its role as a secret keeper was outlined. 31 | 32 | Azimuth recognizes the Urbit Hierarchical Deterministic (HD) wallet, which stores sets of keys allowing certain operations to take place. 33 | 34 | ![](https://media.urbit.org/fora/proposals/UP-8.jpg){: width=75%} 35 | 36 | The most important of these are: 37 | 38 | - the _ownership key_, which establishes your ownership of an Ethereum address (typically via a Master Ticket or Metamask) 39 | - the _management proxy_, which allows someone to configure network keys and manage sponsorship 40 | - the _voting proxy_, which allows a galaxy to delegate voting 41 | - the _spawn proxy_, which permits someone to create new daughter identities on your behalf 42 | 43 | The management and spawn proxies are useful for hosting planet services or selling points. 44 | 45 | - Reading: [Tlon Corporation, "Urbit HD Wallet"](https://urbit.org/docs/glossary/hdwallet/) 46 | - Reading: [Anthony Arroyo `~poldec-tonteg`, Will Kim `~hadrud-lodsef`, Morgan Sutherland `~hidrel-fabtel`, "UP8: Urbit HD wallet"](https://github.com/urbit/proposals/blob/master/008-urbit-hd-wallet.md) 47 | - Reading: [Tlon Corporation, "Wallet-Generator"](https://urbit.org/docs/glossary/wallet-generator/) 48 | 49 | 52 | 53 | 54 | ## Bridge 55 | 56 | ![](../img/40-header-mars-2.png){: width=100%} 57 | 58 | [Bridge](https://github.com/urbit/bridge) is the premier service for manipulating the Azimuth PKI. Bridge provides the following services: 59 | 60 | - manage sponsors and proxies 61 | - spawn daughter points 62 | - transfer ownership 63 | - rekey a ship (move to a new Ethereum address) 64 | 65 | Bridge interacts with Azimuth via Ecliptic contracts, Ecliptic being the point management contract for Urbit. 66 | 67 | - Resource: [Azimuth PKI](https://github.com/urbit/azimuth) 68 | - Resource: [Bridge](https://github.com/urbit/bridge) 69 | 70 | ### Ethereum Contracts 71 | 72 | You should review the core contracts, which are written in [Solidity](https://solidity.readthedocs.io/en/v0.7.4/) for the Ethereum Virtual Machine. 73 | 74 | [`azimuth-js`](https://github.com/urbit/azimuth-js) provides a number of tools for managing transfers; for instance, transfers are initiated from [`Admin/AdminTransfer`](https://github.com/urbit/bridge/blob/master/src/views/Admin/AdminTransfer.js) and accepted in [`AcceptTransfer`](https://github.com/urbit/bridge/blob/master/src/views/AcceptTransfer.js) 75 | 76 | If you are interested in further details, there has been extensive discussion of how to access and manage contracts automatically or manually on the `urbit-dev` mailing list. 77 | 78 | - Reading: [Azimuth contract](https://github.com/urbit/azimuth/blob/master/contracts/Azimuth.sol) 79 | - Reading: [Ecliptic contract](https://github.com/urbit/azimuth/blob/master/contracts/Ecliptic.sol) 80 | 81 | 82 | ## The Future of Azimuth 83 | 84 | ![](../img/40-header-mars-3.png){: width=100%} 85 | 86 | There has been some dissatisfaction with the Ethereum substrate which Azimuth currently uses. Since Azimuth is a public-key infrastructure that is only operated by Ethereum, it is possible and may become desirable to move Azimuth to a different platform, perhaps onto Urbit itself someday. 87 | 88 | “Any Urbit PKI must fulfill a minimal set of requirements: 89 | 90 | - “Must prevent double-spending of assets 91 | - “Must have a globally-consistent state 92 | - “Must have data availability of the full PKI state 93 | - “Must have cheap enough transactions to allow user onboarding and maintenance 94 | - “Must have interoperability with other blockchains so as to allow trustless atomic swaps of Urbit assets for digital currencies 95 | - “Must have high enough throughput to support Urbit’s use-cases 96 | - “Must have a protocol, social or technological, for upgrading the PKI ruleset” 97 | 98 | There have been a number of proposals in this direction, such as “planetoids” (tracked off-chain by sponsoring stars), batched transactions, etc. 99 | 100 | - Optional Reading: [Ted Blackman `~rovnys-ricfer`, Logan Allen, "Proof of Authority Urbit PKI"](https://gist.github.com/belisarius222/41998e569fe741ab0e1ffd98ec92b6f9) 101 | -------------------------------------------------------------------------------- /resources/.gitkeep: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /resources/pokemon.hoon: -------------------------------------------------------------------------------- 1 | :- %say 2 | =< 3 | |= [[* eny=@uv *] *] 4 | :- %noun 5 | =/ eevee [%eevee `(set @tas)`(sy `(list @tas)`~[%normal]) `(set @tas)`(sy `(list @tas)`~[%growl %body-slam])] 6 | =/ gyrados [%gyrados `(set @tas)`(sy `(list @tas)`~[%water %flying]) `(set @tas)`(sy `(list @tas)`~[%bite %crunch %double-team])] 7 | =/ unique-hash `@uw`(~(raw og eny) 60) 8 | =/ eevee-1 [unique-hash "Eevee" eevee 55 55 55 50 55] 9 | ~& eevee 10 | ~& gyrados 11 | ~& eevee-1 12 | eevee-1 13 | |% 14 | +$ pokemon 15 | $% id=@uw :: unique hash 16 | name=tape :: name of pokemon 17 | kind=species :: kind of pokemon 18 | hp=@ud :: current health 19 | max-hp=@ud :: normal maximum health 20 | attack=@ud :: attack 21 | defense=@ud :: defense 22 | speed=@ud :: speed 23 | == 24 | +$ species 25 | $% name=%tas :: pokemon species name as tag 26 | type=(set type) :: pokemon types 27 | moves=(set move) :: species-specific abilities 28 | == 29 | +$ type ?(%bug %dragon %ice %fighting %fire %flying %grass %ghost %ground %electric %normal %poison %psychic %rock %water) 30 | +$ move ?(%barrage %bite %bind %body-slam %comet-punch %constrict %conversion %cut %crunch %disable %dizzy-punch %double-team %growl) 31 | -- 32 | 33 | --------------------------------------------------------------------------------