diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 000000000..590e4c730 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,16 @@ +name: MarkBind Deploy + +on: [push] + +jobs: + build_and_deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - name: Build & Deploy to GitHub Pages + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_REPOSITORY: ${{ secrets.GITHUB_REPOSITORY }} + GITHUB_ACTOR: ${{ secrets.GITHUB_ACTOR }} + BASE_URL: /2024 + uses: MarkBind/markbind-action@1.0.0 diff --git a/README.html b/README.html new file mode 100644 index 000000000..6b4f2f4b8 --- /dev/null +++ b/README.html @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + +

CS3281&2 student data website

+ + + diff --git a/README.page-vue-render.js b/README.page-vue-render.js new file mode 100644 index 000000000..2cc1d0222 --- /dev/null +++ b/README.page-vue-render.js @@ -0,0 +1,13 @@ + + var pageVueRenderFn = function anonymous( +) { +with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""}},[_c('navbar',{attrs:{"placement":"top","type":"primary"},scopedSlots:_u([{key:"brand",fn:function(){return [_c('a',{staticClass:"navbar-brand",attrs:{"href":"/2024/index.html","title":"Home"}},[_v("CS3281&2-2024/Students")])]},proxy:true},{key:"right",fn:function(){return [_c('li',[_c('a',{staticClass:"nav-link",attrs:{"href":"https://github.com/nus-cs3281/2024"}},[_c('span',[_c('span',{staticClass:"fab fa-github",attrs:{"aria-hidden":"true"}})])])])]},proxy:true}])},[_v(" "),_c('dropdown',{staticClass:"nav-link",scopedSlots:_u([{key:"header",fn:function(){return [_v("CS3281")]},proxy:true}])},[_v(" "),_c('li',[_c('a',{staticClass:"dropdown-item",attrs:{"href":"/2024/index.html"}},[_v("Students")])]),_v(" "),_c('li',[_c('a',{staticClass:"dropdown-item",attrs:{"href":"/2024/students/knowledge.html"}},[_v("Knowledge")])]),_v(" "),_c('li',[_c('a',{staticClass:"dropdown-item",attrs:{"href":"https://nus-cs3281.github.io/2024-dashboard/?search=&sort=groupTitle&sortWithin=title&timeframe=commit&mergegroup=&groupSelect=groupByAuthors&breakdown=false"}},[_v("Code Dashboard")])])]),_v(" "),_c('dropdown',{staticClass:"nav-link",scopedSlots:_u([{key:"header",fn:function(){return [_v("CS3282")]},proxy:true}])},[_v(" "),_c('li',[_c('a',{staticClass:"dropdown-item",attrs:{"href":"/2024/cs3282-index.html"}},[_v("Students")])]),_v(" "),_c('li',[_c('a',{staticClass:"dropdown-item",attrs:{"href":"/2024/students/talksSchedule.html"}},[_v("Lightning Talks")])])]),_v(" "),_c('li',[_c('a',{staticClass:"nav-link",attrs:{"href":"/2024/instructions.html"}},[_v("Instructions")])]),_v(" "),_c('li',[_c('a',{staticClass:"nav-link",attrs:{"href":"https://nus-cs3281.github.io/website/"}},[_v("CS3281&2 Website "),_c('span',[_c('span',{staticClass:"glyphicon glyphicon-share-alt",attrs:{"aria-hidden":"true"}})])])])],1)],1),_v(" "),_c('div',{attrs:{"id":"flex-body"}},[_m(0),_v(" "),_c('overlay-source',{staticClass:"fixed-header-padding",attrs:{"id":"page-nav","tag-name":"nav","to":"page-nav"}},[_c('div',{staticClass:"nav-component slim-scroll"})])],1),_v(" "),_m(1)])} +}; + var pageVueStaticRenderFns = [function anonymous( +) { +with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('h1',{attrs:{"id":"cs3281-and-amp-2-student-data-website"}},[_v("CS3281&2 student data website"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#cs3281-and-amp-2-student-data-website","onclick":"event.stopPropagation()"}})])])} +},function anonymous( +) { +with(this){return _c('footer',[_c('div',{staticClass:"text-center"},[_c('p',[_v("["),_c('strong',[_v("This site was generated using "),_c('img',{attrs:{"src":"https://markbind.org/favicon.ico","width":"25"}}),_v(" "),_c('a',{attrs:{"href":"https://markbind.org/"}},[_v("MarkBind 5.2.0")])]),_v(" on Mon, Jan 15, 2024, 1:21:17 PM UTC]"),_c('br'),_v(" "),_c('span',{staticClass:"dimmed"},[_c('small',[_c('small',[_v("favicon.ico of this site was made by "),_c('a',{attrs:{"href":"https://www.flaticon.com/authors/smashicons","title":"Smashicons"}},[_v("Smashicons")]),_v(" from "),_c('a',{attrs:{"href":"https://www.flaticon.com/","title":"Flaticon"}},[_v("www.flaticon.com")]),_v(" is licensed by "),_c('a',{attrs:{"href":"http://creativecommons.org/licenses/by/3.0/","title":"Creative Commons BY 3.0","target":"_blank"}},[_v("CC 3.0 BY")])])])])])])])} +}]; + \ No newline at end of file diff --git a/cs3282-index.html b/cs3282-index.html new file mode 100644 index 000000000..a2085e7a4 --- /dev/null +++ b/cs3282-index.html @@ -0,0 +1,23 @@ + + + + + + + CS3282 - 2024 Batch + + + + + + + + +

CS3282 - 2024 Batch

CATcher:

MarkBind:

RepoSense:

TEAMMATES:

CATcher

GOH YEE CHONG, GABRIEL

LEE XIONG JIE, ISAAC

VIGNESH SANKAR IYER

WONG CHEE HONG

MarkBind

CHAN YU CHENG

ELTON GOH JUN HAO

HANNAH CHIA KAI XIN

LEE WEI, DAVID

RepoSense

CHARISMA KAUSAR

DAVID GARETH ONG

GOKUL RAJIV

MARCUS TANG XIN KYE

TEAMMATES

CHANG WENG YEW, NICOLAS

DOMINIC LIM KAI JUN

JAY ALJELO SAEZ TING

KEVIN FOONG WEI TONG

MOK KHENG SHENG FERGUS

NEO WEI QING

ONG JUN HENG, CEDRIC

SIM SING YEE, EUNICE

ZHANG ZIQING

+ + + diff --git a/cs3282-index.page-vue-render.js b/cs3282-index.page-vue-render.js new file mode 100644 index 000000000..321151d36 --- /dev/null +++ b/cs3282-index.page-vue-render.js @@ -0,0 +1,49 @@ + + var pageVueRenderFn = function anonymous( +) { +with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""}},[_c('navbar',{attrs:{"placement":"top","type":"primary"},scopedSlots:_u([{key:"brand",fn:function(){return [_c('a',{staticClass:"navbar-brand",attrs:{"href":"/2024/index.html","title":"Home"}},[_v("CS3281&2-2024/Students")])]},proxy:true},{key:"right",fn:function(){return [_c('li',[_c('a',{staticClass:"nav-link",attrs:{"href":"https://github.com/nus-cs3281/2024"}},[_c('span',[_c('span',{staticClass:"fab fa-github",attrs:{"aria-hidden":"true"}})])])])]},proxy:true}])},[_v(" "),_c('dropdown',{staticClass:"nav-link",scopedSlots:_u([{key:"header",fn:function(){return [_v("CS3281")]},proxy:true}])},[_v(" "),_c('li',[_c('a',{staticClass:"dropdown-item",attrs:{"href":"/2024/index.html"}},[_v("Students")])]),_v(" "),_c('li',[_c('a',{staticClass:"dropdown-item",attrs:{"href":"/2024/students/knowledge.html"}},[_v("Knowledge")])]),_v(" "),_c('li',[_c('a',{staticClass:"dropdown-item",attrs:{"href":"https://nus-cs3281.github.io/2024-dashboard/?search=&sort=groupTitle&sortWithin=title&timeframe=commit&mergegroup=&groupSelect=groupByAuthors&breakdown=false"}},[_v("Code Dashboard")])])]),_v(" "),_c('dropdown',{staticClass:"nav-link",scopedSlots:_u([{key:"header",fn:function(){return [_v("CS3282")]},proxy:true}])},[_v(" "),_c('li',[_c('a',{staticClass:"dropdown-item",attrs:{"href":"/2024/cs3282-index.html"}},[_v("Students")])]),_v(" "),_c('li',[_c('a',{staticClass:"dropdown-item",attrs:{"href":"/2024/students/talksSchedule.html"}},[_v("Lightning Talks")])])]),_v(" "),_c('li',[_c('a',{staticClass:"nav-link",attrs:{"href":"/2024/instructions.html"}},[_v("Instructions")])]),_v(" "),_c('li',[_c('a',{staticClass:"nav-link",attrs:{"href":"https://nus-cs3281.github.io/website/"}},[_v("CS3281&2 Website "),_c('span',[_c('span',{staticClass:"glyphicon glyphicon-share-alt",attrs:{"aria-hidden":"true"}})])])])],1)],1),_v(" "),_c('div',{attrs:{"id":"flex-body"}},[_c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_m(0),_v(" "),_m(1),_v(" "),_m(2),_v(" "),_m(3),_v(" "),_m(4),_v(" "),_m(5),_v(" "),_m(6),_v(" "),_m(7),_v(" "),_m(8),_v(" "),_m(9),_v(" "),_c('div',[_c('box',[_c('h2',{attrs:{"id":"goh-yee-chong-gabriel"}},[_v("GOH YEE CHONG, GABRIEL"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#goh-yee-chong-gabriel","onclick":"event.stopPropagation()"}})]),_v(" "),_c('div',{staticClass:"container"},[_c('div',{staticClass:"row"},[_c('div',{staticClass:"col"},[_c('img',{attrs:{"src":"/2024/students/gycgabriel/photo.png","width":"100"}}),_c('br')]),_v(" "),_c('div',{staticClass:"col"},[_c('p',[_c('strong',[_v("GitHub:")]),_v(" "),_c('span',[_c('a',{attrs:{"href":"https://www.github.com/gycgabriel"}},[_v("https://www.github.com/gycgabriel")])]),_c('br')]),_v(" "),_c('p',[_c('strong',[_v("Projects:")]),_v(" "),_c('span',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher"}},[_v("CATcher")]),_v(", "),_c('a',{attrs:{"href":""}})])])])])]),_v(" "),_c('p'),_v(" "),_c('panel',{attrs:{"minimized":""},scopedSlots:_u([{key:"header",fn:function(){return [_c('p',[_c('strong',[_v("Progress")])])]},proxy:true}])},[_v(" "),_c('div')]),_v(" "),_c('panel',{attrs:{"minimized":""},scopedSlots:_u([{key:"header",fn:function(){return [_c('p',[_c('strong',[_v("Knowledge gained")])])]},proxy:true}])},[_v(" "),_c('div',[_c('h3',{attrs:{"id":"error-messages-and-hint-labels-in-angular-forms"}},[_v("Error messages and Hint labels in Angular forms"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#error-messages-and-hint-labels-in-angular-forms","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Forms have a "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("FormGroup")]),_v(", where each part of the form is controled by a "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("FormControl")]),_v(" component.")]),_v(" "),_c('p',[_v("In the ts file, Validators check and ensure the form is valid for submission. If it is not, the submit button is greyed out.")]),_v(" "),_c('p',[_v("In the html file, the individual form input boxes are built, and shown with "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("*ngIf")]),_v(" statements. "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("")]),_v(" also has additional parameters to specify whether the input is required and the max length of the input. The form error messages are programmed here in the html file, for example:")]),_v(" "),_c('pre',[_c('code',{pre:true,attrs:{"class":"hljs"}},[_c('span',[_v("\n")]),_c('span',[_v(" Title required.\n")]),_c('span',[_v("\n")])])]),_c('p',[_v("Hint labels can be used to show the remaining characters in a input box with limited characters when approaching that limit.")]),_v(" "),_c('p',[_v("While a string with validators could be used to instantiate a "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("FormGroup")]),_v(", a "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("FormControl")]),_v(" element ensured that validators are processed such that the form error messages are shown in components that are children to other Angular components. (PR "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher/pull/861"}},[_v("#861")]),_v(")")]),_v(" "),_c('p',[_v("Resources:")]),_v(" "),_c('ul',[_c('li',[_c('a',{attrs:{"href":"https://www.kiltandcode.com/2020/08/13/show-validation-error-messages-for-reactive-forms-in-angular-9/"}},[_v("Show Validation Error Messages for Reactive Forms in Angular 9")])])]),_v(" "),_c('h3',{attrs:{"id":"lifecycle-hooks-in-angular"}},[_v("Lifecycle Hooks in Angular"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#lifecycle-hooks-in-angular","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("After a component is instantiated, the ts file has lifecycle hooks in the form of methods that initialize or modify the component content or state. These methods are prefixed with "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("ng")]),_v(".")]),_v(" "),_c('p',[_v("The sequence in which these lifecycle hooks are called:")]),_v(" "),_c('ul',[_c('li',[_v("OnChanges")]),_v(" "),_c('li',[_v("OnInit")]),_v(" "),_c('li',[_v("DoCheck - repeated")]),_v(" "),_c('li',[_v("AfterContentInit")]),_v(" "),_c('li',[_v("AfterContentChecked - repeated")]),_v(" "),_c('li',[_v("AfterViewInit")]),_v(" "),_c('li',[_v("AfterViewChecked - repeated")]),_v(" "),_c('li',[_v("OnDestroy")])]),_v(" "),_c('p',[_v("Most notably used is "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("ngOnInit")]),_v(", which used to instantiate the component variables. In CATcher, "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("ngAfterViewInit")]),_v(" is also used to load issues after the component has been initialized.")]),_v(" "),_c('p',[_v("Resources:")]),_v(" "),_c('ul',[_c('li',[_c('a',{attrs:{"href":"https://angular.io/guide/lifecycle-hooks"}},[_v("Lifecycle Hooks")])]),_v(" "),_c('li',[_c('a',{attrs:{"href":"https://blog.logrocket.com/angular-lifecycle-hooks/"}},[_v("Angular lifecycle hooks explained")])]),_v(" "),_c('li',[_c('a',{attrs:{"href":"https://stackoverflow.com/questions/40817336/whats-the-difference-between-ngoninit-and-ngafterviewinit-of-angular2#:~:text=ngOnInit()%20is%20called%20right,its%20children's%20views%2C%20are%20created"}},[_v("What's the difference between ngOnInit and ngAfterViewInit of Angular2?")])]),_v(" "),_c('li',[_c('a',{attrs:{"href":"https://www.youtube.com/watch?v=kKtrHrciIVs&ab_channel=WebTechTalk"}},[_v("Video: Angular - Zero to Hero - Life Cycle Hooks")])])]),_v(" "),_c('h3',{attrs:{"id":"viewchild-in-angular"}},[_v("ViewChild in Angular"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#viewchild-in-angular","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("While html files can add custom child components using custom defined decorators such as "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("")]),_v(", the parent component may need references to these children components to add change content or add interactability. ViewChild, ContentChild are queries to access child components from the parent component.")]),_v(" "),_c('p',[_v("For example:")]),_v(" "),_c('pre',[_c('code',{pre:true,attrs:{"class":"hljs"}},[_c('span',[_v("@ViewChild(ViewIssueComponent, { static: false }) viewIssue: ViewIssueComponent;\n")])])]),_c('h4',{attrs:{"id":"static-vs-dynamic-queries"}},[_v("Static vs Dynamic queries"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#static-vs-dynamic-queries","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Static queries are queries on child components that do not change during runtime, as such result of the reference to the child component can be made available in "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("ngOnInit")]),_v(".")]),_v(" "),_c('p',[_v("Dynamic queries are queries on child components that change during runtime, so reference to child component can only be made available in "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("ngAfterViewInit")]),_v(".")]),_v(" "),_c('p',[_v("Resources:")]),_v(" "),_c('ul',[_c('li',[_c('a',{attrs:{"href":"https://blog.angular-university.io/angular-viewchild/"}},[_v("Angular @ViewChild")])]),_v(" "),_c('li',[_c('a',{attrs:{"href":"https://angular.io/guide/static-query-migration#what-does-this-flag-mean-and-why-is-it-necessary"}},[_v("Static query migration guide")])]),_v(" "),_c('li',[_c('a',{attrs:{"href":"https://www.youtube.com/watch?v=4YmnbGoh49U&ab_channel=AngularConnect"}},[_v("Video: Better concepts, less code in Angular 2 - Victor Savkin and Tobias Bosch")])]),_v(" "),_c('li',[_c('a',{attrs:{"href":"https://stackoverflow.com/questions/34326745/whats-the-difference-between-viewchild-and-contentchild"}},[_v("What's the difference between @ViewChild and @ContentChild?")])])]),_v(" "),_c('h3',{attrs:{"id":"property-binding"}},[_v("Property Binding"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#property-binding","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Square brackets in html tags in angular indicate that the right hand side is a dynamic expression. For example:")]),_v(" "),_c('pre',[_c('code',{pre:true,attrs:{"class":"hljs"}},[_c('span',[_v("\n")]),_c('span',[_v("\n")])])]),_c('p',[_v("The dynamic expression can be evaluated in the context of the corresponding .ts file of the html file.")]),_v(" "),_c('h3',{attrs:{"id":"event-binding"}},[_v("Event binding"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#event-binding","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Parenthesis within html tags, for example "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("(click)")]),_v(" are used to call the component's corresponding method on click. In the example above, "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("$event.stopPropagation()")]),_v(" is a Javascript call that prevents the label "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Disagree")]),_v(" within the issue bar from being clickable because its parent is clickable. The click event from parent is stopped from propagating to this particular child.")]),_v(" "),_c('p',[_v("Resources:")]),_v(" "),_c('ul',[_c('li',[_c('a',{attrs:{"href":"https://angular.io/guide/property-binding"}},[_v("Angular Doc Property Binding")])]),_v(" "),_c('li',[_c('a',{attrs:{"href":"https://angular.io/guide/event-binding"}},[_v("Angular Doc Event Binding")])]),_v(" "),_c('li',[_c('a',{attrs:{"href":"https://stackoverflow.com/a/35944965"}},[_v("StackOverflow simple summary")])]),_v(" "),_c('li',[_c('a',{attrs:{"href":"https://stackoverflow.com/questions/32315647/javascript-how-does-event-stoppropagation-work"}},[_v("StackOverflow Stop Propagation")])])]),_v(" "),_c('h3',{attrs:{"id":"git-rebase"}},[_v("Git Rebase"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#git-rebase","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Below is a link to a good explanation with visuals to explain rebasing. Rebasing helped to clean the commit history of my main branch after accidental merging with other branches.")]),_v(" "),_c('p',[_v("Resource:")]),_v(" "),_c('ul',[_c('li',[_c('a',{attrs:{"href":"https://stackoverflow.com/a/29049698"}},[_v("github fork : your branch is 5 commits ahead how to clean this without pushing")]),_v(" |")])]),_v(" "),_c('h3',{attrs:{"id":"github-file-upload-api-createfile-vs-createtree"}},[_v("Github File Upload API: CreateFile vs CreateTree"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#github-file-upload-api-createfile-vs-createtree","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("The API for committing a single file and committing multiple files at once are different.\nAttempting to do multiple single file commits in a short duration of time will likely cause HttpError to occur. The current recommeded fix is to put in sleep before the next single file commit, or merge multiple single file commits into a single multiple file commit.")]),_v(" "),_c('p',[_v("Resources:")]),_v(" "),_c('ul',[_c('li',[_c('a',{attrs:{"href":"https://stackoverflow.com/a/58837709"}},[_v("Use Octokit or the GitHub Rest API to upload multiple files")])]),_v(" "),_c('li',[_c('a',{attrs:{"href":"https://stackoverflow.com/a/19732043"}},[_v("GITHub API Issue with file upload")])]),_v(" "),_c('li',[_c('a',{attrs:{"href":"https://gist.github.com/StephanHoyer/91d8175507fcae8fb31a"}},[_v("Committing multiple files code gist Octokat")])]),_v(" "),_c('li',[_c('a',{attrs:{"href":"https://github.com/octokit/octokit.js/issues/1308"}},[_v("Octokit Pushing a tree")])]),_v(" "),_c('li',[_c('a',{attrs:{"href":"https://stackoverflow.com/questions/61583403/edit-multiple-files-in-single-commit-with-github-api"}},[_v("Github API Edit multiple files upload")])])])])]),_v(" "),_c('panel',{attrs:{"minimized":""},scopedSlots:_u([{key:"header",fn:function(){return [_c('p',[_c('strong',[_v("Observations")]),_v(" from external projects")])]},proxy:true}])},[_v(" "),_c('div',[_c('h3',{attrs:{"id":"project-foo"}},[_v("Project: Foo"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#project-foo","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Give an intro to the project here ...")]),_v(" "),_c('h3',{attrs:{"id":"my-contributions"}},[_v("My Contributions"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#my-contributions","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Give a description of your contributions, including links to relevant PRs")]),_v(" "),_c('h3',{attrs:{"id":"my-learning-record"}},[_v("My Learning Record"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#my-learning-record","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Give tools/technologies you learned here. Include resources you used, and a brief summary of the resource.")])])])],1)],1),_v(" "),_c('div',[_c('box',[_c('h2',{attrs:{"id":"lee-xiong-jie-isaac"}},[_v("LEE XIONG JIE, ISAAC"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#lee-xiong-jie-isaac","onclick":"event.stopPropagation()"}})]),_v(" "),_c('div',{staticClass:"container"},[_c('div',{staticClass:"row"},[_c('div',{staticClass:"col"},[_c('img',{attrs:{"src":"/2024/students/luminousleek/photo.png","width":"100"}}),_c('br')]),_v(" "),_c('div',{staticClass:"col"},[_c('p',[_c('strong',[_v("GitHub:")]),_v(" "),_c('span',[_c('a',{attrs:{"href":"https://www.github.com/luminousleek"}},[_v("https://www.github.com/luminousleek")])]),_c('br')]),_v(" "),_c('p',[_c('strong',[_v("Projects:")]),_v(" "),_c('span',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher"}},[_v("CATcher")])])])])])]),_v(" "),_c('p'),_v(" "),_c('panel',{attrs:{"minimized":""},scopedSlots:_u([{key:"header",fn:function(){return [_c('p',[_c('strong',[_v("Progress")])])]},proxy:true}])},[_v(" "),_c('div')]),_v(" "),_c('panel',{attrs:{"minimized":""},scopedSlots:_u([{key:"header",fn:function(){return [_c('p',[_c('strong',[_v("Knowledge gained")])])]},proxy:true}])},[_v(" "),_c('div',[_c('h3',{attrs:{"id":"css-flexbox"}},[_v("CSS Flexbox"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#css-flexbox","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Flexbox is used to order, align and space out items in a one dimensional container (i.e. a row or a column), even when the size of the items are unknown or dynamic.")]),_v(" "),_c('p',[_v("Items can be given a default size ("),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("flex-basis")]),_v("), and can also grow ("),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("flex-grow")]),_v(") and shrink ("),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("flex-shrink")]),_v(") according to the extra space in the container (or lack thereof). These three properties can be controlled with the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("flex")]),_v(" property, e.g.")]),_v(" "),_c('pre',[_c('code',{pre:true,attrs:{"class":"hljs css"}},[_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-selector-class"}},[_v(".item")]),_v(" {\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-attribute"}},[_v("flex")]),_v(": "),_c('span',{pre:true,attrs:{"class":"hljs-number"}},[_v("0")]),_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-number"}},[_v("1")]),_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-number"}},[_v("10%")]),_v("\n")]),_c('span',[_v("}\n")])])]),_c('p',[_v("where the three parameters correspond to "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("flex-grow")]),_v(", "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("flex-shrink")]),_v(" and "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("flex-basis")]),_v(" respectively. In this case, the default width of the item is 10% of the width of the container, and it does not grow nor shrink relative to the other items (assuming the other items also have their "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("flex")]),_v(" property set to "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("0 1 auto")]),_v(").")]),_v(" "),_c('p',[_v("The "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("flex-basis")]),_v(" property can also be set to the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("content")]),_v(" keyword, where the width of the item is based on the content within the item (e.g. if it contains text, then the width of the item is the length of the text string). This allows for dynamically sized items within the container, which may enable the layout to look cleaner.")]),_v(" "),_c('p',[_v("For a helpful summary of flexbox properties, visit "),_c('a',{attrs:{"href":"https://css-tricks.com/snippets/css/a-guide-to-flexbox/"}},[_v("https://css-tricks.com/snippets/css/a-guide-to-flexbox/")])]),_v(" "),_c('h3',{attrs:{"id":"prettier-husky-and-pretty-quick"}},[_v("Prettier, husky and pretty-quick"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#prettier-husky-and-pretty-quick","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Prettier is a tool to format code according to a given code style automatically. Unlike a linter such as TSLint, prettier only cares about formatting, rather than detecting programming errors. Prettier supports both Typescript and Angular, which CATcher is written in.")]),_v(" "),_c('p',[_v("Since it is quite wasteful to run prettier to format the entire codebase every time a change is made, so a more efficient method is to format the codebase once, and then format only the changes made during each commit.")]),_v(" "),_c('p',[_v("This is where the husky tool comes in, which enables hooks to be run before each commit. The relevant hook here is pretty-quick, and this formats the changed/staged files during each commit. This frees developers from having to fuss with maintaining code formatting or fixing formatting mistakes, leading to less frustration.")]),_v(" "),_c('p',[_v("For more information, visit "),_c('a',{attrs:{"href":"https://prettier.io"}},[_v("Prettier")]),_v(" and "),_c('a',{attrs:{"href":"https://typicode.github.io/husky/"}},[_v("husky")])]),_v(" "),_c('h3',{attrs:{"id":"arcsecond"}},[_v("Arcsecond"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#arcsecond","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_c('a',{attrs:{"href":"https://github.com/francisrstokes/arcsecond"}},[_v("Arcsecond")]),_v(" is a zero-dependency parser combinator library for Javascript that is now being used in CATcher to parse GitGub issues and comments.")]),_v(" "),_c('p',[_v("Previously in order to parse the comments, we used the regex string "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("(${headerString})\\\\s+([\\\\s\\\\S]*?)(?=${headerString}|$)\\gi")]),_v(" which is neither human readable nor maintainable. In addition, this string only finds matches - more regex is used to extract relevant information from the comments.")]),_v(" "),_c('p',[_v("In comparison, arcsecond offers human friendly parsers such as "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("str")]),_v(", "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("char")]),_v(", "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("letters")]),_v(", "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("digits")]),_v(", "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("between")]),_v(" and so on, and these parsers can be composed and run in sequence. This makes building and maintaining parsers much easier. In addition, arcsecond also allows you to extract certain information from a string (as opposed to the entire string) by way of the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("coroutine")]),_v(" parser.")]),_v(" "),_c('p',[_v("For example, take the string \"Today is Wednesday and the weather is 30 degrees Celsius\", and you want to extract the day (Wednesday) and the temperature (30). One parser that can achieve that is:")]),_v(" "),_c('pre',[_c('code',{pre:true,attrs:{"class":"hljs typescript"}},[_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("const")]),_v(" dayWeatherParser = coroutine("),_c('span',{pre:true,attrs:{"class":"hljs-function"}},[_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("function")]),_v("*("),_c('span',{pre:true,attrs:{"class":"hljs-params"}}),_v(") ")]),_v("{\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("yield")]),_v(" str("),_c('span',{pre:true,attrs:{"class":"hljs-string"}},[_v("\"Today is \"")]),_v("); "),_c('span',{pre:true,attrs:{"class":"hljs-comment"}},[_v("// parse and ignore")]),_v("\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("const")]),_v(" day = "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("yield")]),_v(" letters; "),_c('span',{pre:true,attrs:{"class":"hljs-comment"}},[_v("// parse 'Wednesday' and store")]),_v("\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("yield")]),_v(" str("),_c('span',{pre:true,attrs:{"class":"hljs-string"}},[_v("\" and the weather is \"")]),_v("); "),_c('span',{pre:true,attrs:{"class":"hljs-comment"}},[_v("// parse and ignore")]),_v("\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("const")]),_v(" temperature = "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("yield")]),_v(" digits; "),_c('span',{pre:true,attrs:{"class":"hljs-comment"}},[_v("// parse '30' and store")]),_v("\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("yield")]),_v(" str("),_c('span',{pre:true,attrs:{"class":"hljs-string"}},[_v("\" degrees Celsius\"")]),_v("); "),_c('span',{pre:true,attrs:{"class":"hljs-comment"}},[_v("// parse and ignore")]),_v("\n")]),_c('span',[_v("\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("return")]),_v(" {\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-attr"}},[_v("day")]),_v(": day,\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-attr"}},[_v("temperature")]),_v(": temperature\n")]),_c('span',[_v(" }\n")]),_c('span',[_v("})\n")])])]),_c('p',[_v("This allows us to build complex and versatile parsers easily, yet in a way that is clear and understandable. For more information, check out the "),_c('a',{attrs:{"href":"https://github.com/francisrstokes/arcsecond/blob/master/tutorial/tutorial-part-1.md"}},[_v("tutorial here")])]),_v(" "),_c('h3',{attrs:{"id":"jasmine"}},[_v("Jasmine"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#jasmine","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_c('a',{attrs:{"href":"https://jasmine.github.io/"}},[_v("Jasmine")]),_v(" is a testing framework for Javascript code. In Jasmine, test suites are functions in "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("describe")]),_v(" blocks, and each spec is also a function in an "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("it")]),_v(" block.")]),_v(" "),_c('p',[_v("For example, here is a suite that tests a certain function:")]),_v(" "),_c('pre',[_c('code',{pre:true,attrs:{"class":"hljs typescript"}},[_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-function"}},[_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("function")]),_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-title"}},[_v("testMethod")]),_v("("),_c('span',{pre:true,attrs:{"class":"hljs-params"}}),_v(") ")]),_v("{\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("return")]),_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-literal"}},[_v("true")]),_v(";\n")]),_c('span',[_v("}\n")]),_c('span',[_v("\n")]),_c('span',[_v("describe("),_c('span',{pre:true,attrs:{"class":"hljs-string"}},[_v("\"testMethod suite\"")]),_v(", "),_c('span',{pre:true,attrs:{"class":"hljs-function"}},[_v("() =>")]),_v(" {\n")]),_c('span',[_v(" it("),_c('span',{pre:true,attrs:{"class":"hljs-string"}},[_v("\"testMethod should return true\"")]),_v(", "),_c('span',{pre:true,attrs:{"class":"hljs-function"}},[_v("() =>")]),_v(" {\n")]),_c('span',[_v(" expect(testMethod()).toBe("),_c('span',{pre:true,attrs:{"class":"hljs-literal"}},[_v("true")]),_v(");\n")]),_c('span',[_v(" });\n")]),_c('span',[_v("});\n")])])]),_c('p',[_v("Expectations are built with the function "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("expect")]),_v(" which takes a value ("),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("testMethod()")]),_v(" in the example above), and is chained with a "),_c('a',{attrs:{"href":"https://jasmine.github.io/api/edge/matchers.html"}},[_v("Matcher")]),_v(" such as "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("toBe")]),_v(", "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("toEqual")]),_v(" or "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("toBeGreaterThan")]),_v(". This provides greater flexibility than say JUnit's assert methods, since one assert method corresponds to one condition.")]),_v(" "),_c('p',[_v("Since test suites and specs are functions, normal Javascript scoping rules apply, so variables can be shared between specs. In addition, there are separate setup and teardown methods such as "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("beforeEach")]),_v(" and "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("afterAll")]),_v(".")]),_v(" "),_c('p',[_v("For more information, check out the "),_c('a',{attrs:{"href":"https://jasmine.github.io/tutorials/your_first_suite"}},[_v("Your First Suite tutorial here")])])])]),_v(" "),_c('panel',{attrs:{"minimized":""},scopedSlots:_u([{key:"header",fn:function(){return [_c('p',[_c('strong',[_v("Observations")]),_v(" from external projects")])]},proxy:true}])},[_v(" "),_c('div',[_c('h3',{attrs:{"id":"project-foo-2"}},[_v("Project: Foo"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#project-foo-2","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Give an intro to the project here ...")]),_v(" "),_c('h3',{attrs:{"id":"my-contributions-2"}},[_v("My Contributions"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#my-contributions-2","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Give a description of your contributions, including links to relevant PRs")]),_v(" "),_c('h3',{attrs:{"id":"my-learning-record-2"}},[_v("My Learning Record"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#my-learning-record-2","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Give tools/technologies you learned here. Include resources you used, and a brief summary of the resource.")])])])],1)],1),_v(" "),_c('div',[_c('box',[_c('h2',{attrs:{"id":"vignesh-sankar-iyer"}},[_v("VIGNESH SANKAR IYER"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#vignesh-sankar-iyer","onclick":"event.stopPropagation()"}})]),_v(" "),_c('div',{staticClass:"container"},[_c('div',{staticClass:"row"},[_c('div',{staticClass:"col"},[_c('img',{attrs:{"src":"/2024/students/vigneshsankariyer1234567890/photo.png","width":"100"}}),_c('br')]),_v(" "),_c('div',{staticClass:"col"},[_c('p',[_c('strong',[_v("GitHub:")]),_v(" "),_c('span',[_c('a',{attrs:{"href":"https://github.com/vigneshsankariyer1234567890"}},[_v("https://github.com/vigneshsankariyer1234567890")])]),_c('br')]),_v(" "),_c('p',[_c('strong',[_v("Projects:")]),_v(" "),_c('span',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher"}},[_v("CATcher")])])])])])]),_v(" "),_c('p'),_v(" "),_c('panel',{attrs:{"minimized":""},scopedSlots:_u([{key:"header",fn:function(){return [_c('p',[_c('strong',[_v("Progress")])])]},proxy:true}])},[_v(" "),_c('div')]),_v(" "),_c('panel',{attrs:{"minimized":""},scopedSlots:_u([{key:"header",fn:function(){return [_c('p',[_c('strong',[_v("Knowledge gained")])])]},proxy:true}])},[_v(" "),_c('div',[_c('h3',{attrs:{"id":"angular"}},[_v("Angular"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#angular","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Having had experience in mainly React and NodeJS projects earlier, I was overall more used to creating projects with Functional Components, rather than Class Components as with Angular. However, I realised that one of the key aspects of frontend frameworks, namely reactivity, was in fact the main drivers of development of such frameworks in the first place!")]),_v(" "),_c('p',[_v("In fact, even React were originally championing the idea of Class Components in order to isolate various web components into areas or responsibility, following rule number 1 of Software Engineering: Single Responsibility. However, while React is largely unopinionated in how you structure your code with regards to the coupling of business logic and HTML, Angular differs by dictating where and how you structure your components.")]),_v(" "),_c('p',[_v("Angular separates components into modules which comprise of 3 to 4 files:")]),_v(" "),_c('ul',[_c('li',[_v("Components, which are necessarily TypeScript classes which have the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("@Component")]),_v(" decorator;")]),_v(" "),_c('li',[_v("Templates, which dictate the HTML that is produced and rendered by the component;")]),_v(" "),_c('li',[_v("Styles, which dictate the type of styling to apply to the component.")]),_v(" "),_c('li',[_v("Module, which indicate the modules or services that are to be imported by the component. Interestingly,")])]),_v(" "),_c('p',[_v("On the other hand, React only dictates that class components should produce some sort of HTML using the render function. Even this is removed with the introduction of Functional Components that are simply functions which render and produce some HTML. React introduces hooks which are often used by developers to manage some state at the component level, using functions with side effects.")]),_v(" "),_c('p',[_v("Each method has its positives and negatives. Because of its opinionated nature, Angular makes it easy to standardize frontend coding standards and pattern across an entire enterprise, making it an apt choice to use as a tool for OSS development. On the other hand, React allows you to develop code more quickly, with more attention needed to be paid at the rendering lifecycles in order to let the Virtual DOM know when a particular component needs to be rendered again. On top of this, Angular wholely separates business logic from rendered HTML, whereas React takes the does not make this distinction.")]),_v(" "),_c('p',[_v("Another key point is how React and Angular differentiate in providing context (sharing or passing down state between different branches of the DOM tree). React has its own Context API that is used to share some sort of state between different components, whereas Angular does this by the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("providers")]),_v(" declaration in the module folder, which results in a set of singletons that are shared by components that exist below it in the tree.")]),_v(" "),_c('h3',{attrs:{"id":"rxjs"}},[_v("RxJS"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#rxjs","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("I also picked up RxJS along the way, which was Angular's answer to creating reactive components. RxJS essentially deals with asynchronous pipe/filter, publisher/subscriber behavior which allows values to change and other components or functions to subscribe to these changes. This works considering Angular's Change Detection strategy which I will explain later.")]),_v(" "),_c('p',[_v("In comparison, React introduced and adopted hooks to encapsulate the behavior of having to rerender. React does this by operating on a Virtual DOM, and appropriately rerendering components and their children in patches when a change was detected. On the other hand, Angular does not have any abstraction to operate and rerender components whose state have changed. Instead, Angular uses a Change Detection Strategy which can be configured by the user (either onPush or Default). Angular Change Detection works by using Zone.js and activating after every async action performed. CD traversal starts at the root component (usually App) and works its way down the component tree updating the DOM as needed. What's happening under the hood is that browser events are registered into Zone.js - Angular's mechanism for orchestrating async events - which emits changes after initial template bindings are created.\n...")])])]),_v(" "),_c('panel',{attrs:{"minimized":""},scopedSlots:_u([{key:"header",fn:function(){return [_c('p',[_c('strong',[_v("Observations")]),_v(" from external projects")])]},proxy:true}])},[_v(" "),_c('div',[_c('h3',{attrs:{"id":"project-foo-3"}},[_v("Project: Foo"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#project-foo-3","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Give an intro to the project here ...")]),_v(" "),_c('h3',{attrs:{"id":"my-contributions-3"}},[_v("My Contributions"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#my-contributions-3","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Give a description of your contributions, including links to relevant PRs")]),_v(" "),_c('h3',{attrs:{"id":"my-learning-record-3"}},[_v("My Learning Record"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#my-learning-record-3","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Give tools/technologies you learned here. Include resources you used, and a brief summary of the resource.")])])])],1)],1),_v(" "),_c('div',[_c('box',[_c('h2',{attrs:{"id":"wong-chee-hong"}},[_v("WONG CHEE HONG"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#wong-chee-hong","onclick":"event.stopPropagation()"}})]),_v(" "),_c('div',{staticClass:"container"},[_c('div',{staticClass:"row"},[_c('div',{staticClass:"col"},[_c('img',{attrs:{"src":"/2024/students/cheehongw/photo.png","width":"100"}}),_c('br')]),_v(" "),_c('div',{staticClass:"col"},[_c('p',[_c('strong',[_v("GitHub:")]),_v(" "),_c('span',[_c('a',{attrs:{"href":"https://www.github.com/cheehongw"}},[_v("https://www.github.com/cheehongw")])]),_c('br')]),_v(" "),_c('p',[_c('strong',[_v("Projects:")]),_v(" "),_c('span',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher"}},[_v("CATcher")])])])])])]),_v(" "),_c('p'),_v(" "),_c('panel',{attrs:{"minimized":""},scopedSlots:_u([{key:"header",fn:function(){return [_c('p',[_c('strong',[_v("Progress")])])]},proxy:true}])},[_v(" "),_c('div')]),_v(" "),_c('panel',{attrs:{"minimized":""},scopedSlots:_u([{key:"header",fn:function(){return [_c('p',[_c('strong',[_v("Knowledge gained")])])]},proxy:true}])},[_v(" "),_c('div',[_c('h2',{attrs:{"id":"angular-essentials"}},[_v("Angular Essentials"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#angular-essentials","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("I had contributed to CATcher as part of IWM, but I have never really approached the Angular aspects of the project.")]),_v(" "),_c('p',[_v("Essentially, the core ideas behind Angular involves:")]),_v(" "),_c('ul',[_c('li',[_v("Components, a TypeScript class with "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("@Component")]),_v(" decorator, an HTML template and styles.\n"),_c('ul',[_c('li',[_v("The decorator accepts parameters that help Angular know which HTML file is the component's template and which css file is the component's styles.")]),_v(" "),_c('li',[_v("The decorator also accepts a parameter that is the component's selector, which is how we can reuse this component as an HTML element in other HTML files.")])])]),_v(" "),_c('li',[_v("An HTML template that instructs Angular how to render the component")]),_v(" "),_c('li',[_v("An optional set of CSS styles that define the appearance of the template's HTML elements")])]),_v(" "),_c('p',[_v("The other key concepts include event bindings and property binding that link the template to the TypeScript class. Knowing these essentials allowed me to fix "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/57"}},[_v("WATcher PR#57")]),_v(".")]),_v(" "),_c('p',[_v("Another key part of Angular is its Dependency Injection system and services. Angular allows us to provide dependencies at different levels of the application, and how the dependencies are instantiated.")]),_v(" "),_c('ul',[_c('li',[_v("For example, when you providing a service at the root level, Angular creates a single, shared instance of the service and injects it into any class that asks for it.")]),_v(" "),_c('li',[_v("Also, it seems like most of WATcher and CATcher's services are provided at the root level.")])]),_v(" "),_c('p',[_v("Finally, as part of fixing \""),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/92"}},[_v("Remove label-filter-bar as module export #92")]),_v("\", I also learned about how related components are organized and grouped into modules. Each Module are self-contained and provide a certain set of functionality and components related to that module, thereby achieving separation of concerns.")]),_v(" "),_c('p',[_v("Resources:")]),_v(" "),_c('ul',[_c('li',[_c('a',{attrs:{"href":"https://angular.io/guide/what-is-angular"}},[_v("https://angular.io/guide/what-is-angular")])]),_v(" "),_c('li',[_c('a',{attrs:{"href":"https://angular.io/guide/dependency-injection"}},[_v("https://angular.io/guide/dependency-injection")])]),_v(" "),_c('li',[_c('a',{attrs:{"href":"https://angular.io/guide/ngmodules"}},[_v("https://angular.io/guide/ngmodules")])])]),_v(" "),_c('h2',{attrs:{"id":"e2e-testing-with-playwright"}},[_v("E2E Testing with Playwright"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#e2e-testing-with-playwright","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("After having 2 separate hotfixes pushed in a single semester, I started to look more deeply into ensuring the robustness of our application. During these 2 hotfixes, bugs were only uncovered during manual testing. However, it is time consuming to conduct manual tests, and we need to find a way to automate it. E2E tests simulate user interactions such as clicks and typing and is a useful way to ensure our end-product is performing as expected.")]),_v(" "),_c('p',[_v("During this semester, one of the high priority issues was to migrate our E2E solution away from Protractor. As such, I have investigated Cypress and Playwright as two potential E2E solutions.")]),_v(" "),_c('h4',{attrs:{"id":"mocking-services"}},[_v("Mocking services"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#mocking-services","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("When performing migration from Protractor to Playwright, I learned about the different strategies E2E tests can be conducted. Typically, we would want to conduct E2E tests against our production server, since that is what our end users will be using. However, since CATcher depends alot on GitHub's API for its functionality, we are unable to perform automated tests against GitHub. A second strategy would be to mock the functions that hit GitHub's API, and we would test solely the functionalities and behaviours of the app. This let me realized that there is a test vs production version of CATcher.")]),_v(" "),_c('p',[_v("I have also looked into whether it is possible to perform E2E testing against the production server, since one of the bugs fixed in the hotfixes can only be caught if we did not adopt a mocking strategy. One of the key feasibility concerns I had with testing against the GitHub API was simulating user authentication. This was because authenticating with GitHub requires multi-factor authentication, something that is difficult to achieve with automated E2E testing. Some potential solutions to bypassing MFA would be to use TOTP, which can be generated programmatically. More research will be needed in this area.")]),_v(" "),_c('h4',{attrs:{"id":"aspects-learnt"}},[_v("Aspects Learnt"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#aspects-learnt","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ul',[_c('li',[_v("Configuring and setting up Playwright for a project.")]),_v(" "),_c('li',[_v("Learned about how Playwright/Cypress/Protractor identifies and interacts with HTML elements using selectors.")]),_v(" "),_c('li',[_v("Learned about how CATcher API calls are mocked during E2E testing")])]),_v(" "),_c('p',[_v("Resources:")]),_v(" "),_c('ul',[_c('li',[_c('a',{attrs:{"href":"https://playwright.dev"}},[_v("https://playwright.dev")])]),_v(" "),_c('li',[_c('a',{attrs:{"href":"https://www.cypress.io/"}},[_v("https://www.cypress.io/")])]),_v(" "),_c('li',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher/pull/539"}},[_v("This pull request by ptvrajsk documenting how he implemented E2E with Protractor")])])]),_v(" "),_c('h2',{attrs:{"id":"github-actions"}},[_v("Github Actions"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#github-actions","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("I also picked up Github Actions when contributing to the CI/CD pipeline in "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/81"}},[_v("Enable linting in Github workflow #81")]),_v(". I learned how Github Actions are set up and how they can be triggered upon pushing to main/master and also on pull requests.")]),_v(" "),_c('p',[_v("Furthermore, I learnt how we can use matrix strategies to run the same job with different parameters, such as different OS and different node versions.")]),_v(" "),_c('p',[_v("Resources:")]),_v(" "),_c('ul',[_c('li',[_c('a',{attrs:{"href":"https://docs.github.com/en/actions/quickstart"}},[_v("https://docs.github.com/en/actions/quickstart")])]),_v(" "),_c('li',[_c('a',{attrs:{"href":"https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs"}},[_v("https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs")])])]),_v(" "),_c('h2',{attrs:{"id":"rxjs-and-the-observer-pattern"}},[_v("RxJS and the Observer Pattern"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#rxjs-and-the-observer-pattern","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Part of working with CATcher source code was frequently encountering Observables and Observers. RxJS supports "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Observers")]),_v(" and "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Observables")]),_v(", allowing updates to some "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Observable")]),_v(" to be received by some "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Observer")]),_v(" that is subscribed to it. With this pattern, we can trigger updates in many dependent objects automatically and asynchronously when some object state changes.")]),_v(" "),_c('p',[_v("Resources:")]),_v(" "),_c('ul',[_c('li',[_c('a',{attrs:{"href":"https://rxjs.dev/"}},[_v("https://rxjs.dev/")])])])])]),_v(" "),_c('panel',{attrs:{"minimized":""},scopedSlots:_u([{key:"header",fn:function(){return [_c('p',[_c('strong',[_v("Observations")]),_v(" from external projects")])]},proxy:true}])},[_v(" "),_c('div',[_c('h3',{attrs:{"id":"project-foo-4"}},[_v("Project: Foo"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#project-foo-4","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Give an intro to the project here ...")]),_v(" "),_c('h3',{attrs:{"id":"my-contributions-4"}},[_v("My Contributions"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#my-contributions-4","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Give a description of your contributions, including links to relevant PRs")]),_v(" "),_c('h3',{attrs:{"id":"my-learning-record-4"}},[_v("My Learning Record"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#my-learning-record-4","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Give tools/technologies you learned here. Include resources you used, and a brief summary of the resource.")])])])],1)],1),_v(" "),_m(10),_v(" "),_c('div',[_c('box',[_c('h2',{attrs:{"id":"chan-yu-cheng"}},[_v("CHAN YU CHENG"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#chan-yu-cheng","onclick":"event.stopPropagation()"}})]),_v(" "),_c('div',{staticClass:"container"},[_c('div',{staticClass:"row"},[_c('div',{staticClass:"col"},[_c('img',{attrs:{"src":"/2024/students/yucheng11122017/photo.png","width":"100"}}),_c('br')]),_v(" "),_c('div',{staticClass:"col"},[_c('p',[_c('strong',[_v("GitHub:")]),_v(" "),_c('span',[_c('a',{attrs:{"href":"https://github.com/yucheng11122017"}},[_v("https://github.com/yucheng11122017")])]),_c('br')]),_v(" "),_c('p',[_c('strong',[_v("Projects:")]),_v(" "),_c('span',[_c('a',{attrs:{"href":"https://github.com/yucheng11122017/markbind"}},[_v("Markbind")])])])])])]),_v(" "),_c('p'),_v(" "),_c('panel',{attrs:{"minimized":""},scopedSlots:_u([{key:"header",fn:function(){return [_c('p',[_c('strong',[_v("Progress")])])]},proxy:true}])},[_v(" "),_c('div')]),_v(" "),_c('panel',{attrs:{"minimized":""},scopedSlots:_u([{key:"header",fn:function(){return [_c('p',[_c('strong',[_v("Knowledge gained")])])]},proxy:true}])},[_v(" "),_c('div',[_c('h3',{attrs:{"id":"vue"}},[_v("Vue"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#vue","onclick":"event.stopPropagation()"}})]),_v(" "),_c('h4',{attrs:{"id":"vue-components"}},[_v("Vue components"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#vue-components","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Since Markbind uses Vue components, I had to pick this up, having only experience with React before. I had to learn what is a Vue instance, how to compile Vue and so on.\nResources I used included the Markbind dev page regarding "),_c('a',{attrs:{"href":"https://markbind.org/devdocs/devGuide/design/serverSideRendering.html"}},[_v("SSR")]),_v(" of course, the "),_c('a',{attrs:{"href":"https://vuejs.org/guide/introduction.html"}},[_v("Vue Official Documentation")]),_v(" and "),_c('a',{attrs:{"href":"https://markbind.org/devdocs/devGuide/design/serverSideRendering.html"}},[_v("another Vue tutorial")]),_v(".\nThis was especially useful when dealing with Vue templates in one of my PRs about jQuery, which logged an warning since there was a script tag in the template. I had to learn about side effects in Vue from resources such as this "),_c('a',{attrs:{"href":"https://github.com/vuejs/vue/issues/11697"}},[_v("stackflow post")]),_v(" about Vue disallowing side effects for not just script tags but also style tags.")]),_v(" "),_c('h4',{attrs:{"id":"vue-test-utils"}},[_v("Vue test utils"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#vue-test-utils","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Since every new feature in Markbind required unit testing, I had to create unit tests for the scroll top button component. Therefore, I had to learn how to use Vue Test Utils and its snapshots.\nI had to learn how to")]),_v(" "),_c('ul',[_c('li',[_v("deal with setTimeout. This was probably the hardest part as trying to mock the setTimeout (following this "),_c('a',{attrs:{"href":"https://stackoverflow.com/questions/67981140/how-to-test-settimeout-function-calld-in-vue-created-hook-using-vue-utils-jes"}},[_v("tutorial")]),_v(") and using nextTick (using this "),_c('a',{attrs:{"href":"https://dmitripavlutin.com/vue-next-tick/"}},[_v("tutorial")]),_v(") on Vue test did not work. I had to resort to using setTimeout in the test to wait out the setTimeout in the component.")]),_v(" "),_c('li',[_v("mount components with props and attached to a document")]),_v(" "),_c('li',[_v("dispatch events to trigger the scroll event needed for the scroll top button component")]),_v(" "),_c('li',[_v("test if a function has been called")])]),_v(" "),_c('h3',{attrs:{"id":"jquery-cheerio-and-javascript-for-dom-manipulation"}},[_v("Jquery, Cheerio and Javascript for DOM manipulation"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#jquery-cheerio-and-javascript-for-dom-manipulation","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("As I had to write a plugin and remove jQuery, I became a lot more familiar with DOM manipulation using Cheerio, jQuery and vanilla Javascript. Since I had to remove jQuery from Markbind, this "),_c('a',{attrs:{"href":"https://youmightnotneedjquery.com/"}},[_v("page")]),_v(" was very useful for me to understand how to convert from jQuery to vanilla Javascript. I also learnt from the "),_c('a',{attrs:{"href":"https://api.jquery.com/"}},[_v("jQuery API documentation")]),_v(" about each functions' behavior, especially more advanced functions like wrap and on. Through this PR, I became more familiar with using vanilla Javascript for DOM manipulation as well. For example, how to create elements, add styling and scroll etc.\nBecause the contact form plugin required DOM manipulation, I used cheerio for this PR and learnt about its API calls. The "),_c('a',{attrs:{"href":"https://cheerio.js.org/"}},[_v("cheerio API documentation")]),_v(" was very helpful in my understanding of the calls.")]),_v(" "),_c('h3',{attrs:{"id":"css"}},[_v("CSS"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#css","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("As I worked on some front end bugs, I had to learn more about CSS. Specifically:")]),_v(" "),_c('ul',[_c('li',[_v("How styles override each other. The iconColor in bozes are not working in certain circumstances due to Bootstrap styling. Hence, I had to learn more about overriding in CSS styles. This "),_c('a',{attrs:{"href":"https://www.tutorialspoint.com/Rules-to-override-Style-Sheet-Rule-in-CSS"}},[_v("guide")]),_v(" was useful in teaching me about it and I also about the "),_c('a',{attrs:{"href":"https://www.w3schools.com/css/css_important.asp"}},[_v("important property in CSS")]),_v(" which was what was causing the bug")]),_v(" "),_c('li',[_v("Transitions. The panel transition had some errors with an abrupt transition, which was a bug regarding the CSS transitions. I learnt about how CSS transitions from 0 to the max-height, and if the max-height was not set correctly (in this case it did not include margins) there would be problems.")]),_v(" "),_c('li',[_v("CSS selectors. As I had to style the form plugin and also had to finish up a PR regarding standardising tab buttons, I learnt about CSS selectors used for styling, from selecting by tag to by descendents. This "),_c('a',{attrs:{"href":"http://web.simmons.edu/~grabiner/comm244/weekfour/selectors.html"}},[_v("guide")]),_v(" was useful for my learning")])]),_v(" "),_c('h3',{attrs:{"id":"typescript-and-migration"}},[_v("Typescript and migration"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#typescript-and-migration","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("As I did a typescript migration, I learnt to code in it. Specifically")]),_v(" "),_c('ul',[_c('li',[_v("Different ways to import and export files and functions in Typescript, which differed significantly from Javascript. The "),_c('a',{attrs:{"href":"https://markbind.org/devdocs/devGuide/development/migratingToTypeScript.html#import-export-syntax-reference"}},[_v("Markbind documentation")]),_v(" on that was very useful in my understanding.")]),_v(" "),_c('li',[_v("Defining and importing types. I learnt that npm packages often defined interfaces for their packages, making it easier to convert.")])]),_v(" "),_c('p',[_v("I learnt about the simliarity index about github files. According to the typescript migration documentation, there was a need to have two seperate commits, one to rename and one to adapt. If both were done within one commit, the simliarity index would be below the threshold and the commit history would be lost. This is something that I would definitely take note of in the future when renaming files.")]),_v(" "),_c('p',[_v("I had to do a squash commit for the typescript migration. I learnt about the differences between rebasing vs merging through this "),_c('a',{attrs:{"href":"https://www.atlassian.com/git/tutorials/merging-vs-rebasing"}},[_v("article")]),_v(" and about the pros and cons and dos and don'ts for rebasing. I was encountering the problem where squashing the merge resulted in the PR containing the recent commits from the master branch. This taught me not to miz up merging and rebasing and just do one or the other.")]),_v(" "),_c('h3',{attrs:{"id":"github-actions-2"}},[_v("Github actions"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#github-actions-2","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("I learnt how to configure Github actions as I had to upgrade node version from 14 to 16 in Markbind/markbind-action and to also remove some depreated syntaxes. I learnt about the workflow of github actions and it's purpose.\nI also had to learn how to test GitHub actions. I followed the tutorial in "),_c('a',{attrs:{"href":"https://markbind.org/devdocs/devGuide/githubActions/markbindAction.html"}},[_v("Markbind Dev Guide")]),_v(" on testing and also attempted to use VSCode Extension for Github Actions to test more effectively following this "),_c('a',{attrs:{"href":"https://github.blog/2023-03-28-announcing-the-github-actions-extension-for-vs-code/"}},[_v("tutorial")]),_v(".")]),_v(" "),_c('h3',{attrs:{"id":"nunjucks"}},[_v("Nunjucks"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#nunjucks","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("I learnt about Nunjucks when making documentation updates. Specifically, regarding Nunjucks Macros: how to declare them, write if statements and how to use them. The "),_c('a',{attrs:{"href":"https://mozilla.github.io/nunjucks/getting-started.html"}},[_v("documentation on Nunjucks")]),_v(" are particularly useful.")]),_v(" "),_c('h3',{attrs:{"id":"node-js-versioning"}},[_v("Node.js versioning"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#node-js-versioning","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("I learnt about Node.js versioning when upgrading the Node version and when writing the documentaiton on migrating Node js. For example, odd numbered Node.js versions are unstable and will reach end of life sooner, while even numbered Node.js version will be maintained for a longer period. I also learnt the difference between a major release and minor release, with the "),_c('tooltip',{scopedSlots:_u([{key:"content",fn:function(){return [_v("Eg. 1.0.0 to 2.0.0")]},proxy:true}])},[_v("former increasing the first number")]),_v(" and containing major and breaking changes, while the later has smaller changes which are not breaking.")],1),_v(" "),_c('h3',{attrs:{"id":"deployment"}},[_v("Deployment"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#deployment","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("For the node.js version upgrade, I had to check that the deployment was ok with the higher version. I therefore had to learn how to deploy the sites with github pages,CircleCi and Appveyor and Surge. I didn't do it with Travis due to a persistent account error. I followed the tutorial in the "),_c('a',{attrs:{"href":"https://markbind.org/userGuide/deployingTheSite.html"}},[_v("Markbind tutorial")]),_v(" to learn the deploying for each CI platform.")]),_v(" "),_c('h3',{attrs:{"id":"reuse-principle"}},[_v("Reuse principle"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#reuse-principle","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("There was an issue with Markdown using include within another include, because the outer variable was overriding the inner variable. This causes a cyclical reference error. I was told that this was inline with the golden principle of reuse, where inner variables should be allowed to override the inner variables so that components can be reused without having to change the inner contents.")]),_v(" "),_c('h3',{attrs:{"id":"documentation"}},[_v("Documentation"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#documentation","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("I learnt about the importance of good documentation and how to manage documentation. I think it is quite easy to keep adding things into documentation but it is more important to be able to present information in a way that is presentation and pallatable to users. For example, Markbind had an issue with cyclical references in includes and it would be good to document this. However, since it was an edge case, it was recommended to instead use a panel which was not as noticable so users could easily skip over it if not applicable to them.")])])]),_v(" "),_c('panel',{attrs:{"minimized":""},scopedSlots:_u([{key:"header",fn:function(){return [_c('p',[_c('strong',[_v("Observations")]),_v(" from external projects")])]},proxy:true}])},[_v(" "),_c('div',[_c('h3',{attrs:{"id":"project-foo-5"}},[_v("Project: Foo"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#project-foo-5","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Give an intro to the project here ...")]),_v(" "),_c('h3',{attrs:{"id":"my-contributions-5"}},[_v("My Contributions"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#my-contributions-5","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Give a description of your contributions, including links to relevant PRs")]),_v(" "),_c('h3',{attrs:{"id":"my-learning-record-5"}},[_v("My Learning Record"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#my-learning-record-5","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Give tools/technologies you learned here. Include resources you used, and a brief summary of the resource.")])])])],1)],1),_v(" "),_c('div',[_c('box',[_c('h2',{attrs:{"id":"elton-goh-jun-hao"}},[_v("ELTON GOH JUN HAO"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#elton-goh-jun-hao","onclick":"event.stopPropagation()"}})]),_v(" "),_c('div',{staticClass:"container"},[_c('div',{staticClass:"row"},[_c('div',{staticClass:"col"},[_c('img',{attrs:{"src":"/2024/students/EltonGohJH/photo.png","width":"100"}}),_c('br')]),_v(" "),_c('div',{staticClass:"col"},[_c('p',[_c('strong',[_v("GitHub:")]),_v(" "),_c('span',[_c('a',{attrs:{"href":"https://github.com/EltonGohJH"}},[_v("https://github.com/EltonGohJH")])]),_c('br')]),_v(" "),_c('p',[_c('strong',[_v("Projects:")]),_v(" "),_c('span',[_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind"}},[_v("MarkBind")])])])])])]),_v(" "),_c('p'),_v(" "),_c('panel',{attrs:{"minimized":""},scopedSlots:_u([{key:"header",fn:function(){return [_c('p',[_c('strong',[_v("Progress")])])]},proxy:true}])},[_v(" "),_c('div')]),_v(" "),_c('panel',{attrs:{"minimized":""},scopedSlots:_u([{key:"header",fn:function(){return [_c('p',[_c('strong',[_v("Knowledge gained")])])]},proxy:true}])},[_v(" "),_c('div',[_c('h3',{attrs:{"id":"special-mention-to-chatgpt-and-github-copilot"}},[_v("Special mention to ChatGPT and GitHub Copilot"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#special-mention-to-chatgpt-and-github-copilot","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("A fun fact is that I use ChatGPT and GitHub Copilot for everything in the list below.\nChatGPT just makes it so much easy to write and debug code. ChatGPT has really helped me to picked up the technology and tools mentioned below.\nI find that GitHub Copilot is super helpful when writing boiler plates code and code in general.")]),_v(" "),_c('h3',{attrs:{"id":"vue-js"}},[_v("Vue.js"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#vue-js","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("During the semester, I learned the fundamentals of Vue.js, including the Vue lifecycle, creating Vue components, and working with both Vue 2 and Vue 3.\nIt was exciting to discover that my previous experience with React was easily transferable to Vue, which helped me to quickly grasp the fundamentals of the framework.")]),_v(" "),_c('p',[_v("While using Vue, I also realised the importance of having a huge community behind a framework.\nWhen working with Vue, I find it harder to find solutions online as there are less resources available compared to React.\nHowever, I still had a great time learning Vue and learning a new framework for Frontend.")]),_v(" "),_c('h4',{attrs:{"id":"resource-used"}},[_v("Resource used:"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#resource-used","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ul',[_c('li',[_c('a',{attrs:{"href":"https://vuejs.org/"}},[_v("Vue docs")]),_v(": This is the most valuable resource I used to learn Vue. The docs are pretty well written and easy to understand.\nHowever, there are some parts that are not very well documented such as SSR.")])]),_v(" "),_c('h3',{attrs:{"id":"monorepo-and-monorepo-management-tools"}},[_v("Monorepo and Monorepo management tools"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#monorepo-and-monorepo-management-tools","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("During the semester, I learned about Monorepo and Monorepo management tools like Lerna, NPM Workspaces, and Turborepo.\nI gained an understanding of the benefits that Monorepo provides, such as simplified version control, dependency management and sharing of configs.\nI learned how Monorepo management tools can help with versioning and also help to speed up running test and building through concurrency and caching.")]),_v(" "),_c('p',[_v("Overall, I gained a greater appreciation for Monorepo and its management tools, and I can see how they can greatly simplify software development and improve efficiency.")]),_v(" "),_c('h4',{attrs:{"id":"resource-used-2"}},[_v("Resource used:"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#resource-used-2","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ul',[_c('li',[_c('a',{attrs:{"href":"https://lerna.js.org/"}},[_v("Lerna docs")]),_v(": This is the main resource I used to learn about Lerna. The docs are pretty well written and easy to understand.")]),_v(" "),_c('li',[_c('a',{attrs:{"href":"https://www.youtube.com/watch?v=9iU_IE6vnJ8"}},[_v("Fireship on monorepo")]),_v(": This is a good summary video by Fireship which shares about what exactly is Monorepo and why it is useful.")])]),_v(" "),_c('h3',{attrs:{"id":"serverside-rendering-ssr"}},[_v("Serverside Rendering (SSR)"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#serverside-rendering-ssr","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("This is my first time actually working with SSR directly.\nPrior to this, I only have a basic understanding of SSR, and I was not sure how it works.\nThrough learning how to migrate from Vue 2 and Vue 3, I have really learnt a lot about how SSR works and why is it needed.\nBelow are a list of things that I have learned about SSR:")]),_v(" "),_c('ul',[_c('li',[_v("How does SSR work and what are the benefits of using SSR?")]),_v(" "),_c('li',[_v("How does SSR differ from Client-Side Rendering (CSR)?")]),_v(" "),_c('li',[_v("What is client-side hydration and how does it work in conjunction with SSR?")]),_v(" "),_c('li')]),_v(" "),_c('p',[_v("I am really glad that I have learnt about SSR as SSR will is getting more and more prevalent in the industry.")]),_v(" "),_c('h4',{attrs:{"id":"resource-used-3"}},[_v("Resource used:"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#resource-used-3","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ul',[_c('li',[_c('a',{attrs:{"href":"https://vuejs.org/"}},[_v("Vue docs")]),_v(": This is super helpful in understand about SSR in vue.")]),_v(" "),_c('li',[_v("Other than that, I think a lot of SSR and even CSR knowledge is learned from ChatGPT.")])]),_v(" "),_c('h3',{attrs:{"id":"webpack"}},[_v("Webpack"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#webpack","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Previously, in all honesty I did not really know what Webpack is and how it works.\nWebpack seems to just be a magical tool that just works.\nThrough updating of Webpack and attempting to migrate Vue 2 to Vue 3. I learned a lot about Webpack and what it does.\nBelow are a list of things that I have learned about Webpack:")]),_v(" "),_c('ul',[_c('li',[_v("What is Webpack and how does it work? (bundling etc.)")]),_v(" "),_c('li',[_v("Learned about different types of Webpack plugins")])]),_v(" "),_c('h4',{attrs:{"id":"resource-used-4"}},[_v("Resource used:"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#resource-used-4","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ul',[_c('li',[_c('a',{attrs:{"href":"https://webpack.js.org/"}},[_v("Webpack docs")]),_v(": This is the main resource I used to learn about Webpack.")])]),_v(" "),_c('h3',{attrs:{"id":"i-learn-how-to-use-open-source-software"}},[_v("I learn how to use Open Source Software"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#i-learn-how-to-use-open-source-software","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("This is quite a random learning point, but I think it is important to mention.\nSomehow, I handled a lot of upgrading of dependencies.\nI learned how to safely update dependencies and ensure that it does not break a codebase.\nI also learned the importance of reading the changelog and release notes of dependencies.")]),_v(" "),_c('p',[_v("I had a painful experience when I had to debug why html format has changed after running npm install.\nThe reason for this is that the developer of js-beautify has changed the way it formats custom tag but did not mention it in the release notes.\nThis caused a lot of tests to fail and I had to spend a lot of time debugging it.")]),_v(" "),_c('p',[_v("Through this experience, I learned the importance of ensuring that changes are documented properly and correctly.")])])]),_v(" "),_c('panel',{attrs:{"minimized":""},scopedSlots:_u([{key:"header",fn:function(){return [_c('p',[_c('strong',[_v("Observations")]),_v(" from external projects")])]},proxy:true}])},[_v(" "),_c('div',[_c('h3',{attrs:{"id":"project-foo-6"}},[_v("Project: Foo"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#project-foo-6","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Give an intro to the project here ...")]),_v(" "),_c('h3',{attrs:{"id":"my-contributions-6"}},[_v("My Contributions"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#my-contributions-6","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Give a description of your contributions, including links to relevant PRs")]),_v(" "),_c('h3',{attrs:{"id":"my-learning-record-6"}},[_v("My Learning Record"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#my-learning-record-6","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Give tools/technologies you learned here. Include resources you used, and a brief summary of the resource.")])])])],1)],1),_v(" "),_c('div',[_c('box',[_c('h2',{attrs:{"id":"hannah-chia-kai-xin"}},[_v("HANNAH CHIA KAI XIN"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#hannah-chia-kai-xin","onclick":"event.stopPropagation()"}})]),_v(" "),_c('div',{staticClass:"container"},[_c('div',{staticClass:"row"},[_c('div',{staticClass:"col"},[_c('img',{attrs:{"src":"/2024/students/kaixin-hc/photo.png","width":"100"}}),_c('br')]),_v(" "),_c('div',{staticClass:"col"},[_c('p',[_c('strong',[_v("GitHub:")]),_v(" "),_c('span',[_c('a',{attrs:{"href":"https://www.github.com/kaixin-hc"}},[_v("https://www.github.com/kaixin-hc")])]),_c('br')]),_v(" "),_c('p',[_c('strong',[_v("Projects:")]),_v(" "),_c('span',[_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind"}},[_v("Markbind")])])])])])]),_v(" "),_c('p'),_v(" "),_c('panel',{attrs:{"minimized":""},scopedSlots:_u([{key:"header",fn:function(){return [_c('p',[_c('strong',[_v("Progress")])])]},proxy:true}])},[_v(" "),_c('div')]),_v(" "),_c('panel',{attrs:{"minimized":""},scopedSlots:_u([{key:"header",fn:function(){return [_c('p',[_c('strong',[_v("Knowledge gained")])])]},proxy:true}])},[_v(" "),_c('div',[_c('h2',{attrs:{"id":"frontend"}},[_v("Frontend"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#frontend","onclick":"event.stopPropagation()"}})]),_v(" "),_c('h3',{attrs:{"id":"rounded-vs-square-edges-for-signalling-functionality"}},[_v("Rounded vs Square edges for signalling functionality"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#rounded-vs-square-edges-for-signalling-functionality","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Researching whether to use rounded corners, sqared off corners, or fully rounded boxes was interesting from a usability perpective. Some resources I used to learn about them:")]),_v(" "),_c('ul',[_c('li',[_c('a',{attrs:{"href":"https://ux.stackexchange.com/questions/40744/mixing-rounded-corners-and-square-corners"}},[_v("https://ux.stackexchange.com/questions/40744/mixing-rounded-corners-and-square-corners")])]),_v(" "),_c('li',[_c('a',{attrs:{"href":"https://medium.com/@carolinalina/how-to-design-ui-buttons-that-convert-d5ebb1080969"}},[_v("https://medium.com/@carolinalina/how-to-design-ui-buttons-that-convert-d5ebb1080969")])]),_v(" "),_c('li',[_c('a',{attrs:{"href":"https://prototypr.io/post/the-rounded-user-experience/"}},[_v("https://prototypr.io/post/the-rounded-user-experience/")])])]),_v(" "),_c('p',[_v("The information from "),_c('a',{attrs:{"href":"https://uxdesign.cc/make-sense-of-rounded-corners-on-buttons-dfc8e13ea7f7"}},[_v("https://uxdesign.cc/make-sense-of-rounded-corners-on-buttons-dfc8e13ea7f7")]),_v(" in particular made a case for fully rounded buttons for primary content when you have space to spare, to direct users attention to those buttons. They suggested to avoid fully rounded buttons when many are used next to each other as it may not be obvious which to click. I used this information to infer what the average user might takeaway if minimized panels were pills rather than rounded buttons.")]),_v(" "),_c('h3',{attrs:{"id":"vue-2"}},[_v("Vue"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#vue-2","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ul',[_c('li',[_c('a',{attrs:{"href":"https://v1.vuejs.org/guide/instance.html"}},[_v("https://v1.vuejs.org/guide/instance.html")])]),_v(" "),_c('li',[_v("Scoped styles: "),_c('a',{attrs:{"href":"https://vue-loader.vuejs.org/guide/scoped-css.html"}},[_v("https://vue-loader.vuejs.org/guide/scoped-css.html")]),_v(", also informing the issue I created "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/1768"}},[_v("#1768")]),_v(" in MarkBind")]),_v(" "),_c('li',[_v("Learning about slots: "),_c('a',{attrs:{"href":"https://learnvue.co/2021/03/when-why-to-use-vue-scoped-slots/#conclusion"}},[_v("https://learnvue.co/2021/03/when-why-to-use-vue-scoped-slots/#conclusion")]),_v(", "),_c('a',{attrs:{"href":"https://www.smashingmagazine.com/2019/07/using-slots-vue-js/"}},[_v("https://www.smashingmagazine.com/2019/07/using-slots-vue-js/")])])]),_v(" "),_c('h3',{attrs:{"id":"scrollbars"}},[_v("Scrollbars"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#scrollbars","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Using overflow-x: scroll on the default navbar, seemed to cause the dropdown to break.")]),_v(" "),_c('p',[_v("After a few stack overflow posts and reading, I found this article: "),_c('a',{attrs:{"href":"https://css-tricks.com/popping-hidden-overflow/"}},[_v("https://css-tricks.com/popping-hidden-overflow/")]),_v(" that explains that setting "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("overflow-x")]),_v(" sets "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("overflow-y")]),_v(" as well, and it's just not possible to have a dropdown peep out of a scrollable overflow without setting positions relatively. "),_c('a',{attrs:{"href":"https://www.sitepoint.com/community/t/css-drop-down-menu-hidden-behind-horizontal-scrollbar/367783"}},[_v("This discussion")]),_v(" with the offered "),_c('a',{attrs:{"href":"https://codepen.io/paulobrien/embed/vYxWppv?"}},[_v("solution")]),_v(" was also interesting.")]),_v(" "),_c('p',[_v("I briefly explored existing libraries like "),_c('a',{attrs:{"href":"https://floating-ui.com/"}},[_v("https://floating-ui.com/")]),_v(". Libraries like this exist to make it easier to accomplish this surprisingly complex task.")]),_v(" "),_c('p',[_v("I also learned about the accessibility of scrollbars ("),_c('a',{attrs:{"href":"https://adrianroselli.com/2019/01/baseline-rules-for-scrollbar-usability.html"}},[_v("https://adrianroselli.com/2019/01/baseline-rules-for-scrollbar-usability.html")]),_v(") and ("),_c('a',{attrs:{"href":"https://www.w3.org/WAI/standards-guidelines/act/rules/0ssw9k/proposed/"}},[_v("https://www.w3.org/WAI/standards-guidelines/act/rules/0ssw9k/proposed/")]),_v("), which discussed what goes into making scrollbars accessible. Visually, visible scrollbars provide an obvious indication that there is more content. These design tips on scrollbars ("),_c('a',{attrs:{"href":"https://www.nngroup.com/articles/scrolling-and-scrollbars/"}},[_v("https://www.nngroup.com/articles/scrolling-and-scrollbars/")]),_v(") were also interesting, particularly the note to avoid horizontal scrolling wherever possible.")]),_v(" "),_c('p',[_v("This informed my decision that it would be better not to make a scrollable navbar the default, but have a dropdown menu with more options for smaller screens")]),_v(" "),_c('p',[_v("[]::webkit-scrollbar]("),_c('a',{attrs:{"href":"https://developer.mozilla.org/en-US/docs/Web/CSS/::-webkit-scrollbar"}},[_v("https://developer.mozilla.org/en-US/docs/Web/CSS/::-webkit-scrollbar")]),_v(") pseudo-element does not work for all browsers and should be used with caution.")]),_v(" "),_c('h2',{attrs:{"id":"open-source-dependencies"}},[_v("Open source dependencies"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#open-source-dependencies","onclick":"event.stopPropagation()"}})]),_v(" "),_c('h3',{attrs:{"id":"ghpages"}},[_v("ghpages"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#ghpages","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Used when researching the deploy and build commands for MarkBind.")]),_v(" "),_c('ul',[_c('li',[_c('a',{attrs:{"href":"https://github.com/tschaub/gh-pages"}},[_v("https://github.com/tschaub/gh-pages")])])]),_v(" "),_c('h3',{attrs:{"id":"commander"}},[_v("Commander"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#commander","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Used to write CLI programs.")]),_v(" "),_c('ul',[_c('li',[_c('a',{attrs:{"href":"https://www.npmjs.com/package/commander"}},[_v("https://www.npmjs.com/package/commander")])]),_v(" "),_c('li',[_c('a',{attrs:{"href":"https://en.wikipedia.org/wiki/Usage_message"}},[_v("https://en.wikipedia.org/wiki/Usage_message")]),_v(" (conventions in defining parameters)")])]),_v(" "),_c('h3',{attrs:{"id":"jest"}},[_v("jest"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#jest","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Mainly studied the changelog to see if this would break when dependencies were updated.")]),_v(" "),_c('ul',[_c('li',[_v("Introduction: "),_c('a',{attrs:{"href":"https://jestjs.io/"}},[_v("https://jestjs.io/")]),_v(" and repository("),_c('a',{attrs:{"href":"https://github.com/facebook/jest"}},[_v("https://github.com/facebook/jest")]),_v(")")]),_v(" "),_c('li',[_v("relevant blog post: "),_c('a',{attrs:{"href":"https://jestjs.io/blog/2021/05/25/jest-27"}},[_v("https://jestjs.io/blog/2021/05/25/jest-27")])]),_v(" "),_c('li',[_c('a',{attrs:{"href":"https://github.com/facebook/jest/blob/main/CHANGELOG.md#2700"}},[_v("changelog")])]),_v(" "),_c('li',[_v("Jest testrunners: they plan on changing the default test-runner from "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("jasmine2")]),_v(" to "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("jest-circus")]),_v(" in version 27, with "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("jasmine2")]),_v(" "),_c('a',{attrs:{"href":"https://jestjs.io/blog/2020/05/05/jest-26"}},[_v("to be discontinued afterwards")]),_v(". Though I think we're using "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("jasmine2")]),_v(" and not "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("jest-circus")]),_v(", but MarkBind we never explicitly specify a change from the default")])]),_v(" "),_c('h3',{attrs:{"id":"fs-extra"}},[_v("fs-extra"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#fs-extra","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Handy utility that I ended up using extensively")]),_v(" "),_c('ul',[_c('li',[_c('a',{attrs:{"href":"https://github.com/jprichardson/node-fs-extra"}},[_v("https://github.com/jprichardson/node-fs-extra")])])]),_v(" "),_c('h2',{attrs:{"id":"git"}},[_v("Git"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#git","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("CI pipeline (particularly with git):")]),_v(" "),_c('ul',[_c('li',[_c('a',{attrs:{"href":"https://docs.github.com/en/actions/automating-builds-and-tests/about-continuous-integration"}},[_v("https://docs.github.com/en/actions/automating-builds-and-tests/about-continuous-integration")]),_v(", particularly the section on "),_c('a',{attrs:{"href":"https://docs.github.com/en/actions/automating-builds-and-tests/about-continuous-integration#about-continuous-integration-using-github-actions"}},[_v("github actions")])]),_v(" "),_c('li',[_v("Follow-up research about github actions\n"),_c('ul',[_c('li',[_c('a',{attrs:{"href":"https://docs.github.com/en/actions/quickstart"}},[_v("https://docs.github.com/en/actions/quickstart")])]),_v(" "),_c('li',[_c('a',{attrs:{"href":"https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions"}},[_v("https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions")])])])]),_v(" "),_c('li',[_v("Basic research about "),_c('a',{attrs:{"href":"https://travis-ci.org/"}},[_v("Travis CI")]),_v(" and "),_c('a',{attrs:{"href":"https://www.netlify.com/"}},[_v("Netlify")])])]),_v(" "),_c('h2',{attrs:{"id":"logging-framework"}},[_v("Logging Framework"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#logging-framework","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ul',[_c('li',[_c('a',{attrs:{"href":"https://www.sentinelone.com/blog/logging-framework/"}},[_v("https://www.sentinelone.com/blog/logging-framework/")]),_v(" as an introduction")]),_v(" "),_c('li',[_c('a',{attrs:{"href":"https://se-education.org/se-book/errorHandling/#-12"}},[_v("https://se-education.org/se-book/errorHandling/#-12")]),_v(" also as an introduction")]),_v(" "),_c('li',[_c('a',{attrs:{"href":"https://github.com/winstonjs/winston"}},[_v("https://github.com/winstonjs/winston")]),_v(" (library used with markbind)")])]),_v(" "),_c('h2',{attrs:{"id":"ways-versioning-is-implemented"}},[_v("Ways Versioning is Implemented"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#ways-versioning-is-implemented","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ul',[_c('li',[_v("Learn about semantic versioning: "),_c('a',{attrs:{"href":"https://semver.org/"}},[_v("https://semver.org/")])]),_v(" "),_c('li',[_v("Alternate versioning solutions:\n"),_c('ul',[_c('li',[_c('a',{attrs:{"href":"https://github.com/jimporter/mike"}},[_v("https://github.com/jimporter/mike")])]),_v(" "),_c('li',[_c('a',{attrs:{"href":"https://docusaurus.io/docs/versioning"}},[_v("https://docusaurus.io/docs/versioning")])])])])]),_v(" "),_c('h2',{attrs:{"id":"javascript"}},[_v("Javascript"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#javascript","onclick":"event.stopPropagation()"}})]),_v(" "),_c('h3',{attrs:{"id":"javascript-with-regard-to-object-oriented-programming"}},[_v("Javascript with regard to object oriented programming"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#javascript-with-regard-to-object-oriented-programming","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Looking into this was inspired by the issues on refactoring the large "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("core/site/index.js")]),_v(" file which is over 1.5k lines into more manageable class. At present, most of the file is made up of the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Site")]),_v(" class, which makes sense from an object oriented perspective. All the functions which are supported by Site are things which affect what the site itself holds or does: generating itself, deploying itself, initialising itself.")]),_v(" "),_c('p',[_v("One suggestion for refactoring would be separating out each command into separate files. We could abstract away the command logic might be separating each command into classes, having each command inherit from a Command class, and having the site class just generate and execute each command when it is called to do so. But is this necessary or desirable?")]),_v(" "),_c('p',[_v("Java and Javascript are different in that Java is class based and Javascript is prototype-based. Class based languages are founded on the concept of classes and instances being distinct, where classes are an abstract description of a set of potential instances which have the properties defined in the class - no more and no less. Prototype based languages have a 'prototypical object' which is the template used to create a new object, but once you create it or at run time the object can specify its own additional properties and be assigned as the prototype for additional objects (source: "),_c('a',{attrs:{"href":"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Details_of_the_Object_Model"}},[_v("mozilla, class-based vs prototype based languages")]),_v(")")]),_v(" "),_c('p',[_v("Nevertheless, Site.js does use \"classes\" of managers to manage externals, etc, so perhaps in production avoiding classes is not a big deal. Would still be a useful abstraction to manage the complexity of the file.")]),_v(" "),_c('h3',{attrs:{"id":"certain-functions-in-javascript"}},[_v("Certain functions in javascript"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#certain-functions-in-javascript","onclick":"event.stopPropagation()"}})]),_v(" "),_c('panel',{attrs:{"title":"JavaScript forEach (and async loops)"}},[_c('p',[_v("\"JavaScript Array.prototype.forEach loop is not asynchronous. The Array.prototype.forEach method accepts a callback as an argument which can be an asynchronous function, but the forEach method will not wait for any promises to be resolved before moving onto the next iteration.\" ("),_c('a',{attrs:{"href":"https://atomizedobjects.com/blog/javascript/is-javascript-foreach-async/"}},[_v("Source")]),_v(").")]),_v(" "),_c('p',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("forEach")]),_v(" does not look at what is returned, and won't handle the promise that an async function would return. Naturally, this means you cannot use async or await with it. The algorithm for forEach creates a loop that calls the callback function for each("),_c('a',{attrs:{"href":"https://stackoverflow.com/questions/5050265/javascript-node-js-is-array-foreach-asynchronous"}},[_v("StackOverflow Source")]),_v(", "),_c('a',{attrs:{"href":"https://thecodebarbarian.com/for-vs-for-each-vs-for-in-vs-for-of-in-javascript"}},[_v("more information about loops")]),_v(")")]),_v(" "),_c('p',[_v("Instead, we could use map and the promise 'class' functions.")])]),_v(" "),_c('panel',{attrs:{"title":"Javascript map can be destructive sometimes"}},[_c('p',[_v("Just needed to note this, and consider other options. Refactoring my code allowed me to avoid destructively modifying the list.\n[source]("),_c('a',{attrs:{"href":"https://dev.to/lofiandcode/"}},[_v("https://dev.to/lofiandcode/")]),_v("\ncan-map-mutate-the-original-array-yes-dmb)")])])],1)]),_v(" "),_c('panel',{attrs:{"minimized":""},scopedSlots:_u([{key:"header",fn:function(){return [_c('p',[_c('strong',[_v("Observations")]),_v(" from external projects")])]},proxy:true}])},[_v(" "),_c('div',[_c('h3',{attrs:{"id":"project-foo-7"}},[_v("Project: Foo"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#project-foo-7","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Give an intro to the project here ...")]),_v(" "),_c('h3',{attrs:{"id":"my-contributions-7"}},[_v("My Contributions"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#my-contributions-7","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Give a description of your contributions, including links to relevant PRs")]),_v(" "),_c('h3',{attrs:{"id":"my-learning-record-7"}},[_v("My Learning Record"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#my-learning-record-7","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Give tools/technologies you learned here. Include resources you used, and a brief summary of the resource.")])])])],1)],1),_v(" "),_c('div',[_c('box',[_c('h2',{attrs:{"id":"lee-wei-david"}},[_v("LEE WEI, DAVID"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#lee-wei-david","onclick":"event.stopPropagation()"}})]),_v(" "),_c('div',{staticClass:"container"},[_c('div',{staticClass:"row"},[_c('div',{staticClass:"col"},[_c('img',{attrs:{"src":"/2024/students/itsyme/photo.png","width":"100"}}),_c('br')]),_v(" "),_c('div',{staticClass:"col"},[_c('p',[_c('strong',[_v("GitHub:")]),_v(" "),_c('span',[_c('a',{attrs:{"href":"https://www.github.com/itsyme"}},[_v("https://www.github.com/itsyme")])]),_c('br')]),_v(" "),_c('p',[_c('strong',[_v("Projects:")]),_v(" "),_c('span',[_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind"}},[_v("MarkBind")])])])])])]),_v(" "),_c('p'),_v(" "),_c('panel',{attrs:{"minimized":""},scopedSlots:_u([{key:"header",fn:function(){return [_c('p',[_c('strong',[_v("Progress")])])]},proxy:true}])},[_v(" "),_c('div')]),_v(" "),_c('panel',{attrs:{"minimized":""},scopedSlots:_u([{key:"header",fn:function(){return [_c('p',[_c('strong',[_v("Knowledge gained")])])]},proxy:true}])},[_v(" "),_c('div',[_c('h3',{attrs:{"id":"vue-js-2"}},[_v("Vue.js"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#vue-js-2","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("One of the largest takeaways from working with MarkBind in the last semester has been Vue.js, an open-source front-end framework that MarkBind uses to build it's UI components. Previously, only knowing the React.js framework, Vue.js is a handy addition to my arsenal. The basics of Vue.js was rather simple to pick up. Reading the "),_c('a',{attrs:{"href":"https://vuejs.org/guide/introduction.html"}},[_v("Vue.js documentation")]),_v(", and referencing examples of already implemented Vue components in MarkBind, I quickly understood the use of "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("