diff --git a/.retype/404.html b/.retype/404.html index 36d0340..39909f1 100644 --- a/.retype/404.html +++ b/.retype/404.html @@ -24,11 +24,11 @@ - + - + - +
diff --git a/.retype/contribute/how-to/index.html b/.retype/contribute/how-to/index.html index 6b3c706..d5c4fcb 100644 --- a/.retype/contribute/how-to/index.html +++ b/.retype/contribute/how-to/index.html @@ -27,11 +27,11 @@ - + - + - +
diff --git a/.retype/index.html b/.retype/index.html index 21b296b..b4c6d66 100644 --- a/.retype/index.html +++ b/.retype/index.html @@ -29,11 +29,11 @@ - + - + - +
diff --git a/.retype/resources/js/config.js b/.retype/resources/js/config.js index cada5c6..b699f2b 100644 --- a/.retype/resources/js/config.js +++ b/.retype/resources/js/config.js @@ -1 +1 @@ -var __DOCS_CONFIG__ = {"id":"MBFu4cHvANlMEsgQZALHM131DqgNSp4yxGL","key":"xgY/NWJB6QH+J0oy37sRzj+R7dY8bqyC1beMprBUNtc.sJ8+iE4V8KzhZY8Ek9mbmaS9aJIusPAa6M5u1zNoSMsuwxpHTZM5MO6i2p3lAA7k1xZwaW3UkwcPXz5CYdEpEw.36","base":"/","host":"tutorials.icdevs.org","version":"1.0.0","sidebarFilterPlaceholder":"Filter","toolbarFilterPlaceholder":"Filter","showSidebarFilter":true,"filterNotFoundMsg":"No member names found containing the query \"{query}\"","maxHistoryItems":15,"homeIcon":"","access":[{"value":"public","label":"Public"},{"value":"protected","label":"Protected"}],"toolbarLinks":[{"id":"fields","label":"Fields"},{"id":"properties","label":"Properties","shortLabel":"Props"},{"id":"methods","label":"Methods"},{"id":"events","label":"Events"}],"sidebar":[{"n":"/","l":"Who we are"},{"n":"tutorials","l":"Tutorials","c":false,"o":true,"i":[{"n":"basics","l":"Basics"},{"n":"motoko_playground","l":"Motoko playground"},{"n":"primitive_types","l":"Primitive data types"},{"n":"understanding_types","l":"Understanding types"},{"n":"serving_svg_over_http","l":"Serving simple SVG over HTTP"}],"s":""},{"n":"contribute","l":"Contribute","c":false,"i":[{"n":"how-to","l":"How To"}],"s":""}],"search":{"mode":0,"minChars":2,"maxResults":20,"placeholder":"Search","hotkeys":["/"],"noResultsFoundMsg":"Sorry, no results found.","recognizeLanguages":true,"languages":[0]}}; +var __DOCS_CONFIG__ = {"id":"4213br7ERw2VvbQjZKmReQCTaay7th9LU/T","key":"KnaJeO6Gq6W7gMKQ8Z0LJkELNMP7LtDlBTp4caaI3Nc.ggOyorOcTK678IP+64iW/39Kk/Pxp1fSI9fWuI5IDEOt94N6n3OQSAqP/OjtGN4rozpWr5Vk3xg3ouRPKlnjdw.57","base":"/","host":"tutorials.icdevs.org","version":"1.0.0","sidebarFilterPlaceholder":"Filter","toolbarFilterPlaceholder":"Filter","showSidebarFilter":true,"filterNotFoundMsg":"No member names found containing the query \"{query}\"","maxHistoryItems":15,"homeIcon":"","access":[{"value":"public","label":"Public"},{"value":"protected","label":"Protected"}],"toolbarLinks":[{"id":"fields","label":"Fields"},{"id":"properties","label":"Properties","shortLabel":"Props"},{"id":"methods","label":"Methods"},{"id":"events","label":"Events"}],"sidebar":[{"n":"/","l":"Who we are"},{"n":"tutorials","l":"Tutorials","c":false,"o":true,"i":[{"n":"basics","l":"Basics"},{"n":"motoko_playground","l":"Motoko playground"},{"n":"primitive_types","l":"Primitive data types"},{"n":"understanding_types","l":"Understanding types"},{"n":"null_variants_switch","l":"Null, variants and the switch statement"},{"n":"serving_svg_over_http","l":"Serving simple SVG over HTTP"}],"s":""},{"n":"contribute","l":"Contribute","c":false,"i":[{"n":"how-to","l":"How To"}],"s":""}],"search":{"mode":0,"minChars":2,"maxResults":20,"placeholder":"Search","hotkeys":["/"],"noResultsFoundMsg":"Sorry, no results found.","recognizeLanguages":true,"languages":[0]}}; diff --git a/.retype/resources/js/search.json b/.retype/resources/js/search.json index 9f28453..58a6d09 100644 --- a/.retype/resources/js/search.json +++ b/.retype/resources/js/search.json @@ -1 +1 @@ -[[{"l":"Who we are","p":["… for the use and development of the Internet Computer and related technologies. It pursues activities such as","\uD83C\uDFD8️ community organization","\uD83D\uDCB0 funding","\uD83D\uDCD6 educational resources","\uD83D\uDD2C scientific discovery","conferences","developer funding","educational material development","educational symposiums","ICDevs.org (registered as The Internet Computer Developers Education and Discovery Corporation) is a 501(c)3 Texas Non-profit.","ICDevs.org is completely independent from the DFINITY Foundation and the ICA. Our goal is to further diversify and decentralize the Internet Computer ecosystem. By providing a United States-based non-profit organization we open up new, tax-advantaged ways, for US-based proponents of the Internet Computer to organize their resources and influence to advance the Ideals of the Internet Computer.","ICDevs.org seeks to provide the general public with","Meet our Board and Advisors","Meet our Developer Advisory Committee","open-source systems funding","Read our Bylaws","scientific and technology development","strategic community organization"]},{"i":"what-is-the-internet-computer","l":"♾️ What is the Internet Computer","p":["From : Dfinity docs","The Internet Computer is a blockchain that enables developers, organizations, and entrepreneurs to build and deploy secure, autonomous, and tamper-proof software programs.","As an application developer, you might find it useful to think of the Internet Computer as providing the following key elements:","An open communication protocol that enables general-purpose computations to run transparently directly on the internet A network that runs the protocol to provide computing capacity—for example, the hardware, CPU, and memory required to run programs—through independent data centers. A globally-accessible and scalable blockchain platform for running software applications.","ICDevs.org believes in a future where a significant portion of enterprise and consumer information management and commerces occurs with the Internet Computer involved. Our goal is that most people will be using the Internet Computer without knowing that they are doing so. To reach this goal we need a significant number of well-trained and well-equipped developers to build the infrastructure that seamlessly melds real-world activity into trustless computing infrastructure.","Places to learn more:","Dfinity IC Community Start Developing"]}],[{"l":"Basics"},{"i":"install---create---run","l":"Install - Create - Run","p":["Install SDK","Get version","Create a new project","Start local network - the flag is for running on background","Stop local network","Upgrade dfx version","Get Candid uri ulr"]}],[{"l":"Getting to know the motoko playground","p":["Motoko playground is a simple web interface that allows you to write and deploy motoko code in your web browser. It is a #1 choice for developers that just have started getting to know about the Internet Computer ecosystem and want to learn motoko programing language.","Motoko is a programing language developed natively for the Internet Computer blockchain. If you want to learn more about Motoko, visit the documentation page."]},{"l":"Start first project","p":["You can easily open Motoko playground by visiting this link https://m7sm4-2iaaa-aaaab-qabra-cai.raw.ic0.app/","Create a new project","You should se a modal window simmilar to the screen above that is basically giving you three options:","Create a new blank project","Open one of the pre-prepared projects","Import code from public Github repo","If you want to start coding from scratch, clicking on New Motoko project is the best option for you. In this tutorial, let's click on the Counter example so we can demonstrate how to use the playground.","This will get you the a Readme file that describes the project and presents how to deploy the code locally on your computer. As Motoko playground is working in the browser, you don't need to set up your local development enviroment and install the SKD now. Skip this and just click to the Main.mo file on the left hand side. This will bring you to the code.","Counter example code","This is how your workspace looks. On the left, you can manage files in your project, load packages and other canisters (smart contracts). In the bottom is a little console that shows you logs, this is where you look for error messagess when deploying. In the top right there is a Deploy button that we will use for deploying and testing our code."]},{"l":"Deploy your code","p":["Counter example is a very simple project to start with. Explaining the code in detail is above the scope of this tutorial but we will briefly go through it just to see what we can expect.","The actor has a stable variable counter, that will store the number of the counter and 3 public funcitons – get, set and inc. These functions form a public interface of our canister and we will see them in the generated Candid interface after deploy.","Candid is an IDL (interface definition language) developed for the IC ecosystem in order to facilitate communication between services written in different programing languages. You can read more about it here.","Motoko playground not only allows you to write and deploy your code, it also generates a Candid UI so you can test the functionality. Click on the deploy button to see it in action.","Deploying the project","First, you need to confirm the deploy by selecting a canister name and set up a garbage collector strategy. You can keep the settings as it is for now and click Install. You should see a success message in the console log.","Motoko Playground is really deploying your canister to the network. As it serves for educational and testing purposes only, there are some limitations such as only 1 GB of data can be used and the canister will expier after 20 minutes. Using this playground is very convinient for new devs learning Motoko, as you don't have to pay for cycles fees for deployment, which you would need to do when deploying to the mainnet directly."]},{"l":"Experiment with Candid UI","p":["If your project deployed successfully, you now should see a Candid UI on your right-hand side.","Candind UI","As we mentioned above, Candid UI follows the interface defined in your Motoko code. You should see a form consisting of three functions get, inc and set. Function get and inc is not expecting any argument so you can click on Query or Call button and experiment with it. Function set is expecting a natural number (Nat) that you can pass in the input field.","You will notice that query functions have very fast execution usually in terms of miliseconds. On the other hand, functions calling an update usually takes about 2 seconds."]},{"l":"Update your code","p":["Once you start practicing Motoko, you will want to update your code frequently. Just click on the Deploy button again, it is going to ask you if you want to Upgrade or Reinstall the code. If you choose update, the stable memory will stay. On the opposite, reinstalling canister will refresh the memory.","If you make significant changes to the code, you might get notified that the update will not be compatible with the previous version and the playground makes you reinstall the whole canister.","Let's make an easy exercise right now. Try to update your code with a new function dec, that will decrease the counter of 1 each time. Remember, the counter should not go below zero."]},{"l":"Import a module","p":["To import a module from Motoko base library, you can do it like that:","Now you have available all of the functions that are present in the Nat module that you can find on the official documentation page https://smartcontracts.org/docs/base-libraries/Nat.html. Notice, that there are also other modules available.","Now, lets make a function is_zero, that will return true if the counter value is zero or false if it's not a zero. Use a function imported from Nat module.","Viola, here is the whole working code in case you got lost. You can copy paste it to your playground."]},{"i":"save--share-your-code","l":"Save & share your code","p":["You know might want to save your code so you can open it later. You can either save the code and keep in in a local file or click on the Save & Share button in the top-right corner. This will generate you an unique link that you can come back to later."]},{"l":"Useful resources and links","p":["If you want to experiment with more exapmles of Motoko code. You can again click on the Open tutorial button in the top right corner. More examples can be found in this GitHub repo which was made by Dfinity foundation. Lastly, there is a no-code Motoko editor Blocks which contains some examples too and the Build & Run button will deploy your code via Motoko Playground as well.","Medium article a Yan Chen from Dfinity Foundation about Motoko Playground: https://medium.com/dfinity/introducing-the-motoko-playground-an-online-development-environment-for-the-internet-computer-efb4cd09ea8b","Community converstaion from Dfinity also with Yan Chen about Motoko Playground: https://www.youtube.com/watch?v=A_RbxhN0BHI","Link to a Motoko documentation page: https://smartcontracts.org/docs/language-guide/motoko.html"]}],[{"l":"Primitive data types","p":["Types play a significant role in Motoko language. Compared to modern general purpose languages such as Python, Motoko is very strict about types. This have a good purpose as it helps preventing Motoko programs to go wrong as mentioned in the documentation page.","For example, each variable in a Motoko program carries an associated type, and this type is known statically, before the program executes. Each use of each variable is checked by the compiler to prevent runtime type errors, including null reference errors, invalid field access and the like."]},{"l":"Types in Motoko","p":["Generaly speaking, we can categorize types into two groups: primitive types non-primitive values. This text focuses on primitive types mainly so we will explain them in more detail in the next chapture. To give you the contrast, let's quickly go through the primitive vs non-primitive values.","Primitive types in Motoko programming language are integers, natural numbers floating numbers, characters, texts and booleans.","Example of a primitive type, declaration of a variable that will have type of a natural number an is initialized with the value of 1:","Non-primitive values can be tuples, arrays, objects, variants, functions, async values or error values.","Example of a non-primitive type, declaring an array that b that can only contain natural numbers and is initialized with values 1, 2, 3:","You can easily experiment with types and run this sample code in the Motoko playground if you are not familiar with it you can follow Getting to know Motoko Playground tutorial."]},{"l":"Primitive types","p":["In this chapter, we will go through all of the primitive types and give you examples of how to declare variables and what can be assigned to them."]},{"l":"1. Unbounded Integers","p":["Unbounded integers can be assigned with positive or negative numbers. There are some ways how to declare an integer variable:","Let's make a little exercise now. Write a funciton called add, that will take two integers as arguments and return a sum of these two numbers.","That was quite easy, right? Try to experiment with it in the Candid UI."]},{"l":"2. Unbounded Natural numbers","p":["Unbounded natural numbers can be assigned with positive numbers only. Motoko program will trap if you try to assign a negative number."]},{"l":"3. Bounded numbers","p":["As integers can also go below zero, we have space for 256 numbers too but in the range from -128 to 127.","But if you try this your program will fail because we are overflowing the maximum value:","For Nat16 the maximum value that can be assigned is 65 535 (2^ 16) and for Int16 we have minimum –32768 and maximum –32767. The same logic applies for 32 and 64 size of a type. This gives you understanding of what value can be assigned to a variable of specific type and gives you freedom to decide which one to use when designing your own program.","If you try to run this program, it will trap. Motoko Playground is well prepared for this type of situations, it doesn't let you execute the program and shows you an explanatory error message:","In Motoko, these bounded numbers types are available:","Int16","Int32","Int64","Int8","Keep in mind, even if you have a value that would fit into a smaller size Nat/Int, you can only assign it if it has the same type. Something like this will not work in Motoko:","Nat16","Nat32","Nat64","Nat8","Overflowing the Nat8 value in Motoko Playground","This means that you can declare a variable:","To explain the pattern, each type consist of Nat/Int and a number. This number represents quantity of bits that will be assigned in memory of the computer for this specific type. For example Nat8 variable can be only assigned with values ranging from 0 to 255. This comes from a formula 2^ 8 = 256 so the maximum number is 255 as we are starting from 0.","Unbounded numbers variables can be assigned theoretically with numbers of any size. There are situations when you don't need this. For example if you want to declare a variable that will represent an age of a person. This variable should never exceed a number greater than 200. You might consider to use a bounded variable to be more memory effective."]},{"l":"4. Floating point numbers","p":["For decimal numbers Float type is available in Motoko. Here are some ways how to assign a value to declared float variable:"]},{"l":"5. Characters and text","p":["For single characters, there is a type called Char and for strings of characters a Text type. Be careful, char type must be assigned with single quotes and string types with double qoutes. Lets try to declare your own variables:","Let's create a funciton concat, that will take two strings a and b as arguments and will return a concatenated text of them both with a single space between them.","Exactly, you can use the # operator to concatenate strings in Motoko!"]},{"l":"6. Booleans","p":["For booleans we have a Bool type in Motoko. It can only hold a value either true or false."]},{"l":"Useful resources and links","p":["Motoko documentaion page talking about types: https://smartcontracts.org/docs/languages/motoko-at-a-glance.html#_primitive_types","Motoko basic concepts and terms: https://smartcontracts.org/docs/language-guide/basic-concepts.html#intro-values","Motoko base library: https://smartcontracts.org/docs/base-libraries/stdlib-intro.html"]}],[{"l":"Understanding types","p":["Now that we learned about primitive types in the previous lecture, let's move on to non-primitive types. In this tutorial, we are going to demonstrate how to declare them and build them with primitive types.","This is a natural process as non-primitive values can be user-defined, meaning that you can build objects or structures that combines multiple primitive types together."]},{"l":"Non-primitive types","p":["Let's quickly go through non-primitive types that are present in Motoko and how to declare them."]},{"l":"1. Tuples","p":["Tuples are simple objects that can contain multiple elements. These elements can be different types but you can't change number of elements after you declare it. You could create a simple tuple type to store name and surname for a person:","Then, you could easily create a tuple that will store not only name but also an age of the person as you can mix different types in a tuple:","However, for more complex situations you should consider creating your own object with named parameters which would be more readable. Tuples are usually used for simple use cases only."]},{"l":"2. Arrays","p":["Arrays are used for storing multiple values. Unlike tuples, they can contain only one specific type. You can define mutable and immutable arrays. The difference is that mutable arrays can be updated and immutable arrays cannot."]},{"i":"21-immutable-arrays","l":"2.1 Immutable arrays","p":["Here is how you define an immutable array:","Now as we defined an immutable array with the type of text, Motoko playground will not let you include any other value than text, also it doesn't let you to update the value:","Let's make a first excersise. Try to write a function called getDay, that will take a Nat as an argument and returns a name of the corresponding day.","Here we go. That was simple. You can notice 2 things – function is very well defined with types in the input as well as in the output, if you try to put anything else then natural number it is not going to work.","Also, we are using the query keyword in the function declaration which will make the function execution much faster. It is a very good idea to use query function anytime we are not trying to update values in the backend of our app."]},{"i":"21-mutable-arrays","l":"2.1 Mutable arrays","p":["Declaration of a mutable array is very similar to immutable array. The key difference is using the var keyword. Let's try to declare an immutable array.","Notice that now Motoko Playground allows you to reassign the array with different values. For example:","You could also change the number of elements inside freely. However, you still can't change an element inside individually as only the whole array is mutable but the content inside is not:","If you woul like to make a totally mutable array, you need to use the var keyword also inside the declaration. Here is the full working code of a mutable array:","If you run this code in you Motoko Playground and try tu run the function in the Candid UI, you should get \"Sunday\" for the index of 0.","If you'd like to make immutable array mutable and vice versa, you need to use functions from the Array section of the Motoko base library. Specifically it is thaw function to make array mutable and freeze function to make it immutable.","Notice that after using the thaw function, we can assign another array to the variable or even assign a value to a specific index. This wouldn't be possible with immutable array."]},{"l":"3. Records","p":["In Motoko, similarly to arrays, records objects can be mutable and immutable. Here is how you define an immutable object Person with attributes name, surname and age:","Analogically, if you want to have your object type mutable, you should use the var keyword. Let's redesign the example above so we are able to update the age of a person, name and surname cannot be changed:"]},{"l":"4. Variants","p":["When declaring an object above, we have to define all of the parameters so we have a person that has name AND surname AND age. Variants perform more like OR as we are expecting to get one of the values inside. Let's create a variant type Status that will have options single, married and divorced.","Now let's update the Person record type that we created before and add status as another parameter. We expect the status parameter to be updated later on in time.","With this design, we assured that each person can only have one of the available statuses."]},{"l":"5. Functions","p":["We've been already messing around simple functions in this and previous tutorials so you probably know how to define them. Let's go through some more examples so you can recognize different types of functions in Motoko."]},{"l":"Public and private functions","p":["Most of the functions that we defined so far were public, as there was no specific reason to make them private. Private functions are used for specific situations when you don't want to expose the private function to the public interface of your canister.","Example of a public function in Motoko, using the keyword public before the function definition:","If you would like to make your function private, you use the private keyword. You will notice that private functions also have an _ underscore character in their names. This is not required by the language itself but recommended as a naming convention."]},{"l":"Functions from Motoko base library","p":["Like we presented in the array section, there is plenty of functions available in the Motoko base library. There is a section for each type. These functions are called from the imported module like we did with the thaw function:","Notice that some functions require to define the data type in the <> brackets.","Go through the base library and check what is inside for each type. These funcitons are going to save your time when writing your programs. However, please respect that Motoko is still quite a fresh language and there is not yet as many functions available as for more mature languages."]},{"l":"Anonymous functions","p":["Anonymous functions are also known as lambdas. You define them for generic purpose in your program to complete small tasks. They are not ment to be part of the public interface."]},{"l":"6. Async values","p":["When canisters or actors communicate with each other on the Internet Computer, it happens asynchronously. Messagess are processed one after another (in sequence) in an isolated way.","Let's have a look at an example from the documentation page:","Await keyword is used to say to our program that we are expecting a value from the other service but the value will be returned in the future, that is why we have to wait for it. After the future value is assigned to our variables result1 and result2 the program knows that it can call the finalStep function."]},{"l":"7. Optional values","p":["Optional values are used when we are expecting a specific type but it can be null as well. Optional values are defined with question mark and can be mostly found in the record type declaration or in functions.","Let's extend the Person model from above and add another parameter partner that will point to another person instance. Naturally, single persons will not have a partner so we must keep this parameter optional.","Optional values play significant roles also in function definitions as funciton can as well expect or return a null value. There will be more detailed tutorial on that soon."]},{"l":"Useful links and resources","p":["Motoko Bootcamp video about variables, functions and types by Albert Du https://www.youtube.com/watch?v=4YX41Nm7Wx8","Motoko Bootcamp video about variants by Paul Young https://www.youtube.com/watch?v=GFenqSGhj7I&"]}],[{"l":"Serving simple SVG over HTTP","p":["In this tutorial, things are going to get more excited. We are going to learn how to serve a SVG image over HTTP(s) directly from your canister. Yes – canisters can serve web content over HTTP! You are probably familiar with that as it is one of the main advantages of the Internet Computer over the other blockchains. But there is also a http_request() function that you can use in Motoko to define how exactly is your canister going to behave when contacted over HTTP protocol.","This could be useful when you want to serve custom SVG images or define custom api endpoint over the URL. Serving a dynamic NFT file is what we're going to do now.","We are going to use Motoko Playground for deploying the code, this will give you a quick start without needing to setting up your local enviroment."]},{"l":"HTTP Requests","p":["We are going to start with this skeleton template used for educational purposes during the Motoko Bootcamp event.","The template contains of two files, first the module file http.mo that contains types needed for HTTP communication from the canister.","If the code seems too exotic to you, please check this video that is explaining basics of HTTP protocol. The most key part for our case in this tutorial are the Request and Response types that play the main role in our simple HTTP communication.","The second file is your main.mo file that loads the module http and contains a simple function http_request that puts it all together.","Now, try to deploy the code in the Motoko Playground. Let's ignore the Candid UI for now and focus on the Log message with the canister ID: Code installed at canister id wch4f-miaaa-aaaab-qadfa-cai. Your canister ID will be of course different. Copy your canister ID and create this URL following this pattern https://<>.raw.ic0.app/:","If all goes fine and you open your URL in your browser you should see the Hello world message.","Notice that there is a \"raw\" keyword in the URL. Raw in the URL means we are serving non certified assets. This certification means that IC guarantees that you are getting right data. Certification can be expensive as it can cost a lot of assets so it only makes sense when serving very important data. You would need to implement a hash function for certification which is beyond the scope of this tutorial."]},{"l":"SVG image","p":["Now, let's put some SVG image into works. SVGs are basically text files that carry vector information about some visual. You can easily find any SVG file online and use it or you can use the same as we. Create a text variable called svg that will contain data about your curve.","In order to display the SVG, we need to replace this line of code in our http_request function body = Text.encodeUtf8(\"Hello world\"); with the svg variable:","You could also adjust the header format of the return type if you want to be precise, but it will work with text/html as well.","Now if you deploy your code and try to refresh your canister page again in the browser, you should see the SVG image instead of Hello, World message. Beautifull infinity symbol.","SVG infinity symbol from the canister","Here we go! You just served a SVG file over HTTP on the Internet Computer."]},{"l":"Dynamic SVG","p":["To demonstrate the power of serving SVG images over HTTP, we can now make a simple example of dynamically changing the SVG color.","Notice that there is a color definition at the beginning of our curve (path) in the SVG format fill=' black'. We can make this to change dynamically based on the number in the URL requested to the canister.","To start, let's create an array that will contain some colors:","Now, let's define a function make_svg that will take a color as a text argument and returns colored SVG if it finds it in our colors array. If it doesn't find the color in our array, it will return the default black color.","We are first looping through our colors array to find out if color is in it. If it is found we assign it as a result_color, if it is not inside we will use \"black\" as default. Notice that we are contatenating the SVG string with the color name.","Now let's change the http_request() function, so it gets the /path from the request and call the color_svg function, that will return the SVG code with the right color.","Now deploy your code and open the canister URL in another window of your browser again. Include the NFT color behind the URL so it looks like this (remember to use your own canister ID from the log console):","SVG rendered with specific color","Try to put something else than registered color name in the URL, you should see the default black symbol.","Here is the full working code in the Motoko Playground in case you got lost somewhere.","Main.mo","http.mo","Imagine what you can do with SVG files now, you have unlimited possibilities as this format is completely extendable or customizable. You can create more curves and layers, make interactions etc."]},{"l":"Useful resources and links","p":["Austin Fatheree presenting HTTP requests for Motoko Bootcamp https://www.youtube.com/watch?v=gaVuMaTP2lQ","Basics of HTTP communication https://www.youtube.com/watch?v=iYM2zFP3Zn0","Documentation page regarding canisters to respond HTTP requests https://smartcontracts.org/docs/http-middleware.html#_enabling_canisters_to_respond_to_http_requests","Motoko example HTTP counter from Dfinity https://github.com/dfinity/examples/blob/master/motoko/http_counter/src/main.mo"]}],[{"l":"How To Contribute","p":["Follow these basic steps to add tutorials and contribute:","Clone our docs repo git clone git@github.com:icdevs/ic_devs_org_tutorials.git","Navigate to the cloned repo root directory","Install Retype(this is a great open source tool that helped us to create these docs) npm install retypeapp --global","Run the site locally retype watch","Create a new tutorial","Create a file under the tutorials folder (i.e. 'motoko-basics.md')","Write the tutorial in Markdown ( Formatting rules)","Create a PR","That is it. Once we review the changes we will merge with our main branch and your tutorial will be live \uD83D\uDE80 \uD83D\uDE80 \uD83D\uDE80"]},{"i":"happy-coding","l":"Happy coding!!!"}]] \ No newline at end of file +[[{"l":"Who we are","p":["… for the use and development of the Internet Computer and related technologies. It pursues activities such as","\uD83C\uDFD8️ community organization","\uD83D\uDCB0 funding","\uD83D\uDCD6 educational resources","\uD83D\uDD2C scientific discovery","conferences","developer funding","educational material development","educational symposiums","ICDevs.org (registered as The Internet Computer Developers Education and Discovery Corporation) is a 501(c)3 Texas Non-profit.","ICDevs.org is completely independent from the DFINITY Foundation and the ICA. Our goal is to further diversify and decentralize the Internet Computer ecosystem. By providing a United States-based non-profit organization we open up new, tax-advantaged ways, for US-based proponents of the Internet Computer to organize their resources and influence to advance the Ideals of the Internet Computer.","ICDevs.org seeks to provide the general public with","Meet our Board and Advisors","Meet our Developer Advisory Committee","open-source systems funding","Read our Bylaws","scientific and technology development","strategic community organization"]},{"i":"what-is-the-internet-computer","l":"♾️ What is the Internet Computer","p":["From : Dfinity docs","The Internet Computer is a blockchain that enables developers, organizations, and entrepreneurs to build and deploy secure, autonomous, and tamper-proof software programs.","As an application developer, you might find it useful to think of the Internet Computer as providing the following key elements:","An open communication protocol that enables general-purpose computations to run transparently directly on the internet A network that runs the protocol to provide computing capacity—for example, the hardware, CPU, and memory required to run programs—through independent data centers. A globally-accessible and scalable blockchain platform for running software applications.","ICDevs.org believes in a future where a significant portion of enterprise and consumer information management and commerces occurs with the Internet Computer involved. Our goal is that most people will be using the Internet Computer without knowing that they are doing so. To reach this goal we need a significant number of well-trained and well-equipped developers to build the infrastructure that seamlessly melds real-world activity into trustless computing infrastructure.","Places to learn more:","Dfinity IC Community Start Developing"]}],[{"l":"Basics"},{"i":"install---create---run","l":"Install - Create - Run","p":["Install SDK","Get version","Create a new project","Start local network - the flag is for running on background","Stop local network","Upgrade dfx version","Get Candid uri ulr"]}],[{"l":"Getting to know the motoko playground","p":["Motoko playground is a simple web interface that allows you to write and deploy motoko code in your web browser. It is a #1 choice for developers that just have started getting to know about the Internet Computer ecosystem and want to learn the motoko programming language.","Motoko is a programming language developed natively for the Internet Computer blockchain. If you want to learn more about Motoko, visit the documentation page."]},{"l":"Start first project","p":["You can easily open Motoko playground by visiting this link https://m7sm4-2iaaa-aaaab-qabra-cai.raw.ic0.app/","Create a new project","You should see a modal window similar to the screen above that is basically giving you three options:","Create a new blank project","Open one of the pre-prepared projects","Import code from public Github repo","If you want to start coding from scratch, clicking on the New Motoko project is the best option for you. In this tutorial, let's click on the Counter example so we can demonstrate how to use the playground.","This will get you to a readme file that describes the project and presents how to deploy the code locally on your computer. As Motoko playground is working in the browser, you don't need to set up your local development environment and install the SKD now. Skip this and just click to the Main.mo file on the left hand side. This will bring you to the code.","Counter example code","This is how your workspace looks. On the left, you can manage files in your project, load packages and other canisters (smart contracts). In the bottom is a little console that shows you logs, this is where you look for error messages when deploying. In the top right there is a Deploy button that we will use for deploying and testing our code."]},{"l":"Deploy your code","p":["Counter example is a very simple project to start with. Explaining the code in detail is above the scope of this tutorial but we will briefly go through it just to see what we can expect.","The actor has a stable variable counter, that will store the number of the counter and 3 public functions – get, set and inc. These functions form a public interface of our canister and we will see them in the generated Candid interface after deploy.","Candid is an IDL (interface definition language) developed for the IC ecosystem in order to facilitate communication between services written in different programing languages. You can read more about it here.","Motoko playground not only allows you to write and deploy your code, it also generates a Candid UI so you can test the functionality. Click on the deploy button to see it in action.","Deploying the project","First, you need to confirm the deploy by selecting a canister name and set up a garbage collector strategy. You can keep the settings as it is for now and click Install. You should see a success message in the console log.","Motoko Playground is really deploying your canister to the network. As it serves for educational and testing purposes only, there are some limitations such as only 1 GB of data can be used and the canister will expire after 20 minutes. Using this playground is very convenient for new devs learning Motoko, as you don't have to pay for cycles fees for deployment, which you would need to do when deploying to the mainnet directly."]},{"l":"Experiment with Candid UI","p":["If your project deployed successfully, you now should see a Candid UI on your right-hand side.","Candind UI","As we mentioned above, Candid UI follows the interface defined in your Motoko code. You should see a form consisting of three functions get, inc and set. Function get and inc is not expecting any argument so you can click on Query or Call button and experiment with it. Function set is expecting a natural number (Nat) that you can pass in the input field.","You will notice that query functions have very fast execution usually in terms of milliseconds. On the other hand, functions calling an update usually takes about 2 seconds."]},{"l":"Update your code","p":["Once you start practicing Motoko, you will want to update your code frequently. Just click on the Deploy button again, it is going to ask you if you want to Upgrade or Reinstall the code. If you choose update, the stable memory will stay. On the opposite, reinstalling canister will refresh the memory.","If you make significant changes to the code, you might get notified that the update will not be compatible with the previous version and the playground makes you reinstall the whole canister.","Let's make an easy exercise right now. Try to update your code with a new function dec, that will decrease the counter of 1 each time. Remember, the counter should not go below zero."]},{"l":"Import a module","p":["To import a module from Motoko base library, you can do it like that:","Now you have available all of the functions that are present in the Nat module that you can find on the official documentation page https://smartcontracts.org/docs/base-libraries/Nat.html. Notice, that there are also other modules available.","Now, lets make a function is_zero, that will return true if the counter value is zero or false if it's not a zero. Use a function imported from Nat module.","Viola, here is the whole working code in case you got lost. You can copy paste it to your playground."]},{"i":"save--share-your-code","l":"Save & share your code","p":["You know might want to save your code so you can open it later. You can either save the code and keep it in a local file or click on the Save & Share button in the top-right corner. This will generate you an unique link that you can come back to later."]},{"l":"Useful resources and links","p":["If you want to experiment with more examples of Motoko code. You can again click on the Open tutorial button in the top right corner. More examples can be found in this GitHub repo which was made by Dfinity foundation. Lastly, there is a no-code Motoko editor Blocks which contains some examples too and the Build & Run button will deploy your code via Motoko Playground as well.","Medium article a Yan Chen from Dfinity Foundation about Motoko Playground: https://medium.com/dfinity/introducing-the-motoko-playground-an-online-development-environment-for-the-internet-computer-efb4cd09ea8b","Community conversation from Dfinity also with Yan Chen about Motoko Playground: https://www.youtube.com/watch?v=A_RbxhN0BHI","Link to a Motoko documentation page: https://smartcontracts.org/docs/language-guide/motoko.html"]},{"l":"The author","p":["This tutorial was written by Lukas Vozda. If you find some resources out of date, have some suggestions or just want to get in touch. You can find me on Twitter @lukas_icp or Discord LukeVoz#0574."]}],[{"l":"Primitive data types","p":["Types play a significant role in Motoko language. Compared to modern general purpose languages such as Python, Motoko is very strict about types. This have a good purpose as it helps preventing Motoko programs to go wrong as mentioned in the documentation page.","For example, each variable in a Motoko program carries an associated type, and this type is known statically, before the program executes. Each use of each variable is checked by the compiler to prevent runtime type errors, including null reference errors, invalid field access and the like."]},{"l":"Types in Motoko","p":["Generally speaking, we can categorize types into two groups: primitive types and non-primitive values. This text focuses on primitive types mainly so we will explain them in more detail in the next chapter. To give you the contrast, let's quickly go through the primitive vs non-primitive values.","Primitive types in the Motoko programming language are integers, natural numbers, floating numbers, characters, texts and booleans.","Example of a primitive type, declaration of a variable that will have type of a natural number an is initialized with the value of 1:","Non-primitive values can be tuples, arrays, objects, variants, functions, async values or error values.","Example of a non-primitive type, declaring an array that b that can only contain natural numbers and is initialized with values 1, 2, 3:","You can easily experiment with types and run this sample code in the Motoko playground if you are not familiar with it you can follow Getting to know Motoko Playground tutorial."]},{"l":"Primitive types","p":["In this chapter, we will go through all of the primitive types and give you examples of how to declare variables and what can be assigned to them."]},{"l":"1. Unbounded Integers","p":["Unbounded integers can be assigned with positive or negative numbers. There are some ways how to declare an integer variable:","Let's do a little exercise now. Write a function called add, that will take two integers as arguments and return a sum of these two numbers.","That was quite easy, right? Try to experiment with it in the Candid UI."]},{"l":"2. Unbounded Natural numbers","p":["Unbounded natural numbers can be assigned with positive numbers only. The Motoko program will trap if you try to assign a negative number."]},{"l":"3. Bounded numbers","p":["As integers can also go below zero, we have space for 256 numbers too but in the range from -128 to 127.","But if you try this your program will fail because we are overflowing the maximum value:","For Nat16 the maximum value that can be assigned is 65 535 (2^ 16) and for Int16 we have minimum –32768 and maximum –32767. The same logic applies for 32 and 64 sizes of a type. This gives you understanding of what value can be assigned to a variable of specific type and gives you freedom to decide which one to use when designing your own program.","If you try to run this program, it will trap. Motoko Playground is well prepared for this type of situations, it doesn't let you execute the program and shows you an explanatory error message:","In Motoko, these bounded numbers types are available:","Int16","Int32","Int64","Int8","Keep in mind, even if you have a value that would fit into a smaller size Nat/Int, you can only assign it if it has the same type. Something like this will not work in Motoko:","Nat16","Nat32","Nat64","Nat8","Overflowing the Nat8 value in Motoko Playground","This means that you can declare a variable:","To explain the pattern, each type consists of Nat/Int and a number. This number represents the quantity of bits that will be assigned in memory of the computer for this specific type. For example Nat8 variable can be only assigned with values ranging from 0 to 255. This comes from a formula 2^ 8 = 256 so the maximum number is 255 as we are starting from 0.","Unbounded numbers variables can be assigned theoretically with numbers of any size. There are situations when you don't need this. For example if you want to declare a variable that will represent an age of a person. This variable should never exceed a number greater than 200. You might consider using a bounded variable to be more memory effective."]},{"l":"4. Floating point numbers","p":["For decimal numbers Float type is available in Motoko. Here are some ways how to assign a value to declared float variable:"]},{"l":"5. Characters and text","p":["For single characters, there is a type called Char and for strings of characters a Text type. Be careful, char type must be assigned with single quotes and string types with double quotes. Let's try to declare your own variables:","Let's create a function concat, that will take two strings a and b as arguments and will return a concatenated text of them both with a single space between them.","Exactly, you can use the # operator to concatenate strings in Motoko!"]},{"l":"6. Booleans","p":["For booleans we have a Bool type in Motoko. It can only hold a value either true or false."]},{"l":"Useful resources and links","p":["Motoko documentation page talking about types: https://smartcontracts.org/docs/languages/motoko-at-a-glance.html#_primitive_types","Motoko basic concepts and terms: https://smartcontracts.org/docs/language-guide/basic-concepts.html#intro-values","Motoko base library: https://smartcontracts.org/docs/base-libraries/stdlib-intro.html"]},{"l":"The author","p":["This tutorial was written by Lukas Vozda. If you find some resources out of date, have some suggestions or just want to get in touch. You can find me on Twitter @lukas_icp or Discord LukeVoz#0574."]}],[{"l":"Understanding types","p":["Now that we learned about primitive types in the previous lecture, let's move on to non-primitive types. In this tutorial, we are going to demonstrate how to declare them and build them with primitive types.","This is a natural process as non-primitive values can be user-defined, meaning that you can build objects or structures that combine multiple primitive types together."]},{"l":"Non-primitive types","p":["Let's quickly go through non-primitive types that are present in Motoko and how to declare them."]},{"l":"1. Tuples","p":["Tuples are simple objects that can contain multiple elements. These elements can be different types but you can't change the number of elements after you declare it. You could create a simple tuple type to store name and surname for a person:","Then, you could easily create a tuple that will store not only name but also an age of the person as you can mix different types in a tuple:","However, for more complex situations you should consider creating your own object with named parameters which would be more readable. Tuples are usually used for simple use cases only."]},{"l":"2. Arrays","p":["Arrays are used for storing multiple values. Unlike tuples, they can contain only one specific type. You can define mutable and immutable arrays. The difference is that mutable arrays can be updated and immutable arrays cannot."]},{"i":"21-immutable-arrays","l":"2.1 Immutable arrays","p":["Here is how you define an immutable array:","Now as we defined an immutable array with the type of text, Motoko playground will not let you include any other value than text, also it doesn't let you to update the value:","Let's do a first exersise. Try to write a function called getDay, that will take a Nat as an argument and returns a name of the corresponding day.","Here we go. That was simple. You can notice 2 things – function is very well defined with types in the input as well as in the output, if you try to put anything else than a natural number it is not going to work.","Also, we are using the query keyword in the function declaration which will make the function execution much faster. It is a very good idea to use a query function anytime we are not trying to update values in the backend of our app."]},{"i":"21-mutable-arrays","l":"2.1 Mutable arrays","p":["Declaration of a mutable array is very similar to an immutable array. The key difference is using the var keyword. Let's try to declare an immutable array.","Notice that now Motoko Playground allows you to reassign the array with different values. For example:","You could also change the number of elements inside freely. However, you still can't change an element inside individually as only the whole array is mutable but the content inside is not:","If you would like to make a totally mutable array, you need to use the var keyword also inside the declaration. Here is the full working code of a mutable array:","If you run this code in your Motoko Playground and try to run the function in the Candid UI, you should get \"Sunday\" for the index of 0.","If you'd like to make the immutable array mutable and vice versa, you need to use functions from the Array section of the Motoko base library. Specifically it is the thaw function to make the array mutable and the freeze function to make it immutable.","Notice that after using the thaw function, we can assign another array to the variable or even assign a value to a specific index. This wouldn't be possible with the immutable array."]},{"l":"3. Records","p":["In Motoko, similarly to arrays, records objects can be mutable and immutable. Here is how you define an immutable object Person with attributes name, surname and age:","Analogically, if you want to have your object type mutable, you should use the var keyword. Let's redesign the example above so we are able to update the age of a person, name and surname cannot be changed:"]},{"l":"4. Variants","p":["When declaring an object above, we have to define all of the parameters so we have a person that has name AND surname AND age. Variants perform more like OR as we are expecting to get one of the values inside. Let's create a variant type Status that will have options single, married and divorced.","Now let's update the Person record type that we created before and add status as another parameter. We expect the status parameter to be updated later on in time.","With this design, we assured that each person can only have one of the available statuses."]},{"l":"5. Functions","p":["We've been already messing around simple functions in this and previous tutorials so you probably know how to define them. Let's go through some more examples so you can recognize different types of functions in Motoko."]},{"l":"Public and private functions","p":["Most of the functions that we defined so far were public, as there was no specific reason to make them private. Private functions are used for specific situations when you don't want to expose the private function to the public interface of your canister.","Example of a public function in Motoko, using the keyword public before the function definition:","If you would like to make your function private, you use the private keyword. You will notice that private functions also have an _ underscore character in their names. This is not required by the language itself but recommended as a naming convention."]},{"l":"Functions from Motoko base library","p":["Like we presented in the array section, there are plenty of functions available in the Motoko base library. There is a section for each type. These functions are called from the imported module like we did with the thaw function:","Notice that some functions require to define the data type in the <> brackets.","Go through the base library and check what is inside for each type. These functions are going to save your time when writing your programs. However, please respect that Motoko is still quite a fresh language and there are not yet as many functions available as are with more mature languages."]},{"l":"Anonymous functions","p":["Anonymous functions are also known as lambdas. You define them for generic purposes in your program to complete small tasks. They are not meant to be part of the public interface."]},{"l":"6. Async values","p":["When canisters or actors communicate with each other on the Internet Computer, it happens asynchronously. Messages are processed one after another (in sequence) in an isolated way.","Let's have a look at an example from the documentation page:","Await keyword is used to say to our program that we are expecting a value from the other service but the value will be returned in the future, that is why we have to wait for it. After the future value is assigned to our variables result1 and result2 the program knows that it can call the finalStep function."]},{"l":"7. Optional values","p":["Optional values are used when we are expecting a specific type but it can be null as well. Optional values are defined with question marks and can be mostly found in the record type declaration or in functions.","Let's extend the Person model from above and add another parameter partner that will point to another person instance. Naturally, single persons will not have a partner so we must keep this parameter optional.","Optional values play significant roles also in function definitions as function can as well expect or return a null value. There will be a more detailed tutorial on that soon."]},{"l":"Useful links and resources","p":["Motoko Bootcamp video about variables, functions and types by Albert Du https://www.youtube.com/watch?v=4YX41Nm7Wx8","Motoko Bootcamp video about variants by Paul Young https://www.youtube.com/watch?v=GFenqSGhj7I&"]},{"l":"The author","p":["This tutorial was written by Lukas Vozda. If you find some resources out of date, have some suggestions or just want to get in touch. You can find me on Twitter @lukas_icp or Discord LukeVoz#0574."]}],[{"i":"null-variants-and-the-switch-statement","l":"Null, variants and the switch statement","p":["We have touched null, the optional type and variants softly in the Understanding types tutorial. Now it's time to dive deeper and write some functions that utilize them together with the switch statement."]},{"l":"Optional type","p":["In the Understanding types tutorial, we have described optional type as a type that we don't know whether we expect a real value of specific type, let's say Text or a null type.","To examine this, let's write a function called day_of_week that will take Nat as an argument and return the name of the week. We can use the days array from the previous tutorial.","That was easy! Now what happens if you put a number higher than 6 as an argument? Even if Motoko Playground deploys your code, it doesn't always mean it is safe. You need to take care of this kind of error yourself to prevent your program from failing.","To fix that, we can use the optional type ?Text, so our function knows that it can also return a null type.","Notice that ?Text and Text type are different. If your function is supposed to return a ?Text type, you can't just return a Text. In such a case, you would see this error:","That is why we put a question mark in front of the return type ?days[n]. Notice that in Candid UI you now can see the (opt \"Tuesday\") value returned instead of just text."]},{"l":"Switch statement","p":["Switch statement is a very popular concept in many programming languages. We could write this simple switch statement in a function as a warm up just that you get familiar with the Motoko syntax:","Things get more interesting when we apply switch statement on the optional type. We can use the switch statement to let our program decide what should happen if the optional value is null and what should happen if it's not.","Let's make a new function called Hello, that will take Text as an optional argument and return a message \"Hello, unknown person\" if the argument is null and \"Hello, /name/\" if it is a text.","To explain this, we have a switch statement that takes the function argument called name, in the case that name is null, it will return unknown person text, if there is something other than null, we are expecting the Text type and we return in concatenation with the greeting."]},{"l":"Variants","p":["Things will get more interesting, when we put variants into play. Variants give us the opportunity to define a specific set of choices or situations. We already touched variants in the previous tutorial, when we defined a variant type Status that says whether a person is single, married or divorced.","This is a very readable and technically effective way to give users of our program a limited choice. Also your program is much safer as it doesn't need to deal with array indexes, strings, typos and so on.","Let's now bring back the code from the previous Understanding types and write a function that will take a Person type as an argument and uses a switch statement on the status parameter of that person to return a text describing whether the person is single, married or divorce.","Deploy this code in your Motoko Playground project and try to create a person called Alice, 30 years old that is single and call the get_status function. Notice that Candid UI will let you choose only one of 3 options for the status attribute that we defined in our code. You should see \"Alice is single\" message in the output. We have also added a check that if a person decides not to fill the name, we will substitute the name with \"Person\" string.","To practice variants and the switch statement some more, let's bring up the days from the beginning of this text and try to create a variant representation of the object.","Not to confuse you, these two objects are very different. The variant way might be a better choice when writing your programs as it doesn't give the user options to insert bad inputs. Also your code might be more readable as #Monday is much easier to understand that day[0] where we might not be sure whether we start days from Monday or Sunday or whether the array indexes start from 1 or 0.","Now let's make a function called is_weekend that will take the Day variant and returns a Text \"weekend\" when the input is Saturday or Sunday or \"weekday\" when it is one of the other days.","Try to run this code in your Motoko Playground workspace and try to experiment with it. You should immediately notice how this code works better:","In the Candid UI you are allowed to input only predefined choices that are straightforward and easy to understand","Your Motoko code is also much simpler, you don't need to take care of specific situations such as the user input number that exceeds the index of the array."]},{"l":"Useful links and resources","p":["Motoko Bootcamp video about variants by Paul Young https://www.youtube.com/watch?v=GFenqSGhj7I&","Motoko Documentation page talking about options and errors https://smartcontracts.org/docs/current/developer-docs/build/languages/motoko/errors#working-with-optionresult","Motoko Documentation page talking about variants https://smartcontracts.org/docs/current/developer-docs/build/languages/motoko/overview#variants"]},{"l":"The author","p":["This tutorial was written by Lukas Vozda. If you find some resources out of date, have some suggestions or just want to get in touch. You can find me on Twitter @lukas_icp or Discord LukeVoz#0574."]}],[{"l":"Serving simple SVG over HTTP","p":["In this tutorial, things are going to get more exciting. We are going to learn how to serve a SVG image over HTTP(s) directly from your canister. Yes – canisters can serve web content over HTTP! You are probably familiar with that as it is one of the main advantages of the Internet Computer over the other blockchains. But there is also a http_request() function that you can use in Motoko to define how exactly is your canister going to behave when contacted over HTTP protocol.","This could be useful when you want to serve custom SVG images or define a custom api endpoint over the URL. Serving a dynamic NFT file is what we're going to do now.","We are going to use Motoko Playground for deploying the code, this will give you a quick start without needing to set up your local environment."]},{"l":"HTTP Requests","p":["We are going to start with this skeleton template used for educational purposes during the Motoko Bootcamp event.","The template contains two files, first the module file http.mo that contains types needed for HTTP communication from the canister.","If the code seems too exotic to you, please check this video that is explaining basics of the HTTP protocol. The most key part for our case in this tutorial are the Request and Response types that play the main role in our simple HTTP communication.","The second file is your main.mo file that loads the module http and contains a simple function http_request that puts it all together.","Now, try to deploy the code in the Motoko Playground. Let's ignore the Candid UI for now and focus on the Log message with the canister ID: Code installed at canister id wch4f-miaaa-aaaab-qadfa-cai. Your canister ID will be of course different. Copy your canister ID and create this URL following this pattern https://<>.raw.ic0.app/:","If all goes fine and you open your URL in your browser you should see the Hello world message.","Notice that there is a \"raw\" keyword in the URL. Raw in the URL means we are serving non certified assets. This certification means that IC guarantees that you are getting right the data. Certification can be expensive as it can cost a lot of assets so it only makes sense when serving very important data. You would need to implement a hash function for certification which is beyond the scope of this tutorial."]},{"l":"SVG image","p":["Now, let's put some SVG images into work. SVGs are basically text files that carry vector information about some visuals. You can easily find any SVG file online and use it or you can use the same as we. Create a text variable called svg that will contain data about your curve.","In order to display the SVG, we need to replace this line of code in our http_request function body = Text.encodeUtf8(\"Hello world\"); with the svg variable:","You could also adjust the header format of the return type if you want to be precise, but it will work with text/html as well.","Now if you deploy your code and try to refresh your canister page again in the browser, you should see the SVG image instead of the Hello, World message. Beautiful infinity symbol.","SVG infinity symbol from the canister","Here we go! You just served a SVG file over HTTP on the Internet Computer."]},{"l":"Dynamic SVG","p":["To demonstrate the power of serving SVG images over HTTP, we can now make a simple example of dynamically changing the SVG color.","Notice that there is a color definition at the beginning of our curve (path) in the SVG format fill=' black'. We can make this to change dynamically based on the number in the URL requested to the canister.","To start, let's create an array that will contain some colors:","Now, let's define a function make_svg that will take a color as a text argument and returns colored SVG if it finds it in our colors array. If it doesn't find the color in our array, it will return the default black color.","We are first looping through our colors array to find out if color is in it. If it is found we assign it as a result_color, if it is not inside we will use \"black\" as default. Notice that we are concatenating the SVG string with the color name.","Now let's change the http_request() function, so it gets the /path from the request and call the color_svg function, that will return the SVG code with the right color.","Now deploy your code and open the canister URL in another window of your browser again. Include the NFT color behind the URL so it looks like this (remember to use your own canister ID from the log console):","SVG rendered with specific color","Try to put something other than registered color name in the URL, you should see the default black symbol.","Here is the full working code in the Motoko Playground in case you got lost somewhere.","Main.mo","http.mo","Imagine what you can do with SVG files now, you have unlimited possibilities as this format is completely extendable or customizable. You can create more curves and layers, make interactions etc."]},{"l":"Useful resources and links","p":["Austin Fatheree presenting HTTP requests for Motoko Bootcamp https://www.youtube.com/watch?v=gaVuMaTP2lQ","Basics of HTTP communication https://www.youtube.com/watch?v=iYM2zFP3Zn0","Documentation page regarding canisters to respond HTTP requests https://smartcontracts.org/docs/http-middleware.html#_enabling_canisters_to_respond_to_http_requests","Motoko example HTTP counter from Dfinity https://github.com/dfinity/examples/blob/master/motoko/http_counter/src/main.mo"]},{"l":"The author","p":["This tutorial was written by Lukas Vozda. If you find some resources out of date, have some suggestions or just want to get in touch. You can find me on Twitter @lukas_icp or Discord LukeVoz#0574."]}],[{"l":"How To Contribute","p":["Follow these basic steps to add tutorials and contribute:","Clone our docs repo git clone git@github.com:icdevs/ic_devs_org_tutorials.git","Navigate to the cloned repo root directory","Install Retype(this is a great open source tool that helped us to create these docs) npm install retypeapp --global","Run the site locally retype watch","Create a new tutorial","Create a file under the tutorials folder (i.e. 'motoko-basics.md')","Write the tutorial in Markdown ( Formatting rules)","Create a PR","That is it. Once we review the changes we will merge with our main branch and your tutorial will be live \uD83D\uDE80 \uD83D\uDE80 \uD83D\uDE80"]},{"i":"happy-coding","l":"Happy coding!!!"}]] \ No newline at end of file diff --git a/.retype/sitemap.xml.gz b/.retype/sitemap.xml.gz index 50eae91..af398e6 100644 Binary files a/.retype/sitemap.xml.gz and b/.retype/sitemap.xml.gz differ diff --git a/.retype/tutorials/basics/index.html b/.retype/tutorials/basics/index.html index 39c7542..5b3fc37 100644 --- a/.retype/tutorials/basics/index.html +++ b/.retype/tutorials/basics/index.html @@ -27,11 +27,11 @@ - + - + - +
diff --git a/.retype/tutorials/motoko_playground/index.html b/.retype/tutorials/motoko_playground/index.html index 706a83e..a661476 100644 --- a/.retype/tutorials/motoko_playground/index.html +++ b/.retype/tutorials/motoko_playground/index.html @@ -29,11 +29,11 @@ - + - + - +
@@ -171,9 +171,9 @@


-

Motoko playground is a simple web interface that allows you to write and deploy motoko code in your web browser. It is a #1 choice for developers that just have started getting to know about the Internet Computer ecosystem and want to learn motoko programing language.

+

Motoko playground is a simple web interface that allows you to write and deploy motoko code in your web browser. It is a #1 choice for developers that just have started getting to know about the Internet Computer ecosystem and want to learn the motoko programming language.

-

Motoko is a programing language developed natively for the Internet Computer blockchain. If you want to learn more about Motoko, visit the documentation page.

+

Motoko is a programming language developed natively for the Internet Computer blockchain. If you want to learn more about Motoko, visit the documentation page.

@@ -187,20 +187,20 @@

Create a new project

-

You should se a modal window simmilar to the screen above that is basically giving you three options:

+

You should see a modal window similar to the screen above that is basically giving you three options:

  1. Create a new blank project
  2. Open one of the pre-prepared projects
  3. Import code from public Github repo
-

If you want to start coding from scratch, clicking on New Motoko project is the best option for you. In this tutorial, let's click on the Counter example so we can demonstrate how to use the playground.

-

This will get you the a Readme file that describes the project and presents how to deploy the code locally on your computer. As Motoko playground is working in the browser, you don't need to set up your local development enviroment and install the SKD now. Skip this and just click to the Main.mo file on the left hand side. This will bring you to the code.

+

If you want to start coding from scratch, clicking on the New Motoko project is the best option for you. In this tutorial, let's click on the Counter example so we can demonstrate how to use the playground.

+

This will get you to a readme file that describes the project and presents how to deploy the code locally on your computer. As Motoko playground is working in the browser, you don't need to set up your local development environment and install the SKD now. Skip this and just click to the Main.mo file on the left hand side. This will bring you to the code.

Counter example code
Counter example code

-

This is how your workspace looks. On the left, you can manage files in your project, load packages and other canisters (smart contracts). In the bottom is a little console that shows you logs, this is where you look for error messagess when deploying. In the top right there is a Deploy button that we will use for deploying and testing our code.

+

This is how your workspace looks. On the left, you can manage files in your project, load packages and other canisters (smart contracts). In the bottom is a little console that shows you logs, this is where you look for error messages when deploying. In the top right there is a Deploy button that we will use for deploying and testing our code.

# @@ -230,7 +230,7 @@

};

-

The actor has a stable variable counter, that will store the number of the counter and 3 public funcitons – get, set and inc. These functions form a public interface of our canister and we will see them in the generated Candid interface after deploy.

+

The actor has a stable variable counter, that will store the number of the counter and 3 public functions – get, set and inc. These functions form a public interface of our canister and we will see them in the generated Candid interface after deploy.

Candid is an IDL (interface definition language) developed for the IC ecosystem in order to facilitate communication between services written in different programing languages. You can read more about it here.

@@ -241,7 +241,7 @@

First, you need to confirm the deploy by selecting a canister name and set up a garbage collector strategy. You can keep the settings as it is for now and click Install. You should see a success message in the console log.

-

Motoko Playground is really deploying your canister to the network. As it serves for educational and testing purposes only, there are some limitations such as only 1 GB of data can be used and the canister will expier after 20 minutes. Using this playground is very convinient for new devs learning Motoko, as you don't have to pay for cycles fees for deployment, which you would need to do when deploying to the mainnet directly.

+

Motoko Playground is really deploying your canister to the network. As it serves for educational and testing purposes only, there are some limitations such as only 1 GB of data can be used and the canister will expire after 20 minutes. Using this playground is very convenient for new devs learning Motoko, as you don't have to pay for cycles fees for deployment, which you would need to do when deploying to the mainnet directly.

# @@ -255,7 +255,7 @@

As we mentioned above, Candid UI follows the interface defined in your Motoko code. You should see a form consisting of three functions get, inc and set. Function get and inc is not expecting any argument so you can click on Query or Call button and experiment with it. Function set is expecting a natural number (Nat) that you can pass in the input field.

-

You will notice that query functions have very fast execution usually in terms of miliseconds. On the other hand, functions calling an update usually takes about 2 seconds.

+

You will notice that query functions have very fast execution usually in terms of milliseconds. On the other hand, functions calling an update usually takes about 2 seconds.

# @@ -327,20 +327,29 @@

Save & share your code

-

You know might want to save your code so you can open it later. You can either save the code and keep in in a local file or click on the Save & Share button in the top-right corner. This will generate you an unique link that you can come back to later.

+

You know might want to save your code so you can open it later. You can either save the code and keep it in a local file or click on the Save & Share button in the top-right corner. This will generate you an unique link that you can come back to later.

# Useful resources and links

-

If you want to experiment with more exapmles of Motoko code. You can again click on the Open tutorial button in the top right corner. More examples can be found in this GitHub repo which was made by Dfinity foundation. Lastly, there is a no-code Motoko editor Blocks which contains some examples too and the Build & Run button will deploy your code via Motoko Playground as well.

+

If you want to experiment with more examples of Motoko code. You can again click on the Open tutorial button in the top right corner. More examples can be found in this GitHub repo which was made by Dfinity foundation. Lastly, there is a no-code Motoko editor Blocks which contains some examples too and the Build & Run button will deploy your code via Motoko Playground as well.

Medium article a Yan Chen from Dfinity Foundation about Motoko Playground:
https://medium.com/dfinity/introducing-the-motoko-playground-an-online-development-environment-for-the-internet-computer-efb4cd09ea8b

-

Community converstaion from Dfinity also with Yan Chen about Motoko Playground:
+

Community conversation from Dfinity also with Yan Chen about Motoko Playground:
https://www.youtube.com/watch?v=A_RbxhN0BHI

Link to a Motoko documentation page:
https://smartcontracts.org/docs/language-guide/motoko.html

+ +

+ # + The author +

+
+
+

This tutorial was written by Lukas Vozda. If you find some resources out of date, have some suggestions or just want to get in touch. You can find me on Twitter @lukas_icp or Discord LukeVoz#0574.

+
diff --git a/.retype/tutorials/null_variants_switch/index.html b/.retype/tutorials/null_variants_switch/index.html new file mode 100644 index 0000000..b72c112 --- /dev/null +++ b/.retype/tutorials/null_variants_switch/index.html @@ -0,0 +1,444 @@ + + + + + + + + + + + + Null, variants and the switch statement + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + +
+ + +
+
+ +
+ + +
+ +
+ + + + +
+ + + + + +
+ +
+ + +
+ + +
+ +
+
+ +
+
+ + + + +
+
+
+
+ +
+ + + + + + + + +
+ +
+
+
+
+ +
+ + + +

+ # + Null, variants and the switch statement +

+
+

We have touched null, the optional type and variants softly in the Understanding types tutorial. Now it's time to dive deeper and write some functions that utilize them together with the switch statement.

+ +

+ # + Optional type +

+
+

In the Understanding types tutorial, we have described optional type as a type that we don't know whether we expect a real value of specific type, let's say Text or a null type.

+

To examine this, let's write a function called day_of_week that will take Nat as an argument and return the name of the week. We can use the days array from the previous tutorial.

+
+
let days : [Text] =  ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"];
+
+public query func day_of_week(n : Nat) async Text {
+	return days[n];
+};
+
+

That was easy! Now what happens if you put a number higher than 6 as an argument? Even if Motoko Playground deploys your code, it doesn't always mean it is safe. You need to take care of this kind of error yourself to prevent your program from failing.

+

To fix that, we can use the optional type ?Text, so our function knows that it can also return a null type.

+
+
public query func day_of_week(n : Nat) : async ?Text {
+    if (n <= 6){
+        return ?days[n];
+    } else {
+        return null;
+    };
+};
+
+

Notice that ?Text and Text type are different. If your function is supposed to return a ?Text type, you can't just return a Text. In such a case, you would see this error:

+
+
expression of type
+  Text
+cannot produce expected type
+  ?Text
+
+

That is why we put a question mark in front of the return type ?days[n]. Notice that in Candid UI you now can see the (opt "Tuesday") value returned instead of just text.

+ +

+ # + Switch statement +

+
+

Switch statement is a very popular concept in many programming languages. We could write this simple switch statement in a function as a warm up just that you get familiar with the Motoko syntax:

+
+
public query func day_of_the_week(n : Nat) : async Text {
+    switch(n){
+        case(1) {
+            return "Monday";
+        };
+        case(2) {
+            return "Tuesday";
+        };
+        case(3) {
+            return "Wednesday";
+        };
+        case(4) {
+            return "Thursday";
+        };
+        case(5) {
+            return "Friday";
+        };
+        case(6) {
+            return "Saturday";
+        };
+        case(7) {
+            return "Sunday";
+        };
+        case(_) {
+            return "Not a valid index";
+        };
+    };
+};
+
+

Things get more interesting when we apply switch statement on the optional type. We can use the switch statement to let our program decide what should happen if the optional value is null and what should happen if it's not.

+

Let's make a new function called Hello, that will take Text as an optional argument and return a message "Hello, unknown person" if the argument is null and "Hello, /name/" if it is a text.

+
+
public query func hello(name : ?Text) : async Text {
+    switch(name){
+        case(null){
+            return "Hello, unknown person";
+        };
+        case(?value){
+            return "Hello, " # value;
+        };
+    };
+};
+
+

To explain this, we have a switch statement that takes the function argument called name, in the case that name is null, it will return unknown person text, if there is something other than null, we are expecting the Text type and we return in concatenation with the greeting.

+ +

+ # + Variants +

+
+

Things will get more interesting, when we put variants into play. Variants give us the opportunity to define a specific set of choices or situations. We already touched variants in the previous tutorial, when we defined a variant type Status that says whether a person is single, married or divorced.

+
+
public type Status = {
+    #single;
+    #married;
+    #divorced;
+};
+
+

This is a very readable and technically effective way to give users of our program a limited choice. Also your program is much safer as it doesn't need to deal with array indexes, strings, typos and so on.

+

Let's now bring back the code from the previous Understanding types and write a function that will take a Person type as an argument and uses a switch statement on the status parameter of that person to return a text describing whether the person is single, married or divorce.

+
+
actor Person {
+
+	public type Status = {
+	    #single;
+	    #married;
+	    #divorced;
+	};
+
+	type Person = {
+	    name : Text;
+	    surname : Text;
+	    age : Nat;
+	    status : Status;
+	    partner : ?Person; // optional attribute
+	};
+
+
+	public query func get_status(p : Person) : async Text {
+	    let name : Text = p.name;
+	    if (name == ""){
+	        let name = "Person";
+	    };
+	    switch(p.status){
+	        case(#single){
+	            return name # " is single.";
+	        };
+	        case(#married){
+	            return name # " is married."
+	        };
+	        case(#divorced){
+	            return name # " is divorced."
+	        };
+	    };
+	};
+}
+
+

Deploy this code in your Motoko Playground project and try to create a person called Alice, 30 years old that is single and call the get_status function. Notice that Candid UI will let you choose only one of 3 options for the status attribute that we defined in our code. You should see "Alice is single" message in the output. We have also added a check that if a person decides not to fill the name, we will substitute the name with "Person" string.

+

To practice variants and the switch statement some more, let's bring up the days from the beginning of this text and try to create a variant representation of the object.

+
+
// Before – days as Array
+let days : [Text] =  ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"];
+
+// After – days as Variants
+type Day = {
+    #Monday;
+    #Tuesday;
+    #Wednesday;
+    #Thursday;
+    #Friday;
+    #Saturday;
+    #Sunday;
+}
+
+

Not to confuse you, these two objects are very different. The variant way might be a better choice when writing your programs as it doesn't give the user options to insert bad inputs. Also your code might be more readable as #Monday is much easier to understand that day[0] where we might not be sure whether we start days from Monday or Sunday or whether the array indexes start from 1 or 0.

+

Now let's make a function called is_weekend that will take the Day variant and returns a Text "weekend" when the input is Saturday or Sunday or "weekday" when it is one of the other days.

+
+
actor Day {
+
+	type Day = {
+	    #Monday;
+	    #Tuesday;
+	    #Wednesday;
+	    #Thursday;
+	    #Friday;
+	    #Saturday;
+	    #Sunday;
+	};
+
+	public query func is_weekend(d : Day) : async Text {
+	    switch d {
+	        case (#Saturday or #Sunday) "weekend";  
+	        case _ "weekday"; 
+	    };
+	};
+}
+
+

Try to run this code in your Motoko Playground workspace and try to experiment with it. You should immediately notice how this code works better:

+
    +
  1. In the Candid UI you are allowed to input only predefined choices that are straightforward and easy to understand
  2. +
  3. Your Motoko code is also much simpler, you don't need to take care of specific situations such as the user input number that exceeds the index of the array.
  4. +
+ +

+ # + Useful links and resources +

+
+

Motoko Bootcamp video about variants by Paul Young
+https://www.youtube.com/watch?v=GFenqSGhj7I&

+

Motoko Documentation page talking about options and errors
+https://smartcontracts.org/docs/current/developer-docs/build/languages/motoko/errors#working-with-optionresult

+

Motoko Documentation page talking about variants
+https://smartcontracts.org/docs/current/developer-docs/build/languages/motoko/overview#variants

+ +

+ # + The author +

+
+
+

This tutorial was written by Lukas Vozda. If you find some resources out of date, have some suggestions or just want to get in touch. You can find me on Twitter @lukas_icp or Discord LukeVoz#0574.

+
+ + + + +
+ +
+ +
+
+
+
    +
+
+ +
+
+
+ + + + + + + +
+ +
+
+ + + +
+ + +
+ + + + diff --git a/.retype/tutorials/primitive_types/index.html b/.retype/tutorials/primitive_types/index.html index 0fab056..9504bc9 100644 --- a/.retype/tutorials/primitive_types/index.html +++ b/.retype/tutorials/primitive_types/index.html @@ -29,11 +29,11 @@ - + - + - +
@@ -179,8 +179,8 @@

Types in Motoko

-

Generaly speaking, we can categorize types into two groups: primitive types non-primitive values. This text focuses on primitive types mainly so we will explain them in more detail in the next chapture. To give you the contrast, let's quickly go through the primitive vs non-primitive values.

-

Primitive types in Motoko programming language are integers, natural numbers floating numbers, characters, texts and booleans.

+

Generally speaking, we can categorize types into two groups: primitive types and non-primitive values. This text focuses on primitive types mainly so we will explain them in more detail in the next chapter. To give you the contrast, let's quickly go through the primitive vs non-primitive values.

+

Primitive types in the Motoko programming language are integers, natural numbers, floating numbers, characters, texts and booleans.

Example of a primitive type, declaration of a variable that will have type of a natural number an is initialized with the value of 1:

let a : Nat = 1;
@@ -213,7 +213,7 @@

let c : Int = 1_000_000; let d : Int = 0xf4; // 245

-

Let's make a little exercise now. Write a funciton called add, that will take two integers as arguments and return a sum of these two numbers.

+

Let's do a little exercise now. Write a function called add, that will take two integers as arguments and return a sum of these two numbers.

public query func add(a : Int, b : Int) : async Int {
     return a+b;
@@ -226,7 +226,7 @@ 

2. Unbounded Natural numbers

-

Unbounded natural numbers can be assigned with positive numbers only. Motoko program will trap if you try to assign a negative number.

+

Unbounded natural numbers can be assigned with positive numbers only. The Motoko program will trap if you try to assign a negative number.

let a : Nat = 1;
 let b : Nat = 1_000_000;
@@ -238,7 +238,7 @@ 

3. Bounded numbers

-

Unbounded numbers variables can be assigned theoretically with numbers of any size. There are situations when you don't need this. For example if you want to declare a variable that will represent an age of a person. This variable should never exceed a number greater than 200. You might consider to use a bounded variable to be more memory effective.

+

Unbounded numbers variables can be assigned theoretically with numbers of any size. There are situations when you don't need this. For example if you want to declare a variable that will represent an age of a person. This variable should never exceed a number greater than 200. You might consider using a bounded variable to be more memory effective.

In Motoko, these bounded numbers types are available:

  • Nat8
  • @@ -250,7 +250,7 @@

  • Int32
  • Int64
-

To explain the pattern, each type consist of Nat/Int and a number. This number represents quantity of bits that will be assigned in memory of the computer for this specific type. For example Nat8 variable can be only assigned with values ranging from 0 to 255. This comes from a formula 2^8 = 256 so the maximum number is 255 as we are starting from 0.

+

To explain the pattern, each type consists of Nat/Int and a number. This number represents the quantity of bits that will be assigned in memory of the computer for this specific type. For example Nat8 variable can be only assigned with values ranging from 0 to 255. This comes from a formula 2^8 = 256 so the maximum number is 255 as we are starting from 0.

This means that you can declare a variable:

let a : Nat8 = 255; // Ok
@@ -272,7 +272,7 @@

let c : Int8 = -130 // Not ok let d : Int8 = 250 // Not ok

-

For Nat16 the maximum value that can be assigned is 65 535 (2^16) and for Int16 we have minimum –32768 and maximum –32767. The same logic applies for 32 and 64 size of a type. This gives you understanding of what value can be assigned to a variable of specific type and gives you freedom to decide which one to use when designing your own program.

+

For Nat16 the maximum value that can be assigned is 65 535 (2^16) and for Int16 we have minimum –32768 and maximum –32767. The same logic applies for 32 and 64 sizes of a type. This gives you understanding of what value can be assigned to a variable of specific type and gives you freedom to decide which one to use when designing your own program.

Keep in mind, even if you have a value that would fit into a smaller size Nat/Int, you can only assign it if it has the same type. Something like this will not work in Motoko:

let a : Int8 = 10; // Not Ok – Int8 and Int32 types not compatible
@@ -302,14 +302,14 @@ 

5. Characters and text

-

For single characters, there is a type called Char and for strings of characters a Text type. Be careful, char type must be assigned with single quotes and string types with double qoutes. Lets try to declare your own variables:

+

For single characters, there is a type called Char and for strings of characters a Text type. Be careful, char type must be assigned with single quotes and string types with double quotes. Let's try to declare your own variables:

let a : Char = 'A'; // Ok
 let b : Char = "B"; // Not ok
 let c : Text =  "Hello, World!" // Ok
 let d : Text = 'Hello, World!' // Not ok
-

Let's create a funciton concat, that will take two strings a and b as arguments and will return a concatenated text of them both with a single space between them.

+

Let's create a function concat, that will take two strings a and b as arguments and will return a concatenated text of them both with a single space between them.

public query func concat(a : Text, b : Text) : async Text {
     return a # " " # b;
@@ -333,12 +333,21 @@ 

Useful resources and links

-

Motoko documentaion page talking about types:
+

Motoko documentation page talking about types:
https://smartcontracts.org/docs/languages/motoko-at-a-glance.html#_primitive_types

Motoko basic concepts and terms:
https://smartcontracts.org/docs/language-guide/basic-concepts.html#intro-values

Motoko base library:
https://smartcontracts.org/docs/base-libraries/stdlib-intro.html

+ +

+ # + The author +

+
+
+

This tutorial was written by Lukas Vozda. If you find some resources out of date, have some suggestions or just want to get in touch. You can find me on Twitter @lukas_icp or Discord LukeVoz#0574.

+
diff --git a/.retype/tutorials/serving_svg_over_http/index.html b/.retype/tutorials/serving_svg_over_http/index.html index 8d4ad7e..a633229 100644 --- a/.retype/tutorials/serving_svg_over_http/index.html +++ b/.retype/tutorials/serving_svg_over_http/index.html @@ -11,29 +11,29 @@ Serving simple SVG over HTTP - + - + - + - + - + - +
@@ -169,9 +169,9 @@

Serving simple SVG over HTTP

-

In this tutorial, things are going to get more excited. We are going to learn how to serve a SVG image over HTTP(s) directly from your canister. Yes – canisters can serve web content over HTTP! You are probably familiar with that as it is one of the main advantages of the Internet Computer over the other blockchains. But there is also a http_request() function that you can use in Motoko to define how exactly is your canister going to behave when contacted over HTTP protocol.

-

This could be useful when you want to serve custom SVG images or define custom api endpoint over the URL. Serving a dynamic NFT file is what we're going to do now.

-

We are going to use Motoko Playground for deploying the code, this will give you a quick start without needing to setting up your local enviroment.

+

In this tutorial, things are going to get more exciting. We are going to learn how to serve a SVG image over HTTP(s) directly from your canister. Yes – canisters can serve web content over HTTP! You are probably familiar with that as it is one of the main advantages of the Internet Computer over the other blockchains. But there is also a http_request() function that you can use in Motoko to define how exactly is your canister going to behave when contacted over HTTP protocol.

+

This could be useful when you want to serve custom SVG images or define a custom api endpoint over the URL. Serving a dynamic NFT file is what we're going to do now.

+

We are going to use Motoko Playground for deploying the code, this will give you a quick start without needing to set up your local environment.

# @@ -179,7 +179,7 @@

We are going to start with this skeleton template used for educational purposes during the Motoko Bootcamp event.

-

The template contains of two files, first the module file http.mo that contains types needed for HTTP communication from the canister.

+

The template contains two files, first the module file http.mo that contains types needed for HTTP communication from the canister.

module {
     public type HeaderField = (Text, Text);
@@ -219,7 +219,7 @@ 

};

-

If the code seems too exotic to you, please check this video that is explaining basics of HTTP protocol. The most key part for our case in this tutorial are the Request and Response types that play the main role in our simple HTTP communication.

+

If the code seems too exotic to you, please check this video that is explaining basics of the HTTP protocol. The most key part for our case in this tutorial are the Request and Response types that play the main role in our simple HTTP communication.

The second file is your main.mo file that loads the module http and contains a simple function http_request that puts it all together.

import HTTP "http";
@@ -241,14 +241,14 @@ 

https://wch4f-miaaa-aaaab-qadfa-cai.raw.ic0.app/

If all goes fine and you open your URL in your browser you should see the Hello world message.

-

Notice that there is a "raw" keyword in the URL. Raw in the URL means we are serving non certified assets. This certification means that IC guarantees that you are getting right data. Certification can be expensive as it can cost a lot of assets so it only makes sense when serving very important data. You would need to implement a hash function for certification which is beyond the scope of this tutorial.

+

Notice that there is a "raw" keyword in the URL. Raw in the URL means we are serving non certified assets. This certification means that IC guarantees that you are getting right the data. Certification can be expensive as it can cost a lot of assets so it only makes sense when serving very important data. You would need to implement a hash function for certification which is beyond the scope of this tutorial.

# SVG image

-

Now, let's put some SVG image into works. SVGs are basically text files that carry vector information about some visual. You can easily find any SVG file online and use it or you can use the same as we. Create a text variable called svg that will contain data about your curve.

+

Now, let's put some SVG images into work. SVGs are basically text files that carry vector information about some visuals. You can easily find any SVG file online and use it or you can use the same as we. Create a text variable called svg that will contain data about your curve.

let svg : Text = "<svg version='1.1' id='Layer_1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px'viewBox='0 0 2703.214 1272.608' style='enable-background:new 0 0 2703.214 1272.608;' xml:space='default'><g><g>" #
 		    "<path fill='black' d='M72.373,651.52C62.109,212.429,541.276-95.972,961.842,145.033c138.551,79.397,256.167,196.988,382.632,325.418 c5.749,5.839,8.404,5.236,13.785-0.188c197.808-199.402,484.222-503.454,885.399-385.157 c168.833,49.784,286.15,159.321,346.255,324.377c201.16,552.413-375.869,1009.769-870.693,706.588 c-124.801-76.466-232.581-181.978-359.98-311.726c-6.801-6.927-9.868-5.946-16.086,0.324c-144.739,145.956-300.538,304.607-492.977,371.024C458.575,1310.846,83.17,1077.492,72.373,651.52z M317.418,643.008 c12.485,253.639,207.59,371.88,415.468,326.918c179.653-38.857,330.36-196.86,458.721-328.811c4.325-4.446,1.9-6.251-1.072-9.025 c-111.488-104.066-220.365-231.184-357.581-296.6C567.01,208.705,316.523,394.639,317.418,643.008z M2385.265,632.288 c-7.903-245.124-201.289-378.703-424.132-326.433c-175.334,41.126-325.161,198.381-449.641,326.279 c-4.318,4.437-2.66,6.509,0.879,9.811c155.637,145.245,339.3,374.567,587.443,332.772 C2265.103,946.877,2385.634,802.91,2385.265,632.288z'/></g></g></svg>";
@@ -259,7 +259,7 @@ 

body = Text.encodeUtf8(svg);

You could also adjust the header format of the return type if you want to be precise, but it will work with text/html as well.

-

Now if you deploy your code and try to refresh your canister page again in the browser, you should see the SVG image instead of Hello, World message. Beautifull infinity symbol.

+

Now if you deploy your code and try to refresh your canister page again in the browser, you should see the SVG image instead of the Hello, World message. Beautiful infinity symbol.

SVG infinity symbol from the canister
SVG infinity symbol from the canister
@@ -291,7 +291,7 @@

"<path fill='" # result_color # "'d='M72.373,651.52C62.109,212.429,541.276-95.972,961.842,145.033c138.551,79.397,256.167,196.988,382.632,325.418 c5.749,5.839,8.404,5.236,13.785-0.188c197.808-199.402,484.222-503.454,885.399-385.157 c168.833,49.784,286.15,159.321,346.255,324.377c201.16,552.413-375.869,1009.769-870.693,706.588 c-124.801-76.466-232.581-181.978-359.98-311.726c-6.801-6.927-9.868-5.946-16.086,0.324c-144.739,145.956-300.538,304.607-492.977,371.024C458.575,1310.846,83.17,1077.492,72.373,651.52z M317.418,643.008 c12.485,253.639,207.59,371.88,415.468,326.918c179.653-38.857,330.36-196.86,458.721-328.811c4.325-4.446,1.9-6.251-1.072-9.025 c-111.488-104.066-220.365-231.184-357.581-296.6C567.01,208.705,316.523,394.639,317.418,643.008z M2385.265,632.288 c-7.903-245.124-201.289-378.703-424.132-326.433c-175.334,41.126-325.161,198.381-449.641,326.279 c-4.318,4.437-2.66,6.509,0.879,9.811c155.637,145.245,339.3,374.567,587.443,332.772 C2265.103,946.877,2385.634,802.91,2385.265,632.288z'/></g></g></svg>"; };

-

We are first looping through our colors array to find out if color is in it. If it is found we assign it as a result_color, if it is not inside we will use "black" as default. Notice that we are contatenating the SVG string with the color name.

+

We are first looping through our colors array to find out if color is in it. If it is found we assign it as a result_color, if it is not inside we will use "black" as default. Notice that we are concatenating the SVG string with the color name.

Now let's change the http_request() function, so it gets the /path from the request and call the color_svg function, that will return the SVG code with the right color.

public query func http_request(request : HTTP.Request) : async HTTP.Response {
@@ -317,7 +317,7 @@ 

SVG rendered with specific color

-

Try to put something else than registered color name in the URL, you should see the default black symbol.

+

Try to put something other than registered color name in the URL, you should see the default black symbol.

Here is the full working code in the Motoko Playground in case you got lost somewhere.

Main.mo

@@ -407,6 +407,15 @@

https://smartcontracts.org/docs/http-middleware.html#_enabling_canisters_to_respond_to_http_requests

Motoko example HTTP counter from Dfinity
https://github.com/dfinity/examples/blob/master/motoko/http_counter/src/main.mo

+ +

+ # + The author +

+
+
+

This tutorial was written by Lukas Vozda. If you find some resources out of date, have some suggestions or just want to get in touch. You can find me on Twitter @lukas_icp or Discord LukeVoz#0574.

+
@@ -416,11 +425,11 @@

+person1.name := "Adam"; // Not ok, expected mutable assignment target

@@ -385,7 +385,7 @@

Functions from Motoko base library

-

Like we presented in the array section, there is plenty of functions available in the Motoko base library. There is a section for each type. These functions are called from the imported module like we did with the thaw function:

+

Like we presented in the array section, there are plenty of functions available in the Motoko base library. There is a section for each type. These functions are called from the imported module like we did with the thaw function:

import Array "mo:base/Array";
 <some code>
@@ -393,14 +393,14 @@ 

<some code>

Notice that some functions require to define the data type in the <> brackets.

-

Go through the base library and check what is inside for each type. These funcitons are going to save your time when writing your programs. However, please respect that Motoko is still quite a fresh language and there is not yet as many functions available as for more mature languages.

+

Go through the base library and check what is inside for each type. These functions are going to save your time when writing your programs. However, please respect that Motoko is still quite a fresh language and there are not yet as many functions available as are with more mature languages.

# Anonymous functions

-

Anonymous functions are also known as lambdas. You define them for generic purpose in your program to complete small tasks. They are not ment to be part of the public interface.

+

Anonymous functions are also known as lambdas. You define them for generic purposes in your program to complete small tasks. They are not meant to be part of the public interface.

func add(x : Int, y : Int) : Int = x + y;
@@ -410,7 +410,7 @@

6. Async values

-

When canisters or actors communicate with each other on the Internet Computer, it happens asynchronously. Messagess are processed one after another (in sequence) in an isolated way.

+

When canisters or actors communicate with each other on the Internet Computer, it happens asynchronously. Messages are processed one after another (in sequence) in an isolated way.

Let's have a look at an example from the documentation page:

let result1 = await service1.computeAnswer(params);
@@ -424,7 +424,7 @@ 

7. Optional values

-

Optional values are used when we are expecting a specific type but it can be null as well. Optional values are defined with question mark and can be mostly found in the record type declaration or in functions.

+

Optional values are used when we are expecting a specific type but it can be null as well. Optional values are defined with question marks and can be mostly found in the record type declaration or in functions.

Let's extend the Person model from above and add another parameter partner that will point to another person instance. Naturally, single persons will not have a partner so we must keep this parameter optional.

public type Status = {
@@ -457,7 +457,7 @@ 

var partner = ?person1; // in real situation, we should also update the status of person1 and person2 and set partner for person1 if the relationship is symmetrical };

-

Optional values play significant roles also in function definitions as funciton can as well expect or return a null value. There will be more detailed tutorial on that soon.

+

Optional values play significant roles also in function definitions as function can as well expect or return a null value. There will be a more detailed tutorial on that soon.

# @@ -468,6 +468,15 @@

https://www.youtube.com/watch?v=4YX41Nm7Wx8

Motoko Bootcamp video about variants by Paul Young
https://www.youtube.com/watch?v=GFenqSGhj7I&

+ +

+ # + The author +

+
+
+

This tutorial was written by Lukas Vozda. If you find some resources out of date, have some suggestions or just want to get in touch. You can find me on Twitter @lukas_icp or Discord LukeVoz#0574.

+
@@ -487,10 +496,10 @@

- + Next - Serving simple SVG over HTTP + Null, variants and the switch statement diff --git a/tutorials/motoko_playground.md b/tutorials/motoko_playground.md index dae8c92..bc04742 100644 --- a/tutorials/motoko_playground.md +++ b/tutorials/motoko_playground.md @@ -9,9 +9,9 @@ order: 500 -Motoko playground is a simple web interface that allows you to write and deploy motoko code in your web browser. It is a #1 choice for developers that just have started getting to know about the Internet Computer ecosystem and want to learn motoko programing language. +Motoko playground is a simple web interface that allows you to write and deploy motoko code in your web browser. It is a #1 choice for developers that just have started getting to know about the Internet Computer ecosystem and want to learn the motoko programming language. -> Motoko is a programing language developed natively for the Internet Computer blockchain. If you want to learn more about Motoko, visit the [documentation page](https://smartcontracts.org/docs/language-guide/motoko.html). +> Motoko is a programming language developed natively for the Internet Computer blockchain. If you want to learn more about Motoko, visit the [documentation page](https://smartcontracts.org/docs/language-guide/motoko.html). ## Start first project @@ -19,19 +19,19 @@ You can easily open Motoko playground by visiting this link https://m7sm4-2iaaa- ![Create a new project](../static/motoko1.png) -You should se a modal window simmilar to the screen above that is basically giving you three options: +You should see a modal window similar to the screen above that is basically giving you three options: 1. Create a new blank project 2. Open one of the pre-prepared projects 3. Import code from public Github repo -If you want to start coding from scratch, clicking on New Motoko project is the best option for you. In this tutorial, let's click on the **Counter** example so we can demonstrate how to use the playground. +If you want to start coding from scratch, clicking on the New Motoko project is the best option for you. In this tutorial, let's click on the **Counter** example so we can demonstrate how to use the playground. -This will get you the a Readme file that describes the project and presents how to deploy the code locally on your computer. As Motoko playground is working in the browser, **you don't need to set up your local development enviroment and install the SKD now**. Skip this and just click to the Main.mo file on the left hand side. This will bring you to the code. +This will get you to a readme file that describes the project and presents how to deploy the code locally on your computer. As Motoko playground is working in the browser, **you don't need to set up your local development environment and install the SKD now**. Skip this and just click to the Main.mo file on the left hand side. This will bring you to the code. ![Counter example code](../static/motoko2.png) -This is how your workspace looks. On the left, you can manage files in your project, load packages and other canisters (smart contracts). In the bottom is a little console that shows you logs, this is where you look for error messagess when deploying. In the top right there is a Deploy button that we will use for deploying and testing our code. +This is how your workspace looks. On the left, you can manage files in your project, load packages and other canisters (smart contracts). In the bottom is a little console that shows you logs, this is where you look for error messages when deploying. In the top right there is a Deploy button that we will use for deploying and testing our code. ## Deploy your code @@ -60,7 +60,7 @@ actor Counter { ``` -The actor has a stable variable counter, that will store the number of the counter and 3 public funcitons – get, set and inc. These functions form a public interface of our canister and we will see them in the generated Candid interface after deploy. +The actor has a stable variable counter, that will store the number of the counter and 3 public functions – get, set and inc. These functions form a public interface of our canister and we will see them in the generated Candid interface after deploy. > Candid is an IDL (interface definition language) developed for the IC ecosystem in order to facilitate communication between services written in different programing languages. You can read more about it [here](https://medium.com/dfinity/candid-a-tool-for-interoperable-programming-languages-on-the-internet-computer-27e7085cd97f). @@ -70,7 +70,7 @@ Motoko playground not only allows you to write and deploy your code, it also gen First, you need to confirm the deploy by selecting a canister name and set up a garbage collector strategy. You can keep the settings as it is for now and click Install. You should see a success message in the console log. -Motoko Playground is really deploying your canister to the network. As it serves for educational and testing purposes only, there are some limitations such as only 1 GB of data can be used and the canister will expier after 20 minutes. Using this playground is very convinient for new devs learning Motoko, as you don't have to pay for cycles fees for deployment, which you would need to do when deploying to the mainnet directly. +Motoko Playground is really deploying your canister to the network. As it serves for educational and testing purposes only, there are some limitations such as only 1 GB of data can be used and the canister will expire after 20 minutes. Using this playground is very convenient for new devs learning Motoko, as you don't have to pay for cycles fees for deployment, which you would need to do when deploying to the mainnet directly. ## Experiment with Candid UI @@ -80,7 +80,7 @@ If your project deployed successfully, you now should see a Candid UI on your ri As we mentioned above, Candid UI follows the interface defined in your Motoko code. You should see a form consisting of three functions get, inc and set. Function get and inc is not expecting any argument so you can click on Query or Call button and experiment with it. Function set is expecting a natural number (Nat) that you can pass in the input field. -You will notice that query functions have very fast execution usually in terms of miliseconds. On the other hand, functions calling an update usually takes about 2 seconds. +You will notice that query functions have very fast execution usually in terms of milliseconds. On the other hand, functions calling an update usually takes about 2 seconds. ## Update your code @@ -144,21 +144,22 @@ actor Counter { Viola, here is the whole working code in case you got lost. You can copy paste it to your playground. ## Save & share your code -You know might want to save your code so you can open it later. You can either save the code and keep in in a local file or click on the Save & Share button in the top-right corner. This will generate you an unique link that you can come back to later. +You know might want to save your code so you can open it later. You can either save the code and keep it in a local file or click on the Save & Share button in the top-right corner. This will generate you an unique link that you can come back to later. ## Useful resources and links -If you want to experiment with more exapmles of Motoko code. You can again click on the Open tutorial button in the top right corner. More examples can be found in [this GitHub repo](https://github.com/dfinity/examples/tree/master/motoko) which was made by Dfinity foundation. Lastly, there is a no-code Motoko editor [Blocks](https://blocks-editor.github.io/blocks/) which contains some examples too and the Build & Run button will deploy your code via Motoko Playground as well. +If you want to experiment with more examples of Motoko code. You can again click on the Open tutorial button in the top right corner. More examples can be found in [this GitHub repo](https://github.com/dfinity/examples/tree/master/motoko) which was made by Dfinity foundation. Lastly, there is a no-code Motoko editor [Blocks](https://blocks-editor.github.io/blocks/) which contains some examples too and the Build & Run button will deploy your code via Motoko Playground as well. Medium article a Yan Chen from Dfinity Foundation about Motoko Playground: https://medium.com/dfinity/introducing-the-motoko-playground-an-online-development-environment-for-the-internet-computer-efb4cd09ea8b -Community converstaion from Dfinity also with Yan Chen about Motoko Playground: +Community conversation from Dfinity also with Yan Chen about Motoko Playground: https://www.youtube.com/watch?v=A_RbxhN0BHI Link to a Motoko documentation page: https://smartcontracts.org/docs/language-guide/motoko.html - +#### The author +> This tutorial was written by Lukas Vozda. If you find some resources out of date, have some suggestions or just want to get in touch. You can find me on Twitter [@lukas_icp](https://mobile.twitter.com/lukas_icp) or Discord LukeVoz#0574. diff --git a/tutorials/null_variants_switch.md b/tutorials/null_variants_switch.md new file mode 100644 index 0000000..04ac4ee --- /dev/null +++ b/tutorials/null_variants_switch.md @@ -0,0 +1,208 @@ +--- +label: Null, variants and the switch statement +order: 400 +--- + +# Null, variants and the switch statement + +We have touched null, the optional type and variants softly in the [Understanding types](/tutorials/understanding_types/) tutorial. Now it's time to dive deeper and write some functions that utilize them together with the switch statement. + +## Optional type + +In the Understanding types tutorial, we have described optional type as a type that we don't know whether we expect a real value of specific type, let's say Text or a null type. + +To examine this, let's write a function called day_of_week that will take Nat as an argument and return the name of the week. We can use the days array from the previous tutorial. + +``` +let days : [Text] = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]; + +public query func day_of_week(n : Nat) async Text { + return days[n]; +}; +``` + +That was easy! Now what happens if you put a number higher than 6 as an argument? Even if Motoko Playground deploys your code, it doesn't always mean it is safe. You need to take care of this kind of error yourself to prevent your program from failing. + +To fix that, we can use the optional type ?Text, so our function knows that it can also return a null type. + +``` +public query func day_of_week(n : Nat) : async ?Text { + if (n <= 6){ + return ?days[n]; + } else { + return null; + }; +}; +``` +Notice that ?Text and Text type are different. If your function is supposed to return a ?Text type, you can't just return a Text. In such a case, you would see this error: + +``` +expression of type + Text +cannot produce expected type + ?Text +``` +That is why we put a question mark in front of the return type ?days[n]. Notice that in Candid UI you now can see the (opt "Tuesday") value returned instead of just text. + +## Switch statement + +Switch statement is a very popular concept in many programming languages. We could write this simple switch statement in a function as a warm up just that you get familiar with the Motoko syntax: + +``` +public query func day_of_the_week(n : Nat) : async Text { + switch(n){ + case(1) { + return "Monday"; + }; + case(2) { + return "Tuesday"; + }; + case(3) { + return "Wednesday"; + }; + case(4) { + return "Thursday"; + }; + case(5) { + return "Friday"; + }; + case(6) { + return "Saturday"; + }; + case(7) { + return "Sunday"; + }; + case(_) { + return "Not a valid index"; + }; + }; +}; +``` +Things get more interesting when we apply switch statement on the optional type. We can use the switch statement to let our program decide what should happen if the optional value is null and what should happen if it's not. + +Let's make a new function called Hello, that will take Text as an optional argument and return a message "Hello, unknown person" if the argument is null and "Hello, /name/" if it is a text. +``` +public query func hello(name : ?Text) : async Text { + switch(name){ + case(null){ + return "Hello, unknown person"; + }; + case(?value){ + return "Hello, " # value; + }; + }; +}; +``` +To explain this, we have a switch statement that takes the function argument called name, in the case that name is null, it will return unknown person text, if there is something other than null, we are expecting the Text type and we return in concatenation with the greeting. + +## Variants + +Things will get more interesting, when we put variants into play. Variants give us the opportunity to define a specific set of choices or situations. We already touched variants in the previous tutorial, when we defined a variant type Status that says whether a person is single, married or divorced. + +``` +public type Status = { + #single; + #married; + #divorced; +}; +``` +This is a very readable and technically effective way to give users of our program a limited choice. Also your program is much safer as it doesn't need to deal with array indexes, strings, typos and so on. + +Let's now bring back the code from the previous [Understanding types](/tutorials/understanding_types/) and write a function that will take a Person type as an argument and uses a switch statement on the status parameter of that person to return a text describing whether the person is single, married or divorce. + +``` +actor Person { + + public type Status = { + #single; + #married; + #divorced; + }; + + type Person = { + name : Text; + surname : Text; + age : Nat; + status : Status; + partner : ?Person; // optional attribute + }; + + + public query func get_status(p : Person) : async Text { + let name : Text = p.name; + if (name == ""){ + let name = "Person"; + }; + switch(p.status){ + case(#single){ + return name # " is single."; + }; + case(#married){ + return name # " is married." + }; + case(#divorced){ + return name # " is divorced." + }; + }; + }; +} +``` +Deploy this code in your Motoko Playground project and try to create a person called Alice, 30 years old that is single and call the get_status function. **Notice that Candid UI will let you choose only one of 3 options for the status attribute that we defined in our code.** You should see "Alice is single" message in the output. We have also added a check that if a person decides not to fill the name, we will substitute the name with "Person" string. + +To practice variants and the switch statement some more, let's bring up the days from the beginning of this text and try to create a variant representation of the object. +``` +// Before – days as Array +let days : [Text] = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]; + +// After – days as Variants +type Day = { + #Monday; + #Tuesday; + #Wednesday; + #Thursday; + #Friday; + #Saturday; + #Sunday; +} +``` +Not to confuse you, these two objects are very different. The variant way might be a better choice when writing your programs as it doesn't give the user options to insert bad inputs. Also your code might be more readable as #Monday is much easier to understand that day[0] where we might not be sure whether we start days from Monday or Sunday or whether the array indexes start from 1 or 0. + +Now let's make a function called is_weekend that will take the Day variant and returns a Text "weekend" when the input is Saturday or Sunday or "weekday" when it is one of the other days. +``` +actor Day { + + type Day = { + #Monday; + #Tuesday; + #Wednesday; + #Thursday; + #Friday; + #Saturday; + #Sunday; + }; + + public query func is_weekend(d : Day) : async Text { + switch d { + case (#Saturday or #Sunday) "weekend"; + case _ "weekday"; + }; + }; +} +``` +Try to run this code in your Motoko Playground workspace and try to experiment with it. You should immediately notice how this code works better: +1. In the Candid UI you are allowed to input only predefined choices that are straightforward and easy to understand +2. Your Motoko code is also much simpler, you don't need to take care of specific situations such as the user input number that exceeds the index of the array. + +## Useful links and resources + +Motoko Bootcamp video about variants by Paul Young +https://www.youtube.com/watch?v=GFenqSGhj7I& + +Motoko Documentation page talking about options and errors +https://smartcontracts.org/docs/current/developer-docs/build/languages/motoko/errors#working-with-optionresult + +Motoko Documentation page talking about variants +https://smartcontracts.org/docs/current/developer-docs/build/languages/motoko/overview#variants + +#### The author +> This tutorial was written by Lukas Vozda. If you find some resources out of date, have some suggestions or just want to get in touch. You can find me on Twitter [@lukas_icp](https://mobile.twitter.com/lukas_icp) or Discord LukeVoz#0574. \ No newline at end of file diff --git a/tutorials/primitive_types.md b/tutorials/primitive_types.md index 19b4bed..1701df9 100644 --- a/tutorials/primitive_types.md +++ b/tutorials/primitive_types.md @@ -11,9 +11,9 @@ Types play a significant role in Motoko language. Compared to modern general pur ## Types in Motoko -Generaly speaking, we can categorize types into two groups: primitive types non-primitive values. This text focuses on primitive types mainly so we will explain them in more detail in the next chapture. To give you the contrast, let's quickly go through the primitive vs non-primitive values. +Generally speaking, we can categorize types into two groups: primitive types and non-primitive values. This text focuses on primitive types mainly so we will explain them in more detail in the next chapter. To give you the contrast, let's quickly go through the primitive vs non-primitive values. -Primitive types in Motoko programming language are integers, natural numbers floating numbers, characters, texts and booleans. +Primitive types in the Motoko programming language are integers, natural numbers, floating numbers, characters, texts and booleans. Example of a primitive type, declaration of a variable that will have type of a natural number an is initialized with the value of 1: @@ -43,7 +43,7 @@ let b : Int = -10; let c : Int = 1_000_000; let d : Int = 0xf4; // 245 ``` -Let's make a little exercise now. Write a funciton called add, that will take two integers as arguments and return a sum of these two numbers. +Let's do a little exercise now. Write a function called add, that will take two integers as arguments and return a sum of these two numbers. ``` public query func add(a : Int, b : Int) : async Int { return a+b; @@ -54,7 +54,7 @@ That was quite easy, right? Try to experiment with it in the Candid UI. ### 2. Unbounded Natural numbers -Unbounded natural numbers can be assigned with positive numbers only. **Motoko program will trap if you try to assign a negative number.** +Unbounded natural numbers can be assigned with positive numbers only. **The Motoko program will trap if you try to assign a negative number.** ``` let a : Nat = 1; @@ -65,7 +65,7 @@ let c : Nat = 0xf4; //245 ### 3. Bounded numbers -Unbounded numbers variables can be assigned theoretically with numbers of any size. There are situations when you don't need this. For example if you want to declare a variable that will represent an age of a person. This variable should never exceed a number greater than 200. You might consider to use a bounded variable to be more memory effective. +Unbounded numbers variables can be assigned theoretically with numbers of any size. There are situations when you don't need this. For example if you want to declare a variable that will represent an age of a person. This variable should never exceed a number greater than 200. You might consider using a bounded variable to be more memory effective. In Motoko, these bounded numbers types are available: - Nat8 @@ -77,7 +77,7 @@ In Motoko, these bounded numbers types are available: - Int32 - Int64 -To explain the pattern, each type consist of Nat/Int and a number. This number represents quantity of bits that will be assigned in memory of the computer for this specific type. For example Nat8 variable can be only assigned with values ranging from 0 to 255. This comes from a formula 2^8 = 256 so the maximum number is 255 as we are starting from 0. +To explain the pattern, each type consists of Nat/Int and a number. This number represents the quantity of bits that will be assigned in memory of the computer for this specific type. For example Nat8 variable can be only assigned with values ranging from 0 to 255. This comes from a formula 2^8 = 256 so the maximum number is 255 as we are starting from 0. This means that you can declare a variable: ``` @@ -102,7 +102,7 @@ let c : Int8 = -130 // Not ok let d : Int8 = 250 // Not ok ``` -For Nat16 the maximum value that can be assigned is 65 535 (2^16) and for Int16 we have minimum –32768 and maximum –32767. The same logic applies for 32 and 64 size of a type. This gives you understanding of what value can be assigned to a variable of specific type and gives you freedom to decide which one to use when designing your own program. +For Nat16 the maximum value that can be assigned is 65 535 (2^16) and for Int16 we have minimum –32768 and maximum –32767. The same logic applies for 32 and 64 sizes of a type. This gives you understanding of what value can be assigned to a variable of specific type and gives you freedom to decide which one to use when designing your own program. Keep in mind, even if you have a value that would fit into a smaller size Nat/Int, you can only assign it if it has the same type. Something like this will **not** work in Motoko: ``` @@ -126,7 +126,7 @@ let d : Float = 3.141_592_653_589_793; ``` ### 5. Characters and text -For single characters, there is a type called Char and for strings of characters a Text type. **Be careful, char type must be assigned with single quotes and string types with double qoutes.** Lets try to declare your own variables: +For single characters, there is a type called Char and for strings of characters a Text type. **Be careful, char type must be assigned with single quotes and string types with double quotes.** Let's try to declare your own variables: ``` let a : Char = 'A'; // Ok @@ -135,7 +135,7 @@ let c : Text = "Hello, World!" // Ok let d : Text = 'Hello, World!' // Not ok ``` -Let's create a funciton concat, that will take two strings a and b as arguments and will return a concatenated text of them both with a single space between them. +Let's create a function concat, that will take two strings a and b as arguments and will return a concatenated text of them both with a single space between them. ``` public query func concat(a : Text, b : Text) : async Text { @@ -155,11 +155,14 @@ var b : Bool = 1; // Not Ok ``` ## Useful resources and links -Motoko documentaion page talking about types: +Motoko documentation page talking about types: https://smartcontracts.org/docs/languages/motoko-at-a-glance.html#_primitive_types Motoko basic concepts and terms: https://smartcontracts.org/docs/language-guide/basic-concepts.html#intro-values Motoko base library: -https://smartcontracts.org/docs/base-libraries/stdlib-intro.html \ No newline at end of file +https://smartcontracts.org/docs/base-libraries/stdlib-intro.html + +#### The author +> This tutorial was written by Lukas Vozda. If you find some resources out of date, have some suggestions or just want to get in touch. You can find me on Twitter [@lukas_icp](https://mobile.twitter.com/lukas_icp) or Discord LukeVoz#0574. \ No newline at end of file diff --git a/tutorials/serving_svg_over_http.md b/tutorials/serving_svg_over_http.md index df418d2..4b888fe 100644 --- a/tutorials/serving_svg_over_http.md +++ b/tutorials/serving_svg_over_http.md @@ -5,17 +5,17 @@ order: 300 # Serving simple SVG over HTTP -In this tutorial, things are going to get more excited. We are going to learn how to serve a SVG image over HTTP(s) directly from your canister. **Yes – canisters can serve web content over HTTP!** You are probably familiar with that as it is one of the main advantages of the Internet Computer over the other blockchains. But there is also a **http_request()** function that you can use in Motoko to define how exactly is your canister going to behave when contacted over HTTP protocol. +In this tutorial, things are going to get more exciting. We are going to learn how to serve a SVG image over HTTP(s) directly from your canister. **Yes – canisters can serve web content over HTTP!** You are probably familiar with that as it is one of the main advantages of the Internet Computer over the other blockchains. But there is also a **http_request()** function that you can use in Motoko to define how exactly is your canister going to behave when contacted over HTTP protocol. -This could be useful when you want to serve custom SVG images or define custom api endpoint over the URL. Serving a dynamic NFT file is what we're going to do now. +This could be useful when you want to serve custom SVG images or define a custom api endpoint over the URL. Serving a dynamic NFT file is what we're going to do now. -We are going to use [Motoko Playground](/tutorials/motoko_playground/) for deploying the code, this will give you a quick start without needing to setting up your local enviroment. +We are going to use [Motoko Playground](/tutorials/motoko_playground/) for deploying the code, this will give you a quick start without needing to set up your local environment. ## HTTP Requests We are going to start with this skeleton [template](https://github.com/motoko-bootcamp/bootcamp/blob/main/daily_challenges/day_6/GUIDE.MD#http-request) used for educational purposes during the Motoko Bootcamp event. -The template contains of two files, first the module file http.mo that contains types needed for HTTP communication from the canister. +The template contains two files, first the module file http.mo that contains types needed for HTTP communication from the canister. ``` module { @@ -56,7 +56,7 @@ module { }; ``` -If the code seems too exotic to you, please check this [video](https://www.youtube.com/watch?v=iYM2zFP3Zn0) that is explaining basics of HTTP protocol. The most key part for our case in this tutorial are the Request and Response types that play the main role in our simple HTTP communication. +If the code seems too exotic to you, please check this [video](https://www.youtube.com/watch?v=iYM2zFP3Zn0) that is explaining basics of the HTTP protocol. The most key part for our case in this tutorial are the Request and Response types that play the main role in our simple HTTP communication. The second file is your main.mo file that loads the module http and contains a simple function http_request that puts it all together. ``` @@ -81,11 +81,11 @@ https://wch4f-miaaa-aaaab-qadfa-cai.raw.ic0.app/ ``` If all goes fine and you open your URL in your browser you should see the Hello world message. -Notice that there is a "raw" keyword in the URL. Raw in the URL means we are serving non certified assets. This certification means that IC guarantees that you are getting right data. Certification can be expensive as it can cost a lot of assets so it only makes sense when serving very important data. You would need to implement a hash function for certification which is beyond the scope of this tutorial. +Notice that there is a "raw" keyword in the URL. Raw in the URL means we are serving non certified assets. This certification means that IC guarantees that you are getting right the data. Certification can be expensive as it can cost a lot of assets so it only makes sense when serving very important data. You would need to implement a hash function for certification which is beyond the scope of this tutorial. ## SVG image -Now, let's put some SVG image into works. SVGs are basically text files that carry vector information about some visual. You can easily find any SVG file online and use it or you can use the same as we. Create a text variable called svg that will contain data about your curve. +Now, let's put some SVG images into work. SVGs are basically text files that carry vector information about some visuals. You can easily find any SVG file online and use it or you can use the same as we. Create a text variable called svg that will contain data about your curve. ``` let svg : Text = "" # ""; @@ -98,7 +98,7 @@ body = Text.encodeUtf8(svg); ``` You could also adjust the header format of the return type if you want to be precise, but it will work with text/html as well. -Now if you deploy your code and try to refresh your canister page again in the browser, you should see the SVG image instead of Hello, World message. Beautifull infinity symbol. +Now if you deploy your code and try to refresh your canister page again in the browser, you should see the SVG image instead of the Hello, World message. Beautiful infinity symbol. ![SVG infinity symbol from the canister](../static/infinity.png) @@ -128,7 +128,7 @@ func color_svg(color : Text) : Text { ""; }; ``` -We are first looping through our colors array to find out if color is in it. If it is found we assign it as a result_color, if it is not inside we will use "black" as default. Notice that we are contatenating the SVG string with the color name. +We are first looping through our colors array to find out if color is in it. If it is found we assign it as a result_color, if it is not inside we will use "black" as default. Notice that we are concatenating the SVG string with the color name. Now let's change the http_request() function, so it gets the /path from the request and call the color_svg function, that will return the SVG code with the right color. @@ -156,7 +156,7 @@ https://wch4f-miaaa-aaaab-qadfa-cai.raw.ic0.app/green ![SVG rendered with specific color](../static/infinity_blue.png) -Try to put something else than registered color name in the URL, you should see the default black symbol. +Try to put something other than registered color name in the URL, you should see the default black symbol. Here is the full working code in the Motoko Playground in case you got lost somewhere. @@ -249,3 +249,6 @@ https://smartcontracts.org/docs/http-middleware.html#_enabling_canisters_to_resp Motoko example HTTP counter from Dfinity https://github.com/dfinity/examples/blob/master/motoko/http_counter/src/main.mo + +#### The author +> This tutorial was written by Lukas Vozda. If you find some resources out of date, have some suggestions or just want to get in touch. You can find me on Twitter [@lukas_icp](https://mobile.twitter.com/lukas_icp) or Discord LukeVoz#0574. \ No newline at end of file diff --git a/tutorials/understanding_types.md b/tutorials/understanding_types.md index d0a58fd..88d86ca 100644 --- a/tutorials/understanding_types.md +++ b/tutorials/understanding_types.md @@ -7,7 +7,7 @@ order: 500 Now that we learned about [primitive types](/tutorials/primitive_types/) in the previous lecture, let's move on to non-primitive types. In this tutorial, we are going to demonstrate how to declare them and build them with primitive types. -This is a natural process as non-primitive values can be **user-defined**, meaning that you can build objects or structures that combines multiple primitive types together. +This is a natural process as non-primitive values can be **user-defined**, meaning that you can build objects or structures that combine multiple primitive types together. ## Non-primitive types @@ -15,7 +15,7 @@ Let's quickly go through non-primitive types that are present in Motoko and how ### 1. Tuples -Tuples are simple objects that can contain multiple elements. These elements can be different types but you can't change number of elements after you declare it. You could create a simple tuple type to store name and surname for a person: +Tuples are simple objects that can contain multiple elements. These elements can be different types but you can't change the number of elements after you declare it. You could create a simple tuple type to store name and surname for a person: ``` type person = (Text, Text); @@ -46,23 +46,23 @@ let days : [Text] = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "S Now as we defined an immutable array with the type of text, Motoko playground will not let you include any other value than text, also it doesn't let you to update the value: ``` -days[0] := "Tuesday"; // Not ok - Expected mutable target assigment +days[0] := "Tuesday"; // Not ok - Expected mutable target assignment days := ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]; // Not ok - The same problem ``` -Let's make a first excersise. Try to write a function called getDay, that will take a Nat as an argument and returns a name of the corresponding day. +Let's do a first exersise. Try to write a function called getDay, that will take a Nat as an argument and returns a name of the corresponding day. ``` public query func getDay(n : Nat) : async Text { return days[n]; }; ``` -Here we go. That was simple. You can notice 2 things – function is very well defined with types in the input as well as in the output, if you try to put anything else then natural number it is not going to work. +Here we go. That was simple. You can notice 2 things – function is very well defined with types in the input as well as in the output, if you try to put anything else than a natural number it is not going to work. -Also, we are using the **query** keyword in the function declaration which will make the function execution much faster. It is a very good idea to use query function anytime we are not trying to update values in the backend of our app. +Also, we are using the **query** keyword in the function declaration which will make the function execution much faster. It is a very good idea to use a query function anytime we are not trying to update values in the backend of our app. #### 2.1 Mutable arrays -Declaration of a mutable array is very similar to immutable array. The key difference is using the var keyword. Let's try to declare an immutable array. +Declaration of a mutable array is very similar to an immutable array. The key difference is using the var keyword. Let's try to declare an immutable array. ``` var days : [Text] = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]; ``` @@ -73,9 +73,9 @@ days := ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Satu ``` You could also change the number of elements inside freely. However, you still can't change an element inside individually as only the whole array is mutable but the content inside is not: ``` -days[0] := "Tuesday"; // Not ok - expected mutable assigment target +days[0] := "Tuesday"; // Not ok - expected mutable assignment target ``` -If you woul like to make a totally mutable array, you need to use the **var** keyword also inside the declaration. Here is the full working code of a mutable array: +If you would like to make a totally mutable array, you need to use the **var** keyword also inside the declaration. Here is the full working code of a mutable array: ``` actor Days { var days : [var Text] = [var "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]; @@ -90,9 +90,9 @@ actor Days { }; ``` -If you run this code in you Motoko Playground and try tu run the function in the Candid UI, you should get "Sunday" for the index of 0. +If you run this code in your Motoko Playground and try to run the function in the Candid UI, you should get "Sunday" for the index of 0. -If you'd like to make immutable array mutable and vice versa, you need to use functions from the [Array section](https://smartcontracts.org/docs/current/references/motoko-ref/array) of the Motoko base library. Specifically it is thaw function to make array mutable and freeze function to make it immutable. +If you'd like to make the immutable array mutable and vice versa, you need to use functions from the [Array section](https://smartcontracts.org/docs/current/references/motoko-ref/array) of the Motoko base library. Specifically it is the thaw function to make the array mutable and the freeze function to make it immutable. ``` import Array "mo:base/Array"; @@ -108,7 +108,7 @@ actor Days { days_mutable[0] := "Hello"; }; ``` -Notice that after using the thaw function, we can assign another array to the variable or even assign a value to a specific index. This wouldn't be possible with immutable array. +Notice that after using the thaw function, we can assign another array to the variable or even assign a value to a specific index. This wouldn't be possible with the immutable array. ### 3. Records In Motoko, similarly to arrays, records objects can be mutable and immutable. Here is how you define an immutable object Person with attributes name, surname and age: @@ -141,7 +141,7 @@ let person1 : Person = { }; person1.age += 1; // Ok -person1.name := "Adam"; // Not ok, expected mutable assigment target +person1.name := "Adam"; // Not ok, expected mutable assignment target ``` ### 4. Variants When declaring an object above, we have to define all of the parameters so we have a person that has name AND surname AND age. Variants perform more like OR as we are expecting to get one of the values inside. Let's create a variant type Status that will have options single, married and divorced. @@ -201,7 +201,7 @@ private query func _getDay(n : Nat) : async Text { ``` #### Functions from Motoko base library -Like we presented in the array section, there is plenty of functions available in the [Motoko base library](https://smartcontracts.org/docs/current/references/motoko-ref/array). There is a section for each type. These functions are called from the imported module like we did with the thaw function: +Like we presented in the array section, there are plenty of functions available in the [Motoko base library](https://smartcontracts.org/docs/current/references/motoko-ref/array). There is a section for each type. These functions are called from the imported module like we did with the thaw function: ``` import Array "mo:base/Array"; @@ -211,18 +211,18 @@ var days_mutable = Array.thaw(days); ``` Notice that some functions require to define the data type in the <> brackets. -Go through the base library and check what is inside for each type. These funcitons are going to save your time when writing your programs. However, please respect that Motoko is still quite a fresh language and there is not yet as many functions available as for more mature languages. +Go through the base library and check what is inside for each type. These functions are going to save your time when writing your programs. However, please respect that Motoko is still quite a fresh language and there are not yet as many functions available as are with more mature languages. #### Anonymous functions -Anonymous functions are also known as lambdas. You define them for generic purpose in your program to complete small tasks. They are not ment to be part of the public interface. +Anonymous functions are also known as lambdas. You define them for generic purposes in your program to complete small tasks. They are not meant to be part of the public interface. ``` func add(x : Int, y : Int) : Int = x + y; ``` ### 6. Async values -When canisters or actors communicate with each other on the Internet Computer, it happens asynchronously. Messagess are processed one after another (in sequence) in an isolated way. +When canisters or actors communicate with each other on the Internet Computer, it happens asynchronously. Messages are processed one after another (in sequence) in an isolated way. Let's have a look at an example from the [documentation page](https://smartcontracts.org/docs/developers-guide/basic-syntax-rules.html#_actors_and_asynchronous_messaging): ``` @@ -234,7 +234,7 @@ finalStep(result1, result2) ### 7. Optional values -Optional values are used when we are expecting a specific type but it can be **null** as well. Optional values are defined with question mark and can be mostly found in the record type declaration or in functions. +Optional values are used when we are expecting a specific type but it can be **null** as well. Optional values are defined with question marks and can be mostly found in the record type declaration or in functions. Let's extend the Person model from above and add another parameter partner that will point to another person instance. Naturally, single persons will not have a partner so we must keep this parameter optional. ``` @@ -268,7 +268,7 @@ let person2 : Person = { var partner = ?person1; // in real situation, we should also update the status of person1 and person2 and set partner for person1 if the relationship is symmetrical }; ``` -Optional values play significant roles also in function definitions as funciton can as well expect or return a null value. There will be more detailed tutorial on that soon. +Optional values play significant roles also in function definitions as function can as well expect or return a null value. There will be a more detailed tutorial on that soon. ## Useful links and resources @@ -276,4 +276,7 @@ Motoko Bootcamp video about variables, functions and types by Albert Du https://www.youtube.com/watch?v=4YX41Nm7Wx8 Motoko Bootcamp video about variants by Paul Young -https://www.youtube.com/watch?v=GFenqSGhj7I& \ No newline at end of file +https://www.youtube.com/watch?v=GFenqSGhj7I& + +#### The author +> This tutorial was written by Lukas Vozda. If you find some resources out of date, have some suggestions or just want to get in touch. You can find me on Twitter [@lukas_icp](https://mobile.twitter.com/lukas_icp) or Discord LukeVoz#0574. \ No newline at end of file