├── .gitignore ├── README.md ├── bundle.toml ├── config.nix ├── default.nix ├── dna ├── .hcignore ├── Vagrantfile ├── app.json ├── conductor-config.toml ├── dist │ └── dna.dna.json ├── test │ ├── index.js │ ├── package-lock.json │ └── package.json └── zomes │ └── courses │ ├── code │ ├── .hcbuild │ ├── Cargo.lock │ ├── Cargo.toml │ └── src │ │ ├── content.rs │ │ ├── course.rs │ │ ├── lib.rs │ │ └── module.rs │ └── zome.json ├── ui.zip └── ui ├── .editorconfig ├── .gitignore ├── .prettierrc ├── LICENSE ├── README.md ├── dist ├── 77c90c1d75fafad6241f.js ├── 77c90c1d75fafad6241f.js.LICENSE.txt ├── 77c90c1d75fafad6241f.js.map ├── index.html ├── precache-manifest.bdefb80fe853de8ae3d06c98f967a7d0.js └── sw.js ├── index.html ├── package-lock.json ├── package.json ├── src ├── components │ ├── leap-app.js │ ├── leap-course-detail.js │ ├── leap-courses-list.js │ ├── leap-dashboard.js │ ├── leap-emtpy-placeholder.js │ └── leap-module.js ├── config.js ├── connection.js ├── graphql │ ├── directive.js │ ├── index.js │ ├── queries.js │ ├── resolvers.js │ └── schema.js ├── index.js ├── router.js ├── shared-styles.js └── utils.js └── webpack.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | target/ 3 | .hc 4 | .cargo/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LeaP - learning-pathways 2 | 3 | LeaP is a Peer to Peer education system based on Holochain. Developed during the first community run Holochain DevCamp #6. 4 | 5 | This repository is used as a learning resource for the students learning how to program Holochain hApps on the Rust lang. 6 | 7 | Design: https://hackmd.io/_Uvrwr1HSNmfsWHqymcgvA 8 | 9 | ### Running the tests or package the DNA 10 | To be able to run the tests and package the DNA 11 | 12 | 1. From the root directory, run `nix-shell` 13 | 2. Navigate to the `dna` folder 14 | 3. Run the `hc test` command OR Run the `hc package` command 15 | 16 | ### Running a UI (or two) 17 | To be able to run the UI and have a working version, follow the below steps: 18 | 19 | 1. Navigate to the `ui` folder 20 | 2. Run the `npm install` command 21 | 22 | #### Run two agents for demo-ing purpose: 23 | 1. Open terminal 24 | 2. From the root directory, run `nix-shell` 25 | 3. Navigate to `ui` folder 26 | 4. Run `npm run demo` 27 | 5. Open browser window and visit: http://localhost:8080 28 | 6. Open second browser window and visit: http://localhost:8081 29 | 30 | #### Run a single agent: 31 | 1. Open terminal 32 | 2. From the root directory, run `nix-shell` 33 | 3. Navigate to `dna` folder 34 | 4. Run `hc run` 35 | 5. Open another terminal and go to the `ui` folder 36 | 6. Run `npm run ui:alice` 37 | 7. Open browser window and visit: http://localhost:8080 38 | 39 | #### Frontend Stack 40 | The front-end stack being used (see package.json): 41 | * [LitElement](https://lit-element.polymer-project.org/) 42 | * [GraphQL](https://graphql.org/) 43 | * [ApolloClient](https://github.com/apollographql/apollo-client) 44 | -------------------------------------------------------------------------------- /bundle.toml: -------------------------------------------------------------------------------- 1 | bridges = [] 2 | 3 | [[instances]] 4 | name = "learning-pathways" 5 | id = "learning-pathways-instance" 6 | dna_hash = "QmdEvz12chBPBrpJB7KZDeh2waTArfuqmnMRrjtDxuQLUg" 7 | uri = "file:./dna/dist/dna.dna.json" 8 | 9 | [[UIs]] 10 | name = "Learning Pathways" 11 | id = "leap-ui" 12 | uri = "file:./ui.zip" 13 | 14 | [[UIs.instance_references]] 15 | ui_handle = "learning-pathways" 16 | instance_id = "learning-pathways-instance" 17 | -------------------------------------------------------------------------------- /config.nix: -------------------------------------------------------------------------------- 1 | { 2 | # extend the shell with buildInputs specific to this project 3 | buildInputs = [ ]; 4 | 5 | # configure holonix itself 6 | holonix = { 7 | 8 | # true = use a github repository as the holonix base (recommended) 9 | # false = use a local copy of holonix (useful for debugging) 10 | use-github = true; 11 | 12 | # configure the remote holonix github when use-github = true 13 | github = { 14 | 15 | # can be any github ref 16 | # branch, tag, commit, etc. 17 | ref = "v0.0.65"; 18 | 19 | # the sha of what is downloaded from the above ref 20 | # note: even if you change the above ref it will not be redownloaded until 21 | # the sha here changes (the sha is the cache key for downloads) 22 | # note: to get a new sha, get nix to try and download a bad sha 23 | # it will complain and tell you the right sha 24 | sha256 = "1frw8z1d3qdly2lcs7z4liwkkqgb344h7p7n1xzpwaqhhm0xa0kd"; 25 | 26 | 27 | # the github owner of the holonix repo 28 | owner = "holochain"; 29 | 30 | # the name of the holonix repo 31 | repo = "holonix"; 32 | }; 33 | 34 | # configuration for when use-github = false 35 | local = { 36 | # the path to the local holonix copy 37 | path = ./.; 38 | }; 39 | 40 | }; 41 | 42 | # configure the release process 43 | release = { 44 | hook = { 45 | # sanity checks before deploying 46 | # to stop the release 47 | # exit 1 48 | preflight = '' 49 | hn-release-hook-preflight-manual 50 | ''; 51 | 52 | # bump versions in the repo 53 | version = '' 54 | hn-release-hook-version-readme 55 | ''; 56 | 57 | # publish artifacts to the world 58 | publish = '' 59 | echo "All finished!!!" 60 | ''; 61 | }; 62 | 63 | # the commit hash that the release process should target 64 | # this will always be behind what ends up being deployed 65 | # the release process needs to add some commits for changelog etc. 66 | commit = "e540606583b1f91ecbaeca4a705a15ecc3d59e6c"; 67 | 68 | # the semver for prev and current releases 69 | # the previous version will be scanned/bumped by release scripts 70 | # the current version is what the release scripts bump *to* 71 | version = { 72 | current = "0.0.30"; 73 | previous = "0.0.29"; 74 | }; 75 | 76 | github = { 77 | # markdown to inject into github releases 78 | # there is some basic string substitution {{ xxx }} 79 | # - {{ changelog }} will inject the changelog as at the target commit 80 | template = '' 81 | {{ changelog }} 82 | 83 | # Installation 84 | 85 | Use Holonix to work with this repository. 86 | 87 | See: 88 | 89 | - https://github.com/holochain/holonix 90 | - https://nixos.org/ 91 | ''; 92 | 93 | # owner of the github repository that release are deployed to 94 | owner = "holochain"; 95 | 96 | # repository name on github that release are deployed to 97 | repo = "holonix"; 98 | 99 | # canonical local upstream name as per `git remote -v` 100 | upstream = "origin"; 101 | }; 102 | }; 103 | } -------------------------------------------------------------------------------- /default.nix: -------------------------------------------------------------------------------- 1 | # This is an example of what downstream consumers of holonix should do 2 | # This is also used to dogfood as many commands as possible for holonix 3 | # For example the release process for holonix uses this file 4 | let 5 | 6 | # point this to your local config.nix file for this project 7 | # example.config.nix shows and documents a lot of the options 8 | config = import ./config.nix; 9 | 10 | # START HOLONIX IMPORT BOILERPLATE 11 | holonix = import ( 12 | if ! config.holonix.use-github 13 | then config.holonix.local.path 14 | else fetchTarball { 15 | url = "https://github.com/${config.holonix.github.owner}/${config.holonix.github.repo}/tarball/${config.holonix.github.ref}"; 16 | sha256 = config.holonix.github.sha256; 17 | } 18 | ) { config = config; }; 19 | # END HOLONIX IMPORT BOILERPLATE 20 | 21 | in 22 | with holonix.pkgs; 23 | { 24 | dev-shell = stdenv.mkDerivation (holonix.shell // { 25 | name = "dev-shell"; 26 | 27 | buildInputs = [ ] 28 | ++ holonix.shell.buildInputs 29 | ++ config.buildInputs 30 | ; 31 | }); 32 | } 33 | -------------------------------------------------------------------------------- /dna/.hcignore: -------------------------------------------------------------------------------- 1 | dist 2 | test 3 | ui 4 | README.md -------------------------------------------------------------------------------- /dna/Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | 4 | # All Vagrant configuration is done below. The "2" in Vagrant.configure 5 | # configures the configuration version (we support older styles for 6 | # backwards compatibility). Please don't change it unless you know what 7 | # you're doing. 8 | Vagrant.configure("2") do |config| 9 | # The most common configuration options are documented and commented below. 10 | # For a complete reference, please see the online documentation at 11 | # https://docs.vagrantup.com. 12 | 13 | # Every Vagrant development environment requires a box. You can search for 14 | # boxes at https://vagrantcloud.com/search. 15 | # 16 | # the holochain-vagrant box is generated by running: 17 | # nix-shell --run hc-test 18 | # from inside the /vagrant dir, which prewarms nix, rust and npm 19 | config.vm.box = "holochain-vagrant" 20 | config.vm.box_url = "https://holochain.love/box" 21 | # uncomment this to use the raw nixos base box instead of the holochain box 22 | # config.vm.box = "nixos/nixos-18.03-x86_64" 23 | 24 | # Disable automatic box update checking. If you disable this, then 25 | # boxes will only be checked for updates when the user runs 26 | # `vagrant box outdated`. This is not recommended. 27 | # config.vm.box_check_update = false 28 | 29 | # Create a forwarded port mapping which allows access to a specific port 30 | # within the machine from a port on the host machine. In the example below, 31 | # accessing "localhost:8080" will access port 80 on the guest machine. 32 | # NOTE: This will enable public access to the opened port 33 | # config.vm.network "forwarded_port", guest: 80, host: 8080 34 | 35 | # Create a forwarded port mapping which allows access to a specific port 36 | # within the machine from a port on the host machine and only allow access 37 | # via 127.0.0.1 to disable public access 38 | # config.vm.network "forwarded_port", guest: 80, host: 8080, host_ip: "127.0.0.1" 39 | 40 | # Create a private network, which allows host-only access to the machine 41 | # using a specific IP. 42 | # config.vm.network "private_network", ip: "192.168.33.10" 43 | 44 | # Create a public network, which generally matched to bridged network. 45 | # Bridged networks make the machine appear as another physical device on 46 | # your network. 47 | # config.vm.network "public_network" 48 | 49 | # Share an additional folder to the guest VM. The first argument is 50 | # the path on the host to the actual folder. The second argument is 51 | # the path on the guest to mount the folder. And the optional third 52 | # argument is a set of non-required options. 53 | # config.vm.synced_folder "../data", "/vagrant_data" 54 | 55 | # Provider-specific configuration so you can fine-tune various 56 | # backing providers for Vagrant. These expose provider-specific options. 57 | # Example for VirtualBox: 58 | # 59 | config.vm.provider "virtualbox" do |vb| 60 | # # Display the VirtualBox GUI when booting the machine 61 | vb.gui = false 62 | # Customize the amount of memory on the VM: 63 | vb.memory = "4096" 64 | vb.cpus = "4" 65 | vb.customize ["modifyvm", :id, "--hwvirtex", "off"] 66 | end 67 | 68 | # View the documentation for the provider you are using for more 69 | # information on available options. 70 | 71 | # requires the vagrant-nixos-plugin to work 72 | # `vagrant plugin install vagrant-nixos-plugin` 73 | # add some simple dev tools 74 | # add some swap space to allow for more RAM on small devices 75 | config.vm.provision :nixos, 76 | run: 'always', 77 | expression: { 78 | swapDevices: [ { device: "/swapfile", size: 16384 } ], 79 | environment: { 80 | systemPackages: [ 81 | # htop is handy for diagnosing runaway memory and cpu usage 82 | :htop, 83 | 84 | # sometimes windows can mess with line endings 85 | # dos2unix can fix that inside the box 86 | # mostly a debugging tool, ultimately the correct line endings need to 87 | # be committed 88 | :dos2unix, 89 | :vim 90 | ] 91 | } 92 | } 93 | 94 | end 95 | -------------------------------------------------------------------------------- /dna/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Holochain App Name", 3 | "description": "A Holochain app", 4 | "authors": [ 5 | { 6 | "identifier": "Author Name ", 7 | "public_key_source": "", 8 | "signature": "" 9 | } 10 | ], 11 | "version": "0.1.0", 12 | "dht": {}, 13 | "properties": null 14 | } -------------------------------------------------------------------------------- /dna/conductor-config.toml: -------------------------------------------------------------------------------- 1 | bridges = [] 2 | persistence_dir = '' 3 | ui_bundles = [] 4 | ui_interfaces = [] 5 | 6 | [[agents]] 7 | id = 'hc-run-agent' 8 | keystore_file = 'testAgent' 9 | name = 'testAgent' 10 | public_address = 'HcScjN8wBwrn3tuyg89aab3a69xsIgdzmX5P9537BqQZ5A7TEZu7qCY4Xzzjhma' 11 | test_agent = true 12 | 13 | [[dnas]] 14 | file = '/home/guillem/projects/holochain/learning-pathways/dna/dist/dna.dna.json' 15 | hash = 'QmdEvz12chBPBrpJB7KZDeh2waTArfuqmnMRrjtDxuQLUg' 16 | id = 'hc-run-dna' 17 | 18 | [[instances]] 19 | agent = 'hc-run-agent' 20 | dna = 'hc-run-dna' 21 | id = 'test-instance' 22 | 23 | [instances.storage] 24 | type = 'memory' 25 | 26 | [[interfaces]] 27 | admin = true 28 | id = 'websocket-interface' 29 | 30 | [[interfaces.instances]] 31 | id = 'test-instance' 32 | 33 | [interfaces.driver] 34 | port = 8888 35 | type = 'websocket' 36 | 37 | [logger] 38 | state_dump = true 39 | type = 'debug' 40 | 41 | [logger.rules] 42 | rules = [] 43 | 44 | [passphrase_service] 45 | type = 'cmd' 46 | 47 | [signals] 48 | consistency = false 49 | trace = false 50 | -------------------------------------------------------------------------------- /dna/test/index.js: -------------------------------------------------------------------------------- 1 | /// NB: The tryorama config patterns are still not quite stabilized. 2 | /// See the tryorama README [https://github.com/holochain/tryorama] 3 | /// for a potentially more accurate example 4 | 5 | 6 | const path = require("path"); 7 | 8 | const { 9 | Orchestrator, 10 | Config, 11 | combine, 12 | singleConductor, 13 | localOnly, 14 | tapeExecutor 15 | } = require("@holochain/tryorama"); 16 | 17 | process.on("unhandledRejection", error => { 18 | // Will print "unhandledRejection err is not defined" 19 | console.error("got unhandledRejection:", error); 20 | }); 21 | 22 | const dnaPath = path.join(__dirname, "../dist/dna.dna.json"); 23 | 24 | const orchestrator = new Orchestrator({ 25 | middleware: combine( 26 | tapeExecutor(require("tape")), 27 | localOnly 28 | ) 29 | }); 30 | 31 | const dna = Config.dna(dnaPath, "course_dna"); 32 | const conductorConfig = Config.gen( 33 | { course_dna: dna }, 34 | { 35 | network: { 36 | type: "sim2h", 37 | sim2h_url: "ws://localhost:9000" 38 | }, 39 | logger: Config.logger({ type: "error" }), 40 | } 41 | ); 42 | 43 | 44 | orchestrator.registerScenario("Write you scenario here", async (s, t) => { 45 | const { alice, bob } = await s.players( 46 | { alice: conductorConfig, bob: conductorConfig }, 47 | true 48 | ); 49 | 50 | const course_addr_1 = await alice.call( 51 | "course_dna", 52 | "courses", 53 | "create_course", 54 | { 55 | title: "course for scenario 5-1", 56 | timestamp: 123 57 | } 58 | ); 59 | 60 | console.log(course_addr_1); 61 | t.ok(course_addr_1.Ok); 62 | await s.consistency(); 63 | 64 | const course_addr_2 = await alice.call( 65 | "course_dna", 66 | "courses", 67 | "create_course", 68 | { 69 | title: "course for scenario 5-2", 70 | timestamp: 1234 71 | } 72 | ); 73 | console.log(course_addr_2); 74 | t.ok(course_addr_2.Ok); 75 | await s.consistency(); 76 | 77 | const all_courses_alice = await alice.call("course_dna", "courses", "get_my_courses", { 78 | }); 79 | 80 | t.true(all_courses_alice.Ok[0] != null); 81 | t.true(all_courses_alice.Ok[1] != null); 82 | 83 | const all_courses_bob = await bob.call("course_dna", "courses", "get_all_courses", { 84 | }); 85 | t.true(all_courses_alice.Ok[0] != null); 86 | t.true(all_courses_alice.Ok[1] != null); 87 | 88 | await s.consistency(); 89 | 90 | }); 91 | 92 | 93 | /* 94 | orchestrator.registerScenario("Scenario1: Create new course", async (s, t) => { 95 | const { alice, bob } = await s.players( 96 | { alice: conductorConfig, bob: conductorConfig }, 97 | true 98 | ); 99 | const course_addr = await alice.call( 100 | "course_dna", 101 | "courses", 102 | "create_course", 103 | { 104 | title: "course test 1" 105 | , timestamp: 123 106 | } 107 | ); 108 | console.log(course_addr); 109 | t.ok(course_addr.Ok); 110 | 111 | await s.consistency(); 112 | 113 | const courseResult = await bob.call("course_dna", "courses", "get_entry", { 114 | address: course_addr.Ok 115 | }); 116 | const course = JSON.parse(courseResult.Ok.App[1]); 117 | console.log(course); 118 | t.deepEqual(course, { 119 | title: "course test 1", 120 | timestamp: 123, 121 | teacher_address: alice.instance("course_dna").agentAddress, 122 | modules: [] 123 | }); 124 | // Wait for all network activity to settle 125 | await s.consistency(); 126 | }); 127 | orchestrator.registerScenario("Scenario2: Update course title", async (s, t) => { 128 | const { alice, bob } = await s.players( 129 | { alice: conductorConfig, bob: conductorConfig }, 130 | true 131 | ); 132 | const course_addr = await alice.call( 133 | "course_dna", 134 | "courses", 135 | "create_course", 136 | { 137 | title: "new course test for update test" 138 | , timestamp: 123 139 | } 140 | ); 141 | 142 | const course_update_addrss = await alice.call( 143 | "course_dna", 144 | "courses", 145 | "update_course", 146 | { 147 | title: "course title updated", 148 | course_address: course_addr.Ok, 149 | modules_addresses: [], 150 | timestamp: 123 151 | 152 | } 153 | ); 154 | 155 | 156 | 157 | const courseResult = await bob.call("course_dna", "courses", "get_entry", { 158 | address: course_update_addrss.Ok 159 | }); 160 | 161 | const course = JSON.parse(courseResult.Ok.App[1]); 162 | console.log(course); 163 | t.deepEqual(course, { 164 | title: "course title updated", 165 | timestamp: 123, 166 | teacher_address: alice.instance("course_dna").agentAddress, 167 | modules: [] 168 | }); 169 | 170 | 171 | 172 | }); 173 | orchestrator.registerScenario("Scenario3: Delete course", async (s, t) => { 174 | const { alice, bob } = await s.players( 175 | { alice: conductorConfig, bob: conductorConfig }, 176 | true 177 | ); 178 | const course_addr = await alice.call( 179 | "course_dna", 180 | "courses", 181 | "create_course", 182 | { 183 | title: "new course test for delete scenario" 184 | , timestamp: 123 185 | } 186 | ); 187 | await s.consistency(); 188 | 189 | const delete_result = await alice.call( 190 | "course_dna", 191 | "courses", 192 | "delete_course", 193 | { 194 | course_address: course_addr.Ok, 195 | } 196 | ); 197 | await s.consistency(); 198 | 199 | t.ok(delete_result.Ok); 200 | 201 | const courseResult = await bob.call("course_dna", "courses", "get_entry", { 202 | address: delete_result.Ok 203 | }); 204 | t.deepEqual(courseResult.Ok.Deletion.deleted_entry_address, course_addr.Ok); 205 | await s.consistency(); 206 | 207 | }); 208 | 209 | orchestrator.registerScenario("Scenario4: Create new Module for a Course", async (s, t) => { 210 | const { alice, bob } = await s.players( 211 | { alice: conductorConfig, bob: conductorConfig }, 212 | true 213 | ); 214 | const course_addr = await alice.call( 215 | "course_dna", 216 | "courses", 217 | "create_course", 218 | { 219 | title: "course for scenario 4" 220 | , timestamp: 123 221 | } 222 | ); 223 | console.log(course_addr); 224 | t.ok(course_addr.Ok); 225 | 226 | await s.consistency(); 227 | // Alice can create a module for course because she is the owner 228 | const new_module_addr = await alice.call("course_dna", "courses", "create_module", { 229 | title: "module 1 for course 1", 230 | course_address: course_addr.Ok, 231 | timestamp: 456 232 | }); 233 | 234 | console.log(new_module_addr); 235 | t.ok(new_module_addr.Ok); 236 | await s.consistency(); 237 | 238 | // Bob can not create a module for course, because he is not the owner of course 239 | const fail_add_module_addr = await bob.call("course_dna", "courses", "create_module", { 240 | title: "module 1 for course 1 by bob", 241 | course_address: course_addr.Ok, 242 | timestamp: 980 243 | }); 244 | 245 | t.error(fail_add_module_addr.Ok); 246 | await s.consistency(); 247 | 248 | const moduleResult = await alice.call("course_dna", "courses", "get_entry", { 249 | address: new_module_addr.Ok 250 | }); 251 | const module = JSON.parse(moduleResult.Ok.App[1]); 252 | console.log(module); 253 | t.deepEqual(module, { 254 | title: "module 1 for course 1", 255 | course_address: course_addr.Ok, 256 | timestamp: 456 257 | }); 258 | await s.consistency(); 259 | }); 260 | 261 | 262 | orchestrator.registerScenario("Scenario5: Get All My Courses", async (s, t) => { 263 | const { alice, bob } = await s.players( 264 | { alice: conductorConfig, bob: conductorConfig }, 265 | true 266 | ); 267 | const course_addr_1 = await alice.call( 268 | "course_dna", 269 | "courses", 270 | "create_course", 271 | { 272 | title: "course for scenario 5-1", 273 | timestamp: 123 274 | } 275 | ); 276 | console.log(course_addr_1); 277 | t.ok(course_addr_1.Ok); 278 | 279 | await s.consistency(); 280 | 281 | const course_addr_2 = await alice.call( 282 | "course_dna", 283 | "courses", 284 | "create_course", 285 | { 286 | title: "course for scenario 5-2", 287 | timestamp: 1234 288 | } 289 | ); 290 | console.log(course_addr_2); 291 | t.ok(course_addr_2.Ok); 292 | 293 | await s.consistency(); 294 | 295 | 296 | const all_courses_alice = await alice.call("course_dna", "courses", "get_my_courses", { 297 | }); 298 | t.true(all_courses_alice.Ok[0] != null); 299 | t.true(all_courses_alice.Ok[1] != null); 300 | 301 | const all_courses_bob = await bob.call("course_dna", "courses", "get_my_courses", { 302 | }); 303 | t.true(all_courses_bob.Ok[0] == null); 304 | 305 | await s.consistency(); 306 | 307 | }); 308 | 309 | 310 | 311 | orchestrator.registerScenario("Scenario6: Create new Content for a Module", async (s, t) => { 312 | const { alice, bob } = await s.players( 313 | { alice: conductorConfig, bob: conductorConfig }, 314 | true 315 | ); 316 | const course_addr = await alice.call( 317 | "course_dna", 318 | "courses", 319 | "create_course", 320 | { 321 | title: "course for scenario 5" 322 | , timestamp: 123 323 | } 324 | ); 325 | console.log(course_addr); 326 | t.ok(course_addr.Ok); 327 | 328 | await s.consistency(); 329 | const module_addr = await alice.call("course_dna", "courses", "create_module", { 330 | title: "module 1 for course 1", 331 | course_address: course_addr.Ok, 332 | timestamp: 456 333 | }); 334 | 335 | console.log(module_addr); 336 | t.ok(module_addr.Ok); 337 | await s.consistency(); 338 | 339 | const content_addr = await alice.call("course_dna", "courses", "create_content", { 340 | name: "content 1 for module 1", 341 | url: "https://youtube.com", 342 | descritpion: "Holochain Intro", 343 | module_address: module_addr.Ok, 344 | timestamp: 789 345 | }); 346 | 347 | console.log(content_addr); 348 | t.ok(content_addr.Ok); 349 | await s.consistency(); 350 | }); 351 | 352 | 353 | 354 | orchestrator.registerScenario("Scenario7: Get all contents of a module", async (s, t) => { 355 | const { alice, bob } = await s.players( 356 | { alice: conductorConfig, bob: conductorConfig }, 357 | true 358 | ); 359 | const course_addr = await alice.call( 360 | "course_dna", 361 | "courses", 362 | "create_course", 363 | { 364 | title: "course for scenario 5" 365 | , timestamp: 123 366 | } 367 | ); 368 | console.log(course_addr); 369 | t.ok(course_addr.Ok); 370 | 371 | await s.consistency(); 372 | // Alice can create a module for course because she is the owner 373 | const module_addr = await alice.call("course_dna", "courses", "create_module", { 374 | title: "module 1 for course 1", 375 | course_address: course_addr.Ok, 376 | timestamp: 456 377 | }); 378 | 379 | console.log(module_addr); 380 | t.ok(module_addr.Ok); 381 | await s.consistency(); 382 | 383 | const content_addr_1 = await alice.call("course_dna", "courses", "create_content", { 384 | name: "content 1 for module 1", 385 | url: "https://youtube.com", 386 | descritpion: "Holochain Intro-Video", 387 | module_address: module_addr.Ok, 388 | timestamp: 7891 389 | }); 390 | 391 | console.log(content_addr_1); 392 | t.ok(content_addr_1.Ok); 393 | await s.consistency(); 394 | 395 | 396 | const content_addr_2 = await alice.call("course_dna", "courses", "create_content", { 397 | name: "content 2 for module 1", 398 | url: "https://soundclould.com", 399 | descritpion: "Holochain Intro-Sound", 400 | module_address: module_addr.Ok, 401 | timestamp: 7892 402 | }); 403 | 404 | console.log(content_addr_2); 405 | t.ok(content_addr_2.Ok); 406 | await s.consistency(); 407 | 408 | 409 | const all_contents_of_module_1 = await alice.call("course_dna", "courses", "get_contents", { 410 | module_address: module_addr.Ok 411 | }); 412 | 413 | t.true(all_contents_of_module_1.Ok[0] != null); 414 | t.true(all_contents_of_module_1.Ok[1] != null); 415 | 416 | await s.consistency(); 417 | }); 418 | 419 | 420 | 421 | orchestrator.registerScenario("Scenario8: delete content from module", async (s, t) => { 422 | const { alice, bob } = await s.players( 423 | { alice: conductorConfig, bob: conductorConfig }, 424 | true 425 | ); 426 | const course_addr = await alice.call( 427 | "course_dna", 428 | "courses", 429 | "create_course", 430 | { 431 | title: "course for scenario 5" 432 | , timestamp: 123 433 | } 434 | ); 435 | console.log(course_addr); 436 | t.ok(course_addr.Ok); 437 | 438 | await s.consistency(); 439 | // Alice can create a module for course because she is the owner 440 | const module_addr = await alice.call("course_dna", "courses", "create_module", { 441 | title: "module 1 for course 1", 442 | course_address: course_addr.Ok, 443 | timestamp: 456 444 | }); 445 | 446 | console.log(module_addr); 447 | t.ok(module_addr.Ok); 448 | await s.consistency(); 449 | 450 | const content_addr_1 = await alice.call("course_dna", "courses", "create_content", { 451 | name: "content 1 for module 1", 452 | url: "https://youtube.com", 453 | descritpion: "Holochain Intro-Video", 454 | module_address: module_addr.Ok, 455 | timestamp: 7891 456 | }); 457 | 458 | console.log(content_addr_1); 459 | t.ok(content_addr_1.Ok); 460 | await s.consistency(); 461 | 462 | 463 | const content_addr_2 = await alice.call("course_dna", "courses", "create_content", { 464 | name: "content 2 for module 1", 465 | url: "https://soundclould.com", 466 | descritpion: "Holochain Intro-Sound", 467 | module_address: module_addr.Ok, 468 | timestamp: 7892 469 | }); 470 | 471 | console.log(content_addr_2); 472 | t.ok(content_addr_2.Ok); 473 | await s.consistency(); 474 | 475 | 476 | const all_contents_of_module_1 = await alice.call("course_dna", "courses", "get_contents", { 477 | module_address: module_addr.Ok 478 | }); 479 | 480 | t.true(all_contents_of_module_1.Ok[0] != null); 481 | t.true(all_contents_of_module_1.Ok[1] != null); 482 | await s.consistency(); 483 | 484 | const delete_content = await alice.call("course_dna", "courses", "delete_content", { 485 | content_address: content_addr_1.Ok 486 | }); 487 | console.log("Hedayat_abedijoo_"); 488 | console.log(delete_content); 489 | t.ok(delete_content.Ok); 490 | 491 | await s.consistency(); 492 | 493 | // const all_contents_of_module_1_again = await alice.call("course_dna", "courses", "get_contents", { 494 | // module_address: module_addr.Ok 495 | // }); 496 | 497 | // t.true(all_contents_of_module_1.Ok[0] != null); 498 | // t.true(all_contents_of_module_1.Ok[1] == null); 499 | 500 | await s.consistency(); 501 | }); 502 | */ 503 | 504 | orchestrator.registerScenario( 505 | "Scenario9: delete module from course, Testing bug scenario", 506 | async (s, t) => { 507 | const { alice, bob } = await s.players( 508 | { alice: conductorConfig, bob: conductorConfig }, 509 | true 510 | ); 511 | const course_addr = await alice.call( 512 | "course_dna", 513 | "courses", 514 | "create_course", 515 | { 516 | title: "course for scenario 9: debugging purpose", 517 | timestamp: 123 518 | } 519 | ); 520 | console.log("Hedayat_abedijoo_course_addr"); 521 | console.log(course_addr); 522 | t.ok(course_addr.Ok); 523 | 524 | await s.consistency(); 525 | // Alice can create a module for course because she is the owner 526 | const module_addr = await alice.call( 527 | "course_dna", 528 | "courses", 529 | "create_module", 530 | { 531 | title: "module 1 for course 1", 532 | course_address: course_addr.Ok, 533 | timestamp: 456 534 | } 535 | ); 536 | 537 | console.log(module_addr); 538 | t.ok(module_addr.Ok); 539 | await s.consistency(); 540 | 541 | const delete_moduel = await alice.call( 542 | "course_dna", 543 | "courses", 544 | "delete_module", 545 | { 546 | module_address: module_addr.Ok 547 | } 548 | ); 549 | console.log(delete_moduel); 550 | t.ok(delete_moduel.Ok); 551 | await s.consistency(); 552 | 553 | const courseResult = await alice.call( 554 | "course_dna", 555 | "courses", 556 | "get_my_courses", 557 | { 558 | // address: course_addr.Ok 559 | } 560 | ); 561 | console.log("Hedayat_abedijoo_getmycourse"); 562 | console.log(courseResult.Ok); 563 | //t.deepEqual(course_addr.Ok, courseResult.Ok[0]); 564 | await s.consistency(); 565 | 566 | console.log("Hedayat_abedijoo_getentry"); 567 | const course_again = await alice.call( 568 | "course_dna", 569 | "courses", 570 | "get_entry", 571 | { 572 | address: course_addr.Ok 573 | } 574 | ); 575 | console.log(course_again.Ok); 576 | await s.consistency(); 577 | 578 | // const content_addr_1 = await alice.call("course_dna", "courses", "create_content", { 579 | // name: "content 1 for module 1", 580 | // url: "https://youtube.com", 581 | // descritpion: "Holochain Intro-Video", 582 | // module_address: module_addr.Ok, 583 | // timestamp: 7891 584 | // }); 585 | 586 | // console.log(content_addr_1); 587 | // t.ok(content_addr_1.Ok); 588 | // await s.consistency(); 589 | 590 | // const content_addr_2 = await alice.call("course_dna", "courses", "create_content", { 591 | // name: "content 2 for module 1", 592 | // url: "https://soundclould.com", 593 | // descritpion: "Holochain Intro-Sound", 594 | // module_address: module_addr.Ok, 595 | // timestamp: 7892 596 | // }); 597 | 598 | // console.log(content_addr_2); 599 | // t.ok(content_addr_2.Ok); 600 | // await s.consistency(); 601 | 602 | // const all_contents_of_module_1 = await alice.call("course_dna", "courses", "get_contents", { 603 | // module_address: module_addr.Ok 604 | // }); 605 | 606 | // t.true(all_contents_of_module_1.Ok[0] != null); 607 | // t.true(all_contents_of_module_1.Ok[1] != null); 608 | // await s.consistency(); 609 | 610 | // const delete_content = await alice.call("course_dna", "courses", "delete_content", { 611 | // content_address: content_addr_1.Ok 612 | // }); 613 | // console.log("Hedayat_abedijoo_"); 614 | // console.log(delete_content); 615 | // t.ok(delete_content.Ok); 616 | 617 | // await s.consistency(); 618 | 619 | // const all_contents_of_module_1_again = await alice.call("course_dna", "courses", "get_contents", { 620 | // module_address: module_addr.Ok 621 | // }); 622 | 623 | // t.true(all_contents_of_module_1.Ok[0] != null); 624 | // t.true(all_contents_of_module_1.Ok[1] == null); 625 | 626 | await s.consistency(); 627 | } 628 | ); 629 | 630 | orchestrator.run(); -------------------------------------------------------------------------------- /dna/test/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "requires": true, 3 | "lockfileVersion": 1, 4 | "dependencies": { 5 | "101": { 6 | "version": "1.6.3", 7 | "resolved": "https://registry.npmjs.org/101/-/101-1.6.3.tgz", 8 | "integrity": "sha512-4dmQ45yY0Dx24Qxp+zAsNLlMF6tteCyfVzgbulvSyC7tCyd3V8sW76sS0tHq8NpcbXfWTKasfyfzU1Kd86oKzw==", 9 | "requires": { 10 | "clone": "^1.0.2", 11 | "deep-eql": "^0.1.3", 12 | "keypather": "^1.10.2" 13 | } 14 | }, 15 | "@babel/runtime": { 16 | "version": "7.8.4", 17 | "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.8.4.tgz", 18 | "integrity": "sha512-neAp3zt80trRVBI1x0azq6c57aNBqYZH8KhMm3TaB7wEI5Q4A2SHfBHE8w9gOhI/lrqxtEbXZgQIrHP+wvSGwQ==", 19 | "requires": { 20 | "regenerator-runtime": "^0.13.2" 21 | } 22 | }, 23 | "@holochain/hachiko": { 24 | "version": "0.5.1", 25 | "resolved": "https://registry.npmjs.org/@holochain/hachiko/-/hachiko-0.5.1.tgz", 26 | "integrity": "sha512-4qY8mNaOZ/YVXdeeuYVOHcA6tXpksxGA64qHILnO/BHxqNt4q8KOUlIYJQYB/wCddGz+DzYU0k+/v5475O2dqA==", 27 | "requires": { 28 | "colors": "^1.3.3", 29 | "lodash": "^4.17.15", 30 | "winston": "^3.2.1", 31 | "winston-null": "^2.0.0" 32 | } 33 | }, 34 | "@holochain/hc-web-client": { 35 | "version": "0.5.1", 36 | "resolved": "https://registry.npmjs.org/@holochain/hc-web-client/-/hc-web-client-0.5.1.tgz", 37 | "integrity": "sha512-4MFtu/G/PZksj4ouzldJ3SQrllE7108u96ZU92C1iJxlxsyvnSli4MSyTpEolnT5KsW9bNF4pzGTIgam/3V8/A==", 38 | "requires": { 39 | "isomorphic-fetch": "^2.2.1", 40 | "rpc-websockets": "^4.3.3" 41 | } 42 | }, 43 | "@holochain/tryorama": { 44 | "version": "0.3.1", 45 | "resolved": "https://registry.npmjs.org/@holochain/tryorama/-/tryorama-0.3.1.tgz", 46 | "integrity": "sha512-DGeUZkh+OCR8/l9hvpJLqqJeakK5Ujs4mEi/7vz1BuBfFwSNfxRhr7029qljMgE5uUg4m7UKCWauBHUyBcF7JA==", 47 | "requires": { 48 | "@holochain/hachiko": "^0.5.1", 49 | "@holochain/hc-web-client": "^0.5.0", 50 | "@iarna/toml": "^2.2.3", 51 | "async-mutex": "^0.1.4", 52 | "axios": "^0.19.0", 53 | "base-64": "^0.1.0", 54 | "colors": "^1.3.3", 55 | "fp-ts": "^2.0.5", 56 | "get-port": "^5.0.0", 57 | "io-ts": "^2.0.1", 58 | "io-ts-reporters": "^1.0.0", 59 | "lodash": "^4.17.15", 60 | "memoizee": "^0.4.14", 61 | "ramda": "^0.26.1", 62 | "uuid": "^3.3.3", 63 | "winston": "^3.2.1" 64 | } 65 | }, 66 | "@iarna/toml": { 67 | "version": "2.2.3", 68 | "resolved": "https://registry.npmjs.org/@iarna/toml/-/toml-2.2.3.tgz", 69 | "integrity": "sha512-FmuxfCuolpLl0AnQ2NHSzoUKWEJDFl63qXjzdoWBVyFCXzMGm1spBzk7LeHNoVCiWCF7mRVms9e6jEV9+MoPbg==" 70 | }, 71 | "assert-args": { 72 | "version": "1.2.1", 73 | "resolved": "https://registry.npmjs.org/assert-args/-/assert-args-1.2.1.tgz", 74 | "integrity": "sha1-QEEDoUUqMv53iYgR5U5ZCoqTc70=", 75 | "requires": { 76 | "101": "^1.2.0", 77 | "compound-subject": "0.0.1", 78 | "debug": "^2.2.0", 79 | "get-prototype-of": "0.0.0", 80 | "is-capitalized": "^1.0.0", 81 | "is-class": "0.0.4" 82 | } 83 | }, 84 | "async": { 85 | "version": "2.6.3", 86 | "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", 87 | "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", 88 | "requires": { 89 | "lodash": "^4.17.14" 90 | } 91 | }, 92 | "async-limiter": { 93 | "version": "1.0.1", 94 | "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", 95 | "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" 96 | }, 97 | "async-mutex": { 98 | "version": "0.1.4", 99 | "resolved": "https://registry.npmjs.org/async-mutex/-/async-mutex-0.1.4.tgz", 100 | "integrity": "sha512-zVWTmAnxxHaeB2B1te84oecI8zTDJ/8G49aVBblRX6be0oq6pAybNcUSxwfgVOmOjSCvN4aYZAqwtyNI8e1YGw==" 101 | }, 102 | "axios": { 103 | "version": "0.19.2", 104 | "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz", 105 | "integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==", 106 | "requires": { 107 | "follow-redirects": "1.5.10" 108 | } 109 | }, 110 | "babel-runtime": { 111 | "version": "6.26.0", 112 | "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", 113 | "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", 114 | "requires": { 115 | "core-js": "^2.4.0", 116 | "regenerator-runtime": "^0.11.0" 117 | }, 118 | "dependencies": { 119 | "regenerator-runtime": { 120 | "version": "0.11.1", 121 | "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", 122 | "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" 123 | } 124 | } 125 | }, 126 | "balanced-match": { 127 | "version": "1.0.0", 128 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 129 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" 130 | }, 131 | "base-64": { 132 | "version": "0.1.0", 133 | "resolved": "https://registry.npmjs.org/base-64/-/base-64-0.1.0.tgz", 134 | "integrity": "sha1-eAqZyE59YAJgNhURxId2E78k9rs=" 135 | }, 136 | "brace-expansion": { 137 | "version": "1.1.11", 138 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 139 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 140 | "requires": { 141 | "balanced-match": "^1.0.0", 142 | "concat-map": "0.0.1" 143 | } 144 | }, 145 | "circular-json": { 146 | "version": "0.5.9", 147 | "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.5.9.tgz", 148 | "integrity": "sha512-4ivwqHpIFJZBuhN3g/pEcdbnGUywkBblloGbkglyloVjjR3uT6tieI89MVOfbP2tHX5sgb01FuLgAOzebNlJNQ==" 149 | }, 150 | "clone": { 151 | "version": "1.0.4", 152 | "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", 153 | "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=" 154 | }, 155 | "color": { 156 | "version": "3.0.0", 157 | "resolved": "https://registry.npmjs.org/color/-/color-3.0.0.tgz", 158 | "integrity": "sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w==", 159 | "requires": { 160 | "color-convert": "^1.9.1", 161 | "color-string": "^1.5.2" 162 | } 163 | }, 164 | "color-convert": { 165 | "version": "1.9.3", 166 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 167 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 168 | "requires": { 169 | "color-name": "1.1.3" 170 | } 171 | }, 172 | "color-name": { 173 | "version": "1.1.3", 174 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 175 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" 176 | }, 177 | "color-string": { 178 | "version": "1.5.3", 179 | "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.3.tgz", 180 | "integrity": "sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw==", 181 | "requires": { 182 | "color-name": "^1.0.0", 183 | "simple-swizzle": "^0.2.2" 184 | } 185 | }, 186 | "colornames": { 187 | "version": "1.1.1", 188 | "resolved": "https://registry.npmjs.org/colornames/-/colornames-1.1.1.tgz", 189 | "integrity": "sha1-+IiQMGhcfE/54qVZ9Qd+t2qBb5Y=" 190 | }, 191 | "colors": { 192 | "version": "1.4.0", 193 | "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", 194 | "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==" 195 | }, 196 | "colorspace": { 197 | "version": "1.1.2", 198 | "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.2.tgz", 199 | "integrity": "sha512-vt+OoIP2d76xLhjwbBaucYlNSpPsrJWPlBTtwCpQKIu6/CSMutyzX93O/Do0qzpH3YoHEes8YEFXyZ797rEhzQ==", 200 | "requires": { 201 | "color": "3.0.x", 202 | "text-hex": "1.0.x" 203 | } 204 | }, 205 | "compound-subject": { 206 | "version": "0.0.1", 207 | "resolved": "https://registry.npmjs.org/compound-subject/-/compound-subject-0.0.1.tgz", 208 | "integrity": "sha1-JxVUaYoVrmCLHfyv0wt7oeqJLEs=" 209 | }, 210 | "concat-map": { 211 | "version": "0.0.1", 212 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 213 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" 214 | }, 215 | "core-js": { 216 | "version": "2.6.11", 217 | "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.11.tgz", 218 | "integrity": "sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==" 219 | }, 220 | "core-util-is": { 221 | "version": "1.0.2", 222 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 223 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" 224 | }, 225 | "cycle": { 226 | "version": "1.0.3", 227 | "resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz", 228 | "integrity": "sha1-IegLK+hYD5i0aPN5QwZisEbDStI=" 229 | }, 230 | "d": { 231 | "version": "1.0.1", 232 | "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", 233 | "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", 234 | "requires": { 235 | "es5-ext": "^0.10.50", 236 | "type": "^1.0.1" 237 | } 238 | }, 239 | "debug": { 240 | "version": "2.6.9", 241 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 242 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 243 | "requires": { 244 | "ms": "2.0.0" 245 | }, 246 | "dependencies": { 247 | "ms": { 248 | "version": "2.0.0", 249 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 250 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 251 | } 252 | } 253 | }, 254 | "deep-eql": { 255 | "version": "0.1.3", 256 | "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-0.1.3.tgz", 257 | "integrity": "sha1-71WKyrjeJSBs1xOQbXTlaTDrafI=", 258 | "requires": { 259 | "type-detect": "0.1.1" 260 | } 261 | }, 262 | "deep-equal": { 263 | "version": "0.1.2", 264 | "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-0.1.2.tgz", 265 | "integrity": "sha1-skbCuApXCkfBG+HZvRBw7IeLh84=" 266 | }, 267 | "define-properties": { 268 | "version": "1.1.3", 269 | "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", 270 | "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", 271 | "requires": { 272 | "object-keys": "^1.0.12" 273 | }, 274 | "dependencies": { 275 | "object-keys": { 276 | "version": "1.1.1", 277 | "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", 278 | "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" 279 | } 280 | } 281 | }, 282 | "defined": { 283 | "version": "0.0.0", 284 | "resolved": "https://registry.npmjs.org/defined/-/defined-0.0.0.tgz", 285 | "integrity": "sha1-817qfXBekzuvE7LwOz+D2SFAOz4=" 286 | }, 287 | "diagnostics": { 288 | "version": "1.1.1", 289 | "resolved": "https://registry.npmjs.org/diagnostics/-/diagnostics-1.1.1.tgz", 290 | "integrity": "sha512-8wn1PmdunLJ9Tqbx+Fx/ZEuHfJf4NKSN2ZBj7SJC/OWRWha843+WsTjqMe1B5E3p28jqBlp+mJ2fPVxPyNgYKQ==", 291 | "requires": { 292 | "colorspace": "1.1.x", 293 | "enabled": "1.0.x", 294 | "kuler": "1.0.x" 295 | } 296 | }, 297 | "dotignore": { 298 | "version": "0.1.2", 299 | "resolved": "https://registry.npmjs.org/dotignore/-/dotignore-0.1.2.tgz", 300 | "integrity": "sha512-UGGGWfSauusaVJC+8fgV+NVvBXkCTmVv7sk6nojDZZvuOUNGUy0Zk4UpHQD6EDjS0jpBwcACvH4eofvyzBcRDw==", 301 | "requires": { 302 | "minimatch": "^3.0.4" 303 | } 304 | }, 305 | "duplexer": { 306 | "version": "0.1.1", 307 | "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", 308 | "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=" 309 | }, 310 | "enabled": { 311 | "version": "1.0.2", 312 | "resolved": "https://registry.npmjs.org/enabled/-/enabled-1.0.2.tgz", 313 | "integrity": "sha1-ll9lE9LC0cX0ZStkouM5ZGf8L5M=", 314 | "requires": { 315 | "env-variable": "0.0.x" 316 | } 317 | }, 318 | "encoding": { 319 | "version": "0.1.12", 320 | "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", 321 | "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", 322 | "requires": { 323 | "iconv-lite": "~0.4.13" 324 | } 325 | }, 326 | "env-variable": { 327 | "version": "0.0.6", 328 | "resolved": "https://registry.npmjs.org/env-variable/-/env-variable-0.0.6.tgz", 329 | "integrity": "sha512-bHz59NlBbtS0NhftmR8+ExBEekE7br0e01jw+kk0NDro7TtZzBYZ5ScGPs3OmwnpyfHTHOtr1Y6uedCdrIldtg==" 330 | }, 331 | "es-abstract": { 332 | "version": "1.17.4", 333 | "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.4.tgz", 334 | "integrity": "sha512-Ae3um/gb8F0mui/jPL+QiqmglkUsaQf7FwBEHYIFkztkneosu9imhqHpBzQ3h1vit8t5iQ74t6PEVvphBZiuiQ==", 335 | "requires": { 336 | "es-to-primitive": "^1.2.1", 337 | "function-bind": "^1.1.1", 338 | "has": "^1.0.3", 339 | "has-symbols": "^1.0.1", 340 | "is-callable": "^1.1.5", 341 | "is-regex": "^1.0.5", 342 | "object-inspect": "^1.7.0", 343 | "object-keys": "^1.1.1", 344 | "object.assign": "^4.1.0", 345 | "string.prototype.trimleft": "^2.1.1", 346 | "string.prototype.trimright": "^2.1.1" 347 | }, 348 | "dependencies": { 349 | "object-keys": { 350 | "version": "1.1.1", 351 | "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", 352 | "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" 353 | } 354 | } 355 | }, 356 | "es-to-primitive": { 357 | "version": "1.2.1", 358 | "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", 359 | "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", 360 | "requires": { 361 | "is-callable": "^1.1.4", 362 | "is-date-object": "^1.0.1", 363 | "is-symbol": "^1.0.2" 364 | } 365 | }, 366 | "es5-ext": { 367 | "version": "0.10.53", 368 | "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz", 369 | "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==", 370 | "requires": { 371 | "es6-iterator": "~2.0.3", 372 | "es6-symbol": "~3.1.3", 373 | "next-tick": "~1.0.0" 374 | } 375 | }, 376 | "es6-iterator": { 377 | "version": "2.0.3", 378 | "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", 379 | "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", 380 | "requires": { 381 | "d": "1", 382 | "es5-ext": "^0.10.35", 383 | "es6-symbol": "^3.1.1" 384 | } 385 | }, 386 | "es6-symbol": { 387 | "version": "3.1.3", 388 | "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", 389 | "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", 390 | "requires": { 391 | "d": "^1.0.1", 392 | "ext": "^1.1.2" 393 | } 394 | }, 395 | "es6-weak-map": { 396 | "version": "2.0.3", 397 | "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", 398 | "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", 399 | "requires": { 400 | "d": "1", 401 | "es5-ext": "^0.10.46", 402 | "es6-iterator": "^2.0.3", 403 | "es6-symbol": "^3.1.1" 404 | } 405 | }, 406 | "event-emitter": { 407 | "version": "0.3.5", 408 | "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", 409 | "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", 410 | "requires": { 411 | "d": "1", 412 | "es5-ext": "~0.10.14" 413 | } 414 | }, 415 | "eventemitter3": { 416 | "version": "3.1.2", 417 | "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz", 418 | "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==" 419 | }, 420 | "ext": { 421 | "version": "1.4.0", 422 | "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz", 423 | "integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==", 424 | "requires": { 425 | "type": "^2.0.0" 426 | }, 427 | "dependencies": { 428 | "type": { 429 | "version": "2.0.0", 430 | "resolved": "https://registry.npmjs.org/type/-/type-2.0.0.tgz", 431 | "integrity": "sha512-KBt58xCHry4Cejnc2ISQAF7QY+ORngsWfxezO68+12hKV6lQY8P/psIkcbjeHWn7MqcgciWJyCCevFMJdIXpow==" 432 | } 433 | } 434 | }, 435 | "fast-safe-stringify": { 436 | "version": "2.0.7", 437 | "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz", 438 | "integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==" 439 | }, 440 | "faucet": { 441 | "version": "0.0.1", 442 | "resolved": "https://registry.npmjs.org/faucet/-/faucet-0.0.1.tgz", 443 | "integrity": "sha1-WX3PHSGJosBiMhtZHo8VHtIDnZw=", 444 | "requires": { 445 | "defined": "0.0.0", 446 | "duplexer": "~0.1.1", 447 | "minimist": "0.0.5", 448 | "sprintf": "~0.1.3", 449 | "tap-parser": "~0.4.0", 450 | "tape": "~2.3.2", 451 | "through2": "~0.2.3" 452 | }, 453 | "dependencies": { 454 | "tape": { 455 | "version": "2.3.3", 456 | "resolved": "https://registry.npmjs.org/tape/-/tape-2.3.3.tgz", 457 | "integrity": "sha1-Lnzgox3wn41oUWZKcYQuDKUFevc=", 458 | "requires": { 459 | "deep-equal": "~0.1.0", 460 | "defined": "~0.0.0", 461 | "inherits": "~2.0.1", 462 | "jsonify": "~0.0.0", 463 | "resumer": "~0.0.0", 464 | "through": "~2.3.4" 465 | } 466 | } 467 | } 468 | }, 469 | "fecha": { 470 | "version": "2.3.3", 471 | "resolved": "https://registry.npmjs.org/fecha/-/fecha-2.3.3.tgz", 472 | "integrity": "sha512-lUGBnIamTAwk4znq5BcqsDaxSmZ9nDVJaij6NvRt/Tg4R69gERA+otPKbS86ROw9nxVMw2/mp1fnaiWqbs6Sdg==" 473 | }, 474 | "follow-redirects": { 475 | "version": "1.5.10", 476 | "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", 477 | "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", 478 | "requires": { 479 | "debug": "=3.1.0" 480 | }, 481 | "dependencies": { 482 | "debug": { 483 | "version": "3.1.0", 484 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", 485 | "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", 486 | "requires": { 487 | "ms": "2.0.0" 488 | } 489 | }, 490 | "ms": { 491 | "version": "2.0.0", 492 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 493 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 494 | } 495 | } 496 | }, 497 | "for-each": { 498 | "version": "0.3.3", 499 | "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", 500 | "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", 501 | "requires": { 502 | "is-callable": "^1.1.3" 503 | } 504 | }, 505 | "fp-ts": { 506 | "version": "2.4.3", 507 | "resolved": "https://registry.npmjs.org/fp-ts/-/fp-ts-2.4.3.tgz", 508 | "integrity": "sha512-R/QwlxnRlboZIObqKjOUf8rkXz36uSWfJO2M5o2cqf7UiHoHlNMojr/PiUyj8j3l1fOP62dR6nsKvFaRSJBIaQ==" 509 | }, 510 | "fs.realpath": { 511 | "version": "1.0.0", 512 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 513 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" 514 | }, 515 | "function-bind": { 516 | "version": "1.1.1", 517 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 518 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" 519 | }, 520 | "get-port": { 521 | "version": "5.1.1", 522 | "resolved": "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz", 523 | "integrity": "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==" 524 | }, 525 | "get-prototype-of": { 526 | "version": "0.0.0", 527 | "resolved": "https://registry.npmjs.org/get-prototype-of/-/get-prototype-of-0.0.0.tgz", 528 | "integrity": "sha1-mHcr0QcW0W3rSzIlFsRp78oorEQ=" 529 | }, 530 | "glob": { 531 | "version": "7.1.6", 532 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", 533 | "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", 534 | "requires": { 535 | "fs.realpath": "^1.0.0", 536 | "inflight": "^1.0.4", 537 | "inherits": "2", 538 | "minimatch": "^3.0.4", 539 | "once": "^1.3.0", 540 | "path-is-absolute": "^1.0.0" 541 | } 542 | }, 543 | "has": { 544 | "version": "1.0.3", 545 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 546 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 547 | "requires": { 548 | "function-bind": "^1.1.1" 549 | } 550 | }, 551 | "has-symbols": { 552 | "version": "1.0.1", 553 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", 554 | "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==" 555 | }, 556 | "iconv-lite": { 557 | "version": "0.4.24", 558 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", 559 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", 560 | "requires": { 561 | "safer-buffer": ">= 2.1.2 < 3" 562 | } 563 | }, 564 | "inflight": { 565 | "version": "1.0.6", 566 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 567 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 568 | "requires": { 569 | "once": "^1.3.0", 570 | "wrappy": "1" 571 | } 572 | }, 573 | "inherits": { 574 | "version": "2.0.4", 575 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 576 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" 577 | }, 578 | "io-ts": { 579 | "version": "2.0.6", 580 | "resolved": "https://registry.npmjs.org/io-ts/-/io-ts-2.0.6.tgz", 581 | "integrity": "sha512-WNfGzm4csMVwL4hX6QlpQWu65SV6GmOUtDo259GKlLYH1cC5bpOENgYHqQIRJ9uR3FuU1RQKDke5STwHZAn3KA==" 582 | }, 583 | "io-ts-reporters": { 584 | "version": "1.0.0", 585 | "resolved": "https://registry.npmjs.org/io-ts-reporters/-/io-ts-reporters-1.0.0.tgz", 586 | "integrity": "sha512-jjMvTnFYYxX3ue3cajmqCAf7sM4+lFvaaUuAL+otJv2DE+WDxYvQeCcUYveoq37rVSftJHZBEOrnvz3x0VdRXA==", 587 | "requires": { 588 | "fp-ts": "^2.0.2", 589 | "io-ts": "^2.0.0" 590 | } 591 | }, 592 | "is-arguments": { 593 | "version": "1.0.4", 594 | "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz", 595 | "integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==" 596 | }, 597 | "is-arrayish": { 598 | "version": "0.3.2", 599 | "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", 600 | "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" 601 | }, 602 | "is-callable": { 603 | "version": "1.1.5", 604 | "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", 605 | "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==" 606 | }, 607 | "is-capitalized": { 608 | "version": "1.0.0", 609 | "resolved": "https://registry.npmjs.org/is-capitalized/-/is-capitalized-1.0.0.tgz", 610 | "integrity": "sha1-TIRktNkdPk7rRIid0s2PGwrEwTY=" 611 | }, 612 | "is-class": { 613 | "version": "0.0.4", 614 | "resolved": "https://registry.npmjs.org/is-class/-/is-class-0.0.4.tgz", 615 | "integrity": "sha1-4FdFFwW7NOOePjNZjJOpg3KWtzY=" 616 | }, 617 | "is-date-object": { 618 | "version": "1.0.2", 619 | "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", 620 | "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==" 621 | }, 622 | "is-promise": { 623 | "version": "2.1.0", 624 | "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", 625 | "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=" 626 | }, 627 | "is-regex": { 628 | "version": "1.0.5", 629 | "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", 630 | "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", 631 | "requires": { 632 | "has": "^1.0.3" 633 | } 634 | }, 635 | "is-stream": { 636 | "version": "1.1.0", 637 | "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", 638 | "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" 639 | }, 640 | "is-symbol": { 641 | "version": "1.0.3", 642 | "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", 643 | "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", 644 | "requires": { 645 | "has-symbols": "^1.0.1" 646 | } 647 | }, 648 | "isarray": { 649 | "version": "1.0.0", 650 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 651 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" 652 | }, 653 | "isomorphic-fetch": { 654 | "version": "2.2.1", 655 | "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", 656 | "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=", 657 | "requires": { 658 | "node-fetch": "^1.0.1", 659 | "whatwg-fetch": ">=0.10.0" 660 | } 661 | }, 662 | "json3": { 663 | "version": "3.3.3", 664 | "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.3.tgz", 665 | "integrity": "sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA==" 666 | }, 667 | "jsonify": { 668 | "version": "0.0.0", 669 | "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", 670 | "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=" 671 | }, 672 | "keypather": { 673 | "version": "1.10.2", 674 | "resolved": "https://registry.npmjs.org/keypather/-/keypather-1.10.2.tgz", 675 | "integrity": "sha1-4ESWMtSz5RbyHMAUznxWRP3c5hQ=", 676 | "requires": { 677 | "101": "^1.0.0" 678 | } 679 | }, 680 | "kuler": { 681 | "version": "1.0.1", 682 | "resolved": "https://registry.npmjs.org/kuler/-/kuler-1.0.1.tgz", 683 | "integrity": "sha512-J9nVUucG1p/skKul6DU3PUZrhs0LPulNaeUOox0IyXDi8S4CztTHs1gQphhuZmzXG7VOQSf6NJfKuzteQLv9gQ==", 684 | "requires": { 685 | "colornames": "^1.1.1" 686 | } 687 | }, 688 | "lodash": { 689 | "version": "4.17.15", 690 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", 691 | "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" 692 | }, 693 | "logform": { 694 | "version": "2.1.2", 695 | "resolved": "https://registry.npmjs.org/logform/-/logform-2.1.2.tgz", 696 | "integrity": "sha512-+lZh4OpERDBLqjiwDLpAWNQu6KMjnlXH2ByZwCuSqVPJletw0kTWJf5CgSNAUKn1KUkv3m2cUz/LK8zyEy7wzQ==", 697 | "requires": { 698 | "colors": "^1.2.1", 699 | "fast-safe-stringify": "^2.0.4", 700 | "fecha": "^2.3.3", 701 | "ms": "^2.1.1", 702 | "triple-beam": "^1.3.0" 703 | } 704 | }, 705 | "lru-queue": { 706 | "version": "0.1.0", 707 | "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz", 708 | "integrity": "sha1-Jzi9nw089PhEkMVzbEhpmsYyzaM=", 709 | "requires": { 710 | "es5-ext": "~0.10.2" 711 | } 712 | }, 713 | "memoizee": { 714 | "version": "0.4.14", 715 | "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.14.tgz", 716 | "integrity": "sha512-/SWFvWegAIYAO4NQMpcX+gcra0yEZu4OntmUdrBaWrJncxOqAziGFlHxc7yjKVK2uu3lpPW27P27wkR82wA8mg==", 717 | "requires": { 718 | "d": "1", 719 | "es5-ext": "^0.10.45", 720 | "es6-weak-map": "^2.0.2", 721 | "event-emitter": "^0.3.5", 722 | "is-promise": "^2.1", 723 | "lru-queue": "0.1", 724 | "next-tick": "1", 725 | "timers-ext": "^0.1.5" 726 | } 727 | }, 728 | "minimatch": { 729 | "version": "3.0.4", 730 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 731 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 732 | "requires": { 733 | "brace-expansion": "^1.1.7" 734 | } 735 | }, 736 | "minimist": { 737 | "version": "0.0.5", 738 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.5.tgz", 739 | "integrity": "sha1-16oye87PUY+RBqxrjwA/o7zqhWY=" 740 | }, 741 | "ms": { 742 | "version": "2.1.2", 743 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 744 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" 745 | }, 746 | "nan": { 747 | "version": "2.14.0", 748 | "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", 749 | "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==" 750 | }, 751 | "next-tick": { 752 | "version": "1.0.0", 753 | "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", 754 | "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=" 755 | }, 756 | "node-fetch": { 757 | "version": "1.7.3", 758 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", 759 | "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", 760 | "requires": { 761 | "encoding": "^0.1.11", 762 | "is-stream": "^1.0.1" 763 | } 764 | }, 765 | "object-inspect": { 766 | "version": "1.7.0", 767 | "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", 768 | "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==" 769 | }, 770 | "object-is": { 771 | "version": "1.0.2", 772 | "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.0.2.tgz", 773 | "integrity": "sha512-Epah+btZd5wrrfjkJZq1AOB9O6OxUQto45hzFd7lXGrpHPGE0W1k+426yrZV+k6NJOzLNNW/nVsmZdIWsAqoOQ==" 774 | }, 775 | "object-keys": { 776 | "version": "0.4.0", 777 | "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-0.4.0.tgz", 778 | "integrity": "sha1-KKaq50KN0sOpLz2V8hM13SBOAzY=" 779 | }, 780 | "object.assign": { 781 | "version": "4.1.0", 782 | "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", 783 | "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", 784 | "requires": { 785 | "define-properties": "^1.1.2", 786 | "function-bind": "^1.1.1", 787 | "has-symbols": "^1.0.0", 788 | "object-keys": "^1.0.11" 789 | }, 790 | "dependencies": { 791 | "object-keys": { 792 | "version": "1.1.1", 793 | "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", 794 | "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" 795 | } 796 | } 797 | }, 798 | "once": { 799 | "version": "1.4.0", 800 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 801 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 802 | "requires": { 803 | "wrappy": "1" 804 | } 805 | }, 806 | "one-time": { 807 | "version": "0.0.4", 808 | "resolved": "https://registry.npmjs.org/one-time/-/one-time-0.0.4.tgz", 809 | "integrity": "sha1-+M33eISCb+Tf+T46nMN7HkSAdC4=" 810 | }, 811 | "path-is-absolute": { 812 | "version": "1.0.1", 813 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 814 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" 815 | }, 816 | "path-parse": { 817 | "version": "1.0.6", 818 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", 819 | "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" 820 | }, 821 | "process-nextick-args": { 822 | "version": "2.0.1", 823 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", 824 | "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" 825 | }, 826 | "ramda": { 827 | "version": "0.26.1", 828 | "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.26.1.tgz", 829 | "integrity": "sha512-hLWjpy7EnsDBb0p+Z3B7rPi3GDeRG5ZtiI33kJhTt+ORCd38AbAIjB/9zRIUoeTbE/AVX5ZkU7m6bznsvrf8eQ==" 830 | }, 831 | "readable-stream": { 832 | "version": "3.5.0", 833 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.5.0.tgz", 834 | "integrity": "sha512-gSz026xs2LfxBPudDuI41V1lka8cxg64E66SGe78zJlsUofOg/yqwezdIcdfwik6B4h8LFmWPA9ef9X3FiNFLA==", 835 | "requires": { 836 | "inherits": "^2.0.3", 837 | "string_decoder": "^1.1.1", 838 | "util-deprecate": "^1.0.1" 839 | } 840 | }, 841 | "regenerator-runtime": { 842 | "version": "0.13.3", 843 | "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz", 844 | "integrity": "sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw==" 845 | }, 846 | "regexp.prototype.flags": { 847 | "version": "1.3.0", 848 | "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz", 849 | "integrity": "sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ==", 850 | "requires": { 851 | "define-properties": "^1.1.3", 852 | "es-abstract": "^1.17.0-next.1" 853 | } 854 | }, 855 | "resolve": { 856 | "version": "1.14.2", 857 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.14.2.tgz", 858 | "integrity": "sha512-EjlOBLBO1kxsUxsKjLt7TAECyKW6fOh1VRkykQkKGzcBbjjPIxBqGh0jf7GJ3k/f5mxMqW3htMD3WdTUVtW8HQ==", 859 | "requires": { 860 | "path-parse": "^1.0.6" 861 | } 862 | }, 863 | "resumer": { 864 | "version": "0.0.0", 865 | "resolved": "https://registry.npmjs.org/resumer/-/resumer-0.0.0.tgz", 866 | "integrity": "sha1-8ej0YeQGS6Oegq883CqMiT0HZ1k=", 867 | "requires": { 868 | "through": "~2.3.4" 869 | } 870 | }, 871 | "rpc-websockets": { 872 | "version": "4.6.1", 873 | "resolved": "https://registry.npmjs.org/rpc-websockets/-/rpc-websockets-4.6.1.tgz", 874 | "integrity": "sha512-xyQC6+95hOFQJBuMRIYi2E3/ddKEMMKuql5Sd49r4578CcthP0N9nHHFkVtvrsAgz4OQH6j7zsLurLNY0nOU6g==", 875 | "requires": { 876 | "@babel/runtime": "^7.4.5", 877 | "assert-args": "^1.2.1", 878 | "babel-runtime": "^6.26.0", 879 | "circular-json": "^0.5.9", 880 | "eventemitter3": "^3.1.2", 881 | "uuid": "^3.3.2", 882 | "ws": "^5.2.2" 883 | } 884 | }, 885 | "safe-buffer": { 886 | "version": "5.2.0", 887 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", 888 | "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" 889 | }, 890 | "safer-buffer": { 891 | "version": "2.1.2", 892 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 893 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 894 | }, 895 | "semver": { 896 | "version": "5.7.1", 897 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", 898 | "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" 899 | }, 900 | "simple-swizzle": { 901 | "version": "0.2.2", 902 | "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", 903 | "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", 904 | "requires": { 905 | "is-arrayish": "^0.3.1" 906 | } 907 | }, 908 | "sleep": { 909 | "version": "6.1.0", 910 | "resolved": "https://registry.npmjs.org/sleep/-/sleep-6.1.0.tgz", 911 | "integrity": "sha512-Z1x4JjJxsru75Tqn8F4tnOFeEu3HjtITTsumYUiuz54sGKdISgLCek9AUlXlVVrkhltRFhNUsJDJE76SFHTDIQ==", 912 | "requires": { 913 | "nan": "^2.13.2" 914 | } 915 | }, 916 | "sprintf": { 917 | "version": "0.1.5", 918 | "resolved": "https://registry.npmjs.org/sprintf/-/sprintf-0.1.5.tgz", 919 | "integrity": "sha1-j4PjmpMXwaUCy324BQ5Rxnn27c8=" 920 | }, 921 | "stack-trace": { 922 | "version": "0.0.10", 923 | "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", 924 | "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=" 925 | }, 926 | "string.prototype.trim": { 927 | "version": "1.2.1", 928 | "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.1.tgz", 929 | "integrity": "sha512-MjGFEeqixw47dAMFMtgUro/I0+wNqZB5GKXGt1fFr24u3TzDXCPu7J9Buppzoe3r/LqkSDLDDJzE15RGWDGAVw==", 930 | "requires": { 931 | "define-properties": "^1.1.3", 932 | "es-abstract": "^1.17.0-next.1", 933 | "function-bind": "^1.1.1" 934 | } 935 | }, 936 | "string.prototype.trimleft": { 937 | "version": "2.1.1", 938 | "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz", 939 | "integrity": "sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag==", 940 | "requires": { 941 | "define-properties": "^1.1.3", 942 | "function-bind": "^1.1.1" 943 | } 944 | }, 945 | "string.prototype.trimright": { 946 | "version": "2.1.1", 947 | "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz", 948 | "integrity": "sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g==", 949 | "requires": { 950 | "define-properties": "^1.1.3", 951 | "function-bind": "^1.1.1" 952 | } 953 | }, 954 | "string_decoder": { 955 | "version": "1.3.0", 956 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", 957 | "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", 958 | "requires": { 959 | "safe-buffer": "~5.2.0" 960 | } 961 | }, 962 | "tap-parser": { 963 | "version": "0.4.3", 964 | "resolved": "https://registry.npmjs.org/tap-parser/-/tap-parser-0.4.3.tgz", 965 | "integrity": "sha1-pOrhkMENdsehEZIf84u+TVjwnuo=", 966 | "requires": { 967 | "inherits": "~2.0.1", 968 | "readable-stream": "~1.1.11" 969 | }, 970 | "dependencies": { 971 | "isarray": { 972 | "version": "0.0.1", 973 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", 974 | "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" 975 | }, 976 | "readable-stream": { 977 | "version": "1.1.14", 978 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", 979 | "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", 980 | "requires": { 981 | "core-util-is": "~1.0.0", 982 | "inherits": "~2.0.1", 983 | "isarray": "0.0.1", 984 | "string_decoder": "~0.10.x" 985 | } 986 | }, 987 | "string_decoder": { 988 | "version": "0.10.31", 989 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", 990 | "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" 991 | } 992 | } 993 | }, 994 | "tape": { 995 | "version": "4.13.0", 996 | "resolved": "https://registry.npmjs.org/tape/-/tape-4.13.0.tgz", 997 | "integrity": "sha512-J/hvA+GJnuWJ0Sj8Z0dmu3JgMNU+MmusvkCT7+SN4/2TklW18FNCp/UuHIEhPZwHfy4sXfKYgC7kypKg4umbOw==", 998 | "requires": { 999 | "deep-equal": "~1.1.1", 1000 | "defined": "~1.0.0", 1001 | "dotignore": "~0.1.2", 1002 | "for-each": "~0.3.3", 1003 | "function-bind": "~1.1.1", 1004 | "glob": "~7.1.6", 1005 | "has": "~1.0.3", 1006 | "inherits": "~2.0.4", 1007 | "is-regex": "~1.0.5", 1008 | "minimist": "~1.2.0", 1009 | "object-inspect": "~1.7.0", 1010 | "resolve": "~1.14.2", 1011 | "resumer": "~0.0.0", 1012 | "string.prototype.trim": "~1.2.1", 1013 | "through": "~2.3.8" 1014 | }, 1015 | "dependencies": { 1016 | "deep-equal": { 1017 | "version": "1.1.1", 1018 | "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", 1019 | "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", 1020 | "requires": { 1021 | "is-arguments": "^1.0.4", 1022 | "is-date-object": "^1.0.1", 1023 | "is-regex": "^1.0.4", 1024 | "object-is": "^1.0.1", 1025 | "object-keys": "^1.1.1", 1026 | "regexp.prototype.flags": "^1.2.0" 1027 | } 1028 | }, 1029 | "defined": { 1030 | "version": "1.0.0", 1031 | "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", 1032 | "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=" 1033 | }, 1034 | "minimist": { 1035 | "version": "1.2.0", 1036 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", 1037 | "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" 1038 | }, 1039 | "object-keys": { 1040 | "version": "1.1.1", 1041 | "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", 1042 | "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" 1043 | } 1044 | } 1045 | }, 1046 | "text-hex": { 1047 | "version": "1.0.0", 1048 | "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", 1049 | "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" 1050 | }, 1051 | "through": { 1052 | "version": "2.3.8", 1053 | "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", 1054 | "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" 1055 | }, 1056 | "through2": { 1057 | "version": "0.2.3", 1058 | "resolved": "https://registry.npmjs.org/through2/-/through2-0.2.3.tgz", 1059 | "integrity": "sha1-6zKE2k6jEbbMis42U3SKUqvyWj8=", 1060 | "requires": { 1061 | "readable-stream": "~1.1.9", 1062 | "xtend": "~2.1.1" 1063 | }, 1064 | "dependencies": { 1065 | "isarray": { 1066 | "version": "0.0.1", 1067 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", 1068 | "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" 1069 | }, 1070 | "readable-stream": { 1071 | "version": "1.1.14", 1072 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", 1073 | "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", 1074 | "requires": { 1075 | "core-util-is": "~1.0.0", 1076 | "inherits": "~2.0.1", 1077 | "isarray": "0.0.1", 1078 | "string_decoder": "~0.10.x" 1079 | } 1080 | }, 1081 | "string_decoder": { 1082 | "version": "0.10.31", 1083 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", 1084 | "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" 1085 | } 1086 | } 1087 | }, 1088 | "timers-ext": { 1089 | "version": "0.1.7", 1090 | "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz", 1091 | "integrity": "sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==", 1092 | "requires": { 1093 | "es5-ext": "~0.10.46", 1094 | "next-tick": "1" 1095 | } 1096 | }, 1097 | "triple-beam": { 1098 | "version": "1.3.0", 1099 | "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", 1100 | "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==" 1101 | }, 1102 | "type": { 1103 | "version": "1.2.0", 1104 | "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", 1105 | "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==" 1106 | }, 1107 | "type-detect": { 1108 | "version": "0.1.1", 1109 | "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-0.1.1.tgz", 1110 | "integrity": "sha1-C6XsKohWQORw6k6FBZcZANrFiCI=" 1111 | }, 1112 | "util-deprecate": { 1113 | "version": "1.0.2", 1114 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 1115 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" 1116 | }, 1117 | "uuid": { 1118 | "version": "3.4.0", 1119 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", 1120 | "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" 1121 | }, 1122 | "whatwg-fetch": { 1123 | "version": "3.0.0", 1124 | "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz", 1125 | "integrity": "sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q==" 1126 | }, 1127 | "winston": { 1128 | "version": "3.2.1", 1129 | "resolved": "https://registry.npmjs.org/winston/-/winston-3.2.1.tgz", 1130 | "integrity": "sha512-zU6vgnS9dAWCEKg/QYigd6cgMVVNwyTzKs81XZtTFuRwJOcDdBg7AU0mXVyNbs7O5RH2zdv+BdNZUlx7mXPuOw==", 1131 | "requires": { 1132 | "async": "^2.6.1", 1133 | "diagnostics": "^1.1.1", 1134 | "is-stream": "^1.1.0", 1135 | "logform": "^2.1.1", 1136 | "one-time": "0.0.4", 1137 | "readable-stream": "^3.1.1", 1138 | "stack-trace": "0.0.x", 1139 | "triple-beam": "^1.3.0", 1140 | "winston-transport": "^4.3.0" 1141 | } 1142 | }, 1143 | "winston-compat": { 1144 | "version": "0.1.4", 1145 | "resolved": "https://registry.npmjs.org/winston-compat/-/winston-compat-0.1.4.tgz", 1146 | "integrity": "sha512-mMEfFsSm6GmkFF+f4/0UJtG4N1vSaczGmXLVJYmS/+u2zUaIPcw2ZRuwUg2TvVBjswgiraN+vNnAG8z4fRUZ4w==", 1147 | "requires": { 1148 | "cycle": "~1.0.3", 1149 | "logform": "^1.6.0", 1150 | "triple-beam": "^1.2.0" 1151 | }, 1152 | "dependencies": { 1153 | "logform": { 1154 | "version": "1.10.0", 1155 | "resolved": "https://registry.npmjs.org/logform/-/logform-1.10.0.tgz", 1156 | "integrity": "sha512-em5ojIhU18fIMOw/333mD+ZLE2fis0EzXl1ZwHx4iQzmpQi6odNiY/t+ITNr33JZhT9/KEaH+UPIipr6a9EjWg==", 1157 | "requires": { 1158 | "colors": "^1.2.1", 1159 | "fast-safe-stringify": "^2.0.4", 1160 | "fecha": "^2.3.3", 1161 | "ms": "^2.1.1", 1162 | "triple-beam": "^1.2.0" 1163 | } 1164 | } 1165 | } 1166 | }, 1167 | "winston-null": { 1168 | "version": "2.0.0", 1169 | "resolved": "https://registry.npmjs.org/winston-null/-/winston-null-2.0.0.tgz", 1170 | "integrity": "sha512-uS5tJB5OkLWOoc3I7/LsWUfTIa5Du38XSviHf/b0TINK659Np9368FJwTt15UoZQYUQVxLpM06lxk2dKET22Xw==", 1171 | "requires": { 1172 | "semver": "^5.6.0", 1173 | "winston-compat": "^0.1.4", 1174 | "winston-transport": "^4.2.0" 1175 | } 1176 | }, 1177 | "winston-transport": { 1178 | "version": "4.3.0", 1179 | "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.3.0.tgz", 1180 | "integrity": "sha512-B2wPuwUi3vhzn/51Uukcao4dIduEiPOcOt9HJ3QeaXgkJ5Z7UwpBzxS4ZGNHtrxrUvTwemsQiSys0ihOf8Mp1A==", 1181 | "requires": { 1182 | "readable-stream": "^2.3.6", 1183 | "triple-beam": "^1.2.0" 1184 | }, 1185 | "dependencies": { 1186 | "readable-stream": { 1187 | "version": "2.3.7", 1188 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", 1189 | "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", 1190 | "requires": { 1191 | "core-util-is": "~1.0.0", 1192 | "inherits": "~2.0.3", 1193 | "isarray": "~1.0.0", 1194 | "process-nextick-args": "~2.0.0", 1195 | "safe-buffer": "~5.1.1", 1196 | "string_decoder": "~1.1.1", 1197 | "util-deprecate": "~1.0.1" 1198 | } 1199 | }, 1200 | "safe-buffer": { 1201 | "version": "5.1.2", 1202 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 1203 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" 1204 | }, 1205 | "string_decoder": { 1206 | "version": "1.1.1", 1207 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", 1208 | "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", 1209 | "requires": { 1210 | "safe-buffer": "~5.1.0" 1211 | } 1212 | } 1213 | } 1214 | }, 1215 | "wrappy": { 1216 | "version": "1.0.2", 1217 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 1218 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" 1219 | }, 1220 | "ws": { 1221 | "version": "5.2.2", 1222 | "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz", 1223 | "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==", 1224 | "requires": { 1225 | "async-limiter": "~1.0.0" 1226 | } 1227 | }, 1228 | "xtend": { 1229 | "version": "2.1.2", 1230 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-2.1.2.tgz", 1231 | "integrity": "sha1-bv7MKk2tjmlixJAbM3znuoe10os=", 1232 | "requires": { 1233 | "object-keys": "~0.4.0" 1234 | } 1235 | } 1236 | } 1237 | } 1238 | -------------------------------------------------------------------------------- /dna/test/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "devDependencies": {}, 3 | "dependencies": { 4 | "@holochain/tryorama": "^0.3.0", 5 | "faucet": "0.0.1", 6 | "json3": "*", 7 | "sleep": "^6.1.0", 8 | "tape": "^4.9.1" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /dna/zomes/courses/code/.hcbuild: -------------------------------------------------------------------------------- 1 | { 2 | "steps": [ 3 | { 4 | "command": "CARGO_TARGET_DIR=${CARGO_TARGET_DIR:-/tmp/my_first_app/target} && echo $CARGO_TARGET_DIR", 5 | "arguments": [] 6 | }, 7 | { 8 | "command": "CARGO_TARGET_DIR=${CARGO_TARGET_DIR:-/tmp/my_first_app/target} && cargo", 9 | "arguments": [ 10 | "build", 11 | "--release", 12 | "--target=wasm32-unknown-unknown", 13 | "--target-dir=$CARGO_TARGET_DIR" 14 | ] 15 | }, 16 | { 17 | "command": "CARGO_TARGET_DIR=${CARGO_TARGET_DIR:-/tmp/my_first_app/target} && wasm-gc", 18 | "arguments": ["$CARGO_TARGET_DIR/wasm32-unknown-unknown/release/courses.wasm"] 19 | }, 20 | { 21 | "command": "CARGO_TARGET_DIR=${CARGO_TARGET_DIR:-/tmp/my_first_app/target} && wasm-opt", 22 | "arguments": [ 23 | "-Oz", 24 | "--vacuum", 25 | "$CARGO_TARGET_DIR/wasm32-unknown-unknown/release/courses.wasm" 26 | ] 27 | }, 28 | { 29 | "command": "CARGO_TARGET_DIR=${CARGO_TARGET_DIR:-/tmp/my_first_app/target} && wasm2wat", 30 | "arguments": [ 31 | "$CARGO_TARGET_DIR/wasm32-unknown-unknown/release/courses.wasm", 32 | "-o", 33 | "$CARGO_TARGET_DIR/wasm32-unknown-unknown/release/courses.wat" 34 | ] 35 | }, 36 | { 37 | "command": "CARGO_TARGET_DIR=${CARGO_TARGET_DIR:-/tmp/my_first_app/target} && wat2wasm", 38 | "arguments": [ 39 | "$CARGO_TARGET_DIR/wasm32-unknown-unknown/release/courses.wat", 40 | "-o", 41 | "$CARGO_TARGET_DIR/wasm32-unknown-unknown/release/courses.wasm" 42 | ] 43 | } 44 | ], 45 | "artifact": "${CARGO_TARGET_DIR:-/tmp/my_first_app/target}/wasm32-unknown-unknown/release/courses.wasm" 46 | } 47 | -------------------------------------------------------------------------------- /dna/zomes/courses/code/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "aho-corasick" 5 | version = "0.6.10" 6 | source = "registry+https://github.com/rust-lang/crates.io-index" 7 | checksum = "81ce3d38065e618af2d7b77e10c5ad9a069859b4be3c2250f674af3840d9c8a5" 8 | dependencies = [ 9 | "memchr", 10 | ] 11 | 12 | [[package]] 13 | name = "ansi_term" 14 | version = "0.11.0" 15 | source = "registry+https://github.com/rust-lang/crates.io-index" 16 | checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" 17 | dependencies = [ 18 | "winapi", 19 | ] 20 | 21 | [[package]] 22 | name = "arrayref" 23 | version = "0.3.5" 24 | source = "registry+https://github.com/rust-lang/crates.io-index" 25 | checksum = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee" 26 | 27 | [[package]] 28 | name = "atty" 29 | version = "0.2.14" 30 | source = "registry+https://github.com/rust-lang/crates.io-index" 31 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 32 | dependencies = [ 33 | "hermit-abi", 34 | "libc", 35 | "winapi", 36 | ] 37 | 38 | [[package]] 39 | name = "autocfg" 40 | version = "0.1.7" 41 | source = "registry+https://github.com/rust-lang/crates.io-index" 42 | checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" 43 | 44 | [[package]] 45 | name = "autocfg" 46 | version = "1.0.0" 47 | source = "registry+https://github.com/rust-lang/crates.io-index" 48 | checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" 49 | 50 | [[package]] 51 | name = "backtrace" 52 | version = "0.3.27" 53 | source = "registry+https://github.com/rust-lang/crates.io-index" 54 | checksum = "60ef64f0896c6f4bd4f788de337c099b83de8c8129279c0084558af33f45ee19" 55 | dependencies = [ 56 | "autocfg 0.1.7", 57 | "backtrace-sys", 58 | "cfg-if", 59 | "libc", 60 | "rustc-demangle", 61 | ] 62 | 63 | [[package]] 64 | name = "backtrace-sys" 65 | version = "0.1.32" 66 | source = "registry+https://github.com/rust-lang/crates.io-index" 67 | checksum = "5d6575f128516de27e3ce99689419835fce9643a9b215a14d2b5b685be018491" 68 | dependencies = [ 69 | "cc", 70 | "libc", 71 | ] 72 | 73 | [[package]] 74 | name = "base64" 75 | version = "0.10.1" 76 | source = "registry+https://github.com/rust-lang/crates.io-index" 77 | checksum = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" 78 | dependencies = [ 79 | "byteorder", 80 | ] 81 | 82 | [[package]] 83 | name = "bitflags" 84 | version = "1.0.4" 85 | source = "registry+https://github.com/rust-lang/crates.io-index" 86 | checksum = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" 87 | 88 | [[package]] 89 | name = "block-buffer" 90 | version = "0.3.3" 91 | source = "registry+https://github.com/rust-lang/crates.io-index" 92 | checksum = "a076c298b9ecdb530ed9d967e74a6027d6a7478924520acddcddc24c1c8ab3ab" 93 | dependencies = [ 94 | "arrayref", 95 | "byte-tools", 96 | ] 97 | 98 | [[package]] 99 | name = "byte-tools" 100 | version = "0.2.0" 101 | source = "registry+https://github.com/rust-lang/crates.io-index" 102 | checksum = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40" 103 | 104 | [[package]] 105 | name = "byteorder" 106 | version = "1.3.2" 107 | source = "registry+https://github.com/rust-lang/crates.io-index" 108 | checksum = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" 109 | 110 | [[package]] 111 | name = "c2-chacha" 112 | version = "0.2.3" 113 | source = "registry+https://github.com/rust-lang/crates.io-index" 114 | checksum = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb" 115 | dependencies = [ 116 | "ppv-lite86", 117 | ] 118 | 119 | [[package]] 120 | name = "cc" 121 | version = "1.0.50" 122 | source = "registry+https://github.com/rust-lang/crates.io-index" 123 | checksum = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd" 124 | 125 | [[package]] 126 | name = "cfg-if" 127 | version = "0.1.10" 128 | source = "registry+https://github.com/rust-lang/crates.io-index" 129 | checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" 130 | 131 | [[package]] 132 | name = "chrono" 133 | version = "0.4.6" 134 | source = "registry+https://github.com/rust-lang/crates.io-index" 135 | checksum = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878" 136 | dependencies = [ 137 | "num-integer", 138 | "num-traits", 139 | "time", 140 | ] 141 | 142 | [[package]] 143 | name = "cloudabi" 144 | version = "0.0.3" 145 | source = "registry+https://github.com/rust-lang/crates.io-index" 146 | checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" 147 | dependencies = [ 148 | "bitflags", 149 | ] 150 | 151 | [[package]] 152 | name = "colored" 153 | version = "1.7.0" 154 | source = "registry+https://github.com/rust-lang/crates.io-index" 155 | checksum = "6e9a455e156a4271e12fd0246238c380b1e223e3736663c7a18ed8b6362028a9" 156 | dependencies = [ 157 | "lazy_static", 158 | ] 159 | 160 | [[package]] 161 | name = "courses" 162 | version = "0.1.0" 163 | dependencies = [ 164 | "hdk", 165 | "hdk_proc_macros", 166 | "holochain_json_derive 0.0.1-alpha2", 167 | "holochain_wasm_utils", 168 | "serde", 169 | "serde_derive", 170 | "serde_json", 171 | ] 172 | 173 | [[package]] 174 | name = "crossbeam-channel" 175 | version = "0.3.8" 176 | source = "registry+https://github.com/rust-lang/crates.io-index" 177 | checksum = "0f0ed1a4de2235cabda8558ff5840bffb97fcb64c97827f354a451307df5f72b" 178 | dependencies = [ 179 | "crossbeam-utils", 180 | "smallvec 0.6.13", 181 | ] 182 | 183 | [[package]] 184 | name = "crossbeam-utils" 185 | version = "0.6.6" 186 | source = "registry+https://github.com/rust-lang/crates.io-index" 187 | checksum = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" 188 | dependencies = [ 189 | "cfg-if", 190 | "lazy_static", 191 | ] 192 | 193 | [[package]] 194 | name = "crunchy" 195 | version = "0.2.2" 196 | source = "registry+https://github.com/rust-lang/crates.io-index" 197 | checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" 198 | 199 | [[package]] 200 | name = "ctor" 201 | version = "0.1.12" 202 | source = "registry+https://github.com/rust-lang/crates.io-index" 203 | checksum = "cd8ce37ad4184ab2ce004c33bf6379185d3b1c95801cab51026bd271bf68eedc" 204 | dependencies = [ 205 | "quote 1.0.2", 206 | "syn 1.0.14", 207 | ] 208 | 209 | [[package]] 210 | name = "difference" 211 | version = "2.0.0" 212 | source = "registry+https://github.com/rust-lang/crates.io-index" 213 | checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" 214 | 215 | [[package]] 216 | name = "digest" 217 | version = "0.7.6" 218 | source = "registry+https://github.com/rust-lang/crates.io-index" 219 | checksum = "03b072242a8cbaf9c145665af9d250c59af3b958f83ed6824e13533cf76d5b90" 220 | dependencies = [ 221 | "generic-array", 222 | ] 223 | 224 | [[package]] 225 | name = "either" 226 | version = "1.5.3" 227 | source = "registry+https://github.com/rust-lang/crates.io-index" 228 | checksum = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" 229 | 230 | [[package]] 231 | name = "env_logger" 232 | version = "0.6.1" 233 | source = "registry+https://github.com/rust-lang/crates.io-index" 234 | checksum = "b61fa891024a945da30a9581546e8cfaf5602c7b3f4c137a2805cf388f92075a" 235 | dependencies = [ 236 | "atty", 237 | "humantime", 238 | "log", 239 | "regex", 240 | "termcolor", 241 | ] 242 | 243 | [[package]] 244 | name = "fake-simd" 245 | version = "0.1.2" 246 | source = "registry+https://github.com/rust-lang/crates.io-index" 247 | checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" 248 | 249 | [[package]] 250 | name = "fuchsia-cprng" 251 | version = "0.1.1" 252 | source = "registry+https://github.com/rust-lang/crates.io-index" 253 | checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" 254 | 255 | [[package]] 256 | name = "futures" 257 | version = "0.3.1" 258 | source = "registry+https://github.com/rust-lang/crates.io-index" 259 | checksum = "b6f16056ecbb57525ff698bb955162d0cd03bee84e6241c27ff75c08d8ca5987" 260 | dependencies = [ 261 | "futures-channel", 262 | "futures-core", 263 | "futures-executor", 264 | "futures-io", 265 | "futures-sink", 266 | "futures-task", 267 | "futures-util", 268 | ] 269 | 270 | [[package]] 271 | name = "futures-channel" 272 | version = "0.3.1" 273 | source = "registry+https://github.com/rust-lang/crates.io-index" 274 | checksum = "fcae98ca17d102fd8a3603727b9259fcf7fa4239b603d2142926189bc8999b86" 275 | dependencies = [ 276 | "futures-core", 277 | "futures-sink", 278 | ] 279 | 280 | [[package]] 281 | name = "futures-channel-preview" 282 | version = "0.3.0-alpha.17" 283 | source = "registry+https://github.com/rust-lang/crates.io-index" 284 | checksum = "21c71ed547606de08e9ae744bb3c6d80f5627527ef31ecf2a7210d0e67bc8fae" 285 | dependencies = [ 286 | "futures-core-preview", 287 | "futures-sink-preview", 288 | ] 289 | 290 | [[package]] 291 | name = "futures-core" 292 | version = "0.3.1" 293 | source = "registry+https://github.com/rust-lang/crates.io-index" 294 | checksum = "79564c427afefab1dfb3298535b21eda083ef7935b4f0ecbfcb121f0aec10866" 295 | 296 | [[package]] 297 | name = "futures-core-preview" 298 | version = "0.3.0-alpha.17" 299 | source = "registry+https://github.com/rust-lang/crates.io-index" 300 | checksum = "4b141ccf9b7601ef987f36f1c0d9522f76df3bba1cf2e63bfacccc044c4558f5" 301 | 302 | [[package]] 303 | name = "futures-executor" 304 | version = "0.3.1" 305 | source = "registry+https://github.com/rust-lang/crates.io-index" 306 | checksum = "1e274736563f686a837a0568b478bdabfeaec2dca794b5649b04e2fe1627c231" 307 | dependencies = [ 308 | "futures-core", 309 | "futures-task", 310 | "futures-util", 311 | ] 312 | 313 | [[package]] 314 | name = "futures-executor-preview" 315 | version = "0.3.0-alpha.17" 316 | source = "registry+https://github.com/rust-lang/crates.io-index" 317 | checksum = "87ba260fe51080ba37f063ad5b0732c4ff1f737ea18dcb67833d282cdc2c6f14" 318 | dependencies = [ 319 | "futures-channel-preview", 320 | "futures-core-preview", 321 | "futures-util-preview", 322 | "num_cpus", 323 | ] 324 | 325 | [[package]] 326 | name = "futures-io" 327 | version = "0.3.1" 328 | source = "registry+https://github.com/rust-lang/crates.io-index" 329 | checksum = "e676577d229e70952ab25f3945795ba5b16d63ca794ca9d2c860e5595d20b5ff" 330 | 331 | [[package]] 332 | name = "futures-io-preview" 333 | version = "0.3.0-alpha.17" 334 | source = "registry+https://github.com/rust-lang/crates.io-index" 335 | checksum = "082e402605fcb8b1ae1e5ba7d7fdfd3e31ef510e2a8367dd92927bb41ae41b3a" 336 | 337 | [[package]] 338 | name = "futures-macro" 339 | version = "0.3.1" 340 | source = "registry+https://github.com/rust-lang/crates.io-index" 341 | checksum = "52e7c56c15537adb4f76d0b7a76ad131cb4d2f4f32d3b0bcabcbe1c7c5e87764" 342 | dependencies = [ 343 | "proc-macro-hack 0.5.11", 344 | "proc-macro2 1.0.8", 345 | "quote 1.0.2", 346 | "syn 1.0.14", 347 | ] 348 | 349 | [[package]] 350 | name = "futures-preview" 351 | version = "0.3.0-alpha.17" 352 | source = "registry+https://github.com/rust-lang/crates.io-index" 353 | checksum = "bf25f91c8a9a1f64c451e91b43ba269ed359b9f52d35ed4b3ce3f9c842435867" 354 | dependencies = [ 355 | "futures-channel-preview", 356 | "futures-core-preview", 357 | "futures-executor-preview", 358 | "futures-io-preview", 359 | "futures-sink-preview", 360 | "futures-util-preview", 361 | ] 362 | 363 | [[package]] 364 | name = "futures-sink" 365 | version = "0.3.1" 366 | source = "registry+https://github.com/rust-lang/crates.io-index" 367 | checksum = "171be33efae63c2d59e6dbba34186fe0d6394fb378069a76dfd80fdcffd43c16" 368 | 369 | [[package]] 370 | name = "futures-sink-preview" 371 | version = "0.3.0-alpha.17" 372 | source = "registry+https://github.com/rust-lang/crates.io-index" 373 | checksum = "4309a25a1069a1f3c10647b227b9afe6722b67a030d3f00a9cbdc171fc038de4" 374 | dependencies = [ 375 | "futures-core-preview", 376 | ] 377 | 378 | [[package]] 379 | name = "futures-task" 380 | version = "0.3.1" 381 | source = "registry+https://github.com/rust-lang/crates.io-index" 382 | checksum = "0bae52d6b29cf440e298856fec3965ee6fa71b06aa7495178615953fd669e5f9" 383 | 384 | [[package]] 385 | name = "futures-util" 386 | version = "0.3.1" 387 | source = "registry+https://github.com/rust-lang/crates.io-index" 388 | checksum = "c0d66274fb76985d3c62c886d1da7ac4c0903a8c9f754e8fe0f35a6a6cc39e76" 389 | dependencies = [ 390 | "futures-channel", 391 | "futures-core", 392 | "futures-io", 393 | "futures-macro", 394 | "futures-sink", 395 | "futures-task", 396 | "memchr", 397 | "pin-utils", 398 | "proc-macro-hack 0.5.11", 399 | "proc-macro-nested", 400 | "slab", 401 | ] 402 | 403 | [[package]] 404 | name = "futures-util-preview" 405 | version = "0.3.0-alpha.17" 406 | source = "registry+https://github.com/rust-lang/crates.io-index" 407 | checksum = "af8198c48b222f02326940ce2b3aa9e6e91a32886eeaad7ca3b8e4c70daa3f4e" 408 | dependencies = [ 409 | "futures-channel-preview", 410 | "futures-core-preview", 411 | "futures-io-preview", 412 | "futures-sink-preview", 413 | "memchr", 414 | "pin-utils", 415 | "slab", 416 | ] 417 | 418 | [[package]] 419 | name = "generic-array" 420 | version = "0.9.0" 421 | source = "registry+https://github.com/rust-lang/crates.io-index" 422 | checksum = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d" 423 | dependencies = [ 424 | "typenum", 425 | ] 426 | 427 | [[package]] 428 | name = "getrandom" 429 | version = "0.1.14" 430 | source = "registry+https://github.com/rust-lang/crates.io-index" 431 | checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" 432 | dependencies = [ 433 | "cfg-if", 434 | "libc", 435 | "wasi", 436 | ] 437 | 438 | [[package]] 439 | name = "hcid" 440 | version = "0.0.6" 441 | source = "registry+https://github.com/rust-lang/crates.io-index" 442 | checksum = "9e5ea27f6b17df2ded5dcfc492ecd0db719d00b144dbaaf2df1658a7e38cfd2e" 443 | dependencies = [ 444 | "reed-solomon", 445 | ] 446 | 447 | [[package]] 448 | name = "hdk" 449 | version = "0.0.42-alpha5" 450 | source = "registry+https://github.com/rust-lang/crates.io-index" 451 | checksum = "be4b8683e2170cb2063a0f9c7d8b111d1edb41ad59f3b40bd5e0e0d1973b351a" 452 | dependencies = [ 453 | "bitflags", 454 | "env_logger", 455 | "holochain_core_types", 456 | "holochain_json_api", 457 | "holochain_json_derive 0.0.17", 458 | "holochain_persistence_api", 459 | "holochain_wasm_utils", 460 | "lazy_static", 461 | "pretty_assertions", 462 | "serde", 463 | "serde_derive", 464 | "serde_json", 465 | "url", 466 | ] 467 | 468 | [[package]] 469 | name = "hdk_proc_macros" 470 | version = "0.0.42-alpha5" 471 | source = "registry+https://github.com/rust-lang/crates.io-index" 472 | checksum = "496e3f6ec56bac12cbdeda714649e3b8f0593664a03d1509587734c541c53d01" 473 | dependencies = [ 474 | "hdk", 475 | "proc-macro2 0.4.27", 476 | "quote 0.6.11", 477 | "syn 0.15.31", 478 | ] 479 | 480 | [[package]] 481 | name = "hermit-abi" 482 | version = "0.1.6" 483 | source = "registry+https://github.com/rust-lang/crates.io-index" 484 | checksum = "eff2656d88f158ce120947499e971d743c05dbcbed62e5bd2f38f1698bbc3772" 485 | dependencies = [ 486 | "libc", 487 | ] 488 | 489 | [[package]] 490 | name = "holochain_core_types" 491 | version = "0.0.42-alpha5" 492 | source = "registry+https://github.com/rust-lang/crates.io-index" 493 | checksum = "f6929be7047a12f0ae7b71d185167574c34bd7b6fb0a344b05c67b75ae898b2b" 494 | dependencies = [ 495 | "arrayref", 496 | "backtrace", 497 | "base64", 498 | "chrono", 499 | "crossbeam-channel", 500 | "futures", 501 | "hcid", 502 | "holochain_json_api", 503 | "holochain_json_derive 0.0.17", 504 | "holochain_locksmith", 505 | "holochain_logging", 506 | "holochain_persistence_api", 507 | "lazy_static", 508 | "lib3h_crypto_api", 509 | "log", 510 | "mashup", 511 | "multihash", 512 | "objekt", 513 | "parking_lot", 514 | "regex", 515 | "rust-base58", 516 | "serde", 517 | "serde_derive", 518 | "serde_json", 519 | "shrinkwraprs", 520 | "snowflake", 521 | "uuid", 522 | "wasmi", 523 | ] 524 | 525 | [[package]] 526 | name = "holochain_json_api" 527 | version = "0.0.17" 528 | source = "registry+https://github.com/rust-lang/crates.io-index" 529 | checksum = "7411832f446f09ea53ce2ca789fd2acd86ad29cc08d6d3c903474c2fada54ca5" 530 | dependencies = [ 531 | "arrayref", 532 | "base64", 533 | "chrono", 534 | "futures-channel-preview", 535 | "futures-core-preview", 536 | "futures-executor-preview", 537 | "futures-io-preview", 538 | "futures-preview", 539 | "futures-sink-preview", 540 | "futures-util-preview", 541 | "hcid", 542 | "holochain_json_derive 0.0.17", 543 | "multihash", 544 | "objekt", 545 | "serde", 546 | "serde_derive", 547 | "serde_json", 548 | "shrinkwraprs", 549 | "uuid", 550 | ] 551 | 552 | [[package]] 553 | name = "holochain_json_derive" 554 | version = "0.0.1-alpha2" 555 | source = "registry+https://github.com/rust-lang/crates.io-index" 556 | checksum = "57d7eb950d0154f032b0cbabdcb9f5d4bd10795b4606cf9df8330642896a2bbd" 557 | dependencies = [ 558 | "quote 0.6.11", 559 | "serde", 560 | "serde_json", 561 | "syn 0.15.31", 562 | ] 563 | 564 | [[package]] 565 | name = "holochain_json_derive" 566 | version = "0.0.17" 567 | source = "registry+https://github.com/rust-lang/crates.io-index" 568 | checksum = "b82510813b7164094ca380651f81350d461fb695f4580c4d25d9f52bcc5e1f5d" 569 | dependencies = [ 570 | "quote 0.6.11", 571 | "serde", 572 | "serde_json", 573 | "syn 0.15.31", 574 | ] 575 | 576 | [[package]] 577 | name = "holochain_locksmith" 578 | version = "0.0.42-alpha5" 579 | source = "registry+https://github.com/rust-lang/crates.io-index" 580 | checksum = "a2ce7fbaf768b41121e7dba60d5c49873239d3b2a8934929672453c474ffc446" 581 | dependencies = [ 582 | "backtrace", 583 | "chrono", 584 | "crossbeam-channel", 585 | "lazy_static", 586 | "log", 587 | "parking_lot", 588 | "snowflake", 589 | ] 590 | 591 | [[package]] 592 | name = "holochain_logging" 593 | version = "0.0.4" 594 | source = "registry+https://github.com/rust-lang/crates.io-index" 595 | checksum = "1eea83e3663d88570a6443db7dbfcabe6fb50797c5b0384d096ca835938bc366" 596 | dependencies = [ 597 | "chrono", 598 | "colored", 599 | "crossbeam-channel", 600 | "log", 601 | "regex", 602 | "serde", 603 | "serde_derive", 604 | "toml", 605 | ] 606 | 607 | [[package]] 608 | name = "holochain_persistence_api" 609 | version = "0.0.11" 610 | source = "registry+https://github.com/rust-lang/crates.io-index" 611 | checksum = "cb154424b75d8cd9e2209537784d5ea4215a09cb83f1feea44822fbea5f5436a" 612 | dependencies = [ 613 | "arrayref", 614 | "base64", 615 | "chrono", 616 | "futures-channel-preview", 617 | "futures-core-preview", 618 | "futures-executor-preview", 619 | "futures-io-preview", 620 | "futures-preview", 621 | "futures-sink-preview", 622 | "futures-util-preview", 623 | "hcid", 624 | "holochain_json_api", 625 | "holochain_json_derive 0.0.17", 626 | "lazy_static", 627 | "multihash", 628 | "objekt", 629 | "rand 0.7.3", 630 | "regex", 631 | "rust-base58", 632 | "serde", 633 | "serde_derive", 634 | "serde_json", 635 | "shrinkwraprs", 636 | "uuid", 637 | ] 638 | 639 | [[package]] 640 | name = "holochain_wasm_utils" 641 | version = "0.0.42-alpha5" 642 | source = "registry+https://github.com/rust-lang/crates.io-index" 643 | checksum = "bf23fd38c1ec9c74756bfbd4d543dc31a233f23a4066c38a3661c68a45a45f57" 644 | dependencies = [ 645 | "holochain_core_types", 646 | "holochain_json_api", 647 | "holochain_json_derive 0.0.17", 648 | "holochain_persistence_api", 649 | "serde", 650 | "serde_derive", 651 | "serde_json", 652 | ] 653 | 654 | [[package]] 655 | name = "humantime" 656 | version = "1.3.0" 657 | source = "registry+https://github.com/rust-lang/crates.io-index" 658 | checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" 659 | dependencies = [ 660 | "quick-error", 661 | ] 662 | 663 | [[package]] 664 | name = "idna" 665 | version = "0.2.0" 666 | source = "registry+https://github.com/rust-lang/crates.io-index" 667 | checksum = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9" 668 | dependencies = [ 669 | "matches", 670 | "unicode-bidi", 671 | "unicode-normalization", 672 | ] 673 | 674 | [[package]] 675 | name = "indexmap" 676 | version = "1.3.1" 677 | source = "registry+https://github.com/rust-lang/crates.io-index" 678 | checksum = "0b54058f0a6ff80b6803da8faf8997cde53872b38f4023728f6830b06cd3c0dc" 679 | dependencies = [ 680 | "autocfg 1.0.0", 681 | ] 682 | 683 | [[package]] 684 | name = "itertools" 685 | version = "0.7.11" 686 | source = "registry+https://github.com/rust-lang/crates.io-index" 687 | checksum = "0d47946d458e94a1b7bcabbf6521ea7c037062c81f534615abcad76e84d4970d" 688 | dependencies = [ 689 | "either", 690 | ] 691 | 692 | [[package]] 693 | name = "itoa" 694 | version = "0.4.5" 695 | source = "registry+https://github.com/rust-lang/crates.io-index" 696 | checksum = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e" 697 | 698 | [[package]] 699 | name = "lazy_static" 700 | version = "1.2.0" 701 | source = "registry+https://github.com/rust-lang/crates.io-index" 702 | checksum = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1" 703 | 704 | [[package]] 705 | name = "lib3h_crypto_api" 706 | version = "0.0.25" 707 | source = "registry+https://github.com/rust-lang/crates.io-index" 708 | checksum = "e77463e2d8d02b1f94fdf5cdd511f485fd42686548a47b594913db9244d538d2" 709 | dependencies = [ 710 | "serde", 711 | "serde_derive", 712 | "zeroize", 713 | ] 714 | 715 | [[package]] 716 | name = "libc" 717 | version = "0.2.66" 718 | source = "registry+https://github.com/rust-lang/crates.io-index" 719 | checksum = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558" 720 | 721 | [[package]] 722 | name = "lock_api" 723 | version = "0.3.3" 724 | source = "registry+https://github.com/rust-lang/crates.io-index" 725 | checksum = "79b2de95ecb4691949fea4716ca53cdbcfccb2c612e19644a8bad05edcf9f47b" 726 | dependencies = [ 727 | "scopeguard", 728 | ] 729 | 730 | [[package]] 731 | name = "log" 732 | version = "0.4.8" 733 | source = "registry+https://github.com/rust-lang/crates.io-index" 734 | checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" 735 | dependencies = [ 736 | "cfg-if", 737 | "serde", 738 | ] 739 | 740 | [[package]] 741 | name = "mashup" 742 | version = "0.1.9" 743 | source = "registry+https://github.com/rust-lang/crates.io-index" 744 | checksum = "f2d82b34c7fb11bb41719465c060589e291d505ca4735ea30016a91f6fc79c3b" 745 | dependencies = [ 746 | "mashup-impl", 747 | "proc-macro-hack 0.4.2", 748 | ] 749 | 750 | [[package]] 751 | name = "mashup-impl" 752 | version = "0.1.9" 753 | source = "registry+https://github.com/rust-lang/crates.io-index" 754 | checksum = "aa607bfb674b4efb310512527d64266b065de3f894fc52f84efcbf7eaa5965fb" 755 | dependencies = [ 756 | "proc-macro-hack 0.4.2", 757 | "proc-macro2 0.4.27", 758 | ] 759 | 760 | [[package]] 761 | name = "matches" 762 | version = "0.1.8" 763 | source = "registry+https://github.com/rust-lang/crates.io-index" 764 | checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" 765 | 766 | [[package]] 767 | name = "maybe-uninit" 768 | version = "2.0.0" 769 | source = "registry+https://github.com/rust-lang/crates.io-index" 770 | checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" 771 | 772 | [[package]] 773 | name = "memchr" 774 | version = "2.3.0" 775 | source = "registry+https://github.com/rust-lang/crates.io-index" 776 | checksum = "3197e20c7edb283f87c071ddfc7a2cca8f8e0b888c242959846a6fce03c72223" 777 | 778 | [[package]] 779 | name = "memory_units" 780 | version = "0.3.0" 781 | source = "registry+https://github.com/rust-lang/crates.io-index" 782 | checksum = "71d96e3f3c0b6325d8ccd83c33b28acb183edcb6c67938ba104ec546854b0882" 783 | 784 | [[package]] 785 | name = "multihash" 786 | version = "0.8.0" 787 | source = "registry+https://github.com/rust-lang/crates.io-index" 788 | checksum = "c62469025f45dee2464ef9fc845f4683c543993792c1993e7d903c17a4546b74" 789 | dependencies = [ 790 | "sha1", 791 | "sha2", 792 | "tiny-keccak", 793 | ] 794 | 795 | [[package]] 796 | name = "num" 797 | version = "0.2.1" 798 | source = "registry+https://github.com/rust-lang/crates.io-index" 799 | checksum = "b8536030f9fea7127f841b45bb6243b27255787fb4eb83958aa1ef9d2fdc0c36" 800 | dependencies = [ 801 | "num-bigint", 802 | "num-complex", 803 | "num-integer", 804 | "num-iter", 805 | "num-rational", 806 | "num-traits", 807 | ] 808 | 809 | [[package]] 810 | name = "num-bigint" 811 | version = "0.2.6" 812 | source = "registry+https://github.com/rust-lang/crates.io-index" 813 | checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" 814 | dependencies = [ 815 | "autocfg 1.0.0", 816 | "num-integer", 817 | "num-traits", 818 | ] 819 | 820 | [[package]] 821 | name = "num-complex" 822 | version = "0.2.4" 823 | source = "registry+https://github.com/rust-lang/crates.io-index" 824 | checksum = "b6b19411a9719e753aff12e5187b74d60d3dc449ec3f4dc21e3989c3f554bc95" 825 | dependencies = [ 826 | "autocfg 1.0.0", 827 | "num-traits", 828 | ] 829 | 830 | [[package]] 831 | name = "num-integer" 832 | version = "0.1.42" 833 | source = "registry+https://github.com/rust-lang/crates.io-index" 834 | checksum = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba" 835 | dependencies = [ 836 | "autocfg 1.0.0", 837 | "num-traits", 838 | ] 839 | 840 | [[package]] 841 | name = "num-iter" 842 | version = "0.1.40" 843 | source = "registry+https://github.com/rust-lang/crates.io-index" 844 | checksum = "dfb0800a0291891dd9f4fe7bd9c19384f98f7fbe0cd0f39a2c6b88b9868bbc00" 845 | dependencies = [ 846 | "autocfg 1.0.0", 847 | "num-integer", 848 | "num-traits", 849 | ] 850 | 851 | [[package]] 852 | name = "num-rational" 853 | version = "0.2.3" 854 | source = "registry+https://github.com/rust-lang/crates.io-index" 855 | checksum = "da4dc79f9e6c81bef96148c8f6b8e72ad4541caa4a24373e900a36da07de03a3" 856 | dependencies = [ 857 | "autocfg 1.0.0", 858 | "num-bigint", 859 | "num-integer", 860 | "num-traits", 861 | ] 862 | 863 | [[package]] 864 | name = "num-traits" 865 | version = "0.2.11" 866 | source = "registry+https://github.com/rust-lang/crates.io-index" 867 | checksum = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096" 868 | dependencies = [ 869 | "autocfg 1.0.0", 870 | ] 871 | 872 | [[package]] 873 | name = "num_cpus" 874 | version = "1.12.0" 875 | source = "registry+https://github.com/rust-lang/crates.io-index" 876 | checksum = "46203554f085ff89c235cd12f7075f3233af9b11ed7c9e16dfe2560d03313ce6" 877 | dependencies = [ 878 | "hermit-abi", 879 | "libc", 880 | ] 881 | 882 | [[package]] 883 | name = "objekt" 884 | version = "0.1.2" 885 | source = "registry+https://github.com/rust-lang/crates.io-index" 886 | checksum = "2069a3ae3dad97a4ae47754e8f47e5d2f1fd32ab7ad8a84bb31d051faa59cc3c" 887 | 888 | [[package]] 889 | name = "output_vt100" 890 | version = "0.1.2" 891 | source = "registry+https://github.com/rust-lang/crates.io-index" 892 | checksum = "53cdc5b785b7a58c5aad8216b3dfa114df64b0b06ae6e1501cef91df2fbdf8f9" 893 | dependencies = [ 894 | "winapi", 895 | ] 896 | 897 | [[package]] 898 | name = "parity-wasm" 899 | version = "0.31.3" 900 | source = "registry+https://github.com/rust-lang/crates.io-index" 901 | checksum = "511379a8194230c2395d2f5fa627a5a7e108a9f976656ce723ae68fca4097bfc" 902 | dependencies = [ 903 | "byteorder", 904 | ] 905 | 906 | [[package]] 907 | name = "parking_lot" 908 | version = "0.9.0" 909 | source = "registry+https://github.com/rust-lang/crates.io-index" 910 | checksum = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252" 911 | dependencies = [ 912 | "lock_api", 913 | "parking_lot_core", 914 | "rustc_version", 915 | ] 916 | 917 | [[package]] 918 | name = "parking_lot_core" 919 | version = "0.6.2" 920 | source = "registry+https://github.com/rust-lang/crates.io-index" 921 | checksum = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b" 922 | dependencies = [ 923 | "cfg-if", 924 | "cloudabi", 925 | "libc", 926 | "redox_syscall", 927 | "rustc_version", 928 | "smallvec 0.6.13", 929 | "winapi", 930 | ] 931 | 932 | [[package]] 933 | name = "percent-encoding" 934 | version = "2.1.0" 935 | source = "registry+https://github.com/rust-lang/crates.io-index" 936 | checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" 937 | 938 | [[package]] 939 | name = "pin-utils" 940 | version = "0.1.0-alpha.4" 941 | source = "registry+https://github.com/rust-lang/crates.io-index" 942 | checksum = "5894c618ce612a3fa23881b152b608bafb8c56cfc22f434a3ba3120b40f7b587" 943 | 944 | [[package]] 945 | name = "ppv-lite86" 946 | version = "0.2.6" 947 | source = "registry+https://github.com/rust-lang/crates.io-index" 948 | checksum = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" 949 | 950 | [[package]] 951 | name = "pretty_assertions" 952 | version = "0.6.1" 953 | source = "registry+https://github.com/rust-lang/crates.io-index" 954 | checksum = "3f81e1644e1b54f5a68959a29aa86cde704219254669da328ecfdf6a1f09d427" 955 | dependencies = [ 956 | "ansi_term", 957 | "ctor", 958 | "difference", 959 | "output_vt100", 960 | ] 961 | 962 | [[package]] 963 | name = "proc-macro-hack" 964 | version = "0.4.2" 965 | source = "registry+https://github.com/rust-lang/crates.io-index" 966 | checksum = "463bf29e7f11344e58c9e01f171470ab15c925c6822ad75028cc1c0e1d1eb63b" 967 | dependencies = [ 968 | "proc-macro-hack-impl", 969 | ] 970 | 971 | [[package]] 972 | name = "proc-macro-hack" 973 | version = "0.5.11" 974 | source = "registry+https://github.com/rust-lang/crates.io-index" 975 | checksum = "ecd45702f76d6d3c75a80564378ae228a85f0b59d2f3ed43c91b4a69eb2ebfc5" 976 | dependencies = [ 977 | "proc-macro2 1.0.8", 978 | "quote 1.0.2", 979 | "syn 1.0.14", 980 | ] 981 | 982 | [[package]] 983 | name = "proc-macro-hack-impl" 984 | version = "0.4.2" 985 | source = "registry+https://github.com/rust-lang/crates.io-index" 986 | checksum = "38c47dcb1594802de8c02f3b899e2018c78291168a22c281be21ea0fb4796842" 987 | 988 | [[package]] 989 | name = "proc-macro-nested" 990 | version = "0.1.3" 991 | source = "registry+https://github.com/rust-lang/crates.io-index" 992 | checksum = "369a6ed065f249a159e06c45752c780bda2fb53c995718f9e484d08daa9eb42e" 993 | 994 | [[package]] 995 | name = "proc-macro2" 996 | version = "0.2.3" 997 | source = "registry+https://github.com/rust-lang/crates.io-index" 998 | checksum = "cd07deb3c6d1d9ff827999c7f9b04cdfd66b1b17ae508e14fe47b620f2282ae0" 999 | dependencies = [ 1000 | "unicode-xid 0.1.0", 1001 | ] 1002 | 1003 | [[package]] 1004 | name = "proc-macro2" 1005 | version = "0.4.27" 1006 | source = "registry+https://github.com/rust-lang/crates.io-index" 1007 | checksum = "4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915" 1008 | dependencies = [ 1009 | "unicode-xid 0.1.0", 1010 | ] 1011 | 1012 | [[package]] 1013 | name = "proc-macro2" 1014 | version = "1.0.8" 1015 | source = "registry+https://github.com/rust-lang/crates.io-index" 1016 | checksum = "3acb317c6ff86a4e579dfa00fc5e6cca91ecbb4e7eb2df0468805b674eb88548" 1017 | dependencies = [ 1018 | "unicode-xid 0.2.0", 1019 | ] 1020 | 1021 | [[package]] 1022 | name = "quick-error" 1023 | version = "1.2.3" 1024 | source = "registry+https://github.com/rust-lang/crates.io-index" 1025 | checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" 1026 | 1027 | [[package]] 1028 | name = "quote" 1029 | version = "0.4.2" 1030 | source = "registry+https://github.com/rust-lang/crates.io-index" 1031 | checksum = "1eca14c727ad12702eb4b6bfb5a232287dcf8385cb8ca83a3eeaf6519c44c408" 1032 | dependencies = [ 1033 | "proc-macro2 0.2.3", 1034 | ] 1035 | 1036 | [[package]] 1037 | name = "quote" 1038 | version = "0.6.11" 1039 | source = "registry+https://github.com/rust-lang/crates.io-index" 1040 | checksum = "cdd8e04bd9c52e0342b406469d494fcb033be4bdbe5c606016defbb1681411e1" 1041 | dependencies = [ 1042 | "proc-macro2 0.4.27", 1043 | ] 1044 | 1045 | [[package]] 1046 | name = "quote" 1047 | version = "1.0.2" 1048 | source = "registry+https://github.com/rust-lang/crates.io-index" 1049 | checksum = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" 1050 | dependencies = [ 1051 | "proc-macro2 1.0.8", 1052 | ] 1053 | 1054 | [[package]] 1055 | name = "rand" 1056 | version = "0.5.6" 1057 | source = "registry+https://github.com/rust-lang/crates.io-index" 1058 | checksum = "c618c47cd3ebd209790115ab837de41425723956ad3ce2e6a7f09890947cacb9" 1059 | dependencies = [ 1060 | "cloudabi", 1061 | "fuchsia-cprng", 1062 | "libc", 1063 | "rand_core 0.3.1", 1064 | "winapi", 1065 | ] 1066 | 1067 | [[package]] 1068 | name = "rand" 1069 | version = "0.7.3" 1070 | source = "registry+https://github.com/rust-lang/crates.io-index" 1071 | checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" 1072 | dependencies = [ 1073 | "getrandom", 1074 | "libc", 1075 | "rand_chacha", 1076 | "rand_core 0.5.1", 1077 | "rand_hc", 1078 | ] 1079 | 1080 | [[package]] 1081 | name = "rand_chacha" 1082 | version = "0.2.1" 1083 | source = "registry+https://github.com/rust-lang/crates.io-index" 1084 | checksum = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" 1085 | dependencies = [ 1086 | "c2-chacha", 1087 | "rand_core 0.5.1", 1088 | ] 1089 | 1090 | [[package]] 1091 | name = "rand_core" 1092 | version = "0.3.1" 1093 | source = "registry+https://github.com/rust-lang/crates.io-index" 1094 | checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" 1095 | dependencies = [ 1096 | "rand_core 0.4.2", 1097 | ] 1098 | 1099 | [[package]] 1100 | name = "rand_core" 1101 | version = "0.4.2" 1102 | source = "registry+https://github.com/rust-lang/crates.io-index" 1103 | checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" 1104 | 1105 | [[package]] 1106 | name = "rand_core" 1107 | version = "0.5.1" 1108 | source = "registry+https://github.com/rust-lang/crates.io-index" 1109 | checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" 1110 | dependencies = [ 1111 | "getrandom", 1112 | ] 1113 | 1114 | [[package]] 1115 | name = "rand_hc" 1116 | version = "0.2.0" 1117 | source = "registry+https://github.com/rust-lang/crates.io-index" 1118 | checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" 1119 | dependencies = [ 1120 | "rand_core 0.5.1", 1121 | ] 1122 | 1123 | [[package]] 1124 | name = "redox_syscall" 1125 | version = "0.1.56" 1126 | source = "registry+https://github.com/rust-lang/crates.io-index" 1127 | checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" 1128 | 1129 | [[package]] 1130 | name = "reed-solomon" 1131 | version = "0.2.1" 1132 | source = "registry+https://github.com/rust-lang/crates.io-index" 1133 | checksum = "13de68c877a77f35885442ac72c8beb7c2f0b09380c43b734b9d63d1db69ee54" 1134 | 1135 | [[package]] 1136 | name = "regex" 1137 | version = "1.1.2" 1138 | source = "registry+https://github.com/rust-lang/crates.io-index" 1139 | checksum = "53ee8cfdddb2e0291adfb9f13d31d3bbe0a03c9a402c01b1e24188d86c35b24f" 1140 | dependencies = [ 1141 | "aho-corasick", 1142 | "memchr", 1143 | "regex-syntax", 1144 | "thread_local", 1145 | "utf8-ranges", 1146 | ] 1147 | 1148 | [[package]] 1149 | name = "regex-syntax" 1150 | version = "0.6.13" 1151 | source = "registry+https://github.com/rust-lang/crates.io-index" 1152 | checksum = "e734e891f5b408a29efbf8309e656876276f49ab6a6ac208600b4419bd893d90" 1153 | 1154 | [[package]] 1155 | name = "rust-base58" 1156 | version = "0.0.4" 1157 | source = "registry+https://github.com/rust-lang/crates.io-index" 1158 | checksum = "b313b91fcdc6719ad41fa2dad2b7e810b03833fae4bf911950e15529a5f04439" 1159 | dependencies = [ 1160 | "num", 1161 | ] 1162 | 1163 | [[package]] 1164 | name = "rustc-demangle" 1165 | version = "0.1.16" 1166 | source = "registry+https://github.com/rust-lang/crates.io-index" 1167 | checksum = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" 1168 | 1169 | [[package]] 1170 | name = "rustc_version" 1171 | version = "0.2.3" 1172 | source = "registry+https://github.com/rust-lang/crates.io-index" 1173 | checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" 1174 | dependencies = [ 1175 | "semver", 1176 | ] 1177 | 1178 | [[package]] 1179 | name = "ryu" 1180 | version = "0.2.8" 1181 | source = "registry+https://github.com/rust-lang/crates.io-index" 1182 | checksum = "b96a9549dc8d48f2c283938303c4b5a77aa29bfbc5b54b084fb1630408899a8f" 1183 | 1184 | [[package]] 1185 | name = "scopeguard" 1186 | version = "1.0.0" 1187 | source = "registry+https://github.com/rust-lang/crates.io-index" 1188 | checksum = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" 1189 | 1190 | [[package]] 1191 | name = "semver" 1192 | version = "0.9.0" 1193 | source = "registry+https://github.com/rust-lang/crates.io-index" 1194 | checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" 1195 | dependencies = [ 1196 | "semver-parser", 1197 | ] 1198 | 1199 | [[package]] 1200 | name = "semver-parser" 1201 | version = "0.7.0" 1202 | source = "registry+https://github.com/rust-lang/crates.io-index" 1203 | checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" 1204 | 1205 | [[package]] 1206 | name = "serde" 1207 | version = "1.0.89" 1208 | source = "registry+https://github.com/rust-lang/crates.io-index" 1209 | checksum = "92514fb95f900c9b5126e32d020f5c6d40564c27a5ea6d1d7d9f157a96623560" 1210 | 1211 | [[package]] 1212 | name = "serde_derive" 1213 | version = "1.0.89" 1214 | source = "registry+https://github.com/rust-lang/crates.io-index" 1215 | checksum = "bb6eabf4b5914e88e24eea240bb7c9f9a2cbc1bbbe8d961d381975ec3c6b806c" 1216 | dependencies = [ 1217 | "proc-macro2 0.4.27", 1218 | "quote 0.6.11", 1219 | "syn 0.15.31", 1220 | ] 1221 | 1222 | [[package]] 1223 | name = "serde_json" 1224 | version = "1.0.39" 1225 | source = "registry+https://github.com/rust-lang/crates.io-index" 1226 | checksum = "5a23aa71d4a4d43fdbfaac00eff68ba8a06a51759a89ac3304323e800c4dd40d" 1227 | dependencies = [ 1228 | "indexmap", 1229 | "itoa", 1230 | "ryu", 1231 | "serde", 1232 | ] 1233 | 1234 | [[package]] 1235 | name = "sha1" 1236 | version = "0.5.0" 1237 | source = "registry+https://github.com/rust-lang/crates.io-index" 1238 | checksum = "171698ce4ec7cbb93babeb3190021b4d72e96ccb98e33d277ae4ea959d6f2d9e" 1239 | 1240 | [[package]] 1241 | name = "sha2" 1242 | version = "0.7.1" 1243 | source = "registry+https://github.com/rust-lang/crates.io-index" 1244 | checksum = "9eb6be24e4c23a84d7184280d2722f7f2731fcdd4a9d886efbfe4413e4847ea0" 1245 | dependencies = [ 1246 | "block-buffer", 1247 | "byte-tools", 1248 | "digest", 1249 | "fake-simd", 1250 | ] 1251 | 1252 | [[package]] 1253 | name = "shrinkwraprs" 1254 | version = "0.2.1" 1255 | source = "registry+https://github.com/rust-lang/crates.io-index" 1256 | checksum = "7d5f047b90b2ca2d1526ff73d67cba61f86f4cf9a8afddc99dd96702ded8e684" 1257 | dependencies = [ 1258 | "bitflags", 1259 | "itertools", 1260 | "quote 0.4.2", 1261 | "syn 0.12.15", 1262 | ] 1263 | 1264 | [[package]] 1265 | name = "slab" 1266 | version = "0.4.2" 1267 | source = "registry+https://github.com/rust-lang/crates.io-index" 1268 | checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" 1269 | 1270 | [[package]] 1271 | name = "smallvec" 1272 | version = "0.6.13" 1273 | source = "registry+https://github.com/rust-lang/crates.io-index" 1274 | checksum = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6" 1275 | dependencies = [ 1276 | "maybe-uninit", 1277 | ] 1278 | 1279 | [[package]] 1280 | name = "smallvec" 1281 | version = "1.1.0" 1282 | source = "registry+https://github.com/rust-lang/crates.io-index" 1283 | checksum = "44e59e0c9fa00817912ae6e4e6e3c4fe04455e75699d06eedc7d85917ed8e8f4" 1284 | 1285 | [[package]] 1286 | name = "snowflake" 1287 | version = "1.3.0" 1288 | source = "registry+https://github.com/rust-lang/crates.io-index" 1289 | checksum = "27207bb65232eda1f588cf46db2fee75c0808d557f6b3cf19a75f5d6d7c94df1" 1290 | 1291 | [[package]] 1292 | name = "syn" 1293 | version = "0.12.15" 1294 | source = "registry+https://github.com/rust-lang/crates.io-index" 1295 | checksum = "c97c05b8ebc34ddd6b967994d5c6e9852fa92f8b82b3858c39451f97346dcce5" 1296 | dependencies = [ 1297 | "proc-macro2 0.2.3", 1298 | "quote 0.4.2", 1299 | "unicode-xid 0.1.0", 1300 | ] 1301 | 1302 | [[package]] 1303 | name = "syn" 1304 | version = "0.15.31" 1305 | source = "registry+https://github.com/rust-lang/crates.io-index" 1306 | checksum = "d2b4cfac95805274c6afdb12d8f770fa2d27c045953e7b630a81801953699a9a" 1307 | dependencies = [ 1308 | "proc-macro2 0.4.27", 1309 | "quote 0.6.11", 1310 | "unicode-xid 0.1.0", 1311 | ] 1312 | 1313 | [[package]] 1314 | name = "syn" 1315 | version = "1.0.14" 1316 | source = "registry+https://github.com/rust-lang/crates.io-index" 1317 | checksum = "af6f3550d8dff9ef7dc34d384ac6f107e5d31c8f57d9f28e0081503f547ac8f5" 1318 | dependencies = [ 1319 | "proc-macro2 1.0.8", 1320 | "quote 1.0.2", 1321 | "unicode-xid 0.2.0", 1322 | ] 1323 | 1324 | [[package]] 1325 | name = "synstructure" 1326 | version = "0.10.2" 1327 | source = "registry+https://github.com/rust-lang/crates.io-index" 1328 | checksum = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f" 1329 | dependencies = [ 1330 | "proc-macro2 0.4.27", 1331 | "quote 0.6.11", 1332 | "syn 0.15.31", 1333 | "unicode-xid 0.1.0", 1334 | ] 1335 | 1336 | [[package]] 1337 | name = "termcolor" 1338 | version = "1.1.0" 1339 | source = "registry+https://github.com/rust-lang/crates.io-index" 1340 | checksum = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f" 1341 | dependencies = [ 1342 | "winapi-util", 1343 | ] 1344 | 1345 | [[package]] 1346 | name = "thread_local" 1347 | version = "0.3.6" 1348 | source = "registry+https://github.com/rust-lang/crates.io-index" 1349 | checksum = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" 1350 | dependencies = [ 1351 | "lazy_static", 1352 | ] 1353 | 1354 | [[package]] 1355 | name = "time" 1356 | version = "0.1.42" 1357 | source = "registry+https://github.com/rust-lang/crates.io-index" 1358 | checksum = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" 1359 | dependencies = [ 1360 | "libc", 1361 | "redox_syscall", 1362 | "winapi", 1363 | ] 1364 | 1365 | [[package]] 1366 | name = "tiny-keccak" 1367 | version = "1.5.0" 1368 | source = "registry+https://github.com/rust-lang/crates.io-index" 1369 | checksum = "1d8a021c69bb74a44ccedb824a046447e2c84a01df9e5c20779750acb38e11b2" 1370 | dependencies = [ 1371 | "crunchy", 1372 | ] 1373 | 1374 | [[package]] 1375 | name = "toml" 1376 | version = "0.5.0" 1377 | source = "registry+https://github.com/rust-lang/crates.io-index" 1378 | checksum = "87c5890a989fa47ecdc7bcb4c63a77a82c18f306714104b1decfd722db17b39e" 1379 | dependencies = [ 1380 | "serde", 1381 | ] 1382 | 1383 | [[package]] 1384 | name = "typenum" 1385 | version = "1.11.2" 1386 | source = "registry+https://github.com/rust-lang/crates.io-index" 1387 | checksum = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9" 1388 | 1389 | [[package]] 1390 | name = "unicode-bidi" 1391 | version = "0.3.4" 1392 | source = "registry+https://github.com/rust-lang/crates.io-index" 1393 | checksum = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" 1394 | dependencies = [ 1395 | "matches", 1396 | ] 1397 | 1398 | [[package]] 1399 | name = "unicode-normalization" 1400 | version = "0.1.12" 1401 | source = "registry+https://github.com/rust-lang/crates.io-index" 1402 | checksum = "5479532badd04e128284890390c1e876ef7a993d0570b3597ae43dfa1d59afa4" 1403 | dependencies = [ 1404 | "smallvec 1.1.0", 1405 | ] 1406 | 1407 | [[package]] 1408 | name = "unicode-xid" 1409 | version = "0.1.0" 1410 | source = "registry+https://github.com/rust-lang/crates.io-index" 1411 | checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" 1412 | 1413 | [[package]] 1414 | name = "unicode-xid" 1415 | version = "0.2.0" 1416 | source = "registry+https://github.com/rust-lang/crates.io-index" 1417 | checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" 1418 | 1419 | [[package]] 1420 | name = "url" 1421 | version = "2.1.0" 1422 | source = "registry+https://github.com/rust-lang/crates.io-index" 1423 | checksum = "75b414f6c464c879d7f9babf951f23bc3743fb7313c081b2e6ca719067ea9d61" 1424 | dependencies = [ 1425 | "idna", 1426 | "matches", 1427 | "percent-encoding", 1428 | ] 1429 | 1430 | [[package]] 1431 | name = "utf8-ranges" 1432 | version = "1.0.4" 1433 | source = "registry+https://github.com/rust-lang/crates.io-index" 1434 | checksum = "b4ae116fef2b7fea257ed6440d3cfcff7f190865f170cdad00bb6465bf18ecba" 1435 | 1436 | [[package]] 1437 | name = "uuid" 1438 | version = "0.7.1" 1439 | source = "registry+https://github.com/rust-lang/crates.io-index" 1440 | checksum = "dab5c5526c5caa3d106653401a267fed923e7046f35895ffcb5ca42db64942e6" 1441 | dependencies = [ 1442 | "rand 0.5.6", 1443 | ] 1444 | 1445 | [[package]] 1446 | name = "wasi" 1447 | version = "0.9.0+wasi-snapshot-preview1" 1448 | source = "registry+https://github.com/rust-lang/crates.io-index" 1449 | checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" 1450 | 1451 | [[package]] 1452 | name = "wasmi" 1453 | version = "0.4.4" 1454 | source = "registry+https://github.com/rust-lang/crates.io-index" 1455 | checksum = "f6a891b45c79e9f96fb66cc84a057211ef9cd2e5e8d093f3dbbd480e146a8758" 1456 | dependencies = [ 1457 | "memory_units", 1458 | "parity-wasm", 1459 | ] 1460 | 1461 | [[package]] 1462 | name = "winapi" 1463 | version = "0.3.8" 1464 | source = "registry+https://github.com/rust-lang/crates.io-index" 1465 | checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" 1466 | dependencies = [ 1467 | "winapi-i686-pc-windows-gnu", 1468 | "winapi-x86_64-pc-windows-gnu", 1469 | ] 1470 | 1471 | [[package]] 1472 | name = "winapi-i686-pc-windows-gnu" 1473 | version = "0.4.0" 1474 | source = "registry+https://github.com/rust-lang/crates.io-index" 1475 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1476 | 1477 | [[package]] 1478 | name = "winapi-util" 1479 | version = "0.1.3" 1480 | source = "registry+https://github.com/rust-lang/crates.io-index" 1481 | checksum = "4ccfbf554c6ad11084fb7517daca16cfdcaccbdadba4fc336f032a8b12c2ad80" 1482 | dependencies = [ 1483 | "winapi", 1484 | ] 1485 | 1486 | [[package]] 1487 | name = "winapi-x86_64-pc-windows-gnu" 1488 | version = "0.4.0" 1489 | source = "registry+https://github.com/rust-lang/crates.io-index" 1490 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1491 | 1492 | [[package]] 1493 | name = "zeroize" 1494 | version = "0.9.2" 1495 | source = "registry+https://github.com/rust-lang/crates.io-index" 1496 | checksum = "4177936c03b5a349c1b8e4509c46add268e66bc66fe92663729fa0570fe4f213" 1497 | dependencies = [ 1498 | "zeroize_derive", 1499 | ] 1500 | 1501 | [[package]] 1502 | name = "zeroize_derive" 1503 | version = "0.9.3" 1504 | source = "registry+https://github.com/rust-lang/crates.io-index" 1505 | checksum = "080616bd0e31f36095288bb0acdf1f78ef02c2fa15527d7e993f2a6c7591643e" 1506 | dependencies = [ 1507 | "proc-macro2 0.4.27", 1508 | "quote 0.6.11", 1509 | "syn 0.15.31", 1510 | "synstructure", 1511 | ] 1512 | -------------------------------------------------------------------------------- /dna/zomes/courses/code/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "courses" 3 | version = "0.1.0" 4 | authors = ["hc-scaffold-framework"] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | serde = "=1.0.89" 9 | serde_json = { version = "=1.0.39", features = ["preserve_order"] } 10 | serde_derive = "=1.0.89" 11 | hdk = "=0.0.42-alpha5" 12 | hdk_proc_macros = "=0.0.42-alpha5" 13 | holochain_wasm_utils = "=0.0.42-alpha5" 14 | holochain_json_derive = "=0.0.1-alpha2" 15 | 16 | [lib] 17 | path = "src/lib.rs" 18 | crate-type = ["cdylib"] 19 | -------------------------------------------------------------------------------- /dna/zomes/courses/code/src/content.rs: -------------------------------------------------------------------------------- 1 | /************************ Import Required Libraries */ 2 | use crate::course; 3 | use crate::course::Course; 4 | use crate::module::Module; 5 | use hdk::holochain_core_types::dna::entry_types::Sharing; 6 | use hdk::holochain_core_types::{entry::Entry, validation::EntryValidationData}; 7 | use hdk::holochain_json_api::{error::JsonError, json::JsonString}; 8 | use hdk::holochain_persistence_api::cas::content::Address; 9 | use hdk::prelude::LinkMatch; 10 | use hdk::{ 11 | entry_definition::ValidatingEntryType, 12 | error::{ZomeApiError, ZomeApiResult}, 13 | AGENT_ADDRESS, 14 | }; 15 | use holochain_wasm_utils::api_serialization::{ 16 | get_entry::{GetEntryOptions, GetEntryResult}, 17 | get_links::GetLinksOptions, 18 | }; 19 | use std::convert::TryFrom; 20 | /******************************************* */ 21 | 22 | #[derive(Serialize, Deserialize, Debug, DefaultJson, Clone)] 23 | pub struct Content { 24 | name: String, 25 | url: String, 26 | description: String, 27 | timestamp: u64, 28 | module_address: Address, 29 | } 30 | 31 | impl Content { 32 | pub fn new( 33 | name: String, 34 | module_address: Address, 35 | url: String, 36 | timestamp: u64, 37 | description: String, 38 | ) -> Self { 39 | Content { 40 | name, 41 | url, 42 | description, 43 | timestamp, 44 | module_address, 45 | } 46 | } 47 | 48 | pub fn entry(&self) -> Entry { 49 | Entry::App("content".into(), self.into()) 50 | } 51 | } 52 | 53 | ////////////////////Course Entry Definition 54 | pub fn module_entry_def() -> ValidatingEntryType { 55 | entry!( 56 | name: "content", 57 | description: "this is the content for each module", 58 | sharing: Sharing::Public, 59 | validation_package: || { 60 | hdk::ValidationPackageDefinition::Entry 61 | }, 62 | validation: | validation_data: hdk::EntryValidationData| { 63 | match validation_data { 64 | EntryValidationData::Create { entry, validation_data } => { 65 | validate_author(&validation_data.sources(), &entry.module_address)?; 66 | Ok(()) 67 | }, 68 | EntryValidationData::Modify { new_entry, old_entry, validation_data, .. } => { 69 | if new_entry.module_address != old_entry.module_address { 70 | return Err(String::from("Cannot modify the module of a content")); 71 | } 72 | validate_author(&validation_data.sources(), &new_entry.module_address)?; 73 | Ok(()) 74 | }, 75 | EntryValidationData::Delete { old_entry, validation_data, .. } => { 76 | validate_author(&validation_data.sources(), &old_entry.module_address)?; 77 | 78 | Ok(()) 79 | } 80 | } 81 | } 82 | ) 83 | } 84 | /////////////////////////// Validations 85 | pub fn validate_author( 86 | signing_addresses: &Vec
, 87 | module_address: &Address, 88 | ) -> ZomeApiResult<()> { 89 | let module: Module = hdk::utils::get_as_type(module_address.clone())?; 90 | let course: Course = hdk::utils::get_as_type(module.course_address.clone())?; 91 | if !signing_addresses.contains(&course.teacher_address) { 92 | return Err(ZomeApiError::from(String::from( 93 | "Error: Only the teacher can create or modify a content for module", 94 | ))); 95 | } 96 | Ok(()) 97 | } 98 | 99 | /// Helper Functions 100 | pub fn create( 101 | name: String, 102 | module_address: Address, 103 | url: String, 104 | timestamp: u64, 105 | description: String, 106 | ) -> ZomeApiResult
{ 107 | let new_content = Content::new(name, module_address.clone(), url, timestamp, description); 108 | let new_content_entry = new_content.entry(); 109 | let new_content_address = hdk::commit_entry(&new_content_entry)?; 110 | hdk::link_entries( 111 | &module_address, 112 | &new_content_address, 113 | "module->contents", 114 | "", 115 | )?; 116 | 117 | Ok(new_content_address) 118 | } 119 | 120 | pub fn get_contents(module_address: &Address) -> ZomeApiResult> { 121 | let links = hdk::get_links( 122 | &module_address, 123 | LinkMatch::Exactly("module->contents"), 124 | LinkMatch::Any, 125 | )?; 126 | 127 | Ok(links.addresses()) 128 | } 129 | pub fn delete(content_address: Address) -> ZomeApiResult
{ 130 | let content: Content = hdk::utils::get_as_type(content_address.clone())?; 131 | 132 | hdk::remove_link( 133 | &content.module_address, 134 | &content_address, 135 | "module->contents", 136 | "", 137 | )?; 138 | 139 | hdk::remove_entry(&content_address) 140 | } 141 | 142 | pub fn update( 143 | content_address: Address, 144 | name: String, 145 | url: String, 146 | description: String, 147 | ) -> ZomeApiResult
{ 148 | let mut content: Content = hdk::utils::get_as_type(content_address.clone())?; 149 | content.description = description; 150 | content.name = name; 151 | content.url = url; 152 | hdk::update_entry(content.entry(), &content_address) 153 | } 154 | -------------------------------------------------------------------------------- /dna/zomes/courses/code/src/course.rs: -------------------------------------------------------------------------------- 1 | /************************ Import Required Libraries */ 2 | use hdk::{ 3 | entry_definition::ValidatingEntryType, 4 | error::{ZomeApiError, ZomeApiResult}, 5 | AGENT_ADDRESS, 6 | }; 7 | 8 | use hdk::holochain_core_types::dna::entry_types::Sharing; 9 | use hdk::holochain_core_types::{entry::Entry, validation::EntryValidationData}; 10 | use holochain_wasm_utils::api_serialization::{ 11 | get_entry::{GetEntryOptions, GetEntryResult}, 12 | get_links::GetLinksOptions, 13 | }; 14 | 15 | use hdk::holochain_json_api::{error::JsonError, json::JsonString}; 16 | use hdk::holochain_persistence_api::cas::content::Address; 17 | use hdk::prelude::AddressableContent; 18 | use hdk::prelude::LinkMatch; 19 | use hdk::ValidationData; 20 | use std::convert::TryFrom; 21 | /******************************************* */ 22 | 23 | #[derive(Serialize, Deserialize, Debug, DefaultJson, Clone)] 24 | pub struct Course { 25 | pub title: String, 26 | pub modules: Vec
, 27 | pub timestamp: u64, 28 | pub teacher_address: Address, 29 | } 30 | 31 | impl Course { 32 | // Constrcuctor 33 | pub fn new(title: String, owner: Address, timestamp: u64) -> Self { 34 | Course { 35 | title: title, 36 | teacher_address: owner, 37 | modules: Vec::default(), 38 | timestamp: timestamp, 39 | } 40 | } 41 | pub fn from(title: String, owner: Address, timestamp: u64, modules: Vec
) -> Self { 42 | Course { 43 | title: title, 44 | teacher_address: owner, 45 | modules: modules, 46 | timestamp: timestamp, 47 | } 48 | } 49 | 50 | pub fn entry(&self) -> Entry { 51 | Entry::App("course".into(), self.into()) 52 | } 53 | } 54 | 55 | ////////////////////Course Entry Definition 56 | pub fn course_entry_def() -> ValidatingEntryType { 57 | entry!( 58 | name: "course", 59 | description: "this is the definition of course", 60 | sharing: Sharing::Public, 61 | validation_package: || { 62 | hdk::ValidationPackageDefinition::Entry 63 | }, 64 | validation: | validation_data: hdk::EntryValidationData| { 65 | match validation_data{ 66 | EntryValidationData::Create { entry, validation_data } => { 67 | if !validation_data.sources().contains(&entry.teacher_address) { 68 | return Err(String::from("Only the teacher can create their courses")); 69 | } 70 | 71 | validate_course_title(&entry.title) 72 | }, 73 | EntryValidationData::Modify { new_entry, old_entry, validation_data, .. } => { 74 | if new_entry.teacher_address != old_entry.teacher_address { 75 | return Err(String::from("Cannot change the teacher of the course")); 76 | } 77 | 78 | if !validation_data.sources().contains(&old_entry.teacher_address) { 79 | return Err(String::from("Only the teacher can modify their courses")); 80 | } 81 | 82 | validate_course_title(&new_entry.title)?; 83 | 84 | Ok(()) 85 | }, 86 | EntryValidationData::Delete {old_entry, validation_data, .. } => { 87 | if !validation_data.sources().contains(&old_entry.teacher_address) { 88 | return Err(String::from("Only the teacher can delete their courses")); 89 | } 90 | 91 | Ok(()) 92 | } 93 | } 94 | }, 95 | links: [ 96 | from!( // to query all the courses of a user(all courses that a user is the teacher or owner of) 97 | "%agent_id", 98 | link_type: "teacher->courses", 99 | validation_package: || { 100 | hdk::ValidationPackageDefinition::Entry 101 | } , 102 | validation: | _validation_data: hdk::LinkValidationData | { 103 | // TODO: Homework. Implement validation rules if required. 104 | Ok(()) 105 | } 106 | ), 107 | from!( // to query all courses that one user enrolled 108 | "%agent_id", 109 | link_type: "student->courses", 110 | validation_package: || { 111 | hdk::ValidationPackageDefinition::Entry 112 | } , 113 | validation: | _validation_data: hdk::LinkValidationData | { 114 | // TODO: Homework. Implement validation rules if required. 115 | Ok(()) 116 | } 117 | ), 118 | to!( // to query all enrolled user for a course 119 | "%agent_id", 120 | link_type: "course->students", 121 | validation_package: || { 122 | hdk::ValidationPackageDefinition::Entry 123 | }, 124 | validation: | _validation_data: hdk::LinkValidationData | { 125 | // TODO: Homework. Implement validation rules if required. 126 | Ok(()) 127 | } 128 | ) 129 | ] 130 | ) 131 | } 132 | 133 | //// Anchor Definition : This Anchor will be used to query all courses 134 | pub fn anchor_entry_def() -> ValidatingEntryType { 135 | entry!( 136 | name: "anchor", 137 | description:"Anchor to all Courses", 138 | sharing: Sharing::Public, 139 | validation_package:||{ 140 | hdk::ValidationPackageDefinition::Entry 141 | }, 142 | validation:|_validation_data: hdk::EntryValidationData|{ 143 | Ok(()) 144 | }, 145 | links:[ 146 | to!( 147 | "course", 148 | link_type: "course_list", 149 | validation_package:||{ 150 | hdk::ValidationPackageDefinition::Entry 151 | }, 152 | validation:|_validation_data: hdk::LinkValidationData|{ 153 | Ok(()) 154 | } 155 | ) 156 | ] 157 | ) 158 | } 159 | 160 | pub fn anchor_entry() -> Entry { 161 | Entry::App("anchor".into(), "course".into()) 162 | } 163 | 164 | pub fn anchor_address() -> ZomeApiResult
{ 165 | hdk::entry_address(&anchor_entry()) 166 | } 167 | 168 | /*********************** Course Validations */ 169 | fn validate_course_title(title: &str) -> Result<(), String> { 170 | if title.len() > 50 { 171 | Err("Course title is too long".into()) 172 | } else { 173 | Ok(()) 174 | } 175 | } 176 | 177 | /********************************************** */ 178 | /// Course Helper Functions: CRUD 179 | 180 | pub fn create(title: String, timestamp: u64) -> ZomeApiResult
{ 181 | let anchor_entry = anchor_entry(); 182 | let anchor_address = hdk::commit_entry(&anchor_entry)?; // if Anchor exist, it returns the commited one. 183 | 184 | let new_course = Course::new(title, AGENT_ADDRESS.to_string().into(), timestamp); 185 | let new_course_entry = new_course.entry(); 186 | let new_course_address = hdk::commit_entry(&new_course_entry)?; 187 | 188 | hdk::link_entries(&AGENT_ADDRESS, &new_course_address, "teacher->courses", "")?; 189 | 190 | hdk::link_entries(&anchor_address, &new_course_address, "course_list", "")?; 191 | 192 | Ok(new_course_address) 193 | } 194 | 195 | pub fn update( 196 | title: String, 197 | modules_addresses: Vec
, 198 | course_address: &Address, 199 | ) -> ZomeApiResult
{ 200 | let course: Course = hdk::utils::get_as_type(course_address.clone())?; 201 | 202 | let new_version_course = Course::from( 203 | title, 204 | course.teacher_address, 205 | course.timestamp, 206 | modules_addresses, 207 | ); 208 | let new_version_course_entry = new_version_course.entry(); 209 | 210 | hdk::update_entry(new_version_course_entry, course_address) 211 | } 212 | 213 | pub fn delete(address: Address) -> ZomeApiResult
{ 214 | hdk::remove_link(&anchor_address()?, &address, "course_list", "")?; 215 | 216 | let students = get_students(address.clone())?; 217 | let course: Course = hdk::utils::get_as_type(address.clone())?; 218 | 219 | for student in students { 220 | hdk::remove_link(&student, &address, "student->course", "")?; 221 | } 222 | hdk::remove_link(&course.teacher_address, &address, "teacher->courses", "")?; 223 | 224 | hdk::remove_entry(&address) 225 | } 226 | 227 | pub fn list() -> ZomeApiResult> { 228 | let addresses = hdk::get_links( 229 | &anchor_address()?, 230 | LinkMatch::Exactly("course_list"), 231 | LinkMatch::Any, 232 | )? 233 | .addresses(); 234 | 235 | Ok(addresses) 236 | } 237 | 238 | pub fn get_my_courses() -> ZomeApiResult> { 239 | let links = hdk::get_links( 240 | &AGENT_ADDRESS, 241 | LinkMatch::Exactly("teacher->courses"), 242 | LinkMatch::Any, 243 | )?; 244 | 245 | Ok(links.addresses()) 246 | } 247 | 248 | pub fn get_my_enrolled_courses() -> ZomeApiResult> { 249 | let links = hdk::get_links( 250 | &AGENT_ADDRESS, 251 | LinkMatch::Exactly("student->courses"), 252 | LinkMatch::Any, 253 | )?; 254 | 255 | Ok(links.addresses()) 256 | } 257 | 258 | pub fn add_module_to_course( 259 | course_address: &Address, 260 | module_address: &Address, 261 | ) -> ZomeApiResult
{ 262 | let current_course = hdk::get_entry(course_address).unwrap().unwrap(); 263 | if let Entry::App(_, current_course) = current_course { 264 | let mut course_entry = Course::try_from(current_course.clone()) 265 | .expect("Entry at this address is not Course. You sent a wrong address"); 266 | course_entry.modules.push(module_address.clone()); 267 | hdk::update_entry( 268 | Entry::App("course".into(), course_entry.into()), 269 | course_address, 270 | ) 271 | } else { 272 | panic!("This address is not a valid address") 273 | } 274 | } 275 | 276 | pub fn enrol_in_course(course_address: Address) -> ZomeApiResult
{ 277 | hdk::link_entries(&AGENT_ADDRESS, &course_address, "student->courses", "")?; 278 | hdk::link_entries(&course_address, &AGENT_ADDRESS, "course->students", "") 279 | } 280 | 281 | pub fn get_students(course_address: Address) -> ZomeApiResult> { 282 | let links = hdk::get_links( 283 | &course_address, 284 | LinkMatch::Exactly("course->students"), 285 | LinkMatch::Any, 286 | )?; 287 | 288 | Ok(links.addresses()) 289 | } 290 | -------------------------------------------------------------------------------- /dna/zomes/courses/code/src/lib.rs: -------------------------------------------------------------------------------- 1 | /***************** Required Library */ 2 | #![feature(vec_remove_item)] 3 | #![allow(dead_code)] 4 | #![allow(unused_imports)] 5 | #![feature(proc_macro_hygiene)] 6 | #[macro_use] 7 | extern crate hdk; 8 | extern crate hdk_proc_macros; 9 | extern crate serde; 10 | #[macro_use] 11 | extern crate serde_derive; 12 | extern crate serde_json; 13 | #[macro_use] 14 | extern crate holochain_json_derive; 15 | 16 | use hdk::prelude::*; 17 | 18 | //use hdk::holochain_json_api::json::JsonString; 19 | 20 | use hdk::holochain_json_api::{error::JsonError, json::JsonString}; 21 | use hdk::holochain_persistence_api::cas::content::Address; 22 | use hdk::AGENT_ADDRESS; 23 | use hdk_proc_macros::zome; 24 | 25 | //use std::convert::TryInto; 26 | 27 | /******************************** */ 28 | mod content; 29 | mod course; 30 | mod module; 31 | use course::Course; 32 | #[zome] 33 | mod course_zome { 34 | 35 | #[init] 36 | fn init() { 37 | Ok(()) 38 | } 39 | 40 | #[validate_agent] 41 | pub fn validate_agent(validation_data: EntryValidationData) { 42 | Ok(()) 43 | } 44 | 45 | #[zome_fn("hc_public")] 46 | fn get_my_address() -> ZomeApiResult
{ 47 | Ok(AGENT_ADDRESS.clone()) 48 | } 49 | 50 | /**************************** Course Entry Definition and Functions */ 51 | #[entry_def] 52 | fn anchor_entry_definition() -> ValidatingEntryType { 53 | course::anchor_entry_def() 54 | } 55 | 56 | #[entry_def] 57 | fn course_entry_definition() -> ValidatingEntryType { 58 | course::course_entry_def() 59 | } 60 | 61 | #[zome_fn("hc_public")] 62 | fn create_course(title: String, timestamp: u64) -> ZomeApiResult
{ 63 | course::create(title, timestamp) 64 | } 65 | 66 | #[zome_fn("hc_public")] 67 | fn get_entry(address: Address) -> ZomeApiResult> { 68 | hdk::get_entry(&address) 69 | } 70 | 71 | #[zome_fn("hc_public")] 72 | fn update_course( 73 | title: String, 74 | modules_addresses: Vec
, 75 | course_address: Address, 76 | ) -> ZomeApiResult
{ 77 | course::update(title, modules_addresses, &course_address) 78 | } 79 | 80 | #[zome_fn("hc_public")] 81 | fn delete_course(course_address: Address) -> ZomeApiResult
{ 82 | course::delete(course_address) 83 | } 84 | 85 | #[zome_fn("hc_public")] 86 | fn get_all_courses() -> ZomeApiResult> { 87 | course::list() 88 | } 89 | #[zome_fn("hc_public")] 90 | fn get_my_courses() -> ZomeApiResult> { 91 | course::get_my_courses() 92 | } 93 | 94 | #[zome_fn("hc_public")] 95 | fn get_my_enrolled_courses() -> ZomeApiResult> { 96 | course::get_my_enrolled_courses() 97 | } 98 | 99 | #[zome_fn("hc_public")] 100 | fn enrol_in_course(course_address: Address) -> ZomeApiResult
{ 101 | course::enrol_in_course(course_address) 102 | } 103 | 104 | #[zome_fn("hc_public")] 105 | fn get_all_students(course_address: Address) -> ZomeApiResult> { 106 | course::get_students(course_address) 107 | } 108 | 109 | /**************************** Module Entry Definition & Functions */ 110 | #[entry_def] 111 | fn module_entry_definition() -> ValidatingEntryType { 112 | module::entry_def() 113 | } 114 | 115 | #[zome_fn("hc_public")] 116 | fn create_module( 117 | title: String, 118 | course_address: Address, 119 | timestamp: u64, 120 | ) -> ZomeApiResult
{ 121 | module::create(title, &course_address, timestamp) 122 | } 123 | 124 | #[zome_fn("hc_public")] 125 | fn update_module(title: String, module_address: Address) -> ZomeApiResult
{ 126 | module::update(title, &module_address) 127 | } 128 | 129 | #[zome_fn("hc_public")] 130 | fn delete_module(module_address: Address) -> ZomeApiResult
{ 131 | module::delete(module_address) 132 | } 133 | 134 | /**************************** Content Zome Functions */ 135 | #[entry_def] 136 | fn content_entry_definition() -> ValidatingEntryType { 137 | content::module_entry_def() 138 | } 139 | 140 | #[zome_fn("hc_public")] 141 | fn create_content( 142 | name: String, 143 | module_address: Address, 144 | url: String, 145 | timestamp: u64, 146 | description: String, 147 | ) -> ZomeApiResult
{ 148 | content::create(name, module_address, url, timestamp, description) 149 | } 150 | 151 | #[zome_fn("hc_public")] 152 | fn get_contents(module_address: Address) -> ZomeApiResult> { 153 | content::get_contents(&module_address) 154 | } 155 | #[zome_fn("hc_public")] 156 | fn delete_content(content_address: Address) -> ZomeApiResult
{ 157 | content::delete(content_address) 158 | } 159 | 160 | #[zome_fn("hc_public")] 161 | fn update_content( 162 | content_address: Address, 163 | name: String, 164 | url: String, 165 | description: String, 166 | ) -> ZomeApiResult
{ 167 | content::update(content_address, name, url, description) 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /dna/zomes/courses/code/src/module.rs: -------------------------------------------------------------------------------- 1 | /************************ Import Required Libraries */ 2 | use hdk::prelude::*; 3 | 4 | use crate::course::Course; 5 | use std::convert::TryFrom; 6 | /******************************************* */ 7 | 8 | #[derive(Serialize, Deserialize, Debug, self::DefaultJson, Clone)] 9 | pub struct Module { 10 | pub title: String, 11 | pub timestamp: u64, 12 | pub course_address: Address, 13 | } 14 | 15 | impl Module { 16 | pub fn new(title: String, course_address: Address, timestamp: u64) -> Self { 17 | Module { 18 | title: title, 19 | course_address: course_address, 20 | timestamp: timestamp, 21 | } 22 | } 23 | 24 | pub fn entry(&self) -> Entry { 25 | Entry::App("module".into(), self.into()) 26 | } 27 | } 28 | 29 | /*********************** Course Validations */ 30 | fn validate_module_title(title: &str) -> Result<(), String> { 31 | if title.len() > 200 { 32 | Err("Module title is too long".into()) 33 | } else { 34 | Ok(()) 35 | } 36 | } 37 | 38 | pub fn validate_author(signing_addresses: &Vec
, module: &Module) -> ZomeApiResult<()> { 39 | let course: Course = hdk::utils::get_as_type(module.course_address.clone())?; 40 | hdk::debug(format!("{:?}", course))?; 41 | if !signing_addresses.contains(&course.teacher_address) { 42 | return Err(ZomeApiError::from(String::from( 43 | "Only the teacher can create or modify a module for it", 44 | ))); 45 | } 46 | Ok(()) 47 | } 48 | 49 | // Entry Definition 50 | pub fn entry_def() -> ValidatingEntryType { 51 | entry!( 52 | name: "module", 53 | description: "this is the definition of module", 54 | sharing: Sharing::Public, 55 | validation_package: || { 56 | hdk::ValidationPackageDefinition::Entry 57 | }, 58 | validation: | validation_data: hdk::EntryValidationData| { 59 | match validation_data { 60 | EntryValidationData::Create { entry, validation_data } => { 61 | validate_module_title(&entry.title)?; 62 | 63 | validate_author(&validation_data.sources(), &entry)?; 64 | 65 | Ok(()) 66 | }, 67 | EntryValidationData::Modify { new_entry, old_entry, validation_data, .. } => { 68 | validate_module_title(&new_entry.title)?; 69 | 70 | if new_entry.course_address != old_entry.course_address { 71 | return Err(String::from("Cannot modify the course of a module")); 72 | } 73 | validate_author(&validation_data.sources(), &new_entry)?; 74 | Ok(()) 75 | }, 76 | EntryValidationData::Delete { old_entry, validation_data, .. } => { 77 | validate_author(&validation_data.sources(), &old_entry)?; 78 | 79 | Ok(()) 80 | } 81 | } 82 | }, 83 | links:[ 84 | to!( 85 | "content", 86 | link_type: "module->contents", 87 | validation_package:||{ 88 | hdk::ValidationPackageDefinition::Entry 89 | }, 90 | validation:|_validation_data: hdk::LinkValidationData|{ 91 | // TODO: Homework. Implement validation rules if required. 92 | Ok(()) 93 | } 94 | ) 95 | ] 96 | ) 97 | } 98 | 99 | pub fn create(title: String, course_address: &Address, timestamp: u64) -> ZomeApiResult
{ 100 | let mut course: Course = hdk::utils::get_as_type(course_address.clone())?; 101 | 102 | let new_module = Module::new(title, course_address.clone(), timestamp); 103 | let new_module_address = hdk::commit_entry(&new_module.entry())?; 104 | 105 | course.modules.push(new_module_address.clone()); 106 | course.timestamp += 1; 107 | hdk::update_entry(course.entry(), &course_address)?; 108 | 109 | Ok(new_module_address) 110 | } 111 | 112 | pub fn update(title: String, module_address: &Address) -> ZomeApiResult
{ 113 | let mut module: Module = hdk::utils::get_as_type(module_address.clone())?; 114 | 115 | module.title = title; 116 | 117 | hdk::update_entry(module.entry(), module_address) 118 | } 119 | 120 | pub fn delete(module_address: Address) -> ZomeApiResult
{ 121 | let module: Module = hdk::utils::get_as_type(module_address.clone())?; 122 | 123 | let mut course: Course = hdk::utils::get_as_type(module.course_address.clone())?; 124 | 125 | let result = hdk::remove_entry(&module_address)?; 126 | 127 | course.modules.remove_item(&module_address); 128 | course.timestamp += 1; // we need to prevent duplication by changing the array. 129 | hdk::update_entry(course.entry(), &module.course_address)?; 130 | 131 | Ok(result) 132 | } 133 | -------------------------------------------------------------------------------- /dna/zomes/courses/zome.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "courses", 3 | "description": "Generated from the rust-zome-template" 4 | } 5 | -------------------------------------------------------------------------------- /ui.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/holochain-devcamp/learning-pathways/1820d7b98b1892f1b68d918ae821fb554adca408/ui.zip -------------------------------------------------------------------------------- /ui/.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | 8 | [*] 9 | 10 | # Change these settings to your own preference 11 | indent_style = space 12 | indent_size = 2 13 | 14 | # We recommend you to keep these unchanged 15 | end_of_line = lf 16 | charset = utf-8 17 | trim_trailing_whitespace = true 18 | insert_final_newline = true 19 | 20 | [*.md] 21 | trim_trailing_whitespace = false 22 | 23 | [*.json] 24 | indent_size = 2 25 | 26 | [*.{html,js,md}] 27 | block_comment_start = /** 28 | block_comment = * 29 | block_comment_end = */ 30 | -------------------------------------------------------------------------------- /ui/.gitignore: -------------------------------------------------------------------------------- 1 | ## editors 2 | /.idea 3 | /.vscode 4 | 5 | ## system files 6 | .DS_Store 7 | 8 | ## npm 9 | /node_modules/ 10 | /npm-debug.log 11 | 12 | ## testing 13 | /coverage/ 14 | 15 | ## temp folders 16 | /.tmp/ 17 | 18 | # build 19 | /_site/ 20 | -------------------------------------------------------------------------------- /ui/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true 3 | } 4 | -------------------------------------------------------------------------------- /ui/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 leap-app 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /ui/README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 | ## Open-wc Starter App 6 | 7 | [![Built with open-wc recommendations](https://img.shields.io/badge/built%20with-open--wc-blue.svg)](https://github.com/open-wc) 8 | 9 | ## Quickstart 10 | 11 | To get started: 12 | 13 | ```sh 14 | npm init @open-wc 15 | # requires node 10 & npm 6 or higher 16 | ``` 17 | 18 | ## Scripts 19 | 20 | - `start` runs your app for development, reloading on file changes 21 | - `start:build` runs your app after it has been built using the build command 22 | - `build` builds your app and outputs it in your `dist` directory 23 | - `test` runs your test suite with Karma 24 | - `lint` runs the linter for your project -------------------------------------------------------------------------------- /ui/dist/77c90c1d75fafad6241f.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /*! 2 | Copyright (C) 2013-2017 by Andrea Giammarchi - @WebReflection 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | 22 | */ 23 | 24 | /*! ***************************************************************************** 25 | Copyright (c) Microsoft Corporation. All rights reserved. 26 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 27 | this file except in compliance with the License. You may obtain a copy of the 28 | License at http://www.apache.org/licenses/LICENSE-2.0 29 | 30 | THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 31 | KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED 32 | WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, 33 | MERCHANTABLITY OR NON-INFRINGEMENT. 34 | 35 | See the Apache Version 2.0 License for specific language governing permissions 36 | and limitations under the License. 37 | ***************************************************************************** */ 38 | 39 | /** 40 | * @license 41 | * Copyright (c) 2017 The Polymer Project Authors. All rights reserved. 42 | * This code may only be used under the BSD style license found at 43 | * http://polymer.github.io/LICENSE.txt 44 | * The complete set of authors may be found at 45 | * http://polymer.github.io/AUTHORS.txt 46 | * The complete set of contributors may be found at 47 | * http://polymer.github.io/CONTRIBUTORS.txt 48 | * Code distributed by Google as part of the polymer project is also 49 | * subject to an additional IP rights grant found at 50 | * http://polymer.github.io/PATENTS.txt 51 | */ 52 | 53 | /** 54 | * @license 55 | * Copyright (c) 2018 The Polymer Project Authors. All rights reserved. 56 | * This code may only be used under the BSD style license found at 57 | * http://polymer.github.io/LICENSE.txt 58 | * The complete set of authors may be found at 59 | * http://polymer.github.io/AUTHORS.txt 60 | * The complete set of contributors may be found at 61 | * http://polymer.github.io/CONTRIBUTORS.txt 62 | * Code distributed by Google as part of the polymer project is also 63 | * subject to an additional IP rights grant found at 64 | * http://polymer.github.io/PATENTS.txt 65 | */ 66 | 67 | /** 68 | * @license 69 | * Copyright 2016 Google Inc. 70 | * 71 | * Permission is hereby granted, free of charge, to any person obtaining a copy 72 | * of this software and associated documentation files (the "Software"), to deal 73 | * in the Software without restriction, including without limitation the rights 74 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 75 | * copies of the Software, and to permit persons to whom the Software is 76 | * furnished to do so, subject to the following conditions: 77 | * 78 | * The above copyright notice and this permission notice shall be included in 79 | * all copies or substantial portions of the Software. 80 | * 81 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 82 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 83 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 84 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 85 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 86 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 87 | * THE SOFTWARE. 88 | */ 89 | 90 | /** 91 | * @license 92 | * Copyright 2016 Google Inc. All rights reserved. 93 | * 94 | * Licensed under the Apache License, Version 2.0 (the "License"); 95 | * you may not use this file except in compliance with the License. 96 | * You may obtain a copy of the License at 97 | * 98 | * http://www.apache.org/licenses/LICENSE-2.0 99 | * 100 | * Unless required by applicable law or agreed to in writing, software 101 | * distributed under the License is distributed on an "AS IS" BASIS, 102 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 103 | * See the License for the specific language governing permissions and 104 | * limitations under the License. 105 | */ 106 | 107 | /** 108 | * @license 109 | * Copyright 2017 Google Inc. 110 | * 111 | * Permission is hereby granted, free of charge, to any person obtaining a copy 112 | * of this software and associated documentation files (the "Software"), to deal 113 | * in the Software without restriction, including without limitation the rights 114 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 115 | * copies of the Software, and to permit persons to whom the Software is 116 | * furnished to do so, subject to the following conditions: 117 | * 118 | * The above copyright notice and this permission notice shall be included in 119 | * all copies or substantial portions of the Software. 120 | * 121 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 122 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 123 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 124 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 125 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 126 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 127 | * THE SOFTWARE. 128 | */ 129 | 130 | /** 131 | * @license 132 | * Copyright 2018 Google Inc. 133 | * 134 | * Permission is hereby granted, free of charge, to any person obtaining a copy 135 | * of this software and associated documentation files (the "Software"), to deal 136 | * in the Software without restriction, including without limitation the rights 137 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 138 | * copies of the Software, and to permit persons to whom the Software is 139 | * furnished to do so, subject to the following conditions: 140 | * 141 | * The above copyright notice and this permission notice shall be included in 142 | * all copies or substantial portions of the Software. 143 | * 144 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 145 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 146 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 147 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 148 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 149 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 150 | * THE SOFTWARE. 151 | */ 152 | 153 | /** 154 | * @license 155 | * Copyright 2019 Google Inc. 156 | * 157 | * Permission is hereby granted, free of charge, to any person obtaining a copy 158 | * of this software and associated documentation files (the "Software"), to deal 159 | * in the Software without restriction, including without limitation the rights 160 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 161 | * copies of the Software, and to permit persons to whom the Software is 162 | * furnished to do so, subject to the following conditions: 163 | * 164 | * The above copyright notice and this permission notice shall be included in 165 | * all copies or substantial portions of the Software. 166 | * 167 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 168 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 169 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 170 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 171 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 172 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 173 | * THE SOFTWARE. 174 | */ 175 | 176 | /** 177 | @license 178 | Copyright 2020 Google Inc. All Rights Reserved. 179 | 180 | Licensed under the Apache License, Version 2.0 (the "License"); 181 | you may not use this file except in compliance with the License. 182 | You may obtain a copy of the License at 183 | 184 | http://www.apache.org/licenses/LICENSE-2.0 185 | 186 | Unless required by applicable law or agreed to in writing, software 187 | distributed under the License is distributed on an "AS IS" BASIS, 188 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 189 | See the License for the specific language governing permissions and 190 | limitations under the License. 191 | */ 192 | 193 | /** 194 | @license 195 | Copyright (c) 2019 The Polymer Project Authors. All rights reserved. 196 | This code may only be used under the BSD style license found at 197 | http://polymer.github.io/LICENSE.txt The complete set of authors may be found at 198 | http://polymer.github.io/AUTHORS.txt The complete set of contributors may be 199 | found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as 200 | part of the polymer project is also subject to an additional IP rights grant 201 | found at http://polymer.github.io/PATENTS.txt 202 | */ 203 | 204 | /** 205 | @license 206 | Copyright 2018 Google Inc. All Rights Reserved. 207 | 208 | Licensed under the Apache License, Version 2.0 (the "License"); 209 | you may not use this file except in compliance with the License. 210 | You may obtain a copy of the License at 211 | 212 | http://www.apache.org/licenses/LICENSE-2.0 213 | 214 | Unless required by applicable law or agreed to in writing, software 215 | distributed under the License is distributed on an "AS IS" BASIS, 216 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 217 | See the License for the specific language governing permissions and 218 | limitations under the License. 219 | */ 220 | 221 | /** 222 | @license 223 | Copyright 2019 Google Inc. All Rights Reserved. 224 | 225 | Licensed under the Apache License, Version 2.0 (the "License"); 226 | you may not use this file except in compliance with the License. 227 | You may obtain a copy of the License at 228 | 229 | http://www.apache.org/licenses/LICENSE-2.0 230 | 231 | Unless required by applicable law or agreed to in writing, software 232 | distributed under the License is distributed on an "AS IS" BASIS, 233 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 234 | See the License for the specific language governing permissions and 235 | limitations under the License. 236 | */ 237 | 238 | /** 239 | @license 240 | Copyright 2020 Google Inc. All Rights Reserved. 241 | 242 | Licensed under the Apache License, Version 2.0 (the "License"); 243 | you may not use this file except in compliance with the License. 244 | You may obtain a copy of the License at 245 | 246 | http://www.apache.org/licenses/LICENSE-2.0 247 | 248 | Unless required by applicable law or agreed to in writing, software 249 | distributed under the License is distributed on an "AS IS" BASIS, 250 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 251 | See the License for the specific language governing permissions and 252 | limitations under the License. 253 | */ 254 | -------------------------------------------------------------------------------- /ui/dist/77c90c1d75fafad6241f.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"77c90c1d75fafad6241f.js","sources":["webpack:///77c90c1d75fafad6241f.js"],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAk58CA;;;;;;;;;AAoHA;;;;;;;;;;;;;;;;;;;;AAqBA;;;;;;;;AASA;;;;;;;;;;;AAYA;;;;;;;;;;;;;;;;;;;AAoBA;;;;;;;;;;;;;;;;;;;AAoBA;;;;;;;;;;;;;;;;;;;;;;;AAwBA;;;;;;;;;;;;;;;;;;;AAoBA;;;;;;;;;;;;;;;;;;;AAoBA;;;;;;;;;;;;;;;;;;;;;;;AAwBA;;;;;;;;AAUA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqxDA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6eA;AAiFA;AACA;;;AAKA;;;;;;;;;;;;;;;;;;;;;AA6BA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgnDA;AAkHA;AACA;AACA;;AAYA;AAieA","sourceRoot":""} -------------------------------------------------------------------------------- /ui/dist/index.html: -------------------------------------------------------------------------------- 1 | leap-courses -------------------------------------------------------------------------------- /ui/dist/precache-manifest.bdefb80fe853de8ae3d06c98f967a7d0.js: -------------------------------------------------------------------------------- 1 | self.__precacheManifest = (self.__precacheManifest || []).concat([ 2 | { 3 | "revision": "360819b589cac27113a6", 4 | "url": "77c90c1d75fafad6241f.js" 5 | }, 6 | { 7 | "revision": "3df0d03a439d9146057f46744a60648c", 8 | "url": "77c90c1d75fafad6241f.js.LICENSE.txt" 9 | }, 10 | { 11 | "revision": "0bd4322464f3bf60f3fb085afdd43ae7", 12 | "url": "index.html" 13 | } 14 | ]); -------------------------------------------------------------------------------- /ui/dist/sw.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Welcome to your Workbox-powered service worker! 3 | * 4 | * You'll need to register this file in your web app and you should 5 | * disable HTTP caching for this file too. 6 | * See https://goo.gl/nhQhGp 7 | * 8 | * The rest of the code is auto-generated. Please don't update this file 9 | * directly; instead, make changes to your Workbox build configuration 10 | * and re-run your build process. 11 | * See https://goo.gl/2aRDsh 12 | */ 13 | 14 | importScripts("https://storage.googleapis.com/workbox-cdn/releases/4.3.1/workbox-sw.js"); 15 | 16 | importScripts( 17 | "precache-manifest.bdefb80fe853de8ae3d06c98f967a7d0.js" 18 | ); 19 | 20 | self.addEventListener('message', (event) => { 21 | if (event.data && event.data.type === 'SKIP_WAITING') { 22 | self.skipWaiting(); 23 | } 24 | }); 25 | 26 | /** 27 | * The workboxSW.precacheAndRoute() method efficiently caches and responds to 28 | * requests for URLs in the manifest. 29 | * See https://goo.gl/S9QRab 30 | */ 31 | self.__precacheManifest = [].concat(self.__precacheManifest || []); 32 | workbox.precaching.precacheAndRoute(self.__precacheManifest, {}); 33 | 34 | workbox.routing.registerNavigationRoute(workbox.precaching.getCacheKeyForURL("/index.html")); 35 | -------------------------------------------------------------------------------- /ui/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 11 | 12 | 29 | leap-courses 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /ui/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "build": "PRODUCTION=true webpack --mode=production", 4 | "start": "WS_INTERFACE=ws://localhost:8888 webpack-dev-server --watch", 5 | "hc:alice": "cd ../dna && hc run --agent-name alice --networked sim2h", 6 | "hc:bob": "cd ../dna && hc run --agent-name bob -p 8889 --networked sim2h", 7 | "ui:alice": "WS_INTERFACE=ws://localhost:8888 USERNAME=Alice webpack-dev-server --port 8080", 8 | "ui:bob": "WS_INTERFACE=ws://localhost:8889 USERNAME=Bob webpack-dev-server --port 8081", 9 | "demo": "concurrently \"sim2h_server\" \"npm run hc:alice\" \"npm run hc:bob\" \"npm run ui:alice\" \"npm run ui:bob\" " 10 | }, 11 | "devDependencies": { 12 | "@open-wc/building-webpack": "^2.1.0", 13 | "concurrently": "^5.0.2", 14 | "es-dev-server": "^1.5.0", 15 | "webpack": "^4.28.0", 16 | "webpack-cli": "^3.3.4", 17 | "webpack-dev-server": "^3.10.1" 18 | }, 19 | "name": "leap-app", 20 | "version": "0.0.0", 21 | "description": "Webcomponent leap-app following open-wc recommendations", 22 | "author": "leap-app", 23 | "license": "MIT", 24 | "dependencies": { 25 | "@authentic/mwc-card": "^0.9.0", 26 | "@authentic/mwc-circular-progress": "^0.9.0", 27 | "@holochain/hc-web-client": "^0.5.1", 28 | "@material/mwc-button": "^0.13.0", 29 | "@material/mwc-dialog": "^0.13.0", 30 | "@material/mwc-drawer": "^0.13.0", 31 | "@material/mwc-fab": "^0.13.0", 32 | "@material/mwc-icon": "^0.13.0", 33 | "@material/mwc-icon-button": "^0.13.0", 34 | "@material/mwc-list": "^0.13.0", 35 | "@material/mwc-tab": "^0.13.0", 36 | "@material/mwc-tab-bar": "^0.13.0", 37 | "@material/mwc-textarea": "^0.13.0", 38 | "@material/mwc-textfield": "^0.13.0", 39 | "@material/mwc-top-app-bar": "^0.13.0", 40 | "apollo-boost": "^0.4.7", 41 | "apollo-link-schema": "^1.2.4", 42 | "graphql": "^14.5.8", 43 | "graphql-tools": "^4.0.6", 44 | "lit-element": "^2.0.1", 45 | "lit-html": "^1.0.0", 46 | "navigo": "^7.1.2" 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /ui/src/components/leap-app.js: -------------------------------------------------------------------------------- 1 | import { LitElement, html } from 'lit-element'; 2 | import { router } from '../router'; 3 | 4 | export class LeapApp extends LitElement { 5 | static get properties() { 6 | return { 7 | appContent: { 8 | type: Object 9 | } 10 | }; 11 | } 12 | 13 | constructor() { 14 | super(); 15 | router 16 | .on(() => router.navigate('/home')) 17 | .on( 18 | '/home', 19 | () => 20 | (this.appContent = html` 21 | 22 | `) 23 | ) 24 | .on( 25 | '/course/:id', 26 | params => 27 | (this.appContent = html` 28 | 29 | `) 30 | ) 31 | .resolve(); 32 | } 33 | 34 | render() { 35 | return this.appContent; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /ui/src/components/leap-course-detail.js: -------------------------------------------------------------------------------- 1 | import { LitElement, html, css } from 'lit-element'; 2 | 3 | import '@authentic/mwc-circular-progress'; 4 | import '@material/mwc-button'; 5 | import '@material/mwc-icon-button'; 6 | 7 | import { sharedStyles } from '../shared-styles'; 8 | import { router } from '../router'; 9 | import { getClient } from '../graphql'; 10 | import { 11 | GET_COURSE_INFO, 12 | CREATE_MODULE, 13 | ENROL_IN_COURSE, 14 | DELETE_COURSE 15 | } from '../graphql/queries'; 16 | 17 | export class LeapCourseDetail extends LitElement { 18 | static get properties() { 19 | return { 20 | courseId: { 21 | type: String 22 | }, 23 | course: { 24 | type: Object 25 | } 26 | }; 27 | } 28 | 29 | static get styles() { 30 | return [ 31 | sharedStyles, 32 | css` 33 | .fab { 34 | position: absolute; 35 | bottom: 16px; 36 | right: 16px; 37 | } 38 | ` 39 | ]; 40 | } 41 | 42 | async loadCourse() { 43 | this.course = undefined; 44 | 45 | const client = await getClient(); 46 | 47 | const result = await client.query({ 48 | query: GET_COURSE_INFO, 49 | variables: { 50 | courseId: this.courseId 51 | } 52 | }); 53 | 54 | this.course = result.data.course; 55 | this.myAddress = result.data.myAddress; 56 | } 57 | 58 | firstUpdated() { 59 | this.loadCourse(); 60 | this.addEventListener('course-updated', () => this.loadCourse()); 61 | } 62 | 63 | updated(changedValues) { 64 | super.updated(changedValues); 65 | 66 | if (changedValues.get('courseId')) { 67 | this.loadCourse(); 68 | } 69 | } 70 | 71 | async createModule() { 72 | const client = await getClient(); 73 | 74 | const result = await client.mutate({ 75 | mutation: CREATE_MODULE, 76 | variables: { 77 | courseId: this.courseId, 78 | title: this.moduleTitle 79 | }, 80 | refetchQueries: [ 81 | { 82 | query: GET_COURSE_INFO, 83 | variables: { 84 | courseId: this.courseId 85 | } 86 | } 87 | ] 88 | }); 89 | 90 | this.loadCourse(); 91 | } 92 | 93 | renderCreateModuleDialog() { 94 | return html` 95 | 96 | (this.moduleTitle = e.target.value)} 102 | > 103 | 104 | 105 | this.createModule()} 109 | > 110 | Create 111 | 112 | 113 | Cancel 114 | 115 | 116 | `; 117 | } 118 | 119 | renderModules() { 120 | if (this.course.modules.length === 0) 121 | return html` 122 | 125 | `; 126 | 127 | return html` 128 |
129 | ${this.course.modules.map( 130 | module => 131 | html` 132 | 138 | ` 139 | )} 140 |
141 | `; 142 | } 143 | 144 | userIsTeacher() { 145 | return this.myAddress === this.course.teacher_address; 146 | } 147 | 148 | async enrolInCourse() { 149 | const client = await getClient(); 150 | 151 | await client.mutate({ 152 | mutation: ENROL_IN_COURSE, 153 | variables: { 154 | courseId: this.courseId 155 | } 156 | }); 157 | 158 | router.navigate('/home'); 159 | } 160 | 161 | async deleteCourse() { 162 | const client = await getClient(); 163 | 164 | await client.mutate({ 165 | mutation: DELETE_COURSE, 166 | variables: { 167 | courseId: this.courseId 168 | } 169 | }); 170 | 171 | router.navigate('/home'); 172 | } 173 | 174 | renderCourseInfo() { 175 | return html` 176 | 177 |
178 |
179 | ${this.course.title} 182 | Taught by ${this.course.teacher_address} 183 |
184 | 185 | ${this.userIsTeacher() 186 | ? html` 187 |
188 | 194 | (this.shadowRoot.getElementById( 195 | 'create-module-dialog' 196 | ).open = true)} 197 | > 198 | 199 | this.deleteCourse()} 205 | > 206 |
207 | ` 208 | : html` 209 | this.enrolInCourse()} 214 | > 215 | `} 216 |
217 |
218 | `; 219 | } 220 | 221 | renderStudentsList() { 222 | if (this.course.students.length === 0) 223 | return html` 224 | 227 | `; 228 | 229 | return html` 230 | 231 | ${this.course.students.map( 232 | student => html` 233 | 234 | ${student} 235 | 236 | ` 237 | )} 238 | 239 | `; 240 | } 241 | 242 | render() { 243 | if (!this.course) 244 | return html` 245 |
246 | 247 |
248 | `; 249 | 250 | return html` 251 | ${this.renderCreateModuleDialog()} 252 | 253 |
254 | 255 | router.navigate('/home')} 259 | > 260 |
${this.course.title}
261 |
262 | 263 |
267 | ${this.renderCourseInfo()} 268 | 269 |
270 |
271 |

Modules

272 | ${this.renderModules()} 273 |
274 | 275 |
276 |

Students

277 | ${this.renderStudentsList()} 278 |
279 |
280 |
281 |
282 | `; 283 | } 284 | } 285 | -------------------------------------------------------------------------------- /ui/src/components/leap-courses-list.js: -------------------------------------------------------------------------------- 1 | import { LitElement, html } from 'lit-element'; 2 | 3 | import '@authentic/mwc-card'; 4 | import '@material/mwc-list'; 5 | import '@material/mwc-list/mwc-list-item'; 6 | import '@authentic/mwc-circular-progress'; 7 | 8 | import { router } from '../router'; 9 | import { sharedStyles } from '../shared-styles'; 10 | import { getClient } from '../graphql'; 11 | import { GET_COURSES } from '../graphql/queries'; 12 | 13 | export class LeapCoursesList extends LitElement { 14 | static get properties() { 15 | return { 16 | filter: { 17 | type: String 18 | }, 19 | courses: { 20 | type: Array 21 | } 22 | }; 23 | } 24 | 25 | static get styles() { 26 | return sharedStyles; 27 | } 28 | 29 | async firstUpdated() { 30 | this.loadCourses(); 31 | } 32 | 33 | async loadCourses() { 34 | this.courses = undefined; 35 | 36 | const client = await getClient(); 37 | const result = await client.query({ 38 | query: GET_COURSES, 39 | variables: { 40 | filter: this.filter || 'all' 41 | } 42 | }); 43 | 44 | this.courses = result.data.courses; 45 | 46 | if (this.courses.length > 0) { 47 | this.selectedCourseId = this.courses[0].id; 48 | } 49 | } 50 | 51 | updated(changedValues) { 52 | super.updated(changedValues); 53 | 54 | if (changedValues.get('filter')) { 55 | this.loadCourses(); 56 | } 57 | } 58 | 59 | render() { 60 | if (!this.courses) 61 | return html` 62 |
63 | 64 |
65 | `; 66 | 67 | if (this.courses.length === 0) 68 | return html` 69 |
70 | 73 |
74 | `; 75 | 76 | return html` 77 | 78 | ${this.courses.map( 79 | course => html` 80 | router.navigate(`course/${course.id}`)} 82 | > 83 | ${course.title} 84 | 85 | ` 86 | )} 87 | 88 | `; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /ui/src/components/leap-dashboard.js: -------------------------------------------------------------------------------- 1 | import { LitElement, html, css } from 'lit-element'; 2 | 3 | import { USERNAME } from '../config'; 4 | 5 | import '@material/mwc-top-app-bar'; 6 | import '@material/mwc-dialog'; 7 | import '@material/mwc-textfield'; 8 | import '@material/mwc-button'; 9 | import '@material/mwc-fab'; 10 | 11 | import { sharedStyles } from '../shared-styles'; 12 | import { getClient } from '../graphql'; 13 | import { CREATE_COURSE } from '../graphql/queries'; 14 | import { router } from '../router'; 15 | 16 | const tabs = ['enrolled-courses', 'my-courses', 'all-courses']; 17 | 18 | export class LeapDashboard extends LitElement { 19 | static get styles() { 20 | return [ 21 | sharedStyles, 22 | css` 23 | mwc-card { 24 | margin: 24px; 25 | } 26 | 27 | .card-content { 28 | padding: 16px; 29 | min-height: 200px; 30 | display: flex; 31 | flex-direction: column; 32 | } 33 | 34 | .fab { 35 | position: absolute; 36 | right: 36px; 37 | bottom: 36px; 38 | } 39 | 40 | .title { 41 | font-size: 24px; 42 | } 43 | 44 | leap-courses-list { 45 | margin-top: 8px; 46 | flex: 1; 47 | display: flex; 48 | } 49 | ` 50 | ]; 51 | } 52 | 53 | firstUpdated() { 54 | this.activeTab = 0; 55 | } 56 | 57 | static get properties() { 58 | return { 59 | activeTab: { 60 | type: Number 61 | } 62 | }; 63 | } 64 | 65 | renderCreateCourseDialog() { 66 | return html` 67 | 68 | (this.courseTitle = e.target.value)} 74 | > 75 | 76 | 77 | this.createCourse()} 81 | > 82 | Create 83 | 84 | 85 | Cancel 86 | 87 | 88 | `; 89 | } 90 | 91 | async createCourse() { 92 | const client = await getClient(); 93 | 94 | const result = await client.mutate({ 95 | mutation: CREATE_COURSE, 96 | variables: { 97 | title: this.courseTitle 98 | } 99 | }); 100 | 101 | router.navigate(`course/${result.data.createCourse.id}`); 102 | } 103 | 104 | render() { 105 | return html` 106 | ${this.renderCreateCourseDialog()} 107 |
108 | 109 |
LeaP ${USERNAME ? '/ ' + USERNAME : ''}
110 |
111 | 112 |
116 | 117 |
118 | All courses 119 | 123 |
124 |
125 | 126 | 127 |
128 | My courses 129 | 133 |
134 |
135 | 136 | 137 |
138 | Enrolled courses 139 | 143 |
144 |
145 |
146 | 147 | 153 | (this.shadowRoot.getElementById( 154 | 'create-course-dialog' 155 | ).open = true)} 156 | > 157 |
158 | `; 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /ui/src/components/leap-emtpy-placeholder.js: -------------------------------------------------------------------------------- 1 | import { LitElement, css, html } from 'lit-element'; 2 | import { sharedStyles } from '../shared-styles'; 3 | 4 | export class LeapEmtpyPlacholder extends LitElement { 5 | static get styles() { 6 | return [ 7 | sharedStyles, 8 | css` 9 | .message { 10 | font-size: 18px; 11 | text-align: center; 12 | } 13 | 14 | .container { 15 | opacity: 0.6; 16 | } 17 | mwc-icon { 18 | --mdc-icon-size: 64px; 19 | } 20 | :host { 21 | display: flex; 22 | flex: 1; 23 | } 24 | ` 25 | ]; 26 | } 27 | 28 | static get properties() { 29 | return { 30 | message: { 31 | type: String 32 | } 33 | }; 34 | } 35 | 36 | render() { 37 | return html` 38 |
39 | filter_drama 40 | ${this.message || 'No items in this list'} 41 |
42 | `; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /ui/src/components/leap-module.js: -------------------------------------------------------------------------------- 1 | import { LitElement, html, css } from 'lit-element'; 2 | 3 | import '@authentic/mwc-card'; 4 | import '@material/mwc-list'; 5 | import '@material/mwc-list/mwc-list-item'; 6 | import '@material/mwc-dialog'; 7 | import '@material/mwc-textfield'; 8 | import '@material/mwc-textarea'; 9 | import '@material/mwc-icon'; 10 | import '@material/mwc-icon-button'; 11 | 12 | import { sharedStyles } from '../shared-styles'; 13 | import { getClient } from '../graphql'; 14 | import { 15 | UPDATE_MODULE, 16 | DELETE_MODULE, 17 | CREATE_CONTENT, 18 | DELETE_CONTENT, 19 | UPDATE_CONTENT 20 | } from '../graphql/queries'; 21 | 22 | export class LeapModule extends LitElement { 23 | static get properties() { 24 | return { 25 | module: { 26 | type: Object 27 | }, 28 | editable: { 29 | type: Boolean 30 | }, 31 | editingTitle: { 32 | type: Boolean 33 | }, 34 | editingContent: { 35 | type: Object 36 | } 37 | }; 38 | } 39 | 40 | constructor() { 41 | super(); 42 | this.editingContent = {}; 43 | } 44 | 45 | static get styles() { 46 | return [ 47 | sharedStyles, 48 | css` 49 | .dialog-field { 50 | padding-top: 16px; 51 | padding-bottom: 16px; 52 | } 53 | 54 | .content-title { 55 | font-size: 18px; 56 | } 57 | 58 | .action { 59 | --mdc-icon-button-size: 40px; 60 | } 61 | ` 62 | ]; 63 | } 64 | 65 | async createOrUpdateContent() { 66 | const client = await getClient(); 67 | 68 | if (this.editingContent.id) { 69 | await client.mutate({ 70 | mutation: UPDATE_CONTENT, 71 | variables: { 72 | courseId: this.courseId, 73 | contentId: this.editingContent.id, 74 | content: { 75 | name: this.editingContent.name, 76 | description: this.editingContent.description, 77 | url: this.editingContent.url 78 | } 79 | } 80 | }); 81 | } else { 82 | await client.mutate({ 83 | mutation: CREATE_CONTENT, 84 | variables: { 85 | courseId: this.courseId, 86 | moduleId: this.module.id, 87 | content: { 88 | name: this.editingContent.name, 89 | description: this.editingContent.description, 90 | url: this.editingContent.url 91 | } 92 | } 93 | }); 94 | } 95 | 96 | this.dispatchEvent(new CustomEvent('course-updated', { composed: true })); 97 | } 98 | 99 | async updateModule() { 100 | this.editingTitle = false; 101 | 102 | const client = await getClient(); 103 | await client.mutate({ 104 | mutation: UPDATE_MODULE, 105 | variables: { 106 | courseId: this.courseId, 107 | moduleId: this.module.id, 108 | title: this.renameModule 109 | } 110 | }); 111 | 112 | this.dispatchEvent(new CustomEvent('course-updated', { composed: true })); 113 | } 114 | 115 | async deleteModule() { 116 | const client = await getClient(); 117 | await client.mutate({ 118 | mutation: DELETE_MODULE, 119 | variables: { 120 | courseId: this.courseId, 121 | moduleId: this.module.id 122 | } 123 | }); 124 | 125 | this.dispatchEvent(new CustomEvent('course-updated', { composed: true })); 126 | } 127 | 128 | async deleteContent(contentId) { 129 | const client = await getClient(); 130 | await client.mutate({ 131 | mutation: DELETE_CONTENT, 132 | variables: { 133 | courseId: this.courseId, 134 | contentId: contentId 135 | } 136 | }); 137 | 138 | this.dispatchEvent(new CustomEvent('course-updated', { composed: true })); 139 | } 140 | 141 | showContentDialog(existingContent) { 142 | this.editingContent = existingContent || {}; 143 | this.shadowRoot.getElementById('create-content-dialog').open = true; 144 | } 145 | 146 | renderCreateContentDialog() { 147 | return html` 148 | 152 |
153 | (this.editingContent.name = e.target.value)} 160 | > 161 | 162 | (this.editingContent.description = e.target.value)} 168 | > 169 | 170 | (this.editingContent.url = e.target.value)} 176 | > 177 | 178 |
179 | this.createOrUpdateContent()} 183 | > 184 | Create 185 | 186 | ${this.editable 187 | ? html` 188 | { 193 | e.stopPropagation(); 194 | this.deleteContent(this.editingContent.id); 195 | }} 196 | > 197 | ` 198 | : html``} 199 | 200 | Cancel 201 | 202 |
203 | `; 204 | } 205 | 206 | renderHeader() { 207 | return html` 208 |
209 |
210 | ${this.renderTitle()} 211 |
212 | ${this.renderToolbar()} 213 |
214 | `; 215 | } 216 | 217 | renderTitle() { 218 | return html` 219 |
220 | ${this.editable && this.editingTitle 221 | ? html` 222 | (this.renameModule = e.target.value)} 225 | .value=${this.module.title} 226 | > 227 | ` 228 | : html` 229 | ${this.module.title} 230 | `} 231 |
232 | `; 233 | } 234 | 235 | renderToolbar() { 236 | if (!this.editable) return html``; 237 | 238 | if (this.editingTitle) 239 | return html` 240 |
241 | this.updateModule()} 246 | > 247 | (this.editingTitle = false)} 252 | > 253 |
254 | `; 255 | 256 | return html` 257 |
258 | (this.editingTitle = true)} 263 | > 264 | this.showContentDialog()} 270 | > 271 | this.deleteModule()} 277 | > 278 |
279 | `; 280 | } 281 | 282 | renderContent(content, index) { 283 | return html` 284 | window.open(content.url)} 286 | class="content-item" 287 | hasMeta 288 | twoline 289 | > 290 | ${content.name} 291 | ${content.description} 292 | 293 | ${this.editable 294 | ? html` 295 | { 299 | e.stopPropagation(); 300 | this.showContentDialog(content); 301 | }} 302 | >edit 304 | ` 305 | : html``} 306 | 307 | ${index !== this.module.contents.length - 1 308 | ? html` 309 |
  • 310 | ` 311 | : html``} 312 | `; 313 | } 314 | 315 | render() { 316 | return html` 317 | ${this.renderCreateContentDialog()} 318 | 319 | 320 |
    321 | ${this.renderHeader()} 322 | ${this.module.contents.length === 0 323 | ? html` 324 | 327 | ` 328 | : html` 329 | 330 | ${this.module.contents.map((content, index) => 331 | this.renderContent(content, index) 332 | )} 333 | 334 | `} 335 |
    336 |
    337 | `; 338 | } 339 | } 340 | -------------------------------------------------------------------------------- /ui/src/config.js: -------------------------------------------------------------------------------- 1 | export const INSTANCE_NAME = process.env.PRODUCTION 2 | ? 'learning-pathways' 3 | : 'test-instance'; 4 | export const ZOME_NAME = 'courses'; 5 | export const HOST_URL = process.env.WS_INTERFACE; 6 | export const USERNAME = undefined; 7 | -------------------------------------------------------------------------------- /ui/src/connection.js: -------------------------------------------------------------------------------- 1 | // hc-web-client.js is Holochain’s JavaScript library that helps 2 | // you easily set up a WebSocket connection to your app. 3 | // And it is a thin wrapper around rpc-websockets to enable calling zome functions 4 | // in Holochain apps installed in a conductor. 5 | // More info: https://github.com/holochain/hc-web-client 6 | import { connect } from '@holochain/hc-web-client'; 7 | import { HOST_URL } from './config'; 8 | 9 | let connection = undefined; 10 | 11 | export async function getConnection() { 12 | // return connection if already established 13 | if (connection) return connection; 14 | 15 | // establish a new websocket connection and expose callZome 16 | const { callZome } = await connect({ url: HOST_URL }); 17 | 18 | // define connection and execute callZome function 19 | connection = (instance, zome, fnName) => async params => { 20 | console.log( 21 | `Calling zome function: ${instance}/${zome}/${fnName} with params`, 22 | params 23 | ); 24 | 25 | // https://developer.holochain.org/docs/guide/conductor_json_rpc_api/ 26 | const result = await callZome(instance, zome, fnName)(params); 27 | 28 | console.log( 29 | `Zome function ${instance}/${zome}/${fnName} with params returned`, 30 | result 31 | ); 32 | 33 | return result; 34 | }; 35 | 36 | return connection; 37 | } 38 | -------------------------------------------------------------------------------- /ui/src/graphql/directive.js: -------------------------------------------------------------------------------- 1 | import { SchemaDirectiveVisitor } from 'graphql-tools'; 2 | 3 | import { INSTANCE_NAME, ZOME_NAME } from '../config'; 4 | import { parseEntry } from '../utils'; 5 | 6 | export class LoadEntityDirective extends SchemaDirectiveVisitor { 7 | visitFieldDefinition(field, detail) { 8 | let defaultResolver = field.resolve; 9 | 10 | field.resolve = async (parent, args, context, info) => { 11 | let entityId; 12 | 13 | if (defaultResolver) { 14 | entityId = await defaultResolver(parent, args, context, info); 15 | } else if (args.courseId) { 16 | entityId = args.courseId; 17 | } else { 18 | entityId = parent[field.name]; 19 | } 20 | 21 | if (!entityId) return null; 22 | 23 | if (typeof entityId === 'string') 24 | return this.loadEntry(entityId, context.callZome); 25 | else return entityId.map(id => this.loadEntry(id, context.callZome)); 26 | }; 27 | } 28 | 29 | async loadEntry(entityId, callZome) { 30 | 31 | const entryResult = await callZome( 32 | INSTANCE_NAME, 33 | ZOME_NAME, 34 | 'get_entry' 35 | )({ 36 | address: entityId 37 | }); 38 | 39 | const entry = parseEntry(entryResult); 40 | 41 | return { id: entityId, ...entry }; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /ui/src/graphql/index.js: -------------------------------------------------------------------------------- 1 | import { makeExecutableSchema } from 'graphql-tools'; 2 | import { ApolloClient, InMemoryCache } from 'apollo-boost'; 3 | import { SchemaLink } from 'apollo-link-schema'; 4 | 5 | import { resolvers } from './resolvers'; 6 | import { typeDefs } from './schema'; 7 | import { LoadEntityDirective } from './directive'; 8 | import { getConnection } from '../connection'; 9 | 10 | let client = undefined; 11 | 12 | export async function getClient() { 13 | if (client) return client; 14 | 15 | const connection = await getConnection(); 16 | 17 | const schema = makeExecutableSchema({ 18 | typeDefs, 19 | resolvers, 20 | schemaDirectives: { 21 | loadEntry: LoadEntityDirective 22 | } 23 | }); 24 | 25 | const link = new SchemaLink({ schema, context: { callZome: connection } }); 26 | 27 | client = new ApolloClient({ 28 | cache: new InMemoryCache(), 29 | connectToDevTools: true, 30 | link 31 | }); 32 | return client; 33 | } 34 | -------------------------------------------------------------------------------- /ui/src/graphql/queries.js: -------------------------------------------------------------------------------- 1 | import gql from 'graphql-tag'; 2 | 3 | export const GET_COURSES = gql` 4 | query GetCourses($filter: String!) { 5 | courses(filter: $filter) { 6 | id 7 | title 8 | teacher_address 9 | students 10 | } 11 | } 12 | `; 13 | 14 | export const GET_COURSE_INFO = gql` 15 | query GetCourseInfo($courseId: String!) { 16 | myAddress 17 | course(courseId: $courseId) { 18 | id 19 | title 20 | students 21 | teacher_address 22 | modules { 23 | id 24 | title 25 | contents { 26 | id 27 | name 28 | description 29 | url 30 | } 31 | } 32 | } 33 | } 34 | `; 35 | 36 | export const CREATE_COURSE = gql` 37 | mutation CreateCourse($title: String!) { 38 | createCourse(title: $title) { 39 | id 40 | title 41 | teacher_address 42 | } 43 | } 44 | `; 45 | 46 | export const DELETE_COURSE = gql` 47 | mutation DeleteCourse($courseId: ID!) { 48 | deleteCourse(courseId: $courseId) { 49 | courses(filter: "get_all_courses") { 50 | id 51 | title 52 | teacher_address 53 | students 54 | } 55 | } 56 | } 57 | `; 58 | 59 | export const DELETE_MODULE = gql` 60 | mutation DeleteModule($courseId: ID!, $moduleId: ID!) { 61 | deleteModule(courseId: $courseId, moduleId: $moduleId) { 62 | id 63 | title 64 | students 65 | teacher_address 66 | modules { 67 | id 68 | title 69 | contents { 70 | id 71 | name 72 | description 73 | url 74 | } 75 | } 76 | } 77 | } 78 | `; 79 | 80 | export const DELETE_CONTENT = gql` 81 | mutation DeleteContent($courseId: ID!, $contentId: ID!) { 82 | deleteContent(courseId: $courseId, contentId: $contentId) { 83 | id 84 | title 85 | students 86 | teacher_address 87 | modules { 88 | id 89 | title 90 | contents { 91 | id 92 | name 93 | description 94 | url 95 | } 96 | } 97 | } 98 | } 99 | `; 100 | 101 | export const UPDATE_CONTENT = gql` 102 | mutation UpdateContent( 103 | $courseId: ID! 104 | $contentId: ID 105 | $content: ContentInput! 106 | ) { 107 | updateContent(contentId: $contentId, content: $content) { 108 | id 109 | title 110 | students 111 | teacher_address 112 | modules { 113 | id 114 | title 115 | contents { 116 | id 117 | name 118 | description 119 | url 120 | } 121 | } 122 | } 123 | } 124 | `; 125 | 126 | export const CREATE_MODULE = gql` 127 | mutation CreateModule($courseId: ID!, $title: String!) { 128 | createModule(courseId: $courseId, title: $title) { 129 | id 130 | title 131 | students 132 | teacher_address 133 | modules { 134 | id 135 | title 136 | contents { 137 | id 138 | name 139 | description 140 | url 141 | } 142 | } 143 | } 144 | } 145 | `; 146 | 147 | export const UPDATE_MODULE = gql` 148 | mutation UpdateModule($courseId: ID!, $moduleId: ID!, $title: String!) { 149 | updateModule(courseId: $courseId, moduleId: $moduleId, title: $title) { 150 | id 151 | title 152 | students 153 | teacher_address 154 | modules { 155 | id 156 | title 157 | contents { 158 | id 159 | name 160 | description 161 | url 162 | } 163 | } 164 | } 165 | } 166 | `; 167 | 168 | export const CREATE_CONTENT = gql` 169 | mutation CreateContent( 170 | $courseId: ID! 171 | $moduleId: ID! 172 | $content: ContentInput! 173 | ) { 174 | createContent(courseId: $courseId, moduleId: $moduleId, content: $content) { 175 | id 176 | title 177 | students 178 | teacher_address 179 | modules { 180 | id 181 | title 182 | contents { 183 | id 184 | name 185 | description 186 | url 187 | } 188 | } 189 | } 190 | } 191 | `; 192 | 193 | export const ENROL_IN_COURSE = gql` 194 | mutation EnrolInCourse($courseId: ID!) { 195 | enrolInCourse(courseId: $courseId) { 196 | id 197 | title 198 | students 199 | } 200 | } 201 | `; 202 | -------------------------------------------------------------------------------- /ui/src/graphql/resolvers.js: -------------------------------------------------------------------------------- 1 | import { INSTANCE_NAME, ZOME_NAME } from '../config'; 2 | import { parseResponse } from '../utils'; 3 | 4 | export const resolvers = { 5 | Query: { 6 | async courses(_, { filter }, { callZome }) { 7 | const fnName = 8 | filter === 'enrolled-courses' 9 | ? 'get_my_enrolled_courses' 10 | : filter === 'my-courses' 11 | ? 'get_my_courses' 12 | : 'get_all_courses'; 13 | 14 | const result = await callZome(INSTANCE_NAME, ZOME_NAME, fnName)({}); 15 | 16 | return parseResponse(result); 17 | }, 18 | async myAddress(_, __, { callZome }) { 19 | const result = await callZome( 20 | INSTANCE_NAME, 21 | ZOME_NAME, 22 | 'get_my_address' 23 | )({}); 24 | 25 | return parseResponse(result); 26 | } 27 | }, 28 | Course: { 29 | async students(parent, _, { callZome }) { 30 | const result = await callZome( 31 | INSTANCE_NAME, 32 | ZOME_NAME, 33 | 'get_all_students' 34 | )({ 35 | course_address: parent.id 36 | }); 37 | 38 | return parseResponse(result); 39 | } 40 | }, 41 | Module: { 42 | async contents(parent, _, { callZome }) { 43 | const result = await callZome( 44 | INSTANCE_NAME, 45 | ZOME_NAME, 46 | 'get_contents' 47 | )({ 48 | module_address: parent.id 49 | }); 50 | 51 | return parseResponse(result); 52 | } 53 | }, 54 | Mutation: { 55 | async createCourse(_, { title }, { callZome }) { 56 | const result = await callZome( 57 | INSTANCE_NAME, 58 | ZOME_NAME, 59 | 'create_course' 60 | )({ 61 | timestamp: getTimestamp(), 62 | title 63 | }); 64 | 65 | return parseResponse(result); 66 | }, 67 | async updateCourse(_, { title, courseId, modulesAddresses }, { callZome }) { 68 | const result = await callZome( 69 | INSTANCE_NAME, 70 | ZOME_NAME, 71 | 'update_course' 72 | )({ 73 | title, 74 | course_address: courseId, 75 | modules_addresses: modulesAddresses 76 | }); 77 | 78 | return parseResponse(result); 79 | }, 80 | async deleteCourse(_, { courseId }, { callZome }) { 81 | const result = await callZome( 82 | INSTANCE_NAME, 83 | ZOME_NAME, 84 | 'delete_course' 85 | )({ 86 | course_address: courseId 87 | }); 88 | 89 | return parseResponse(result); 90 | }, 91 | async createModule(_, { courseId, title }, { callZome }) { 92 | const result = await callZome( 93 | INSTANCE_NAME, 94 | ZOME_NAME, 95 | 'create_module' 96 | )({ 97 | timestamp: getTimestamp(), 98 | course_address: courseId, 99 | title 100 | }); 101 | 102 | return new Promise(resolve => { 103 | setTimeout(() => resolve(courseId), 300); 104 | }); 105 | }, 106 | async updateModule(_, { courseId, moduleId, title }, { callZome }) { 107 | const result = await callZome( 108 | INSTANCE_NAME, 109 | ZOME_NAME, 110 | 'update_module' 111 | )({ 112 | module_address: moduleId, 113 | title 114 | }); 115 | 116 | return new Promise(resolve => { 117 | setTimeout(() => resolve(courseId), 300); 118 | }); 119 | }, 120 | async deleteModule(_, { courseId, moduleId }, { callZome }) { 121 | const result = await callZome( 122 | INSTANCE_NAME, 123 | ZOME_NAME, 124 | 'delete_module' 125 | )({ 126 | module_address: moduleId 127 | }); 128 | 129 | return new Promise(resolve => { 130 | setTimeout(() => resolve(courseId), 300); 131 | }); 132 | }, 133 | async createContent(_, { courseId, content, moduleId }, { callZome }) { 134 | const result = await callZome( 135 | INSTANCE_NAME, 136 | ZOME_NAME, 137 | 'create_content' 138 | )({ 139 | timestamp: getTimestamp(), 140 | name: content.name, 141 | module_address: moduleId, 142 | url: content.url, 143 | description: content.description 144 | }); 145 | 146 | return new Promise(resolve => { 147 | setTimeout(() => resolve(courseId), 300); 148 | }); 149 | }, 150 | async updateContent(_, { courseId, content, contentId }, { callZome }) { 151 | const result = await callZome( 152 | INSTANCE_NAME, 153 | ZOME_NAME, 154 | 'update_content' 155 | )({ 156 | name: content.name, 157 | content_address: contentId, 158 | url: content.url, 159 | description: content.description 160 | }); 161 | 162 | return new Promise(resolve => { 163 | setTimeout(() => resolve(courseId), 300); 164 | }); 165 | }, 166 | async deleteContent(_, { courseId, contentId }, { callZome }) { 167 | const result = await callZome( 168 | INSTANCE_NAME, 169 | ZOME_NAME, 170 | 'delete_content' 171 | )({ 172 | content_address: contentId 173 | }); 174 | 175 | return new Promise(resolve => { 176 | setTimeout(() => resolve(courseId), 300); 177 | }); 178 | }, 179 | async enrolInCourse(_, { courseId }, { callZome }) { 180 | const result = await callZome( 181 | INSTANCE_NAME, 182 | ZOME_NAME, 183 | 'enrol_in_course' 184 | )({ 185 | course_address: courseId 186 | }); 187 | 188 | parseResponse(result); 189 | return courseId; 190 | } 191 | } 192 | }; 193 | 194 | function getTimestamp() { 195 | return Math.floor(Date.now() / 1000); 196 | } 197 | -------------------------------------------------------------------------------- /ui/src/graphql/schema.js: -------------------------------------------------------------------------------- 1 | import gql from 'graphql-tag'; 2 | 3 | export const typeDefs = gql` 4 | directive @loadEntry on FIELD_DEFINITION 5 | 6 | type Course { 7 | id: ID! 8 | title: String! 9 | modules: [Module!]! @loadEntry 10 | teacher_address: ID! 11 | students: [ID!]! 12 | } 13 | 14 | type Module { 15 | id: ID! 16 | course_address: Course! @loadEntry 17 | title: String! 18 | contents: [Content!]! @loadEntry 19 | } 20 | 21 | type Content { 22 | id: ID! 23 | name: String! 24 | description: String! 25 | url: String! 26 | } 27 | 28 | type Query { 29 | courses(filter: String!): [Course!]! @loadEntry 30 | course(courseId: ID!): Course! @loadEntry 31 | myAddress: ID! 32 | } 33 | 34 | input ContentInput { 35 | name: String! 36 | description: String! 37 | url: String! 38 | } 39 | 40 | type Mutation { 41 | createCourse(title: String!): Course! @loadEntry 42 | updateCourse(courseId: ID!, title: String!, modulesIds: [ID!]!): Course! 43 | @loadEntry 44 | deleteCourse(courseId: ID!): Query 45 | createModule(courseId: ID!, title: String!): Course! @loadEntry 46 | updateModule(courseId: ID!, moduleId: ID!, title: String!): Course! 47 | @loadEntry 48 | deleteModule(courseId: ID!, moduleId: ID!): Course! @loadEntry 49 | createContent(courseId: ID!, moduleId: ID!, content: ContentInput!): Course! @loadEntry 50 | updateContent(courseId: ID!, contentId: ID!, content: ContentInput!): Course! @loadEntry 51 | deleteContent(courseId: ID!, contentId: ID!): Course! @loadEntry 52 | enrolInCourse(courseId: ID!): Course! @loadEntry 53 | } 54 | `; 55 | 56 | /* 57 | */ 58 | -------------------------------------------------------------------------------- /ui/src/index.js: -------------------------------------------------------------------------------- 1 | import { LeapDashboard } from './components/leap-dashboard'; 2 | import { LeapApp } from './components/leap-app'; 3 | import { LeapCoursesList } from './components/leap-courses-list'; 4 | import { LeapCourseDetail } from './components/leap-course-detail'; 5 | import { LeapModule } from './components/leap-module'; 6 | import { LeapEmtpyPlacholder } from './components/leap-emtpy-placeholder'; 7 | 8 | customElements.define('leap-course-detail', LeapCourseDetail); 9 | customElements.define('leap-courses-list', LeapCoursesList); 10 | customElements.define('leap-app', LeapApp); 11 | customElements.define('leap-dashboard', LeapDashboard); 12 | customElements.define('leap-module', LeapModule); 13 | customElements.define('leap-empty-placeholder', LeapEmtpyPlacholder); 14 | -------------------------------------------------------------------------------- /ui/src/router.js: -------------------------------------------------------------------------------- 1 | import Navigo from 'navigo'; 2 | 3 | export const router = new Navigo( 4 | process.env.PRODUCTION ? null : `http://localhost:${window.location.port}` 5 | ); 6 | -------------------------------------------------------------------------------- /ui/src/shared-styles.js: -------------------------------------------------------------------------------- 1 | import { css } from 'lit-element'; 2 | 3 | export const sharedStyles = css` 4 | .column { 5 | display: flex; 6 | flex-direction: column; 7 | } 8 | 9 | .row { 10 | display: flex; 11 | flex-direction: row; 12 | } 13 | 14 | .fill { 15 | flex: 1; 16 | height: 100%; 17 | width: 100%; 18 | } 19 | 20 | .center-content { 21 | display: flex; 22 | justify-content: center; 23 | align-items: center; 24 | } 25 | 26 | .fading { 27 | opacity: 0.7; 28 | } 29 | 30 | .medium-padding { 31 | padding: 16px; 32 | } 33 | 34 | .title { 35 | font-size: 20px; 36 | font-weight: bold; 37 | } 38 | 39 | .danger { 40 | --mdc-theme-primary: red; 41 | } 42 | `; 43 | -------------------------------------------------------------------------------- /ui/src/utils.js: -------------------------------------------------------------------------------- 1 | export function parseResponse(response) { 2 | const object = typeof response === 'string' ? JSON.parse(response) : response; 3 | 4 | return object.hasOwnProperty('Ok') ? object.Ok : object; 5 | } 6 | 7 | export function parseEntry(entry) { 8 | return JSON.parse(parseResponse(entry).App[1]); 9 | } 10 | -------------------------------------------------------------------------------- /ui/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const webpack = require('webpack'); 3 | const { createDefaultConfig } = require('@open-wc/building-webpack'); 4 | 5 | // if you need to support IE11 use "modern-and-legacy-config" instead. 6 | // const { createCompatibilityConfig } = require('@open-wc/building-webpack'); 7 | // module.exports = createCompatibilityConfig({ 8 | // input: path.resolve(__dirname, './index.html'), 9 | // }); 10 | 11 | const config = createDefaultConfig({ 12 | input: path.resolve(__dirname, './index.html'), 13 | mode: process.env.PRODUCTION ? 'production' : 'development' 14 | }); 15 | 16 | module.exports = { 17 | ...config, 18 | plugins: [ 19 | ...config.plugins, 20 | new webpack.EnvironmentPlugin({ 21 | WS_INTERFACE: process.env.WS_INTERFACE, 22 | PRODUCTION: process.env.PRODUCTION, 23 | USERNAME: process.env.USERNAME 24 | }) 25 | ] 26 | }; 27 | --------------------------------------------------------------------------------