---
tags: mstu5003, tinker, js
---
# TINKER - Javascript Part II
Hongyang Liu, Chenyou Wu, Kelly Huang, Biao Wang
<!--
- See repository: https://github.com/jmk2142/TodoMSTU5003
-->
- See demonstration: https://codepen.io/jmk2142/pen/oGxwPQ
- Tinker Markdown: https://hackmd.io/zJmA8GKJR5-Oe2Zy4r1wqw?both
<!--
For this week, the actual Markdown file is not available via Github Gists. I have included it within this week's Tinker repository along with the rest of the code. It is called `README.md`. You might want to `IMPORT` the markdown into hackmd.io to use that tool (recommended.)
To get access to this code, and the actual Markdown to play with, you can use Github to CLONE the repository using the Github GUI Client. You can get the idea of what repositories are in my Youtube Video:
## Github: How to clone my repository
You'll want to start with the video overview:
https://youtu.be/QOXhN90d9Mk?list=PLn93-yl6k7zUkSFNI8MQqmIVn017z8vKO
Since you want to copy MY repository, once you have the Github GUI Client installed - you can do so with one click of a button. Just click on the Clone or download option, then **Open in Desktop** and that will automatically open it up in the Git GUI. (See Below)

Keep in mind that since you are cloning my repository, you will only be able to commit changes to your local computer. You will not be able to _sync_ or _push_ changes to my Github repository - for obvious security reasons. (You wouldn't want just anyone to change YOUR code.)
If you would like to use Github for your work in progress, what you can do is **_FORK_** my repository first. (See _FORK_ button under account picture.) This will create a copy of this repository under your account name in Github. You can clone YOUR version of this to your local computer, then commit and push to your account to your heart's content. :smiley_cat:
---
-->
## Devtools
You will also want to watch this video on the `console` as we will be using it extensively to Tinker this week.
General Video on Console: https://youtu.be/GAqOggzH_GE?list=PLn93-yl6k7zUkSFNI8MQqmIVn017z8vKO
One of the most important tools we'll use is the `DEBUGGER`.
:::success
**Debugger Demonstration and Youtube Video**
<!--
REPO: https://github.com/jmk2142/Debugger
DEMO: https://jmk2142.github.io/Debugger
-->
CODE: https://codepen.io/jmk2142/pen/RwZErre
DEMO: https://cdpn.io/jmk2142/debug/RwZErre
YOUTUBE: https://youtu.be/RdF7j4no0Ts
:::
I recommend that at some point, you watch these demonstrations and use these tools to explore the Tinker.
:::info
In order to use `console.dir(object)` and see the object property/values, make sure your console setting is set to DEFAULT.

:::
## Tinker GIST: TODOS
> Good bye, "Hello World!"
`Hello World` is probably the most common introductory program around as it's so simple.
```javascript=
alert("Hello World!");
// Or alternatively...
console.log("Hello World!");
```
Unfortunately, it's not very useful. It doesn't really show the range of different programming concepts and to be quite frank, it's boring. Many beginners like us are interested in creating interactive applications and this requires a range of programming concepts.
1. HTML Elements
2. CSS
3. Variables
4. Operators
5. Functions
6. Control Statements
7. Events
8. Data Structures + Data (e.g. Arrays, Objects, Booleans, Numbers, Strings)
And you really cant get a sense of how these things work together with a 1 line program like `Hello World!`.
### Enter TODOS
Some clever programmer realized this and probably thought:
> What's the simplest, _real_ program I can build that will incorporate all the important aspects of a basic interactive program?
And the **TODOS** or **TODO LIST** program was born.
The beauty of TODOS is that it has everything in a pretty simple package. It can be solved using a variety of different strategies and can be created to be _simpler_ or _more sophsiticated_ depending on ones needs. It tends to now be the defacto standard for demonstrating a full interactive application.
Beginners AND advanced students alike build TODO apps as they learn new things. For example, our TODOS Tinker is designed to demonstrate the base JS concepts with a few _stretch_ challenges embedded in it. In my regular practice, when I have to learn a new library or framework, I will probably start by viewing an existing TODO app built with that specific library to see how that library works. Sort of like how you might compare a basic HTML page with a Bootstrap page (of the same content) to be able to compare and contrast the two. If you're interested, you can briefly look at [this page](http://todomvc.com/) which is an archive of the TODO application built in various different frameworks.
And this is where I am hoping to take this class, the culmination of all the things we've been working towards - to understanding this first, real, interactive program and hopefully - you can apply some of these concepts in your own works.
## Tinker Tasks
In this tinker, were going to:
1. Review prior concepts in this new context:
- Variables, functions, events, and arrays
2. Observe, analyze, and study new concepts:
- Control statements (E.g. `if`, `for`)
- Logical operators (E.g. `===`,`&&`, `||`,`<`,`<=`,`>`,`>=`, etc.)
- Objects (and `array` of `objects`)
3. Learn how to use more developer tools to study JS code
- Source (i.e. debugger)
- Console (i.e. `console.log`, `console.dir`)
We will continue to observe, analyze and think about this program in terms of:
> What is the STATE?
> What is the SEQUENCE?
> What is the CAUSALITY?
### Part 0: Conceptual Program Overview
Play with the program and observe how it reacts to user interactions.
- _Without_ talking about it in _programming terms_ explain the user observable steps/process of the following three interactions and how the program responds.
- Adding a todo
:::info
The user can input a task in the fillable space at the bottom. After the user is done typing, he/she can press the "add" button and the task will be added to the todo list.
```markdown=
WRITE the Task
Press the Add button
READ the Add Button
WRITE the task to the list
REPEAT everytime the Add button is pressed
```
:::
- Completing a todo
:::info
The user can click on the circle and it will complete the task on the todo list. The task will grey out and there will be a line that crosses the task out. The red remove button number will go up.
```markdown=
Press the circle bullet
READ the circle
WRITE the checkmark
READ the checkmark
WRITE the remove button number up by one for task done
REPEAT everytime the circle bullet is pressed
```
:::
- Removing a todo(s)
:::info
The user can remove an item in the todo list if they have a completed item. Once the user clicks on the red button, it will remove the task. However, if there are no completed tasks, the remove button will be grey.
```markdown=
Press the circle bullet
READ the circle
WRITE the checkmark
Complete the item
READ the checkmark
WRITE the remove button number up by one for task done
REPEAT everytime the circle bullet is pressed
Press the Remove button
READ the remove button
Remove task from list
REPEAT everytime the REMOVE button is pressed
IF there is a completed item
ELSE the remove button will not be active
```
:::
Be specific but imagine you are talking to a _non-programmer_. Think about this in terms of observable actions and reactions.
> User puts toast in the toaster. Sets the length of the timer. Pushes the lever to start the toaster. The toast pops out the toaster after the time is completed and goes "DING".
- For each of the interactions above write in _pseudocode_ the steps of how the program for that interaction unfold and results. Pseudocode is semi-formal structure to write out the gist of how your program would work. It uses some keywords but is largely language agnostic. There isn't a single correct way to do it but the following are some rules that can help.
- RULES:
- One statement per line
- CAPITALIZE initial _keywords_
- READ, WRITE, IF, ELSE, REPEAT, UNTIL, AND, OR
- Indent to show hierarchy and groups of operation
- Keep statements language independent
```markdown=
# Making toast for a big family
READ loaf of bread
READ slice of loaf
Put slice in toaster
WRITE time to toast
Start the toaster
Cook the toast
READ time
WRITE time by one second less
REPEAT UNTIL time is zero
Remove toast
REPEAT for all slices in loaf
# Serving toast
WRITE number of slices total
READ number of family members
READ toastiness
IF toast is burnt AND (total slices >= number of family members)
throw away toast
decrement slices total
ELSE
serve toast to family member
```
- Using your pseudocode, identify the function(s) in the actual JS code that relate to your pseudocode.
:::info
-Add a todo: The function to add a to-do is called `initializeToDos()`, `onEnterKey(event)`,`addTodoItem()` and `updateTodoItems()`
-Completing a todo: The function to complete a to-do is called `updateTodoItems()`, and`toggleComplete(event)` .
-Removing a todo: The function to remove a to-do is called `updateRemoveBtn`, `resetInput()`, `removeTodoItem(event)`, `updateTodoItems()`
:::
- Compare and contrast your pseudocode with the actual code.
- Explain what similarities and differences you noticed about the instructions / steps / processes in the code vs. your psuedocode.
:::info
-For adding to do items, the similarities between our psuedocode vs. the actual code is that it address how the button will return the new todo item onto the list when it is activated. However, the actual code is more complex. It gives a condtional function that talks about what to return when the button add is incorporated. It also defines what state the todo will be in (if it is completed or not). It also resets the input.
-For completing a todo function, the main similarities between our psuedocode and the actual code is that we both had an event trigger that completes the task. We also discussed how completing a task would update the remove button as well. However, the main difference our pseudocode vs the actual code is that it incorporates conditions. For example, the actual code talks about when the todo is added it will not be checked as completed. However, if someone triggers the checkmark it will change the code as completed. It also talks about when there are no tasks on the list then it reutnrs something that says "Nothing todo..."
-For the remove button, the similarities is that we talked about updating the todo list when the items are removed. Also the reset button will be disabled. We also made it into a conditional function.
:::
- Manipulate different parts of the code as you see fit. Why did you decide to manipulate that part? What happened? (More structured tinkering to follow.)
### Part 1: Variables, Functions, Arrays, and Events
- Explain the `data` variable.
- What does this data (and the data inside) represent conceptually?
- The data represents data that runs from certain function, it also indicates the true/false status for the result of each function
- If I wanted to access the second object, how would I do that in code?
- You can select the specfic array [0,1]
- If I wanted to access the `done` property of the first object, how would I do that?
- you can select the specfic array [0,1,2]
- Look through the rest of the code where this `data` array is used. When the user does things, am I manipulating the visual display and updating the data to reflect those changes? Or am I manipulating the data and updating the visual display to reflect those changes?
- Is this what you would have thought of?
- this is manipulating the data and updating the visual display
- What might be the significance of this program design decision?
- this means you can add many visusal display or modify them. Basically the data is like a control botton and you can change whatever the result is
- What do these lines in my code do?
```javascript=
var todosEl = document.querySelector('#todos');
var inputEl = document.querySelector('input');
var completedEl = document.querySelector('#counter');
```
- it changes HTML elements so it can reflect visusally and give users feedback
- Why declare these (see above) variables at the Global scope instead of in the functions?
- Or not at all... (E.g. `document.querySelector('#todos');`)
- Becasue it is in the entire webpage so the changes needed to be made globally, if in the function, you need to declare many times
- The `toggleComplete` function has an event parameter. Inside the function I access `event.currentTarget`. What is the difference between `event.currentTarget` and `event.target` which we used previously?
> The first function will happen based on other function's situation, the second one does not need to do so.
> CurrentTarget returns an error of undefined by the consel in the debug mode
- Hint 1: You can add a `console.log(event)` etc. inside that function to test the value of `event.target` and `event.currentTarget`.
- Hint 2: When testing, click on a todo to "complete" it. Click on two areas: the `li` as well as the `i` (font icon) element to see the differences.
- Hint 3: You can pass multiple arguments to `console.log()`. I often pass two: first a string label, second the thing I want to log. This will basically make the logs easier to identify if you use `console.log()` a lot.
```javascript=
console.log("SOME LABEL: ", dataToLog);
```
- In the `toggleComplete` function, there is a `event.currentTarget.id`. Is that `id` the same thing as the id property in my todo objects in the `data` array?
- No, this if is the function id which represents a complete function while the second id represents ceryain objects/element
- What does `!something` mean? (The exclamation mark) and how is it used in this code when we `toggleComplete`?
- it means any action and in the code, it uses to call a event or function
- Try calling some of the functions directly from the console. Some will work. Some won't.
- I tried call the `toggleComplete`but didnt work because it needs one function to be called first.
- I tried call`getTodoData` but did not work because the id cannot be defined and we need to put an ID value from the data array itself.
- Look at the function declarations in the JS panel.
- _Where_ is each function being called?
- Each function is being called by console.log()
- _When_ is each function, actually called?
- When there is somthing in the console.loh()
- What parameter(s) does that function have?
- If the parameter is defined as task, it can be either a event or item while if the parameter is defined as a variable, then we could define a function.
- What is the argument that is passed into the function when it is called?
- If we enter new value (input.El) into the function `addToDoItem`, a new task will show up in the to do list which in this case, the argument is the variable we have entered.
- Use the console (in Chrome devtools) to `console.log()` and `console.dir()` the following. What is the difference between `console.log` and `console.dir` and why is `console.dir` kind of more useful for looking at some kinds of data?
```javascript=
console.log(data);
console.log(todosEl);
console.dir(data);
console.dir(todosEl);
```
- When we output in JS using console.log(), we only see the raw result, which is the direct information. For console.dir(), it will shows all properties while Dir () shows a more complete structure and enough data information for us to read.
### Part 2: Objects and Arrays of Objects
- Manipulate the different _properties_ of the _objects_ inside the `data` array.
- Change all todo objects' `done` property to `true`.
- Change some of the task values.
- Run your code and explain how this changes what you see and why.
- In order to complete an item in the list.
- `console.dir()` the `data` array. Goto the console and _OPEN_ the `> Array(3)` text by clicking on it. Go deeper by opening up the nested objects. Analyze what you see. Then add a new todo through the user interface. `console.dir()` the `data` array again and investigate the insides.
- What is the difference between `data` before and after adding a new todo?
:::info


:::
- Run the following code:
```javascript=
data.push({
done: true,
task: "Goto Aikido Lessons",
id: getTimeStamp()
});
console.dir(data);
```
- What did the code above do?
- push() adds new items to the end of an array and changes the length of the array and returns the new length.
- Does our page reflect the changes made? Why or why not? Prove it.
- We didn't see any change in the page after running the `data.push` in the console.
- Does order matter in `Objects`?
- No, I don't think so.
- What is the difference between `Object` keys (E.g. `done`, `task`, `id`) and `Array` indices (E.g. `0`, `1`, `2`)?
-Arrays and objects are two ways of collecting data into a group.Arrays are especially useful when creating ordered collections where items in the collection can be accessed by their numerical position in the list.
- How are they similar?
- They are both mutable and used to store a collection of datas.
```javascript=
var myAry = [123, "Code", true];
var myObj = {
id: 123,
task: "Code",
done: true
}
console.log(myAry[1]);
console.log(myObj["task"]);
console.log(myObj.task);
```
- Compare the following in the console:
```javascript=
var element = document.querySelector('ul');
var author = { first: "Mark", last: "Twain" }
var example = {
theAnswer: 42,
student: true,
hobby: "Fishing",
sayHello: function(){
alert("Hello");
},
favNums: [1,2,3],
favAuthor: author
};
console.dir(example);
console.dir(el);
```
- What is an `element` really?
: Element is the most general base class from which all element objects.
- How does our `element` relate in terms of similarities and differences to `example`?
: Elements and examples are variances. Difference: example has attributes and values, while Element has none. Element functions can also replace or manipulate UL tags in HTML.
- If I wanted to call the function in the `example` object, how would I do that? Prove it.
: you can enter `example.sayHello();`
- Try the following code in the console. How does dot notation and bracket notation differ and why would you want to use one or the other?
- Dot notation is faster to write and clearer to read.Dot notation allows us to tell a instance of a class to use one of the methods inside that class.
```javascript=
var x = "username";
var user = {
username: "happyCat"
}
console.log(user.username);
console.log(user["username"]);
console.log(user[x]);
console.log(user.x);
```
- Identify various areas where the `.` object notation is used and explain the thing on the left side of the `.` and the thing on the right side of the `.`
- Javascript Object Notation is a text-based, human-readable data interchange format used for representing simple data structures and objects in Web browser-based code.
- E.g. `document.querySelector()` `document` is... `querySelector` is...
- The Document method querySelector() returns the first Element within the document that matches the specified selector, or group of selectors. If no matches are found, null is returned.
- HINT: There are MANY choices here.
- In two areas of my code, I use what is called a `filter` function. It's a function that arrays can use like `list.pop()`, `list.push()`.
- How does a filter function work?
- It is used to filter an array based on specified criteria.
- What is the significance of the function argument that is passed INTO the filter parameters?
- It is the real values passed to the function.
- With regard to the function that is passed into the filter as an argument, that function must `return` a boolean or evaluate to a boolean. What is the purpose of this?
- The filter() method returns an array containing elements of the parent array that match the set test.
E.g. `var x = list.filter(...); // What was returned to x?`
- CAUTION: NOT the function argument that goes into the filter.
- HINT: If you don't know, can you use console to "test" an idea out?
- Does filtering an array _change_ the original array?
- No, it does not change the original array.
### Part 3 Control Structures
- I use the `if` statement in several places in this code. Explain why a conditional is necessary in:
- `updateTodoItems`
- `updateRemoveButton`
- `onEnterKey`
- `validateTask`
- `addTodoItem`
- `getTodoData`
- HINT: You might want to `console.log` the boolean condition where you see the `if` statements to understand what condition we are evaluating.
```javascript=
if (booleanCondition) {
...
}
console.log(booleanCondition);
```
:::info
These functions all have different actions to be called due to the conditions varied. For example, `updateTodoItems`: check if the todo is done and update the values based on its conditions.
:::
- Comment on how the boolean condition works as there are many different examples.
:::info
The boolean condition may works from inside to outside. As we can see the `addTodoItem` function below.

When we input new todo items into the list.The function will verify if the input is not empty first. The `inputEl.value` here is equal to the result of `validateTask(task)`.
:::
- In this code, there are two kinds of `for` loops. The more traditional that looks like:
```javascript=
for (var i=0; i < list.length; i++) {
// CODE
}
```
and a `for of` loop that looks like:
```javascript=
for (item of list) {
// CODE
}
```
- How does a `for of` loop work?
:::info
Run through every item of the list.
:::
- What does the `item` represent? (It can be named anything: `x`, `item`, `thing` etc.)
:::info
In this case, it represent every single todo inside the todo list.
:::
- Why are `for of` loops convenient compared to the traditional `for`?
:::info
The code is shorter and clearer to run through all objects.
:::
- For what purpose(s) do I employ a `for` or `for of` loop in this program?
:::info
Track the id data of every todo in the list. It might be used into counting the items.
:::
- On Facebook or Pinterest, or Twitter, how does a loop through data relate to the display of content?
:::info
If we click heart icon(or other actions) of the displayed content. The value of the class can be updated. When the loop runs, the content can be seen in the saved items.
:::
### Part 3 Specific Routines
- Take a look at the `updateTodoItems`. Comment it out and replace it with this alternate, but functionally identical version. How does this function work and how do they relate / differ?
:::info
If we updated the function it would change the style of the list. It removes the bullet circle from the list. Instead of checking the circle to make complete an item on the list, the user would click on the box instead. However, the two functions still work the same way.
The new function checks if there is something in the todo list by using `data.length`first and then go into details of every single value of to do item. On the other hand, the old one is a loop template. It loops through the javascript everytime the button is press.
:::
```javscript=
function updateTodoItems() {
todosEl.innerHTML = "";
if (!data.length) {
var liElement = document.createElement('li');
liElement.innerText = "Nothing todo...";
todosEl.appendChild(liElement);
} else {
for (todo of data) {
var liElement = document.createElement('li');
var iElement = document.createElement('i');
liElement.id = todo.id;
liElement.onclick = toggleComplete;
if (todo.done) {
liElement.className = "complete";
iElement.className = "fa fa-check-circle-o";
} else {
iElement.className = "fa fa-circle-o";
}
liElement.appendChild(iElement);
liElement.innerText = todo.task;
todosEl.appendChild(liElement);
}
}
updateRemoveBtn();
}
```
- Take a look at the helper function `getTimeStamp`. This function will return a number, in milliseconds, the current time stamp since January 1, 1970.
- I call this when I create new todo items, what are some ideas as to why I might be using a timestamp for todo `ids`?
:::info
Not only can it record when someone adds a todo, but it also makes sure that every id is unique. IDs cannot be repeated or the computer will be confused. Therefore, using a timestamp would be useful when people are creating new items.
:::
- Take a look at the incomplete functions `markAllComplete` and `updateItemsLeft`.
- Can you complete these and add the functionality to this app?
:::info
`markAllComplete`:
```
function markAllComplete() {
for (var i=0; i<data.length; i++) {
if (data[i].done==false) {
data[i].done=true;
}
}
updateTodoItems();
}
```
After writing this function, we also added an onclick button into the html to call the function:
```
<button onclick="markAllComplete()">Mark All Complete</button>
```
`updateItemsLeft`:
```
function updateItemsLeft() {
let remainingEl= document.querySelector('#remaining')
var completedTodos = data.filter(function(todo){
return todo.done === true;
});
remainingEl.textContent= data.length-completedTodos.length;
updateTodoItems();
}
```
To make sure that the function prints whenever an item is completed, we added `updateItemsLeft()` into to `updateTodoItems()`. We also added the function to html by adding:
```
<div> You have <span id="remaining"></span> tasks left todo</div>
```
The updated codePen can be found here: https://codepen.io/kh3111/pen/dyVbWQW?editors=1011
:::
### Part 4 Debugging, Tools
Using the Chrome debugger (source) tool create breakpoints and watch the program execute line by line, part by part. Experience how this tool can give you insight into your program's _STATE_, _SEQUENCE_, _CAUSALITY_.
#### Chrome Debugger
- Set breakpoints at the following locations of your program
- `function initializeTodos`
- `function onEnterKey`
- `function addTodoItem`
- `function toggleComplete`
- Use the `Step over the next function call` feature to watch how the program pauses during the _SEQUENCE_ of its routines.
- Use the `Step into the next function call` feature to watch how the program pauses during the _SEQUENCE_ of its routines.
- What is the difference between `Step over` and `Step into` and how does this help you understand programs?
:::info
The step over executes the next function and pauses on the line after the function. It executes the whole function. On the other hand, step into excutes the next line of code (goes into the function) and then it pauses after it takes the action. Step into helps us understand programs by examinign each line of the code. Step over lets us examine the code by function so we can examine what happens when the function is called as a whole.
:::
- Use `Step into` until you've reached the line `var inputEl = document.querySelector('input');`. Should be highlighted in blue.
- Highlight the variable `todosEl` on the line before it and `right click` on it. Select _Evaluate in console_.
- What does the console print?
:::info
When we highlight `todosEl` it prints:
```
<ul id="todos">
<!--ITEMS HERE -->
</ul>
```
:::
- Highlight the variable `inputEl` on this highlighted blue line.
- Why does the console say `inputEl` is undefined?
:::info
`inputEl` is undefined because the code has not run into the class `input`. Therefore, it is not defined yet.
:::
- When you step through your code, does the blue line represent code that is about to be executed or code that has already executed? How do you know?
:::info
The blue line represents that the code has already executed. We know this because lines in `updateTodoItems()` adds a new code to the side of the function once it moves to the next step. The new code on the side matches the highlighted blue code.
:::
- What do you predict would be the console value of the variable `completedEl` on the next line if you _Evaluate to console_ at this point?
:::info
At this point, we think that the console value would be undefined as well because the code did not run through a code that has the id `counter` yet.
:::
- Watch how debugger annotates your source code with the updated _state_ of different variables as your program progresses.
- How does the debugger behave when you enter a loop in your program?
:::info
We took `updateTodoItems` function to observe a loop in debugger. And we saw the local scope is `todosHTML` which will update the HTML code when updating the todo items.

When running the `for(todo of data)`:
1. It first go to `data` and we can see there are 3 objects in an array.

2. Then it jump to `todo` to check the condition of the first object

Since the `todo.done` of object[0] is `false`. After going through `if(todo.done)` function. It jumped to the `else` condition to update the `todosHTML`. And then update the `li` by adding the `todo.task` inside the HTML.


3. The step 2 will run again as a loop when checking the object[1] and object[2] in this array. It directs to if/else function based on true/false value of the `todo.done`.
4. After the 3 times loop. The debugger jumped to later `if` function to see if anything inside the whole `todosHTML`.Finally trigger the `updateRemoveBtn`.
:::
- How does the debugger behave when you reach the a `filter` function call?
:::info
When we called the `filter` function.The degger jumped to `dato`, `filter` and `done` in sequence.It stays on `done` during 3 clicks and then went to the `completedEL` and `length`.

:::
- What does filter do and how does it work?
:::info
We guess the `filter` function will make sure the objects which meet the requirement go to further actions. In this case, the debugger stayed on `done` 3 times and jumped to next action when the 3rd time click. It is because only the 3rd object in this array meet the `filter` requeirement which is `todo.done === true`.
:::
### Part X: Putting all together
**Explain the program line by line with sufficient details, part by part.**
:::success
- Line by line
- Part by part
- Be sure to copy blocks of code into this markdown using code formatting/fences as references to your explanations.
- For repetitive code, you can explain how a line works then summarize how it would work for the rest.
:::
**Make it yours (group's)**
:::success
- Try to extend this program to do something cool, as a group, your own original idea(s).
- What is something that a Todo list or todo list user might benefit from?
:::