From d44b29a229b0223a36beee0261c9c87e5549ae33 Mon Sep 17 00:00:00 2001 From: Jessie Mongeon Date: Wed, 17 Jan 2024 16:10:16 -0600 Subject: [PATCH 1/6] Page revisions --- .../backend/candid/candid-howto.md | 2 +- .../backend/motoko/access-control.md | 18 +- .../backend/motoko/at-a-glance.md | 14 +- .../backend/motoko/calculator.md | 2 +- .../backend/motoko/candid-ui.md | 65 +-- .../backend/motoko/counter-tutorial.md | 2 +- .../backend/motoko/define-an-actor.md | 6 +- .../backend/motoko/deploying.md | 10 +- .../backend/motoko/explore-templates.md | 5 +- .../backend/motoko/hello-location.md | 8 +- .../backend/motoko/intercanister-calls.md | 10 +- docs/developer-docs/backend/motoko/mo-doc.md | 4 +- .../backend/motoko/multiple-actors.md | 15 +- .../backend/motoko/optimizing.md | 2 +- .../backend/motoko/phonebook.md | 2 +- .../backend/motoko/scalability-cancan.md | 48 +- .../backend/motoko/simple-cycles.md | 2 +- .../frontend/boilerplate-frontend.mdx | 475 ++++++++++++++++++ .../frontend/javascript-frontend.md | 114 ----- .../developer-docs/frontend/react-frontend.md | 116 ----- .../frontend/svelte-frontend.md | 115 ----- docs/developer-docs/frontend/vue-frontend.md | 114 ----- 22 files changed, 549 insertions(+), 600 deletions(-) create mode 100644 docs/developer-docs/frontend/boilerplate-frontend.mdx delete mode 100644 docs/developer-docs/frontend/javascript-frontend.md delete mode 100644 docs/developer-docs/frontend/react-frontend.md delete mode 100644 docs/developer-docs/frontend/svelte-frontend.md delete mode 100644 docs/developer-docs/frontend/vue-frontend.md diff --git a/docs/developer-docs/backend/candid/candid-howto.md b/docs/developer-docs/backend/candid/candid-howto.md index 359a8bf105..db5245abe6 100644 --- a/docs/developer-docs/backend/candid/candid-howto.md +++ b/docs/developer-docs/backend/candid/candid-howto.md @@ -6,7 +6,7 @@ As discussed in the [Candid concepts](./candid-concepts.md) page, Candid provide As a concrete example, let’s assume there is a `counter` canister already deployed on the network with the following Candid interface: -``` candid +```candid service Counter : { inc : (step: nat) -> (nat); } diff --git a/docs/developer-docs/backend/motoko/access-control.md b/docs/developer-docs/backend/motoko/access-control.md index 6e5ed0213c..9e15c7f898 100644 --- a/docs/developer-docs/backend/motoko/access-control.md +++ b/docs/developer-docs/backend/motoko/access-control.md @@ -48,7 +48,7 @@ Open the `src/access_hello_backend/main.mo` file in a text editor and delete the Copy and paste this code into the file: -``` +```motoko // Import base modules import AssocList "mo:base/AssocList"; import Error "mo:base/Error"; @@ -56,36 +56,46 @@ import List "mo:base/List"; shared({ caller = initializer }) actor class() { - // Establish role-based greetings to display + // Establish the role-based greetings to display public shared({ caller }) func greet(name : Text) : async Text { + + // If an identity with admin rights calls the method, display this greeting: if (has_permission(caller, #assign_role)) { return "Hello, " # name # ". You have a role with administrative privileges." + + // If an identity with the authorized user rights calls the method, display this greeting: } else if (has_permission(caller, #lowest)) { return "Welcome, " # name # ". You have an authorized account. Would you like to play a game?"; + + // If the identity is not an admin or authorized user, display this greeting: } else { return "Greetings, " # name # ". Nice to meet you!"; } }; - // Define custom types + // Define the custom types used for each user type public type Role = { #owner; #admin; #authorized; }; + // Define the custom types for assigning the permissions public type Permission = { #assign_role; #lowest; }; + // Create two stable variables to store the roles associated with each principal private stable var roles: AssocList.AssocList = List.nil(); private stable var role_requests: AssocList.AssocList = List.nil(); + // Return the caller's principal func principal_eq(a: Principal, b: Principal): Bool { return a == b; }; + // Get the principal's current role func get_role(pal: Principal) : ?Role { if (pal == initializer) { ?#owner; @@ -163,7 +173,7 @@ Let's take a look at a few key elements of this dapp: - You might notice that the `greet` function is a variation on the `greet` function you have seen in previous guides. In this dapp, however, the `greet` function uses a message caller to determine the permissions that should be applied and, based on the permissions associated with the caller, which greeting to display. -- The dapp defines two custom types—one for `Roles` and one for `Permissions`. +- The dapp defines two custom types, one for `Roles` and one for `Permissions`. - The `assign_roles` function enables the message caller to assign a role to the principal associated with an identity. diff --git a/docs/developer-docs/backend/motoko/at-a-glance.md b/docs/developer-docs/backend/motoko/at-a-glance.md index 0a35214c59..a2e5d625b2 100644 --- a/docs/developer-docs/backend/motoko/at-a-glance.md +++ b/docs/developer-docs/backend/motoko/at-a-glance.md @@ -1,10 +1,8 @@ -# 4: Motoko quick start +# 4: Motoko quickstart ## Overview -The [1.3: Deploying your first dapp](/docs/tutorials/developer-journey/level-1/1.3-first-dapp.md) developer journey tutorial provides a fast path to deploying a simple default application without stopping to admire the scenery along the way. Individual tutorials in this section walk through specific scenarios, pointing out details about what you’re doing in each step. - -If the quick start and tutorials are not quite your style, this at-a-glance cheat sheet summarizes the steps to follow for quick reference. +This at-a-glance cheat sheet summarizes the steps to follow for quick reference. ## Prerequisites @@ -34,7 +32,13 @@ Start the Internet Computer for local development or check your connection to th ## Register, build, and deploy locally or on the mainnet -For the mainnet, use: `--network ic`. +To deploy locally, use the command: + +``` +dfx deploy +``` + +For deploying to the mainnet, use: `--network ic`. ``` dfx deploy --network diff --git a/docs/developer-docs/backend/motoko/calculator.md b/docs/developer-docs/backend/motoko/calculator.md index 0c794d582d..04e05f4bea 100644 --- a/docs/developer-docs/backend/motoko/calculator.md +++ b/docs/developer-docs/backend/motoko/calculator.md @@ -73,7 +73,7 @@ Then, open the `src/calc_backend/calc_main.mo` file in a text editor and delete Copy and paste this code into the `calc_main.mo` file: -``` +```motoko // This single-cell calculator defines one calculator instruction per // public entry point (add, sub, mul, div). diff --git a/docs/developer-docs/backend/motoko/candid-ui.md b/docs/developer-docs/backend/motoko/candid-ui.md index 6c12f6e466..a19cc35f32 100644 --- a/docs/developer-docs/backend/motoko/candid-ui.md +++ b/docs/developer-docs/backend/motoko/candid-ui.md @@ -11,70 +11,15 @@ Based on the type signature of the actor, Candid also provides a web interface t ## Using Candid UI -After you have deployed your project in the local canister execution environment using the `dfx deploy` or `dfx canister install` command, you can access the Candid web interface endpoint in a browser. +To learn how to use Candid, check out the documentation here: -This web interface, the Candid UI, exposes the service description in a form, enabling you to quickly view and test functions and experiment with entering different data types without writing any front-end code. +- [Candid UI](../candid/index.md). -To use the Candid web interface to test canister functions, first find the Candid UI canister identifier associated with the current project by running the command: +- [What is Candid?](../candid/candid-concepts.md). -``` -dfx canister id __Candid_UI -``` +- [Using Candid](../candid/candid-howto.md). -This command displays the canister identifier for the Candid UI with output similar to the following: - -``` -r7inp-6aaaa-aaaaa-aaabq-cai -``` - -Copy the Candid UI canister identifier so that it is available in the clipboard. - -If you've stopped the local canister execution environment, restart it locally by running the following command: - -``` -dfx start --background -``` - -Open a browser and navigate to the address and port number specified in the `dfx.json` configuration file. - -By default, the local canister execution environment binds to the `127.0.0.1:4943` address and port number. - -Add the required `canisterId` parameter and the Candid UI canister identifier returned by the `dfx canister id __Candid_UI` command to the URL. - -For example, the full URL should look similar to the following but with the `CANDID-UI-CANISTER-IDENTIFIER` that was returned by the `dfx canister id __Candid_UI` command: - -``` -http://127.0.0.1:4943/?canisterId= -``` - -For instance, with the example canister identifier for the Candid UI as shown above, this could look as follows: - -``` -http://127.0.0.1:4943/?canisterId=r7inp-6aaaa-aaaaa-aaabq-cai -``` - -The browser then displays a form for you to specify a canister identifier or choose a Candid description (`.did`) file. -Note that this field refers to the canister identifier of the canister you would like to interact with (as opposed to the canister identifier for the Candid UI that you used in the last step). - -Specify the canister identifier of the canister you would like to test in the **Provide a canister ID** field, then click **Go** to display the service description. - -If you aren’t sure which canister identifier to use, you can run the `dfx canister id` command to look up the identifier for a specific canister name. For instance, to get the canister identifier for a canister named `my_counter`, you would use: - -``` -dfx canister id my_counter -``` - -Review the list of function calls and types defined in the dapp. - -Type a value of the appropriate type for a function or click **Random** to generate a value, then click **Call** or **Query** to see the result. - -:::info -Note that depending on the data type, the Candid interface might display additional configuration settings for testing functions. -::: - -For example, if a function takes an array, you might need to specify the number of items in the array before entering values. - -![Calculator functions](_attachments/candid-calc.png) +- [Candid specification](https://github.com/dfinity/candid/blob/master/spec/Candid.md). ## Next steps diff --git a/docs/developer-docs/backend/motoko/counter-tutorial.md b/docs/developer-docs/backend/motoko/counter-tutorial.md index 0882d0989e..24e6345849 100644 --- a/docs/developer-docs/backend/motoko/counter-tutorial.md +++ b/docs/developer-docs/backend/motoko/counter-tutorial.md @@ -70,7 +70,7 @@ To modify the default template source code, open the `src/my_counter_backend/inc Copy and paste this code into the `increment_counter.mo` file: -``` +```motoko // Create a simple Counter actor. actor Counter { stable var currentValue : Nat = 0; diff --git a/docs/developer-docs/backend/motoko/define-an-actor.md b/docs/developer-docs/backend/motoko/define-an-actor.md index 3f5728b0cf..e27a43d147 100644 --- a/docs/developer-docs/backend/motoko/define-an-actor.md +++ b/docs/developer-docs/backend/motoko/define-an-actor.md @@ -43,7 +43,7 @@ The sample canister for this guide doesn’t use any frontend assets, so you can For example, if you remove the `actor_hello_assets` section, the configuration file looks like this: -``` +```json { "canisters": { "actor_hello": { @@ -78,7 +78,7 @@ The next step is to write a canister that prints a statement like the traditiona Copy and paste this code into the `main.mo` file: -``` +```motoko import Debug "mo:base/Debug"; actor HelloActor { public query func hello() : async () { @@ -205,7 +205,7 @@ The `dfx canister create` command also stores the connection-specific canister i For example: -``` +```json { "actor_hello_backend": { "local": "dzh22-nuaaa-aaaaa-qaaoa-cai" diff --git a/docs/developer-docs/backend/motoko/deploying.md b/docs/developer-docs/backend/motoko/deploying.md index 8c93e001d8..ee826fff66 100644 --- a/docs/developer-docs/backend/motoko/deploying.md +++ b/docs/developer-docs/backend/motoko/deploying.md @@ -32,7 +32,7 @@ Open the `dfx.json` configuration file in a text editor to review the default se It may look like this: -``` +```json { "canisters": { "explore_hello_backend": { @@ -90,7 +90,7 @@ Let’s take a look at the sample program in the default `main.mo` template file Open the `src/explore_hello_backend/main.mo` file in a text editor and review the code in the template: -``` +```motoko actor { public func greet(name : Text) : async Text { return "Hello, " # name # "!"; @@ -141,8 +141,6 @@ Leave the terminal that displays network operations open and switch your focus t After you connect to the local canister execution environment, you can register with the network to generate unique, network-specific **canister identifiers** for your project. -In the [1.3: Deploying your first dapp](/docs/tutorials/developer-journey/level-1/1.3-first-dapp.md) developer journey tutorial, this step was performed as part of the `dfx deploy` command work flow. This guide demonstrates how to perform each of the operations independently. - To register canister identifiers for the local network, register unique canister identifiers for the canisters in the project by running the following command: ``` @@ -162,7 +160,7 @@ Because you are connected to the local canister execution environment, these can For example: -``` +```json { "explore_hello_backend": { "local": "br5f7-7uaaa-aaaaa-qaaca-cai" @@ -289,7 +287,7 @@ Open a terminal window on your local computer, if you don’t already have one o Open the `src/explore_hello_frontend/src/index.js` file in a text editor and review the code in the template script: -``` +```javascript import { explore_hello } from "../../declarations/explore_hello_backend"; document.getElementById("clickMeBtn").addEventListener("click", async () => { diff --git a/docs/developer-docs/backend/motoko/explore-templates.md b/docs/developer-docs/backend/motoko/explore-templates.md index ef52641f98..b2c24af7f3 100644 --- a/docs/developer-docs/backend/motoko/explore-templates.md +++ b/docs/developer-docs/backend/motoko/explore-templates.md @@ -1,7 +1,6 @@ # 2: Project organization ## Overview -If you started your tour of the IC SDK with the [0.6: Introduction to dfx](/docs/tutorials/developer-journey/level-0/06-intro-dfx.md) developer journey tutorial, you have already seen the basic work flow for creating dapps that run on the Internet Computer. Now, let’s take a closer look at that work flow by exploring the default files and folders that are added to your workspace when you create a new project. As a preview, the following diagram illustrates the development work flow when running the Internet Computer locally on you computer. @@ -68,7 +67,7 @@ To review the default configuration file for your project, open the `dfx.json` c The contents of the file should resemble the following: -``` +```json { "canisters": { "explore_hello_backend": { @@ -119,7 +118,7 @@ Let’s take a look at the sample program in the default `main.mo` template file To review the default sample program for your project, open the `src/explore_hello_backend/main.mo` file in a text editor and review the code in the template: -``` +```motoko actor { public query func greet(name : Text) : async Text { return "Hello, " # name # "!"; diff --git a/docs/developer-docs/backend/motoko/hello-location.md b/docs/developer-docs/backend/motoko/hello-location.md index 9f2de29a1c..b647f5d079 100644 --- a/docs/developer-docs/backend/motoko/hello-location.md +++ b/docs/developer-docs/backend/motoko/hello-location.md @@ -49,7 +49,7 @@ Modify the default source code to replace the `greet` function with a `location` For example, you can replace the file's existing code with the following: -``` +```motoko actor { public func location(city : Text) : async Text { return "Hello, " # city # "!"; @@ -150,7 +150,7 @@ Open the `dfx.json` configuration file in a text editor and change the default ` For this step, you should modify both the canister name and the path to the main program for the canister to use `favorite_cities`. Your `dfx.json` file should look like this: -``` +```json { "canisters": { "favorite_cities": { @@ -179,7 +179,7 @@ cp -r src/location_hello_backend src/favorite_cities Open the `src/favorite_cities/main.mo` file in a text editor. Copy and paste the following code sample to replace the `location` function with two new functions: -``` +```motoko actor { public func location(cities : [Text]) : async Text { @@ -201,7 +201,7 @@ You might notice that `Text` in this code example is enclosed by square (`[ ]`) The code sample also uses the basic format of an `apply` operation for the array, which can be abstracted as: -``` +```motoko public func apply(fs : [A -> B], xs : [A]) : [B] { var ys : [B] = []; for (f in fs.vals()) { diff --git a/docs/developer-docs/backend/motoko/intercanister-calls.md b/docs/developer-docs/backend/motoko/intercanister-calls.md index c6a4e93edf..8495dc1c31 100644 --- a/docs/developer-docs/backend/motoko/intercanister-calls.md +++ b/docs/developer-docs/backend/motoko/intercanister-calls.md @@ -1,7 +1,7 @@ # 7: Making inter-canister calls ## Overview -One of the most important features of the Internet Computer blockchain for developers is the ability to call functions in one canister from another canister. This capability to make calls between canisters—also sometimes referred to as **inter-canister calls**—enables you to reuse and share functionality in multiple dapps. +One of the most important features of the Internet Computer blockchain for developers is the ability to call functions in one canister from another canister. This capability to make calls between canisters, also sometimes referred to as **inter-canister calls**, enables you to reuse and share functionality in multiple dapps. For example, you might want to create a dapp for professional networking, organizing community events, or hosting fundraising activities. Each of these dapps might have a social component that enables users to identify social relationships based on some criteria or shared interest, such as friends and family or current and former colleagues. @@ -40,7 +40,7 @@ Create a new file, `src/canister1/main.mo`. In this file, insert the following code: -``` +```motoko import Canister2 "canister:canister2"; actor { @@ -54,7 +54,7 @@ Then, create another new file, `src/canister2/main.mo`. In this file, insert the following code: -``` +```motoko import Prim "mo:prim"; actor { @@ -67,7 +67,7 @@ actor { Open the `dfx.json` file and delete the existing content. Then, insert the following code: -``` +```json { "canisters": { "canister1": { @@ -129,7 +129,7 @@ The output should resemble the following: Alternatively, you can also use a canister id to access a previously deployed canister by using the following piece of code in the `src/canister1/main.mo` file: -``` +```motoko actor { public func main(canisterId: Text) : async Nat { let canister2 = actor(canisterId): actor { getValue: () -> async Nat }; diff --git a/docs/developer-docs/backend/motoko/mo-doc.md b/docs/developer-docs/backend/motoko/mo-doc.md index 1eca7243b4..b5e496c879 100644 --- a/docs/developer-docs/backend/motoko/mo-doc.md +++ b/docs/developer-docs/backend/motoko/mo-doc.md @@ -2,7 +2,7 @@ `mo-doc` is a command-line tool for generating documentation for Motoko source code. It processes source files and generates documentation in various formats. -## Quick start +## Quickstart Download `mo-doc` from Motoko's [GitHub releases page](https://github.com/dfinity/motoko/releases) or simply use the binary included in your [dfx](https://internetcomputer.org/docs/current/developer-docs/setup/install) installation: @@ -65,6 +65,6 @@ func factorial(n : Nat) : ?Nat { ``` ## Resources -Check out Motoko's [base library souce code](https://github.com/dfinity/motoko-base/tree/master/src) for additional examples and best practices. +Check out Motoko's [base library source code](https://github.com/dfinity/motoko-base/tree/master/src) for additional examples and best practices. The source code for `mo-doc` is available in the [dfinity/motoko](https://github.com/dfinity/motoko/tree/master/src/docs) GitHub repository. Contributions are welcome! diff --git a/docs/developer-docs/backend/motoko/multiple-actors.md b/docs/developer-docs/backend/motoko/multiple-actors.md index 911a1faf32..7b0b1a0486 100644 --- a/docs/developer-docs/backend/motoko/multiple-actors.md +++ b/docs/developer-docs/backend/motoko/multiple-actors.md @@ -45,7 +45,7 @@ Open the `dfx.json` configuration file in a text editor, then change the default For example, under the `canisters` key: -``` +```json "assistant": { "main": "src/assistant/main.mo", "type": "motoko" @@ -60,7 +60,7 @@ Add a new canister name, source code location, and canister type for the `rock_p After making the changes, the `canisters` section of the `dfx.json` file should look similar to this: -``` +```json { "canisters": { "assistant": { @@ -113,7 +113,7 @@ Open the `src/assistant/main.mo` file in a text editor and delete the existing c Copy and paste this code into the file: -``` +```motoko import Array "mo:base/Array"; import Nat "mo:base/Nat"; @@ -168,22 +168,26 @@ Open the `src/rock_paper_scissors/main.mo` file in a text editor and delete the Copy and paste this code into the file: -``` +```motoko import I "mo:base/Iter"; +// Define an actor actor RockPaperScissors { + // Define stable variables stable var alice_score : Nat = 0; stable var bob_score : Nat = 0; stable var alice_last : Choice = #scissors; stable var bob_last : Choice = #rock; + // Define custom types for the player's choice type Choice = { #rock; #paper; #scissors; }; + // Define a function to return the winner of the game public func contest() : async Text { for (i in I.range(0, 99)) { battle_round(); @@ -194,6 +198,7 @@ actor RockPaperScissors { return (winner); }; + // Define the function for the game func battle_round() : () { let a = alice(bob_last); let b = bob(alice_last); @@ -233,7 +238,7 @@ Open the `src/daemon/main.mo` file in a text editor and delete the existing cont Copy and paste this code into the file: -``` +```motoko actor Daemon { stable var running = false; diff --git a/docs/developer-docs/backend/motoko/optimizing.md b/docs/developer-docs/backend/motoko/optimizing.md index 8287876714..123ce59cd7 100644 --- a/docs/developer-docs/backend/motoko/optimizing.md +++ b/docs/developer-docs/backend/motoko/optimizing.md @@ -14,7 +14,7 @@ Before getting started, assure you have set up your developer environment accord `Wasm-opt` can be used to enable canister optimizations through a configuration option in the project's `dfx.json` file, such as: -``` +```json { "canisters": { "my_canister": { diff --git a/docs/developer-docs/backend/motoko/phonebook.md b/docs/developer-docs/backend/motoko/phonebook.md index 462a9c89a1..2ba0e78b4d 100644 --- a/docs/developer-docs/backend/motoko/phonebook.md +++ b/docs/developer-docs/backend/motoko/phonebook.md @@ -86,7 +86,7 @@ To modify the default template, open the `src/phonebook_backend/main.mo` file in Copy and paste the following code into the `main.mo` file: -``` +```motoko // Import standard library functions for lists import L "mo:base/List"; diff --git a/docs/developer-docs/backend/motoko/scalability-cancan.md b/docs/developer-docs/backend/motoko/scalability-cancan.md index 1cc5137cd3..6b31860b08 100644 --- a/docs/developer-docs/backend/motoko/scalability-cancan.md +++ b/docs/developer-docs/backend/motoko/scalability-cancan.md @@ -12,37 +12,13 @@ The [CanCan sample application](https://github.com/dfinity/cancan) is a simplifi - How to build a frontend that implements more sophisticated user interface features for desktop or mobile apps. -## Splitting uploaded content into multiple canisters +This dapp is designed with the following architecture and design choices: -Because canisters are compiled WebAssembly modules, they have certain known limitations. For example, currently WebAssembly modules have a maximum of 4GB for memory and an upper limit on the number of object calls allowed. +- Splitting uploaded content into multiple canisters: Canisters on ICP are compiled into WebAssembly modules which have certain known limitations. For example, currently WebAssembly modules have a maximum of 4GB for memory and an upper limit on the number of object calls allowed. For a video-sharing sample applications like CanCan, these limitations mean that multiple canisters are required and that data must be broken into smaller chunks for storage and retrieval. -For a video-sharing sample applications like CanCan, these limitations mean that multiple canisters are required and that data must be broken into smaller chunks for storage and retrieval. +- Simplifying scalability: Because the Internet Computer protocol relies on replicated state across nodes in a subnet, it provides certain guarantees about fault tolerance and failover natively. The BigMap library provides a simple, plug-in library for building scalable applications using key-value storage on the Internet Computer. By using the BigMap library as a backend service, the CanCan sample application can dynamically chunk, serialize, and distribute data to multiple canisters. -### Implementing a distributed hash table - -The initial attempt to build a scalable video-sharing service for the Internet Computer used a distributed hash table (DHT) as a backend service with simple get and put functions that distributed data—chunks of the video to be uploaded or streamed—into a predefined set of canisters. In the early phases of the project, this approach was sufficient for a proof-of-concept and verifying that the video data could be properly transcoded for storage and retrieval. - -However, the scalability of the application was limited because the distributed hash table relied on a specific number of canisters that it could populate with data for storage and retrieve data from for viewing. In addition, the original implementation of the distributed hash table backend service included code to accommodate common network connectivity issues that could cause nodes to be unavailable or lose data. - -## Simplifying scalability - -Because the Internet Computer protocol relies on replicated state across nodes in a subnet, it provides certain guarantees about fault tolerance and failover natively that are not generally available to applications running on other platforms or protocols. - -With the realization that the Internet Computer could ensure that canisters were available to receive and respond to requests,the original distributed hash table backend service was replaced with a simpler but more scalable backend service called BigMap. - -BigMap provides a simple, plug-in library for building scalable applications using key-value storage on the Internet Computer. By using the BigMap library as a backend service, the CanCan sample application can dynamically chunk, serialize, and distribute data to multiple canisters. - -The library offers building blocks for application-specific, in-memory data abstractions that scale using any number of canisters. Each canister still has limited capacity, but the application instantiates the canisters it needs and keeps track of the fragments that make up the full video content for each user’s videos in an index file called the `manifest`. - -The code required for the `BigMap` service is much simpler than a traditional distributed hash table because the Internet Computer provides scalability, replication, failover, and fault tolerance. - -## Demonstrating interoperability - -The BigMap service included in the CanCan sample application repository is written in the Rust programming language. However, the CanCan sample application also demonstrates interoperability between canisters written in different languages. - -In this case, the `BigMap` functionality is implemented using the Rust programming language and other services—such as encoding and decoding of video content and the management of user principals for authentication—are implemented using Motoko. - -By deploying different parts of the sample application as canisters, the interaction between them provides a seamless user experience. +- Demonstrating interoperability: The BigMap service included in the CanCan sample application repository is written in the Rust programming language. However, the CanCan sample application also demonstrates interoperability between canisters written in different languages. By deploying different parts of the sample application as canisters, the interaction between them provides a seamless user experience. Although the `BigMap` service you see in the CanCan repository is written in Rust, the service was actually implemented in both Rust and Motoko programming languages to demonstrate the following: @@ -52,17 +28,13 @@ Although the `BigMap` service you see in the CanCan repository is written in Rus - Both language implementation work seamlessly because the Candid language provides a common language for describing the BigMap API, independent of JavaScript, Rust, or Motoko. -## Authentication model +- Authentication model: This CanCan sample application uses the public-private key pair, browser-based local storage, and the `Principal` data type to authenticate users. -Much like the LinkedUp sample application, the CanCan sample application uses the public-private key pair, browser-based local storage, and the `Principal` data type to authenticate users. +- Implementing frontend features: The CanCan sample application uses the React library in combination with TypeScript to implement frontend user interface. -## Implementing frontend features +## Data model overview -The CanCan sample application uses the React library in combination with TypeScript to implement frontend user interface. - -### Data model overview - -The application stores information about users and information about videos. To support most browsers, the videos are serialized into byte arrays with video data stored in 500kb segments of bytes that are referred to as [Uint8Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array) objects. When a video is requested, the manifest loads the list of chunks required to play the video and concatenates the chunks before displaying the video in a standard `