tag:blogger.com,1999:blog-35865425013678634302024-02-24T12:46:49.447-08:00C3HO's BlogC3HOhttp://www.blogger.com/profile/11262089715979645506noreply@blogger.comBlogger57125tag:blogger.com,1999:blog-3586542501367863430.post-45410438599417832742023-03-10T21:14:00.010-08:002023-03-12T10:17:50.778-07:00Contains Duplicate (Leetcode)I wrote a <a href="https://c3ho.blogspot.com/2020/04/data-structures-and-algorithms.html">post</a> roughly 2/3 years ago regarding data structures and algorithms. I thought I'd follow up with some questions I'd come across such as the famous <a href="https://leetcode.com/discuss/general-discussion/460599/blind-75-leetcode-questions" target="_blank">Blind 75 Leetcode Questions</a> and write down what my thought process to approaching the problem + run time and space complexity of the solution for the given question.<div><br /></div><div>I usually solve all my questions in Python. The first of which questions we will work on is <a href="https://leetcode.com/problems/contains-duplicate/description/" target="_blank">Contains Duplicate</a>:</div><div><code><br /></code></div><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiHT-epZOHlZH49O098va1LMHptuq2HwFlJwHHnCE8Zox3Az7dir530qEtBXOI1-kIYiMzkv54BWV1GdomrbX5ZrbBZqIpDnsRMP0hz2EqzrLjSdW_gFuq9m4jE-83E3mVV9mE0Yl3nG76DgdT0Hp9I2wx4ZC_J3IOQnt8nbos9NFjXQT-_jrtxJkw-0g/s1026/contains-duplicate.JPG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="780" data-original-width="1026" height="304" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiHT-epZOHlZH49O098va1LMHptuq2HwFlJwHHnCE8Zox3Az7dir530qEtBXOI1-kIYiMzkv54BWV1GdomrbX5ZrbBZqIpDnsRMP0hz2EqzrLjSdW_gFuq9m4jE-83E3mVV9mE0Yl3nG76DgdT0Hp9I2wx4ZC_J3IOQnt8nbos9NFjXQT-_jrtxJkw-0g/w400-h304/contains-duplicate.JPG" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div></div><div>Regardless of the approach, we'll have to check every number in "nums" so our run time will be O(length of nums) at a minimum. We'll also assume within nums there is only one possible duplicate.</div><div><br /></div><div>What's the most intuitive solution when we read through this? Most likely checking the current number n against all other numbers (n+1, n+2, n+3...).</div><div><br /></div><div>We'll use the first example: we're on the first element, 1. We'll have to check 1 against 2, 1 against 3, 1 against 1. Then we'll check 2 against 3, 2 against 1, we don't have to check 2 against the initial number because we have already made that comparison before.</div><div><br /></div><div>So we'll come up with something like the below:</div><div><br /></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiHcVfGyJneTZ4TVVc1uRdh1A4Z5HVKGraRTmJ4x24JiyCTCQXNPfVpy3xvRGAzCbet2aeys91Ay6FTaZ5vPIdxhCgXklqtzl7cUtbwrbz48gVUELkql5Lgd0vyN2s3B-PdgVkZhEVXIrpXyl9L-OonHTp3UaTQggZD7JlEU-O2wTWLXDsp_s-cBINVNw/s563/naieve-solution.JPG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="154" data-original-width="563" height="110" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiHcVfGyJneTZ4TVVc1uRdh1A4Z5HVKGraRTmJ4x24JiyCTCQXNPfVpy3xvRGAzCbet2aeys91Ay6FTaZ5vPIdxhCgXklqtzl7cUtbwrbz48gVUELkql5Lgd0vyN2s3B-PdgVkZhEVXIrpXyl9L-OonHTp3UaTQggZD7JlEU-O2wTWLXDsp_s-cBINVNw/w400-h110/naieve-solution.JPG" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: left;">Code is pretty simple, we use a for loop to iterate through nums and within that loop, we'll do another for loop to check elements of n+1 until we reach n + length(nums) - 1. This results in a O(N^2) solution because for each iteration of nums we're roughly going through it length(nums) - index times. The space complexity of this is O(1) since no extra structure is used to store anything.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">Is there anything we can do to reduce the number of times we have to iterate through the list? We can perhaps use a dictionary, a key/value store. We will use the number as the key and a value depending on how many times we have come across the number. Using Example 1:</div><div class="separator" style="clear: both; text-align: left;"><ol style="text-align: left;"><li>first iteration, the value of element at iteration 0 is 1, does the key 1 exist in the dictionary? No, we'll add it and set the value to 1</li><li>second iteration, the value of element at iteration 1 is 2, does the key 2 exist in the dictionary? No, we'll add it and set the value to 1</li></ol></div><div class="separator" style="clear: both; text-align: left;">and so on until we hit <b>iteration 4</b>, does the key 1 exist in the dictionary? <b>Yes</b>! we'll return <b>True</b> since the key exists and this means we have found a duplicate. In another scenario if we iterate through the whole list and no duplicates are found we'll return <b>False</b>.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEid03TSvVBX7Qdxv_sIr2SCzySaGHy0m-Z3ayOTv2pc2pCKcrV37xfNqqoYXvcLa_d37cOEholNseDZ66GNl8QOwci79cWbLvPx5hFLIxJjESG0eOh14yokW5D4BPvgDNK5-_FEutyeL7WQkzLzldAdBwV5DIqugxEzJ7HTqZgqCNOsYpuCrBph3qisUw/s536/dictionary.JPG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="201" data-original-width="536" height="150" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEid03TSvVBX7Qdxv_sIr2SCzySaGHy0m-Z3ayOTv2pc2pCKcrV37xfNqqoYXvcLa_d37cOEholNseDZ66GNl8QOwci79cWbLvPx5hFLIxJjESG0eOh14yokW5D4BPvgDNK5-_FEutyeL7WQkzLzldAdBwV5DIqugxEzJ7HTqZgqCNOsYpuCrBph3qisUw/w400-h150/dictionary.JPG" width="400" /></a></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">What is the complexity of the above code? O(N) time-complexity since we're only iterating through the array once (we have to create a dictionary from nums). O(N) space-complexity since we'll need to store values up to length nums in the variable my_dict.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">Is there a more concise way to do this? Actually there is, we can use a structure called Sets, a set in Python is similar to a list (array) except it does not allow duplicate values.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">Given a set cannot contain duplicate elements, we can compare it to the original list, if both are the same we return False, otherwise if they're not the same that must mean the nums must contain a duplicate. We arrive at something like below:</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhshAEUqoql892naAj2sANPD0vB6x5CY1NOndRAUTW52HLKINO2pR2Wi555MbXgFMtKboL7eCh23U8VM5D7k9a7p0PBpxIU6NO3_LcexoeqXQihbu9DuOepbmnE4L-O0xcxyfQcZvn0v-fD6ls7jAl7p1a3r5Vrjn2TS5mCL6rRsNYkYJCkMoGcOzYX6w/s532/solution.JPG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="91" data-original-width="532" height="69" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhshAEUqoql892naAj2sANPD0vB6x5CY1NOndRAUTW52HLKINO2pR2Wi555MbXgFMtKboL7eCh23U8VM5D7k9a7p0PBpxIU6NO3_LcexoeqXQihbu9DuOepbmnE4L-O0xcxyfQcZvn0v-fD6ls7jAl7p1a3r5Vrjn2TS5mCL6rRsNYkYJCkMoGcOzYX6w/w400-h69/solution.JPG" width="400" /></a></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">What we're doing in this case is comparing the length of nums against the length of nums turned into a set. If there are no duplicates both lengths should be equal and we'll get a value of 0 (False). Otherwise we'll get a value of 1 (True) since the length of the set nums cannot contain any duplicate values the relation between the two lengths would be something like this: <i>length of nums >= length of set(nums).</i></div><div class="separator" style="clear: both; text-align: left;"><i><br /></i></div><div class="separator" style="clear: both; text-align: left;">What is the complexity of the above code? Same as the dictionary solution, as we'll only iterate through nums once and we'll have to create a set of length nums (roughly) to store values up to length nums.</div></div>C3HOhttp://www.blogger.com/profile/11262089715979645506noreply@blogger.com0tag:blogger.com,1999:blog-3586542501367863430.post-44049522372401085982021-04-21T18:40:00.004-07:002021-04-21T18:45:48.452-07:00Documentation!<p> Recently I've been working with a fork of the <a href="https://github.com/edx/edx-platform" target="_blank">Open edx platform</a> (https://github.com/edx/edx-platform). My coworker and I were tasked with changing the built in player which accepts a mp4 link (youtube or s3), into one that allows users to upload a file to the platform that to be indexed into the user's s3 bucket and then update the player with the uploaded video. Sounds fun right? I assure you, it is not.</p><p><br /></p><p>I have no idea how big the code base is. It is massive and contrary to the implementation docs, the development documentation are hugely outdated. After struggling with the code, my coworker and I were able to complete the clients request and implemented the customized workflow. </p><p><br /></p><p>Then came the next request, analytics: Which users of the platform completed which modules? How long did a user spend watching a video? How many users enrolled in a specific course this week? We proposed two solutions, one was a hugely outdated, but easy to implement analytics providing a high-level overview of users of the platform. Unfortunately the library wasn't updated to support the newest release of Open edX platform we were using (Koa.2) and worst of all, it didn't provide the granularity the client was asking for. </p><p><br /></p><p>Great. Second solution: Use Open edX's own data analytics solution, this alternative is infamous for clogging up the Open edX's forum with requests to help debug the installation/implementation of it (including yours truly) and forcing many people to instead use the first solution. Just check out how amazing this document is teaching you to <a href="https://edx.readthedocs.io/projects/edx-installing-configuring-and-running/en/latest/insights/install_insights.html">implement </a>this, enjoy the diagram. </p><p><br /></p><p>I finally found some extremely old documentation written by the chief architect of edX. Check out the documentation for <a href="https://openedx.atlassian.net/wiki/spaces/OpenOPS/pages/43385371/edX+Analytics+Installation">it</a>. This was created in 2015 and has been barely updated since, one of the steps even tells you to use a Hadoop 2.3 when the repo has already migrated to use Hadoop 2.7. Out of all the instructions, I can personally tell you I had an issue with literally every step that required me to hack at it, there is no FAQ and the slack channel + forums are so quiet, you'd be ecstatic to even get a response. If it is one thing OSD has taught me, it was to research and adapt and maybe there might be a light at the end of it all. Here's a list of topics I had to research about to almost finally get this working:</p><p></p><ul style="text-align: left;"><li>Hadoop</li><li>Hive</li><li>Ansible</li><li>Django</li><li>Tutor Open edX</li><li>Virtual env</li><li>AWS</li><li>MySQL</li><li>Oauth2</li><li>Luigi</li></ul><div>All this because, documentation is not up to date. People who work on Telescope, be thankful the slack channel is extremely active and the documentation is up to date.</div><p></p>C3HOhttp://www.blogger.com/profile/11262089715979645506noreply@blogger.com0tag:blogger.com,1999:blog-3586542501367863430.post-15485740546426946532020-10-08T22:56:00.001-07:002020-10-08T22:56:25.230-07:00Fun with Docker<p>I'm starting a new project for work soon. Instead of developing from the ground up, we'll be using an existing open-source solution and customizing it to suit the project's need. I figured this is going to be more devops and less coding as we'll mostly be doing modifications on the existing code and decided to play around with Docker since I don't have much experience writing Dockerfiles or docker-compose files.</p><p>I took one of my side projects I created with a node.js backend and react frontend and decided to "dockerize" it. I decided to start with the front-end for now since the backend requires Redis.</p><blockquote><div style="background-color: #1e1e1e; color: #d4d4d4; font-family: Consolas, "Courier New", monospace; font-size: 14px; line-height: 19px; white-space: pre;"><div><span style="color: #6a9955;"># Use the official image as a parent image</span></div><div><span style="color: #c586c0;">FROM</span> <span style="color: #4ec9b0;">node</span>:lts-alpine</div><br /><div><span style="color: #6a9955;"># Set the working directory.</span></div><div><span style="color: #c586c0;">WORKDIR</span> <span style="color: #ce9178;">"/adventure-capitalist"</span></div><br /><div><span style="color: #6a9955;">#Copy the file from host to current location</span></div><div><span style="color: #c586c0;">COPY</span> <span style="color: #9cdcfe;">package.json</span> <span style="color: #9cdcfe;">.</span></div><br /><div><span style="color: #6a9955;"># Run the command inside your iamge filesyste.</span></div><div><span style="color: #c586c0;">RUN</span> <span style="color: #9cdcfe;">npm</span> <span style="color: #9cdcfe;">install</span></div><br /><div><span style="color: #6a9955;"># copy the rest of app's source code from host to image files</span></div><div><span style="color: #c586c0;">COPY</span> <span style="color: #9cdcfe;">.</span> <span style="color: #9cdcfe;">.</span></div><br /><div><span style="color: #6a9955;"># Add the metadata to the image to describe which port the container is listening to </span></div><div><span style="color: #c586c0;">EXPOSE</span> <span style="color: #9cdcfe;">3000</span></div><br /><div><span style="color: #6a9955;"># RUN cd /adventure-capitalist/src/backend/data && node app.js</span></div><br /><div><span style="color: #6a9955;"># Run the specified command within the container.</span></div><div><span style="color: #c586c0;">CMD</span> <span style="color: #9cdcfe;">[</span> <span style="color: #ce9178;">"npm"</span><span style="color: #9cdcfe;">,</span> <span style="color: #ce9178;">"start"</span> <span style="color: #9cdcfe;">]</span></div></div></blockquote><p>After writing this file, I built it using docker build --tag adventure-capitalist:1.0 .</p><p>Docker builds the image and after building it, I run it in a container using: docker run -p 8000:3000 --name ac adventure-capitalist:1.0 </p><p><br /></p><p>This should do it right? I'll go to localhost:8000 and should see my front-end right? NOPE I logged the container with the command docker logs ac, and didn't see any issues. Decided to ask <a href="https://github.com/manekenpix">@manekenpix</a> for a second pair of eyes + google "dockerizing a react app" and found out why it wasn't <a href="https://mherman.org/blog/dockerizing-a-react-app/">working </a>. I needed to add the -it flag otherwise it won't work:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgNzK56BbbE02KRY8bVZvx0vyfSbLDzxTl5a3wPjYDB9gOX2VGb7gq_wFdX02RdruVYqp4EDmaSGRQkTLN2O6j5mxqCGUCj-1krc2fCglk7LwE0uLT3XlQJRSwQtgEzdyYnGWTAJpyp7tet/s746/docker.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="82" data-original-width="746" height="70" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgNzK56BbbE02KRY8bVZvx0vyfSbLDzxTl5a3wPjYDB9gOX2VGb7gq_wFdX02RdruVYqp4EDmaSGRQkTLN2O6j5mxqCGUCj-1krc2fCglk7LwE0uLT3XlQJRSwQtgEzdyYnGWTAJpyp7tet/w640-h70/docker.PNG" width="640" /></a></div><br /><p>So the full command I had to use was: docker run -it -p 8000:3000 --name ac adventure-capitalist:1.0</p><p><br /></p><p>References:</p><p>https://mherman.org/blog/dockerizing-a-react-app/</p>C3HOhttp://www.blogger.com/profile/11262089715979645506noreply@blogger.com1tag:blogger.com,1999:blog-3586542501367863430.post-19217381597569879622020-09-25T19:03:00.003-07:002020-09-25T19:03:54.056-07:00Padding your Github statsThese past few days I got to have some fun reviewing github repos in @<a href="https://github.com/humphd">humphd's </a>OSD600 class (I made sure I didn't take all the issues). I primarily focused on Python and Javascript/Node.js repos as I'm most comfortable with them. It was actually really fun as I got to suggest some things they did not think about or things I learned while attending OSD600/OSD700 from a year ago. I must say though, these students are way better than when I first started OSD600... Extremely looking forward to their contributions for Hacktoberfest and even more so if they decide to contribute to <a href="https://telescope.cdot.systems">Telescope</a>. C3HOhttp://www.blogger.com/profile/11262089715979645506noreply@blogger.com0tag:blogger.com,1999:blog-3586542501367863430.post-28943158863667451252020-09-21T18:08:00.005-07:002020-09-21T23:30:29.747-07:00Pre-September<p> Over the summer I was employed as a research assistant for Seneca on an NLP project. Now that we're wrapping up and with October coming around I decided to play around with Golang and look for some projects to work on aside from <strike>slaving away</strike> contributing to Telescope. My previous professor linked the repo for the backend of the Canadian COVID app and I found the perfect issue. If successful, I'll have contributed to something used across Canada...?</p><p><br /></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhxIGPfRbNuST1ZLU48JOtDtcUDINoEwtqQtTYui27RCr7Z_J4x-UXn-Gyr7xcfJHsq_WBfNE4QekYul7pfFXcZHXS-yPlp7pqcJUgCCf0pUuXzhvemHZhcImOys0ua6N4TXJs7Dhw1TNR3/s1688/September.PNG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="820" data-original-width="1688" height="310" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhxIGPfRbNuST1ZLU48JOtDtcUDINoEwtqQtTYui27RCr7Z_J4x-UXn-Gyr7xcfJHsq_WBfNE4QekYul7pfFXcZHXS-yPlp7pqcJUgCCf0pUuXzhvemHZhcImOys0ua6N4TXJs7Dhw1TNR3/w640-h310/September.PNG" width="640" /></a></div><br /><p><br /></p>C3HOhttp://www.blogger.com/profile/11262089715979645506noreply@blogger.com0tag:blogger.com,1999:blog-3586542501367863430.post-6044977870842595852020-06-05T16:43:00.001-07:002020-06-05T16:45:35.506-07:00Attempt at Creating a Clone of Adventure CapitalistAfter about 3 weeks working on this project, I'm kind of done. Built with React/Node/Redis/SocketIO I learned a lot. The reason I say I'm kind of finished is because unless I overhaul the whole backend of the code, I don't think I can get it working 100%. ... I know it looks awful haha.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi7jaWlkZLc1P1CXuvgl7rJXmFMH9G-e-4bX439z86_ZlYSoXtUxPNZ8WmypaGAFEbxs1bBiSi3Lf-zYhJq7ytQpKsVUioCW1jI_RFrO3hqPHhoFyh3X93uFEsx11fY4emeLmtiGvMJnuY6/s1600/AC.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="300" data-original-width="585" height="328" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi7jaWlkZLc1P1CXuvgl7rJXmFMH9G-e-4bX439z86_ZlYSoXtUxPNZ8WmypaGAFEbxs1bBiSi3Lf-zYhJq7ytQpKsVUioCW1jI_RFrO3hqPHhoFyh3X93uFEsx11fY4emeLmtiGvMJnuY6/s640/AC.PNG" width="640" /></a></div>
<br />
The project was fun and challenging, there weren't any guidelines on how the project should be built aside from it being written in Javascript/Typescript. I initially tried using Typescript, but it gave me headaches with the difference in import exporting. This is something I'll probably need to learn more about.<br />
<br />
You can check out a version of a working game <a href="http://en.gameslol.net/adventure-capitalist-1086.html">here </a>(not mine). The hardest part about creating this clone is regarding hiring a manager. Hiring a manager takes care of clicking for one of these shops. The number on the right shows the "cooldown" of the button before it can be pressed again. A manager will auto this process so whenever the shop is off cooldown, it should be clicked, the timer is actually reflects how much cooldown time is left, there should also be a progress bar providing a visual representation.<br />
<br />
There were 2 issues to think about:<br />
<br />
<ol>
<li>The initial max cooldown of the Lemonade shop is 500ms, when a player purchases a certain amount of the shop, the max cooldown is actually halved or and it becomes exponential with each threshold reached. So potentially this shop could be firing a request every 7.8ms (500 / 64), what tool should I use for this?</li>
<li>How should I manage the auto clicking by managers?</li>
<li>The managed shops should also be running even if the window isn't open, players should be informed of how much cash they have earned while the window was closed</li>
</ol>
<div>
I looked around a bit and decided to use websockets, specifically Socket.IO. I thought using the traditional HTTP/GET request would destroy the backend since there could be a ton of requests being sent.</div>
<div>
<br /></div>
<div>
The second issue I kept thinking of was how to create the auto function for managing a shop + keeping track of how much time was left AND having all this be reflected on the front-end. After thinking about this for a few days and getting nowhere, I reached out to <a href="https://github.com/humphd">@humphd</a> who suggested using the TTL(time to live) + Pub/Sub functionalities of Redis. This was pretty cool as it had me researching about keyspace notifications for Redis. That's all for now... I may blog more about this later.</div>
C3HOhttp://www.blogger.com/profile/11262089715979645506noreply@blogger.com1tag:blogger.com,1999:blog-3586542501367863430.post-28243431561271775892020-05-06T11:09:00.003-07:002020-05-08T00:05:49.395-07:00Typescript + LintersTaking a small break from Telescope until the summer semester resumes. I've started collaborating with a elementary school friend on a project to build a clone of the game Adventure Capitalist. After working with Javascript for so long, I decided to try doing this in Typescript. It went pretty well up until I had the following line of code:<br />
<br />
<div style="text-align: center;">
<code style="background-color: #d0e0e3;">const index = this.shops.findIndex((shop: Shop) => shop.name == shopName);</code></div>
<div style="text-align: center;">
<br /></div>
<div style="text-align: left;">
When I was trying to compile my code, I kept getting the following error<br />
<br />
<div style="text-align: center;">
<code style="background-color: #d0e0e3;">Property 'findIndex' does not exist on type 'Shop[]'</code> </div>
<br />
Pretty sure this should work as shops is an array of type Shop. As a developer usually does when they run into issues, I started googling the problem and checking Stack Overflow. It recommended I change my tsconfig.json "target" to es2015 and the findIndex() is an es6 function and add es6 to "lib". I did all that and tried compiling, still no good. I reached out to my frequent collaborator from Telescope <a href="https://github.com/manekenpix">@manekenpix</a> and he suggested I just try running the code. It works?</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
Turns out it was a linter issue, although it still compiled properly. Upon further research 2 hours later, I realized I was using the cli command wrong, or at least the way I was using it was going to cause errors. I was compiling my .ts to .js by using the command <code>tsc index.ts</code> instead of <code>tsc</code>, when a specific file name is used, it will disregard the tsconfig.json file settings and just try to compile your Typescript to Javascript. So I tried running 'tsc', it worked! No errors and it was outputting all the compiled .js files inside my /build folder (ignored in .gitignore) I specified in my tsconfig.json file.</div>
C3HOhttp://www.blogger.com/profile/11262089715979645506noreply@blogger.com0tag:blogger.com,1999:blog-3586542501367863430.post-46417587502031202882020-04-30T19:20:00.000-07:002020-05-01T09:05:58.977-07:00Data Structures and AlgorithmsI'm finally done all my courses and since the job market isn't that great right now, I have taken a different approach. Instead of working personal projects or contributing to open source, I've decided to brush up on data structures and algorithms for a bit.<br />
<br />
One thing I found lacking for Seneca's Computer Science related programs was the science portion of Computer Science, maybe it was because I was enrolled in CPA and not their BSD program.<br />
<br />
For CPA the only course that deals with data structures and algorithms, DSA555 is offered as a professional option. After taking the course I noticed why, as a pretty smart person in the class said "<i>If this was a mandatory course, a lot of people would be dropping out of the program, it was pretty hard</i>". I still wish there was another similar course or two offered so we could learn more about analyzing the run times of more complex functions and graphs.<br />
<br />
I took DSA555 last winter and have more or less forgot how to implement or how most of the things I learned in the class work: linked lists, trees, different types of searches + sorts. So now as I am typing this blog, I am solving and looking at problems on <a href="https://leetcode.com/problemset/all/">leetcode</a>.<br />
<br />
A friend of mine currently works for Tesla and is looking for a new job. Most of the places he's been interviewing at for a full stack position have also asked him data structure and algorithm questions on top of questions involving joining two tables in SQL or how to mock a request for testing.<br />
<br />
I think this is fair as it makes a developer conscious of the code they write and makes it easier to recognize patterns and respond accordingly.<br />
<br />
For example, say I have an array of sorted numbers and I have to find if a given number exists:<br />
<br />
I could loop through the array and check each element<br />
Or<br />
I could check if my given number is the middle element in the array. Depending on if it is bigger or smaller I can use the upper or lower half of the array and repeat the same steps, until the number is found or not found.<br />
<br />
The second option sounds tedious, but depending on the size of the array, it may actually turn out to be faster than the initial option.<br />
<br />
It also allows developers to think about the function they are writing performance-wise. Is it a O(n) solution? O(n^2) or worse O(n^3)? If it is the latter two, can I improve the run time of it? For personal projects this may not matter as much, but if you are working on software or systems that will be used by millions of people or contains a ton of data, these little things start to add up!C3HOhttp://www.blogger.com/profile/11262089715979645506noreply@blogger.com0tag:blogger.com,1999:blog-3586542501367863430.post-22506457134237053932020-04-23T13:50:00.004-07:002020-04-26T09:19:24.198-07:00OSD700 Post 1.0When our prof doesn't have to review our feeble PRs, he's on a mission.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiLxqSxmBEMZBLmBxmvrkywuKn9sfW6O7tWS6czJfwB9NwNfPJot-WqVnH6JT3b5azqbjw678ph2d0ywuCGyqho1gDCon_2gXxRCOD1e3fIvC5tVw9ave5DgagYkLWuqyZ6o5R_3Yt3_W4Q/s1600/Prof+going+off.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="403" data-original-width="785" height="205" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiLxqSxmBEMZBLmBxmvrkywuKn9sfW6O7tWS6czJfwB9NwNfPJot-WqVnH6JT3b5azqbjw678ph2d0ywuCGyqho1gDCon_2gXxRCOD1e3fIvC5tVw9ave5DgagYkLWuqyZ6o5R_3Yt3_W4Q/s400/Prof+going+off.PNG" width="400" /></a></div>
<br />C3HOhttp://www.blogger.com/profile/11262089715979645506noreply@blogger.com0tag:blogger.com,1999:blog-3586542501367863430.post-32022928641543034272020-04-14T09:37:00.000-07:002020-04-14T10:01:25.635-07:00OSD700 Release 1.0We've finally hit 1.0 for Telescope. What a journey.<br />
<br />
I finished up the issues I was still working on from 0.9 and worked on a few more:<br />
<br />
<b>PR #<a href="https://github.com/Seneca-CDOT/telescope/pull/919">919</a>: Feed Type Should Support Delete, Modify (Delete + Create)</b><br />
Overall, I did not expect the whole "add feed" feature to be this big. We had 4-5 people working on this. 3 on the back-end, 1 on the front-end and our prof helping out on both ends. Happy to say we have it working. My PR was working as expected, but it wasn't doing great performance-wise due to multiple Promise.all() and awaits, with help from our prof, we were able to get rid of a lot of them. I learned if you want to trigger our prof, wrap a Promise.all() within another Promise.all().<br />
<br />
<b>PR <a href="https://github.com/Seneca-CDOT/telescope/pull/931">#931</a>: Add a Way to Receive Updates when New Posts are Available</b><br />
PR is done, I'm beginning to regret mentioning I wanted to work with React.<br />
<br />
<b>PR #<a href="https://github.com/Seneca-CDOT/telescope/pull/937">937</a>: Finish Search Feature</b><br />
This PR was possible because I learned a few things from reviewing a PR by <a href="https://github.com/Silvyre">@Silvyre</a>. Seriously, if you want to be a better developer, look into doing code reviews, you'll widen your perspective.<br />
<br />
<b>PR <a href="https://github.com/Seneca-CDOT/telescope/pull/989">#989</a>: Teach tools/autodeployment/server.js about a release to master</b><br />
Our staging box auto deploys itself whenever there is a change in the master branch. We wanted to change it up for production so it will only auto deploy itself whenever there is a tagged release. One of the things I have neglected during my years at Seneca is scripting or just using linux commands. I've started on the path of slowly redeeming myself with this PR.<br />
<br />
<b>PR <a href="https://github.com/Seneca-CDOT/telescope/pull/993">#993</a>: Remove "feed added successfully" after some period</b><br />
Front end change, this uses the SnackBar component implemented in #931 to display a toast informing the user if their feed has been added<br />
<br />
<b>Wrapping Up</b><br />
I started this journey in OSD600 where our first assignment was to create a notepad app (I did the bare minimum) and trying to enhance or debug other students' implementation of it on Github, I even remember I had issues writing the notepad app. Back then, I could not imagine contributing to building a project from the ground up (Telescope)... I could barely fix an issue a week to keep up with Hacktoberfest during that time.<br />
<br />
Now that OSD700 is about to wrap-up, I've noticed how much my attitude and skill changed:<br />
<br />
We have to implement a new tool for Telescope? No problem, time for some experimenting.<br />
There's a new component that needs to be built? Front-end huh... but I'm game.<br />
New issues dealing with a tool that has been implemented but I haven't used yet? Pick me!<br />
Nginx issues? Oh god. where's <a href="https://github.com/manekenpix">@manekenpix</a> to hold my hand through this?<br />
<br />
Overall this course and project was extremely fun. We worked like a team you would find in a workplace, we had dev-ops, back-end devs, front-end devs. We got to explore and experiment with different tools we normally wouldn't get a chance to work with all at once: ElasticSearch, Redis, Kubernetes(lol), Gatsby, GraphQL, Nginx, Docker, Jest, SSO. It did not matter if we were not able to implement them in the project. Just the opportunity to experiment with it has improved my knowledge with it, which I am very grateful for.<br />
<br />
I think why these open source classes were so fun was because all the things we were doing were open ended. These were real world issues, there is no answer guide for us to take a look at when we were stuck. Sometimes even our prof was reading API or tool docs to understand and help us out when we were stuck on our PRs.<br />
<br />
Lastly, I do not think this would have been possible without our prof and lead <a href="https://github.com/humphd">@humphd</a>, he's a monster. Deployment, back-end, front-end, authentication, system + architecture design, he is knowledgeable in it all. He can and will request changes on your PR which you spent hours working on. As of writing, we have ~468 closed PRs, of which he has probably reviewed close to that same number of them. Thank you for guiding us.<br />
<br />
In no particular order it was a blast working with you guys. Thank you <a href="https://github.com/manekenpix">@manekenpix</a>, <a href="https://github.com/cindyledev">@cindyledev</a>, <a href="https://github.com/Silvyre">@Silvyre</a>, <a href="https://github.com/agarcia-caicedo">@agarcia-caicedo</a>, <a href="https://github.com/grommers00">@grommers00</a>, <a href="https://github.com/miggs125">@miggs125</a>, <a href="https://github.com/lozinska">@lozinska</a>, <a href="https://github.com/yatsenko-julia">@yatsenko-julia</a><br />
<br />
Other students at Seneca, if you have a chance to take OSD600/OSD700. Please do. This is probably the highlight of your program.C3HOhttp://www.blogger.com/profile/11262089715979645506noreply@blogger.com0tag:blogger.com,1999:blog-3586542501367863430.post-34353557408788346562020-04-06T15:02:00.004-07:002020-04-06T22:45:52.651-07:00OSD700 Release 0.9This post serves two purposes. I was told to blog and this is to test PR #<a href="https://github.com/Seneca-CDOT/telescope/pull/931">931</a> for <a href="https://github.com/Seneca-CDOT/telescope">Telescope</a>.<br />
<br />
I'd like to give a big shout out to frequent collaborator and contributor @<a href="https://github.com/manekenpix">manekenpix </a>for always helping me out. Be it reviews, collaborating on issues or help testing. He has made contributing to Telescope a lot easier than it should've been.<br />
<br />
Here's the PR list I worked on for 0.9 and will continue to work on for 1.0<br />
<br />
<b>PR #<a href="https://github.com/Seneca-CDOT/telescope/pull/937">937</a>: Finish Search Feature</b><br />
This is a PR in progress<br />
<br />
The search feature we have right <a href="https://dev.telescope.cdot.systems/search">now</a> works, but it isn't polished. We currently only support one search filter, authors. Searching takes a while, but there's no indication of whether the results are loading or not. I added a spinner to fix this. I have to also have to add an endpoint we have to search through Post content and return post results based on the data we get back.<br />
<br />
<b>PR #<a href="https://github.com/Seneca-CDOT/telescope/pull/931">931</a>: Add a Way to Receive Updates When New Posts are Available</b><br />
This is a PR in progress<br />
<br />
This is pretty close to finishing. I added a timer that will fire off a fetch request to get the number of posts in Telescope. If there is a change, a non-intrusive alert should pop up for 6 seconds letting the user know there are new posts available.<br />
<br />
This PR also led @<a href="https://github.com/manekenpix">manekenpix </a>and I on a 3 hour wild goose chase to track down why we weren't able to get one of the custom headers we had for Telescope. This resulted in the following PR #<a href="https://github.com/Seneca-CDOT/telescope/pull/935">934</a>, that's right, if you check the PR it took us 3 hours to add/change 4 lines. It was fun, but so so frustrating.<br />
<br />
<b>PR #<a href="https://github.com/Seneca-CDOT/telescope/pull/919">919</a>: Feed Type Should Support Delete, Modify (Delete + Create)</b><br />
When I get frustrated with the two PRs above, I like to work on this because the backend doesn't lie. I don't have to deal with stuff rendering or not rendering on my screen or go reading up on new hooks. I pray if I ever have to do front-end development in the workplace I'll only have to use UseEffect and UseState hooks.<br />
<br />
Anyways, this PR provides the functionality of removing a Feed and having it also remove associated posts in Redis + ElasticSearch. This PR was enjoyable because it taught me the advantages of writing lots of tests. The function works, but I just need to finish writing a test for it and it should be ready to be reviewed by our gatekeeper @<a href="https://github.com/humphd">humphd</a>.<br />
<br />
Other PRs I worked on were refactoring the layout.js component we had previously using class components to become functional components. Refactoring this didn't take so long and at the end of it, I realized I got pretty good at using the useEffect and useState hooks of React.<br />
<br />
As we're nearing 1.0 for Telescope and with so many things left to finish prior to shipping. I present the following as nobody in the Telescope channel has started panicking yet.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_vPN8q1gLgeftybqFl4tbQHRxPV7BIwoCaAQuN2F8uR_y5HwTlLTGcw7zlwdC4dfun4Hk060pm23Zi_SU7cHBgeFXyADVDncCSLFRLIq7nVt_fcvJC2gx1mThyZ787v4MUy27BUiFjHru/s1600/dog+meme+cropped.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="576" data-original-width="586" height="314" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_vPN8q1gLgeftybqFl4tbQHRxPV7BIwoCaAQuN2F8uR_y5HwTlLTGcw7zlwdC4dfun4Hk060pm23Zi_SU7cHBgeFXyADVDncCSLFRLIq7nVt_fcvJC2gx1mThyZ787v4MUy27BUiFjHru/s320/dog+meme+cropped.png" width="320" /></a></div>
<br />
<br />
<br />C3HOhttp://www.blogger.com/profile/11262089715979645506noreply@blogger.com0tag:blogger.com,1999:blog-3586542501367863430.post-30948819227807329512020-04-02T20:07:00.000-07:002020-04-02T20:16:48.728-07:00Developing with a Test First ApproachI spent this week kind of sluggishly finishing up PRs that were close to completing such as the version on the <a href="https://github.com/Seneca-CDOT/telescope/pull/843">banner</a>. We can now see what the latest commit Telescope is running now by clicking on the version.<br />
<div>
<br /></div>
<div>
Another <a href="https://github.com/Seneca-CDOT/telescope/pull/842">one</a> I finished up since last release was configuring Nginx to use recommended settings by Mozilla.<br />
<div>
<br />
Yes, I am still neglecting Kubernetes...<br />
<br /></div>
</div>
<div>
However, today I'm here to write about an issue I just took on and started working on at 2AM this morning, <a href="https://github.com/Seneca-CDOT/telescope/pull/919">Issue-908</a> and I think I am close to finish. This work involved Redis, which was nice as some of my earliest contributions to Telescope were Redis related issues.</div>
<div>
<br /></div>
<div>
For this PR I took a different approach, put a heavy emphasis on thinking about and writing tests, I quickly wrote new features that should have mostly worked and used the tests I wrote to aid in making sure they are mostly correct. Up to this point, I haven't really written much tests, I have maybe modified existing tests. So this time I made sure I wrote a ton of tests to cover situations and from there working on the new features so that whatever I am expecting and what I'm actually receiving match. </div>
<div>
<br /></div>
<div>
The approach was refreshing, instead of having to console.log() things, the tests easily told me what they were doing or what the value being returned was. For example as part of this PR I had to create a function that removes the Feed and all its associated Posts, some people might write a test that adds two posts belonging to a feed, delete the feed and check whether the posts still exist in the database.</div>
<div>
<br /></div>
<div>
Here's what I did:</div>
<div>
<ol>
<li>Create the feed for the test, make sure the created feed has the same values I used to create the feed.</li>
<li>Create two posts, make sure the created posts' data have the same values I used to create the posts.</li>
<li>Remove the feed, make sure the removed feed doesn't return any thing, check if both posts are empty too.</li>
</ol>
</div>
<div>
Is this test perfect? Probably not, there may or may not be some edge cases I haven't though of yet. Is this overkill? I have no idea, but more is probably better in this case. Will I write more tests in the future as long as it is not in the front-end? You bet. With all these tests, if any of them start failing, I can probably pinpoint where the code went wrong, instead of playing a guessing game.<br />
<br />
Be responsible, write tests!</div>
<div>
<br /></div>
C3HOhttp://www.blogger.com/profile/11262089715979645506noreply@blogger.com0tag:blogger.com,1999:blog-3586542501367863430.post-29139016058333220272020-03-30T11:16:00.001-07:002020-03-30T17:50:09.341-07:00The Importance of Taking Time OffEver since I've enrolled in the Open Source Development classes at Seneca, I've had a blast. I learned about using all sorts of new technologies, got to collaborate with people who are much more skilled at programming than I am, and I've had the chance to contribute to projects that seemed interesting. I could've graduated last semester, however the project and the idea of being able to learn and ship a product under the guidance of a very experienced professor convinced me to stay for another semester just for this course.<br />
<div>
<br /></div>
<div>
This isn't a post to say I regret my decision, far from it. The previous week prior to writing this post, I've been waking up at 8/9 in the morning and have been working on issues all the way til usually late in the morning of the next day (seems like this isn't unique for our class). But I started to feel kind of burnt out, the things I enjoyed doing just a week ago, I started to procrastinate on or not look forward to. I decided on a simple solution, take the weekend off and just enjoy time with things not related to Telescope. Do some exercise, go for a walk(I have no idea how advisable this is currently), spend time with the family or watch a movie. </div>
<div>
<br /></div>
<div>
I think it helped. As I'm writing this blog, I am content with my routine of checking slack, opening up my laptop that hasn't been opened for a a few days, browsing through outstanding issues on Github, typing the commands 'docker-compose up elasticsearch redis' then 'npm start' and fixing currently stale PRs.</div>
<div>
<br /></div>
<div>
I think this is applicable to probably anything and not just my situation, if you're starting to not enjoy something, take a bit of time off, enjoy other things and then re-evaluate.</div>
C3HOhttp://www.blogger.com/profile/11262089715979645506noreply@blogger.com2tag:blogger.com,1999:blog-3586542501367863430.post-25526193030884859552020-03-22T20:03:00.000-07:002020-03-23T07:48:45.814-07:00OSD700 Release 0.8This release was almost like 0.7, three weeks(kind of) to work on it. I worked on tackling most of the existing issues assigned to me as I had an outstanding ~15 issues that didn't have a PR yet.<br />
<br />
All links are to their pull requests.<br />
<br />
<b>Issue <a href="https://github.com/Seneca-CDOT/telescope/pull/808">538</a>: Expose Search Endpoint Via Web API</b><br />
A throwback to working with Express.js, a previous PR went in to include ElasticSearch, we can currently use its client on port 9200, but we didn't really integrate it with Telescope, this PR was to fix that. I created a new endpoint now at https://dev.telesope.cdot.systems/query, we also now have a query parameter called search that accepts search strings of less than 256 characters. Thank you to @<a href="https://github.com/raygervais">raygervais</a>, @<a href="https://github.com/manekenpix">manekenpix</a>, @<a href="https://github.com/cindyledev">cindyledev</a> for the review.<br />
<br />
https://dev.telescope.cdot.systems/query?search="search string here" should return blogs that contains whatever is entered after the "=" sign. Usually URL encodes spaces with %20 and I thought I would have to decode this, but surprisingly this was not the case and Express.js handles the encoding and decoding(I assume). I also added an error message informing the user if the user doesn't provide / provides an empty string for the search query parameter.<br />
<br />
<b>Issue 634: Nginx Configuration for Staging and Production</b><br />
This one was awesome, I still have no idea what I'm doing with Nginx. But it was extremely fun to just collaborate on this with someone as we were trying to get this to work. Building on top of what @<a href="https://github.com/manekenpix">manekenpix </a>had done previously to cache static files within Telescope, we're also caching all endpoints for Telescope. I forgot the exact settings we had, but hitting an endpoint on Telescope will now cause Nginx to cache the endpoint for the next while and instead of having to go to Telescope to get the requested page, Nginx will serve the cached endpoint until it is considered stale.<br />
<br />
Assuming there are no cached endpoints yet. We can test it by doing a curl -I https://dev.telescope.cdot.systems/posts, there should be a response header with 'X-Proxy-Cache: MISS'. Visit the address in the browser, then use the same curl command again and this time you should receive 'X-Proxy-Cache: HIT'<br />
<br />
<b>Issue <a href="https://github.com/Seneca-CDOT/telescope/pull/792">648</a>: Switch from in-memory to Redis-backed Session Management</b><br />
This was a simple PR, switching away from a package we're using to a production ready package. It was simple until I realized, my PR was breaking a lot of our current tests. A suggestion from @<a href="https://github.com/humphd">humphd </a>to use our current ioredis library fixed all these issues.<br />
<br />
<b>Issue <a href="https://github.com/Seneca-CDOT/telescope/pull/842">668</a> Compare Nginx Config with Mozilla Recommendations</b><br />
Also Nginx related PR which I have no idea what I'm doing, except to use their recommendations in our nginx configuration file.<br />
<br />
<b>Issue <a href="https://github.com/Seneca-CDOT/telescope/pull/807">724</a> Add Site Property to Feeds and Redis</b><br />
I think this PR is close, I just need confirmation if what I'm doing is a correct way.The feedparser-promised package parses all posts for the processed feed and returns a link in its metadata which is supposed to contain the url without the tags, for example https://c3ho.blogspot.com/feeds/posts/default/-/open-source should become https://c3ho.blogspot.com. But upon further testing, this is not the case and only feeds from Wordpress are working as intended. I wrote a simple function instead to just take the feed url provided by the user and do some regex to obtain the "link" foregoing the metadata link route as it is not consistent.<br />
<br />
<b>Issue <a href="https://github.com/Seneca-CDOT/telescope/pull/792">750 </a>Make Search Bar Return Results</b><br />
Building upon work I did previously to create a component for Author results, I now had to combine the GraphQL queries I worked on and the Author component so results will be displayed when a user types a string into the search bar. This was fun and stressful as it taught me more about React hooks, but tons of frustration on trying to get GraphQL queries and Apollo Client to work on the front end. In the end I wasn't able to get search bar to return results when the button is clicked, so I had to opt for it to dynamically return results as the user inputs text. Thank you @<a href="https://github.com/cindyledev">cindyledev</a> for religiously reviewing all the later commits for this PR.<br />
<br />
<b>Issue <a href="https://github.com/Seneca-CDOT/telescope/pull/843">803</a> Include Version Info on Header Banner</b><br />
This PR works, we've tested it locally with the commands npm run build and npm run develop and it has worked on several machines. I just don't know why ZEIT doesn't like it. We turned the version info on the banner into a link so when you hover over it, there's the SHA info regarding the commit it is on and clicking on it will bring the user to the commit in Github.<br />
<br />
I keep saying this, but for this upcoming release, I'll be finishing up unfinished PRs and get Kubernetes working so I can tackle replacing our REST APIs with serverless functions.C3HOhttp://www.blogger.com/profile/11262089715979645506noreply@blogger.com0tag:blogger.com,1999:blog-3586542501367863430.post-13928256781728060672020-03-13T21:34:00.001-07:002020-03-14T16:12:43.447-07:00Serverless Functions(Node)Serverless functions are pretty cool, they take care of another worry developers might have: <i>What if I get so many requests that it overloads my server?</i> Simple, you don't. You let an almost trillion dollar company(Amazon) handle it. These functions are able to scale up and down depending on the # of requests all handled by AWS Lambda.<br />
<br />
We'll be using the serverless package which makes settings up AWS lambda pretty simple.<br />
<br />
Before we begin, make sure you have a AWS account and user created and provide the user programmatic access:<br />
<ol>
<li>Use the command: <span style="background-color: rgba(27 , 31 , 35 , 0.05); color: #24292e; font-family: , "consolas" , "liberation mono" , "menlo" , monospace; font-size: 11.9px;">serverless config credentials --provider aws --key userKey --secret userSecret</span> . Replace userKey and userSecret with the appropriate user information you created for the AWS account. </li>
<li>Use the command <span style="background-color: rgba(27 , 31 , 35 , 0.05); color: #24292e; font-family: , "consolas" , "liberation mono" , "menlo" , monospace; font-size: 11.9px;">serverless create --template aws-nodejs --path folderName</span> . Replace folderName with your choice, this will create a folder with <span style="background-color: rgba(27 , 31 , 35 , 0.05); color: #24292e; font-family: , "consolas" , "liberation mono" , "menlo" , monospace; font-size: 11.9px;">serverless.yml</span> and a file called handler.js</li>
</ol>
There's really two parts that make up the serverless functions, the <span style="background-color: rgba(27 , 31 , 35 , 0.05); color: #24292e; font-family: , "consolas" , "liberation mono" , "menlo" , monospace; font-size: 11.9px;">serverless.yml</span> and the corresponding .js file containing the functions. For this example I'll have a file called handler.js containing all my functions I wish to make serverless.<br />
<br />
When trying to hook up the functions, we must have a few things:<br />
<ol>
<li>Define the functions in the file(handler.js)</li>
<li>Make sure the available handler is available for the function</li>
</ol>
In my handler.js file I'll have the two following functions<br />
<br />
hello() which returns the message 'Hi' and bye() which returns the message 'Bye'.<br />
Here's how bye looks like<br />
<br />
<pre style="background-color: #f6f8fa; border-radius: 3px; box-sizing: border-box; color: #24292e; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace; font-size: 11.9px; line-height: 1.45; overflow-wrap: normal; overflow: auto; padding: 16px;"><code style="background: initial; border-radius: 3px; border: 0px; box-sizing: border-box; display: inline; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace; font-size: 11.9px; line-height: inherit; margin: 0px; overflow-wrap: normal; overflow: visible; padding: 0px; word-break: normal;">module.exports.bye = async (event, context, callback) => {
const str = `Bye`;
return str;
}</code></pre>
<br />
The event argument contains information about other AWS services the function has gone through, if it went through a load balancer it will contain information about the load balancer. For more information about it, find it <a href="https://docs.aws.amazon.com/lambda/latest/dg/lambda-services.html">here</a>.<br />
<br />
The context argument contains information about the invocation, function and environment. For more information about it, find it <a href="https://docs.aws.amazon.com/lambda/latest/dg/nodejs-context.html">here</a>.<br />
<br />
The callback argument contains information you want to send back in case of success or error, the callback actually accepts two arguments <span style="background-color: rgba(27 , 31 , 35 , 0.05); color: #24292e; font-family: , "consolas" , "liberation mono" , "menlo" , monospace; font-size: 11.9px;">callback(response_error, response_success)</span>. Amazon provides documentation on how you should handle async vs sync callbacks <a href="https://docs.aws.amazon.com/lambda/latest/dg/nodejs-handler.html">here</a><br />
<br />
Make sure both functions are exported. In the .yml file under the functions: section you want to create a section for each.<br />
<pre style="background-color: #f6f8fa; border-radius: 3px; box-sizing: border-box; color: #24292e; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace; font-size: 11.9px; line-height: 1.45; overflow-wrap: normal; overflow: auto; padding: 16px;"><code style="background: initial; border-radius: 3px; border: 0px; box-sizing: border-box; display: inline; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace; font-size: 11.9px; line-height: inherit; margin: 0px; overflow-wrap: normal; overflow: visible; padding: 0px; word-break: normal;">functions:
hello:
handler: handler.hello
events:
- http:
path: users/hello
method: get
bye:
handler: handler.bye
events:
- http:
path: users/bye
method: get</code></pre>
You'll notice we have the function name, followed by handler: fileName.functionName.<br />
<br />
To push the code to AWS, we'll have to use the command <span style="background-color: rgba(27 , 31 , 35 , 0.05); color: #24292e; font-family: , "consolas" , "liberation mono" , "menlo" , monospace; font-size: 11.9px;">serverless deploy -v</span>, you'll have to push the code anytime you want the changes reflected on AWS<br />
<br />
To call any of the functions to test on command line, use the command <span style="background-color: rgba(27 , 31 , 35 , 0.05); color: #24292e; font-family: , "consolas" , "liberation mono" , "menlo" , monospace; font-size: 11.9px;">serverless invoke -f functionName</span><br />
<br />
To test your app locally, we'll be using serverless-offline package. Once the package has been installed, we have to add the following at the end of serverless.yml:<br />
<pre style="background-color: #f6f8fa; border-radius: 3px; box-sizing: border-box; color: #24292e; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace; font-size: 11.9px; line-height: 1.45; overflow-wrap: normal; overflow: auto; padding: 16px;"><code style="background: initial; border-radius: 3px; border: 0px; box-sizing: border-box; display: inline; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace; font-size: 11.9px; line-height: inherit; margin: 0px; overflow-wrap: normal; overflow: visible; padding: 0px; word-break: normal;">plugins:
- serverless-offline</code></pre>
<br />
Use the command <span style="background-color: rgba(27 , 31 , 35 , 0.05); color: #24292e; font-family: , "consolas" , "liberation mono" , "menlo" , monospace; font-size: 11.9px;">serverless offline start</span> to start it up locally. This uses default port 3000 and you should now be able to get 'Bye' in the terminal or console when you hit the route: <span style="background-color: rgba(27 , 31 , 35 , 0.05); color: #24292e; font-family: , "consolas" , "liberation mono" , "menlo" , monospace; font-size: 11.9px;">localhost:3000/users/bye</span><br />
<br />
This wasn't too bad. Now you can say you have knowledge of cloud based programming!<br />
<br />
Source: <a href="https://hackernoon.com/a-crash-course-on-serverless-with-node-js-632b37d58b44">https://hackernoon.com/a-crash-course-on-serverless-with-node-js-632b37d58b44</a>C3HOhttp://www.blogger.com/profile/11262089715979645506noreply@blogger.com0tag:blogger.com,1999:blog-3586542501367863430.post-8875023086640864142020-03-13T19:45:00.003-07:002020-03-14T16:11:47.933-07:00Planning for March Break<div>
Most public institutions have closed or are preparing to close for the next week and now we're getting an unexpected March Break so there's some planning on what to do for the next few weeks while this happens:</div>
<div>
<br /></div>
<div>
<b>Running</b>:</div>
<div>
Last October I ran the ScotiaBank half marathon(21 km) a goal of mine since I was young. I've been thinking if this year's half marathon goes well again, I'll try for a full marathon(42 km) and make qualifying in the Boston marathon an eventual goal. I thought I did pretty well finishing in a time of 1:45 for a half marathon until I realized to qualify for the Boston event you need to finish a marathon in ~3:03. This means I have to shave off 15 mins off my half marathon time WHILE running twice as long. I've got a long way to go. The improving weather and off time should allow me to start running earlier.</div>
<div>
<br /></div>
<div>
<b>Boxing</b>:</div>
<div>
I've been boxing for ~6 years now and instructor for 2 years. This week or more off should probably allow me to take some of the classes instead of only teaching.</div>
<div>
<br /></div>
<div>
<b>Teaching</b>:</div>
<div>
A friend of mine reached out to me around December to see if I would be interested in teaching programming to children(Scratch) and pre-teens(basic Javascript) once a week for 8 weeks starting in at a community center starting February. I'm assuming it went well as he asked me to teach HTML/CSS basics starting April. Time to plan how and what to teach kids about HTML.<br />
<br />
On a side note, for anyone who wants to test quick things for Javascript like a quickly written function or to test some packages without wanting to install express package and all that stuff in Visual Studio Code, I highly suggest Glitch. They have an option for launching a basic web-page or a node-express app (allows users to also install packages), they also have a terminal to interact with your app and the option to import/export your code from/to Github.</div>
<div>
<br /></div>
<div>
<b>Dogs</b>:</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDy8RSd1x-4lFID2CzzSvb7MYTgxEeoACz8gC-3X6cYdsqIShy32y-NueOHQRuX2wSpNQvE20W7jIC7CwKCxN7eaLP-xjbZ54-StBJhilSi7MoTzcEa1Iuub2zxcsA4fWRSEletODjrgca/s1600/koda.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="480" data-original-width="640" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDy8RSd1x-4lFID2CzzSvb7MYTgxEeoACz8gC-3X6cYdsqIShy32y-NueOHQRuX2wSpNQvE20W7jIC7CwKCxN7eaLP-xjbZ54-StBJhilSi7MoTzcEa1Iuub2zxcsA4fWRSEletODjrgca/s320/koda.jpg" width="320" /></a></div>
<div>
I have two dogs, got to take them out for more walks or runs during the time off!</div>
<div>
<br /></div>
<div>
<b>Programming</b>:</div>
During the first class of OSD700 our professor mentioned something pretty interesting that we could look into for Telescope, serverless functions. I'm not entirely sure if we'll have the opportunity to use it in Telescope, but I figured I'll look into it and if the opportunity arises, collaborate with another student who has expressed interest in it on and implement it.<br />
<br />
Another is to learn a bit more about deployment: Docker and Nginx. I just kind of use Docker to get ElasticSearch running, but have no idea how to create a docker file from scratch myself as all the hard work was done by <a href="https://github.com/manekenpix">@manekenpix</a> and <a href="https://github.com/raygervais">@raygervais</a><br />
<br />
Last goal I have is to also trim down the amount of issues I have assigned to myself. I think I had somewhere around 15 issues...C3HOhttp://www.blogger.com/profile/11262089715979645506noreply@blogger.com0tag:blogger.com,1999:blog-3586542501367863430.post-92226034856881153092020-02-26T18:54:00.001-08:002020-02-26T23:19:42.018-08:00OSD700 Release 0.7I tried to become a fullstack developer for this release. It... went better than I thought somehow? For this release I finally got to work on some front end. I remembered again why I like the back end so much more.<br />
<div>
<br /></div>
<div>
Thankfully, this release spanned 3 weeks instead of the normal 2 we're normally allotted. The first week I spent relearning how to use React and also learning how to use Material-UI. We're using Material instead of Bootstrap because some students in the class have developed a severe allergic reaction to Bootstrap. </div>
<div>
<br /></div>
<div>
<b>Author Result Component</b></div>
<div>
Issue can be found <a href="https://github.com/Seneca-CDOT/telescope/issues/722">here</a></div>
<div>
<br /></div>
<div>
I'm ashamed to admit, it took me at least 3+ hours just to make the search result component which can be found <a href="https://github.com/Seneca-CDOT/telescope/pull/744">here</a> (the time didn't include the design by <a href="https://github.com/agarcia-caicedo?tab=followers">@agarcia-caicedo</a>). I'm very grateful I didn't have to design the component as well or we might not even have a component at all, also big thank you to <a href="https://github.com/cindyledev">@cindyledev</a> for her reviews and suggestions as it made the process a lot quicker. </div>
<div>
<br /></div>
<div>
<b>Attaching the MyFeeds Component to the Backend</b></div>
<div>
Issue can be found <a href="https://github.com/Seneca-CDOT/telescope/issues/745">here</a></div>
<div>
<br /></div>
<div>
Wow, this took a whole day. Prior to this release, I saw our professor <a href="https://github.com/humphd">@humphd</a> submit a PR to refactor some previously merged React code from class components to functional components and didn't understand what was going on... since it was front-end stuff. </div>
<div>
<br /></div>
<div>
Well... a day was spent learning what functional components are(I learned React the class component way) and all the changes the React community have implemented. I read about how they are trying to steer people towards using React hooks instead of the previously used class components(although they are still supported). It took a while to understand (their docs are extremely helpful), still a newbie, but I understand it a lot more and have to admit, it is much better than their previous class components. Thank you to <a href="https://github.com/Grommers00">@Grommers00</a> for his work on the backend code changes and <a href="https://github.com/Silvyre">@Silvyre</a> for creating the component + quick review.</div>
<div>
<br /></div>
<div>
<b>Automatic Deployment to Staging on Master</b></div>
<div>
Issue can be found <a href="https://github.com/Seneca-CDOT/telescope/issues/699">here</a></div>
<div>
<br /></div>
<div>
I spent an afternoon with a frequent collaborator <a href="https://github.com/manekenpix">@manekenpix</a> to figure out how this all works. It was pretty interesting as we thought it would take a very long time to get this working, but after 2 hours we had a simple server that was listening to issues filed in a private Github repository and would output a message. The next step would be to automate all the shell commands that are currently being manually executed by him whenever we want Staging to be updated. I am just hoping he gets to work on more issues aside from deployment because he has expressed how much he enjoyed coding.<br />
<br /></div>
<div>
Now, automatic deployment can range from being really simple to extremely complex. We can have an app that experiences some downtime as the app is updating to being really complicated where we apply the Green/Blue model and minimize any downtime.<br />
<br />
Green/Blue - Two identical versions(Green and Blue) of the app will be available, one sits idle as the other one is running. When we bring down the one that is running (Green), we direct traffic to the other(Blue). This minimizes whatever downtime is being experienced as the current files in Green are being deleted, updated to the latest updates of the app from the GitHub repo and Green's containers are being spun up. Once Green is up and running again, we direct traffic back to the newly updated Green and idle Blue again. In this case the Blue can also act as a back-up which we can revert to if there are changes breaking the app or if Green is somehow experiencing issues.<br />
<br /></div>
<div>
<b>Switch our app from REST to GraphQL</b></div>
<div>
Issue can be found <a href="https://github.com/Seneca-CDOT/telescope/issues/697">here</a></div>
<div>
<br /></div>
<div>
We implemented GraphQL and it works, but only if you go to http://localhost:3000/playground or https://dev.telescope.cdot.systems/playground. Out of all the issues this one was the most frustrating. I thought we were using Gatsby because it works well with GraphQL, I didn't know how it was going to work well, but it would just kind of work. This wasn't the case, we had to install an extra plugin called <a href="https://www.gatsbyjs.org/packages/gatsby-source-graphql/">gatsby-source-plugin</a>, It took a whole day for me to understand the changes I was making in gatsby-config.js 😂.</div>
<div>
<br /></div>
<div>
Anyways, this issue was so we can use all the queries we built for GraphQL to be used in the front end code too. A PR is ready to go which specifically addresses this issue... however moving forward some experimenting to understand how to use the data properly as well as what Static Query/ Page Query/ Static Query Hook are is going to be needed in order to use Gatsby properly with GraphQL<br />
<br />
Overall, this release was a fun way to move away from just working on back end, refreshing/updating my knowledge on front end stuff and working on issues that were in between the two. I can't design things to save my life, but I can probably implement the design in React! Since I can do back end and front end things, I'm now a full stack developer right? Probably not.<br />
<br />
For 0.8 alongside triaging issues, my goal is to try to get Kubernetes/minikube up for Production.</div>
C3HOhttp://www.blogger.com/profile/11262089715979645506noreply@blogger.com0tag:blogger.com,1999:blog-3586542501367863430.post-47380288982420986712020-02-09T22:13:00.001-08:002020-02-09T22:30:59.499-08:00Fullstack Developer Wanted??I don't get these job postings.<br />
<div>
<br /></div>
<div>
There was apparently an infamous post written on Medium by a big named guy declaring Fullstack is dead. </div>
<div>
<br /></div>
<div>
After working on Telescope, I think so too. The field is so broad now with ever increasing amounts of technology a developer is supposed to know. A typical fullstack developer posting on sites goes as follows</div>
<div>
<br /></div>
<div>
We're looking for a fullstack developer with the following experience:</div>
<div>
<ul>
<li>Node.js + Express/Java/Golang/Python/.Net</li>
<li>Javascript, CSS, HTML5</li>
<li>Angular/React + Redux/Vue</li>
<li>Docker</li>
<li>No SQL: MongoDB/ Cassandra/ DynamoDB</li>
<li>SQL: Oracle/ MySql</li>
<li>AWS (may or may not include serverless functions)</li>
<li>GIT</li>
</ul>
<div>
Bonus if you have experience with the following:</div>
<ul>
<li>Redis/Memcached</li>
<li>User Experience design</li>
<li>GraphQL</li>
<li>CI/CD: Travis, Circle</li>
<li>Kubernetes</li>
<li>JWT/Auth0</li>
</ul>
<div>
WTF? One of the students in the class has spent pretty much a semester if not two, just learning and trying to implement SSO for Telescope. I mean I understand this is a wishlist, but this is insane. You might as well hire my Open Source Prof, @humphd at this rate. Thanks. </div>
</div>
C3HOhttp://www.blogger.com/profile/11262089715979645506noreply@blogger.com3tag:blogger.com,1999:blog-3586542501367863430.post-44097638684465537872020-02-09T12:43:00.002-08:002020-02-09T17:55:05.605-08:00OSD700 Release 0.6Worked on a few issues for Telescope for this release:<br />
<br />
<b>GraphQL documentation for Telescope</b><br />
Issue can be found <a href="https://github.com/Seneca-CDOT/telescope/issues/587">here</a><br />
<br />
This was fun, I knew nothing about GraphQL going into this. By the end of it I was even hacking away at nested queries on my own branch which we haven't even implemented yet in Telescope. I always shied away from documentation, because I rather be coding. I guess it is true. To see if you've really learned something, you should be able to explain or teach it to someone else.<br />
<br />
<b>GraphQL filters for Telescope</b><br />
Issue can be found <a href="https://github.com/Seneca-CDOT/telescope/issues/591">here</a><br />
<br />
Aside from documenting on how to use GraphQL, I also took on an issue which required me to rewrite some queries to allow filtering and support future search functionality for the front end. This taught me some pain points about GraphQL as I always assumed it could do stuff like a traditional database, fro example: select * from posts where posts > provided date or something along those lines. GraphQL cannot or rather is unable to support this without installing another library, I ended up writing my own logic to do filtering and pagination.<br />
<br />
On a side note, I also learned people can publish scalars(GraphQL typing) in packages for other people to download and use.<br />
<br />
<b>Include logic to filter inactive feeds and invalidate inactive feeds for Telescope</b><br />
Issue can be found <a href="https://github.com/Seneca-CDOT/telescope/issues/462">here</a><br />
<br />
Another issue I started over the Christmas weekend and finally finished. This went through a few iterations and in the end it was suggested to scrap the current code written in favor of a more Redis oriented solution.<br />
<br />
<b>Refactor promises for plumadriver</b><br />
Issue can be found <a href="https://github.com/Seneca-CDOT/plumadriver/issues/50">here</a><br />
<br />
I was suggested this issue by our prof, since I did quite a bit of work on refactoring promises for Telescope. It was an interesting experience reading typescript code and contributing to another repository after a few months of just working on Telescope.C3HOhttp://www.blogger.com/profile/11262089715979645506noreply@blogger.com0tag:blogger.com,1999:blog-3586542501367863430.post-25060254779780095652020-01-29T21:08:00.002-08:002020-01-30T07:03:17.295-08:00GraphQL Nested QueriesThe whole point of GraphQL is its flexibility, I can view all the authors in the database and then I can add an additional query that can display all the books by the one author, we call these nested queries. I recently spent an afternoon + evening with <a href="https://whataboutopensource.blogspot.com/">@manekenpix</a> to take a look at nested queries in GraphQL for the Telescope project.<br />
<br />
We currently have a schema like below<br />
<pre class="c-mrkdwn__pre" data-stringify-type="pre" style="--saf-0: rgba(var(--sk_foreground_low,29,28,29),0.13); border-radius: 4px; border: 1px solid var(--saf-0); box-sizing: inherit; color: #1d1c1d; counter-reset: list-0 0 list-1 0 list-2 0 list-3 0 list-4 0 list-5 0 list-6 0 list-7 0 list-8 0 list-9 0; font-family: Monaco, Menlo, Consolas, "Courier New", monospace !important; font-size: 12px; font-variant-ligatures: none; line-height: 1.50001; margin-bottom: 4px; margin-top: 4px; overflow-wrap: break-word; padding: 8px; tab-size: 4; white-space: pre-wrap; word-break: normal;"> # 'Feed' matches our Feed type used with redis
type Feed {
id: String
author: String
url: String
posts: [Post]
}<span class="c-mrkdwn__br" data-stringify-type="paragraph-break" style="box-sizing: inherit; display: block; height: unset;"></span> # 'Post' matches our Post type used with redis
type Post {
id: String
author: String
title: String
html: String
text: String
published: String
updated: String
url: String
site: String
guid: String
}</pre>
<br />
Notice feed can also return an array of Post, to allow nested queries, we have to define them in resolvers after the Query:<br />
<br />
<pre class="c-mrkdwn__pre" data-stringify-type="pre" style="--saf-0: rgba(var(--sk_foreground_low,29,28,29),0.13); border-radius: 4px; border: 1px solid var(--saf-0); box-sizing: inherit; color: #1d1c1d; counter-reset: list-0 0 list-1 0 list-2 0 list-3 0 list-4 0 list-5 0 list-6 0 list-7 0 list-8 0 list-9 0; font-family: Monaco, Menlo, Consolas, "Courier New", monospace !important; font-size: 12px; font-variant-ligatures: none; line-height: 1.50001; margin-bottom: 4px; margin-top: 4px; overflow-wrap: break-word; padding: 8px; tab-size: 4; white-space: pre-wrap; word-break: normal;">module.exports.resolvers = {
Query: {
//Queries are here
},
Feed: {
posts: async parent => {
const maxPosts = await getPostsCount();
const ids = await getPosts(0, maxPosts);
const posts = await Promise.all(ids.map(postId => getPost(postId)));
const filteredPosts = posts.filter(post => post.author === parent.author);
return filteredPosts;
},
},
};</pre>
<br />
What the above code does is get all Posts in the database, then filter the Posts only returning Posts that have the same author as the returned value of the feed author. For example if I'm running the following query in GraphQL<br />
<br />
<pre class="c-mrkdwn__pre" data-stringify-type="pre" style="--saf-0: rgba(var(--sk_foreground_low,29,28,29),0.13); border-radius: 4px; border: 1px solid var(--saf-0); box-sizing: inherit; color: #1d1c1d; counter-reset: list-0 0 list-1 0 list-2 0 list-3 0 list-4 0 list-5 0 list-6 0 list-7 0 list-8 0 list-9 0; font-family: Monaco, Menlo, Consolas, "Courier New", monospace !important; font-size: 12px; font-variant-ligatures: none; line-height: 1.50001; margin-bottom: 4px; margin-top: 4px; overflow-wrap: break-word; padding: 8px; tab-size: 4; white-space: pre-wrap; word-break: normal;">{
getFeedById(id: "123") {
author
id
posts {
title
}
}
}</pre>
<br />
and the author name is Marie, the parent parameter that is provided to the nested query (posts) will be the results of the getFeedById which in this case the author name is Marie.<br />
<br />
Real life data using a classmate of mine:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgiGbdMsfGOxP6qiLw6hASeWWJnxVfEAbzhmUcWD_ck0Fcwjl29SIv5D_3XcnkjIZfTHObQqXfzLTXK6CpF4bkIocCgWA33Jmg2ub6MCcaosCe4nbdyLOkYpfXbPVNhbHAyAdW6NQlHDtr4/s1600/nested+query.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="400" data-original-width="1600" height="160" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgiGbdMsfGOxP6qiLw6hASeWWJnxVfEAbzhmUcWD_ck0Fcwjl29SIv5D_3XcnkjIZfTHObQqXfzLTXK6CpF4bkIocCgWA33Jmg2ub6MCcaosCe4nbdyLOkYpfXbPVNhbHAyAdW6NQlHDtr4/s640/nested+query.PNG" width="640" /></a></div>
<br />
<br />
<br />C3HOhttp://www.blogger.com/profile/11262089715979645506noreply@blogger.com0tag:blogger.com,1999:blog-3586542501367863430.post-31504453358104540882020-01-24T21:09:00.003-08:002020-01-30T07:03:53.827-08:00OSD700 Release 0.5As part of 0.5 I was working working mainly on two issues and got a chance to help someone start contributing to Telescope.<br />
<div>
<br />
<b>Async/Await</b></div>
<div>
I've blogged a bit about using async/await to replace our Promise code in Telescope. I started the working during the winter break and was finally able to get that merged this week. The issue actually took a while as it spanned across ~15 files in Telescope and had me refactor functions and tests at the same time, which admittedly was pretty scary. I can say I know how to use async/await a bit better, but there's still a long road ahead!</div>
<div>
<br />
<b>Kubernetes(minikube)</b></div>
<div>
My other issue I've been working on is a collaboration between me and another classmate <a href="https://whataboutopensource.blogspot.com/">@manekenpix</a> to deploy Kubernetes(minikube) on a site for Telescope at http:://dev.telescope.cdot.systems/planet. We've had success being able to deploy services and even got the ingress to work on our own machines locally. However after 5 hours of sitting down and lots of expletives yelled at the computer, we had an issue when trying to deploy it on the machine CDOT has prepared to host Telescope. We forgot minikube runs using a vm on the computer, exposing the service and deployment only really exposes it to the computer the vm is running on. After a bit of researching and asking around on the slack channel we have decided to try a Bridged connection to expose the vm to outside traffic. We're crossing our fingers to have this for 0.6 (hopefully).</div>
<div>
<br />
<b>Helping a new contributor</b></div>
<div>
Lastly, our professor Dave Humphrey has been actively recruiting students from his other classes to participate on Telescope (where was this teacher when I started learning web development). Which I think is an amazing idea as they gain experience in filing/fixing issues, receiving feedback and just collaborating with other programmers on an open source project. One student took on a great starter issue to standardize the error code on the project. I was kind of a mentor in helping the contributor get their code merged. This gave me flashbacks to OSD600 where our professor pretty much spent the whole semester teaching git and helping students with their git problems. Long story short, the student was able to get their PR merged and is happily taking on another issue. Git is hard and it is even more so when things land daily if not every few hours, the student admitted he used git before, but wasn't used to the pace at which Telescope moved.</div>
<div>
<br /></div>
<div>
The mentoring also taught me something, our professor has started to emphasize the importance of submitting a PR with some work completed instead of a full fledged PR. This way if their current work is starting to go sideways the community can direct the contributor to the correct path, preventing them from going further down the wrong path. For example, the contributor I was helping out kept trying to rebase, apply their changes then commit to their PR all in one go and this kept failing. Instead, I asked the contributor to:</div>
<div>
<ol>
<li>rebase their PR and drop any of the unrelated commits, push code to their PR. At this point we'd review and see what other changes we need to make, such as do we have to use any files from master to the working branch because a file on the working branch is too far gone?</li>
<li>if the current status of the PR looked good, we'd apply their changes to fix the issue and review to see what other changes we need to make</li>
</ol>
<div>
This approach worked a lot better and the contributor got their PR merged today!<br />
<br />
In hindsight, I think I've become a better programmer. 4/5 months ago I was attempting to enhance another person's simple note taking app on github.</div>
</div>
C3HOhttp://www.blogger.com/profile/11262089715979645506noreply@blogger.com0tag:blogger.com,1999:blog-3586542501367863430.post-28191269746032252612020-01-19T21:12:00.001-08:002020-01-19T21:15:37.604-08:00Async Await and Promises<pre class="a-b-r-La" style="background-color: white; font-family: "Courier New", Courier, monospace, arial, sans-serif; font-size: 14px; overflow-wrap: break-word; user-select: text; white-space: pre-wrap;">As a continuation of my PR for Telescope, I thought I should talk a bit about async/await and the old way of using return new Promise(). Here are a few examples of do's and don'ts:</pre>
<pre class="a-b-r-La" style="background-color: white; font-family: "Courier New", Courier, monospace, arial, sans-serif; font-size: 14px; overflow-wrap: break-word; user-select: text; white-space: pre-wrap;"></pre>
<pre class="a-b-r-La" style="background-color: white; font-family: "Courier New", Courier, monospace, arial, sans-serif; font-size: 14px; overflow-wrap: break-word; user-select: text; white-space: pre-wrap;">// <b>Async functions return promises, no need to add await </b>
// DON"T DO
async function returnsPromise(){
return await promiseFunction();
}
// DO
async function returnsPromiseFixed(){
return promiseFunction();
}
//---------------------------------------------------------------------------
// <b>Don't use await when function is not async </b>
// DON"T DO
function noAsync(){
let promise = await promiseFunction();
}
// DO
async function noAsyncFixed(){
let promise = await promiseFunction();
}
//---------------------------------------------------------------------------
</pre>
<pre class="a-b-r-La" style="background-color: white; font-family: "Courier New", Courier, monospace, arial, sans-serif; font-size: 14px; overflow-wrap: break-word; user-select: text; white-space: pre-wrap;"></pre>
<pre class="a-b-r-La" style="background-color: white; font-family: "Courier New", Courier, monospace, arial, sans-serif; font-size: 14px; overflow-wrap: break-word; user-select: text; white-space: pre-wrap;">// <b>Writing errors</b>
async function f() {
await Promise.reject(New Error("Error"));
}
// SAME AS
async function f() {
throw new Error("Error");
}
<pre class="a-b-r-La" style="font-family: "courier new", courier, monospace, arial, sans-serif; overflow-wrap: break-word; white-space: pre-wrap;">//---------------------------------------------------------------------------</pre>
// <b>Use try catch to wrap only code that can throw</b>
// DON"T DO
async function tryCatch() {
try {
const fetchResult = await fetch();
const data = await fetchResult.json();
const t = blah();
} catch (error) {
logger.log(error);
throw new Error(error);
}
}
// DO
async function tryCatchFixed() {
try {
const fetchResult = await fetch();
const data = await fetchResult.json();
} catch (error) {
logger.log(error);
throw new Error(error);
}
}
const t = blah();
//---------------------------------------------------------------------------
// <b>Use async/await. Don't use Promises</b>
// DON"T DO
async function usePromise() {
new Promise(function(res, rej) {
if (isValidString) {
res(analysis);
} else {
res(textInfo);
}
if (isValidStrinng === undefined) {
rej(textInfo);
}
})
}
// DO
async function usePromiseFixed() {
const asyResult = await asyFunc()
}
// --------------------------------------------------------------------------
// <b>Don't use async when it is not needed... Don't be overzealous with async/await</b>
// <b>For example the sentiment module we're using is not an async function</b>
// DON"T DO
module.exports.run = async function(text) {
const sentiment = new Sentiment();
return Promise.resolve(sentiment.analyze(text));
};
// DO
module.exports.run = function(text) {
const sentiment = new Sentiment();
return sentiment.analyze(text);
};
// --------------------------------------------------------------------------
// <b>Avoid making things too sequential</b>
// DON"T DO
async function logInOrder(urls) {
for (const url of urls) {
const response = await fetch(url);
console.log(await response.text());
}
}
// DO
async function logInOrder(urls) {
// fetch all the URLs in parallel
const textPromises = urls.map(async url => {
const response = await fetch(url);
return response.text();
});
// log them in sequence
for (const textPromise of textPromises) {
console.log(await textPromise);
}
}
// --------------------------------------------------------------------------
</pre>
<pre class="a-b-r-La" style="background-color: white; font-family: "Courier New", Courier, monospace, arial, sans-serif; font-size: 14px; overflow-wrap: break-word; user-select: text; white-space: pre-wrap;">// <b>Examples</b>
// refactor following function:
function loadJson(url) {
return fetch(url)
.then(response => {
if (response.status == 200) {
return response.json();
} else {
throw new Error(response.status);
}
})
}
// Solution:
function loadJson(url) {
let fetchResult = await fetch(url);
if (fetchResult.status == 200){
let json = await fetchResult.json();
return json;
}
throw new Error(fetchResult.status);
}
// refactor to use try/catch
function demoGithubUser() {
let name = prompt("Enter a name?", "iliakan");
return loadJson(`https://api.github.com/users/${name}`)
.then(user => {
alert(`Full name: ${user.name}.`);
return user;
})
.catch(err => {
if (err instanceof HttpError && err.response.status == 404) {
alert("No such user, please reenter.");
return demoGithubUser();
} else {
throw err;
}
});
}
demoGithubUser();
// Solution:
async function demoGithubUser() {
let user;
while(true){
let name = prompt("Enter a name?", "iliakan");
try {
user = await loadJson(`https://api.github.com/users/${name}`)
break;
} catch (err) {
if (err) {
alert("No such user, please reenter.");
return demoGithubUser();
} else {
throw err;
}
}
}
}
// Call async from non-async
async function wait() {
await new Promise(resolve => setTimeout(resolve, 1000));
return 10;
}
function f() {
// ...what to write here?
// we need to call async wait() and wait to get 10
// remember, we can't use "await"
}
// Solution:
function f() {
wait().then(result => alert(result));
}</pre>
C3HOhttp://www.blogger.com/profile/11262089715979645506noreply@blogger.com0tag:blogger.com,1999:blog-3586542501367863430.post-39779218263246133862020-01-11T00:57:00.001-08:002020-01-11T01:02:20.380-08:00Telescope Issue-525<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNh8eo4SFFEGbKCvfLRIFGOBTg67rpHoxR37UM6B1wsdIH7ax_E22nxSGxMPOaFrOZudZbqpTzHgouzyjBnhyE_-hgJn-Ml_EPpsLaSEri431jcMVRFKxonvHnBj3LBXhsBGq7eUegzqeQ/s1600/ezgif.com-add-text+%25282%2529.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="270" data-original-width="480" height="225" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNh8eo4SFFEGbKCvfLRIFGOBTg67rpHoxR37UM6B1wsdIH7ax_E22nxSGxMPOaFrOZudZbqpTzHgouzyjBnhyE_-hgJn-Ml_EPpsLaSEri431jcMVRFKxonvHnBj3LBXhsBGq7eUegzqeQ/s400/ezgif.com-add-text+%25282%2529.gif" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div style="text-align: center;">
The <a href="https://c3ho.blogspot.com/2019/12/so-i-added-new-linting-rules.html">story</a> of my PR for <a href="https://github.com/Seneca-CDOT/telescope/issues/525">issue-525</a>.</div>
<div style="text-align: center;">
I can't believe I'm making gifs at 4 in the morning.</div>
C3HOhttp://www.blogger.com/profile/11262089715979645506noreply@blogger.com0tag:blogger.com,1999:blog-3586542501367863430.post-1469849319688324972020-01-08T23:25:00.000-08:002020-01-08T23:32:36.482-08:00Kubernetes Pt3<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3wmy4d4zkQO9pOBrxle5frOlDZFGO8OgW3gjpE6_NeVXupKffb6oiBnpA7tyv4u8k-1Rp44xiupd_zYlS_lRdlXEmNLWj4FTFCQ61y3_Cvh9yBqNb1qopSEWK8RIzzvBN4mLH4diIvcdo/s1600/35033FAC-A86C-4044-ACE7-A0224F4ED37D.jpeg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="295" data-original-width="1600" height="116" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3wmy4d4zkQO9pOBrxle5frOlDZFGO8OgW3gjpE6_NeVXupKffb6oiBnpA7tyv4u8k-1Rp44xiupd_zYlS_lRdlXEmNLWj4FTFCQ61y3_Cvh9yBqNb1qopSEWK8RIzzvBN4mLH4diIvcdo/s640/35033FAC-A86C-4044-ACE7-A0224F4ED37D.jpeg" width="640" /></a></div>
<br />
<div style="text-align: center;">
*Blessed*</div>
<div style="text-align: center;">
<br /></div>
<div style="text-align: center;">
<img alt="Image result for angel singing meme" src="https://media.giphy.com/media/11xZJROxVpF0n6/giphy.gif" /><br />
<br />
<div style="text-align: left;">
Thank you @manekenpix, I still have no idea how to fix all the problems we came across, but let us just enjoy this for now.</div>
</div>
C3HOhttp://www.blogger.com/profile/11262089715979645506noreply@blogger.com0tag:blogger.com,1999:blog-3586542501367863430.post-27745453302713550182020-01-06T14:21:00.000-08:002020-01-07T00:16:01.537-08:00Kubernetes Pt2In the previous post we used kubectl command lines to deploy. However we can create .yaml configuration files and have kubectl create them that way also<br />
<div>
<br /></div>
<div>
the .yaml file will have the following</div>
<div>
<br /></div>
<div>
apiVersion: (name)</div>
<div>
kind: Deployment</div>
<div>
metadata:</div>
<div>
name: (appName)</div>
<div>
labels:</div>
<div>
app: (imageTag)</div>
<div>
spec:</div>
<div>
replicas: (replicaNumber)</div>
<div>
selector:</div>
<div>
matchLabels:</div>
<div>
app: (imageTag)</div>
<div>
template:</div>
<div>
metadata:</div>
<div>
labels:</div>
<div>
app: (imageTag)</div>
<div>
spec:</div>
<div>
containers:</div>
<div>
- name: (imageTag)</div>
<div>
image: (dockerImage)</div>
<div>
ports:</div>
<div>
- containerPort: (portNumber)</div>
<div>
<br /></div>
<div>
Then enter the following command:</div>
<div>
<i>kubectl create -f (.yaml file)</i><br />
<i><br /></i>
I pulled an example from the edx Kubernetes course using the nginx image to deploy a webserver<br />
<br />
<div>
apiVersion: <b>apps/v1</b></div>
<div>
kind: <b>Deployment</b></div>
<div>
metadata:</div>
<div>
name: <b>webserver</b></div>
<div>
labels:</div>
<div>
app: <b>nginx</b></div>
<div>
spec:</div>
<div>
replicas: <b>3</b></div>
<div>
selector:</div>
<div>
matchLabels:</div>
<div>
app: <b>nginx</b></div>
<div>
template:</div>
<div>
metadata:</div>
<div>
labels:</div>
<div>
app: <b>nginx</b></div>
<div>
spec:</div>
<div>
containers:</div>
<div>
- name: <b>nginx</b></div>
<div>
image: <b>nginx:alpine</b></div>
<div>
ports:</div>
<div>
- containerPort: <b>80</b><br />
<b><br /></b>
This will deploy an app named webserver replicated across three pods.<br />
<br />
We can also define a appName-svc-.yaml file to expose our service with the following content:<br />
<br />
apiVersion: (get this value from running kubectl api-version)<br />
kind: Service<br />
metadata:<br />
name: web-service<br />
labels:<br />
run: web-service<br />
spec:<br />
type: (serviceType)<br />
externalName: (externalLink) *Use this field if serviceType is set to ExternalName<br />
ports:<br />
- port: (portNumber)<br />
protocol: TCP<br />
selector:<br />
app: (imageTag)<br />
<br />
Then enter the following command:<br />
<i>kubectl create -f (appName)-svc.yaml</i><br />
<i><br /></i>
serviceType can be any of the below:<br />
<ol>
<li>LoadBalancer - if the cloud provider Kubernetes is running on provides load balancing.</li>
<li>ClusterIP - can only reach the service only from within the cluster</li>
<li>NodePort - creates a ClusterIP and NodePort service will route to it. Allows access from outside the cluster by using NodeIP:NodePort</li>
<li>ExternalName - maps the service to the contents of the externalName field</li>
</ol>
Also pulled from the edx Kubernetes course:<br />
<br />
apiVersion: <b>v1</b><br />
kind: <b>Service</b><br />
metadata:<br />
name: <b>web-service</b><br />
labels:<br />
run: <b>web-service</b><br />
spec:<br />
type: <b>NodePort</b><br />
ports:<br />
- port: <b>80</b><br />
protocol: <b>TCP</b><br />
selector:<br />
app: <b>nginx</b><br />
<br /></div>
</div>
C3HOhttp://www.blogger.com/profile/11262089715979645506noreply@blogger.com0