diff --git a/README.html b/README.html index 15a4a3cfc..3d29cb947 100644 --- a/README.html +++ b/README.html @@ -12,7 +12,7 @@ const baseUrl = '/2024' -

CS3281&2 student data website

+

CS3281&2 student data website

diff --git a/README.page-vue-render.js b/README.page-vue-render.js index 44286ab01..5d2a7421a 100644 --- a/README.page-vue-render.js +++ b/README.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} 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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/activities-dashboard.html b/activities-dashboard.html index b3c6dc903..9667b8251 100644 --- a/activities-dashboard.html +++ b/activities-dashboard.html @@ -14,7 +14,7 @@

GitHub Activities Dashboard

  • This page contains a list of your NUS-OSS GitHub posts during the period eligible for course credit.
    For CS3282 students, the activity period varies based on when you finished CS3282.
  • The content of each panel body may not be exactly as it shows up on GitHub, as some crude sanitizations have been done to prevent post contents interfering with MarkBind parsing.
  • It goes without saying that GitHub activities are not the sole representation of your work. It's just one source of evidence only. So, don't put too much importance on what you see in this page.
    -Furthermore, the stats (i.e., posts counts) are not directly comparable between devs, as they are influenced by the type of work/project.
  • This page will be updated once in a while, in 1-2 week intervals.

[This page was last updated on 2024-05-07 @22:54]

CS3281

ARIF..ALID @Arif-Khalid 23 27+84 10 9


MISR..ITYA @MadLamprey 13 0+10 3 1


NERE.. BIN @NereusWB922 36 16+35 8 7


NGUY..UYEN @nknguyenhc 20 39+67 12 22


EYO ..EVIN @KevinEyo1 13 42+10 6 26


LAM ..FONG @LamJiuFong 8 36+13 2 14


WANG..TING @jingting1412 9 45+6 2 4


WANG..IWEN @yiwen101 14 92+6 7 21


XU S..UYAO @Tim-Siu 8 55+16 3 15


ALVI..S NG @supermii2 3 9+5 3 4


GEOR.. YAO @asdfghjkxd 15 50+38 9 5


JONA.. WEI @jonasongg 15 49+22 7 5


POON..RYAN @sopa301 20 47+43 11 8


CHIN..YUAN @mingyuanc 15 46+22 0 0


DOMI.. GIN @domoberzin 31 14+20 1 1


TYE ..QUES @marquestye 11 26+9 1 0


XENO..NONG @xenosf 17 13+11 3 1


YEO ..HENG @dishenggg 20 18+7 1 1


ZHU ..ANXI @yuanxi1 10 7+3 0 0



CS3282

GOH ..RIEL @gycgabriel 3 0+42 5 5


LEE ..SAAC @luminousleek 11 11+112 7 11


VIGN..IYER @vigneshsankariyer1234567890 5 0+43 1 4


WONG..HONG @cheehongw 8 10+45 7 11


CHAN..HENG @yucheng11122017 12 23+485 9 69


ELTO.. HAO @EltonGohJH 2 5+83 3 16


HANN.. XIN @kaixin-hc 12 3+201 7 67


LEE ..AVID @itsyme 4 5+62 5 5


CHAR..USAR @ckcherry23 2 0+226 11 23


DAVI.. ONG @vvidday 0 0+107 1 1


GOKU..AJIV @gok99 1 0+63 3 13


MARC.. KYE @MarcusTXK 0 0+63 3 4


CHAN..OLAS @Nicolascwy 30 27+172 7 11


DOMI.. JUN @domlimm 7 11+107 3 35


JAY ..TING @jayasting98 14 13+168 5 10


KEVI..TONG @kevin9foong 6 3+26 3 2


MOK ..RGUS @FergusMok 22 27+156 4 4


NEO ..QING @weiquu 34 4+332 24 58


ONG ..DRIC @cedricongjh 55 15+406 12 79


SIM ..NICE @EuniceSim142 18 16+62 0 0


ZHAN..QING @ziqing26 24 7+206 4 6


+Furthermore, the stats (i.e., posts counts) are not directly comparable between devs, as they are influenced by the type of work/project.
  • This page will be updated once in a while, in 1-2 week intervals.
  • [This page was last updated on 2024-05-07 @22:54]

    CS3281

    ARIF..ALID @Arif-Khalid 23 27+84 10 9


    MISR..ITYA @MadLamprey 13 0+10 3 1


    NERE.. BIN @NereusWB922 36 16+35 8 7


    NGUY..UYEN @nknguyenhc 20 39+67 12 22


    EYO ..EVIN @KevinEyo1 13 42+10 6 26


    LAM ..FONG @LamJiuFong 8 36+13 2 14


    WANG..TING @jingting1412 9 45+6 2 4


    WANG..IWEN @yiwen101 14 92+6 7 21


    XU S..UYAO @Tim-Siu 8 55+16 3 15


    ALVI..S NG @supermii2 3 9+5 3 4


    GEOR.. YAO @asdfghjkxd 15 50+38 9 5


    JONA.. WEI @jonasongg 15 49+22 7 5


    POON..RYAN @sopa301 20 47+43 11 8


    CHIN..YUAN @mingyuanc 15 46+22 0 0


    DOMI.. GIN @domoberzin 31 14+20 1 1


    TYE ..QUES @marquestye 11 26+9 1 0


    XENO..NONG @xenosf 17 13+11 3 1


    YEO ..HENG @dishenggg 20 18+7 1 1


    ZHU ..ANXI @yuanxi1 10 7+3 0 0



    CS3282

    GOH ..RIEL @gycgabriel 3 0+42 5 5


    LEE ..SAAC @luminousleek 11 11+112 7 11


    VIGN..IYER @vigneshsankariyer1234567890 5 0+43 1 4


    WONG..HONG @cheehongw 8 10+45 7 11


    CHAN..HENG @yucheng11122017 12 23+485 9 69


    ELTO.. HAO @EltonGohJH 2 5+83 3 16


    HANN.. XIN @kaixin-hc 12 3+201 7 67


    LEE ..AVID @itsyme 4 5+62 5 5


    CHAR..USAR @ckcherry23 2 0+226 11 23


    DAVI.. ONG @vvidday 0 0+107 1 1


    GOKU..AJIV @gok99 1 0+63 3 13


    MARC.. KYE @MarcusTXK 0 0+63 3 4


    CHAN..OLAS @Nicolascwy 30 27+172 7 11


    DOMI.. JUN @domlimm 7 11+107 3 35


    JAY ..TING @jayasting98 14 13+168 5 10


    KEVI..TONG @kevin9foong 6 3+26 3 2


    MOK ..RGUS @FergusMok 22 27+156 4 4


    NEO ..QING @weiquu 34 4+332 24 58


    ONG ..DRIC @cedricongjh 55 15+406 12 79


    SIM ..NICE @EuniceSim142 18 16+62 0 0


    ZHAN..QING @ziqing26 24 7+206 4 6


    diff --git a/activities-dashboard.page-vue-render.js b/activities-dashboard.page-vue-render.js index 325b88da5..edb0f0a0b 100644 --- a/activities-dashboard.page-vue-render.js +++ b/activities-dashboard.page-vue-render.js @@ -20,6 +20,6 @@ with(this){return _c('h1',{attrs:{"id":"cs3281"}},[_v("CS3281"),_c('a',{staticCl with(this){return _c('h1',{attrs:{"id":"cs3282"}},[_v("CS3282"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#cs3282","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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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 index 4c0a73b70..7f35125c0 100644 --- a/cs3282-index.html +++ b/cs3282-index.html @@ -16,7 +16,7 @@ Zitadel, Templ, FerretDB

    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


    1. In the Python project, NEWS entries document contributions so that it can be added into the changelog.

    +date-fns

    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


    1. In the Python project, NEWS entries document contributions so that it can be added into the changelog.

    diff --git a/cs3282-index.page-vue-render.js b/cs3282-index.page-vue-render.js index ea91b4ecd..c01e9ad1c 100644 --- a/cs3282-index.page-vue-render.js +++ b/cs3282-index.page-vue-render.js @@ -47,6 +47,6 @@ with(this){return _c('h1',{attrs:{"id":"teammates"}},[_v("TEAMMATES"),_c('a',{st with(this){return _c('li',{staticClass:"footnote-item",attrs:{"id":"fn-90-1"}},[_c('p',[_v("In the Python project, "),_c('code',{staticClass:"hljs inline no-lang"},[_v("NEWS")]),_v(" entries document contributions so that it can be added into the changelog.")])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/index.html b/index.html index 4bd4583b5..9380fd45f 100644 --- a/index.html +++ b/index.html @@ -12,7 +12,7 @@ const baseUrl = '/2024' -

    CS3281 - 2024 Batch

    CATcher:

    MarkBind:

    RepoSense:

    TEAMMATES:

    CATcher

    ARIF KHALID

    MISRA ADITYA

    NEREUS NG WEI BIN

    NGUYEN KHOI NGUYEN

    MarkBind

    EYO KAI WEN, KEVIN

    LAM JIU FONG

    WANG JINGTING

    WANG YIWEN

    XU SHUYAO

    RepoSense

    ALVIS NG

    GEORGE TAY QUAN YAO

    JONAS ONG SI WEI

    POON YIP HANG, RYAN

    TEAMMATES

    CHING MING YUAN

    DOMINIC BERZIN CHUA WAY GIN

    TYE JIA JUN, MARQUES

    XENOS FIORENZO ANONG

    YEO DI SHENG

    ZHU YUANXI

    +

    CS3281 - 2024 Batch

    CATcher:

    MarkBind:

    RepoSense:

    TEAMMATES:

    CATcher

    ARIF KHALID

    MISRA ADITYA

    NEREUS NG WEI BIN

    NGUYEN KHOI NGUYEN

    MarkBind

    EYO KAI WEN, KEVIN

    LAM JIU FONG

    WANG JINGTING

    WANG YIWEN

    XU SHUYAO

    RepoSense

    ALVIS NG

    GEORGE TAY QUAN YAO

    JONAS ONG SI WEI

    POON YIP HANG, RYAN

    TEAMMATES

    CHING MING YUAN

    DOMINIC BERZIN CHUA WAY GIN

    TYE JIA JUN, MARQUES

    XENOS FIORENZO ANONG

    YEO DI SHENG

    ZHU YUANXI

    diff --git a/index.page-vue-render.js b/index.page-vue-render.js index 3e2771da0..ec0fc6123 100644 --- a/index.page-vue-render.js +++ b/index.page-vue-render.js @@ -1,7 +1,7 @@ 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('li',[_c('a',{staticClass:"dropdown-item",attrs:{"href":"/2024/activities-dashboard.html"}},[_v("Activities 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:"dropdown-item",attrs:{"href":"/2024/activities-dashboard.html"}},[_v("Activities Dashboard")])])]),_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":"arif-khalid"}},[_v("ARIF KHALID"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#arif-khalid","onclick":"event.stopPropagation()"}})]),_v(" "),_c('div',{staticClass:"container"},[_c('div',{staticClass:"row"},[_c('div',{staticClass:"col"},[_c('img',{attrs:{"src":"/2024/students/Arif-Khalid/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/Arif-Khalid"}},[_v("https://github.com/Arif-Khalid")])]),_c('br')]),_v(" "),_c('p',[_c('strong',[_v("Projects:")]),_v(" "),_c('span',[_c('a',{attrs:{"href":"https://github.com/CATcher-org"}},[_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',[_c('h1',{attrs:{"id":"key-contributions"}},[_v("Key Contributions"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#key-contributions","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ul',[_c('li',[_v("Actively participated in submitting and resolving issues found, implementing features and team discussions")]),_v(" "),_c('li',[_v("Focus on bug fixes that hurt the usability of CATcher and WATcher")]),_v(" "),_c('li',[_v("Reviewed PRs constructively with focus on scalability and code style of the existing code base")]),_v(" "),_c('li',[_v("Update CI/CD workflow, specifically improving automation by using an on push deployment and a release drafter template and bot which formatted and displayed release changes"),_c('br'),_v(" "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/272"}},[_v("Automatic deployment #272")]),_v(", "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/285"}},[_v("Release changelog automation #285")])]),_v(" "),_c('li',[_v("Revamp and updates to filter system of WATcher\n"),_c('ul',[_c('li',[_v("Adopted a centralised service and observer pattern behaviour"),_c('br'),_v(" "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/259"}},[_v("Refactor certain filters into its own service #259")]),_v(", "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/261"}},[_v("Refactor sorting #261")]),_v(", "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/264"}},[_v("Refactor milestone filters #264")])]),_v(" "),_c('li',[_v("Update filters to be stored into and restored from url"),_c('br'),_v(" "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/314"}},[_v("Add filters to url #314")])]),_v(" "),_c('li',[_v("Allow filters to be kept across repo changes"),_c('br'),_v(" "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/281"}},[_v("Keep filters when switching repo #281")])])])])]),_v(" "),_c('div',{staticClass:"table-responsive"},[_c('table',{staticClass:"markbind-table table table-bordered table-striped"},[_c('thead',[_c('tr',[_c('th',[_v("Week")]),_v(" "),_c('th',[_v("Achievements")])])]),_v(" "),_c('tbody',[_c('tr',[_c('td',[_v("2")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/223"}},[_v("Hide 0 issue columns #223")])])]),_v(" "),_c('tr',[_c('td',[_v("4")]),_v(" "),_c('td',[_v("Submitted Issue: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/249"}},[_v("Refactor filters into its own service #249")])])]),_v(" "),_c('tr',[_c('td',[_v("4")]),_v(" "),_c('td',[_v("Submitted Issue: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/237"}},[_v("Update Angular version to 11.2.14 #237")])])]),_v(" "),_c('tr',[_c('td',[_v("5")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/238"}},[_v("Remove unused services #238")]),_v(", Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/253"}},[_v("Remove unused models #253")]),_v(", Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/250"}},[_v("Remove unused session-fix-confirmation component #250")])])]),_v(" "),_c('tr',[_c('td',[_v("5")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/252"}},[_v("Upgrade to angular 11 #252")])])]),_v(" "),_c('tr',[_c('td',[_v("5")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/254"}},[_v("Refactor Label model #254")])])]),_v(" "),_c('tr',[_c('td',[_v("5")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher/pull/1243"}},[_v("Faulty list view when back navigating #1243")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/255"}},[_v("Add shareable repo-specific URL #255")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/259"}},[_v("Refactor certain filters into its own service #259")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/261"}},[_v("Refactor sorting #261")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/264"}},[_v("Refactor milestone filters #264")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/267"}},[_v("Upgrade to angular 12 #267")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/269"}},[_v("Fix zone testing import error #269")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/275"}},[_v("Update test cases for phase service #275")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/282"}},[_v("Three-state labels #282")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/265"}},[_v("Refactor title filter #265")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/272"}},[_v("Automatic deployment #272")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Submitted Issue: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/273"}},[_v("Release changelog automation #273")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Submitted Issue: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/283"}},[_v("Save milestones by name #283")])])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_v("Submitted Issue: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/catcher-org.github.io/issues/35"}},[_v("Incorrect numbering in user-workflow #35")])])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_v("Submitted Issue: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/295"}},[_v("Add tests for filters service #295")])])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher-docs/pull/14"}},[_v("Update Design page #14")])])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/288"}},[_v("Enable pre push hook for npm run test #288")])])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/286"}},[_v("Remove sorting by assignees in issue sorter #286")])])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/289"}},[_v("Refactor milestones to save by name #289")])])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_v("Pending PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher-docs/pull/12"}},[_v("Update user workflow #12")])])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_v("Submitted Issue: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/305"}},[_v("Label filter bar test case error #305")])])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/309"}},[_v("Hide redundant column pagination #309")])])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/310"}},[_v("Status filter checkboxes #310")])])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/281"}},[_v("Keep filters when switching repo #281")])])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/285"}},[_v("Release changelog automation #285")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/313"}},[_v("Integrate Grouping Service #313")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/311"}},[_v("Keep milestones when switching repo #311")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/314"}},[_v("Add filters to url #314")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Submitted Issue: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/333"}},[_v("Default preset view is custom when it should be currently active #333")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Submitted Issue: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/340"}},[_v("Remove quotations from filters in url #340")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Submitted Issue: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/352"}},[_v("Showing of preset views before selecting a repo")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/334"}},[_v("Fix default preset view #334")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/345"}},[_v("Remove quotation marks from url #345")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/319"}},[_v("Include groupby params in url #319")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/320"}},[_v("Add preset views #320")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/322"}},[_v("Update repo on back and forward navigation #322")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/324"}},[_v("Reset GroupingContextService only if \"keep filter\" is selected #324")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/327"}},[_v("Create release 1.2.0 #327")]),_v(", Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/329"}},[_v("Resolve conflicts for 1.2.0 #329")]),_v(", Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/331"}},[_v("Deploy V1.2.0 #331")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/349"}},[_v("Create release V1.2.1 #349")]),_v(", Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/350"}},[_v("Deploy V1.2.1 #350")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/360"}},[_v("Optimise Github API calls #360")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Submitted Issue: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/372"}},[_v("Reset of sort filter after some time #372")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/355"}},[_v("Show preset view only when repo is set #355")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/357"}},[_v("Fix top and bottom shadow of columns #357")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/364"}},[_v("Create release V1.2.2 #364")]),_v(", Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/365"}},[_v("Deploy V1.2.2 #365")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/374"}},[_v("Fix reset of filters on label fetch #374")])])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/312"}},[_v("Add test cases for filters service #312")])])])])])])])]),_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("In order to work on CATcher and WATcher, I had to learn how to use Angular. With a background in react, it was a difficult transition due to the added checks and strict nature of Angular."),_c('br'),_v("\nBelow are a few of my learning points:")]),_v(" "),_c('ul',[_c('li',[_v("Components:\n"),_c('ul',[_c('li',[_v("Each component consists of 4 different files, each of them critical to know. Logic can be contained in either typescript of html component files and you initialise other components through the HTML rather than the typescript file")]),_v(" "),_c('li',[_v("Components also have a module file which is where its dependencies are stated, i.e., the other components, services, modules it depends on")])])]),_v(" "),_c('li',[_v("Services:\n"),_c('ul',[_c('li',[_v("Each service is like a component but without anything to display. They perform functions that could be contained within components but are extracted out to increase modularity and reusability")]),_v(" "),_c('li',[_v("Like components, services can depend on other services and are often injected into components as dependencies")])])]),_v(" "),_c('li',[_v("Modules:\n"),_c('ul',[_c('li',[_v("Modules are containers for a dedicated group of files consisting of components, services or other modules")]),_v(" "),_c('li',[_v("Each module conventionally contains all the code pertaining to a certain feature")]),_v(" "),_c('li',[_v("The root module thus contains all code in the code base, child modules under the root module contain more feature-specific code in a hierarchial structure")]),_v(" "),_c('li',[_v("Modules are critical to understand in order to understand the code base and create new features")])])]),_v(" "),_c('li',[_v("RxJS\n"),_c('ul',[_c('li',[_v("While not exactly part of angular, it is important in learning angular as they are often if not always used in tandem")]),_v(" "),_c('li',[_v("RxJS is a library that allows reactive programming, i.e., the ability to subscribe to changes instead of polling for a change")]),_v(" "),_c('li',[_v("This makes it easier to compose asynchronous and cleaner, more optimized code using observer pattern")]),_v(" "),_c('li',[_v("Observers are a very useful tool that allows me to react to changes by subscribing to an event. This contributes to cleaner, more optimised and reusable code.")]),_v(" "),_c('li',[_v("Pipes allow you to consevutively call functions on the prior function's output, similar to function chaining. This allows us to have cleaner and reusable and more understandable code since you don't need to call functions separately and you can create functions out of a chain of other functions easily.")]),_v(" "),_c('li',[_v("Not to be confused with angular pipes which run via the \"|\" symbol in the html file, allowing you to transform data before it is displayed to the user.")])])])]),_v(" "),_c('p',[_v("I learned Angular through various Youtube tutorials, Udemy tutorials, reading the documentation and trying out different things through personal test projects venturing into Angular.")]),_v(" "),_c('ul',[_c('li',[_v("Youtube taught me basic fundamentals of Angular.")]),_v(" "),_c('li',[_v("Udemy taught me more in depth and guided me through small personal projects.")]),_v(" "),_c('li',[_v("The documentation gave me deeper understanding and insight into details not covered in tutorials")])]),_v(" "),_c('h3',{attrs:{"id":"typescript"}},[_v("TypeScript"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#typescript","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Angular uses TypeScript, so I needed to learn TypeScript. I had only a background in JavaScript while working with React and learning TypeScript had its own difficulties.\nBelow are a few of my learning points:")]),_v(" "),_c('ul',[_c('li',[_v("What and Why TypeScript:\n"),_c('ul',[_c('li',[_v("TypeScript acts as a wrapper over JavaScript, compiling into JavaScript code behind the scenes when you build your project")]),_v(" "),_c('li',[_v("The reason people use TypeScript is because of the increased strictness where things have to be statically typed. This reduces the occurences of bugs and makes bugs easier to find when they do occur")]),_v(" "),_c('li',[_v("This makes TypeScript an extremely useful language to pick up and is used widely in industry")])])]),_v(" "),_c('li',[_v("Types:\n"),_c('ul',[_c('li',[_v("As in the name, typescript has types and almost everything is required to by statically typed")]),_v(" "),_c('li',[_v("The \"any\" type bypassed this requirement but is generally regarded as a bad practice as you have made TypeScript into JavaScript")]),_v(" "),_c('li',[_v("You can define your own types and use those types, similar to a typedef in other languages. This is often how objects are passed in TypeScript")])])])]),_v(" "),_c('p',[_v("I learned TypeScript through Youtube tutorials")]),_v(" "),_c('ul',[_c('li',[_v("Youtube taught me the fundamentals as well as understanding the why and underlying implementation of typescript")])]),_v(" "),_c('h3',{attrs:{"id":"continuous-integration-continuous-deployment-ci-cd"}},[_v("Continuous Integration/Continuous Deployment (CI/CD)"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#continuous-integration-continuous-deployment-ci-cd","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("As an area I have litte experience in, I wanted to dive into the CI/CD pipeline of CATcher and WATcher, gain an understanding of how it works and contribute to make it better.\nBelow are a few of my learning points:")]),_v(" "),_c('ul',[_c('li',[_v("Automated testing\n"),_c('ul',[_c('li',[_v("With large projects like CATcher and WATcher, there are many areas that can and unavoidably will go wrong with many contributors editing different parts of the code base")]),_v(" "),_c('li',[_v("Manual testing is very time consuming when there are so many features to test, any one of which could have been broken by any changes to the code")]),_v(" "),_c('li',[_v("Human error might also cause us to miss certain bugs as we simply did not test for them")]),_v(" "),_c('li',[_v("Automated testing allows for pre-written tests that perform these checks quickly on a headless browser when making any changes, greatly reducing the occurence of uncaught bugs introduced")]),_v(" "),_c('li',[_v("Test case design must be comprehensive in positive and negative cases without testing every specific possible input, instead grouping inputs such as all invalid types given into one test case")])])]),_v(" "),_c('li',[_v("Continuous deployment\n"),_c('ul',[_c('li',[_v("With mission-critical projects like CATcher, it is imperative to have automated deployment")]),_v(" "),_c('li',[_v("One reason is to maintain stability of the deployment, completely negating human errors such as forgetting any one step in deployment. The deployment made is done the same everytime through an automated process")]),_v(" "),_c('li',[_v("Another reason is to speed up development as developers will not need to go through the manual deployment on every release")])])]),_v(" "),_c('li',[_v("Github Actions\n"),_c('ul',[_c('li',[_v("Github actions is a very useful CI/CD tool when the code is already hosted on github")]),_v(" "),_c('li',[_v("Compared to alternatives, it is much simpler to set up as it is one click away for every github repo, create a workflow yml file and thats it")]),_v(" "),_c('li',[_v("There are many pre-defined actions such as actions/checkout that you can use to simplify your dev-ops. In this case you don't need to write your own code to checkout your repository")])])]),_v(" "),_c('li',[_v("Angular deployment\n"),_c('ul',[_c('li',[_v("Angular has a package that allows you to build directly into your github pages")]),_v(" "),_c('li',[_v("This simplifies the process further since you simply call this command through the github actions for an immediate deployment")])])])]),_v(" "),_c('p',[_v("I learned CI/CD through inspecting the code base, trying out different workflows in my own repos and youtube tutorials")]),_v(" "),_c('ul',[_c('li',[_v("The code base gave me a guideline as to the proper way and usage of workflows, along with the proper syntax of creating a workflow")]),_v(" "),_c('li',[_v("Youtube gave me broader knowledge into creating my own workflows not specific to the CATcher project")]),_v(" "),_c('li',[_v("Trying out creating my own workflows and contributing to WATcher workflows solidified my understanding and gave me confidence in what I learned")])]),_v(" "),_c('h3',{attrs:{"id":"code-quality"}},[_v("Code Quality"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#code-quality","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Code quality is always important but is especially so when there are so many people working on the same project. Since large portions of WATcher was copied from CATcher, WATcher was made overtly large with a great number of redundant code. It was very poor code quality and the importance of code quality was made clear.")]),_v(" "),_c('ul',[_c('li',[_v("Code Cleanliness\n"),_c('ul',[_c('li',[_v("Redundant code clutters the code base, making it especially hard to understand certain functionality since you have to sift through so much to find what you are looking for")]),_v(" "),_c('li',[_v("As a new developer, it created an unecessarily difficult experience getting a grasp of the code base")]),_v(" "),_c('li',[_v("Over reliance on comments also clutters the code base when code should be self-explanatory")]),_v(" "),_c('li',[_v("Over three levels of indentation should be avoided, at which point the code is made very hard to understand and inner indents should be refactored into separate functions")])])]),_v(" "),_c('li',[_v("Code simplicity (KISS)\n"),_c('ul',[_c('li',[_v("There are many ways to do the same thing and it is always best to Keep It Simple")]),_v(" "),_c('li',[_v("Always use the simplest way to come to the same outcome, even if they use unecessary variables")]),_v(" "),_c('li',[_v("Variables and functions should be aptly named so they are understood readily such as a "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("filteredData")]),_v(" variable for storing data after it has been filtered")]),_v(" "),_c('li',[_v("Since code is read more than it is written, keeping it simple allows future developers, even yourself to understand the purpose and reason behind any piece of code")])])]),_v(" "),_c('li',[_v("Documentation\n"),_c('ul',[_c('li',[_v("Documentation is important to help others understand parts of the code that are not immediately apparent")]),_v(" "),_c('li',[_v("However, it is important to not rely too heavily on documentation and wherever possible, code you write should be self-explanatory")]),_v(" "),_c('li',[_v("Instead of writing a one-liner that does everything, split logically linked portions into separate parts, using different functions or storing outputs in appropriately named variables")])])]),_v(" "),_c('li',[_v("Following coding style\n"),_c('ul',[_c('li',[_v("Assuming you are not the originator of the project, you need to follow the coding style of the project as well")]),_v(" "),_c('li',[_v("Since there are always multiple ways of doing the same thing, it is often arguable which way is the best. When joining an already established project, it is critical to follow the coding style of your predecessors")]),_v(" "),_c('li',[_v("An example would be returning a complete object instead of a part of an object and appending to a newly created object in the parent function. Both accomplish the same thing and arguably are equally understandable")])])])]),_v(" "),_c('p',[_v("I learned about code quality through analysing the responses of seniors to my own pull requests as well as other's pull requests, supplementing my knowledge by reading articles on code quality both generally and specific to web development")]),_v(" "),_c('ul',[_c('li',[_v("Inspection of pull requests gave me understanding of what is good quality code and what is considered bad along with the reasoning behind those decisions")]),_v(" "),_c('li',[_v("Articles online provided me with more general guidelines pertaining to code quality in large projects, helping fill in the gaps that I didnt encounter in PR reviews")])]),_v(" "),_c('h3',{attrs:{"id":"testing"}},[_v("Testing"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#testing","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Testing is another important part of any project as it reduces the occurrence of major errors and bugs throughout development. With little prior experience in testing, I sought to learn more about it and apply it in WATcher.")]),_v(" "),_c('ul',[_c('li',[_v("Jasmine\n"),_c('ul',[_c('li',[_v("A testing framework for javascript")]),_v(" "),_c('li',[_v("Clean and intuitive syntax")]),_v(" "),_c('li',[_v("Suite of functionality developed over many years")]),_v(" "),_c('li',[_v("I learned Jasmine through looking through test cases in CATcher and WATcher, along with reading its official documentation\n"),_c('ul',[_c('li',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("describe(string, function)")]),_v(" houses related specs labeled by string and defined as function")]),_v(" "),_c('li',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("it(string, function)")]),_v(" defines a spec labeled by string and defined as function")]),_v(" "),_c('li',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("expect(any).toBeFalse")]),_v(" defines an expectation of "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("any")]),_v(". There are a large number of matchers for any possible comparison")]),_v(" "),_c('li',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("beforeEach(function)")]),_v(" defines a function to be called before each of the specs in this describe block")]),_v(" "),_c('li',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("createSpyObj(string, string[])")]),_v(" creates a spy object that acts as a stub for classes that are depended on by what is being tested. Spies can track calls to it and all arguments")])])])])]),_v(" "),_c('li',[_v("Test case design\n"),_c('ul',[_c('li',[_v("Boundary Value Analysis and equivalence partitioning\n"),_c('ul',[_c('li',[_v("Boundary value analysis is a technique where tests are designed to include representatives of boundary values in a range")]),_v(" "),_c('li',[_v("Equivalence partitioning is a technique where input data is partitioned into units of equivalent data for which tests can be written")]),_v(" "),_c('li',[_v("These techniques allow for a smaller number of tests to be written, for essentially the same amount of coverage\n"),_c('ul',[_c('li',[_v("This is because inputs which would fail/pass for the same reason, such as being an input of an invalid type, are grouped as a single or only a few test cases.")]),_v(" "),_c('li',[_v("The alternative would be to create tests for each input type in this example, straining developer resources for not much benefit")])])])])]),_v(" "),_c('li',[_v("Testing for behaviour\n"),_c('ul',[_c('li',[_v("A common mistake is to test for implementation rather than behaviour")]),_v(" "),_c('li',[_v("This would result in failed test cases when implementation changes even though the resulting behaviour, what the user would experience, remains the same")]),_v(" "),_c('li',[_v("Test cases should test for what the result is versus what the implementation is")]),_v(" "),_c('li',[_v("An example would be testing whether a variable changes in component A correctly vs testing what other components receive from component A after the change")]),_v(" "),_c('li',[_v("A developer might edit the implementation of component A so the variable no longer changes, however the accurate behaviour of emission to other components remains the same and the test cases should not fail")])])]),_v(" "),_c('li',[_v("Testing coverage\n"),_c('ul',[_c('li',[_v("Test coverage is how much of the code has actually been ran through during testing\n"),_c('ul',[_c('li',[_v("Function/method coverage : based on functions executed e.g., testing executed 90 out of 100 functions")]),_v(" "),_c('li',[_v("Statement coverage : based on the number of lines of code executed e.g., testing executed 23k out of 25k LOC")]),_v(" "),_c('li',[_v("Decision/branch coverage : based on the decision points exercised e.g., an if statement evaluated to both true and false with separate test cases during testing is considered 'covered'")]),_v(" "),_c('li',[_v("Condition coverage : based on the boolean sub-expressions, each evaluated to both true and false with different test cases")])])]),_v(" "),_c('li',[_v("A good future implementation would be to implement code coverage as a github action report when making pull requests to main")]),_v(" "),_c('li',[_v("At the very least, all public functions of a class should be uniquely tested in order to verify behaviour seen by other components\nI learned about testing web applications through Nereus, reading Jasmine documentation, articles and youtube videos about testing and the "),_c('a',{attrs:{"href":"https://nus-cs2113-ay2324s2.github.io/website/index.html"}},[_v("CS2113 website")])])])])])]),_v(" "),_c('li',[_v("Nereus imparted knowledge of testing which helped me understand the core fundamentals, allowing me to more quickly pick up the technique as I learnt, especially the test case implementation")]),_v(" "),_c('li',[_v("The Jasmine documentation gave me confidence in creating my own test cases for unique behaviour such as changing routes in testing")]),_v(" "),_c('li',[_v("Youtube videos, articles and the CS2113 website helped me to understand and implement test case design techniques to create comprehensive and well designed test cases")])])])])],1)],1),_v(" "),_c('div',[_c('box',[_c('h2',{attrs:{"id":"misra-aditya"}},[_v("MISRA ADITYA"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#misra-aditya","onclick":"event.stopPropagation()"}})]),_v(" "),_c('div',{staticClass:"container"},[_c('div',{staticClass:"row"},[_c('div',{staticClass:"col"},[_c('img',{attrs:{"src":"/2024/students/MadLamprey/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/MadLamprey"}},[_v("https://www.github.com/MadLamprey")])]),_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',[_c('h3',{attrs:{"id":"summary"}},[_v("Summary"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#summary","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("In WATcher, I primarily identified critical UI issues, significantly enhancing interface and service functionalities to boost user experience and application efficiency. I also contributed to the documentation of WATcher to aid future development. In CATcher, my focus was on migrating the linter from TSLint to ESLint, a crucial step that enhanced code quality and facilitated better maintainability.")]),_v(" "),_c('h3',{attrs:{"id":"details"}},[_v("Details"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#details","onclick":"event.stopPropagation()"}})]),_v(" "),_c('h4',{attrs:{"id":"catcher-2"}},[_v("CATcher"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#catcher-2","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_c('strong',[_v("PRs Opened")])]),_v(" "),_c('div',{staticClass:"table-responsive"},[_c('table',{staticClass:"markbind-table table table-bordered table-striped"},[_c('thead',[_c('tr',[_c('th',[_v("Week")]),_v(" "),_c('th',[_v("PR")])])]),_v(" "),_c('tbody',[_c('tr',[_c('td',[_v("2")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher/pull/1237"}},[_v("#1237")]),_v(" Add whitespace validation")])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher/pull/1250"}},[_v("#1250")]),_v(" Migrate from TSLint to ESLint")])])])])]),_c('h4',{attrs:{"id":"watcher"}},[_v("WATcher"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#watcher","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_c('strong',[_v("Issues Created")])]),_v(" "),_c('div',{staticClass:"table-responsive"},[_c('table',{staticClass:"markbind-table table table-bordered table-striped"},[_c('thead',[_c('tr',[_c('th',[_v("Week")]),_v(" "),_c('th',[_v("Issue")])])]),_v(" "),_c('tbody',[_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/266"}},[_v("#266")]),_v(" Upgrade to Angular 12")])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/361"}},[_v("#361")]),_v(" Make ItemsPerPage common for all card views")])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/363"}},[_v("#363")]),_v(" Remodel the design of the Filter bar")])])])])]),_c('p',[_c('strong',[_v("PRs Opened")])]),_v(" "),_c('div',{staticClass:"table-responsive"},[_c('table',{staticClass:"markbind-table table table-bordered table-striped"},[_c('thead',[_c('tr',[_c('th',[_v("Week")]),_v(" "),_c('th',[_v("PR")])])]),_v(" "),_c('tbody',[_c('tr',[_c('td',[_v("2")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/228"}},[_v("#228")]),_v(" Prevent redirection when repo not set")])]),_v(" "),_c('tr',[_c('td',[_v("4")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/252"}},[_v("#252")]),_v(" Upgrade to Angular 11")])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/267"}},[_v("#267")]),_v(" Upgrade to Angular 12")])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/286"}},[_v("#286")]),_v(" Remove sorting by assignees in Issue Sorter")])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/303"}},[_v("#303")]),_v(" Create tests for Milestone service")])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/304"}},[_v("#304")]),_v(" Create tests for Error Handling service")])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/307"}},[_v("#307")]),_v(" Add tool tip for hidden users")])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/315"}},[_v("#315")]),_v(" Split 'Without a milestone' option")])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/318"}},[_v("#318")]),_v(" Add sorting by Status")])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/337"}},[_v("#337")]),_v(" Add icon for PRs without milestones")])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/362"}},[_v("#362")]),_v(" Make ItemsPerPage common for all card views")])])])])]),_c('p',[_c('strong',[_v("PRs Reviewed")])]),_v(" "),_c('div',{staticClass:"table-responsive"},[_c('table',{staticClass:"markbind-table table table-bordered table-striped"},[_c('thead',[_c('tr',[_c('th',[_v("Week")]),_v(" "),_c('th',[_v("PR")])])]),_v(" "),_c('tbody',[_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/260"}},[_v("#260")]),_v(" Remove test cases for permissions service")])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/313"}},[_v("#313")]),_v(" Integrate Grouping Service")])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/334"}},[_v("#334")]),_v(" Fix default preset view")])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"xhttps://github.com/CATcher-org/WATcher/pull/350"}},[_v("#350")]),_v(" Deploy v1.2.1")])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/351"}},[_v("#351")]),_v(" Enable automated testing on the deploy branch")])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/364"}},[_v("#364")]),_v(" Create release V1.2.2")])])])])]),_c('h4',{attrs:{"id":"watcher-docs"}},[_v("WATcher-docs"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#watcher-docs","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_c('strong',[_v("PRs Opened")])]),_v(" "),_c('div',{staticClass:"table-responsive"},[_c('table',{staticClass:"markbind-table table table-bordered table-striped"},[_c('thead',[_c('tr',[_c('th',[_v("Week")]),_v(" "),_c('th',[_v("PR")])])]),_v(" "),_c('tbody',[_c('tr',[_c('td',[_v("5")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher-docs/pull/13"}},[_v("#13")]),_v(" Add devcontainer support")])]),_v(" "),_c('tr',[_c('td',[_v("5")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher-docs/pull/14"}},[_v("#14")]),_v(" Update Design page")])])])])])])]),_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-2"}},[_v("Angular"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#angular-2","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Underpinning the development of CATcher and WATcher, it was of paramount importance to understand the nuances of the Angular framework. This presented a challenge, transitioning from ReactJs - a framework I was comfortable with. The structure of Angular, contrasted with React's flexibility, necessitated a deep and rigorous engagement with Angular's ecosystem.")]),_v(" "),_c('ul',[_c('li',[_c('strong',[_v("Transitioning from ReactJs")]),_v(":\n"),_c('ul',[_c('li',[_v("I was initially struck by Angular's comprehensive framework, which unlike ReactJs's straightforward library-based approach, provides a full suite of development tools. Angular mandates a structured environment that rigorously applies TypeScript for static typing, modules for encapsulation, and injectors for dependency management, ensuring robust, scalable applications. This all-inclusive nature required adapting to a relatively complex development environment.")])])]),_v(" "),_c('li',[_c('strong',[_v("Angular Directives and DOM Manipulation")]),_v(":\n"),_c('ul',[_c('li',[_v("Directives are essentially markers that Angular allows us to attach to elements to influence their behaviour in a specific way.")]),_v(" "),_c('li',[_v("These constructs allow for direct DOM manipulation, a capability not native to React. I leveraged structural directives like "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("*ngIf")]),_v(" for conditional rendering, and attribute directives to modify behaviors of DOM elements dynamically. This exploration provided practical insights into complex DOM operations without full page reloads, facilitating rich, responsive user interactions.")])])]),_v(" "),_c('li',[_c('strong',[_v("Form Validation with Angular Validators")]),_v(":\n"),_c('ul',[_c('li',[_v("Linking back to the use of Angular Directives, their coupling with Validators makes for robustness and expressiveness, especially in the case of forms, to allow for proper feedback to be given to the user.")]),_v(" "),_c('li',[_v("I learned about the creation and use of custom validators as part of the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("@angular/forms")]),_v(" library, which are a crucial aspect of an application that consists of Form-based components. Angular's form validation is highly robust, integrated deeply with its reactive and template-driven forms, facilitating complex form handling with built-in validators and custom validation functions. In contrast, React forms often require additional libraries for similar levels of validation robustness.")])])]),_v(" "),_c('li',[_c('strong',[_v("Software Maintenance")]),_v(":\n"),_c('ul',[_c('li',[_v("In a bid to keep the application and its dependencies up-to-date, constant upgrade to newer versions of the tech stack used, is crucial. This also falls in line with our goal to follow best software practices.")]),_v(" "),_c('li',[_v("My role extended to maintaining the application's health by upgrading Angular and its ecosystem. This task required a thorough understanding of semantic versioning, dependency conflicts, and the Angular update cycle. React, while flexible, typically requires third-party tools to manage similar tasks, leading to a more hands-on and sometimes fragmented maintenance experience.")])])])]),_v(" "),_c('p',[_v("Through contributions and an extensive understanding of the codebase, I have attained a certain degree of comfort with Angular as a frontend framework, and will further practice the use of Angular and its features in personal projects.")]),_v(" "),_c('h3',{attrs:{"id":"docker-integration-in-watcher-documentation"}},[_v("Docker Integration in WATcher Documentation"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#docker-integration-in-watcher-documentation","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Incorporating Docker into the WATcher documentation development process was a strategic move to standardize and streamline the development environment. My involvement with setting up a Dev Container using Docker provided valuable insights into containerization and its impact on development workflows.")]),_v(" "),_c('ul',[_c('li',[_c('strong',[_v("Understanding and Implementing Dev Containers")]),_v(":\n"),_c('ul',[_c('li',[_v("Dev Containers provide a consistent, isolated, and replicable development environment for all contributors, regardless of their local setup. This is crucial for eliminating differences observed in working on the development environment on different systems.")]),_v(" "),_c('li',[_v("I utilized Docker to encapsulate the build environment into a Docker Image, defined by a Dockerfile. This approach ensures that all dependencies and runtime environments are uniformly configured across different development setups.")])])]),_v(" "),_c('li',[_c('strong',[_v("Customization and Configuration")]),_v(":\n"),_c('ul',[_c('li',[_v("The use of the VSCode Dev Container as a base allowed for significant customization tailored to the specific needs of the WATcher documentation project. By parameterizing the build process ("),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("devcontainer.json")]),_v("), I was able to define and manage configurations such as environment variables, port forwarding, and startup commands efficiently.")]),_v(" "),_c('li',[_v("One of the key benefits of implementing Docker was significantly reducing the onboarding time for new developers. By providing a container that includes all necessary dependencies pre-installed and pre-configured, new team members could get up and running with minimal setup.")])])])]),_v(" "),_c('p',[_v("Working with Docker deepened my understanding of containerization technologies and their role in modern software development. It highlighted the importance of infrastructure as code (IaC) in automating and simplifying development processes. It reinforced best practices in DevOps, particularly in terms of environment standardization.")]),_v(" "),_c('h3',{attrs:{"id":"linters"}},[_v("Linters"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#linters","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("As part of maintaining development tools, I worked on migrating the project from using TSLint (which is now deprecated), to ESLint. This helped me understand the true role of linters, and how they are defined for a project.")]),_v(" "),_c('ul',[_c('li',[_c('strong',[_v("Understanding Linters")]),_v(":\n"),_c('ul',[_c('li',[_v("As studied in CS2103T, linters are vital tools in modern software development, used for static code analysis to enforce coding standards and identify problematic patterns in the code. My experience with linters deepened during the migration, reinforcing their role in improving code quality, reducing bugs, and maintaining consistency across large codebases.")])])]),_v(" "),_c('li',[_c('strong',[_v("The Migration Process")]),_v(":\n"),_c('ul',[_c('li',[_v("The migration from TSLint to ESLint involved a strategic review and translation of linting rules to ensure continuity and adherence to our established coding practices. Despite the availability of automated tools like "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("tslint-to-eslint")]),_v(", which attempts to convert configurations, many rules required manual adjustments to align with ESLint’s syntax and capabilities, as well as to not make too many disruptive changes to the codebase.")]),_v(" "),_c('li',[_v("This process was meticulous, involving:\n"),_c('ul',[_c('li',[_c('strong',[_v("Rule Assessment")]),_v(": Evaluating each TSLint rule and its impact on our codebase, determining essential rules, and mapping them to their ESLint counterparts.")]),_v(" "),_c('li',[_c('strong',[_v("Configuration Translation")]),_v(": Manually configuring ESLint rules where automated tools fell short, ensuring that our new linting setup maintained the integrity and intent of the original rules without compromising on code quality.")]),_v(" "),_c('li',[_c('strong',[_v("Testing and Adjustment")]),_v(": Rigorously testing the new ESLint configurations across our projects to identify any discrepancies and adjust rules to better fit our development practices and project specifics.")])])]),_v(" "),_c('li',[_v("ESLint provides comprehensive support for both JavaScript and TypeScript, offering a unified linting solution that reduces complexity and improves analysis accuracy. ESLint’s architecture allows for extensive customization and extension, enabling the integration of plugins that address specific needs such as React-specific linting rules or accessibility checks.")])])])]),_v(" "),_c('p',[_v("The migration to ESLint has not only streamlined the development environment but also enriched my understanding of effective coding practices.")]),_v(" "),_c('h3',{attrs:{"id":"jasmine"}},[_v("Jasmine"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#jasmine","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("While developing tests for the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("ErrorHandlingService")]),_v(" and "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("MilestoneService")]),_v(" in WATcher, I gained significant insights into Jasmine's powerful features and how they can be leveraged to create thorough, reliable, and maintainable test suites.")]),_v(" "),_c('ul',[_c('li',[_c('strong',[_v("Behavior-Driven Development Approach")]),_v(":\n"),_c('ul',[_c('li',[_v("Jasmine's BDD framework encourages a more descriptive and natural language style in writing tests, which aligns well with how software behavior is described in real-world scenarios.")])])]),_v(" "),_c('li',[_c('strong',[_v("Mocking and Spying")]),_v(":\n"),_c('ul',[_c('li',[_v("Jasmine's mocking and spying capabilities were instrumental in isolating the tests. By creating spy objects for dependencies like "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("MatSnackBar")]),_v(" and "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("LoggingService")]),_v(", I could simulate their behavior and assert that they were being called correctly without actually triggering real side effects.")]),_v(" "),_c('li',[_v("A spy object was created for "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("GithubService")]),_v(" using Jasmine's "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("createSpyObj")]),_v(" method, which allowed us to simulate its "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("fetchAllMilestones")]),_v(" method without actual HTTP requests. This approach isolates the test environment from external dependencies.")])])]),_v(" "),_c('li',[_c('strong',[_v("Asynchronous Testing")]),_v(":\n"),_c('ul',[_c('li',[_v("The use of RxJS's of function to return observable sequences makes the method calls predictable and easily testable.")]),_v(" "),_c('li',[_v("Jasmine's asynchronous testing capability, demonstrated with the done callback, was crucial. It ensures that tests involving observables only complete after all asynchronous operations have been resolved, providing an accurate assessment of the method's behavior.")])])]),_v(" "),_c('li',[_c('strong',[_v("Conditional Behavior Testing")]),_v(":\n"),_c('ul',[_c('li',[_v("The "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("handleError()")]),_v(" method's conditional logic, which dictates different responses based on the error type, highlighted the importance of comprehensive test paths. I learned to utilize Jasmine's "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("it")]),_v(" blocks effectively to specify and isolate each logical branch within the method. This practice ensures that every potential execution path is tested, which is crucial for error handling logic where different types of errors can lead to different user experiences.")])])])]),_v(" "),_c('p',[_v("This exploration into Jasmine's capabilities not only enhanced my technical skills but also deepened my understanding of strategic test planning and execution in a behavior-driven development context. The experience emphasized the value of detailed, well-structured tests in maintaining high software quality and reliability.")]),_v(" "),_c('h3',{attrs:{"id":"ui-ux-design"}},[_v("UI/UX Design"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#ui-ux-design","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("A rather inconspicuous but significant learning point, while working on WATcher and CATcher, was UI and UX design. Since the main aim of these applications is to assist students, tutors, professors to understand, contextualise and identify key information with ease, several design decisions had to made from the point of view of how it would most benefit the users.")]),_v(" "),_c('p',[_v("Some of these included:")]),_v(" "),_c('ol',[_c('li',[_c('p',[_c('strong',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/361"}},[_v("#361")]),_v(" Make ItemsPerPage common for all card views")])]),_v(" "),_c('ul',[_c('li',[_v("Implementing a consistent ItemsPerPage filter across different views ensures that users have a predictable and stable interface, improving usability and reducing cognitive load.")])])]),_v(" "),_c('li',[_c('p',[_c('strong',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/363"}},[_v("#363")]),_v(" Remodel the design of the Filter bar")])]),_v(" "),_c('ul',[_c('li',[_v("Redesigning the filter bar to create a design that is both functionally effective and aesthetically pleasing, requiring a balance between form and function.")])])]),_v(" "),_c('li',[_c('p',[_c('strong',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/307"}},[_v("#307")]),_v(" Add tool tip for hidden users")])]),_v(" "),_c('ul',[_c('li',[_v("Adding tooltips is a critical aspect of UI design for enhancing user understanding without cluttering the interface, to ensure that they appear in contexts where users most need guidance.")])])]),_v(" "),_c('li',[_c('p',[_c('strong',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/318"}},[_v("#318")]),_v(" Add sorting by Status")])]),_v(" "),_c('ul',[_c('li',[_v("Understanding of the most logical ways users might want to organize data, enhancing the application's usability.")])])]),_v(" "),_c('li',[_c('p',[_c('strong',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/337"}},[_v("#337")]),_v(" Add icon for PRs without milestones")])]),_v(" "),_c('ul',[_c('li',[_v("The use of icons to convey information is a staple in UI design, providing visual cues that help users quickly grasp the status of items.")])])])]),_v(" "),_c('p',[_v("Working on these PRs likely provided a deep dive into the principles of user-centered design, focusing on enhancing the user's journey through intuitive layouts, actionable insights, and consistent behaviors across the application. The challenges often revolved around integrating new features without disrupting the existing user experience, requiring careful consideration of design continuity and user expectations.")])])])],1)],1),_v(" "),_c('div',[_c('box',[_c('h2',{attrs:{"id":"nereus-ng-wei-bin"}},[_v("NEREUS NG WEI BIN"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#nereus-ng-wei-bin","onclick":"event.stopPropagation()"}})]),_v(" "),_c('div',{staticClass:"container"},[_c('div',{staticClass:"row"},[_c('div',{staticClass:"col"},[_c('img',{attrs:{"src":"/2024/students/NereusWB922/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/NereusWB922"}},[_v("https://github.com/NereusWB922")])]),_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":"https://github.com/CATcher-org/WATcher"}},[_v("WATcher")])])])])])]),_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',[_c('h3',{attrs:{"id":"summary-2"}},[_v("Summary"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#summary-2","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ul',[_c('li',[_c('strong',[_v("Fix Bugs")]),_v(": Fix uncaught error for invalid link navigation in CATcher and some minor bugs found in WATcher preset view feature.")]),_v(" "),_c('li',[_c('strong',[_v("Testing Aspect")]),_v(": Refactored outdated test cases in WATcher and enable automated testing in pre-push hooks and GitHub Actions.")]),_v(" "),_c('li',[_c('strong',[_v("New Feature")]),_v(": Implemented an extensible group by feature for WATcher's Issue Viewer. Currently, it supports grouping by assignee and milestone.")]),_v(" "),_c('li',[_c('strong',[_v("User Experience")]),_v(": Improved WATcher's Activity Dashboard design. Implemented a dropdown menu for easier repo change in WATcher's Issue Viewer.")]),_v(" "),_c('li',[_c('strong',[_v("Managing")]),_v(": Deployed CATcher V1.2.0 in week 10.")])]),_v(" "),_c('div',{staticClass:"table-responsive"},[_c('table',{staticClass:"markbind-table table table-bordered table-striped"},[_c('thead',[_c('tr',[_c('th',[_v("Week")]),_v(" "),_c('th',[_v("Achievements")])])]),_v(" "),_c('tbody',[_c('tr',[_c('td',[_v("3")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher/pull/1239"}},[_v("Uncaught error when invalid link is clicked #1239")])])]),_v(" "),_c('tr',[_c('td',[_v("4")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/233"}},[_v("Improve activity dashboard design #233")])])]),_v(" "),_c('tr',[_c('td',[_v("4")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/241"}},[_v("Refactor test cases for Login Component, Session Model and Conflict Model #241")])])]),_v(" "),_c('tr',[_c('td',[_v("4")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/243"}},[_v("Remove markdown.css from test env stylesheets #243")])])]),_v(" "),_c('tr',[_c('td',[_v("4")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/244"}},[_v("Refactor test cases for issue paginator #244")])])]),_v(" "),_c('tr',[_c('td',[_v("4")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/245"}},[_v("Refactor test cases for issue sorter #245")])])]),_v(" "),_c('tr',[_c('td',[_v("4")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/246"}},[_v("Refactor github label constants #246")])])]),_v(" "),_c('tr',[_c('td',[_v("4")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/247"}},[_v("Refactor test cases for search filter #247")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/259"}},[_v("Refactor certain filters into its own service #259")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/260"}},[_v("Remove test cases for permissions service #260")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Submitted issue: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher/issues/1251"}},[_v("Improve E2E testing #1251")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher/pull/257"}},[_v("Refactor test cases for Issue Model #257")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher/pull/258"}},[_v("Refactor test cases for Label Service #258")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher/pull/262"}},[_v("Remove constants for DataFile and Team model #262")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher/pull/263"}},[_v("Refactor test cases for Phase Service #263")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Submitted issue: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/268"}},[_v("Encounter error for npm run test after upgrading to Angular v11 #268")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher/pull/269"}},[_v("Fix zone testing import error #269")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher/pull/270"}},[_v("Refactor test cases for issue sorter #270")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher/pull/271"}},[_v("Refactor test cases for user service #271")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher/pull/274"}},[_v("Refactor test cases for label filter bar component #274")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher/pull/275"}},[_v("Update test cases for phase service #275")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/288"}},[_v("Enable pre push hook for npm run test #288")])])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/290"}},[_v("Create tests for ErrorMessage, ErrorHandling and Milestone services #290")])])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/303"}},[_v("Create tests for Milestone service #303")])])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_v("Submitted issue: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/306"}},[_v("GroupBy Feature #306")])])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/281"}},[_v("Keep filters when switching repos #281")])])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/307"}},[_v("Add tool tip for hidden users #307")])])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/291"}},[_v("Refactor Phase Service and remove Phase #291")])])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/308"}},[_v("Setup grouping strategy and service #308")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/311"}},[_v("Keep milestones when switching repo #311")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/313"}},[_v("Integrate Grouping Service #313")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Submitted issue: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/317"}},[_v("Encode grouping to url #317")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/320"}},[_v("Add preset views #320")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/316"}},[_v("Implement group by milestone #316")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Submitted issue: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/321"}},[_v("Update IssueViewer's Repo on Back/Forward Navigation #321")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/319"}},[_v("Include groupby params in url #319")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/322"}},[_v("Update repo on back and forward navigation #322")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/323"}},[_v("Refactor MilestoneGroupingStrategy to match the changes in #315 #323")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/324"}},[_v("Reset GroupingContextService only if \"keep filter\" is selected #324")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/326"}},[_v("Fix for no milestone case #326")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/314"}},[_v("Add filters to url #314")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/325"}},[_v("Enable npm run test in GitHub Action #325")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/331"}},[_v("Deploy V1.2.0 #331")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/334"}},[_v("Fix default preset view #334")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/338"}},[_v("Fix preset view selection appearance #338")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Submitted issue: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/341"}},[_v("Provide preset value for groupby #341")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Submitted issue: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/342"}},[_v("Add filter for assignee #342")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/339"}},[_v("Show prs without milestone #339")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/347"}},[_v("Implement dropdown menu for repo change #347")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/345"}},[_v("Remove quotation marks from url #345")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/346"}},[_v("Hide column issue count #346")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/355"}},[_v("Show preset view only when repo is set #355")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/356"}},[_v("Fix top shadow hiding of columns #356")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/357"}},[_v("Fix bottom shadow of columns #357")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Submitted issue: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/358"}},[_v("Milestone without deadline is not considered as currently active #358")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/357"}},[_v("Fix top and bottom shadow of columns #357")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/360"}},[_v("Optimise Github API calls #360")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/359"}},[_v("Consider open milestone without deadline as currently active #359")])])])])])])])]),_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-3"}},[_v("Angular"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#angular-3","onclick":"event.stopPropagation()"}})]),_v(" "),_c('h4',{attrs:{"id":"components"}},[_v("Components"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#components","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Components are the main building blocks for Angular. Each components consists of 3 files:")]),_v(" "),_c('ul',[_c('li',[_c('strong',[_v("HTML")]),_v(": Defines the layout of the component's view.")]),_v(" "),_c('li',[_c('strong',[_v("CSS")]),_v(": Defines the component-specific styles.")]),_v(" "),_c('li',[_c('strong',[_v("Typescript")]),_v(": Implements the component's logic and behavior.")])]),_v(" "),_c('p',[_v("Refer to the "),_c('a',{attrs:{"href":"https://angular.io/guide/component-overview"}},[_v("Angular Documentation")]),_v(" for guidelines on creating components.")]),_v(" "),_c('h4',{attrs:{"id":"attribute-directive"}},[_v("Attribute Directive"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#attribute-directive","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Attribute directives can change the appearance or behavior of DOM elements and Angular components.")]),_v(" "),_c('p',[_v("For detailed guidance, refer to the "),_c('a',{attrs:{"href":"https://angular.io/guide/attribute-directives"}},[_v("Angular Documentation")]),_v(". It provides guidelines on creating and applying attribute directive, covering user events handling and passing values to attribute directive.")]),_v(" "),_c('p',[_v("In "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher/pull/1239"}},[_v("PR #1239")]),_v(", I implemented an attribute directive that listen to click event and will open error snackbar if the target link is an internal link.")]),_v(" "),_c('h4',{attrs:{"id":"ngtemplateoutlet"}},[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("NgTemplateOutlet")]),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#ngtemplateoutlet","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("NgTemplateOutlet")]),_v(" is a directive in Angular that allows for "),_c('strong',[_v("dynamic rendering")]),_v(" of templates. It allows the template to be specified along with the context data that should be injected into it.")]),_v(" "),_c('p',[_v("I utilized "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("NgTemplateOutlet")]),_v(" to dynamically render different headers for the card view component based on current grouping criteria. Refer to "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/blob/main/src/app/issues-viewer/card-view/card-view.component.html"}},[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("CardViewComponenet")])]),_v(" for implementation details.")]),_v(" "),_c('h3',{attrs:{"id":"jasmine-2"}},[_v("Jasmine"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#jasmine-2","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Jasmine is a behavior-driven development framewrok specific for JavaScript unit testing.")]),_v(" "),_c('p',[_v("I primarily learned how to use Jasmine from its "),_c('a',{attrs:{"href":"https://jasmine.github.io/api/edge/global"}},[_v("documentation")]),_v(". I utilized it extensively while working on WATcher test case refactoring. Some relevant PRs include: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/241"}},[_v("PR #241")]),_v(", "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/244"}},[_v("PR #244")]),_v(", "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/245"}},[_v("PR #245")]),_v(", "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/246"}},[_v("PR #246")]),_v(", "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/247"}},[_v("PR #247")])]),_v(" "),_c('ul',[_c('li',[_c('strong',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("describe")])]),_v(": Define a group of spec (suite)")]),_v(" "),_c('li',[_c('strong',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("it")])]),_v(": Define a single spec.")]),_v(" "),_c('li',[_c('strong',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("expect")])]),_v(": Create an expectation for a spec.")]),_v(" "),_c('li',[_c('strong',[_v("Class "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Spy")])]),_v(": Mock functions (spies) that can be used to track function calls.")])]),_v(" "),_c('h4',{attrs:{"id":"asynchronous-testing-with-observables"}},[_v("Asynchronous Testing with Observables"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#asynchronous-testing-with-observables","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("When dealing with asynchronous operations like observables, Jasmine provides support through the use of the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("done")]),_v(" function. This allows for effective testing of asynchronous behavior by signaling when a test has completed its execution.")]),_v(" "),_c('p',[_v("Here's an example from my "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/275"}},[_v("pull request")]),_v(":")]),_v(" "),_c('pre',[_c('code',{pre:true,attrs:{"class":"hljs javascript"}},[_c('span',[_v("it("),_c('span',{pre:true,attrs:{"class":"hljs-string"}},[_v("'should throw error for URL without repo parameter'")]),_v(", "),_c('span',{pre:true,attrs:{"class":"hljs-function"}},[_v("("),_c('span',{pre:true,attrs:{"class":"hljs-params"}},[_v("done")]),_v(") =>")]),_v(" {\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("const")]),_v(" urlWithoutRepo = "),_c('span',{pre:true,attrs:{"class":"hljs-string"}},[_v("'/issuesViewer'")]),_v(";\n")]),_c('span',[_v("\n")]),_c('span',[_v(" phaseService.setupFromUrl(urlWithoutRepo).subscribe({\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-attr"}},[_v("error")]),_v(": "),_c('span',{pre:true,attrs:{"class":"hljs-function"}},[_v("("),_c('span',{pre:true,attrs:{"class":"hljs-params"}},[_v("err")]),_v(") =>")]),_v(" {\n")]),_c('span',[_v(" expect(err).toEqual("),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("new")]),_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-built_in"}},[_v("Error")]),_v("(ErrorMessageService.invalidUrlMessage()));\n")]),_c('span',[_v(" done(); "),_c('span',{pre:true,attrs:{"class":"hljs-comment"}},[_v("// Signal that the test has completed")]),_v("\n")]),_c('span',[_v(" }\n")]),_c('span',[_v(" });\n")]),_c('span',[_v("});\n")])])]),_c('p',[_v("Resources: "),_c('a',{attrs:{"href":"https://medium.com/google-developer-experts/angular-2-unit-testing-with-jasmine-defe20421584#59a4"}},[_v("Angular — Unit Testing recipes (v2+)")])]),_v(" "),_c('h4',{attrs:{"id":"testing-for-behavior"}},[_v("Testing for Behavior"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#testing-for-behavior","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("It's essential to test for behavior rather than implementation details. This principle was emphasized by a senior in my pull reqeust. By focusing on behavior, tests become more resilient to changes in the codebase and provide better documentation for how components and functions should be used.")]),_v(" "),_c('p',[_v("Here's an example that illustrates the difference between testing behavior and implementation:")]),_v(" "),_c('p',[_v("Context: "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("changeRepositoryIfValid")]),_v(" will call "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("changeCurrentRepository")]),_v(" if repository is valid.")]),_v(" "),_c('pre',[_c('code',{pre:true,attrs:{"class":"hljs javascript"}},[_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-comment"}},[_v("// Test for behavior")]),_v("\n")]),_c('span',[_v("it("),_c('span',{pre:true,attrs:{"class":"hljs-string"}},[_v("'should set current repository if repository is valid'")]),_v(", "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("async")]),_v(" () => {\n")]),_c('span',[_v(" githubServiceSpy.isRepositoryPresent.and.returnValue("),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("of")]),_v("("),_c('span',{pre:true,attrs:{"class":"hljs-literal"}},[_v("true")]),_v("));\n")]),_c('span',[_v("\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("await")]),_v(" phaseService.changeRepositoryIfValid(WATCHER_REPO);\n")]),_c('span',[_v("\n")]),_c('span',[_v(" expect(phaseService.currentRepo).toEqual(WATCHER_REPO);\n")]),_c('span',[_v("});\n")]),_c('span',[_v("\n")]),_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-comment"}},[_v("// Test for implementation")]),_v("\n")]),_c('span',[_v("it("),_c('span',{pre:true,attrs:{"class":"hljs-string"}},[_v("'should call changeRepository method if repository is valid'")]),_v(", "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("async")]),_v(" () => {\n")]),_c('span',[_v(" githubServiceSpy.isRepositoryPresent.and.returnValue("),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("of")]),_v("("),_c('span',{pre:true,attrs:{"class":"hljs-literal"}},[_v("true")]),_v("));\n")]),_c('span',[_v("\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("const")]),_v(" changeCurrentRepositorySpy = spyOn(phaseService, "),_c('span',{pre:true,attrs:{"class":"hljs-string"}},[_v("'changeCurrentRepository'")]),_v(");\n")]),_c('span',[_v("\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("await")]),_v(" phaseService.changeRepositoryIfValid(WATCHER_REPO);\n")]),_c('span',[_v("\n")]),_c('span',[_v(" expect(changeCurrentRepositorySpy).toHaveBeenCalledWith(WATCHER_REPO);\n")]),_c('span',[_v("});\n")])])]),_c('h3',{attrs:{"id":"design-pattern"}},[_v("Design Pattern"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#design-pattern","onclick":"event.stopPropagation()"}})]),_v(" "),_c('h4',{attrs:{"id":"strategy-design-pattern"}},[_v("Strategy Design Pattern"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#strategy-design-pattern","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("The Strategy design pattern allows for the selection of algorithms at runtime by defining a family of interchangeable algorithms and encapsulating each one. It enables flexibility and easy extension of functionality without modifying existing code.")]),_v(" "),_c('p',[_v("I utilized the Strategy Design Pattern to implement a "),_c('strong',[_v("\"Group by\"")]),_v(" feature that organizes issues / prs based on different criteria.")]),_v(" "),_c('p',[_v("Implementation of group by feature :")]),_v(" "),_c('ul',[_c('li',[_v("Grouping Strategy Interface ("),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/blob/main/src/app/core/services/grouping/grouping-strategy.interface.ts"}},[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("GroupingStrategy")])]),_v("): Defines a common interface for all supported grouping strategies.")]),_v(" "),_c('li',[_v("Concrete Grouping Strategy: Each strategy groups the issues/prs based on different criterias.\n"),_c('ul',[_c('li',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/blob/main/src/app/core/services/grouping/assignee-grouping-strategy.service.ts"}},[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("AssigneeGroupingStrategy")])])]),_v(" "),_c('li',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/blob/main/src/app/core/services/grouping/milestone-grouping-strategy.service.ts"}},[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("MilestoneGroupingStrategy")])])])])]),_v(" "),_c('li',[_v("Context ("),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/blob/main/src/app/core/services/grouping/grouping-context.service.ts"}},[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("GroupingContextService")])]),_v("): This service is used to apply the grouping strategies based on user selection.")])])])])],1)],1),_v(" "),_c('div',[_c('box',[_c('h2',{attrs:{"id":"nguyen-khoi-nguyen"}},[_v("NGUYEN KHOI NGUYEN"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#nguyen-khoi-nguyen","onclick":"event.stopPropagation()"}})]),_v(" "),_c('div',{staticClass:"container"},[_c('div',{staticClass:"row"},[_c('div',{staticClass:"col"},[_c('img',{attrs:{"src":"/2024/students/nknguyenhc/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/nknguyenhc"}},[_v("https://github.com/nknguyenhc")])]),_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":"https://github.com/CATcher-org/WATcher"}},[_v("WATcher")])])])])])]),_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',[_c('h3',{attrs:{"id":"summary-3"}},[_v("Summary"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#summary-3","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("In CATcher, I mainly fixed bugs and made small enhancements in functionalities. In WATcher, I contributed to the enhancement of the issue viewer - the main functionality of WATcher.")]),_v(" "),_c('h3',{attrs:{"id":"details-2"}},[_v("Details"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#details-2","onclick":"event.stopPropagation()"}})]),_v(" "),_c('h4',{attrs:{"id":"catcher-3"}},[_v("CATcher"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#catcher-3","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_c('strong',[_v("PRs opened")])]),_v(" "),_c('div',{staticClass:"table-responsive"},[_c('table',{staticClass:"markbind-table table table-bordered table-striped"},[_c('thead',[_c('tr',[_c('th',[_v("Week")]),_v(" "),_c('th',[_v("PR")])])]),_v(" "),_c('tbody',[_c('tr',[_c('td',[_v("<1")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher/pull/1233"}},[_v("#1233")]),_v(" Fix broken duplicate links")])]),_v(" "),_c('tr',[_c('td',[_v("<1")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher/pull/1234"}},[_v("#1234")]),_v(" Default branch to "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("main")])])]),_v(" "),_c('tr',[_c('td',[_v("4")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher/pull/1241"}},[_v("#1241")]),_v(" Preserve line breaks in markdown")])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher/pull/1245"}},[_v("#1245")]),_v(" Fix markddown blockquote preview difference")])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher/pull/1256"}},[_v("#1256")]),_v(" Add login redirect")])])])])]),_c('p',[_c('strong',[_v("PRs reviewed")])]),_v(" "),_c('div',{staticClass:"table-responsive"},[_c('table',{staticClass:"markbind-table table table-bordered table-striped"},[_c('thead',[_c('tr',[_c('th',[_v("Week")]),_v(" "),_c('th',[_v("PR")])])]),_v(" "),_c('tbody',[_c('tr',[_c('td',[_v("5")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher/pull/1243"}},[_v("#1243")]),_v(" Faulty list view when back navigating")])])])])]),_c('h4',{attrs:{"id":"watcher-2"}},[_v("WATcher"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#watcher-2","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_c('strong',[_v("PRs opened")])]),_v(" "),_c('div',{staticClass:"table-responsive"},[_c('table',{staticClass:"markbind-table table table-bordered table-striped"},[_c('thead',[_c('tr',[_c('th',[_v("Week")]),_v(" "),_c('th',[_v("PR")])])]),_v(" "),_c('tbody',[_c('tr',[_c('td',[_v("2")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/230"}},[_v("#230")]),_v(" Fix label filter not working")])]),_v(" "),_c('tr',[_c('td',[_v("3")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/235"}},[_v("#235")]),_v(" Show list of hidden users")])]),_v(" "),_c('tr',[_c('td',[_v("4")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/254"}},[_v("#254")]),_v(" Refactor Label model")])]),_v(" "),_c('tr',[_c('td',[_v("5")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/255"}},[_v("#255")]),_v(" Add shareable repo-specific URL")])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/282"}},[_v("#282")]),_v(" Three-state labels")])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/309"}},[_v("#309")]),_v(" Hide redundant column pagination")])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/310"}},[_v("#310")]),_v(" Status filter checkboxes")])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/320"}},[_v("#320")]),_v(" Add preset views")])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/326"}},[_v("#326")]),_v(" Fix for no milestone case")])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/327"}},[_v("#327")]),_v(" Create release 1.2.0")])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/338"}},[_v("#338")]),_v(" Fix preset view selection appearance")])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/346"}},[_v("#346")]),_v(" Hide column issue count")])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/360"}},[_v("#360")]),_v(" Optimise Github API calls")])])])])]),_c('p',[_c('strong',[_v("Issues created")])]),_v(" "),_c('div',{staticClass:"table-responsive"},[_c('table',{staticClass:"markbind-table table table-bordered table-striped"},[_c('thead',[_c('tr',[_c('th',[_v("Week")]),_v(" "),_c('th',[_v("Issue")])])]),_v(" "),_c('tbody',[_c('tr',[_c('td',[_v("2")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/229"}},[_v("#229")]),_v(" App filters do not work with some label names")])]),_v(" "),_c('tr',[_c('td',[_v("3")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/236"}},[_v("#236")]),_v(" Bypass logging in if viewing public repos only")])]),_v(" "),_c('tr',[_c('td',[_v("3")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/240"}},[_v("#240")]),_v(" Hiding labels do not work as expected")])]),_v(" "),_c('tr',[_c('td',[_v("4")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/251"}},[_v("#251")]),_v(" Add shareable repo-specific URL")])]),_v(" "),_c('tr',[_c('td',[_v("5")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/256"}},[_v("#256")]),_v(" Refactor test cases for Label model")])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/277"}},[_v("#277")]),_v(" Add current filters to URL")])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/278"}},[_v("#278")]),_v(" Make URL redirect to work with activity dashboard")])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/287"}},[_v("#287")]),_v(" Reading property of "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("undefined")]),_v(" when switching repo in activity dashboard")])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/343"}},[_v("#343")]),_v(" Hide column issue count if only one page")])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/344"}},[_v("#344")]),_v(" Change the repo change form from popup to dropdown")])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/371"}},[_v("#371")]),_v(" Horizontal scrollbar on an issue card")])])])])]),_c('p',[_c('strong',[_v("PRs reviewed")])]),_v(" "),_c('div',{staticClass:"table-responsive"},[_c('table',{staticClass:"markbind-table table table-bordered table-striped"},[_c('thead',[_c('tr',[_c('th',[_v("Week")]),_v(" "),_c('th',[_v("PR")])])]),_v(" "),_c('tbody',[_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/261"}},[_v("#261")]),_v(" Refactor sorting")])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/281"}},[_v("#281")]),_v(" Keep filters when switching repos")])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/307"}},[_v("#307")]),_v(" Add tooltip for hidden users")])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/308"}},[_v("#308")]),_v(" Setup grouping strategy and service")])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/311"}},[_v("#311")]),_v(" Keep milestones when switching repo")])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/313"}},[_v("#313")]),_v(" Integrate Grouping Service")])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/314"}},[_v("#314")]),_v(" Add filters to url")])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/315"}},[_v("#315")]),_v(" Split 'Without a milestone' option")])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/316"}},[_v("#316")]),_v(" Implement group by milestone")])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/318"}},[_v("#318")]),_v(" Add sorting by Status")])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/322"}},[_v("#322")]),_v(" Update repo on back and forth navigation")])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/323"}},[_v("#323")]),_v(" Refactor MilestoneGroupingStrategy to match changes in #315")])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/325"}},[_v("#325")]),_v(" Enable npm run test in Github Action")])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/331"}},[_v("#331")]),_v(" Deploy V1.2.0")])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/337"}},[_v("#337")]),_v(" Add icon for PRs without milestones")])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/347"}},[_v("#337")]),_v(" Implement dropdown menu for repo change")])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/359"}},[_v("#359")]),_v(" Consider open milestone without deadline as currently active")])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/374"}},[_v("#374")]),_v(" Fix reset of filters on label fetch")])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/375"}},[_v("#375")]),_v(" fix: word-break issue in issue-pr-card-header.component.css #371")])])])])])])]),_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-4"}},[_v("Angular"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#angular-4","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Of course, Angular is the framework used to run CATcher and WATcher, so learning how it works is an essential part of contributing to the projects. These projects are my first experience using Angular.")]),_v(" "),_c('p',[_v("As I have experienced React.js and Alpine.js, with experience of working in frontend development during my internship, I expected to pick up Angular with ease. However, slightly different from my expectation, the OOP aspect of Angular makes it quite difficult to pick up.")]),_v(" "),_c('p',[_v("There are a few interesting concepts that I picked up along the way:")]),_v(" "),_c('ul',[_c('li',[_v("Each class is decorated with "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("@Component")]),_v(" to mark it as an Angular component. This decorator determines a few important properties of the component, including the query selector, the HTML template and the stylesheets.")]),_v(" "),_c('li',[_v("Class fields, if used in HTML templates, updates the rendered HTML template if its value is changed. In React.js, this is only possible with a state hook.")]),_v(" "),_c('li',[_v("Dependencies of a component can be injected from root using factory methods, and does not have to be explicitly instantiated.")])]),_v(" "),_c('p',[_v("The knowledge of how a component is declared allows me to confidently create a new component in "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/235"}},[_v("WATcher-PR#235")]),_v(", which was the component to show a list of users with 0 PRs and issues.")]),_v(" "),_c('p',[_v("One interesting thing about Angular is that it provides a few methods that developers can make use of, to reduce the complexity of component class. This knowledge allows me to make "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/230"}},[_v("WATcher-PR#230")]),_v(", where I directly modified the Angular model used in the HTML template.")]),_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 initially had a lot of trouble trying to understand the operators in RxJS. Ultimately, I was able to understand how it works, and the differences between different operators on an "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Observable")]),_v(". I was able to see the similarities between different RxJS operators and Java "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("stream")]),_v(" methods.")]),_v(" "),_c('ul',[_c('li',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Observable::pipe")]),_v(" allows methods to modify the value within the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Observable")]),_v(", notably with "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("map")]),_v(" and "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("mergeMap")]),_v(".")]),_v(" "),_c('li',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Observable::subscribe")]),_v(" listens for changes within the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Observable")]),_v(".")])]),_v(" "),_c('p',[_v("The knowledge of RxJS operators allow me to modify the underlying processes of the Angular services, and created "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher/pull/1234"}},[_v("CATcher-PR#1234")]),_v(", where I set branch for image uploads to "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("main")]),_v(".")]),_v(" "),_c('p',[_v("One thing to note about RxJS operator is that, "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Observable")]),_v(" pipes are treated as functions, in a sense that they are only called when there is a subscriber. If there are multiple pipes merged into one, each individual pipes are called when there is a subscriber. Consider this example:")]),_v(" "),_c('pre',[_c('code',{pre:true,attrs:{"class":"hljs ts"}},[_c('span',[_v("Observable a = "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("from")]),_v("(); "),_c('span',{pre:true,attrs:{"class":"hljs-comment"}},[_v("// some declaration")]),_v("\n")]),_c('span',[_v("Observable b = a.pipe(f);\n")]),_c('span',[_v("Observable x = b.pipe(g);\n")]),_c('span',[_v("Observable y = b.pipe(h);\n")]),_c('span',[_v("Observable c = merge(x, y);\n")]),_c('span',[_v("c.subscribe();\n")])])]),_c('p',[_v("Notice that "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("c")]),_v(" is a merged "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Observable")]),_v(" from pipes of "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("f, g")]),_v(" and "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("f, h")]),_v(". So, "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("g")]),_v(" and "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("h")]),_v(" each are called once, but "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("f")]),_v(" is called twice! Imagine if "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("f")]),_v(" is a function making multiple API calls to Github.")]),_v(" "),_c('p',[_v("This knowledge allows me to "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/360/files#diff-7006ea7c06fd1129a5fc2c0aefbf660f5b2ddf1821ede1c269a2f8f1a9c971bc"}},[_v("reduce Github API calls for issues")]),_v(". To get issues from a repository, one must make multiple API calls, each obtaining 100 issues. These API calls are contained within the function "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("f")]),_v(". So instead of splitting the pipe, I refactored to merge "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("g")]),_v(" and "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("h")]),_v(" and continue the pipe from "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("b")]),_v(":")]),_v(" "),_c('pre',[_c('code',{pre:true,attrs:{"class":"hljs ts"}},[_c('span',[_v("Observable a = "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("from")]),_v("(); "),_c('span',{pre:true,attrs:{"class":"hljs-comment"}},[_v("// some declaration")]),_v("\n")]),_c('span',[_v("Observable b = a.pipe(f);\n")]),_c('span',[_v("Observable c = b.pipe(merge(g, h));\n")]),_c('span',[_v("c.subscribe();\n")])])])])])],1)],1),_v(" "),_m(10),_v(" "),_c('div',[_c('box',[_c('h2',{attrs:{"id":"eyo-kai-wen-kevin"}},[_v("EYO KAI WEN, KEVIN"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#eyo-kai-wen-kevin","onclick":"event.stopPropagation()"}})]),_v(" "),_c('div',{staticClass:"container"},[_c('div',{staticClass:"row"},[_c('div',{staticClass:"col"},[_c('img',{attrs:{"src":"/2024/students/KevinEyo1/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/KevinEyo1"}},[_v("https://www.github.com/KevinEyo1")])]),_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',[_c('h3',{attrs:{"id":"markbind-2"}},[_v("MarkBind"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#markbind-2","onclick":"event.stopPropagation()"}})]),_v(" "),_c('div',{staticClass:"table-responsive"},[_c('table',{staticClass:"markbind-table table table-bordered table-striped"},[_c('thead',[_c('tr',[_c('th',[_v("Week")]),_v(" "),_c('th',[_v("Achievements")])])]),_v(" "),_c('tbody',[_c('tr',[_c('td',[_v("2")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2400"}},[_v("MarkBind Template for Software Project Documentation#2400")])])]),_v(" "),_c('tr',[_c('td',[_v("4")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2406"}},[_v("Enhance search performance of algolia plugin #2406")])])]),_v(" "),_c('tr',[_c('td',[_v("5")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2406"}},[_v("Enhance search performance of algolia plugin #2406")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2429"}},[_v("Utilize GitHub Actions to aid checking of commit message #2429")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2429"}},[_v("Utilize GitHub Actions to aid checking of commit message #2429")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2439"}},[_v("Upgrade simple-git version #2439")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2439"}},[_v("Upgrade simple-git version #2439")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2440"}},[_v("UG > PagNav: Misleading sentence #2440")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2440"}},[_v("UG > PagNav: Misleading sentence #2440")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Submitted Issue: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2458"}},[_v("Fancylists to package MarkBind's current and future list features #2458")])])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2454"}},[_v("Customizing list icons: give a way to apply to current item only #2454")])])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_v("Submitted Issue: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2464"}},[_v("Utilize GitHub Actions to check for SEMVER impact label #2464")])])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2470"}},[_v("Utilize GitHub Actions to check for SEMVER impact label #2464")])])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_v("Researched Issue: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2359"}},[_v("Bootstrap migration tracker #2359")])])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2398"}},[_v("MarkBind Template for Student Portfolio #2398")])])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_v("Researched Issue: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2187"}},[_v("[Feature request] Tag (keywortd) support #2187")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Researched Issue: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2464"}},[_v("Utilize GitHub Actions to check for SEMVER impact label #2464")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2470"}},[_v("Utilize GitHub Actions to check for SEMVER impact label #2464")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Submitted Issue: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2479"}},[_v("Reusable workflow repo for all repos under organisation #2479")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2400"}},[_v("MarkBind Template for Software Project Documentation#2400")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2484"}},[_v("Add a reminder when contributor is new to ping all contributor bot #2484")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Submitted Issue: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2488"}},[_v("Improve security of GitHub Actions workflows #2488")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Researched Issue: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2488"}},[_v("Improve security of GitHub Actions workflows #2488")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Researched Issue: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2448"}},[_v("Explore using Bun for testing and setup #2448")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2454"}},[_v("Customizing list icons: give a way to apply to current item only #2454")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Researched Issue: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2140"}},[_v("Utilize GitHub Action to aid PR review #2140")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2510"}},[_v("Improve security of GitHub Actions workflows #2510")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2514"}},[_v("UG: images appear in two places #2514")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2484"}},[_v("Add a reminder when contributor is new to ping all contributor bot #2484")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2510"}},[_v("Improve security of GitHub Actions workflows #2510")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Researched Issue: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2495"}},[_v("Add github action to automatically unassign issues after a certain period of inactivity #2495")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2514"}},[_v("UG: images appear in two places #2514")])])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2521"}},[_v("Fix workflow file deploy-docs #2521")])])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2521"}},[_v("Fix workflow file deploy-docs #2521")])])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_v("Researched Issue: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2495"}},[_v("Add github action to automatically unassign issues after a certain period of inactivity #2495")])])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2523"}},[_v("Using DangerJS to check changes coupling of implementation files to test or documentation files #2523")])])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_v("Submitted Issue: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2527"}},[_v("Add documentation for workflow security for GitHub Actions #2527")])])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2528"}},[_v("Add documentation regarding security practices for github actions #2528")])])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2523"}},[_v("Using DangerJS to check changes coupling of implementation files to test or documentation files #2523")])])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2528"}},[_v("Add documentation regarding security practices for github actions #2528")])])])])])])])]),_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":"summary-of-key-contributions"}},[_v("Summary of Key Contributions"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#summary-of-key-contributions","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Worked on adding "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2400"}},[_v("Software Project Documentation")]),_v(" template to MarkBind, allowing for users to have a starting point for using MarkBind in their project documentation.")]),_v(" "),_c('p',[_v("Researched into possible integrations of "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2448"}},[_v("Bun")]),_v(" and "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2359"}},[_v("Bootstrap v5.2 and v5.3")]),_v(" into MarkBind, to determine the value and feasibility of these integrations.")]),_v(" "),_c('p',[_v("Worked on "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2454"}},[_v("customizing list icons")]),_v(", such that icons for list items can be customized to apply to the current item only instead of default inheritance to future items.")]),_v(" "),_c('p',[_v("Worked largely on DevOps side of MarkBind, utilizing GitHub Actions and workflows to handle automation of tasks. These tasks include checking for "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2429"}},[_v("commit messages in PR descriptions")]),_v(", "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2470"}},[_v("SEMVER impact labels")]),_v(", "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2484"}},[_v("reminding adding of new contributors to contributor list")]),_v(".")]),_v(" "),_c('p',[_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2140"}},[_v("Researched")]),_v(" and "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2523"}},[_v("implemented")]),_v(" the use of DangerJS to automate checking of changes coupling of implementation files to test or documentation files, to ensure that any changes to the repository is properly documented and tested.")]),_v(" "),_c('p',[_v("Researched into the implementation of automating "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2495"}},[_v("unassigning of assigned users to issues")]),_v(" after a certain period of inactivity.")]),_v(" "),_c('p',[_v("Researched into "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2488"}},[_v("common security practices")]),_v(" for GitHub Actions, and "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2510"}},[_v("implementing these practices")]),_v(" into the MarkBind repository. These practices are also "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2528"}},[_v("documented")]),_v(" for future contributors to the project.")]),_v(" "),_c('h3',{attrs:{"id":"markbind-codebase"}},[_v("MarkBind codebase"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#markbind-codebase","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Learned the underlying workings and how different parts of the codebase are linked together to provide MarkBind's functionalities. From the parser to the renderer, and the different plugins that can be used to extend MarkBind's capabilities. Learned how to implement new features, adding relevant test and documentation to ensure that the codebase is maintainable and modifiable.")]),_v(" "),_c('h3',{attrs:{"id":"github-actions"}},[_v("GitHub Actions"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#github-actions","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Learned how GitHub Actions fits into the development workflow, and how to use it to automate tasks. I used the GitHub Actions documentation to learn about the different types of workflows, how to create and configure workflows, and how to use the different actions available.")]),_v(" "),_c('ul',[_c('li',[_c('p',[_c('strong',[_v("Resource")]),_v(": "),_c('a',{attrs:{"href":"https://docs.github.com/en/actions"}},[_v("GitHub Actions Documentation")])])]),_v(" "),_c('li',[_c('p',[_c('strong',[_v("Summary")]),_v(": GitHub Actions makes it easy to automate all your software workflows, now with world-class CI/CD. Build, test, and deploy your code right from GitHub. Make code reviews, branch management, and issue triaging work the way you want.")])]),_v(" "),_c('li',[_c('p',[_c('strong',[_v("Resource")]),_v(": "),_c('a',{attrs:{"href":"https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions"}},[_v("GitHub Actions Workflow Syntax")])])]),_v(" "),_c('li',[_c('p',[_c('strong',[_v("Summary")]),_v(": GitHub Actions uses YAML syntax to define the events, jobs, and steps that make up your workflow. You can create a custom workflow or use a starter workflow template to get started.")])]),_v(" "),_c('li',[_c('p',[_c('strong',[_v("Resource")]),_v(": "),_c('a',{attrs:{"href":"https://docs.github.com/en/actions/security-guides/automatic-token-authentication"}},[_v("GITHUB_TOKEN")])])]),_v(" "),_c('li',[_c('p',[_c('strong',[_v("Summary")]),_v(": The GITHUB_TOKEN is a GitHub Actions token that is automatically generated by GitHub and used to authenticate in a workflow run. It is scoped to the repository that contains the workflow file, and can be used to perform read and write operations on the repository. It is automatically available to your workflow and does not need to be stored as a secret.")])])]),_v(" "),_c('p',[_v("Learned yaml and bash for creation of workflows.")]),_v(" "),_c('ul',[_c('li',[_c('p',[_c('strong',[_v("Resource")]),_v(": "),_c('a',{attrs:{"href":"https://www.cloudbees.com/blog/yaml-tutorial-everything-you-need-get-started"}},[_v("YAML Syntax")])])]),_v(" "),_c('li',[_c('p',[_c('strong',[_v("Summary")]),_v(": YAML is a human-readable data serialization standard that can be used in conjunction with all programming languages and is often used to write configuration files. It can also be used in workflows to define the structure of the workflow, including the events, jobs, and steps that make up the workflow.")])]),_v(" "),_c('li',[_c('p',[_c('strong',[_v("Resource")]),_v(": "),_c('a',{attrs:{"href":"https://devhints.io/bash"}},[_v("Bash Scripting")])])]),_v(" "),_c('li',[_c('p',[_c('strong',[_v("Summary")]),_v(": Bash is a Unix shell and command language written by Brian Fox for the GNU Project as a free software replacement for the Bourne shell. It has been distributed widely as the shell for the GNU operating system and as a default shell on Linux and OS X.")])]),_v(" "),_c('li',[_c('p',[_c('strong',[_v("Resource")]),_v(": "),_c('a',{attrs:{"href":"https://web.archive.org/web/20230408142504/https://wiki.bash-hackers.org/syntax/pe"}},[_v("Bash Parameter Expansion")])])]),_v(" "),_c('li',[_c('p',[_c('strong',[_v("Summary")]),_v(": Parameter expansion is a way to manipulate variables in Bash. It is a form of variable substitution that allows for the manipulation of variables in various ways.")])])]),_v(" "),_c('p',[_v("Learned how to use other actions in workflows, such as the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("actions/checkout")]),_v(" action to check out a repository onto the runner, allowing subsequent steps to execute operations on the checked-out repository.")]),_v(" "),_c('ul',[_c('li',[_c('strong',[_v("Resource")]),_v(": "),_c('a',{attrs:{"href":"https://github.com/marketplace"}},[_v("GitHub Marketplace")])]),_v(" "),_c('li',[_c('strong',[_v("Summary")]),_v(": The GitHub Marketplace is a collection of actions that can be used in your workflows. You can search for actions by category, language, or other criteria, and use them in your workflows to automate tasks.")])]),_v(" "),_c('p',[_v("Learned how to use DangerJS to aid with workflows.")]),_v(" "),_c('ul',[_c('li',[_c('strong',[_v("Resource")]),_v(": "),_c('a',{attrs:{"href":"https://danger.systems/js/"}},[_v("DangerJS")])]),_v(" "),_c('li',[_c('strong',[_v("Summary")]),_v(": Danger runs during your CI process, and helps with automating common code review chores. This provides another layer of automation over the code review process, ensuring that all changes are properly documented and tested.")])]),_v(" "),_c('p',[_c('strong',[_v("When to create new workflows (outside of modifiability)")]),_v("\nAlthough keeping multiple jobs within the same workflow file is possible, sometimes it may be better not to. Jobs are run based on event triggers such as pull requests etc, but you must add it to the top. This meant that if you had multiple jobs in the same workflow file, they would all run when the event trigger was activated. If you wanted a trigger to only trigger a specific job, you would need to add a check to exclude all other jobs from that trigger.")]),_v(" "),_c('p',[_v("Pull request trigger by default has the types "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("opened")]),_v(", "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("synchronize")]),_v(", and "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("reopened")]),_v(".")]),_v(" "),_c('p',[_c('strong',[_v("Testing and debugging workflows")]),_v("\nThis can be done locally with the help of Docker and act.")]),_v(" "),_c('p',[_v("Benefits of local testing:\nFast Feedback - Avoid commit/push every time you want to test out the changes.")]),_v(" "),_c('ul',[_c('li',[_c('p',[_c('strong',[_v("Resource")]),_v(": "),_c('a',{attrs:{"href":"https://nektosact.com/usage/index.html"}},[_v("Act Usage")])])]),_v(" "),_c('li',[_c('p',[_c('strong',[_v("Summary")]),_v(": Act reads in your GitHub Actions from .github/workflows/ and determines the set of actions that need to be run. It uses the Docker API to either pull or build the necessary images, as defined in your workflow files and finally determines the execution path based on the dependencies that were defined. Once it has the execution path, it then uses the Docker API to run containers for each action based on the images prepared earlier.")])]),_v(" "),_c('li',[_c('p',[_c('strong',[_v("Resource")]),_v(": "),_c('a',{attrs:{"href":"https://docs.docker.com/get-started/overview/"}},[_v("Docker Docs")])])]),_v(" "),_c('li',[_c('p',[_c('strong',[_v("Summary")]),_v(":")])])]),_v(" "),_c('p',[_v("Steps (PR):")]),_v(" "),_c('ol',[_c('li',[_v("Download act and Docker.")]),_v(" "),_c('li',[_v("Start up Docker daemon.")]),_v(" "),_c('li',[_v("Create a JSON file with the appropriate PR file structure (can use python script to generate it).")]),_v(" "),_c('li',[_v("Run "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("act pull_request -j specific-job -e pr-event.json")]),_v(" to run a specific job on the PR event environment.")])]),_v(" "),_c('h4',{attrs:{"id":"keywords"}},[_v("Keywords"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#keywords","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("uses")]),_v(":\nCan be used to reference an action in the same repository, a public repository, or a published Docker container image. The "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("uses")]),_v(" keyword can also be used to reference an action in a private repository by specifying the repository using the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("repository")]),_v(" keyword.")]),_v(" "),_c('p',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("env")]),_v(":\nIt is best to avoid having expressions "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("${{ }}")]),_v(" in "),_c('em',[_v("run")]),_v(" portion of a step. Instead, "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("env")]),_v(" allows defining of variables that store the expression.")]),_v(" "),_c('p',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("awk")]),_v(" :\nCan be used to extract a section of body, from a line containing "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("START")]),_v(" to a line containing "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("END")]),_v(" (inclusive of full line).\n"),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("section=$(echo \"$body\" | awk '/START/,/END/')")])]),_v(" "),_c('h4',{attrs:{"id":"use-of-third-party-actions"}},[_v("Use of third-party actions"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#use-of-third-party-actions","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ul',[_c('li',[_c('strong',[_v("Resource")]),_v(": "),_c('a',{attrs:{"href":"https://github.com/marketplace?type=actions"}},[_v("GitHub Actions Marketplace")])]),_v(" "),_c('li',[_c('strong',[_v("Summary")]),_v(": The GitHub Actions Marketplace is a collection of actions that can be used in your workflows. You can search for actions by category, language, or other criteria, and use them in your workflows to automate tasks.")])]),_v(" "),_c('p',[_v("Useful actions:")]),_v(" "),_c('div',{staticClass:"table-responsive"},[_c('table',{staticClass:"markbind-table table table-bordered table-striped"},[_c('thead',[_c('tr',[_c('th',[_v("Action")]),_v(" "),_c('th',[_v("Description")])])]),_v(" "),_c('tbody',[_c('tr',[_c('td',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("actions/checkout@v3")])]),_v(" "),_c('td',[_v("Check out a repository onto the runner, allowing subsequent steps to execute operations on the checked-out repository, i.e. gaining access to the repository's code.")])]),_v(" "),_c('tr',[_c('td',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("actions/github-script@v7")])]),_v(" "),_c('td',[_v("Run a script in the GitHub Actions environment using the GitHub CLI. Refer to "),_c('a',{attrs:{"href":"https://octokit.github.io/rest.js/v20"}},[_v("here")])])]),_v(" "),_c('tr',[_c('td',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("actions/setup-node@v3")])]),_v(" "),_c('td',[_v("Set up a Node.js environment for use in workflows.")])]),_v(" "),_c('tr',[_c('td',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("actions/stale")])]),_v(" "),_c('td',[_v("Close stale issues and pull requests.")])]),_v(" "),_c('tr',[_c('td',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("boundfoxstudios/action-unassign-contributor-after-days-of-inactivity")])]),_v(" "),_c('td',[_v("Automatically unassign user from issues after a certain period of inactivity.")])])])])]),_c('h4',{attrs:{"id":"extra-information-about-how-stale-and-unassign-actions-work-in-the-context-of-markbind"}},[_v("Extra information about how stale and unassign actions work in the context of MarkBind"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#extra-information-about-how-stale-and-unassign-actions-work-in-the-context-of-markbind","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("The definition of inactivity for the GitHub action is any form of history to the issue, be it labeling, comments or references. The action works such that issues and PRs are treated and checked for inactivity separately. This means that any updates done to a PR regarding this issue, will not reset inactivity for the issue.")]),_v(" "),_c('p',[_v("How unassign and stale actions work:")]),_v(" "),_c('ol',[_c('li',[_v("Stale action adds "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Stale")]),_v(" label to issue or PR based on inactivity (default 60 days)")]),_v(" "),_c('li',[_v("Unassign action routinely checks for this "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Stale")]),_v(" label, then checks whether it's been a set amount of days after the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Stale")]),_v(" label has been added with no other activity (default 7 days)")]),_v(" "),_c('li',[_v("For issues passing the check before, it un-assigns users and removes "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Stale")]),_v(" label")])]),_v(" "),_c('p',[_c('a',{attrs:{"href":"https://github.com/BoundfoxStudios/fairy-tale-defender/blob/develop/.github/workflows/project-management.yml#L105"}},[_v("Reference workflow of real-life example")])]),_v(" "),_c('h5',{attrs:{"id":"solution-using-unassign-and-stale-actions"}},[_v("Solution using unassign and stale actions"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#solution-using-unassign-and-stale-actions","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Add the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Stale")]),_v(" label after 6 days and ping a reminder, then have the "),_c('a',{attrs:{"href":"https://github.com/marketplace/actions/unassign-contributor-after-days-of-inactivity"}},[_v("unassign-contributor-after-days-of-inactivity")]),_v(" run 1 day after.\nIt can also only check on issues that are actually assigned to someone, so that theres no redundancy.\n"),_c('strong',[_v("Limitations:")])]),_v(" "),_c('ol',[_c('li',[_v("Any changes in PR regarding issue will not reset inactivity of issue, meaning if discussion and updates are done on the PR instead of the issue, the issue risks being "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Stale")]),_v(" and the user being unassigned despite them actively working on the PR.")]),_v(" "),_c('li',[_v("It can ping a general reminder (without resetting the inactivity) but it cannot ping the user directly with "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("@username")]),_v(" in the reminder due to how the code is written. It is possible to separately ping the user in another comment but that will cause a reset in inactivity. This means slightly lower visibility for the reminder.")])]),_v(" "),_c('h5',{attrs:{"id":"improvements-for-limitation-1"}},[_v("Improvements for limitation 1"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#improvements-for-limitation-1","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Building on unassign action, which at some point it might be better off just building our own unassign action for better integration and control\n"),_c('strong',[_v("Check corresponding PR (requires more implementation)")]),_v("\nAdd additional check before setting "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Stale")]),_v(" label to check if corresponding PR has history.\nThis can be done through checking the list of open PRs and their descriptions whether it mentions the issue. It can also be done through looking at the issue’s history, for PRs that mention it, then checking the history of those PRs. This should be quite manageable since the number of open PRs at any point of time is still relatively low for Markbind’s scale.")]),_v(" "),_c('p',[_c('strong',[_v("Check corresponding issue (requires more implementation)")]),_v("\nOn any activity in PRs, check description to find issues linked to the PR, so activity on PR can be translated to activity on the issue as well by posting a comment on the corresponding issue or something of that nature. This might require checking for a specific issue that has the user assigned to avoid commenting on relevant but not directly linked issues, if the PR has multiple relevant issues. We can also only call it on commits instead of any activity, so as to avoid over-polluting the issue with comments.")]),_v(" "),_c('h5',{attrs:{"id":"improvements-for-limitation-2"}},[_v("Improvements for limitation 2"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#improvements-for-limitation-2","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_c('strong',[_v("Ping after unassign")]),_v("\nSame as before, add "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Stale")]),_v(" level after 6 days, but don't need to ping the user, wait until unassign 1 day after, then ping the user that they have been unassigned and if they are still working on it, ask them to reassign themselves. This would likely fit better with a longer timeline.\nThis solves the visibility problem as it can directly ping the user as resetting the inactivity after the user has been unassigned wouldn't matter.")]),_v(" "),_c('p',[_c('strong',[_v("Implement our own stale action (requires more implementation)")]),_v("\nImplement a simplified version of stale action that now allows pinging of user before applying the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Stale")]),_v(" label.")]),_v(" "),_c('h4',{attrs:{"id":"pull-request-target"}},[_v("pull_request_target"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#pull-request-target","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Due to security reasons, for permissions given to "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("GITHUB_TOKEN")]),_v(", the maximum access for pull requests from public forked repositories is restricted to only read, so it is not possible to add labels since there is no write access. GitHub introduced the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("pull_request_target")]),_v(" event that will bypass this restriction and give the token write access.\nPros:")]),_v(" "),_c('ol',[_c('li',[_v("It allows labelling of PR")]),_v(" "),_c('li',[_v("Increased security as base branch workflows can be trusted, protecting job from running modified and malicious workflows\nCons:")]),_v(" "),_c('li',[_v("It can only run on "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("pull_request")]),_v(" events and not "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("pull_request_review")]),_v(" events which means need to run on PR merge rather than on PR approved.")]),_v(" "),_c('li',[_v("This event runs in the context of the base of the pull request, rather than in the context of the merge commit, as the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("pull_request")]),_v(" event does. This could lead to security vulnerabilities if scripts run are not properly checked for malicious code.\nCan be aided by seeking approval before running the job, refer to "),_c('a',{attrs:{"href":"https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/enabling-features-for-your-repository/managing-github-actions-settings-for-a-repository#controlling-changes-from-forks-to-workflows-in-public-repositories"}},[_v("change repo settings")])])]),_v(" "),_c('h5',{attrs:{"id":"alternative-implementations"}},[_v("Alternative implementations"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#alternative-implementations","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_c('a',{attrs:{"href":"https://stackoverflow.com/questions/67247752/how-to-use-secret-in-pull-request-review-similar-to-pull-request-target"}},[_v("Workaround")]),_v("\nPros: this can allow for still triggering on PR approved\nCons: immensely complicates the workflow")]),_v(" "),_c('p',[_v("Personal Access Token (PAT)\nCreate a PAT with the necessary permissions and add it to your repository's secrets. Then, modify the workflow to use this secret instead of the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("GITHUB_TOKEN")]),_v(".\nPros: this can allow for still triggering on PR approved\nCons: exposes your repository to risks if the forked code can access the token")]),_v(" "),_c('h3',{attrs:{"id":"github-actions-security"}},[_v("GitHub Actions Security"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#github-actions-security","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ul',[_c('li',[_c('strong',[_v("Resource")]),_v(": "),_c('a',{attrs:{"href":"https://dev.to/suzukishunsuke/secure-github-actions-by-pullrequesttarget-641"}},[_v("Using pull_request_target")])]),_v(" "),_c('li',[_c('strong',[_v("Resource")]),_v(": "),_c('a',{attrs:{"href":"https://blog.gitguardian.com/github-actions-security-cheat-sheet/"}},[_v("Security and Cheatsheet")])]),_v(" "),_c('li',[_c('strong',[_v("Resource")]),_v(": "),_c('a',{attrs:{"href":"https://securitylab.github.com/research/github-actions-preventing-pwn-requests/"}},[_v("Security Lab")])])]),_v(" "),_c('p',[_c('strong',[_v("Specific version tags")]),_v("\nWhen using third-party actions, pin the version with a commit hash rather than a tag to shield your workflow from potential supply-chain compromise, since tags can be adjusted to a malicious codebase state but commit hashes provide immutability.\nThis can be done by going to the codebase for the specific tag version and looking for the latest commit of the version desired and copying the commit’s full SHA from the url link.\nUse:\n"),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("uses: someperson/post-issue@f054a8b5c1271c37293245628f1cae047eff08c9")]),_v("\nInstead of:\n"),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("uses: someperson/post-issue@v7")]),_v("\nDownside is that the updates must be done by updating the commit hash instead of it being done automatically through moving the tag to a new release.\nThis can be solved by using tools like Dependabot or Renovatebot by adding a comment of the version used, enabling automated dependency updates. Tools like StepSecurity can also be used.")]),_v(" "),_c('p',[_c('strong',[_v("Minimally scoped credentials")]),_v("\nEvery credential used in the workflow should have the minimum required permissions to execute the job.\nIn particular, use the ‘permissions’ key to make sure the GITHUB_TOKEN is configured with the least privileges for each job.\n"),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("permissions")]),_v(" can be restricted at the repo, workflow or job level.\n"),_c('strong',[_v("Environment variables")]),_v(", like "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("${{ secrets.GITHUB_TOKEN }}")]),_v(", should be limited by scope, and should be declared at the step level when possible.")]),_v(" "),_c('p',[_c('strong',[_v("Pull_request_target")]),_v(" (must be used for write access if PR is from forked repo)\nDo not use actions/checkout with this as it can give write permission and secrets access to untrusted code. Any building step, script execution, or even action call could be used to compromise the entire repository. This can be fixed by adding code to ensure that the code being checked out belongs to the base branch, which would also be limiting since the code checked out is not up to date for the PR.\nThis can be done using:")]),_v(" "),_c('pre',[_c('code',{pre:true,attrs:{"class":"hljs"}},[_c('span',[_v("- uses: actions/checkout@v4\n")]),_c('span',[_v(" with:\n")]),_c('span',[_v(" ref: $ \n")])])]),_c('p',[_v("Triggers workflows based on the latest commit of the pull request's base branch.\nEven if workflow files are modified or deleted on feature branches, workflows on the default branch aren't affected so you can prevent malicious code from being executed in CI without code review.\nAnother solution that allows "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("pull_request_target")]),_v(" with "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("actions/checkout")]),_v(" used on the PR branch, is to add an additional step of running workflow only on approval by trusted users, such that the trusted user has to check the changes in the code from the PR to ensure there is no malicious code before running the workflow.")]),_v(" "),_c('p',[_c('strong',[_v("Untrusted input")]),_v("\nDon't directly reference values you do not control, such as "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("echo “${{github.event.pull_request.title}}”")]),_v(", since it can contain malicious code and lead to an injection attack.\nInstead use an action with arguments (recommended):")]),_v(" "),_c('pre',[_c('code',{pre:true,attrs:{"class":"hljs"}},[_c('span',[_v("uses: fakeaction/printtitle@v3 \n")]),_c('span',[_v("with: \n")]),_c('span',[_v("title: $\n")])])]),_c('p',[_v("Or bind the value to an intermediate environment variable:")]),_v(" "),_c('pre',[_c('code',{pre:true,attrs:{"class":"hljs"}},[_c('span',[_v("env: \n")]),_c('span',[_v("PR_TITLE: $\n")]),_c('span',[_v("run: | \n")]),_c('span',[_v("echo “$PR_TITLE” \n")])])]),_c('p',[_v("Use "),_c('a',{attrs:{"href":"https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect"}},[_c('strong',[_v("OIDC")])]),_v(" and respective Secrets Manager for access to cloud providers instead of using secrets.\nUse "),_c('a',{attrs:{"href":"https://docs.github.com/en/actions/security-guides/using-secrets-in-github-actions"}},[_c('strong',[_v("GitHub Secrets")])]),_v(" to store keys securely and reference in workflows using "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("${{}}")]),_v(".\nCan use "),_c('a',{attrs:{"href":"https://github.com/GitGuardian/ggshield-action?ref=blog.gitguardian.com"}},[_c('strong',[_v("GitGuardian Shield")])]),_v(" to help with scanning for security vulnerabilities.")]),_v(" "),_c('h3',{attrs:{"id":"typescript-2"}},[_v("Typescript"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#typescript-2","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Typescript is a superset of JavaScript that adds static typing to the language. By manipulating variables and functions, Typescript can help catch errors before they occur.")]),_v(" "),_c('div',{staticClass:"table-responsive"},[_c('table',{staticClass:"markbind-table table table-bordered table-striped"},[_c('thead',[_c('tr',[_c('th',[_v("Syntax")]),_v(" "),_c('th',[_v("Name")]),_v(" "),_c('th',[_v("Feature")])])]),_v(" "),_c('tbody',[_c('tr',[_c('td',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("?")])]),_v(" "),_c('td',[_v("Optional chaining operator")]),_v(" "),_c('td',[_v("variable returns undefined if doesn't exist. Also used for optional function parameters or class properties")])]),_v(" "),_c('tr',[_c('td',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("??")])]),_v(" "),_c('td',[_v("Nullish coalescing operator")]),_v(" "),_c('td',[_v("returns the right-hand operand when the left-hand operand is null or undefined.")])]),_v(" "),_c('tr',[_c('td',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("!")])]),_v(" "),_c('td',[_v("Non-null assertion operator")]),_v(" "),_c('td',[_v("variable is not null or undefined, only used if you are sure that value will exist.")])])])])]),_c('h3',{attrs:{"id":"process-of-upgrading-dependencies-and-packages"}},[_v("Process of upgrading dependencies and packages"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#process-of-upgrading-dependencies-and-packages","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("MarkBind uses a monorepo structure, which means that multiple packages are contained in a single repository.\nThe process of upgrading dependencies and packages in MarkBind involves the following steps:")]),_v(" "),_c('ol',[_c('li',[_c('p',[_c('strong',[_v("Checking current versions")]),_v(": Check the current versions of the dependencies and packages in the project. This can be done by looking at the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("package.json")]),_v(" file for each project. The command "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("npm ls package_name")]),_v(" will output which packages are using what versions.")])]),_v(" "),_c('li',[_c('p',[_c('strong',[_v("Review changelog and documentation")]),_v(": Review the changelog and documentation for the dependencies and packages to see what changes have been made in the new versions.")])]),_v(" "),_c('li',[_c('p',[_c('strong',[_v("Upgrade dependencies and packages")]),_v(": Update the relevant "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("package.json")]),_v(" file or the root one for dependencies across all packages, then run "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("npm run setup")])])])])])])],1)],1),_v(" "),_c('div',[_c('box',[_c('h2',{attrs:{"id":"lam-jiu-fong"}},[_v("LAM JIU FONG"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#lam-jiu-fong","onclick":"event.stopPropagation()"}})]),_v(" "),_c('div',{staticClass:"container"},[_c('div',{staticClass:"row"},[_c('div',{staticClass:"col"},[_c('img',{attrs:{"src":"/2024/students/LamJiuFong/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/LamJiuFong"}},[_v("https://www.github.com/LamJiuFong")])]),_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',[_c('h3',{attrs:{"id":"summary-of-key-contributions-2"}},[_v("Summary of Key Contributions"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#summary-of-key-contributions-2","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("I have spent most of my time working on "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2302"}},[_v("Issue #2302")]),_v(" where I was trying to make Markbind able to support setting global variables via nunjucks syntax, which would if done, significantly improve users' convenience while using the product.\nI have pushed the progress of solving this issue through various research and experiment efforts through "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2474"}},[_v("this PR")]),_v(".\nLastly, I am able to document the major challenges that developers will face and the common pitfalls when tackling this issue.")]),_v(" "),_c('p',[_v("Other than that, I have also focused on researching/investigating challenging issues that have caused or may cause bugs in Markbind. For example,\n"),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2367"}},[_v("the lazy loading issue")]),_v(", "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2416"}},[_v("gitignore not generated issue")]),_v(", "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2508"}},[_v("issue with script's defer attribute")]),_v(", "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2467"}},[_v("potential npm unlink issue")]),_v(", "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2463"}},[_v("Jest's mock issue")])]),_v(" "),_c('p',[_v("I have also improved users' experience by optimizing our product's performance, related works are "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2450"}},[_v("introducing lazy loading")]),_v(" and "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2522"}},[_v("improve loading speed by moving scripts after the html files are loaded")]),_v(".")]),_v(" "),_c('div',{staticClass:"table-responsive"},[_c('table',{staticClass:"markbind-table table table-bordered table-striped"},[_c('thead',[_c('tr',[_c('th',[_v("Week")]),_v(" "),_c('th',[_v("Progress")])])]),_v(" "),_c('tbody',[_c('tr',[_c('td',[_v("2")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2395"}},[_v("#2395")]),_v(" Allow markbind serve to specify custom host")])]),_v(" "),_c('tr',[_c('td',[_v("4")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2425"}},[_v("#2425")]),_v(" Migrate stylelint to latest version")])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Created Issue: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2451"}},[_v("#2451")]),_v(" Missing output for plugins: Web3Forms")])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Researched on Issue: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2367"}},[_v("#2367")]),_v(" Re-introduce lazy loading")])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2450"}},[_v("#2450")]),_v(" Re-introduce lazy loading")])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_v("Created Issue: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2468"}},[_v("#2468")]),_v(" Allow users to define the height/width in percentages for Pic and Annotate")])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_v("Researched on Issue: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2416"}},[_v("#2416")]),_v(" .gitignore not generated when init")])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2469"}},[_v("#2469")]),_v(" Fix .gitignore not generated bug")])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2463"}},[_v("#2463")]),_v(" Test logger calls in tests for NodeProcessor")])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_v("Researched on Issue: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2467"}},[_v("#2467")]),_v(" Add documentation about npm unlink in DG")])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2474"}},[_v("#2474")]),_v(" Allow setting global variables using nunjucks syntax")])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2484"}},[_v("#2484")]),_v(" Add a reminder when contributor is new to ping all contributor bot")])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2472"}},[_v("#2472")]),_v(" Add the announcement component")])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2481"}},[_v("#2481")]),_v(" Migrate Site.test to Typescript")])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2491"}},[_v("#2491")]),_v(" Allocate space for scrollbar in sitenav and pagenav")])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2492"}},[_v("#2492")]),_v(" Defer scripts in page template")])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Researched on Issue: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2508"}},[_v("#2508")]),_v(" PR2492 causes regression to Modal")])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2522"}},[_v("#2522")]),_v(" Move scripts to bottom in page template")])]),_v(" "),_c('tr',[_c('td',[_v("Reading")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2446"}},[_v("#2446")]),_v(" Add dataTable plugin")])]),_v(" "),_c('tr',[_c('td',[_v("Exam")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2540"}},[_v("#2540")]),_v(" Bump fontawesome to remove console error")])]),_v(" "),_c('tr',[_c('td',[_v("Exam")]),_v(" "),_c('td',[_v("Researched on Issue: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2302"}},[_v("#2302")]),_v(" Add support for setting & importing variables via Nunjucks syntax into global variables")])])])])])])]),_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":"node-package-manager-npm"}},[_v("Node Package Manager (npm)"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#node-package-manager-npm","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("A default package manager for Node.js.")]),_v(" "),_c('ol',[_c('li',[_v("npm simplifies the process of installing, updating, and managing external libraries or modules in a Node.js project.")]),_v(" "),_c('li',[_v("npm allows developers to define and run scripts in their project's package.json file, automating common development tasks.")]),_v(" "),_c('li',[_v("npm allows developers to publish their own packages on the npm registry.")])]),_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('ol',[_c('li',[_v("npm CLI - A powerful tool to interact with npm. Learnt the usages of the basic commands like "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("npm install")]),_v(", "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("npm update")]),_v(", "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("npm run ")]),_v(" etc. and how they helped streamline the development process.")]),_v(" "),_c('li',[_v("package.json - Learnt how to interpret different parts of the json file eg. "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("\"scripts\"")]),_v(", "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("\"dependencies\"")]),_v(" and how to manage them.")]),_v(" "),_c('li',[_v("How to publish my own package to the public.")]),_v(" "),_c('li',[_v("How to use "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v(".npmignore")])])]),_v(" "),_c('h4',{attrs:{"id":"resources"}},[_v("Resources:"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#resources","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ol',[_c('li',[_c('a',{attrs:{"href":"https://docs.npmjs.com/"}},[_v("npm Docs")]),_v(" - Documentation for the npm registry, website, and command-line interface")])]),_v(" "),_c('h3',{attrs:{"id":"stylelint"}},[_v("Stylelint"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#stylelint","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("A CSS linter that helps enforce conventions and avoid errors.")]),_v(" "),_c('ol',[_c('li',[_v("Stylelint has over 100 built-in rules for modern CSS syntax and features, but it is customisable and supports plugins/configs.")]),_v(" "),_c('li',[_v("It can fix problems automatically where possible.")]),_v(" "),_c('li',[_v("It can extract embedded styles from HTML, Markdown and CSS-in-JS template literals.")]),_v(" "),_c('li',[_v("It can also parse CSS-like languages like SCSS, Sass, Less and SugarSS.")])]),_v(" "),_c('h4',{attrs:{"id":"aspects-learnt-2"}},[_v("Aspects learnt:"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#aspects-learnt-2","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ol',[_c('li',[_v("Configuring the linter using the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("stylelintrc.js")]),_v(" file, a configuration object for Stylelint to suit our own needs.")]),_v(" "),_c('li',[_v("Integrating Stylelint into our project.")])]),_v(" "),_c('h4',{attrs:{"id":"resources-2"}},[_v("Resources:"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#resources-2","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ol',[_c('li',[_c('a',{attrs:{"href":"https://stylelint.io/"}},[_v("Stylelint offical Docs")])])]),_v(" "),_c('h3',{attrs:{"id":"commander-js"}},[_v("Commander.js"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#commander-js","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("A JavaScript library that provides a framework for building command-line interfaces (CLIs) in Node.js applications")]),_v(" "),_c('h4',{attrs:{"id":"aspects-learnt-3"}},[_v("Aspects learnt:"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#aspects-learnt-3","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ol',[_c('li',[_v("Define commands, options, and arguments using Commander.js for Markbind.")])]),_v(" "),_c('h4',{attrs:{"id":"resources-3"}},[_v("Resources:"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#resources-3","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ol',[_c('li',[_c('a',{attrs:{"href":"https://www.npmjs.com/package/commander"}},[_v("Commander.js README")])])]),_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("A CI/CD platform allowing developers to automate workflows directly within their GitHub repository.")]),_v(" "),_c('ol',[_c('li',[_v("It supports customised workflows using YAML files to automate tasks such as building, testing, and deploying code.")])]),_v(" "),_c('h4',{attrs:{"id":"aspects-learnt-4"}},[_v("Aspects learnt:"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#aspects-learnt-4","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ol',[_c('li',[_v("Understanding how Github Actions works in a specific repository.")]),_v(" "),_c('li',[_v("Interpreting "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v(".yml")]),_v(" files in "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v(".github/workflow")]),_v(".")])]),_v(" "),_c('h3',{attrs:{"id":"chrome-devtools"}},[_v("Chrome DevTools"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#chrome-devtools","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("A set of web developer tools built directly into the Chrome browser.")]),_v(" "),_c('ol',[_c('li',[_v("We can utilise it to diagnose problems and monitor our program's performance eg. time used for each file to load")]),_v(" "),_c('li',[_v("We can see what is actually happening under the hood eg. which files are loaded before others")])]),_v(" "),_c('h4',{attrs:{"id":"aspects-learnt-5"}},[_v("Aspects learnt:"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#aspects-learnt-5","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ol',[_c('li',[_v("How to check the attributes of each HTML component on the page.")]),_v(" "),_c('li',[_v("How to change the behavior of the browser in terms of loading speed by utilising the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Network")]),_v(" section - disable cache and change network settings")]),_v(" "),_c('li',[_v("How to monitor the behavior and performance of the browser by using the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Performance insights")]),_v(" section")])]),_v(" "),_c('h4',{attrs:{"id":"resources-4"}},[_v("Resources:"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#resources-4","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ol',[_c('li',[_v("Most stack overflow articles will teach us how to interpret the output of Chrome DevTools, I realise it is easy to find such articles by searching \"How to know xxxx\", eg. How to know if lazy loading is working")])]),_v(" "),_c('h3',{attrs:{"id":"nunjucks"}},[_v("Nunjucks"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#nunjucks","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("A template engine for Javascript. It provides a way to mix static content with dynamic data.")]),_v(" "),_c('h4',{attrs:{"id":"aspect-learnt"}},[_v("Aspect learnt:"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#aspect-learnt","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ol',[_c('li',[_v("I mostly learnt about nunjucks' API and learn to integrate it into our project.")]),_v(" "),_c('li',[_v("Learnt how Nunjucks works under the hood, from configuring to parsing to rendering, I have developed a strong understanding on how to integrate Nunjucks to my own project.")])]),_v(" "),_c('h4',{attrs:{"id":"resources-5"}},[_v("Resources:"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#resources-5","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ol',[_c('li',[_c('a',{attrs:{"href":"https://mozilla.github.io/nunjucks/api.html"}},[_v("Nunjucks offiical API")])])]),_v(" "),_c('h3',{attrs:{"id":"jest"}},[_v("Jest"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#jest","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("A Javascript testing framework that focuses on simplicity when writing tests.")]),_v(" "),_c('h4',{attrs:{"id":"aspect-learnt-2"}},[_v("Aspect learnt:"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#aspect-learnt-2","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ol',[_c('li',[_v("Learnt to differentiate mocks and spies and their particular use cases.")]),_v(" "),_c('li',[_v("Learnt how to use "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("jest.mock")]),_v(", "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("jest.fn")]),_v(" to implement mocks and "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("jest.spyOn")]),_v(" to create spies.")])]),_v(" "),_c('h4',{attrs:{"id":"resources-6"}},[_v("Resources:"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#resources-6","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ol',[_c('li',[_c('a',{attrs:{"href":"https://jestjs.io/"}},[_v("Jest official documentation")])]),_v(" "),_c('li',[_c('a',{attrs:{"href":"https://medium.com/@rickhanlonii/understanding-jest-mocks-f0046c68e53c"}},[_v("Explains how to use the three functions")])])]),_v(" "),_c('h3',{attrs:{"id":"mdn-web-docs"}},[_v("mdn web_docs"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#mdn-web-docs","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("A website that documents web technologies for developers. The articles are written by developers that covers a lot of aspects related to the web.")]),_v(" "),_c('h4',{attrs:{"id":"aspects-learnt-6"}},[_v("Aspects learnt:"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#aspects-learnt-6","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ol',[_c('li',[_v("Learnt about some fundamentals about the web eg. how browser renders the files, how the HTML elements like "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("")]),_v(" and "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v(" diff --git a/instructions.page-vue-render.js b/instructions.page-vue-render.js index fcf999821..c8f7de480 100644 --- a/instructions.page-vue-render.js +++ b/instructions.page-vue-render.js @@ -53,6 +53,6 @@ with(this){return _c('h2',{attrs:{"id":"cs3282-updating-the-observations-page"}} with(this){return _c('p',[_v("Update the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("observations.md")]),_v(" page in your folder with relevant observations from your work under the 'External Project' component.")])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/siteData.json b/siteData.json index 9553437fc..b2295e169 100644 --- a/siteData.json +++ b/siteData.json @@ -1120,6 +1120,7 @@ "unit-testing-with-mockito": "Unit Testing with Mockito", "e2e-testing": "E2E Testing", "tye-jia-jun-marques": "TYE JIA JUN, MARQUES", + "datastore": "Datastore", "hibernate-3": "Hibernate", "mockito-2": "Mockito", "docker-2": "Docker", @@ -1190,6 +1191,7 @@ { "src": "students/marquestye/knowledge.md", "headings": { + "datastore": "Datastore", "hibernate": "Hibernate", "mockito": "Mockito", "docker": "Docker" diff --git a/students/Arif-Khalid/info.html b/students/Arif-Khalid/info.html index 116938252..b61387250 100644 --- a/students/Arif-Khalid/info.html +++ b/students/Arif-Khalid/info.html @@ -12,7 +12,7 @@ const baseUrl = '/2024' -
    +
    diff --git a/students/Arif-Khalid/info.page-vue-render.js b/students/Arif-Khalid/info.page-vue-render.js index 02bc17b82..f5b0f0934 100644 --- a/students/Arif-Khalid/info.page-vue-render.js +++ b/students/Arif-Khalid/info.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('p',[_c('span',{attrs:{"id":"github"}},[_c('a',{attrs:{"href":"https://github.com/Arif-Khalid"}},[_v("https://github.com/Arif-Khalid")])])]),_v(" "),_c('p',[_c('span',{attrs:{"id":"projects"}},[_c('a',{attrs:{"href":"https://github.com/CATcher-org"}},[_v("CATcher")])])])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/Arif-Khalid/knowledge.html b/students/Arif-Khalid/knowledge.html index 686967b70..6befd8eec 100644 --- a/students/Arif-Khalid/knowledge.html +++ b/students/Arif-Khalid/knowledge.html @@ -38,7 +38,7 @@
  • Testing coverage
  • Nereus imparted knowledge of testing which helped me understand the core fundamentals, allowing me to more quickly pick up the technique as I learnt, especially the test case implementation
  • The Jasmine documentation gave me confidence in creating my own test cases for unique behaviour such as changing routes in testing
  • Youtube videos, articles and the CS2113 website helped me to understand and implement test case design techniques to create comprehensive and well designed test cases
  • +I learned about testing web applications through Nereus, reading Jasmine documentation, articles and youtube videos about testing and the CS2113 website
  • Nereus imparted knowledge of testing which helped me understand the core fundamentals, allowing me to more quickly pick up the technique as I learnt, especially the test case implementation
  • The Jasmine documentation gave me confidence in creating my own test cases for unique behaviour such as changing routes in testing
  • Youtube videos, articles and the CS2113 website helped me to understand and implement test case design techniques to create comprehensive and well designed test cases
  • diff --git a/students/Arif-Khalid/knowledge.page-vue-render.js b/students/Arif-Khalid/knowledge.page-vue-render.js index 930e6d9c9..71f4b9e17 100644 --- a/students/Arif-Khalid/knowledge.page-vue-render.js +++ b/students/Arif-Khalid/knowledge.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('h3',{attrs:{"id":"angular"}},[_v("Angular"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#angular","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("In order to work on CATcher and WATcher, I had to learn how to use Angular. With a background in react, it was a difficult transition due to the added checks and strict nature of Angular."),_c('br'),_v("\nBelow are a few of my learning points:")]),_v(" "),_c('ul',[_c('li',[_v("Components:\n"),_c('ul',[_c('li',[_v("Each component consists of 4 different files, each of them critical to know. Logic can be contained in either typescript of html component files and you initialise other components through the HTML rather than the typescript file")]),_v(" "),_c('li',[_v("Components also have a module file which is where its dependencies are stated, i.e., the other components, services, modules it depends on")])])]),_v(" "),_c('li',[_v("Services:\n"),_c('ul',[_c('li',[_v("Each service is like a component but without anything to display. They perform functions that could be contained within components but are extracted out to increase modularity and reusability")]),_v(" "),_c('li',[_v("Like components, services can depend on other services and are often injected into components as dependencies")])])]),_v(" "),_c('li',[_v("Modules:\n"),_c('ul',[_c('li',[_v("Modules are containers for a dedicated group of files consisting of components, services or other modules")]),_v(" "),_c('li',[_v("Each module conventionally contains all the code pertaining to a certain feature")]),_v(" "),_c('li',[_v("The root module thus contains all code in the code base, child modules under the root module contain more feature-specific code in a hierarchial structure")]),_v(" "),_c('li',[_v("Modules are critical to understand in order to understand the code base and create new features")])])]),_v(" "),_c('li',[_v("RxJS\n"),_c('ul',[_c('li',[_v("While not exactly part of angular, it is important in learning angular as they are often if not always used in tandem")]),_v(" "),_c('li',[_v("RxJS is a library that allows reactive programming, i.e., the ability to subscribe to changes instead of polling for a change")]),_v(" "),_c('li',[_v("This makes it easier to compose asynchronous and cleaner, more optimized code using observer pattern")]),_v(" "),_c('li',[_v("Observers are a very useful tool that allows me to react to changes by subscribing to an event. This contributes to cleaner, more optimised and reusable code.")]),_v(" "),_c('li',[_v("Pipes allow you to consevutively call functions on the prior function's output, similar to function chaining. This allows us to have cleaner and reusable and more understandable code since you don't need to call functions separately and you can create functions out of a chain of other functions easily.")]),_v(" "),_c('li',[_v("Not to be confused with angular pipes which run via the \"|\" symbol in the html file, allowing you to transform data before it is displayed to the user.")])])])]),_v(" "),_c('p',[_v("I learned Angular through various Youtube tutorials, Udemy tutorials, reading the documentation and trying out different things through personal test projects venturing into Angular.")]),_v(" "),_c('ul',[_c('li',[_v("Youtube taught me basic fundamentals of Angular.")]),_v(" "),_c('li',[_v("Udemy taught me more in depth and guided me through small personal projects.")]),_v(" "),_c('li',[_v("The documentation gave me deeper understanding and insight into details not covered in tutorials")])]),_v(" "),_c('h3',{attrs:{"id":"typescript"}},[_v("TypeScript"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#typescript","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Angular uses TypeScript, so I needed to learn TypeScript. I had only a background in JavaScript while working with React and learning TypeScript had its own difficulties.\nBelow are a few of my learning points:")]),_v(" "),_c('ul',[_c('li',[_v("What and Why TypeScript:\n"),_c('ul',[_c('li',[_v("TypeScript acts as a wrapper over JavaScript, compiling into JavaScript code behind the scenes when you build your project")]),_v(" "),_c('li',[_v("The reason people use TypeScript is because of the increased strictness where things have to be statically typed. This reduces the occurences of bugs and makes bugs easier to find when they do occur")]),_v(" "),_c('li',[_v("This makes TypeScript an extremely useful language to pick up and is used widely in industry")])])]),_v(" "),_c('li',[_v("Types:\n"),_c('ul',[_c('li',[_v("As in the name, typescript has types and almost everything is required to by statically typed")]),_v(" "),_c('li',[_v("The \"any\" type bypassed this requirement but is generally regarded as a bad practice as you have made TypeScript into JavaScript")]),_v(" "),_c('li',[_v("You can define your own types and use those types, similar to a typedef in other languages. This is often how objects are passed in TypeScript")])])])]),_v(" "),_c('p',[_v("I learned TypeScript through Youtube tutorials")]),_v(" "),_c('ul',[_c('li',[_v("Youtube taught me the fundamentals as well as understanding the why and underlying implementation of typescript")])]),_v(" "),_c('h3',{attrs:{"id":"continuous-integration-continuous-deployment-ci-cd"}},[_v("Continuous Integration/Continuous Deployment (CI/CD)"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#continuous-integration-continuous-deployment-ci-cd","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("As an area I have litte experience in, I wanted to dive into the CI/CD pipeline of CATcher and WATcher, gain an understanding of how it works and contribute to make it better.\nBelow are a few of my learning points:")]),_v(" "),_c('ul',[_c('li',[_v("Automated testing\n"),_c('ul',[_c('li',[_v("With large projects like CATcher and WATcher, there are many areas that can and unavoidably will go wrong with many contributors editing different parts of the code base")]),_v(" "),_c('li',[_v("Manual testing is very time consuming when there are so many features to test, any one of which could have been broken by any changes to the code")]),_v(" "),_c('li',[_v("Human error might also cause us to miss certain bugs as we simply did not test for them")]),_v(" "),_c('li',[_v("Automated testing allows for pre-written tests that perform these checks quickly on a headless browser when making any changes, greatly reducing the occurence of uncaught bugs introduced")]),_v(" "),_c('li',[_v("Test case design must be comprehensive in positive and negative cases without testing every specific possible input, instead grouping inputs such as all invalid types given into one test case")])])]),_v(" "),_c('li',[_v("Continuous deployment\n"),_c('ul',[_c('li',[_v("With mission-critical projects like CATcher, it is imperative to have automated deployment")]),_v(" "),_c('li',[_v("One reason is to maintain stability of the deployment, completely negating human errors such as forgetting any one step in deployment. The deployment made is done the same everytime through an automated process")]),_v(" "),_c('li',[_v("Another reason is to speed up development as developers will not need to go through the manual deployment on every release")])])]),_v(" "),_c('li',[_v("Github Actions\n"),_c('ul',[_c('li',[_v("Github actions is a very useful CI/CD tool when the code is already hosted on github")]),_v(" "),_c('li',[_v("Compared to alternatives, it is much simpler to set up as it is one click away for every github repo, create a workflow yml file and thats it")]),_v(" "),_c('li',[_v("There are many pre-defined actions such as actions/checkout that you can use to simplify your dev-ops. In this case you don't need to write your own code to checkout your repository")])])]),_v(" "),_c('li',[_v("Angular deployment\n"),_c('ul',[_c('li',[_v("Angular has a package that allows you to build directly into your github pages")]),_v(" "),_c('li',[_v("This simplifies the process further since you simply call this command through the github actions for an immediate deployment")])])])]),_v(" "),_c('p',[_v("I learned CI/CD through inspecting the code base, trying out different workflows in my own repos and youtube tutorials")]),_v(" "),_c('ul',[_c('li',[_v("The code base gave me a guideline as to the proper way and usage of workflows, along with the proper syntax of creating a workflow")]),_v(" "),_c('li',[_v("Youtube gave me broader knowledge into creating my own workflows not specific to the CATcher project")]),_v(" "),_c('li',[_v("Trying out creating my own workflows and contributing to WATcher workflows solidified my understanding and gave me confidence in what I learned")])]),_v(" "),_c('h3',{attrs:{"id":"code-quality"}},[_v("Code Quality"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#code-quality","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Code quality is always important but is especially so when there are so many people working on the same project. Since large portions of WATcher was copied from CATcher, WATcher was made overtly large with a great number of redundant code. It was very poor code quality and the importance of code quality was made clear.")]),_v(" "),_c('ul',[_c('li',[_v("Code Cleanliness\n"),_c('ul',[_c('li',[_v("Redundant code clutters the code base, making it especially hard to understand certain functionality since you have to sift through so much to find what you are looking for")]),_v(" "),_c('li',[_v("As a new developer, it created an unecessarily difficult experience getting a grasp of the code base")]),_v(" "),_c('li',[_v("Over reliance on comments also clutters the code base when code should be self-explanatory")]),_v(" "),_c('li',[_v("Over three levels of indentation should be avoided, at which point the code is made very hard to understand and inner indents should be refactored into separate functions")])])]),_v(" "),_c('li',[_v("Code simplicity (KISS)\n"),_c('ul',[_c('li',[_v("There are many ways to do the same thing and it is always best to Keep It Simple")]),_v(" "),_c('li',[_v("Always use the simplest way to come to the same outcome, even if they use unecessary variables")]),_v(" "),_c('li',[_v("Variables and functions should be aptly named so they are understood readily such as a "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("filteredData")]),_v(" variable for storing data after it has been filtered")]),_v(" "),_c('li',[_v("Since code is read more than it is written, keeping it simple allows future developers, even yourself to understand the purpose and reason behind any piece of code")])])]),_v(" "),_c('li',[_v("Documentation\n"),_c('ul',[_c('li',[_v("Documentation is important to help others understand parts of the code that are not immediately apparent")]),_v(" "),_c('li',[_v("However, it is important to not rely too heavily on documentation and wherever possible, code you write should be self-explanatory")]),_v(" "),_c('li',[_v("Instead of writing a one-liner that does everything, split logically linked portions into separate parts, using different functions or storing outputs in appropriately named variables")])])]),_v(" "),_c('li',[_v("Following coding style\n"),_c('ul',[_c('li',[_v("Assuming you are not the originator of the project, you need to follow the coding style of the project as well")]),_v(" "),_c('li',[_v("Since there are always multiple ways of doing the same thing, it is often arguable which way is the best. When joining an already established project, it is critical to follow the coding style of your predecessors")]),_v(" "),_c('li',[_v("An example would be returning a complete object instead of a part of an object and appending to a newly created object in the parent function. Both accomplish the same thing and arguably are equally understandable")])])])]),_v(" "),_c('p',[_v("I learned about code quality through analysing the responses of seniors to my own pull requests as well as other's pull requests, supplementing my knowledge by reading articles on code quality both generally and specific to web development")]),_v(" "),_c('ul',[_c('li',[_v("Inspection of pull requests gave me understanding of what is good quality code and what is considered bad along with the reasoning behind those decisions")]),_v(" "),_c('li',[_v("Articles online provided me with more general guidelines pertaining to code quality in large projects, helping fill in the gaps that I didnt encounter in PR reviews")])]),_v(" "),_c('h3',{attrs:{"id":"testing"}},[_v("Testing"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#testing","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Testing is another important part of any project as it reduces the occurrence of major errors and bugs throughout development. With little prior experience in testing, I sought to learn more about it and apply it in WATcher.")]),_v(" "),_c('ul',[_c('li',[_v("Jasmine\n"),_c('ul',[_c('li',[_v("A testing framework for javascript")]),_v(" "),_c('li',[_v("Clean and intuitive syntax")]),_v(" "),_c('li',[_v("Suite of functionality developed over many years")]),_v(" "),_c('li',[_v("I learned Jasmine through looking through test cases in CATcher and WATcher, along with reading its official documentation\n"),_c('ul',[_c('li',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("describe(string, function)")]),_v(" houses related specs labeled by string and defined as function")]),_v(" "),_c('li',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("it(string, function)")]),_v(" defines a spec labeled by string and defined as function")]),_v(" "),_c('li',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("expect(any).toBeFalse")]),_v(" defines an expectation of "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("any")]),_v(". There are a large number of matchers for any possible comparison")]),_v(" "),_c('li',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("beforeEach(function)")]),_v(" defines a function to be called before each of the specs in this describe block")]),_v(" "),_c('li',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("createSpyObj(string, string[])")]),_v(" creates a spy object that acts as a stub for classes that are depended on by what is being tested. Spies can track calls to it and all arguments")])])])])]),_v(" "),_c('li',[_v("Test case design\n"),_c('ul',[_c('li',[_v("Boundary Value Analysis and equivalence partitioning\n"),_c('ul',[_c('li',[_v("Boundary value analysis is a technique where tests are designed to include representatives of boundary values in a range")]),_v(" "),_c('li',[_v("Equivalence partitioning is a technique where input data is partitioned into units of equivalent data for which tests can be written")]),_v(" "),_c('li',[_v("These techniques allow for a smaller number of tests to be written, for essentially the same amount of coverage\n"),_c('ul',[_c('li',[_v("This is because inputs which would fail/pass for the same reason, such as being an input of an invalid type, are grouped as a single or only a few test cases.")]),_v(" "),_c('li',[_v("The alternative would be to create tests for each input type in this example, straining developer resources for not much benefit")])])])])]),_v(" "),_c('li',[_v("Testing for behaviour\n"),_c('ul',[_c('li',[_v("A common mistake is to test for implementation rather than behaviour")]),_v(" "),_c('li',[_v("This would result in failed test cases when implementation changes even though the resulting behaviour, what the user would experience, remains the same")]),_v(" "),_c('li',[_v("Test cases should test for what the result is versus what the implementation is")]),_v(" "),_c('li',[_v("An example would be testing whether a variable changes in component A correctly vs testing what other components receive from component A after the change")]),_v(" "),_c('li',[_v("A developer might edit the implementation of component A so the variable no longer changes, however the accurate behaviour of emission to other components remains the same and the test cases should not fail")])])]),_v(" "),_c('li',[_v("Testing coverage\n"),_c('ul',[_c('li',[_v("Test coverage is how much of the code has actually been ran through during testing\n"),_c('ul',[_c('li',[_v("Function/method coverage : based on functions executed e.g., testing executed 90 out of 100 functions")]),_v(" "),_c('li',[_v("Statement coverage : based on the number of lines of code executed e.g., testing executed 23k out of 25k LOC")]),_v(" "),_c('li',[_v("Decision/branch coverage : based on the decision points exercised e.g., an if statement evaluated to both true and false with separate test cases during testing is considered 'covered'")]),_v(" "),_c('li',[_v("Condition coverage : based on the boolean sub-expressions, each evaluated to both true and false with different test cases")])])]),_v(" "),_c('li',[_v("A good future implementation would be to implement code coverage as a github action report when making pull requests to main")]),_v(" "),_c('li',[_v("At the very least, all public functions of a class should be uniquely tested in order to verify behaviour seen by other components\nI learned about testing web applications through Nereus, reading Jasmine documentation, articles and youtube videos about testing and the "),_c('a',{attrs:{"href":"https://nus-cs2113-ay2324s2.github.io/website/index.html"}},[_v("CS2113 website")])])])])])]),_v(" "),_c('li',[_v("Nereus imparted knowledge of testing which helped me understand the core fundamentals, allowing me to more quickly pick up the technique as I learnt, especially the test case implementation")]),_v(" "),_c('li',[_v("The Jasmine documentation gave me confidence in creating my own test cases for unique behaviour such as changing routes in testing")]),_v(" "),_c('li',[_v("Youtube videos, articles and the CS2113 website helped me to understand and implement test case design techniques to create comprehensive and well designed test cases")])])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/Arif-Khalid/progress.html b/students/Arif-Khalid/progress.html index 813c11053..9fc82b063 100644 --- a/students/Arif-Khalid/progress.html +++ b/students/Arif-Khalid/progress.html @@ -13,7 +13,7 @@

    Key Contributions

    Week Achievements
    2 Merged PR: Hide 0 issue columns #223
    4 Submitted Issue: Refactor filters into its own service #249
    4 Submitted Issue: Update Angular version to 11.2.14 #237
    5 Merged PR: Remove unused services #238, Merged PR: Remove unused models #253, Merged PR: Remove unused session-fix-confirmation component #250
    5 Reviewed PR: Upgrade to angular 11 #252
    5 Reviewed PR: Refactor Label model #254
    5 Merged PR: Faulty list view when back navigating #1243
    6 Reviewed PR: Add shareable repo-specific URL #255
    6 Merged PR: Refactor certain filters into its own service #259
    6 Merged PR: Refactor sorting #261
    6 Merged PR: Refactor milestone filters #264
    7 Reviewed PR: Upgrade to angular 12 #267
    7 Reviewed PR: Fix zone testing import error #269
    7 Reviewed PR: Update test cases for phase service #275
    7 Reviewed PR: Three-state labels #282
    7 Merged PR: Refactor title filter #265
    7 Merged PR: Automatic deployment #272
    7 Submitted Issue: Release changelog automation #273
    7 Submitted Issue: Save milestones by name #283
    8 Submitted Issue: Incorrect numbering in user-workflow #35
    8 Submitted Issue: Add tests for filters service #295
    8 Reviewed PR: Update Design page #14
    8 Reviewed PR: Enable pre push hook for npm run test #288
    8 Reviewed PR: Remove sorting by assignees in issue sorter #286
    8 Merged PR: Refactor milestones to save by name #289
    8 Pending PR: Update user workflow #12
    9 Submitted Issue: Label filter bar test case error #305
    9 Reviewed PR: Hide redundant column pagination #309
    9 Reviewed PR: Status filter checkboxes #310
    9 Merged PR: Keep filters when switching repo #281
    9 Merged PR: Release changelog automation #285
    10 Reviewed PR: Integrate Grouping Service #313
    10 Merged PR: Keep milestones when switching repo #311
    10 Merged PR: Add filters to url #314
    11 Submitted Issue: Default preset view is custom when it should be currently active #333
    11 Submitted Issue: Remove quotations from filters in url #340
    11 Submitted Issue: Showing of preset views before selecting a repo
    11 Merged PR: Fix default preset view #334
    11 Merged PR: Remove quotation marks from url #345
    11 Reviewed PR: Include groupby params in url #319
    11 Reviewed PR: Add preset views #320
    11 Reviewed PR: Update repo on back and forward navigation #322
    11 Reviewed PR: Reset GroupingContextService only if "keep filter" is selected #324
    11 Reviewed PR: Create release 1.2.0 #327, Reviewed PR: Resolve conflicts for 1.2.0 #329, Reviewed PR: Deploy V1.2.0 #331
    11 Reviewed PR: Create release V1.2.1 #349, Reviewed PR: Deploy V1.2.1 #350
    11 Reviewed PR: Optimise Github API calls #360
    12 Submitted Issue: Reset of sort filter after some time #372
    12 Merged PR: Show preset view only when repo is set #355
    12 Merged PR: Fix top and bottom shadow of columns #357
    12 Merged PR: Create release V1.2.2 #364, Merged PR: Deploy V1.2.2 #365
    12 Merged PR: Fix reset of filters on label fetch #374
    13 Merged PR: Add test cases for filters service #312
    +
    Week Achievements
    2 Merged PR: Hide 0 issue columns #223
    4 Submitted Issue: Refactor filters into its own service #249
    4 Submitted Issue: Update Angular version to 11.2.14 #237
    5 Merged PR: Remove unused services #238, Merged PR: Remove unused models #253, Merged PR: Remove unused session-fix-confirmation component #250
    5 Reviewed PR: Upgrade to angular 11 #252
    5 Reviewed PR: Refactor Label model #254
    5 Merged PR: Faulty list view when back navigating #1243
    6 Reviewed PR: Add shareable repo-specific URL #255
    6 Merged PR: Refactor certain filters into its own service #259
    6 Merged PR: Refactor sorting #261
    6 Merged PR: Refactor milestone filters #264
    7 Reviewed PR: Upgrade to angular 12 #267
    7 Reviewed PR: Fix zone testing import error #269
    7 Reviewed PR: Update test cases for phase service #275
    7 Reviewed PR: Three-state labels #282
    7 Merged PR: Refactor title filter #265
    7 Merged PR: Automatic deployment #272
    7 Submitted Issue: Release changelog automation #273
    7 Submitted Issue: Save milestones by name #283
    8 Submitted Issue: Incorrect numbering in user-workflow #35
    8 Submitted Issue: Add tests for filters service #295
    8 Reviewed PR: Update Design page #14
    8 Reviewed PR: Enable pre push hook for npm run test #288
    8 Reviewed PR: Remove sorting by assignees in issue sorter #286
    8 Merged PR: Refactor milestones to save by name #289
    8 Pending PR: Update user workflow #12
    9 Submitted Issue: Label filter bar test case error #305
    9 Reviewed PR: Hide redundant column pagination #309
    9 Reviewed PR: Status filter checkboxes #310
    9 Merged PR: Keep filters when switching repo #281
    9 Merged PR: Release changelog automation #285
    10 Reviewed PR: Integrate Grouping Service #313
    10 Merged PR: Keep milestones when switching repo #311
    10 Merged PR: Add filters to url #314
    11 Submitted Issue: Default preset view is custom when it should be currently active #333
    11 Submitted Issue: Remove quotations from filters in url #340
    11 Submitted Issue: Showing of preset views before selecting a repo
    11 Merged PR: Fix default preset view #334
    11 Merged PR: Remove quotation marks from url #345
    11 Reviewed PR: Include groupby params in url #319
    11 Reviewed PR: Add preset views #320
    11 Reviewed PR: Update repo on back and forward navigation #322
    11 Reviewed PR: Reset GroupingContextService only if "keep filter" is selected #324
    11 Reviewed PR: Create release 1.2.0 #327, Reviewed PR: Resolve conflicts for 1.2.0 #329, Reviewed PR: Deploy V1.2.0 #331
    11 Reviewed PR: Create release V1.2.1 #349, Reviewed PR: Deploy V1.2.1 #350
    11 Reviewed PR: Optimise Github API calls #360
    12 Submitted Issue: Reset of sort filter after some time #372
    12 Merged PR: Show preset view only when repo is set #355
    12 Merged PR: Fix top and bottom shadow of columns #357
    12 Merged PR: Create release V1.2.2 #364, Merged PR: Deploy V1.2.2 #365
    12 Merged PR: Fix reset of filters on label fetch #374
    13 Merged PR: Add test cases for filters service #312
    diff --git a/students/Arif-Khalid/progress.page-vue-render.js b/students/Arif-Khalid/progress.page-vue-render.js index 0b2d5d578..5698bb3a2 100644 --- a/students/Arif-Khalid/progress.page-vue-render.js +++ b/students/Arif-Khalid/progress.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('h1',{attrs:{"id":"key-contributions"}},[_v("Key Contributions"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#key-contributions","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ul',[_c('li',[_v("Actively participated in submitting and resolving issues found, implementing features and team discussions")]),_v(" "),_c('li',[_v("Focus on bug fixes that hurt the usability of CATcher and WATcher")]),_v(" "),_c('li',[_v("Reviewed PRs constructively with focus on scalability and code style of the existing code base")]),_v(" "),_c('li',[_v("Update CI/CD workflow, specifically improving automation by using an on push deployment and a release drafter template and bot which formatted and displayed release changes"),_c('br'),_v(" "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/272"}},[_v("Automatic deployment #272")]),_v(", "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/285"}},[_v("Release changelog automation #285")])]),_v(" "),_c('li',[_v("Revamp and updates to filter system of WATcher\n"),_c('ul',[_c('li',[_v("Adopted a centralised service and observer pattern behaviour"),_c('br'),_v(" "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/259"}},[_v("Refactor certain filters into its own service #259")]),_v(", "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/261"}},[_v("Refactor sorting #261")]),_v(", "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/264"}},[_v("Refactor milestone filters #264")])]),_v(" "),_c('li',[_v("Update filters to be stored into and restored from url"),_c('br'),_v(" "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/314"}},[_v("Add filters to url #314")])]),_v(" "),_c('li',[_v("Allow filters to be kept across repo changes"),_c('br'),_v(" "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/281"}},[_v("Keep filters when switching repo #281")])])])])]),_v(" "),_c('div',{staticClass:"table-responsive"},[_c('table',{staticClass:"markbind-table table table-bordered table-striped"},[_c('thead',[_c('tr',[_c('th',[_v("Week")]),_v(" "),_c('th',[_v("Achievements")])])]),_v(" "),_c('tbody',[_c('tr',[_c('td',[_v("2")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/223"}},[_v("Hide 0 issue columns #223")])])]),_v(" "),_c('tr',[_c('td',[_v("4")]),_v(" "),_c('td',[_v("Submitted Issue: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/249"}},[_v("Refactor filters into its own service #249")])])]),_v(" "),_c('tr',[_c('td',[_v("4")]),_v(" "),_c('td',[_v("Submitted Issue: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/237"}},[_v("Update Angular version to 11.2.14 #237")])])]),_v(" "),_c('tr',[_c('td',[_v("5")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/238"}},[_v("Remove unused services #238")]),_v(", Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/253"}},[_v("Remove unused models #253")]),_v(", Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/250"}},[_v("Remove unused session-fix-confirmation component #250")])])]),_v(" "),_c('tr',[_c('td',[_v("5")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/252"}},[_v("Upgrade to angular 11 #252")])])]),_v(" "),_c('tr',[_c('td',[_v("5")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/254"}},[_v("Refactor Label model #254")])])]),_v(" "),_c('tr',[_c('td',[_v("5")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher/pull/1243"}},[_v("Faulty list view when back navigating #1243")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/255"}},[_v("Add shareable repo-specific URL #255")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/259"}},[_v("Refactor certain filters into its own service #259")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/261"}},[_v("Refactor sorting #261")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/264"}},[_v("Refactor milestone filters #264")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/267"}},[_v("Upgrade to angular 12 #267")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/269"}},[_v("Fix zone testing import error #269")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/275"}},[_v("Update test cases for phase service #275")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/282"}},[_v("Three-state labels #282")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/265"}},[_v("Refactor title filter #265")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/272"}},[_v("Automatic deployment #272")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Submitted Issue: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/273"}},[_v("Release changelog automation #273")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Submitted Issue: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/283"}},[_v("Save milestones by name #283")])])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_v("Submitted Issue: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/catcher-org.github.io/issues/35"}},[_v("Incorrect numbering in user-workflow #35")])])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_v("Submitted Issue: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/295"}},[_v("Add tests for filters service #295")])])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher-docs/pull/14"}},[_v("Update Design page #14")])])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/288"}},[_v("Enable pre push hook for npm run test #288")])])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/286"}},[_v("Remove sorting by assignees in issue sorter #286")])])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/289"}},[_v("Refactor milestones to save by name #289")])])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_v("Pending PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher-docs/pull/12"}},[_v("Update user workflow #12")])])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_v("Submitted Issue: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/305"}},[_v("Label filter bar test case error #305")])])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/309"}},[_v("Hide redundant column pagination #309")])])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/310"}},[_v("Status filter checkboxes #310")])])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/281"}},[_v("Keep filters when switching repo #281")])])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/285"}},[_v("Release changelog automation #285")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/313"}},[_v("Integrate Grouping Service #313")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/311"}},[_v("Keep milestones when switching repo #311")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/314"}},[_v("Add filters to url #314")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Submitted Issue: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/333"}},[_v("Default preset view is custom when it should be currently active #333")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Submitted Issue: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/340"}},[_v("Remove quotations from filters in url #340")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Submitted Issue: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/352"}},[_v("Showing of preset views before selecting a repo")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/334"}},[_v("Fix default preset view #334")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/345"}},[_v("Remove quotation marks from url #345")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/319"}},[_v("Include groupby params in url #319")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/320"}},[_v("Add preset views #320")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/322"}},[_v("Update repo on back and forward navigation #322")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/324"}},[_v("Reset GroupingContextService only if \"keep filter\" is selected #324")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/327"}},[_v("Create release 1.2.0 #327")]),_v(", Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/329"}},[_v("Resolve conflicts for 1.2.0 #329")]),_v(", Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/331"}},[_v("Deploy V1.2.0 #331")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/349"}},[_v("Create release V1.2.1 #349")]),_v(", Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/350"}},[_v("Deploy V1.2.1 #350")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/360"}},[_v("Optimise Github API calls #360")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Submitted Issue: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/372"}},[_v("Reset of sort filter after some time #372")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/355"}},[_v("Show preset view only when repo is set #355")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/357"}},[_v("Fix top and bottom shadow of columns #357")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/364"}},[_v("Create release V1.2.2 #364")]),_v(", Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/365"}},[_v("Deploy V1.2.2 #365")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/374"}},[_v("Fix reset of filters on label fetch #374")])])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/312"}},[_v("Add test cases for filters service #312")])])])])])])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/EltonGohJH/info.html b/students/EltonGohJH/info.html index 64f8f2e5c..7616cffb4 100644 --- a/students/EltonGohJH/info.html +++ b/students/EltonGohJH/info.html @@ -12,7 +12,7 @@ const baseUrl = '/2024' -
    +
    diff --git a/students/EltonGohJH/info.page-vue-render.js b/students/EltonGohJH/info.page-vue-render.js index 85347584b..9c7636580 100644 --- a/students/EltonGohJH/info.page-vue-render.js +++ b/students/EltonGohJH/info.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('p',[_c('span',{attrs:{"id":"github"}},[_c('a',{attrs:{"href":"https://github.com/EltonGohJH"}},[_v("https://github.com/EltonGohJH")])])]),_v(" "),_c('p',[_c('span',{attrs:{"id":"projects"}},[_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind"}},[_v("MarkBind")])])])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/EltonGohJH/knowledge.html b/students/EltonGohJH/knowledge.html index 24370e884..1af14dca1 100644 --- a/students/EltonGohJH/knowledge.html +++ b/students/EltonGohJH/knowledge.html @@ -33,7 +33,7 @@ The 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. This caused a lot of tests to fail and I had to spend a lot of time debugging it.

    Through this experience, I learned the importance of ensuring that changes are documented properly and correctly.

    gomock

    I have learned to use GoMock, a mocking framework for Golang, which streamlines the creation of mock objects for unit testing. It helps with decoupling components, enabling the simulation of complex behaviors and interactions. I am surprised how easy it to use to mock complex behaviours. Will definitely use it for Golang testing next time!

    Resource used:

    Yarn workspaces

    Yarn Workspaces is a feature of Yarn that simplifies handling multiple packages within a single repository by enabling shared dependencies and centralized script management. I learnt Yarn Workspaces while setting up the repository for the Twenty project. -Overall, it is a good experience as I learnt more alternatives to Lerna and NPM workspaces.

    Resource used:

    +Overall, it is a good experience as I learnt more alternatives to Lerna and NPM workspaces.

    Resource used:

    diff --git a/students/EltonGohJH/knowledge.page-vue-render.js b/students/EltonGohJH/knowledge.page-vue-render.js index 52da425ea..2fcc99ebf 100644 --- a/students/EltonGohJH/knowledge.page-vue-render.js +++ b/students/EltonGohJH/knowledge.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_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('h3',{attrs:{"id":"gomock"}},[_v("gomock"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#gomock","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("I have learned to use GoMock, a mocking framework for Golang, which streamlines the creation of mock objects for unit testing. It helps with decoupling components, enabling the simulation of complex behaviors and interactions. I am surprised how easy it to use to mock complex behaviours.\nWill definitely use it for Golang testing next time!")]),_v(" "),_c('h4',{attrs:{"id":"resource-used-5"}},[_v("Resource used:"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#resource-used-5","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ul',[_c('li',[_c('a',{attrs:{"href":"https://github.com/uber-go/mock"}},[_v("gomock docs")])])]),_v(" "),_c('h3',{attrs:{"id":"yarn-workspaces"}},[_v("Yarn workspaces"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#yarn-workspaces","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Yarn Workspaces is a feature of Yarn that simplifies handling multiple packages within a single repository by enabling shared dependencies and centralized script management. I learnt Yarn Workspaces while setting up the repository for the Twenty project.\nOverall, it is a good experience as I learnt more alternatives to Lerna and NPM workspaces.")]),_v(" "),_c('h4',{attrs:{"id":"resource-used-6"}},[_v("Resource used:"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#resource-used-6","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ul',[_c('li',[_c('a',{attrs:{"href":"https://yarnpkg.com/features/workspaces"}},[_v("Yarn workspaces docs")])])])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/EltonGohJH/observations.html b/students/EltonGohJH/observations.html index 751a8cf98..859ac52c7 100644 --- a/students/EltonGohJH/observations.html +++ b/students/EltonGohJH/observations.html @@ -14,7 +14,7 @@

    Projects I have worked on

    Mattermost

    Mattermost is an open-source collaboration platform designed for secure communication throughout the entire software development lifecycle. It serves as a self-hostable alternative to Slack, offering similar functionalities with the added benefit of full control over hosting and management.

    Twenty

    Twenty CRM is a modern, open-source Customer Relationship Management (CRM) platform. It serves as an self-hostable alternative to Salesforce.

    My Contributions

    In the mattermost PR (merged). I addressed this issue where the CLI command to list the teams uses a magic number of 9999. Utilizing such large magic numbers presents two problems: it restricts the ability to list more than 9999 teams and could result in a request that is too large. To solve this, I implemented pagination for the request, with each page containing 200 teams. Subsequently, I updated the test cases to reflect the new expected behavior.

    In the Twenty PR (merged). I addressed an issue reported by a user concerning LinkedIn school URLs not parsing correctly. Upon investigating the issue on the frontend, I discovered that the existing regex was only configured to support company URLs. To resolve this, I updated the regex to also accommodate school URLs and conducted tests to ensure the fix was effective.

    My Learning Record

    gomock

    I have learned to use GoMock, a mocking framework for Golang, which streamlines the creation of mock objects for unit testing. It helps with decoupling components, enabling the simulation of complex behaviors and interactions. I am surprised how easy it to use to mock complex behaviours. Will definitely use it for Golang testing next time!

    Resource used:

    Yarn workspaces

    Yarn Workspaces is a feature of Yarn that simplifies handling multiple packages within a single repository by enabling shared dependencies and centralized script management. I learnt Yarn Workspaces while setting up the repository for the Twenty project. -Overall, it is a good experience as I learnt more alternatives to Lerna and NPM workspaces.

    Resource used:

    Practices/tools from Mattermost that could be adopted by Markbind

    I was particularly impressed with the Twenty's onboarding guide because it includes multi-OS setup guides and instructions on setting up through Docker containers. Furthermore, it provides an IDE setup guide, and its repository contains a .vscode/extensions.json file that assists users in configuring VS Code. For Markbind, while the Docker container setup may not be necessary, adopting a multi-OS guide could be beneficial. It could promote useful tools like nvm for testing across multiple Node.js versions, and a VS Code extensions list could help new developers adhere to our coding practices.

    I was really impressed with the PR review workflow at Mattermost. It's incredibly systematic, featuring stages such as UI review, Dev review, and QA review, which make the process feel seamless. Additionally, they utilize bots to remind reviewers to complete their reviews. While Markbind is smaller and might not require such an elaborate setup, investigating the potential of GitHub PR bots could be beneficial. These tools could streamline our review process and ensure that contributions are efficiently and effectively vetted.

    +Overall, it is a good experience as I learnt more alternatives to Lerna and NPM workspaces.

    Resource used:

    Practices/tools from Mattermost that could be adopted by Markbind

    I was particularly impressed with the Twenty's onboarding guide because it includes multi-OS setup guides and instructions on setting up through Docker containers. Furthermore, it provides an IDE setup guide, and its repository contains a .vscode/extensions.json file that assists users in configuring VS Code. For Markbind, while the Docker container setup may not be necessary, adopting a multi-OS guide could be beneficial. It could promote useful tools like nvm for testing across multiple Node.js versions, and a VS Code extensions list could help new developers adhere to our coding practices.

    I was really impressed with the PR review workflow at Mattermost. It's incredibly systematic, featuring stages such as UI review, Dev review, and QA review, which make the process feel seamless. Additionally, they utilize bots to remind reviewers to complete their reviews. While Markbind is smaller and might not require such an elaborate setup, investigating the potential of GitHub PR bots could be beneficial. These tools could streamline our review process and ensure that contributions are efficiently and effectively vetted.

    diff --git a/students/EltonGohJH/observations.page-vue-render.js b/students/EltonGohJH/observations.page-vue-render.js index 5ccd9947f..352285a2e 100644 --- a/students/EltonGohJH/observations.page-vue-render.js +++ b/students/EltonGohJH/observations.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('h3',{attrs:{"id":"projects-i-have-worked-on"}},[_v("Projects I have worked on"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#projects-i-have-worked-on","onclick":"event.stopPropagation()"}})]),_v(" "),_c('h4',{attrs:{"id":"mattermost"}},[_v("Mattermost"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#mattermost","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Mattermost is an open-source collaboration platform designed for secure communication throughout the entire software development lifecycle. It serves as a self-hostable alternative to Slack, offering similar functionalities with the added benefit of full control over hosting and management.")]),_v(" "),_c('h3',{attrs:{"id":"twenty"}},[_v("Twenty"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#twenty","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Twenty CRM is a modern, open-source Customer Relationship Management (CRM) platform. It serves as an self-hostable alternative to Salesforce.")]),_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("In the "),_c('a',{attrs:{"href":"https://github.com/mattermost/mattermost/pull/26278"}},[_v("mattermost PR (merged)")]),_v(". I addressed this "),_c('a',{attrs:{"href":"https://github.com/mattermost/mattermost/issues/25991"}},[_v("issue")]),_v(" where the CLI command to list the teams uses a magic number of 9999. Utilizing such large magic numbers presents two problems: it restricts the ability to list more than 9999 teams and could result in a request that is too large. To solve this, I implemented pagination for the request, with each page containing 200 teams. Subsequently, I updated the test cases to reflect the new expected behavior.")]),_v(" "),_c('p',[_v("In the "),_c('a',{attrs:{"href":"https://github.com/twentyhq/twenty/pull/4198"}},[_v("Twenty PR (merged)")]),_v(". I addressed an "),_c('a',{attrs:{"href":"https://github.com/twentyhq/twenty/issues/4181"}},[_v("issue")]),_v(" reported by a user concerning LinkedIn school URLs not parsing correctly. Upon investigating the issue on the frontend, I discovered that the existing regex was only configured to support company URLs. To resolve this, I updated the regex to also accommodate school URLs and conducted tests to ensure the fix was effective.")]),_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('h3',{attrs:{"id":"gomock"}},[_v("gomock"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#gomock","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("I have learned to use GoMock, a mocking framework for Golang, which streamlines the creation of mock objects for unit testing. It helps with decoupling components, enabling the simulation of complex behaviors and interactions. I am surprised how easy it to use to mock complex behaviours.\nWill definitely use it for Golang testing next time!")]),_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://github.com/uber-go/mock"}},[_v("gomock docs")])])]),_v(" "),_c('h3',{attrs:{"id":"yarn-workspaces"}},[_v("Yarn workspaces"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#yarn-workspaces","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Yarn Workspaces is a feature of Yarn that simplifies handling multiple packages within a single repository by enabling shared dependencies and centralized script management. I learnt Yarn Workspaces while setting up the repository for the Twenty project.\nOverall, it is a good experience as I learnt more alternatives to Lerna and NPM workspaces.")]),_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://yarnpkg.com/features/workspaces"}},[_v("Yarn workspaces docs")])])]),_v(" "),_c('h3',{attrs:{"id":"practices-tools-from-mattermost-that-could-be-adopted-by-markbind"}},[_v("Practices/tools from Mattermost that could be adopted by Markbind"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#practices-tools-from-mattermost-that-could-be-adopted-by-markbind","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("I was particularly impressed with the "),_c('a',{attrs:{"href":"https://docs.twenty.com/start/local-setup/"}},[_v("Twenty's onboarding guide")]),_v(" because it includes multi-OS setup guides and instructions on setting up through Docker containers. Furthermore, it provides an IDE setup guide, and its repository contains a "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v(".vscode/extensions.json")]),_v(" file that assists users in configuring VS Code. For Markbind, while the Docker container setup may not be necessary, adopting a multi-OS guide could be beneficial. It could promote useful tools like "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("nvm")]),_v(" for testing across multiple Node.js versions, and a VS Code extensions list could help new developers adhere to our coding practices.")]),_v(" "),_c('p',[_v("I was really impressed with the PR review workflow at Mattermost. It's incredibly systematic, featuring stages such as UI review, Dev review, and QA review, which make the process feel seamless. Additionally, they utilize bots to remind reviewers to complete their reviews. While Markbind is smaller and might not require such an elaborate setup, investigating the potential of GitHub PR bots could be beneficial. These tools could streamline our review process and ensure that contributions are efficiently and effectively vetted.")])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/EltonGohJH/progress.html b/students/EltonGohJH/progress.html index b2753ea9e..05be29d53 100644 --- a/students/EltonGohJH/progress.html +++ b/students/EltonGohJH/progress.html @@ -12,7 +12,7 @@ const baseUrl = '/2024' -
    Week Achievements
    1 Helped prepare idea & facilitated Saturday code sprint - MarkBind website making
    3 Repo cleaning - Added tags to issues, added items to project road map, added summaries to issues, and cleaned up some issues. Examples: Allow markbind serve to specify custom host #2382, Optimize MarkBind for saving as PDF #2397, UG: images appear in two places #2401
    4 Investigated: UG: images appear in two places #2401
    4 Investigated and closed: The collapsed page nav appears in the print view #2157
    4, 5 Reviewed: MarkBind Template for Software Project Documentation #2400
    5 Reviewed: Migrate stylelint to latest version #2292
    5 Discussed: Use justified text formatting for tooltips #2420
    5, 6 Investigated and reviewed: Fix external styles and script not hoisted #2414
    6 Reviewed: Add line-numbers when wrapping is needed for printing #2431
    6 Investigated: Tooltip artefact left over for annotation point #2432
    6 Reviewed and approved: Disable pop over in a-point if there is no header and content passed by user #2436
    6 Investigated and helped fix bug: Utilize GitHub Actions to aid checking of commit message #2429
    6 Helped fix bug and merged: Annotation content slot #2427
    7 Reviewed and approved: Add horizontal spacing between the icon and text in the custom icon list #2375
    8 Reviewed and approved: Add keeping your fork up to date section in DG #2453
    8 Reviewed and approved: Add text support for icon #2444
    10 Reviewed and approved: Efficient validation for intra-link with hash #2465
    11 Reviewed and approved: Fix stray space before popover and tooltip #2486
    12 Reviewed and approved: Fix off-positioned close button in imported modal #2487
    12 Reviewed: Add note on URLs in includes #2507
    13 Reviewed: Set global variables using nunjucks syntax #2474
    13 Reviewed: Add Mermaid Plugin #2475
    7-13 Part of weekly sync with CS3281 students
    +
    Week Achievements
    1 Helped prepare idea & facilitated Saturday code sprint - MarkBind website making
    3 Repo cleaning - Added tags to issues, added items to project road map, added summaries to issues, and cleaned up some issues. Examples: Allow markbind serve to specify custom host #2382, Optimize MarkBind for saving as PDF #2397, UG: images appear in two places #2401
    4 Investigated: UG: images appear in two places #2401
    4 Investigated and closed: The collapsed page nav appears in the print view #2157
    4, 5 Reviewed: MarkBind Template for Software Project Documentation #2400
    5 Reviewed: Migrate stylelint to latest version #2292
    5 Discussed: Use justified text formatting for tooltips #2420
    5, 6 Investigated and reviewed: Fix external styles and script not hoisted #2414
    6 Reviewed: Add line-numbers when wrapping is needed for printing #2431
    6 Investigated: Tooltip artefact left over for annotation point #2432
    6 Reviewed and approved: Disable pop over in a-point if there is no header and content passed by user #2436
    6 Investigated and helped fix bug: Utilize GitHub Actions to aid checking of commit message #2429
    6 Helped fix bug and merged: Annotation content slot #2427
    7 Reviewed and approved: Add horizontal spacing between the icon and text in the custom icon list #2375
    8 Reviewed and approved: Add keeping your fork up to date section in DG #2453
    8 Reviewed and approved: Add text support for icon #2444
    10 Reviewed and approved: Efficient validation for intra-link with hash #2465
    11 Reviewed and approved: Fix stray space before popover and tooltip #2486
    12 Reviewed and approved: Fix off-positioned close button in imported modal #2487
    12 Reviewed: Add note on URLs in includes #2507
    13 Reviewed: Set global variables using nunjucks syntax #2474
    13 Reviewed: Add Mermaid Plugin #2475
    7-13 Part of weekly sync with CS3281 students
    diff --git a/students/EltonGohJH/progress.page-vue-render.js b/students/EltonGohJH/progress.page-vue-render.js index 9ad895956..f62204564 100644 --- a/students/EltonGohJH/progress.page-vue-render.js +++ b/students/EltonGohJH/progress.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('div',{staticClass:"table-responsive"},[_c('table',{staticClass:"markbind-table table table-bordered table-striped"},[_c('thead',[_c('tr',[_c('th',[_v("Week")]),_v(" "),_c('th',[_v("Achievements")])])]),_v(" "),_c('tbody',[_c('tr',[_c('td',[_v("1")]),_v(" "),_c('td',[_v("Helped prepare idea & facilitated Saturday code sprint - MarkBind website making")])]),_v(" "),_c('tr',[_c('td',[_v("3")]),_v(" "),_c('td',[_v("Repo cleaning - Added tags to issues, added items to project road map, added summaries to issues, and cleaned up some issues. Examples: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2382"}},[_v("Allow markbind serve to specify custom host #2382")]),_v(", "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2397"}},[_v("Optimize MarkBind for saving as PDF #2397")]),_v(", "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2401"}},[_v("UG: images appear in two places #2401")])])]),_v(" "),_c('tr',[_c('td',[_v("4")]),_v(" "),_c('td',[_v("Investigated: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2401"}},[_v("UG: images appear in two places #2401")])])]),_v(" "),_c('tr',[_c('td',[_v("4")]),_v(" "),_c('td',[_v("Investigated and closed: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2157"}},[_v("The collapsed page nav appears in the print view #2157")])])]),_v(" "),_c('tr',[_c('td',[_v("4, 5")]),_v(" "),_c('td',[_v("Reviewed: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2400"}},[_v("MarkBind Template for Software Project Documentation #2400")])])]),_v(" "),_c('tr',[_c('td',[_v("5")]),_v(" "),_c('td',[_v("Reviewed: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2425"}},[_v("Migrate stylelint to latest version #2292")])])]),_v(" "),_c('tr',[_c('td',[_v("5")]),_v(" "),_c('td',[_v("Discussed: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2420"}},[_v("Use justified text formatting for tooltips #2420")])])]),_v(" "),_c('tr',[_c('td',[_v("5, 6")]),_v(" "),_c('td',[_v("Investigated and reviewed: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2414"}},[_v("Fix external styles and script not hoisted #2414")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Reviewed: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2431"}},[_v("Add line-numbers when wrapping is needed for printing #2431")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Investigated: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2432"}},[_v("Tooltip artefact left over for annotation point #2432")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Reviewed and approved: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2436"}},[_v("Disable pop over in a-point if there is no header and content passed by user #2436")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Investigated and helped fix bug: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2429"}},[_v("Utilize GitHub Actions to aid checking of commit message #2429")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Helped fix bug and merged: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2427"}},[_v("Annotation content slot #2427")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Reviewed and approved: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2375"}},[_v("Add horizontal spacing between the icon and text in the custom icon list #2375")])])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_v("Reviewed and approved: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2453"}},[_v("Add keeping your fork up to date section in DG #2453")])])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_v("Reviewed and approved: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2444"}},[_v("Add text support for icon #2444")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Reviewed and approved: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2465"}},[_v("Efficient validation for intra-link with hash #2465")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Reviewed and approved: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2486"}},[_v("Fix stray space before popover and tooltip #2486")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Reviewed and approved: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2487"}},[_v("Fix off-positioned close button in imported modal #2487")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Reviewed: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2507"}},[_v("Add note on URLs in includes #2507")])])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_v("Reviewed: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2474"}},[_v("Set global variables using nunjucks syntax #2474")])])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_v("Reviewed: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2475"}},[_v("Add Mermaid Plugin #2475")])])]),_v(" "),_c('tr',[_c('td',[_v("7-13")]),_v(" "),_c('td',[_v("Part of weekly sync with CS3281 students")])])])])])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/EuniceSim142/info.html b/students/EuniceSim142/info.html index 3a0fc0e39..01e8ecee4 100644 --- a/students/EuniceSim142/info.html +++ b/students/EuniceSim142/info.html @@ -12,7 +12,7 @@ const baseUrl = '/2024' -
    +
    diff --git a/students/EuniceSim142/info.page-vue-render.js b/students/EuniceSim142/info.page-vue-render.js index 6e2b08bc4..10d045fcf 100644 --- a/students/EuniceSim142/info.page-vue-render.js +++ b/students/EuniceSim142/info.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('p',[_c('span',{attrs:{"id":"github"}},[_c('a',{attrs:{"href":"https://www.github.com/EuniceSim142"}},[_v("https://www.github.com/EuniceSim142")])])]),_v(" "),_c('p',[_c('span',{attrs:{"id":"projects"}},[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates"}},[_v("TEAMMATES")])])])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/EuniceSim142/knowledge.html b/students/EuniceSim142/knowledge.html index d6df24285..8a390ecc4 100644 --- a/students/EuniceSim142/knowledge.html +++ b/students/EuniceSim142/knowledge.html @@ -212,7 +212,7 @@

    PR / Code reviews

    While reviewing pull requests for other maintainers, I realised there is still much I can learn about Angular, Bootstrap, and even about the codebase (eg. its structure). Hence to be able to give the best review and advice, I did more research into these technologies and concepts before submitting reviews. (Some of this research is in the "Frontend" part)
     

    Project management

    I realised over the course of the module that there are many facets to managing a large open-source project and it extends beyond reviewing PRs for contributors.
     In particular, I learned how I not only have to ensure the code works, but whether the code written is consistent with the codebase, if there are any better ways to solve the issue and to provide help that guides the contributor and not directly provide the solution.
    -
    + diff --git a/students/EuniceSim142/knowledge.page-vue-render.js b/students/EuniceSim142/knowledge.page-vue-render.js index 1af975b99..5aefa0259 100644 --- a/students/EuniceSim142/knowledge.page-vue-render.js +++ b/students/EuniceSim142/knowledge.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('h3',{attrs:{"id":"cs3282"}},[_v("CS3282"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#cs3282","onclick":"event.stopPropagation()"}})]),_v(" "),_c('h4',{attrs:{"id":"sql-injection-with-orm-hibernate"}},[_v("SQL Injection (with ORM: Hibernate)"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#sql-injection-with-orm-hibernate","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("After v9 migration from NoSQL to SQL database, we have to protect the new database from SQL injection attacks.")]),_v(" "),_c('p',[_v("While working on this project, we had to evaluate if our backend which uses Hibernate ORM. I have previous experience with running SQLi attacks from a computer security introductory module and so had some knowledge of how to do simple testing for it, but this gave me a great chance to understand how injection attacks on modern servers are tested for and prevented.")]),_v(" "),_c('p',[_v("However, since our backend uses Hibernate ORM, I had to also research on how malicious attackers will attack a Hibernate backend. Hibernate increases our attack surface, so not only do we have to test for SQLi attacks written vulnerable SQL queries, we also have to test for SQLi attacks on HQL (hibernate query language) as well as attacks on hibernate itself.")]),_v(" "),_c('p',[_v("Based on the research conducted, we have decided the following:")]),_v(" "),_c('ol',[_c('li',[_c('strong',[_v("SQLi")]),_v(": Hibernate does us a favour as its Criteria API uses parameterized queries with prepared statements, which isolates the SQL code (which is written by developers) from data (provided by users) without restricting users. We will still write unit test cases (at database layer) to check that passing in a parameter with a SQL injection string fails, but we fortunately do not have to add any additional functionality.")]),_v(" "),_c('li',[_c('strong',[_v("Attacks on Hibernate")]),_v(": This is when an attacker specifically targets the hibernate architecture / some vulnerability in Hibernate. This is likely a low priority risk -- with how large-scale Hibernate is used, any vulnerability here would urgently be patched by Hibernate developers (we can find these from CVE database). As long as we keep up-to-date on hibernate versions (ie. upgrade if there is a an important update / bug fix for potential attack on hibernate), which our package manager can help with, we should be ok.")]),_v(" "),_c('li',[_c('strong',[_v("HQLi")]),_v(": Taking advantage of vulnerabilities in the Hibernate query language to execute an injection attack. Conclusion: These attacks requires a VERY advanced level of knowledge about HQLi, which is not the most popular language. Additionally, some attacks shown seem to rely on the developer using unsafe methods (eg. createQuery but with string concatenation of the query).")])]),_v(" "),_c('ul',[_c('li',[_c('a',{attrs:{"href":"https://www.youtube.com/watch?v=DKEwWy043WI"}},[_v("Video: good understanding of ORM Injection attacks (Very sophisticated attacks on HQLi)")])]),_v(" "),_c('li',[_c('a',{attrs:{"href":"https://www.sonarsource.com/blog/exploiting-hibernate-injections/"}},[_v("Source (Summary of HQLi attacks)")])])]),_v(" "),_c('p',[_v("From this project and the research we had to do before discussing ways to move forward, I learned a lot about SQL injection attacks as well as some additional information about our hibernate database:")]),_v(" "),_c('ul',[_c('li',[_v("Most modern applications nowadays have AT LEAST be some minimal level of protection for their database / backend servers. The basic SQLi attacks we learn in university will likely not work in real life in isolation. Often, advanced hackers use SQLi attacks in combination with many other techniques to gain access to a server. This was a great experience to understand how SQLi is foundational knowledge for these attacks and how to build upon it to create actual attacks (eg, to modify to use on ORM servers, tricks to bypass certain validation technqiues).")]),_v(" "),_c('li',[_v("Attacks on ORM -- Hibernate Query Language Injection attacks.")]),_v(" "),_c('li',[_v("Parameterized queries and prepared statements (used in Hibernate's Criteria API)")]),_v(" "),_c('li',[_v("Hibernate: configured hibernate to print the SQL queries the hibernate will generate and use (simulates how a real attacker may clone our repo and make modifications to local configs to observe the queries the orm will create and use)")])]),_v(" "),_c('h4',{attrs:{"id":"testing-migrating-e2e-tests"}},[_v("Testing: Migrating E2E Tests"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#testing-migrating-e2e-tests","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ul',[_c('li',[_v("E2E Tests: I migrated a few E2E tests for v9 migration: mainly updated the tests to load SQL entities if they have been migrated at that point in v9 development, and for other entities that have not yet migrated, continue using the NoSQL entities.")]),_v(" "),_c('li',[_v("SQL Injection Tests: Added tests at the database layer to test fields which accept long strings with little-to-no validations. Ensure that hibernate does not treat the data provided as SQL code.")]),_v(" "),_c('li',[_v("Integration tests: I've previously done this during data migration (modifying or writing new integration test cases), but also added new tests for ARF (Account Request Form).")])]),_v(" "),_c('h4',{attrs:{"id":"feature-design"}},[_v("Feature Design"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#feature-design","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("In CS3281, I worked mainly on database migration and had very minimal work on a new feature. Even during the orientation where we technically did work on a feature, it was not merged in and there was very little discussions on the design -- the main objective was to gain an understanding of how the application was structured.")]),_v(" "),_c('p',[_v("I gained an excellent idea of how Teammates does Design planning as well as effort estimation and planning for timelines when working on ARF (Account request form):")]),_v(" "),_c('ol',[_c('li',[_v("Initial test design: database / API endpoint design, frontend / UI design, test case design, etc.")]),_v(" "),_c('li',[_v("Communication with stakeholders (ie. admin): frequent communication with main user(s) of ARF and integrating their requests / feedback into our design (eg. what should be allowed depending on entity's state, UI preferences, etc)")]),_v(" "),_c('li',[_v("Peer-evaluation: not only for PR reviews, but also evaluating each others' design plans and any additional details we may have missed (eg. following REST principles, fields or entites we may have missed out on, edge cases)")]),_v(" "),_c('li',[_v("Weekly (Scrum?) Meetings: To keep each other up-to-date on our own progress and discuss issues encountered or possible improvements to make (which we sometimes realise when we start development).")]),_v(" "),_c('li',[_v("Communicating when timelines cannot be met")]),_v(" "),_c('li',[_v("Testing in staging / pre-release")]),_v(" "),_c('li',[_v("Release: being present when we start release and respond if fixes are needed and urgent.")])]),_v(" "),_c('h4',{attrs:{"id":"solr-searching"}},[_v("Solr Searching"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#solr-searching","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("ARF was my first chance working with our search engine, solr and it was an unexpectedly large hurdle.")]),_v(" "),_c('ol',[_c('li',[_c('p',[_v("Configurations & Documentation: This was my main pain point when working on this. The changed we implemented was not significant -- simple adding 2 new fields and updating the id field. However, the documentation for solr was very lacking (only about how to setup the docker container) and when there was issues with inserting items for indexing or even getting the instance up and running, there was very little debugging statements to track the source of the issue -- hence, quite a bit of effort and time was taken to trace the issues (not only for local development, but also for running tests as each environment had its own seperate config file)\nHowever from this, I learned a lot about solr configs (), using solr's GUI () to debug / track the state of the solr instance and using solr in general for insert + indexing, retrieving entries, sorting, etc.")])]),_v(" "),_c('li',[_c('p',[_v("Using solr:")]),_v(" "),_c('ul',[_c('li',[_v("Updating solr's schema (solr.sh) to add 2 new fields")]),_v(" "),_c('li',[_v("Updating solr's fields: initially, solr prepends all id of entries with 'java.util.UUID:' as the field was a UUID object when passed to solr for indexing.")]),_v(" "),_c('li',[_v("Matching with any word in the given string and evaluate the performance cost for this (as the new comments field allows for huge number of words)")])])])]),_v(" "),_c('p',[_v("Resource:")]),_v(" "),_c('ul',[_c('li',[_c('a',{attrs:{"href":"https://solr.apache.org/guide/solr/latest/getting-started/introduction.html"}},[_v("Apache Solr Guide")])])]),_v(" "),_c('hr'),_v(" "),_c('h3',{attrs:{"id":"frontend"}},[_v("Frontend"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#frontend","onclick":"event.stopPropagation()"}})]),_v(" "),_c('h4',{attrs:{"id":"angular"}},[_v("Angular"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#angular","onclick":"event.stopPropagation()"}})]),_v(" "),_c('pre',[_c('code',{pre:true},[_v("I have had previous experience working with Angular, so I knew of some basic concepts.\nHowever there are still new things I learned while working on the onboarding task and review PRs:\n 1. **Angular Pipes**:\n - It is preferred to use pipes over manually transforming the data\n - To illustrate:\n ``` html\n \n

    \"Hello World\".toUpperCase()

    \n\n \n

    {{ Hello World | uppercase }}

    \n ```\n - better performance: as pure pipes only execute their `transform` method when the underlying value changes.\n - reduce code re-use: pipes can be declared once and used throughout the application.\n\n - There are 2 different types of pipes\n - pure pipe: only runs when the underlying value changes.\n - impure pipe: runs every Digest cycle / in almost every change-detection cycle.\n - To create an impure pipe, set `pure: false` in the pipe's declaration.\n ```javascript\n @Pipe({\n name: 'myPipe',\n pure : false\n })\n ```\n\n If the input to the pipe is an object with nested fields, if there are any changes to the nested fields, a pure pipe will not detect the change.\n This can be fixed by creating an impure pipe, but the performance of an impure pipe is significantly worse as `transform` executes a lot more frequently, which is especially worse when input to the pipe is large (eg. a list).\n\n Resources:\n - [Pipes: improved performance](https://zmushegh.medium.com/why-use-pipe-instead-of-function-in-angular-507cf972bfb0)\n - [Pure vs Impure Pipes](https://upmostly.com/angular/understanding-pure-vs-impure-pipes-in-angular)\n")])]),_v(" "),_c('h4',{attrs:{"id":"bootstrap"}},[_v("Bootstrap"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#bootstrap","onclick":"event.stopPropagation()"}})]),_v(" "),_c('pre',[_c('code',{pre:true},[_v("I had only used pure CSS before this module so this is the first time I worked with a CSS Framework like Bootstrap.\nWhen reviewing PRs on TEAMMATES, I learned about the various global styles Bootstrap provides.\nFor example:\n- Grid system, `col` & `row`: built upon CSS's flexbox architecture; Bootstrap provides functionality to control how the column / row changes.\n - example: `class=\"col-6 col-lg-4\"`: 50% wide when device specs < 992px (ie. `lg` grid breakpoint) and 1/3 of width on devices specs >= 992px\n - 6 default grid tiers: `sm`, `md`, `lg`, ...\n - if no unit/number provided, bootstrap will distribute the space equally (eg.`class=\"col\"`)\n\nIt is preferred to use Bootstrap classes where possible rather than creating our own responsive CSS.\n\nResources:\n- [Bootstrap Docs: Grid System](https://getbootstrap.com/docs/5.3/layout/grid/)\n")])]),_v(" "),_c('h4',{attrs:{"id":"snapshot-testing"}},[_v("Snapshot testing"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#snapshot-testing","onclick":"event.stopPropagation()"}})]),_v(" "),_c('pre',[_c('code',{pre:true},[_v("I have never used snapshot testing before and only heard of the concept in passing.\nFrom this module, I not only learned about how snapshot testing is done on TEAMMATES (from TEAMMATES' dev docs), but also did a bit of research into how snapshot tests are used to ensure no unexpected changes in the UI.\n")])]),_v(" "),_c('h3',{attrs:{"id":"backend"}},[_v("Backend:"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#backend","onclick":"event.stopPropagation()"}})]),_v(" "),_c('h4',{attrs:{"id":"postgresql-database"}},[_v("PostgreSQL (database)"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#postgresql-database","onclick":"event.stopPropagation()"}})]),_v(" "),_c('pre',[_c('code',{pre:true},[_v("For local development on TEAMMATES, Docker creates a running instance of PostgreSQL database.\n")])]),_v(" "),_c('h4',{attrs:{"id":"orm-object-relational-mapping"}},[_v("ORM (Object Relational Mapping)"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#orm-object-relational-mapping","onclick":"event.stopPropagation()"}})]),_v(" "),_c('pre',[_c('code',{pre:true},[_v("Before working on the data migration project, I have never worked with an ORM before, or even known of the concept of it.\n\nOver the course of the project, I learned what an ORM is, and how it makes backend development easier by mapping between code written in an OOP language and data in a relational database by simplifying and reducing time wasted on handling data manually.\n\n\nAdditionally, I gained first-hand experience working with the Hibernate ORM.\n")])]),_v(" "),_c('h4',{attrs:{"id":"hibernate-java-orm-framework"}},[_v("Hibernate (Java ORM Framework)"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#hibernate-java-orm-framework","onclick":"event.stopPropagation()"}})]),_v(" "),_c('pre',[_c('code',{pre:true},[_v("In particular, v9 migration uses Hibernate (an ORM framework for Java environments) for TEAMMATES.\n\nOver the course of the project, I learned some of Hibernate's concepts:\n- states in a Hibernate session (Transient state: not yet attached to a session, Persistent state: associated with a session)\n- **Persistence Context** & cache-memory / caching in Hibernate (including how the first-level cache, second-level cache and managed entities work)\n - Persistence Context: it is a staging area that sits between the code in TEAMMATES and the PostgreSQL database; the concept is implemented in Hibernate `session`.\n - Hibernate's `session` manages all the data loaded into it, keeps track of any changes to the data and is responsible for updating the data in the database later.\n - Managed Entity: a record in the database that's been loaded into a Hibernate session, and is managed by that session (ie. track any change to the entity and updates database accordingly).\n\n- flushing the session (synchronises the objects in memory / cache with the database)\n - Avoid manually forcing the session to flush\n - Hibernate has no guarantees of when the sesison will be flushed to\n\n- **Annotations** (Since Hibernate implements JPA specification, Hibernate supports any environment that uses Jakarta Persistance Annotations on top of providing their own Hibernate Annotations.)\n - Jakarta Persistence Annotations: `@Entity` (specifies a POJO as a JPA entity), `@Id` (specifies a field as the Primary Key), `@Column` (specifies details of a table's column, eg. `nullable`), `@Table` (to change table/relation name)\n ```java\n @Entity\n @Table(name = \"DeadlineExtensions\")\n class DeadlineExtension {\n @Id\n private UUID id;\n }\n ```\n - Jakarta Persistance Mapping Annotations (`@ManyToOne`, `@OneToMany`, `@JoinColumn`) to create relationships between entities.\n ```java\n // Bi-directional many-to-one relationship.\n // 1 feedback session to many deadline extensions.\n @Entity\n @Table(name = \"DeadlineExtensions\")\n class DeadlineExtension {\n @ManyToOne\n @JoinColumn(name = \"sessionId\", nullable = false)\n private FeedbackSession feedbackSession;\n }\n\n @Entity\n @Table(name = \"FeedbackSessions\")\n class FeedbackSession {\n @OneToMany(mappedBy = \"feedbackSession\", cascade = CascadeType.REMOVE)\n @Fetch(FetchMode.JOIN)\n private List deadlineExtensions;\n }\n ```\n - Hibernate Annotations (`@UpdateTimestamp`)\n\nResources:\n- [Starting Guide for learning Hibernate](https://www.digitalocean.com/community/tutorials/hibernate-tutorial-for-beginners)\n- [Hibernate: Entity lifecycle](https://www.baeldung.com/hibernate-entity-lifecycle)\n- [Object States in Hibernate](https://www.baeldung.com/hibernate-session-object-states)\n- [Hibernate: Caching](https://docs.jboss.org/hibernate/orm/6.2/userguide/html_single/Hibernate_User_Guide.html#caching)\n- [Hibernate: Flushing the Session](https://docs.jboss.org/hibernate/core/3.3/reference/en/html/objectstate.html#objectstate-flushing)\n")])]),_v(" "),_c('h4',{attrs:{"id":"criteria-api"}},[_v("Criteria API"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#criteria-api","onclick":"event.stopPropagation()"}})]),_v(" "),_c('pre',[_c('code',{pre:true},[_v("Criteria API is used to construct type-safe queries that fetch entities from the database.\nFor the v9 migration, I learned and gained experience with using these queries to fetch entity / entities from the PostgreSQL database.\nSuch complex queries (built using `CriteriaBuilder`, `CriteriaQuery` and `TypedQuery` classes) include:\n- using clauses (`SELECT`, `FROM`, `WHERE`),\n- joining multiple relations (`JOIN`) and\n- conditional conjunctions (`and`, `equal`, `greaterThan`, ...) provided by the API.\n\nExample of a complex query:\n```java\n // parameters: feedbackSessionId, userId\n\n CriteriaBuilder cb = HibernateUtil.getCriteriaBuilder();\n // specifies that the query should return DeadlineExtension object(s)\n CriteriaQuery cr = cb.createQuery(DeadlineExtension.class);\n Root root = cr.from(DeadlineExtension.class);\n Join deFsJoin = root.join(\"feedbackSession\");\n // Joins deadline extension table with User table by deadlineExtension's user field.\n Join deUserJoin = root.join(\"user\");\n\n // equivalent to SQL's where clause:\n // SELECT ... WHERE de.feedbackSessionId = feedbackSessionId AND de.userId = userId\n cr.select(root).where(cb.and(\n cb.equal(deFsJoin.get(\"feedbackSessionId\"), feedbackSessionId),\n cb.equal(deUserJoin.get(\"userId\"), userId)));\n\n TypedQuery query = HibernateUtil.createQuery(cr);\n\n // Streams in the results of query, and find the first or return null if none.\n return query.getResultStream().findFirst().orElse(null);\n```\n")])]),_v(" "),_c('h4',{attrs:{"id":"docker"}},[_v("Docker"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#docker","onclick":"event.stopPropagation()"}})]),_v(" "),_c('pre',[_c('code',{pre:true},[_v("Docker provides services that allow us to run processes locally in containers (using processes). I wanted to do more research into Docker and understand more about how it worked when I was working on the onboarding task. This includes learning about the docker commands: `docker-compose` and how hosting and virtualisation is done on Docker.\n\nResources:\n- [Containerization Explained by IBM Technology](https://www.youtube.com/watch?v=0qotVMX-J5s)\n- [Virtualization Explained by IBM Technology](https://www.youtube.com/watch?v=FZR0rG3HKIk&t=64s)\n")])]),_v(" "),_c('h3',{attrs:{"id":"testing"}},[_v("Testing"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#testing","onclick":"event.stopPropagation()"}})]),_v(" "),_c('pre',[_c('code',{pre:true},[_v("I had previously learned about the concept of testing and the various types of tests but never had a chance to work extensively with it.\n\nOver the course of the module when working with TEAMMATES, I realised the importance of testing and gained much valuable experience writing test cases (unit and integration tests in particular).\n\nAdditionally, I learned to use the following testing frameworks:\n- **TestNG** (Automation Testing framework)\n I mainly used TestNG's Annotations to aid in writing unit and integration tests on TEAMMATES.\n For example:\n - `@Test`: to specify that the method is a test case.\n - `@BeforeMethod` and `@AfterMethod`: to specify that the annotated method must be executed before / after all `@Test` methods / test cases in the class.\n - `@BeforeClass`: to specify that the annotated method must be called before running all test cases in that class.\n- **Mockito** (Mocking Framework)\n Mockito was introduced in TEAMMATES to make mocking and stubbing in unit tests easier.\n Mocking in Mockito:\n - When Mockito creates a mock, the object is completely \"fake\" (completely ); it never executes real invocations of the mocked class.\n\n I used Mockito to mock classes that the class being tested on has a dependency with, stub method calls (with `when`, `thenReturn`, `thenThrow`, etc) and verify interactions with the mocked class (with `verify` method).\n ```java\n MyClass expectedObject = new MyClass(\"id\");\n\n myMockedClass = mock(MyClass.class);\n // define the behavior of mocked class: instead of executing the real method, the mocked method only returns the expected object\n when(myMockedClass.getObject(\"id\")).thenReturn(expectedObject);\n\n // verify number of calls to stubbed method with mocked class\n verify(myMockedClass, times(1)).getObject(\"id\");\n ```\n\n Additionally, I researched other concepts Mockito provides: `spy` (for partial mocking) and mocking of static methods (`mockStatic`), but never had a chance to work with them.\n - Spy:\n - partial mocking is done for Spy; ie. in comparison to mocks which don't execute the stubbed method (\"only fake object exists\"), for spy: some parts will use real method invocations (\"a real object exists and we are spy-ing on it\").\n\n - Mocking of static methods:\n - in older versions of Mockito, it's not possible to mock static methods, but with PowerMock (a third-party tool), it is possible in newer versions.\n - instead of `mock`, use `mockStatic` to create a mock for a static class.\n\n - `verify`\n - I initially ran into some issues with `verify` and did more research into the cause;\n In the Action-layer tests, since the mocked logic object is shared with all action test classes, the mocked object accumulates the count of calls to any of the mocked logic methods across multiple test cases.\n Work-arounds:\n 1. create the mock whenever a new test case is called (like how it's done for logic and db layer classes) or\n 2. use `clearInvocations` method to clear to reset the invocation counts for a mock, between test cases.\n - Takeaway: A mock will keep track of all its past invocations.\n\n - Mocking void methods:\n - Mockito's default behaviour for void methods: `doNothing` (ie. the mock does nothing, will not execute the real method)\n - If void method has some complex behaviour: can use `doAnswer` (to define custom behaviour) or invoke the real method (`doCallRealMethod`, but this creates a dependency in unit test case)\n\nResources:\n- [TestNG Annotations](https://www.javatpoint.com/testng-annotations)\n- [Mockito: Spy vs Mock](https://stackoverflow.com/questions/28295625/mockito-spy-vs-mock)\n- [Mocking Static Methods with Mockito](https://www.testim.io/blog/mocking-static-methods-mockito/)\n- [Handling void methods with Mockito](https://www.baeldung.com/mockito-void-methods)\n")])]),_v(" "),_c('h3',{attrs:{"id":"git"}},[_v("Git"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#git","onclick":"event.stopPropagation()"}})]),_v(" "),_c('pre',[_c('code',{pre:true},[_v("Over the course of the data migration, I learned how to rebase a branch and revert to a past commit.\nAdditionally, I did some research into other git commands used during development like force pushing a branch.\nI think my knowledge and understanding of Git has improved greatly, beyond merging, `git pull`, `git fetch` and `git push`.\n")])]),_v(" "),_c('h4',{attrs:{"id":"github-editor"}},[_v("Github Editor"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#github-editor","onclick":"event.stopPropagation()"}})]),_v(" "),_c('pre',[_c('code',{pre:true},[_v("A cool tip / trick I learned from my mentors / peers: change \".com\" in the github url to \".dev\" OR pressing \".\" when on a pull request page will open up the web editor for PR, making it very easy to submit PR reviews and review the code.\n")])]),_v(" "),_c('h3',{attrs:{"id":"oss-related"}},[_v("OSS-related"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#oss-related","onclick":"event.stopPropagation()"}})]),_v(" "),_c('h4',{attrs:{"id":"pr-code-reviews"}},[_v("PR / Code reviews"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#pr-code-reviews","onclick":"event.stopPropagation()"}})]),_v(" "),_c('pre',[_c('code',{pre:true},[_v("While reviewing pull requests for other maintainers, I realised there is still much I can learn about Angular, Bootstrap, and even about the codebase (eg. its structure). Hence to be able to give the best review and advice, I did more research into these technologies and concepts before submitting reviews. (Some of this research is in the \"Frontend\" part)\n")])]),_v(" "),_c('h4',{attrs:{"id":"project-management"}},[_v("Project management"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#project-management","onclick":"event.stopPropagation()"}})]),_v(" "),_c('pre',[_c('code',{pre:true},[_v("I realised over the course of the module that there are many facets to managing a large open-source project and it extends beyond reviewing PRs for contributors.\nIn particular, I learned how I not only have to ensure the code works, but whether the code written is consistent with the codebase, if there are any better ways to solve the issue and to provide help that guides the contributor and not directly provide the solution.\n")])])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/EuniceSim142/observations.html b/students/EuniceSim142/observations.html index bdd594224..903bd0e46 100644 --- a/students/EuniceSim142/observations.html +++ b/students/EuniceSim142/observations.html @@ -17,7 +17,7 @@ This documentation was user-facing. It was meant for users of the software to get a good understanding of what this package of the library provides and any interesting usage examples. While working on this

    My Learning Record

    The codebase was very well documented, with very clear-cut instructions of how to set up the library, the standard practices for developers (including testing documentation and code quality expectations).

    • make: make was used for this project, not only to build executables but also to install dependencies, initialise git hooks, etc.
    • "Sign off and commit suggestion" (cool! allow devs to merge in code directly from ): For very simple and small changes required, we can create a hook that can apply changes / suggestions from reviewers. Although we do hope for new contributors to get this chance to learn about teammates' coding practices, in other instances and for minor nits: it can significantly speed up time taken to merge in PRs if the author does not need to manually make the changes in their branch and push again. -Example of sign off and commit suggestion
    • very well-structured pipelines and application structure (easy to set up, test, lint, etc; clear and concise documentation)
    +Example of sign off and commit suggestion
  • very well-structured pipelines and application structure (easy to set up, test, lint, etc; clear and concise documentation)
  • diff --git a/students/EuniceSim142/observations.page-vue-render.js b/students/EuniceSim142/observations.page-vue-render.js index ac823ae87..eb7251339 100644 --- a/students/EuniceSim142/observations.page-vue-render.js +++ b/students/EuniceSim142/observations.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('h3',{attrs:{"id":"project-stdlib-js"}},[_v("Project: stdlib-js"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#project-stdlib-js","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ul',[_c('li',[_v("Project: "),_c('a',{attrs:{"href":"https://github.com/stdlib-js"}},[_v("stdlib-js")]),_v("\nstdlib-js is a standard library for JavaScript and Node.js. It mainly provides numerical and scientific functionality, with robust performance.")])]),_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('ul',[_c('li',[_c('a',{attrs:{"href":"https://github.com/stdlib-js/stdlib/pull/1722"}},[_v("Merged PR: Improve documentation for "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("math/base/ops")]),_v(" namespace")]),_v("\nThis documentation was user-facing. It was meant for users of the software to get a good understanding of what this package of the library provides and any interesting usage examples. While working on this")])]),_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("The codebase was very well documented, with very clear-cut instructions of how to set up the library, the standard practices for developers (including testing documentation and code quality expectations).")]),_v(" "),_c('ul',[_c('li',[_v("make: make was used for this project, not only to build executables but also to install dependencies, initialise git hooks, etc.")]),_v(" "),_c('li',[_v("\"Sign off and commit suggestion\" (cool! allow devs to merge in code directly from ):\nFor very simple and small changes required, we can create a hook that can apply changes / suggestions from reviewers.\nAlthough we do hope for new contributors to get this chance to learn about teammates' coding practices, in other instances and for minor nits: it can significantly speed up time taken to merge in PRs if the author does not need to manually make the changes in their branch and push again.\n"),_c('a',{attrs:{"href":"/2024/students/EuniceSim142/images/sign-off-example.png","target":"_self"}},[_c('img',{staticClass:"img-fluid",attrs:{"src":"/2024/students/EuniceSim142/images/sign-off-example.png","alt":"Example of sign off and commit suggestion"}})])]),_v(" "),_c('li',[_v("very well-structured pipelines and application structure (easy to set up, test, lint, etc; clear and concise documentation)")])])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/EuniceSim142/progress.html b/students/EuniceSim142/progress.html index cd8268680..a6c698ce0 100644 --- a/students/EuniceSim142/progress.html +++ b/students/EuniceSim142/progress.html @@ -12,7 +12,7 @@ const baseUrl = '/2024' -
    Week Achievements
    2 Reviewed PR: [#12699] Replace ng command in setting-up.md #12701
    2 Merged PR: [#12699] Replace ng command in setting-up.md #12701
    5 Authored PR: [#12048] Migrate FeedbackSessionClosedRemindersAction #12738
    5 Authored PR: [#12048] Migrate FeedbackSessionOpeningRemindersAction #12739
    5 Authored PR: [#12048] Migrate FeedbackSessionOpeningSoonRemindersAction #12740
    5 Authored PR: [#12048] Migrate feedbackSessionPublishedRemindersAction #12741
    5 Authored PR: [#12048] Migrate FeedbackSessionClosingRemindersAction #12743
    R In-person discussion / meeting with SQL Injection dev team (CS3282)
    R Authored PR: [#12048] Migrate StudentCourseJoinConfirmationPageE2ETest #12815
    R Authored PR: [#12048] Migrate account for StudentCourseDetailsPageE2ETest #12818
    R Authored PR: [#12048] Move accounts JSON for InstructorStudentRecordsPageE2ETest #12822
    R Authored PR: [#12048] Move accounts JSON for InstructorStudentListPageE2ETest #12830
    R Authored PR: [#12048] Move accounts JSON for InstructorSessionIndividualExtensionPageE2ETest #12832
    R Authored PR: [#12048] Move accounts JSON for InstructorFeedbackSessionsPageE2ETest #12834
    R Authored PR (not yet merged): [#12048] SQL injection test for FeedbackQuestionsDbIT #12847
    R Authored PR: [#12048] SQL Injection Test for FeedbackResponsesDb #12848
    R Authored PR: [#12048] SQL Injection tests for FeedbackResponseCommentsDbIT #12853
    R Reviewed PR: [#12048] Resolve merge conflicts #12776
    R Reviewed PR: [#12048] SQL injection test for AccountRequestsDbIT #12788
    R Reviewed PR: [#12048] Migrate instructor courses page e2e test #12789
    R Reviewed PR: [#12048] migrate InstructorCourseJoinConfirmationPageE2ETest #12790
    R Reviewed PR: [#12048] migrate AdminHomePageE2ETest #12794
    R Reviewed PR: [#12048] Fix incorrect usage of recipient as param for E2E test #12797
    R Reviewed PR: [#12048] Move accounts JSON for AdminSessionsPageE2ETest #12802
    R Reviewed PR: [#12048] Move accounts JSON for AutomatedSessionRemindersE2ETest #12803
    R Reviewed PR: [#12048] Move accounts JSON for FeedbackConstSumOptionQuestionE2ETest #12804
    R Reviewed PR: [#12048] Move accounts JSON for FeedbackConstSumRecipientQuestionE2ETest #12805
    R Reviewed PR: [#12048] migrate AdminAccountsPageE2ETest #12806
    R Reviewed PR: [#12048] migrate StudentHomePageE2ETest #12807
    R Reviewed PR: [#12048] Move accounts JSON for FeedbackContributionQuestionE2ETest #12808
    R Reviewed PR: [#12048] Move accounts JSON for FeedbackMcqQuestionE2ETest #12809
    R Reviewed PR: [#12048] Move accounts JSON for FeedbackMsqQuestionE2ETest #12810
    R Reviewed PR: [#12048] Move accounts JSON for FeedbackNumScaleQuestionE2ETest #12812
    R Reviewed PR: [#12048] Move accounts JSON for FeedbackRankOptionQuestionE2ETest #12813
    R Reviewed PR: [#12048] Move accounts JSON for FeedbackRankRecipientQuestionE2ETest #12814
    R Reviewed PR: [#12048] Move accounts JSON for FeedbackResultsPageE2ETest #12816
    R Reviewed PR: [#12048] Move accounts JSON for FeedbackRubricQuestionE2ETest #12817
    R Reviewed PR: [#12048] Move accounts JSON for FeedbackSubmitPageE2ETest #12819
    R Reviewed PR: [#12048] Move accounts JSON for FeedbackTextQuestionE2ETest #12821
    R Reviewed PR: [#12048] Move accounts JSON for InstructorCourseDetailsPageE2ETest #12823
    R Reviewed PR: [#12048] Move accounts JSON for InstructorCourseEditPageE2ETest #12825
    R Reviewed PR: [#12048] Move accounts JSON for InstructorCourseEnrollPageE2ETest #12827
    R Reviewed PR: [#12048] Move accounts JSON for InstructorCourseStudentDetailsEditPageE2ETest #12829
    R Reviewed PR: [#12048] Move accounts JSON for InstructorCourseStudentDetailsPageE2ETest #12831
    R Reviewed PR: [#12048] Move accounts JSON for InstructorFeedbackReportPageE2ETest #12833
    R Reviewed PR: [#12048] Fix failing component tests #12837
    R Merged PR: [#12048] Move accounts JSON for AdminSessionsPageE2ETest #12802
    R Merged PR: [#12048] Fix incorrect usage of recipient as param for E2E test #12797
    R Online meeting with ARF dev team (both CS3281 + CS3282 students): requirements planning 1 (user stories)
    7 In-person discussion / meeting with ARF dev team (both CS3281 + CS3282 students): requirements planning 2 (tech design)
    7 Merged PR: [#12048] SQL injection test for AccountsDbIT #12800
    7 Reviewed PR: [#12048] Add SQL injection tests in FeedbackSessionsDbIT #12857
    7 Reviewed PR: [#12048] SQL injection test for AccountsDbIT #12800
    7 Reviewed PR: [#12048] SQL injection test for CoursesDbIT #12801
    7 Merged PR: [#12048] SQL injection test for AccountRequestsDbIT #12788
    9 Reviewed PR: [#11878] Add status and comments to AccountRequest #12898
    9 Reviewed PR: [#11878] Add status and comments to AccountRequest #12898
    9 Reviewed PR: [#11878] Modify CreateAccountRequestAction #12913
    9 Reviewed PR: [#11878] Fix AccountRequest migration script #12915
    9 Reviewed PR: [#11878] Add new account request alert email for admins #12926
    10 Authored PR: [#11878] Add GetAllPendingAccountRequests API #12927
    10 Authored PR: [#11878] Update SearchAccountRequests endpoint #12950
    10 Reviewed PR: [#11878] Admin Search UI Update for ARF #12945
    10 Merged PR: [#11878] Admin Search UI Update for ARF #12945
    10 Reviewed PR: [#11878] Get account requests by ID in storage update method #12955
    10 Merged PR: [#11878] Get account requests by ID in storage update method #12955
    10 Reviewed PR: [#11878] Get by account request ID in SQL injection tests #12956
    10 Merged PR: [#11878] Get by account request ID in SQL injection tests #12956
    10 Reviewed PR: [#11878] Merge master into account-request-form #12972
    11 Authored PR: [#11878] Add AccountRequest Rejection email generator. #12987
    11 Reviewed PR: [#11878] Add Edit and Approve Account Requests functionality #12975
    12 Authored PR: [#11878] Add sort by created_at for getAllPendingRequests #13038
    12 Reviewed PR: [#11878] Add tests for Account Request Table #12977
    12 Merged PR: [#11878] Add tests for Account Request Table #12977
    12 Reviewed PR: [#11878] Create reject account request endpoint #12985
    12 Reviewed PR: [#11878] Create Rejection Modal for Account Requests #12989
    13 Reviewed PR: [#11878] Fix Edit #13056
    13 Merged PR: [#11878] Fix Edit #13056
    +
    Week Achievements
    2 Reviewed PR: [#12699] Replace ng command in setting-up.md #12701
    2 Merged PR: [#12699] Replace ng command in setting-up.md #12701
    5 Authored PR: [#12048] Migrate FeedbackSessionClosedRemindersAction #12738
    5 Authored PR: [#12048] Migrate FeedbackSessionOpeningRemindersAction #12739
    5 Authored PR: [#12048] Migrate FeedbackSessionOpeningSoonRemindersAction #12740
    5 Authored PR: [#12048] Migrate feedbackSessionPublishedRemindersAction #12741
    5 Authored PR: [#12048] Migrate FeedbackSessionClosingRemindersAction #12743
    R In-person discussion / meeting with SQL Injection dev team (CS3282)
    R Authored PR: [#12048] Migrate StudentCourseJoinConfirmationPageE2ETest #12815
    R Authored PR: [#12048] Migrate account for StudentCourseDetailsPageE2ETest #12818
    R Authored PR: [#12048] Move accounts JSON for InstructorStudentRecordsPageE2ETest #12822
    R Authored PR: [#12048] Move accounts JSON for InstructorStudentListPageE2ETest #12830
    R Authored PR: [#12048] Move accounts JSON for InstructorSessionIndividualExtensionPageE2ETest #12832
    R Authored PR: [#12048] Move accounts JSON for InstructorFeedbackSessionsPageE2ETest #12834
    R Authored PR (not yet merged): [#12048] SQL injection test for FeedbackQuestionsDbIT #12847
    R Authored PR: [#12048] SQL Injection Test for FeedbackResponsesDb #12848
    R Authored PR: [#12048] SQL Injection tests for FeedbackResponseCommentsDbIT #12853
    R Reviewed PR: [#12048] Resolve merge conflicts #12776
    R Reviewed PR: [#12048] SQL injection test for AccountRequestsDbIT #12788
    R Reviewed PR: [#12048] Migrate instructor courses page e2e test #12789
    R Reviewed PR: [#12048] migrate InstructorCourseJoinConfirmationPageE2ETest #12790
    R Reviewed PR: [#12048] migrate AdminHomePageE2ETest #12794
    R Reviewed PR: [#12048] Fix incorrect usage of recipient as param for E2E test #12797
    R Reviewed PR: [#12048] Move accounts JSON for AdminSessionsPageE2ETest #12802
    R Reviewed PR: [#12048] Move accounts JSON for AutomatedSessionRemindersE2ETest #12803
    R Reviewed PR: [#12048] Move accounts JSON for FeedbackConstSumOptionQuestionE2ETest #12804
    R Reviewed PR: [#12048] Move accounts JSON for FeedbackConstSumRecipientQuestionE2ETest #12805
    R Reviewed PR: [#12048] migrate AdminAccountsPageE2ETest #12806
    R Reviewed PR: [#12048] migrate StudentHomePageE2ETest #12807
    R Reviewed PR: [#12048] Move accounts JSON for FeedbackContributionQuestionE2ETest #12808
    R Reviewed PR: [#12048] Move accounts JSON for FeedbackMcqQuestionE2ETest #12809
    R Reviewed PR: [#12048] Move accounts JSON for FeedbackMsqQuestionE2ETest #12810
    R Reviewed PR: [#12048] Move accounts JSON for FeedbackNumScaleQuestionE2ETest #12812
    R Reviewed PR: [#12048] Move accounts JSON for FeedbackRankOptionQuestionE2ETest #12813
    R Reviewed PR: [#12048] Move accounts JSON for FeedbackRankRecipientQuestionE2ETest #12814
    R Reviewed PR: [#12048] Move accounts JSON for FeedbackResultsPageE2ETest #12816
    R Reviewed PR: [#12048] Move accounts JSON for FeedbackRubricQuestionE2ETest #12817
    R Reviewed PR: [#12048] Move accounts JSON for FeedbackSubmitPageE2ETest #12819
    R Reviewed PR: [#12048] Move accounts JSON for FeedbackTextQuestionE2ETest #12821
    R Reviewed PR: [#12048] Move accounts JSON for InstructorCourseDetailsPageE2ETest #12823
    R Reviewed PR: [#12048] Move accounts JSON for InstructorCourseEditPageE2ETest #12825
    R Reviewed PR: [#12048] Move accounts JSON for InstructorCourseEnrollPageE2ETest #12827
    R Reviewed PR: [#12048] Move accounts JSON for InstructorCourseStudentDetailsEditPageE2ETest #12829
    R Reviewed PR: [#12048] Move accounts JSON for InstructorCourseStudentDetailsPageE2ETest #12831
    R Reviewed PR: [#12048] Move accounts JSON for InstructorFeedbackReportPageE2ETest #12833
    R Reviewed PR: [#12048] Fix failing component tests #12837
    R Merged PR: [#12048] Move accounts JSON for AdminSessionsPageE2ETest #12802
    R Merged PR: [#12048] Fix incorrect usage of recipient as param for E2E test #12797
    R Online meeting with ARF dev team (both CS3281 + CS3282 students): requirements planning 1 (user stories)
    7 In-person discussion / meeting with ARF dev team (both CS3281 + CS3282 students): requirements planning 2 (tech design)
    7 Merged PR: [#12048] SQL injection test for AccountsDbIT #12800
    7 Reviewed PR: [#12048] Add SQL injection tests in FeedbackSessionsDbIT #12857
    7 Reviewed PR: [#12048] SQL injection test for AccountsDbIT #12800
    7 Reviewed PR: [#12048] SQL injection test for CoursesDbIT #12801
    7 Merged PR: [#12048] SQL injection test for AccountRequestsDbIT #12788
    9 Reviewed PR: [#11878] Add status and comments to AccountRequest #12898
    9 Reviewed PR: [#11878] Add status and comments to AccountRequest #12898
    9 Reviewed PR: [#11878] Modify CreateAccountRequestAction #12913
    9 Reviewed PR: [#11878] Fix AccountRequest migration script #12915
    9 Reviewed PR: [#11878] Add new account request alert email for admins #12926
    10 Authored PR: [#11878] Add GetAllPendingAccountRequests API #12927
    10 Authored PR: [#11878] Update SearchAccountRequests endpoint #12950
    10 Reviewed PR: [#11878] Admin Search UI Update for ARF #12945
    10 Merged PR: [#11878] Admin Search UI Update for ARF #12945
    10 Reviewed PR: [#11878] Get account requests by ID in storage update method #12955
    10 Merged PR: [#11878] Get account requests by ID in storage update method #12955
    10 Reviewed PR: [#11878] Get by account request ID in SQL injection tests #12956
    10 Merged PR: [#11878] Get by account request ID in SQL injection tests #12956
    10 Reviewed PR: [#11878] Merge master into account-request-form #12972
    11 Authored PR: [#11878] Add AccountRequest Rejection email generator. #12987
    11 Reviewed PR: [#11878] Add Edit and Approve Account Requests functionality #12975
    12 Authored PR: [#11878] Add sort by created_at for getAllPendingRequests #13038
    12 Reviewed PR: [#11878] Add tests for Account Request Table #12977
    12 Merged PR: [#11878] Add tests for Account Request Table #12977
    12 Reviewed PR: [#11878] Create reject account request endpoint #12985
    12 Reviewed PR: [#11878] Create Rejection Modal for Account Requests #12989
    13 Reviewed PR: [#11878] Fix Edit #13056
    13 Merged PR: [#11878] Fix Edit #13056
    diff --git a/students/EuniceSim142/progress.page-vue-render.js b/students/EuniceSim142/progress.page-vue-render.js index aaed36cc1..2930a0b7d 100644 --- a/students/EuniceSim142/progress.page-vue-render.js +++ b/students/EuniceSim142/progress.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('div',{staticClass:"table-responsive"},[_c('table',{staticClass:"markbind-table table table-bordered table-striped"},[_c('thead',[_c('tr',[_c('th',[_v("Week")]),_v(" "),_c('th',[_v("Achievements")])])]),_v(" "),_c('tbody',[_c('tr',[_c('td',[_v("2")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12701"}},[_v("[#12699] Replace ng command in setting-up.md #12701")])])]),_v(" "),_c('tr',[_c('td',[_v("2")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12701"}},[_v("[#12699] Replace ng command in setting-up.md #12701")])])]),_v(" "),_c('tr',[_c('td',[_v("5")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12738"}},[_v("[#12048] Migrate FeedbackSessionClosedRemindersAction #12738")])])]),_v(" "),_c('tr',[_c('td',[_v("5")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12739"}},[_v("[#12048] Migrate FeedbackSessionOpeningRemindersAction #12739")])])]),_v(" "),_c('tr',[_c('td',[_v("5")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12740"}},[_v("[#12048] Migrate FeedbackSessionOpeningSoonRemindersAction #12740")])])]),_v(" "),_c('tr',[_c('td',[_v("5")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12741"}},[_v("[#12048] Migrate feedbackSessionPublishedRemindersAction #12741")])])]),_v(" "),_c('tr',[_c('td',[_v("5")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12743"}},[_v("[#12048] Migrate FeedbackSessionClosingRemindersAction #12743")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("In-person discussion / meeting with SQL Injection dev team (CS3282)")])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12815"}},[_v("[#12048] Migrate StudentCourseJoinConfirmationPageE2ETest #12815")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12818"}},[_v("[#12048] Migrate account for StudentCourseDetailsPageE2ETest #12818")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12822"}},[_v("[#12048] Move accounts JSON for InstructorStudentRecordsPageE2ETest #12822")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12830"}},[_v("[#12048] Move accounts JSON for InstructorStudentListPageE2ETest #12830")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12832"}},[_v("[#12048] Move accounts JSON for InstructorSessionIndividualExtensionPageE2ETest #12832")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12834"}},[_v("[#12048] Move accounts JSON for InstructorFeedbackSessionsPageE2ETest #12834")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Authored PR (not yet merged): "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12847"}},[_v("[#12048] SQL injection test for FeedbackQuestionsDbIT #12847")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12848"}},[_v("[#12048] SQL Injection Test for FeedbackResponsesDb #12848")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12853"}},[_v("[#12048] SQL Injection tests for FeedbackResponseCommentsDbIT #12853")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12776"}},[_v("[#12048] Resolve merge conflicts #12776")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12788"}},[_v("[#12048] SQL injection test for AccountRequestsDbIT #12788")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12789"}},[_v("[#12048] Migrate instructor courses page e2e test #12789")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12790"}},[_v("[#12048] migrate InstructorCourseJoinConfirmationPageE2ETest #12790")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12794"}},[_v("[#12048] migrate AdminHomePageE2ETest #12794")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12797"}},[_v("[#12048] Fix incorrect usage of recipient as param for E2E test #12797")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12802"}},[_v("[#12048] Move accounts JSON for AdminSessionsPageE2ETest #12802")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12803"}},[_v("[#12048] Move accounts JSON for AutomatedSessionRemindersE2ETest #12803")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12804"}},[_v("[#12048] Move accounts JSON for FeedbackConstSumOptionQuestionE2ETest #12804")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12805"}},[_v("[#12048] Move accounts JSON for FeedbackConstSumRecipientQuestionE2ETest #12805")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12806"}},[_v("[#12048] migrate AdminAccountsPageE2ETest #12806")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12807"}},[_v("[#12048] migrate StudentHomePageE2ETest #12807")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12808"}},[_v("[#12048] Move accounts JSON for FeedbackContributionQuestionE2ETest #12808")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12809"}},[_v("[#12048] Move accounts JSON for FeedbackMcqQuestionE2ETest #12809")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12810"}},[_v("[#12048] Move accounts JSON for FeedbackMsqQuestionE2ETest #12810")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12812"}},[_v("[#12048] Move accounts JSON for FeedbackNumScaleQuestionE2ETest #12812")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12813"}},[_v("[#12048] Move accounts JSON for FeedbackRankOptionQuestionE2ETest #12813")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12814"}},[_v("[#12048] Move accounts JSON for FeedbackRankRecipientQuestionE2ETest #12814")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12816"}},[_v("[#12048] Move accounts JSON for FeedbackResultsPageE2ETest #12816")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12817"}},[_v("[#12048] Move accounts JSON for FeedbackRubricQuestionE2ETest #12817")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12819"}},[_v("[#12048] Move accounts JSON for FeedbackSubmitPageE2ETest #12819")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12821"}},[_v("[#12048] Move accounts JSON for FeedbackTextQuestionE2ETest #12821")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12823"}},[_v("[#12048] Move accounts JSON for InstructorCourseDetailsPageE2ETest #12823")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12825"}},[_v("[#12048] Move accounts JSON for InstructorCourseEditPageE2ETest #12825")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12827"}},[_v("[#12048] Move accounts JSON for InstructorCourseEnrollPageE2ETest #12827")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12829"}},[_v("[#12048] Move accounts JSON for InstructorCourseStudentDetailsEditPageE2ETest #12829")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12831"}},[_v("[#12048] Move accounts JSON for InstructorCourseStudentDetailsPageE2ETest #12831")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12833"}},[_v("[#12048] Move accounts JSON for InstructorFeedbackReportPageE2ETest #12833")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12837"}},[_v("[#12048] Fix failing component tests #12837")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12802"}},[_v("[#12048] Move accounts JSON for AdminSessionsPageE2ETest #12802")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12797"}},[_v("[#12048] Fix incorrect usage of recipient as param for E2E test #12797")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Online meeting with ARF dev team (both CS3281 + CS3282 students): requirements planning 1 (user stories)")])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("In-person discussion / meeting with ARF dev team (both CS3281 + CS3282 students): requirements planning 2 (tech design)")])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12800"}},[_v("[#12048] SQL injection test for AccountsDbIT #12800")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12857"}},[_v("[#12048] Add SQL injection tests in FeedbackSessionsDbIT #12857")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12800"}},[_v("[#12048] SQL injection test for AccountsDbIT #12800")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12801"}},[_v("[#12048] SQL injection test for CoursesDbIT #12801")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12788"}},[_v("[#12048] SQL injection test for AccountRequestsDbIT #12788")])])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12898"}},[_v("[#11878] Add status and comments to AccountRequest #12898")])])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12898"}},[_v("[#11878] Add status and comments to AccountRequest #12898")])])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12913"}},[_v("[#11878] Modify CreateAccountRequestAction #12913")])])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12915"}},[_v("[#11878] Fix AccountRequest migration script #12915")])])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12926"}},[_v("[#11878] Add new account request alert email for admins #12926")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12927"}},[_v("[#11878] Add GetAllPendingAccountRequests API #12927")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12950"}},[_v("[#11878] Update SearchAccountRequests endpoint #12950")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12945"}},[_v("[#11878] Admin Search UI Update for ARF #12945")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12945"}},[_v("[#11878] Admin Search UI Update for ARF #12945")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12955"}},[_v("[#11878] Get account requests by ID in storage update method #12955")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12955"}},[_v("[#11878] Get account requests by ID in storage update method #12955")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12956"}},[_v("[#11878] Get by account request ID in SQL injection tests #12956")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12956"}},[_v("[#11878] Get by account request ID in SQL injection tests #12956")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12972"}},[_v("[#11878] Merge master into account-request-form #12972")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12987"}},[_v("[#11878] Add AccountRequest Rejection email generator. #12987")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12975"}},[_v("[#11878] Add Edit and Approve Account Requests functionality #12975")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13038"}},[_v("[#11878] Add sort by created_at for getAllPendingRequests #13038")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12977"}},[_v("[#11878] Add tests for Account Request Table #12977")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12977"}},[_v("[#11878] Add tests for Account Request Table #12977")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12985"}},[_v("[#11878] Create reject account request endpoint #12985")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12989"}},[_v("[#11878] Create Rejection Modal for Account Requests #12989")])])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13056"}},[_v("[#11878] Fix Edit #13056")])])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13056"}},[_v("[#11878] Fix Edit #13056")])])])])])])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/FergusMok/info.html b/students/FergusMok/info.html index 46a775acc..58c6d22cb 100644 --- a/students/FergusMok/info.html +++ b/students/FergusMok/info.html @@ -12,7 +12,7 @@ const baseUrl = '/2024' - + diff --git a/students/FergusMok/info.page-vue-render.js b/students/FergusMok/info.page-vue-render.js index d8036df8a..82f8700a3 100644 --- a/students/FergusMok/info.page-vue-render.js +++ b/students/FergusMok/info.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('p',[_c('span',{attrs:{"id":"github"}},[_c('a',{attrs:{"href":"https://github.com/FergusMok"}},[_v("https://github.com/FergusMok")])])]),_v(" "),_c('p',[_c('span',{attrs:{"id":"projects"}},[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates"}},[_v("TEAMMATES")])])])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/FergusMok/knowledge.html b/students/FergusMok/knowledge.html index 1f45d4f06..d19f6fd6c 100644 --- a/students/FergusMok/knowledge.html +++ b/students/FergusMok/knowledge.html @@ -17,7 +17,7 @@ This is useful when working in parallel with branches, and rebasing a long-lived branch that will give merge conflicts. The common problem is having to resolve the same conflict each time you rebase your branch. After toggling rerere on, you will no longer need to resolve the same conflict again after solving it once. This is because git will record your conflict merge results, -and auto-solve them the next time around.

    git config rerere.enabled true

    Alternatively, if you are aware that many of your new commits will result in a conflict, it also be easier to squash them then rebase.

    Git ReReRe: https://git-scm.com/docs/git-rerere

    Additional Tips

    1. To pass additional flags to npm run, you can use append -- --<flag>. E.g npm run test -- --detect-open-handles
    +and auto-solve them the next time around.

    git config rerere.enabled true

    Alternatively, if you are aware that many of your new commits will result in a conflict, it also be easier to squash them then rebase.

    Git ReReRe: https://git-scm.com/docs/git-rerere

    Additional Tips

    1. To pass additional flags to npm run, you can use append -- --<flag>. E.g npm run test -- --detect-open-handles
    diff --git a/students/FergusMok/knowledge.page-vue-render.js b/students/FergusMok/knowledge.page-vue-render.js index 49b1abf79..ad03245ee 100644 --- a/students/FergusMok/knowledge.page-vue-render.js +++ b/students/FergusMok/knowledge.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('h1',{attrs:{"id":"frontend"}},[_v("Frontend"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#frontend","onclick":"event.stopPropagation()"}})]),_v(" "),_c('h3',{attrs:{"id":"angular"}},[_v("Angular"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#angular","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Angular is a frontend framework built on TypeScript. A majority of Angular's functions uses Typescript decorators, which are adds functionalities to functions and class.")]),_v(" "),_c('p',[_v("Each Angular component uses a selector (for other components to reference this component), HTML template, and CSS file to decorate the HTML template.")]),_v(" "),_c('p',[_v("Furthermore, within the HTML template, we are able to use Angular directives. Examples are *ngIf, *ngFor. The asterik is synthetic sugar that surrounds the HTML with a , and is useful for adding and removing tag elements. Another interesting feature is that Angular supports two-way data binding directly, where the HTML's value can affect the actual value and vice versa. Done with [(NgModel)]")]),_v(" "),_c('p',[_v("See:")]),_v(" "),_c('ol',[_c('li',[_c('a',{attrs:{"href":"https://angular.io/guidestructural-directives#what-are-structural-directives"}},[_v("https://angular.io/guidestructural-directives#what-are-structural-directives")]),_v(";")]),_v(" "),_c('li',[_c('a',{attrs:{"href":"https://angular.io/guide/two-way-binding#adding-two-way-data-binding"}},[_v("https://angular.io/guide/two-way-binding#adding-two-way-data-binding")])])]),_v(" "),_c('p',[_v("Angular's CLI is also extremely useful, and most basic features from building and testing are ready out of the box.")]),_v(" "),_c('p',[_v("See: "),_c('a',{attrs:{"href":"https://angular.io/cli"}},[_v("https://angular.io/cli")])]),_v(" "),_c('h3',{attrs:{"id":"rxjs"}},[_v("RxJS"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#rxjs","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("RxJS is a library that helps with async and event-based functions in TEAMMATES through Observables and Subscriptions. RxJS can also be used with other frameworks, like React and Vue.")]),_v(" "),_c('p',[_v("Common pattern of usage:")]),_v(" "),_c('ol',[_c('li',[_v("Create a service class, with a function that calls the backend API. This function returns an Observable.")]),_v(" "),_c('li',[_v("We can call the service from our component, and add on "),_c('b',[_v("operators")]),_v(" to the Observable, such as pipe and subscribe.")]),_v(" "),_c('li',[_v("Pipe will chain observable operators, and subscribe will activate the observabe to listen for the emitted values.")])]),_v(" "),_c('h3',{attrs:{"id":"jasmine-and-jest"}},[_v("Jasmine and Jest"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#jasmine-and-jest","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Jasmine is a testing framework. It describes test cases, and can make use of "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("spies")]),_v(", that can mock return values, track the status of the function. Furthermore, combined with using inspecting HTML elements, we can check the values of the components in different conditions.\nJest is another testing framework used for snapshots. We're able to take snapshots, save them, and compare them later when running the tests again. This is especially useful for regression testing.")]),_v(" "),_c('h1',{attrs:{"id":"backend"}},[_v("Backend"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#backend","onclick":"event.stopPropagation()"}})]),_v(" "),_c('h3',{attrs:{"id":"migration-of-data"}},[_v("Migration of data"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#migration-of-data","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("The 2 main considerations for migration this year was: correctness and performance. I've always been more interested in the performance aspect, and have learnt great amount of things during both processes.")]),_v(" "),_c('h4',{attrs:{"id":"eager-and-lazy-loading"}},[_v("Eager and lazy loading"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#eager-and-lazy-loading","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("The biggest improvement in performance can be found when switching from lazy loading to eager loading. The scenario would be having to query for a collection of entities's relations. Lazy loading would be to query one entity's relations at a time, and eager loading would be to query the entire collections' relations in 1 single query. Lazy loading would incur N round-trip times to the database, leading it to be extremely slow. This is also called the N+1 query problem.")]),_v(" "),_c('p',[_v("However, a main limitation of this method would be the Out-Of-Memory (OoM) error. Lazy loading is preferred only in the situtation where the collection of entities' relations are extremely huge, leading to an inability to load all of them at once in memory. A method the course migration team has done was to query the number of relations the collection has. If it exceeds a certain threshold, we will utilize the lazy method to prevent OoM. Likewise, we are also able to increase the available memory in a Java program.")]),_v(" "),_c('h4',{attrs:{"id":"batch-loading-by-the-database-orm"}},[_v("Batch loading by the database ORM"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#batch-loading-by-the-database-orm","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("One of the biggest improvements seen was also configuring our ORM to utilize batch-loading and batch-saving. Behind the scenes, the ORM may only send a UPDATE request after reaching 5 entities or so. However, an even better method would be asking the ORM to send the request when reaching 50 entities. In fact, this is a pattern recommended by the Hibernate ORM. Implementation can be seen here:")]),_v(" "),_c('p',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12896/files"}},[_v("https://github.com/TEAMMATES/teammates/pull/12896/files")])]),_v(" "),_c('p',[_v("In fact, Hibernate also has common patterns for saving in batches for the most optimal performance")]),_v(" "),_c('p',[_c('a',{attrs:{"href":"https://docs.jboss.org/hibernate/core/3.3/reference/en/html/batch.html"}},[_v("https://docs.jboss.org/hibernate/core/3.3/reference/en/html/batch.html")])]),_v(" "),_c('h4',{attrs:{"id":"utilizing-traditional-database-techniques"}},[_v("Utilizing traditional database techniques"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#utilizing-traditional-database-techniques","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("When loading a large amount of entities, a wise method to improve performance was to only load needed fields. In traditional SQL, this would be done with the SELECT method. Reducing the amount of data to be loaded has significantly improved our query times during migration, with up to 50% at certain times.")]),_v(" "),_c('p',[_v("Another method would the main querying-speed improvers for SQL, indexes. When querying the entire database with an ordered method, a intuitive method would be the sort by createdAt. However, we should instead sort by an index. In fact, all database tables have an implicit index, which is the ID column. Hence, the team used the ID column to sort instead to improve querying performance.")]),_v(" "),_c('h3',{attrs:{"id":"connection-pools"}},[_v("Connection pools"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#connection-pools","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("With the set-up of the SQL database on production, one unseen circumstance during deployment was choosing of the connection pool tool. Connection pools contain the pool of connections for users to query the database. These pools must scale the number of connections accordingly, and also handle any dead connections.")]),_v(" "),_c('p',[_v("During the deployment on production, we initially received errors as our default connection pool was not testing connections on whether they were dead before handing it to users. I quickly learnt that proper connection pools will usually send a "),_c('strong',[_v("connection test query")]),_v(" (\"SELECT 1\") before handing the connection to users.")]),_v(" "),_c('p',[_v("Apart from correctness of connections, connection pools are one of the most important parts when scaling a database's performance. There are many considerations, such as setting the minimum and maximum size of connection pools. A very shocking and counter-intuitive learning point was that DBAs often overestimate the size of connection pools, and reducing the size can actually lead to a 50x improvement. In fact, there's a formula given by PostgreSQL to calculate the optimal number of connections your server can handle, number of connections connections = ((core_count * 2) + effective_spindle_count). More can be read up here:")]),_v(" "),_c('p',[_v("Hikari Connection Pool tuning: "),_c('a',{attrs:{"href":"https://github.com/brettwooldridge/HikariCP/wiki/About-Pool-Sizing"}},[_v("https://github.com/brettwooldridge/HikariCP/wiki/About-Pool-Sizing")])]),_v(" "),_c('h3',{attrs:{"id":"google-cloud-datastore"}},[_v("Google Cloud Datastore"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#google-cloud-datastore","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("I learnt how Datastore's key-value works, it's strengths and limitations, and important conventions. These conventions are seemly counterintuitive for users with an SQL background for smaller applications, but makes sense when building applications at scale.")]),_v(" "),_c('h4',{attrs:{"id":"counters"}},[_v("Counters"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#counters","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("For example, as datastore's structure does not support aggregating functions, functions such as counting is an O(n) operation. The Datastore community's (counterintuitive) convention is to have multiple Counter class.")]),_v(" "),_c('p',[_v("These counters may also face simultaneous write limitations, which is known as contention, when counters change at >5/s. This results in needing to implement 'sharding' counters.")]),_v(" "),_c('p',[_v("Google's article: "),_c('a',{attrs:{"href":"https://medium.com/@duhroach/datastore-sharded-counters-2ba6da7475b0"}},[_v("https://medium.com/@duhroach/datastore-sharded-counters-2ba6da7475b0")])]),_v(" "),_c('h4',{attrs:{"id":"hotspotting"}},[_v("Hotspotting"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#hotspotting","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Datastore's (counterintuitive) convention when writing a large amount of data is to avoid monotonically increasing IDs. This is because ranges of storage with similar IDs are stored on the same 'node'(known as tablets), and massive writes to a node will lead to a significant slowdown, called hotspotting. This is a significant pain point for time-series data.")]),_v(" "),_c('p',[_v("Former Googler: "),_c('a',{attrs:{"href":"https://ikaisays.com/2011/01/25/app-engine-datastore-tip-monotonically-increasing-values-are-bad/"}},[_v("https://ikaisays.com/2011/01/25/app-engine-datastore-tip-monotonically-increasing-values-are-bad/")])]),_v(" "),_c('p',[_v("The convention is to prepend with a known amount of random numbers/hash, or prepend the ID with other useful fields that can be used for querying later on.")]),_v(" "),_c('p',[_v("Schema Design: "),_c('a',{attrs:{"href":"https://cloud.google.com/bigtable/docs/schema-design"}},[_v("https://cloud.google.com/bigtable/docs/schema-design")])]),_v(" "),_c('h4',{attrs:{"id":"datastore-indexes"}},[_v("Datastore Indexes"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#datastore-indexes","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Datastore is built in a way that requires indexes for every single field that requires that needs to be queried. This is because Datastore cannot reference the data of columns, and ONLY the key during the query. The (counterintuitive) convetion is to make indexes for most fields of an entity, and this can lead to 90% of the storage for an entity to be indexes alone. This leads to a trade-off for more performance at scale.")]),_v(" "),_c('p',[_v("However, Google does not bill for storage, and only for writes and reads.")]),_v(" "),_c('p',[_v("Google's tutorial: "),_c('a',{attrs:{"href":"https://youtu.be/d4CiMWy0J70?t=75"}},[_v("https://youtu.be/d4CiMWy0J70?t=75")])]),_v(" "),_c('h3',{attrs:{"id":"git-rerere"}},[_v("Git ReReRe"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#git-rerere","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("While most people know the basics of git, git rerere is slightly more advanced. It stands for "),_c('b',[_v("Re")]),_v("use "),_c('b',[_v("re")]),_v("corded "),_c('b',[_v("re")]),_v("solution.\nThis is useful when working in parallel with branches, and rebasing a long-lived branch that will give merge conflicts.\nThe common problem is having to resolve the same conflict each time you rebase your branch. After toggling rerere on,\nyou will no longer need to resolve the same conflict again after solving it once. This is because git will record your conflict merge results,\nand auto-solve them the next time around.")]),_v(" "),_c('p',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("git config rerere.enabled true")])]),_v(" "),_c('p',[_v("Alternatively, if you are aware that many of your new commits will result in a conflict, it also be easier to squash them then rebase.")]),_v(" "),_c('p',[_v("Git ReReRe: "),_c('a',{attrs:{"href":"https://git-scm.com/docs/git-rerere"}},[_v("https://git-scm.com/docs/git-rerere")])]),_v(" "),_c('h3',{attrs:{"id":"additional-tips"}},[_v("Additional Tips"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#additional-tips","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ol',[_c('li',[_v("To pass additional flags to "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("npm run")]),_v(", you can use append "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("-- --")]),_v(". E.g "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("npm run test -- --detect-open-handles")])])])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/FergusMok/observations.html b/students/FergusMok/observations.html index 410c6a4f0..a78069d68 100644 --- a/students/FergusMok/observations.html +++ b/students/FergusMok/observations.html @@ -12,7 +12,7 @@ const baseUrl = '/2024' -

    Project: Litestar

    Litestar is a powerful, flexible yet opinionated ASGI framework, focused on building APIs, and offers high-performance data validation and parsing, dependency injection, first-class ORM integration, authorization primitives, and much more that's needed to get applications up and running.

    My Contributions

    1. Add reload-include and reload-exclude from uvicorn to CLI
    2. Fixing documentation bug
    3. Helped investigate a logging issue

    My Learning Record

    1. Project outreach

    Litestar's project outreach is one of the best that I've seen in any project. They are transparent about progress, and reach out to both users and contributers to encourage usage and contributions. Because Litestar is an ASGI framework that manages the majority of an application, it requires a large amount of effort and trust by users into the project.

    For example, they regularly post updates on the Python subreddit on major milestone and releases. Furthermore, they hold regular office hours live, and recordings are also posted on YouTube. Furthermore, they maintain a very large pool of "Good First Issues" for contributers to start on. As of writing, they have 20 such issues open.

    1. Project management

    Because Litestar is relatively new status compared to the very popular FastAPI, the maintainers have sought to prove the project's sustainability to their users.

    For example, in the past few years, one of the goals were to increase bus size, to a minimum of 5. They've since achieved this, and their project has been stronger than ever. This is in contrast to FastAPI, which infamously has only a single maintainer, who refuses to take on more maintainers or accept PRs.

    +

    Project: Litestar

    Litestar is a powerful, flexible yet opinionated ASGI framework, focused on building APIs, and offers high-performance data validation and parsing, dependency injection, first-class ORM integration, authorization primitives, and much more that's needed to get applications up and running.

    My Contributions

    1. Add reload-include and reload-exclude from uvicorn to CLI
    2. Fixing documentation bug
    3. Helped investigate a logging issue

    My Learning Record

    1. Project outreach

    Litestar's project outreach is one of the best that I've seen in any project. They are transparent about progress, and reach out to both users and contributers to encourage usage and contributions. Because Litestar is an ASGI framework that manages the majority of an application, it requires a large amount of effort and trust by users into the project.

    For example, they regularly post updates on the Python subreddit on major milestone and releases. Furthermore, they hold regular office hours live, and recordings are also posted on YouTube. Furthermore, they maintain a very large pool of "Good First Issues" for contributers to start on. As of writing, they have 20 such issues open.

    1. Project management

    Because Litestar is relatively new status compared to the very popular FastAPI, the maintainers have sought to prove the project's sustainability to their users.

    For example, in the past few years, one of the goals were to increase bus size, to a minimum of 5. They've since achieved this, and their project has been stronger than ever. This is in contrast to FastAPI, which infamously has only a single maintainer, who refuses to take on more maintainers or accept PRs.

    diff --git a/students/FergusMok/observations.page-vue-render.js b/students/FergusMok/observations.page-vue-render.js index 0d8d7e496..8cfe38078 100644 --- a/students/FergusMok/observations.page-vue-render.js +++ b/students/FergusMok/observations.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('h3',{attrs:{"id":"project-litestar"}},[_v("Project: Litestar"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#project-litestar","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Litestar is a powerful, flexible yet opinionated ASGI framework, focused on building APIs, and offers high-performance data validation and parsing, dependency injection, first-class ORM integration, authorization primitives, and much more that's needed to get applications up and running.")]),_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('ol',[_c('li',[_c('a',{attrs:{"href":"https://github.com/litestar-org/litestar/pull/2973"}},[_v("Add reload-include and reload-exclude from uvicorn to CLI")])]),_v(" "),_c('li',[_c('a',{attrs:{"href":"https://github.com/litestar-org/litestar/pull/2945"}},[_v("Fixing documentation bug")])]),_v(" "),_c('li',[_c('a',{attrs:{"href":"https://github.com/litestar-org/litestar/issues/2954#issuecomment-1886463991"}},[_v("Helped investigate a logging issue")])])]),_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('ol',[_c('li',[_v("Project outreach")])]),_v(" "),_c('p',[_v("Litestar's project outreach is one of the best that I've seen in any project. They are transparent about progress, and reach out to both users and contributers to encourage usage and contributions. Because Litestar is an ASGI framework that manages the majority of an application, it requires a large amount of effort and trust by users into the project.")]),_v(" "),_c('p',[_v("For example, they regularly post "),_c('a',{attrs:{"href":"https://www.reddit.com/r/Python/search/?q=litestar&"}},[_v("updates on the Python subreddit")]),_v(" on major milestone and releases. Furthermore, they hold regular office hours live, and "),_c('a',{attrs:{"href":"https://www.youtube.com/@LitestarOrg"}},[_v("recordings are also posted on YouTube")]),_v(". Furthermore, they maintain a very large pool of "),_c('a',{attrs:{"href":"https://github.com/litestar-org/litestar/issues?q=is%3Aopen+is%3Aissue+label%3A%22Good+First+Issue%22"}},[_v("\"Good First Issues\"")]),_v(" for contributers to start on. As of writing, they have 20 such issues open.")]),_v(" "),_c('ol',{attrs:{"start":"2"}},[_c('li',[_v("Project management")])]),_v(" "),_c('p',[_v("Because Litestar is relatively new status compared to the very popular FastAPI, the maintainers have sought to prove the project's sustainability to their users.")]),_v(" "),_c('p',[_v("For example, in the past few years, one of the goals were to increase bus size, to a minimum of 5. They've since achieved this, and their project has been stronger than ever. This is in contrast to FastAPI, which infamously has only a "),_c('a',{attrs:{"href":"https://github.com/tiangolo/fastapi/issues/4263"}},[_v("single maintainer")]),_v(", who refuses to take on more maintainers or accept PRs.")])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/FergusMok/progress.html b/students/FergusMok/progress.html index d318a0393..a2cfb9e1a 100644 --- a/students/FergusMok/progress.html +++ b/students/FergusMok/progress.html @@ -17,7 +17,7 @@
    • Creation of database and VPC to connect to the application
    • Updated the relevant documentation on teammates-ops
    • Created the relevant SQL commands for creating a non-superuser for production usage
    • Researched and setup the Hikari connection pool for Hibernate
  • Authored and reviewed PRs in the initial non-course migration
    • Researched and gave alternatives on the methods of migration (by application code or BigQuery on GCP)
    • Created the staging environment for non-course migration to test
  • Reviewed and gave suggestions for the Logs project
    • Primarily guided Di Sheng on some user considerations, overall design and review of PRs
  • Authored and reviewed PRs in course migration -
    • Mentored and reviewed the PRs and overall design for the mentee developers
  • Achievements by Week

    Week Achievements
    Before CS3282 Reviewed PR (merged): [#9976] Instructor copying course: Progress bar does not load when no feedback sessions are copied
    Before CS3282 Reviewed PR (merged): [#11639] Create DateTime service and replace time-related magic numbers
    Before CS3282 Reviewed PR (merged): [#11911] Instructor copying course: Progress bar does not load when no feedback sessions are copied
    2 - 3 Authored PR (merged): [#12048] Migrate SubmitFeedbackResponseAction's Logic and Db methods
    2 - 3 Reviewed PR (merged): [#12048] Migrate GetCourseJoinStatusAction
    2 - 3 Authored PR (merged): [#12048] Migrate SubmitFeedbackResponseAction
    2 - 3 Authored PR (closed): [#12048] Migrate OPTIMIZED_SAVING_POLICY_APPLIED for updateFeedbackResponseComment
    2 - 3 Authored PR (merged): [#12048] Migrate SubmitFeedbackResponseAction tests
    4 - 5 Authored PR (merged): [#12048] Add DataMigrationEntitiesBaseScriptSql and DataMigrationForAccountSql
    4 - 5 Authored PR (merged): [#12048] Add verify to seed db
    5 - 6 Reviewed PR (merged): [#12048] Create script to verify row count for non-course entities
    5 - 6 Reviewed PR (merged): [#12048] Add checks to notification script
    5 - 6 Authored PR (merged): [#12048] Improve base script for verifying migrated attributes
    7 Authored PR (merged): [#12048] Improve seeding and migration for non course entities
    7 Authored PR (merged): [#12048] V9 Migration: Fix verification pagination, improve logging
    7 Reviewed PR (merged): [#12048] Fix seeding for notification
    7 Reviewed PR (merged): [#12048] Fix seeding of data for data migration
    8 Reviewed PR (merged): [#12048] Add verification migration script
    8 Authored PR (merged): [#12048] V9 migration and verification script optimization
    8 Reviewed PR (merged): [#12048] V9 migration verification script optimisation - fetch ReadNotifications for account comparison
    8 Reviewed PR (merged): [#11843] Create FeedbackSessionLog entity and cron job action
    9 Authored PR (merged): [#12048] Add SQL configuration into build.properties and build-dev.properties
    9 Authored PR (merged): [#12048] Add SQL description for postgres config
    9 Reviewed PR (merged): [#12048] add delay to task queuer for indexing account request
    9 Reviewed PR (merged): [#12048] Relax read notif verification for migration verification script
    10 Authored PR (merged): [#12048] Config prod settings and convenience scripts for non course migration
    10 Reviewed PR (merged): [#11843] Create Logic and Db layer for FeedbackSessionLogs
    10 Reviewed PR (merged): [#12048] Rerunnable Account Request Migration Script
    10 Reviewed PR (merged): [#12048] Add reverse data migration script for account
    11 Authored PR (merged): [#12048] V9 non course migration for accounts not migrating
    11 Authored PR (merged): [#12048] V9 non course migration fix to check extra SQL accounts
    11 Authored PR (merged): [#12048] Configure connection pool using hikari
    11 Reviewed PR (merged): [#12048] configure agroal connection pool
    11 Reviewed PR (merged): [#12048] Fix account request indexing
    11 Reviewed PR (merged): Add patch data migration script for usage stats
    12 Reviewed PR (merged): [#12048] Data migration for feedback session entities
    12 Reviewed PR (merged): [#12048] Data migration for section entities
    12 Reviewed PR (merged): [#12048] Remove feedbackSession attributes @fetch annotation
    13 Reviewed PR (merged): [#11843] Update front end for session activity logs
    Reading Week Authored PR (merged): [#12048] Delete redundant index
    Reading Week Authored PR (merged): [#12048] Hot fix for migration
    Reading Week Authored PR (merged): [#12048] Prepare for migration testing
    Reading Week Authored PR (merged): [#12048] Add database changes and speed up seeding
    +
    • Mentored and reviewed the PRs and overall design for the mentee developers

    Achievements by Week

    Week Achievements
    Before CS3282 Reviewed PR (merged): [#9976] Instructor copying course: Progress bar does not load when no feedback sessions are copied
    Before CS3282 Reviewed PR (merged): [#11639] Create DateTime service and replace time-related magic numbers
    Before CS3282 Reviewed PR (merged): [#11911] Instructor copying course: Progress bar does not load when no feedback sessions are copied
    2 - 3 Authored PR (merged): [#12048] Migrate SubmitFeedbackResponseAction's Logic and Db methods
    2 - 3 Reviewed PR (merged): [#12048] Migrate GetCourseJoinStatusAction
    2 - 3 Authored PR (merged): [#12048] Migrate SubmitFeedbackResponseAction
    2 - 3 Authored PR (closed): [#12048] Migrate OPTIMIZED_SAVING_POLICY_APPLIED for updateFeedbackResponseComment
    2 - 3 Authored PR (merged): [#12048] Migrate SubmitFeedbackResponseAction tests
    4 - 5 Authored PR (merged): [#12048] Add DataMigrationEntitiesBaseScriptSql and DataMigrationForAccountSql
    4 - 5 Authored PR (merged): [#12048] Add verify to seed db
    5 - 6 Reviewed PR (merged): [#12048] Create script to verify row count for non-course entities
    5 - 6 Reviewed PR (merged): [#12048] Add checks to notification script
    5 - 6 Authored PR (merged): [#12048] Improve base script for verifying migrated attributes
    7 Authored PR (merged): [#12048] Improve seeding and migration for non course entities
    7 Authored PR (merged): [#12048] V9 Migration: Fix verification pagination, improve logging
    7 Reviewed PR (merged): [#12048] Fix seeding for notification
    7 Reviewed PR (merged): [#12048] Fix seeding of data for data migration
    8 Reviewed PR (merged): [#12048] Add verification migration script
    8 Authored PR (merged): [#12048] V9 migration and verification script optimization
    8 Reviewed PR (merged): [#12048] V9 migration verification script optimisation - fetch ReadNotifications for account comparison
    8 Reviewed PR (merged): [#11843] Create FeedbackSessionLog entity and cron job action
    9 Authored PR (merged): [#12048] Add SQL configuration into build.properties and build-dev.properties
    9 Authored PR (merged): [#12048] Add SQL description for postgres config
    9 Reviewed PR (merged): [#12048] add delay to task queuer for indexing account request
    9 Reviewed PR (merged): [#12048] Relax read notif verification for migration verification script
    10 Authored PR (merged): [#12048] Config prod settings and convenience scripts for non course migration
    10 Reviewed PR (merged): [#11843] Create Logic and Db layer for FeedbackSessionLogs
    10 Reviewed PR (merged): [#12048] Rerunnable Account Request Migration Script
    10 Reviewed PR (merged): [#12048] Add reverse data migration script for account
    11 Authored PR (merged): [#12048] V9 non course migration for accounts not migrating
    11 Authored PR (merged): [#12048] V9 non course migration fix to check extra SQL accounts
    11 Authored PR (merged): [#12048] Configure connection pool using hikari
    11 Reviewed PR (merged): [#12048] configure agroal connection pool
    11 Reviewed PR (merged): [#12048] Fix account request indexing
    11 Reviewed PR (merged): Add patch data migration script for usage stats
    12 Reviewed PR (merged): [#12048] Data migration for feedback session entities
    12 Reviewed PR (merged): [#12048] Data migration for section entities
    12 Reviewed PR (merged): [#12048] Remove feedbackSession attributes @fetch annotation
    13 Reviewed PR (merged): [#11843] Update front end for session activity logs
    Reading Week Authored PR (merged): [#12048] Delete redundant index
    Reading Week Authored PR (merged): [#12048] Hot fix for migration
    Reading Week Authored PR (merged): [#12048] Prepare for migration testing
    Reading Week Authored PR (merged): [#12048] Add database changes and speed up seeding
    diff --git a/students/FergusMok/progress.page-vue-render.js b/students/FergusMok/progress.page-vue-render.js index 890f025e5..a711bbb9c 100644 --- a/students/FergusMok/progress.page-vue-render.js +++ b/students/FergusMok/progress.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('h4',{attrs:{"id":"overview"}},[_v("Overview"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#overview","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ul',[_c('li',[_v("Aided in the migration of logic from NoSQL (Datastore) to SQL\n"),_c('ul',[_c('li',[_v("Migrated SubmitFeedbackResponseAction and it's relevant tests")]),_v(" "),_c('li',[_v("Reviewed other actions authored by others")])])]),_v(" "),_c('li',[_v("Took part in Multiple course structure initial discussions")]),_v(" "),_c('li',[_v("Researched and created the SQL setup on Google Cloud Platform\n"),_c('ul',[_c('li',[_v("Creation of database and VPC to connect to the application")]),_v(" "),_c('li',[_v("Updated the relevant documentation on teammates-ops")]),_v(" "),_c('li',[_v("Created the relevant SQL commands for creating a non-superuser for production usage")]),_v(" "),_c('li',[_v("Researched and setup the Hikari connection pool for Hibernate")])])]),_v(" "),_c('li',[_v("Authored and reviewed PRs in the initial non-course migration\n"),_c('ul',[_c('li',[_v("Researched and gave alternatives on the methods of migration (by application code or BigQuery on GCP)")]),_v(" "),_c('li',[_v("Created the staging environment for non-course migration to test")])])]),_v(" "),_c('li',[_v("Reviewed and gave suggestions for the Logs project\n"),_c('ul',[_c('li',[_v("Primarily guided Di Sheng on some user considerations, overall design and review of PRs")])])]),_v(" "),_c('li',[_v("Authored and reviewed PRs in course migration\n"),_c('ul',[_c('li',[_v("Mentored and reviewed the PRs and overall design for the mentee developers")])])])]),_v(" "),_c('h4',{attrs:{"id":"achievements-by-week"}},[_v("Achievements by Week"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#achievements-by-week","onclick":"event.stopPropagation()"}})]),_v(" "),_c('div',{staticClass:"table-responsive"},[_c('table',{staticClass:"markbind-table table table-bordered table-striped"},[_c('thead',[_c('tr',[_c('th',[_v("Week")]),_v(" "),_c('th',[_v("Achievements")])])]),_v(" "),_c('tbody',[_c('tr',[_c('td',[_v("Before CS3282")]),_v(" "),_c('td',[_v("Reviewed PR (merged): "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/11906"}},[_v("[#9976] Instructor copying course: Progress bar does not load when no feedback sessions are copied")])])]),_v(" "),_c('tr',[_c('td',[_v("Before CS3282")]),_v(" "),_c('td',[_v("Reviewed PR (merged): "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/11943"}},[_v("[#11639] Create DateTime service and replace time-related magic numbers")])])]),_v(" "),_c('tr',[_c('td',[_v("Before CS3282")]),_v(" "),_c('td',[_v("Reviewed PR (merged): "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/11914"}},[_v("[#11911] Instructor copying course: Progress bar does not load when no feedback sessions are copied")])])]),_v(" "),_c('tr',[_c('td',[_v("2 - 3")]),_v(" "),_c('td',[_v("Authored PR (merged): "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12732"}},[_v("[#12048] Migrate SubmitFeedbackResponseAction's Logic and Db methods")])])]),_v(" "),_c('tr',[_c('td',[_v("2 - 3")]),_v(" "),_c('td',[_v("Reviewed PR (merged): "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12713"}},[_v("[#12048] Migrate GetCourseJoinStatusAction")])])]),_v(" "),_c('tr',[_c('td',[_v("2 - 3")]),_v(" "),_c('td',[_v("Authored PR (merged): "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12720"}},[_v("[#12048] Migrate SubmitFeedbackResponseAction")])])]),_v(" "),_c('tr',[_c('td',[_v("2 - 3")]),_v(" "),_c('td',[_v("Authored PR (closed): "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12745"}},[_v("[#12048] Migrate OPTIMIZED_SAVING_POLICY_APPLIED for updateFeedbackResponseComment")])])]),_v(" "),_c('tr',[_c('td',[_v("2 - 3")]),_v(" "),_c('td',[_v("Authored PR (merged): "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13033"}},[_v("[#12048] Migrate SubmitFeedbackResponseAction tests ")])])]),_v(" "),_c('tr',[_c('td',[_v("4 - 5")]),_v(" "),_c('td',[_v("Authored PR (merged): "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12766"}},[_v("[#12048] Add DataMigrationEntitiesBaseScriptSql and DataMigrationForAccountSql")])])]),_v(" "),_c('tr',[_c('td',[_v("4 - 5")]),_v(" "),_c('td',[_v("Authored PR (merged): "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12767"}},[_v("[#12048] Add verify to seed db")])])]),_v(" "),_c('tr',[_c('td',[_v("5 - 6")]),_v(" "),_c('td',[_v("Reviewed PR (merged): "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12824"}},[_v("[#12048] Create script to verify row count for non-course entities")])])]),_v(" "),_c('tr',[_c('td',[_v("5 - 6")]),_v(" "),_c('td',[_v("Reviewed PR (merged): "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12836"}},[_v("[#12048] Add checks to notification script")])])]),_v(" "),_c('tr',[_c('td',[_v("5 - 6")]),_v(" "),_c('td',[_v("Authored PR (merged): "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12844"}},[_v("[#12048] Improve base script for verifying migrated attributes")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Authored PR (merged): "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12846"}},[_v("[#12048] Improve seeding and migration for non course entities")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Authored PR (merged): "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12874"}},[_v("[#12048] V9 Migration: Fix verification pagination, improve logging")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Reviewed PR (merged): "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12866"}},[_v("[#12048] Fix seeding for notification")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Reviewed PR (merged): "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12873"}},[_v("[#12048] Fix seeding of data for data migration")])])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_v("Reviewed PR (merged): "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12890"}},[_v("[#12048] Add verification migration script")])])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_v("Authored PR (merged): "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12896"}},[_v("[#12048] V9 migration and verification script optimization ")])])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_v("Reviewed PR (merged): "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12905"}},[_v("[#12048] V9 migration verification script optimisation - fetch ReadNotifications for account comparison")])])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_v("Reviewed PR (merged): "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12895"}},[_v("[#11843] Create FeedbackSessionLog entity and cron job action")])])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_v("Authored PR (merged): "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12917"}},[_v("[#12048] Add SQL configuration into build.properties and build-dev.properties")])])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_v("Authored PR (merged): "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12931"}},[_v("[#12048] Add SQL description for postgres config")])])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_v("Reviewed PR (merged): "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12936"}},[_v("[#12048] add delay to task queuer for indexing account request")])])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_v("Reviewed PR (merged): "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12937"}},[_v("[#12048] Relax read notif verification for migration verification script")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Authored PR (merged): "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12959"}},[_v("[#12048] Config prod settings and convenience scripts for non course migration")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Reviewed PR (merged): "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12914"}},[_v("[#11843] Create Logic and Db layer for FeedbackSessionLogs")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Reviewed PR (merged): "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12932"}},[_v("[#12048] Rerunnable Account Request Migration Script")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Reviewed PR (merged): "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12962"}},[_v("[#12048] Add reverse data migration script for account")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Authored PR (merged): "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12965"}},[_v("[#12048] V9 non course migration for accounts not migrating")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Authored PR (merged): "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12966"}},[_v("[#12048] V9 non course migration fix to check extra SQL accounts")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Authored PR (merged): "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12978"}},[_v("[#12048] Configure connection pool using hikari")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Reviewed PR (merged): "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12971"}},[_v("[#12048] configure agroal connection pool")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Reviewed PR (merged): "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12967"}},[_v("[#12048] Fix account request indexing")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Reviewed PR (merged): "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12970"}},[_v("Add patch data migration script for usage stats")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Reviewed PR (merged): "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12986"}},[_v("[#12048] Data migration for feedback session entities")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Reviewed PR (merged): "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12991"}},[_v("[#12048] Data migration for section entities")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Reviewed PR (merged): "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12992"}},[_v("[#12048] Remove feedbackSession attributes @fetch annotation")])])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_v("Reviewed PR (merged): "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12973"}},[_v(" [#11843] Update front end for session activity logs")])])]),_v(" "),_c('tr',[_c('td',[_v("Reading Week")]),_v(" "),_c('td',[_v("Authored PR (merged): "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13095"}},[_v(" [#12048] Delete redundant index ")])])]),_v(" "),_c('tr',[_c('td',[_v("Reading Week")]),_v(" "),_c('td',[_v("Authored PR (merged): "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13092"}},[_v(" [#12048] Hot fix for migration")])])]),_v(" "),_c('tr',[_c('td',[_v("Reading Week")]),_v(" "),_c('td',[_v("Authored PR (merged): "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13089"}},[_v(" [#12048] Prepare for migration testing")])])]),_v(" "),_c('tr',[_c('td',[_v("Reading Week")]),_v(" "),_c('td',[_v("Authored PR (merged): "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13085"}},[_v(" [#12048] Add database changes and speed up seeding")])])])])])])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/KevinEyo1/info.html b/students/KevinEyo1/info.html index 7b82072fa..651445015 100644 --- a/students/KevinEyo1/info.html +++ b/students/KevinEyo1/info.html @@ -12,7 +12,7 @@ const baseUrl = '/2024' - + diff --git a/students/KevinEyo1/info.page-vue-render.js b/students/KevinEyo1/info.page-vue-render.js index cb0715b77..4c2d906a0 100644 --- a/students/KevinEyo1/info.page-vue-render.js +++ b/students/KevinEyo1/info.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('p',[_c('span',{attrs:{"id":"github"}},[_c('a',{attrs:{"href":"https://www.github.com/KevinEyo1"}},[_v("https://www.github.com/KevinEyo1")])])]),_v(" "),_c('p',[_c('span',{attrs:{"id":"projects"}},[_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind"}},[_v("MarkBind")])])])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/KevinEyo1/knowledge.html b/students/KevinEyo1/knowledge.html index adf9cd773..4c50272de 100644 --- a/students/KevinEyo1/knowledge.html +++ b/students/KevinEyo1/knowledge.html @@ -67,7 +67,7 @@

    Use OIDC and respective Secrets Manager for access to cloud providers instead of using secrets. Use GitHub Secrets to store keys securely and reference in workflows using ${{}}. Can use GitGuardian Shield to help with scanning for security vulnerabilities.

    Typescript

    Typescript is a superset of JavaScript that adds static typing to the language. By manipulating variables and functions, Typescript can help catch errors before they occur.

    Syntax Name Feature
    ? Optional chaining operator variable returns undefined if doesn't exist. Also used for optional function parameters or class properties
    ?? Nullish coalescing operator returns the right-hand operand when the left-hand operand is null or undefined.
    ! Non-null assertion operator variable is not null or undefined, only used if you are sure that value will exist.

    Process of upgrading dependencies and packages

    MarkBind uses a monorepo structure, which means that multiple packages are contained in a single repository. -The process of upgrading dependencies and packages in MarkBind involves the following steps:

    1. Checking current versions: Check the current versions of the dependencies and packages in the project. This can be done by looking at the package.json file for each project. The command npm ls package_name will output which packages are using what versions.

    2. Review changelog and documentation: Review the changelog and documentation for the dependencies and packages to see what changes have been made in the new versions.

    3. Upgrade dependencies and packages: Update the relevant package.json file or the root one for dependencies across all packages, then run npm run setup

    +The process of upgrading dependencies and packages in MarkBind involves the following steps:

    1. Checking current versions: Check the current versions of the dependencies and packages in the project. This can be done by looking at the package.json file for each project. The command npm ls package_name will output which packages are using what versions.

    2. Review changelog and documentation: Review the changelog and documentation for the dependencies and packages to see what changes have been made in the new versions.

    3. Upgrade dependencies and packages: Update the relevant package.json file or the root one for dependencies across all packages, then run npm run setup

    diff --git a/students/KevinEyo1/knowledge.page-vue-render.js b/students/KevinEyo1/knowledge.page-vue-render.js index 5f8dc5d65..771ad4adb 100644 --- a/students/KevinEyo1/knowledge.page-vue-render.js +++ b/students/KevinEyo1/knowledge.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('h3',{attrs:{"id":"summary-of-key-contributions"}},[_v("Summary of Key Contributions"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#summary-of-key-contributions","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Worked on adding "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2400"}},[_v("Software Project Documentation")]),_v(" template to MarkBind, allowing for users to have a starting point for using MarkBind in their project documentation.")]),_v(" "),_c('p',[_v("Researched into possible integrations of "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2448"}},[_v("Bun")]),_v(" and "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2359"}},[_v("Bootstrap v5.2 and v5.3")]),_v(" into MarkBind, to determine the value and feasibility of these integrations.")]),_v(" "),_c('p',[_v("Worked on "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2454"}},[_v("customizing list icons")]),_v(", such that icons for list items can be customized to apply to the current item only instead of default inheritance to future items.")]),_v(" "),_c('p',[_v("Worked largely on DevOps side of MarkBind, utilizing GitHub Actions and workflows to handle automation of tasks. These tasks include checking for "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2429"}},[_v("commit messages in PR descriptions")]),_v(", "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2470"}},[_v("SEMVER impact labels")]),_v(", "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2484"}},[_v("reminding adding of new contributors to contributor list")]),_v(".")]),_v(" "),_c('p',[_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2140"}},[_v("Researched")]),_v(" and "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2523"}},[_v("implemented")]),_v(" the use of DangerJS to automate checking of changes coupling of implementation files to test or documentation files, to ensure that any changes to the repository is properly documented and tested.")]),_v(" "),_c('p',[_v("Researched into the implementation of automating "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2495"}},[_v("unassigning of assigned users to issues")]),_v(" after a certain period of inactivity.")]),_v(" "),_c('p',[_v("Researched into "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2488"}},[_v("common security practices")]),_v(" for GitHub Actions, and "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2510"}},[_v("implementing these practices")]),_v(" into the MarkBind repository. These practices are also "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2528"}},[_v("documented")]),_v(" for future contributors to the project.")]),_v(" "),_c('h3',{attrs:{"id":"markbind-codebase"}},[_v("MarkBind codebase"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#markbind-codebase","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Learned the underlying workings and how different parts of the codebase are linked together to provide MarkBind's functionalities. From the parser to the renderer, and the different plugins that can be used to extend MarkBind's capabilities. Learned how to implement new features, adding relevant test and documentation to ensure that the codebase is maintainable and modifiable.")]),_v(" "),_c('h3',{attrs:{"id":"github-actions"}},[_v("GitHub Actions"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#github-actions","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Learned how GitHub Actions fits into the development workflow, and how to use it to automate tasks. I used the GitHub Actions documentation to learn about the different types of workflows, how to create and configure workflows, and how to use the different actions available.")]),_v(" "),_c('ul',[_c('li',[_c('p',[_c('strong',[_v("Resource")]),_v(": "),_c('a',{attrs:{"href":"https://docs.github.com/en/actions"}},[_v("GitHub Actions Documentation")])])]),_v(" "),_c('li',[_c('p',[_c('strong',[_v("Summary")]),_v(": GitHub Actions makes it easy to automate all your software workflows, now with world-class CI/CD. Build, test, and deploy your code right from GitHub. Make code reviews, branch management, and issue triaging work the way you want.")])]),_v(" "),_c('li',[_c('p',[_c('strong',[_v("Resource")]),_v(": "),_c('a',{attrs:{"href":"https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions"}},[_v("GitHub Actions Workflow Syntax")])])]),_v(" "),_c('li',[_c('p',[_c('strong',[_v("Summary")]),_v(": GitHub Actions uses YAML syntax to define the events, jobs, and steps that make up your workflow. You can create a custom workflow or use a starter workflow template to get started.")])]),_v(" "),_c('li',[_c('p',[_c('strong',[_v("Resource")]),_v(": "),_c('a',{attrs:{"href":"https://docs.github.com/en/actions/security-guides/automatic-token-authentication"}},[_v("GITHUB_TOKEN")])])]),_v(" "),_c('li',[_c('p',[_c('strong',[_v("Summary")]),_v(": The GITHUB_TOKEN is a GitHub Actions token that is automatically generated by GitHub and used to authenticate in a workflow run. It is scoped to the repository that contains the workflow file, and can be used to perform read and write operations on the repository. It is automatically available to your workflow and does not need to be stored as a secret.")])])]),_v(" "),_c('p',[_v("Learned yaml and bash for creation of workflows.")]),_v(" "),_c('ul',[_c('li',[_c('p',[_c('strong',[_v("Resource")]),_v(": "),_c('a',{attrs:{"href":"https://www.cloudbees.com/blog/yaml-tutorial-everything-you-need-get-started"}},[_v("YAML Syntax")])])]),_v(" "),_c('li',[_c('p',[_c('strong',[_v("Summary")]),_v(": YAML is a human-readable data serialization standard that can be used in conjunction with all programming languages and is often used to write configuration files. It can also be used in workflows to define the structure of the workflow, including the events, jobs, and steps that make up the workflow.")])]),_v(" "),_c('li',[_c('p',[_c('strong',[_v("Resource")]),_v(": "),_c('a',{attrs:{"href":"https://devhints.io/bash"}},[_v("Bash Scripting")])])]),_v(" "),_c('li',[_c('p',[_c('strong',[_v("Summary")]),_v(": Bash is a Unix shell and command language written by Brian Fox for the GNU Project as a free software replacement for the Bourne shell. It has been distributed widely as the shell for the GNU operating system and as a default shell on Linux and OS X.")])]),_v(" "),_c('li',[_c('p',[_c('strong',[_v("Resource")]),_v(": "),_c('a',{attrs:{"href":"https://web.archive.org/web/20230408142504/https://wiki.bash-hackers.org/syntax/pe"}},[_v("Bash Parameter Expansion")])])]),_v(" "),_c('li',[_c('p',[_c('strong',[_v("Summary")]),_v(": Parameter expansion is a way to manipulate variables in Bash. It is a form of variable substitution that allows for the manipulation of variables in various ways.")])])]),_v(" "),_c('p',[_v("Learned how to use other actions in workflows, such as the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("actions/checkout")]),_v(" action to check out a repository onto the runner, allowing subsequent steps to execute operations on the checked-out repository.")]),_v(" "),_c('ul',[_c('li',[_c('strong',[_v("Resource")]),_v(": "),_c('a',{attrs:{"href":"https://github.com/marketplace"}},[_v("GitHub Marketplace")])]),_v(" "),_c('li',[_c('strong',[_v("Summary")]),_v(": The GitHub Marketplace is a collection of actions that can be used in your workflows. You can search for actions by category, language, or other criteria, and use them in your workflows to automate tasks.")])]),_v(" "),_c('p',[_v("Learned how to use DangerJS to aid with workflows.")]),_v(" "),_c('ul',[_c('li',[_c('strong',[_v("Resource")]),_v(": "),_c('a',{attrs:{"href":"https://danger.systems/js/"}},[_v("DangerJS")])]),_v(" "),_c('li',[_c('strong',[_v("Summary")]),_v(": Danger runs during your CI process, and helps with automating common code review chores. This provides another layer of automation over the code review process, ensuring that all changes are properly documented and tested.")])]),_v(" "),_c('p',[_c('strong',[_v("When to create new workflows (outside of modifiability)")]),_v("\nAlthough keeping multiple jobs within the same workflow file is possible, sometimes it may be better not to. Jobs are run based on event triggers such as pull requests etc, but you must add it to the top. This meant that if you had multiple jobs in the same workflow file, they would all run when the event trigger was activated. If you wanted a trigger to only trigger a specific job, you would need to add a check to exclude all other jobs from that trigger.")]),_v(" "),_c('p',[_v("Pull request trigger by default has the types "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("opened")]),_v(", "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("synchronize")]),_v(", and "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("reopened")]),_v(".")]),_v(" "),_c('p',[_c('strong',[_v("Testing and debugging workflows")]),_v("\nThis can be done locally with the help of Docker and act.")]),_v(" "),_c('p',[_v("Benefits of local testing:\nFast Feedback - Avoid commit/push every time you want to test out the changes.")]),_v(" "),_c('ul',[_c('li',[_c('p',[_c('strong',[_v("Resource")]),_v(": "),_c('a',{attrs:{"href":"https://nektosact.com/usage/index.html"}},[_v("Act Usage")])])]),_v(" "),_c('li',[_c('p',[_c('strong',[_v("Summary")]),_v(": Act reads in your GitHub Actions from .github/workflows/ and determines the set of actions that need to be run. It uses the Docker API to either pull or build the necessary images, as defined in your workflow files and finally determines the execution path based on the dependencies that were defined. Once it has the execution path, it then uses the Docker API to run containers for each action based on the images prepared earlier.")])]),_v(" "),_c('li',[_c('p',[_c('strong',[_v("Resource")]),_v(": "),_c('a',{attrs:{"href":"https://docs.docker.com/get-started/overview/"}},[_v("Docker Docs")])])]),_v(" "),_c('li',[_c('p',[_c('strong',[_v("Summary")]),_v(":")])])]),_v(" "),_c('p',[_v("Steps (PR):")]),_v(" "),_c('ol',[_c('li',[_v("Download act and Docker.")]),_v(" "),_c('li',[_v("Start up Docker daemon.")]),_v(" "),_c('li',[_v("Create a JSON file with the appropriate PR file structure (can use python script to generate it).")]),_v(" "),_c('li',[_v("Run "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("act pull_request -j specific-job -e pr-event.json")]),_v(" to run a specific job on the PR event environment.")])]),_v(" "),_c('h4',{attrs:{"id":"keywords"}},[_v("Keywords"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#keywords","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("uses")]),_v(":\nCan be used to reference an action in the same repository, a public repository, or a published Docker container image. The "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("uses")]),_v(" keyword can also be used to reference an action in a private repository by specifying the repository using the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("repository")]),_v(" keyword.")]),_v(" "),_c('p',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("env")]),_v(":\nIt is best to avoid having expressions "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("${{ }}")]),_v(" in "),_c('em',[_v("run")]),_v(" portion of a step. Instead, "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("env")]),_v(" allows defining of variables that store the expression.")]),_v(" "),_c('p',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("awk")]),_v(" :\nCan be used to extract a section of body, from a line containing "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("START")]),_v(" to a line containing "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("END")]),_v(" (inclusive of full line).\n"),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("section=$(echo \"$body\" | awk '/START/,/END/')")])]),_v(" "),_c('h4',{attrs:{"id":"use-of-third-party-actions"}},[_v("Use of third-party actions"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#use-of-third-party-actions","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ul',[_c('li',[_c('strong',[_v("Resource")]),_v(": "),_c('a',{attrs:{"href":"https://github.com/marketplace?type=actions"}},[_v("GitHub Actions Marketplace")])]),_v(" "),_c('li',[_c('strong',[_v("Summary")]),_v(": The GitHub Actions Marketplace is a collection of actions that can be used in your workflows. You can search for actions by category, language, or other criteria, and use them in your workflows to automate tasks.")])]),_v(" "),_c('p',[_v("Useful actions:")]),_v(" "),_c('div',{staticClass:"table-responsive"},[_c('table',{staticClass:"markbind-table table table-bordered table-striped"},[_c('thead',[_c('tr',[_c('th',[_v("Action")]),_v(" "),_c('th',[_v("Description")])])]),_v(" "),_c('tbody',[_c('tr',[_c('td',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("actions/checkout@v3")])]),_v(" "),_c('td',[_v("Check out a repository onto the runner, allowing subsequent steps to execute operations on the checked-out repository, i.e. gaining access to the repository's code.")])]),_v(" "),_c('tr',[_c('td',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("actions/github-script@v7")])]),_v(" "),_c('td',[_v("Run a script in the GitHub Actions environment using the GitHub CLI. Refer to "),_c('a',{attrs:{"href":"https://octokit.github.io/rest.js/v20"}},[_v("here")])])]),_v(" "),_c('tr',[_c('td',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("actions/setup-node@v3")])]),_v(" "),_c('td',[_v("Set up a Node.js environment for use in workflows.")])]),_v(" "),_c('tr',[_c('td',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("actions/stale")])]),_v(" "),_c('td',[_v("Close stale issues and pull requests.")])]),_v(" "),_c('tr',[_c('td',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("boundfoxstudios/action-unassign-contributor-after-days-of-inactivity")])]),_v(" "),_c('td',[_v("Automatically unassign user from issues after a certain period of inactivity.")])])])])]),_c('h4',{attrs:{"id":"extra-information-about-how-stale-and-unassign-actions-work-in-the-context-of-markbind"}},[_v("Extra information about how stale and unassign actions work in the context of MarkBind"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#extra-information-about-how-stale-and-unassign-actions-work-in-the-context-of-markbind","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("The definition of inactivity for the GitHub action is any form of history to the issue, be it labeling, comments or references. The action works such that issues and PRs are treated and checked for inactivity separately. This means that any updates done to a PR regarding this issue, will not reset inactivity for the issue.")]),_v(" "),_c('p',[_v("How unassign and stale actions work:")]),_v(" "),_c('ol',[_c('li',[_v("Stale action adds "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Stale")]),_v(" label to issue or PR based on inactivity (default 60 days)")]),_v(" "),_c('li',[_v("Unassign action routinely checks for this "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Stale")]),_v(" label, then checks whether it's been a set amount of days after the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Stale")]),_v(" label has been added with no other activity (default 7 days)")]),_v(" "),_c('li',[_v("For issues passing the check before, it un-assigns users and removes "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Stale")]),_v(" label")])]),_v(" "),_c('p',[_c('a',{attrs:{"href":"https://github.com/BoundfoxStudios/fairy-tale-defender/blob/develop/.github/workflows/project-management.yml#L105"}},[_v("Reference workflow of real-life example")])]),_v(" "),_c('h5',{attrs:{"id":"solution-using-unassign-and-stale-actions"}},[_v("Solution using unassign and stale actions"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#solution-using-unassign-and-stale-actions","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Add the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Stale")]),_v(" label after 6 days and ping a reminder, then have the "),_c('a',{attrs:{"href":"https://github.com/marketplace/actions/unassign-contributor-after-days-of-inactivity"}},[_v("unassign-contributor-after-days-of-inactivity")]),_v(" run 1 day after.\nIt can also only check on issues that are actually assigned to someone, so that theres no redundancy.\n"),_c('strong',[_v("Limitations:")])]),_v(" "),_c('ol',[_c('li',[_v("Any changes in PR regarding issue will not reset inactivity of issue, meaning if discussion and updates are done on the PR instead of the issue, the issue risks being "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Stale")]),_v(" and the user being unassigned despite them actively working on the PR.")]),_v(" "),_c('li',[_v("It can ping a general reminder (without resetting the inactivity) but it cannot ping the user directly with "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("@username")]),_v(" in the reminder due to how the code is written. It is possible to separately ping the user in another comment but that will cause a reset in inactivity. This means slightly lower visibility for the reminder.")])]),_v(" "),_c('h5',{attrs:{"id":"improvements-for-limitation-1"}},[_v("Improvements for limitation 1"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#improvements-for-limitation-1","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Building on unassign action, which at some point it might be better off just building our own unassign action for better integration and control\n"),_c('strong',[_v("Check corresponding PR (requires more implementation)")]),_v("\nAdd additional check before setting "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Stale")]),_v(" label to check if corresponding PR has history.\nThis can be done through checking the list of open PRs and their descriptions whether it mentions the issue. It can also be done through looking at the issue’s history, for PRs that mention it, then checking the history of those PRs. This should be quite manageable since the number of open PRs at any point of time is still relatively low for Markbind’s scale.")]),_v(" "),_c('p',[_c('strong',[_v("Check corresponding issue (requires more implementation)")]),_v("\nOn any activity in PRs, check description to find issues linked to the PR, so activity on PR can be translated to activity on the issue as well by posting a comment on the corresponding issue or something of that nature. This might require checking for a specific issue that has the user assigned to avoid commenting on relevant but not directly linked issues, if the PR has multiple relevant issues. We can also only call it on commits instead of any activity, so as to avoid over-polluting the issue with comments.")]),_v(" "),_c('h5',{attrs:{"id":"improvements-for-limitation-2"}},[_v("Improvements for limitation 2"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#improvements-for-limitation-2","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_c('strong',[_v("Ping after unassign")]),_v("\nSame as before, add "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Stale")]),_v(" level after 6 days, but don't need to ping the user, wait until unassign 1 day after, then ping the user that they have been unassigned and if they are still working on it, ask them to reassign themselves. This would likely fit better with a longer timeline.\nThis solves the visibility problem as it can directly ping the user as resetting the inactivity after the user has been unassigned wouldn't matter.")]),_v(" "),_c('p',[_c('strong',[_v("Implement our own stale action (requires more implementation)")]),_v("\nImplement a simplified version of stale action that now allows pinging of user before applying the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Stale")]),_v(" label.")]),_v(" "),_c('h4',{attrs:{"id":"pull-request-target"}},[_v("pull_request_target"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#pull-request-target","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Due to security reasons, for permissions given to "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("GITHUB_TOKEN")]),_v(", the maximum access for pull requests from public forked repositories is restricted to only read, so it is not possible to add labels since there is no write access. GitHub introduced the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("pull_request_target")]),_v(" event that will bypass this restriction and give the token write access.\nPros:")]),_v(" "),_c('ol',[_c('li',[_v("It allows labelling of PR")]),_v(" "),_c('li',[_v("Increased security as base branch workflows can be trusted, protecting job from running modified and malicious workflows\nCons:")]),_v(" "),_c('li',[_v("It can only run on "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("pull_request")]),_v(" events and not "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("pull_request_review")]),_v(" events which means need to run on PR merge rather than on PR approved.")]),_v(" "),_c('li',[_v("This event runs in the context of the base of the pull request, rather than in the context of the merge commit, as the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("pull_request")]),_v(" event does. This could lead to security vulnerabilities if scripts run are not properly checked for malicious code.\nCan be aided by seeking approval before running the job, refer to "),_c('a',{attrs:{"href":"https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/enabling-features-for-your-repository/managing-github-actions-settings-for-a-repository#controlling-changes-from-forks-to-workflows-in-public-repositories"}},[_v("change repo settings")])])]),_v(" "),_c('h5',{attrs:{"id":"alternative-implementations"}},[_v("Alternative implementations"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#alternative-implementations","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_c('a',{attrs:{"href":"https://stackoverflow.com/questions/67247752/how-to-use-secret-in-pull-request-review-similar-to-pull-request-target"}},[_v("Workaround")]),_v("\nPros: this can allow for still triggering on PR approved\nCons: immensely complicates the workflow")]),_v(" "),_c('p',[_v("Personal Access Token (PAT)\nCreate a PAT with the necessary permissions and add it to your repository's secrets. Then, modify the workflow to use this secret instead of the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("GITHUB_TOKEN")]),_v(".\nPros: this can allow for still triggering on PR approved\nCons: exposes your repository to risks if the forked code can access the token")]),_v(" "),_c('h3',{attrs:{"id":"github-actions-security"}},[_v("GitHub Actions Security"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#github-actions-security","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ul',[_c('li',[_c('strong',[_v("Resource")]),_v(": "),_c('a',{attrs:{"href":"https://dev.to/suzukishunsuke/secure-github-actions-by-pullrequesttarget-641"}},[_v("Using pull_request_target")])]),_v(" "),_c('li',[_c('strong',[_v("Resource")]),_v(": "),_c('a',{attrs:{"href":"https://blog.gitguardian.com/github-actions-security-cheat-sheet/"}},[_v("Security and Cheatsheet")])]),_v(" "),_c('li',[_c('strong',[_v("Resource")]),_v(": "),_c('a',{attrs:{"href":"https://securitylab.github.com/research/github-actions-preventing-pwn-requests/"}},[_v("Security Lab")])])]),_v(" "),_c('p',[_c('strong',[_v("Specific version tags")]),_v("\nWhen using third-party actions, pin the version with a commit hash rather than a tag to shield your workflow from potential supply-chain compromise, since tags can be adjusted to a malicious codebase state but commit hashes provide immutability.\nThis can be done by going to the codebase for the specific tag version and looking for the latest commit of the version desired and copying the commit’s full SHA from the url link.\nUse:\n"),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("uses: someperson/post-issue@f054a8b5c1271c37293245628f1cae047eff08c9")]),_v("\nInstead of:\n"),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("uses: someperson/post-issue@v7")]),_v("\nDownside is that the updates must be done by updating the commit hash instead of it being done automatically through moving the tag to a new release.\nThis can be solved by using tools like Dependabot or Renovatebot by adding a comment of the version used, enabling automated dependency updates. Tools like StepSecurity can also be used.")]),_v(" "),_c('p',[_c('strong',[_v("Minimally scoped credentials")]),_v("\nEvery credential used in the workflow should have the minimum required permissions to execute the job.\nIn particular, use the ‘permissions’ key to make sure the GITHUB_TOKEN is configured with the least privileges for each job.\n"),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("permissions")]),_v(" can be restricted at the repo, workflow or job level.\n"),_c('strong',[_v("Environment variables")]),_v(", like "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("${{ secrets.GITHUB_TOKEN }}")]),_v(", should be limited by scope, and should be declared at the step level when possible.")]),_v(" "),_c('p',[_c('strong',[_v("Pull_request_target")]),_v(" (must be used for write access if PR is from forked repo)\nDo not use actions/checkout with this as it can give write permission and secrets access to untrusted code. Any building step, script execution, or even action call could be used to compromise the entire repository. This can be fixed by adding code to ensure that the code being checked out belongs to the base branch, which would also be limiting since the code checked out is not up to date for the PR.\nThis can be done using:")]),_v(" "),_c('pre',[_c('code',{pre:true,attrs:{"class":"hljs"}},[_c('span',[_v("- uses: actions/checkout@v4\n")]),_c('span',[_v(" with:\n")]),_c('span',[_v(" ref: $ \n")])])]),_c('p',[_v("Triggers workflows based on the latest commit of the pull request's base branch.\nEven if workflow files are modified or deleted on feature branches, workflows on the default branch aren't affected so you can prevent malicious code from being executed in CI without code review.\nAnother solution that allows "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("pull_request_target")]),_v(" with "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("actions/checkout")]),_v(" used on the PR branch, is to add an additional step of running workflow only on approval by trusted users, such that the trusted user has to check the changes in the code from the PR to ensure there is no malicious code before running the workflow.")]),_v(" "),_c('p',[_c('strong',[_v("Untrusted input")]),_v("\nDon't directly reference values you do not control, such as "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("echo “${{github.event.pull_request.title}}”")]),_v(", since it can contain malicious code and lead to an injection attack.\nInstead use an action with arguments (recommended):")]),_v(" "),_c('pre',[_c('code',{pre:true,attrs:{"class":"hljs"}},[_c('span',[_v("uses: fakeaction/printtitle@v3 \n")]),_c('span',[_v("with: \n")]),_c('span',[_v("title: $\n")])])]),_c('p',[_v("Or bind the value to an intermediate environment variable:")]),_v(" "),_c('pre',[_c('code',{pre:true,attrs:{"class":"hljs"}},[_c('span',[_v("env: \n")]),_c('span',[_v("PR_TITLE: $\n")]),_c('span',[_v("run: | \n")]),_c('span',[_v("echo “$PR_TITLE” \n")])])]),_c('p',[_v("Use "),_c('a',{attrs:{"href":"https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect"}},[_c('strong',[_v("OIDC")])]),_v(" and respective Secrets Manager for access to cloud providers instead of using secrets.\nUse "),_c('a',{attrs:{"href":"https://docs.github.com/en/actions/security-guides/using-secrets-in-github-actions"}},[_c('strong',[_v("GitHub Secrets")])]),_v(" to store keys securely and reference in workflows using "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("${{}}")]),_v(".\nCan use "),_c('a',{attrs:{"href":"https://github.com/GitGuardian/ggshield-action?ref=blog.gitguardian.com"}},[_c('strong',[_v("GitGuardian Shield")])]),_v(" to help with scanning for security vulnerabilities.")]),_v(" "),_c('h3',{attrs:{"id":"typescript"}},[_v("Typescript"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#typescript","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Typescript is a superset of JavaScript that adds static typing to the language. By manipulating variables and functions, Typescript can help catch errors before they occur.")]),_v(" "),_c('div',{staticClass:"table-responsive"},[_c('table',{staticClass:"markbind-table table table-bordered table-striped"},[_c('thead',[_c('tr',[_c('th',[_v("Syntax")]),_v(" "),_c('th',[_v("Name")]),_v(" "),_c('th',[_v("Feature")])])]),_v(" "),_c('tbody',[_c('tr',[_c('td',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("?")])]),_v(" "),_c('td',[_v("Optional chaining operator")]),_v(" "),_c('td',[_v("variable returns undefined if doesn't exist. Also used for optional function parameters or class properties")])]),_v(" "),_c('tr',[_c('td',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("??")])]),_v(" "),_c('td',[_v("Nullish coalescing operator")]),_v(" "),_c('td',[_v("returns the right-hand operand when the left-hand operand is null or undefined.")])]),_v(" "),_c('tr',[_c('td',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("!")])]),_v(" "),_c('td',[_v("Non-null assertion operator")]),_v(" "),_c('td',[_v("variable is not null or undefined, only used if you are sure that value will exist.")])])])])]),_c('h3',{attrs:{"id":"process-of-upgrading-dependencies-and-packages"}},[_v("Process of upgrading dependencies and packages"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#process-of-upgrading-dependencies-and-packages","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("MarkBind uses a monorepo structure, which means that multiple packages are contained in a single repository.\nThe process of upgrading dependencies and packages in MarkBind involves the following steps:")]),_v(" "),_c('ol',[_c('li',[_c('p',[_c('strong',[_v("Checking current versions")]),_v(": Check the current versions of the dependencies and packages in the project. This can be done by looking at the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("package.json")]),_v(" file for each project. The command "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("npm ls package_name")]),_v(" will output which packages are using what versions.")])]),_v(" "),_c('li',[_c('p',[_c('strong',[_v("Review changelog and documentation")]),_v(": Review the changelog and documentation for the dependencies and packages to see what changes have been made in the new versions.")])]),_v(" "),_c('li',[_c('p',[_c('strong',[_v("Upgrade dependencies and packages")]),_v(": Update the relevant "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("package.json")]),_v(" file or the root one for dependencies across all packages, then run "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("npm run setup")])])])])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/KevinEyo1/progress.html b/students/KevinEyo1/progress.html index 4ea0a3408..97506dc27 100644 --- a/students/KevinEyo1/progress.html +++ b/students/KevinEyo1/progress.html @@ -12,7 +12,7 @@ const baseUrl = '/2024' -

    MarkBind

    Week Achievements
    2 Authored PR: MarkBind Template for Software Project Documentation#2400
    4 Authored PR: Enhance search performance of algolia plugin #2406
    5 Merged PR: Enhance search performance of algolia plugin #2406
    6 Authored PR: Utilize GitHub Actions to aid checking of commit message #2429
    6 Merged PR: Utilize GitHub Actions to aid checking of commit message #2429
    6 Authored PR: Upgrade simple-git version #2439
    6 Merged PR: Upgrade simple-git version #2439
    6 Authored PR: UG > PagNav: Misleading sentence #2440
    7 Merged PR: UG > PagNav: Misleading sentence #2440
    7 Submitted Issue: Fancylists to package MarkBind's current and future list features #2458
    8 Authored PR: Customizing list icons: give a way to apply to current item only #2454
    8 Submitted Issue: Utilize GitHub Actions to check for SEMVER impact label #2464
    8 Authored PR: Utilize GitHub Actions to check for SEMVER impact label #2464
    8 Researched Issue: Bootstrap migration tracker #2359
    9 Reviewed PR: MarkBind Template for Student Portfolio #2398
    9 Researched Issue: [Feature request] Tag (keywortd) support #2187
    10 Researched Issue: Utilize GitHub Actions to check for SEMVER impact label #2464
    10 Merged PR: Utilize GitHub Actions to check for SEMVER impact label #2464
    10 Submitted Issue: Reusable workflow repo for all repos under organisation #2479
    10 Merged PR: MarkBind Template for Software Project Documentation#2400
    10 Authored PR: Add a reminder when contributor is new to ping all contributor bot #2484
    11 Submitted Issue: Improve security of GitHub Actions workflows #2488
    11 Researched Issue: Improve security of GitHub Actions workflows #2488
    11 Researched Issue: Explore using Bun for testing and setup #2448
    11 Merged PR: Customizing list icons: give a way to apply to current item only #2454
    11 Researched Issue: Utilize GitHub Action to aid PR review #2140
    12 Authored PR: Improve security of GitHub Actions workflows #2510
    12 Authored PR: UG: images appear in two places #2514
    12 Merged PR: Add a reminder when contributor is new to ping all contributor bot #2484
    12 Merged PR: Improve security of GitHub Actions workflows #2510
    12 Researched Issue: Add github action to automatically unassign issues after a certain period of inactivity #2495
    12 Merged PR: UG: images appear in two places #2514
    13 Authored PR: Fix workflow file deploy-docs #2521
    13 Merged PR: Fix workflow file deploy-docs #2521
    13 Researched Issue: Add github action to automatically unassign issues after a certain period of inactivity #2495
    13 Authored PR: Using DangerJS to check changes coupling of implementation files to test or documentation files #2523
    13 Submitted Issue: Add documentation for workflow security for GitHub Actions #2527
    13 Authored PR: Add documentation regarding security practices for github actions #2528
    13 Merged PR: Using DangerJS to check changes coupling of implementation files to test or documentation files #2523
    13 Merged PR: Add documentation regarding security practices for github actions #2528
    +

    MarkBind

    Week Achievements
    2 Authored PR: MarkBind Template for Software Project Documentation#2400
    4 Authored PR: Enhance search performance of algolia plugin #2406
    5 Merged PR: Enhance search performance of algolia plugin #2406
    6 Authored PR: Utilize GitHub Actions to aid checking of commit message #2429
    6 Merged PR: Utilize GitHub Actions to aid checking of commit message #2429
    6 Authored PR: Upgrade simple-git version #2439
    6 Merged PR: Upgrade simple-git version #2439
    6 Authored PR: UG > PagNav: Misleading sentence #2440
    7 Merged PR: UG > PagNav: Misleading sentence #2440
    7 Submitted Issue: Fancylists to package MarkBind's current and future list features #2458
    8 Authored PR: Customizing list icons: give a way to apply to current item only #2454
    8 Submitted Issue: Utilize GitHub Actions to check for SEMVER impact label #2464
    8 Authored PR: Utilize GitHub Actions to check for SEMVER impact label #2464
    8 Researched Issue: Bootstrap migration tracker #2359
    9 Reviewed PR: MarkBind Template for Student Portfolio #2398
    9 Researched Issue: [Feature request] Tag (keywortd) support #2187
    10 Researched Issue: Utilize GitHub Actions to check for SEMVER impact label #2464
    10 Merged PR: Utilize GitHub Actions to check for SEMVER impact label #2464
    10 Submitted Issue: Reusable workflow repo for all repos under organisation #2479
    10 Merged PR: MarkBind Template for Software Project Documentation#2400
    10 Authored PR: Add a reminder when contributor is new to ping all contributor bot #2484
    11 Submitted Issue: Improve security of GitHub Actions workflows #2488
    11 Researched Issue: Improve security of GitHub Actions workflows #2488
    11 Researched Issue: Explore using Bun for testing and setup #2448
    11 Merged PR: Customizing list icons: give a way to apply to current item only #2454
    11 Researched Issue: Utilize GitHub Action to aid PR review #2140
    12 Authored PR: Improve security of GitHub Actions workflows #2510
    12 Authored PR: UG: images appear in two places #2514
    12 Merged PR: Add a reminder when contributor is new to ping all contributor bot #2484
    12 Merged PR: Improve security of GitHub Actions workflows #2510
    12 Researched Issue: Add github action to automatically unassign issues after a certain period of inactivity #2495
    12 Merged PR: UG: images appear in two places #2514
    13 Authored PR: Fix workflow file deploy-docs #2521
    13 Merged PR: Fix workflow file deploy-docs #2521
    13 Researched Issue: Add github action to automatically unassign issues after a certain period of inactivity #2495
    13 Authored PR: Using DangerJS to check changes coupling of implementation files to test or documentation files #2523
    13 Submitted Issue: Add documentation for workflow security for GitHub Actions #2527
    13 Authored PR: Add documentation regarding security practices for github actions #2528
    13 Merged PR: Using DangerJS to check changes coupling of implementation files to test or documentation files #2523
    13 Merged PR: Add documentation regarding security practices for github actions #2528
    diff --git a/students/KevinEyo1/progress.page-vue-render.js b/students/KevinEyo1/progress.page-vue-render.js index db2d2a3ed..117fbee7e 100644 --- a/students/KevinEyo1/progress.page-vue-render.js +++ b/students/KevinEyo1/progress.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('h3',{attrs:{"id":"markbind"}},[_v("MarkBind"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#markbind","onclick":"event.stopPropagation()"}})]),_v(" "),_c('div',{staticClass:"table-responsive"},[_c('table',{staticClass:"markbind-table table table-bordered table-striped"},[_c('thead',[_c('tr',[_c('th',[_v("Week")]),_v(" "),_c('th',[_v("Achievements")])])]),_v(" "),_c('tbody',[_c('tr',[_c('td',[_v("2")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2400"}},[_v("MarkBind Template for Software Project Documentation#2400")])])]),_v(" "),_c('tr',[_c('td',[_v("4")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2406"}},[_v("Enhance search performance of algolia plugin #2406")])])]),_v(" "),_c('tr',[_c('td',[_v("5")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2406"}},[_v("Enhance search performance of algolia plugin #2406")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2429"}},[_v("Utilize GitHub Actions to aid checking of commit message #2429")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2429"}},[_v("Utilize GitHub Actions to aid checking of commit message #2429")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2439"}},[_v("Upgrade simple-git version #2439")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2439"}},[_v("Upgrade simple-git version #2439")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2440"}},[_v("UG > PagNav: Misleading sentence #2440")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2440"}},[_v("UG > PagNav: Misleading sentence #2440")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Submitted Issue: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2458"}},[_v("Fancylists to package MarkBind's current and future list features #2458")])])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2454"}},[_v("Customizing list icons: give a way to apply to current item only #2454")])])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_v("Submitted Issue: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2464"}},[_v("Utilize GitHub Actions to check for SEMVER impact label #2464")])])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2470"}},[_v("Utilize GitHub Actions to check for SEMVER impact label #2464")])])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_v("Researched Issue: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2359"}},[_v("Bootstrap migration tracker #2359")])])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2398"}},[_v("MarkBind Template for Student Portfolio #2398")])])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_v("Researched Issue: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2187"}},[_v("[Feature request] Tag (keywortd) support #2187")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Researched Issue: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2464"}},[_v("Utilize GitHub Actions to check for SEMVER impact label #2464")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2470"}},[_v("Utilize GitHub Actions to check for SEMVER impact label #2464")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Submitted Issue: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2479"}},[_v("Reusable workflow repo for all repos under organisation #2479")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2400"}},[_v("MarkBind Template for Software Project Documentation#2400")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2484"}},[_v("Add a reminder when contributor is new to ping all contributor bot #2484")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Submitted Issue: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2488"}},[_v("Improve security of GitHub Actions workflows #2488")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Researched Issue: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2488"}},[_v("Improve security of GitHub Actions workflows #2488")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Researched Issue: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2448"}},[_v("Explore using Bun for testing and setup #2448")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2454"}},[_v("Customizing list icons: give a way to apply to current item only #2454")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Researched Issue: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2140"}},[_v("Utilize GitHub Action to aid PR review #2140")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2510"}},[_v("Improve security of GitHub Actions workflows #2510")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2514"}},[_v("UG: images appear in two places #2514")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2484"}},[_v("Add a reminder when contributor is new to ping all contributor bot #2484")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2510"}},[_v("Improve security of GitHub Actions workflows #2510")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Researched Issue: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2495"}},[_v("Add github action to automatically unassign issues after a certain period of inactivity #2495")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2514"}},[_v("UG: images appear in two places #2514")])])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2521"}},[_v("Fix workflow file deploy-docs #2521")])])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2521"}},[_v("Fix workflow file deploy-docs #2521")])])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_v("Researched Issue: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2495"}},[_v("Add github action to automatically unassign issues after a certain period of inactivity #2495")])])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2523"}},[_v("Using DangerJS to check changes coupling of implementation files to test or documentation files #2523")])])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_v("Submitted Issue: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2527"}},[_v("Add documentation for workflow security for GitHub Actions #2527")])])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2528"}},[_v("Add documentation regarding security practices for github actions #2528")])])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2523"}},[_v("Using DangerJS to check changes coupling of implementation files to test or documentation files #2523")])])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2528"}},[_v("Add documentation regarding security practices for github actions #2528")])])])])])])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/LamJiuFong/info.html b/students/LamJiuFong/info.html index b56159d90..23768989e 100644 --- a/students/LamJiuFong/info.html +++ b/students/LamJiuFong/info.html @@ -12,7 +12,7 @@ const baseUrl = '/2024' - + diff --git a/students/LamJiuFong/info.page-vue-render.js b/students/LamJiuFong/info.page-vue-render.js index e9908489a..371bbade4 100644 --- a/students/LamJiuFong/info.page-vue-render.js +++ b/students/LamJiuFong/info.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('p',[_c('span',{attrs:{"id":"github"}},[_c('a',{attrs:{"href":"https://www.github.com/LamJiuFong"}},[_v("https://www.github.com/LamJiuFong")])])]),_v(" "),_c('p',[_c('span',{attrs:{"id":"projects"}},[_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind"}},[_v("MarkBind")])])])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/LamJiuFong/knowledge.html b/students/LamJiuFong/knowledge.html index 00c17f0b1..420f102a2 100644 --- a/students/LamJiuFong/knowledge.html +++ b/students/LamJiuFong/knowledge.html @@ -12,7 +12,7 @@ const baseUrl = '/2024' -

    Node Package Manager (npm)

    A default package manager for Node.js.

    1. npm simplifies the process of installing, updating, and managing external libraries or modules in a Node.js project.
    2. npm allows developers to define and run scripts in their project's package.json file, automating common development tasks.
    3. npm allows developers to publish their own packages on the npm registry.

    Aspects learnt:

    1. npm CLI - A powerful tool to interact with npm. Learnt the usages of the basic commands like npm install, npm update, npm run <scripts> etc. and how they helped streamline the development process.
    2. package.json - Learnt how to interpret different parts of the json file eg. "scripts", "dependencies" and how to manage them.
    3. How to publish my own package to the public.
    4. How to use .npmignore

    Resources:

    1. npm Docs - Documentation for the npm registry, website, and command-line interface

    Stylelint

    A CSS linter that helps enforce conventions and avoid errors.

    1. Stylelint has over 100 built-in rules for modern CSS syntax and features, but it is customisable and supports plugins/configs.
    2. It can fix problems automatically where possible.
    3. It can extract embedded styles from HTML, Markdown and CSS-in-JS template literals.
    4. It can also parse CSS-like languages like SCSS, Sass, Less and SugarSS.

    Aspects learnt:

    1. Configuring the linter using the stylelintrc.js file, a configuration object for Stylelint to suit our own needs.
    2. Integrating Stylelint into our project.

    Resources:

    1. Stylelint offical Docs

    Commander.js

    A JavaScript library that provides a framework for building command-line interfaces (CLIs) in Node.js applications

    Aspects learnt:

    1. Define commands, options, and arguments using Commander.js for Markbind.

    Resources:

    1. Commander.js README

    Github Actions

    A CI/CD platform allowing developers to automate workflows directly within their GitHub repository.

    1. It supports customised workflows using YAML files to automate tasks such as building, testing, and deploying code.

    Aspects learnt:

    1. Understanding how Github Actions works in a specific repository.
    2. Interpreting .yml files in .github/workflow.

    Chrome DevTools

    A set of web developer tools built directly into the Chrome browser.

    1. We can utilise it to diagnose problems and monitor our program's performance eg. time used for each file to load
    2. We can see what is actually happening under the hood eg. which files are loaded before others

    Aspects learnt:

    1. How to check the attributes of each HTML component on the page.
    2. How to change the behavior of the browser in terms of loading speed by utilising the Network section - disable cache and change network settings
    3. How to monitor the behavior and performance of the browser by using the Performance insights section

    Resources:

    1. Most stack overflow articles will teach us how to interpret the output of Chrome DevTools, I realise it is easy to find such articles by searching "How to know xxxx", eg. How to know if lazy loading is working

    Nunjucks

    A template engine for Javascript. It provides a way to mix static content with dynamic data.

    Aspect learnt:

    1. I mostly learnt about nunjucks' API and learn to integrate it into our project.
    2. Learnt how Nunjucks works under the hood, from configuring to parsing to rendering, I have developed a strong understanding on how to integrate Nunjucks to my own project.

    Resources:

    1. Nunjucks offiical API

    Jest

    A Javascript testing framework that focuses on simplicity when writing tests.

    Aspect learnt:

    1. Learnt to differentiate mocks and spies and their particular use cases.
    2. Learnt how to use jest.mock, jest.fn to implement mocks and jest.spyOn to create spies.

    Resources:

    1. Jest official documentation
    2. Explains how to use the three functions

    mdn web_docs

    A website that documents web technologies for developers. The articles are written by developers that covers a lot of aspects related to the web.

    Aspects learnt:

    1. Learnt about some fundamentals about the web eg. how browser renders the files, how the HTML elements like <img> and <script> behaves, along with some common issues eg. lazy loading

    Resources:

    1. The website itself
    +

    Node Package Manager (npm)

    A default package manager for Node.js.

    1. npm simplifies the process of installing, updating, and managing external libraries or modules in a Node.js project.
    2. npm allows developers to define and run scripts in their project's package.json file, automating common development tasks.
    3. npm allows developers to publish their own packages on the npm registry.

    Aspects learnt:

    1. npm CLI - A powerful tool to interact with npm. Learnt the usages of the basic commands like npm install, npm update, npm run <scripts> etc. and how they helped streamline the development process.
    2. package.json - Learnt how to interpret different parts of the json file eg. "scripts", "dependencies" and how to manage them.
    3. How to publish my own package to the public.
    4. How to use .npmignore

    Resources:

    1. npm Docs - Documentation for the npm registry, website, and command-line interface

    Stylelint

    A CSS linter that helps enforce conventions and avoid errors.

    1. Stylelint has over 100 built-in rules for modern CSS syntax and features, but it is customisable and supports plugins/configs.
    2. It can fix problems automatically where possible.
    3. It can extract embedded styles from HTML, Markdown and CSS-in-JS template literals.
    4. It can also parse CSS-like languages like SCSS, Sass, Less and SugarSS.

    Aspects learnt:

    1. Configuring the linter using the stylelintrc.js file, a configuration object for Stylelint to suit our own needs.
    2. Integrating Stylelint into our project.

    Resources:

    1. Stylelint offical Docs

    Commander.js

    A JavaScript library that provides a framework for building command-line interfaces (CLIs) in Node.js applications

    Aspects learnt:

    1. Define commands, options, and arguments using Commander.js for Markbind.

    Resources:

    1. Commander.js README

    Github Actions

    A CI/CD platform allowing developers to automate workflows directly within their GitHub repository.

    1. It supports customised workflows using YAML files to automate tasks such as building, testing, and deploying code.

    Aspects learnt:

    1. Understanding how Github Actions works in a specific repository.
    2. Interpreting .yml files in .github/workflow.

    Chrome DevTools

    A set of web developer tools built directly into the Chrome browser.

    1. We can utilise it to diagnose problems and monitor our program's performance eg. time used for each file to load
    2. We can see what is actually happening under the hood eg. which files are loaded before others

    Aspects learnt:

    1. How to check the attributes of each HTML component on the page.
    2. How to change the behavior of the browser in terms of loading speed by utilising the Network section - disable cache and change network settings
    3. How to monitor the behavior and performance of the browser by using the Performance insights section

    Resources:

    1. Most stack overflow articles will teach us how to interpret the output of Chrome DevTools, I realise it is easy to find such articles by searching "How to know xxxx", eg. How to know if lazy loading is working

    Nunjucks

    A template engine for Javascript. It provides a way to mix static content with dynamic data.

    Aspect learnt:

    1. I mostly learnt about nunjucks' API and learn to integrate it into our project.
    2. Learnt how Nunjucks works under the hood, from configuring to parsing to rendering, I have developed a strong understanding on how to integrate Nunjucks to my own project.

    Resources:

    1. Nunjucks offiical API

    Jest

    A Javascript testing framework that focuses on simplicity when writing tests.

    Aspect learnt:

    1. Learnt to differentiate mocks and spies and their particular use cases.
    2. Learnt how to use jest.mock, jest.fn to implement mocks and jest.spyOn to create spies.

    Resources:

    1. Jest official documentation
    2. Explains how to use the three functions

    mdn web_docs

    A website that documents web technologies for developers. The articles are written by developers that covers a lot of aspects related to the web.

    Aspects learnt:

    1. Learnt about some fundamentals about the web eg. how browser renders the files, how the HTML elements like <img> and <script> behaves, along with some common issues eg. lazy loading

    Resources:

    1. The website itself
    diff --git a/students/LamJiuFong/knowledge.page-vue-render.js b/students/LamJiuFong/knowledge.page-vue-render.js index cc1b1bb57..fa411da1f 100644 --- a/students/LamJiuFong/knowledge.page-vue-render.js +++ b/students/LamJiuFong/knowledge.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('h3',{attrs:{"id":"node-package-manager-npm"}},[_v("Node Package Manager (npm)"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#node-package-manager-npm","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("A default package manager for Node.js.")]),_v(" "),_c('ol',[_c('li',[_v("npm simplifies the process of installing, updating, and managing external libraries or modules in a Node.js project.")]),_v(" "),_c('li',[_v("npm allows developers to define and run scripts in their project's package.json file, automating common development tasks.")]),_v(" "),_c('li',[_v("npm allows developers to publish their own packages on the npm registry.")])]),_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('ol',[_c('li',[_v("npm CLI - A powerful tool to interact with npm. Learnt the usages of the basic commands like "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("npm install")]),_v(", "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("npm update")]),_v(", "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("npm run ")]),_v(" etc. and how they helped streamline the development process.")]),_v(" "),_c('li',[_v("package.json - Learnt how to interpret different parts of the json file eg. "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("\"scripts\"")]),_v(", "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("\"dependencies\"")]),_v(" and how to manage them.")]),_v(" "),_c('li',[_v("How to publish my own package to the public.")]),_v(" "),_c('li',[_v("How to use "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v(".npmignore")])])]),_v(" "),_c('h4',{attrs:{"id":"resources"}},[_v("Resources:"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#resources","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ol',[_c('li',[_c('a',{attrs:{"href":"https://docs.npmjs.com/"}},[_v("npm Docs")]),_v(" - Documentation for the npm registry, website, and command-line interface")])]),_v(" "),_c('h3',{attrs:{"id":"stylelint"}},[_v("Stylelint"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#stylelint","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("A CSS linter that helps enforce conventions and avoid errors.")]),_v(" "),_c('ol',[_c('li',[_v("Stylelint has over 100 built-in rules for modern CSS syntax and features, but it is customisable and supports plugins/configs.")]),_v(" "),_c('li',[_v("It can fix problems automatically where possible.")]),_v(" "),_c('li',[_v("It can extract embedded styles from HTML, Markdown and CSS-in-JS template literals.")]),_v(" "),_c('li',[_v("It can also parse CSS-like languages like SCSS, Sass, Less and SugarSS.")])]),_v(" "),_c('h4',{attrs:{"id":"aspects-learnt-2"}},[_v("Aspects learnt:"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#aspects-learnt-2","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ol',[_c('li',[_v("Configuring the linter using the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("stylelintrc.js")]),_v(" file, a configuration object for Stylelint to suit our own needs.")]),_v(" "),_c('li',[_v("Integrating Stylelint into our project.")])]),_v(" "),_c('h4',{attrs:{"id":"resources-2"}},[_v("Resources:"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#resources-2","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ol',[_c('li',[_c('a',{attrs:{"href":"https://stylelint.io/"}},[_v("Stylelint offical Docs")])])]),_v(" "),_c('h3',{attrs:{"id":"commander-js"}},[_v("Commander.js"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#commander-js","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("A JavaScript library that provides a framework for building command-line interfaces (CLIs) in Node.js applications")]),_v(" "),_c('h4',{attrs:{"id":"aspects-learnt-3"}},[_v("Aspects learnt:"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#aspects-learnt-3","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ol',[_c('li',[_v("Define commands, options, and arguments using Commander.js for Markbind.")])]),_v(" "),_c('h4',{attrs:{"id":"resources-3"}},[_v("Resources:"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#resources-3","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ol',[_c('li',[_c('a',{attrs:{"href":"https://www.npmjs.com/package/commander"}},[_v("Commander.js README")])])]),_v(" "),_c('h3',{attrs:{"id":"github-actions"}},[_v("Github Actions"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#github-actions","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("A CI/CD platform allowing developers to automate workflows directly within their GitHub repository.")]),_v(" "),_c('ol',[_c('li',[_v("It supports customised workflows using YAML files to automate tasks such as building, testing, and deploying code.")])]),_v(" "),_c('h4',{attrs:{"id":"aspects-learnt-4"}},[_v("Aspects learnt:"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#aspects-learnt-4","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ol',[_c('li',[_v("Understanding how Github Actions works in a specific repository.")]),_v(" "),_c('li',[_v("Interpreting "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v(".yml")]),_v(" files in "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v(".github/workflow")]),_v(".")])]),_v(" "),_c('h3',{attrs:{"id":"chrome-devtools"}},[_v("Chrome DevTools"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#chrome-devtools","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("A set of web developer tools built directly into the Chrome browser.")]),_v(" "),_c('ol',[_c('li',[_v("We can utilise it to diagnose problems and monitor our program's performance eg. time used for each file to load")]),_v(" "),_c('li',[_v("We can see what is actually happening under the hood eg. which files are loaded before others")])]),_v(" "),_c('h4',{attrs:{"id":"aspects-learnt-5"}},[_v("Aspects learnt:"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#aspects-learnt-5","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ol',[_c('li',[_v("How to check the attributes of each HTML component on the page.")]),_v(" "),_c('li',[_v("How to change the behavior of the browser in terms of loading speed by utilising the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Network")]),_v(" section - disable cache and change network settings")]),_v(" "),_c('li',[_v("How to monitor the behavior and performance of the browser by using the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Performance insights")]),_v(" section")])]),_v(" "),_c('h4',{attrs:{"id":"resources-4"}},[_v("Resources:"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#resources-4","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ol',[_c('li',[_v("Most stack overflow articles will teach us how to interpret the output of Chrome DevTools, I realise it is easy to find such articles by searching \"How to know xxxx\", eg. How to know if lazy loading is working")])]),_v(" "),_c('h3',{attrs:{"id":"nunjucks"}},[_v("Nunjucks"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#nunjucks","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("A template engine for Javascript. It provides a way to mix static content with dynamic data.")]),_v(" "),_c('h4',{attrs:{"id":"aspect-learnt"}},[_v("Aspect learnt:"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#aspect-learnt","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ol',[_c('li',[_v("I mostly learnt about nunjucks' API and learn to integrate it into our project.")]),_v(" "),_c('li',[_v("Learnt how Nunjucks works under the hood, from configuring to parsing to rendering, I have developed a strong understanding on how to integrate Nunjucks to my own project.")])]),_v(" "),_c('h4',{attrs:{"id":"resources-5"}},[_v("Resources:"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#resources-5","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ol',[_c('li',[_c('a',{attrs:{"href":"https://mozilla.github.io/nunjucks/api.html"}},[_v("Nunjucks offiical API")])])]),_v(" "),_c('h3',{attrs:{"id":"jest"}},[_v("Jest"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#jest","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("A Javascript testing framework that focuses on simplicity when writing tests.")]),_v(" "),_c('h4',{attrs:{"id":"aspect-learnt-2"}},[_v("Aspect learnt:"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#aspect-learnt-2","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ol',[_c('li',[_v("Learnt to differentiate mocks and spies and their particular use cases.")]),_v(" "),_c('li',[_v("Learnt how to use "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("jest.mock")]),_v(", "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("jest.fn")]),_v(" to implement mocks and "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("jest.spyOn")]),_v(" to create spies.")])]),_v(" "),_c('h4',{attrs:{"id":"resources-6"}},[_v("Resources:"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#resources-6","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ol',[_c('li',[_c('a',{attrs:{"href":"https://jestjs.io/"}},[_v("Jest official documentation")])]),_v(" "),_c('li',[_c('a',{attrs:{"href":"https://medium.com/@rickhanlonii/understanding-jest-mocks-f0046c68e53c"}},[_v("Explains how to use the three functions")])])]),_v(" "),_c('h3',{attrs:{"id":"mdn-web-docs"}},[_v("mdn web_docs"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#mdn-web-docs","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("A website that documents web technologies for developers. The articles are written by developers that covers a lot of aspects related to the web.")]),_v(" "),_c('h4',{attrs:{"id":"aspects-learnt-6"}},[_v("Aspects learnt:"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#aspects-learnt-6","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ol',[_c('li',[_v("Learnt about some fundamentals about the web eg. how browser renders the files, how the HTML elements like "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("")]),_v(" and "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v(" diff --git a/students/LamJiuFong/progress.page-vue-render.js b/students/LamJiuFong/progress.page-vue-render.js index ca02ae4cf..051b36bbe 100644 --- a/students/LamJiuFong/progress.page-vue-render.js +++ b/students/LamJiuFong/progress.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('h3',{attrs:{"id":"summary-of-key-contributions"}},[_v("Summary of Key Contributions"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#summary-of-key-contributions","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("I have spent most of my time working on "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2302"}},[_v("Issue #2302")]),_v(" where I was trying to make Markbind able to support setting global variables via nunjucks syntax, which would if done, significantly improve users' convenience while using the product.\nI have pushed the progress of solving this issue through various research and experiment efforts through "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2474"}},[_v("this PR")]),_v(".\nLastly, I am able to document the major challenges that developers will face and the common pitfalls when tackling this issue.")]),_v(" "),_c('p',[_v("Other than that, I have also focused on researching/investigating challenging issues that have caused or may cause bugs in Markbind. For example,\n"),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2367"}},[_v("the lazy loading issue")]),_v(", "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2416"}},[_v("gitignore not generated issue")]),_v(", "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2508"}},[_v("issue with script's defer attribute")]),_v(", "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2467"}},[_v("potential npm unlink issue")]),_v(", "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2463"}},[_v("Jest's mock issue")])]),_v(" "),_c('p',[_v("I have also improved users' experience by optimizing our product's performance, related works are "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2450"}},[_v("introducing lazy loading")]),_v(" and "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2522"}},[_v("improve loading speed by moving scripts after the html files are loaded")]),_v(".")]),_v(" "),_c('div',{staticClass:"table-responsive"},[_c('table',{staticClass:"markbind-table table table-bordered table-striped"},[_c('thead',[_c('tr',[_c('th',[_v("Week")]),_v(" "),_c('th',[_v("Progress")])])]),_v(" "),_c('tbody',[_c('tr',[_c('td',[_v("2")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2395"}},[_v("#2395")]),_v(" Allow markbind serve to specify custom host")])]),_v(" "),_c('tr',[_c('td',[_v("4")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2425"}},[_v("#2425")]),_v(" Migrate stylelint to latest version")])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Created Issue: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2451"}},[_v("#2451")]),_v(" Missing output for plugins: Web3Forms")])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Researched on Issue: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2367"}},[_v("#2367")]),_v(" Re-introduce lazy loading")])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2450"}},[_v("#2450")]),_v(" Re-introduce lazy loading")])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_v("Created Issue: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2468"}},[_v("#2468")]),_v(" Allow users to define the height/width in percentages for Pic and Annotate")])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_v("Researched on Issue: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2416"}},[_v("#2416")]),_v(" .gitignore not generated when init")])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2469"}},[_v("#2469")]),_v(" Fix .gitignore not generated bug")])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2463"}},[_v("#2463")]),_v(" Test logger calls in tests for NodeProcessor")])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_v("Researched on Issue: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2467"}},[_v("#2467")]),_v(" Add documentation about npm unlink in DG")])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2474"}},[_v("#2474")]),_v(" Allow setting global variables using nunjucks syntax")])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2484"}},[_v("#2484")]),_v(" Add a reminder when contributor is new to ping all contributor bot")])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2472"}},[_v("#2472")]),_v(" Add the announcement component")])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2481"}},[_v("#2481")]),_v(" Migrate Site.test to Typescript")])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2491"}},[_v("#2491")]),_v(" Allocate space for scrollbar in sitenav and pagenav")])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2492"}},[_v("#2492")]),_v(" Defer scripts in page template")])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Researched on Issue: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2508"}},[_v("#2508")]),_v(" PR2492 causes regression to Modal")])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2522"}},[_v("#2522")]),_v(" Move scripts to bottom in page template")])]),_v(" "),_c('tr',[_c('td',[_v("Reading")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2446"}},[_v("#2446")]),_v(" Add dataTable plugin")])]),_v(" "),_c('tr',[_c('td',[_v("Exam")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2540"}},[_v("#2540")]),_v(" Bump fontawesome to remove console error")])]),_v(" "),_c('tr',[_c('td',[_v("Exam")]),_v(" "),_c('td',[_v("Researched on Issue: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2302"}},[_v("#2302")]),_v(" Add support for setting & importing variables via Nunjucks syntax into global variables")])])])])])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/MadLamprey/info.html b/students/MadLamprey/info.html index 9ea79e9c5..7a6d4058d 100644 --- a/students/MadLamprey/info.html +++ b/students/MadLamprey/info.html @@ -12,7 +12,7 @@ const baseUrl = '/2024' - + diff --git a/students/MadLamprey/info.page-vue-render.js b/students/MadLamprey/info.page-vue-render.js index 2d9658c03..21af39ad3 100644 --- a/students/MadLamprey/info.page-vue-render.js +++ b/students/MadLamprey/info.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('p',[_c('span',{attrs:{"id":"github"}},[_c('a',{attrs:{"href":"https://www.github.com/MadLamprey"}},[_v("https://www.github.com/MadLamprey")])])]),_v(" "),_c('p',[_c('span',{attrs:{"id":"projects"}},[_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher"}},[_v("CATcher")])])])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/MadLamprey/knowledge.html b/students/MadLamprey/knowledge.html index a6fff3413..8d52c08fb 100644 --- a/students/MadLamprey/knowledge.html +++ b/students/MadLamprey/knowledge.html @@ -25,7 +25,7 @@
    • Jasmine's BDD framework encourages a more descriptive and natural language style in writing tests, which aligns well with how software behavior is described in real-world scenarios.
  • Mocking and Spying:
    • Jasmine's mocking and spying capabilities were instrumental in isolating the tests. By creating spy objects for dependencies like MatSnackBar and LoggingService, I could simulate their behavior and assert that they were being called correctly without actually triggering real side effects.
    • A spy object was created for GithubService using Jasmine's createSpyObj method, which allowed us to simulate its fetchAllMilestones method without actual HTTP requests. This approach isolates the test environment from external dependencies.
  • Asynchronous Testing:
    • The use of RxJS's of function to return observable sequences makes the method calls predictable and easily testable.
    • Jasmine's asynchronous testing capability, demonstrated with the done callback, was crucial. It ensures that tests involving observables only complete after all asynchronous operations have been resolved, providing an accurate assessment of the method's behavior.
  • Conditional Behavior Testing: -
    • The handleError() method's conditional logic, which dictates different responses based on the error type, highlighted the importance of comprehensive test paths. I learned to utilize Jasmine's it blocks effectively to specify and isolate each logical branch within the method. This practice ensures that every potential execution path is tested, which is crucial for error handling logic where different types of errors can lead to different user experiences.
  • This exploration into Jasmine's capabilities not only enhanced my technical skills but also deepened my understanding of strategic test planning and execution in a behavior-driven development context. The experience emphasized the value of detailed, well-structured tests in maintaining high software quality and reliability.

    UI/UX Design

    A rather inconspicuous but significant learning point, while working on WATcher and CATcher, was UI and UX design. Since the main aim of these applications is to assist students, tutors, professors to understand, contextualise and identify key information with ease, several design decisions had to made from the point of view of how it would most benefit the users.

    Some of these included:

    1. #361 Make ItemsPerPage common for all card views

      • Implementing a consistent ItemsPerPage filter across different views ensures that users have a predictable and stable interface, improving usability and reducing cognitive load.
    2. #363 Remodel the design of the Filter bar

      • Redesigning the filter bar to create a design that is both functionally effective and aesthetically pleasing, requiring a balance between form and function.
    3. #307 Add tool tip for hidden users

      • Adding tooltips is a critical aspect of UI design for enhancing user understanding without cluttering the interface, to ensure that they appear in contexts where users most need guidance.
    4. #318 Add sorting by Status

      • Understanding of the most logical ways users might want to organize data, enhancing the application's usability.
    5. #337 Add icon for PRs without milestones

      • The use of icons to convey information is a staple in UI design, providing visual cues that help users quickly grasp the status of items.

    Working on these PRs likely provided a deep dive into the principles of user-centered design, focusing on enhancing the user's journey through intuitive layouts, actionable insights, and consistent behaviors across the application. The challenges often revolved around integrating new features without disrupting the existing user experience, requiring careful consideration of design continuity and user expectations.

    +
    • The handleError() method's conditional logic, which dictates different responses based on the error type, highlighted the importance of comprehensive test paths. I learned to utilize Jasmine's it blocks effectively to specify and isolate each logical branch within the method. This practice ensures that every potential execution path is tested, which is crucial for error handling logic where different types of errors can lead to different user experiences.

    This exploration into Jasmine's capabilities not only enhanced my technical skills but also deepened my understanding of strategic test planning and execution in a behavior-driven development context. The experience emphasized the value of detailed, well-structured tests in maintaining high software quality and reliability.

    UI/UX Design

    A rather inconspicuous but significant learning point, while working on WATcher and CATcher, was UI and UX design. Since the main aim of these applications is to assist students, tutors, professors to understand, contextualise and identify key information with ease, several design decisions had to made from the point of view of how it would most benefit the users.

    Some of these included:

    1. #361 Make ItemsPerPage common for all card views

      • Implementing a consistent ItemsPerPage filter across different views ensures that users have a predictable and stable interface, improving usability and reducing cognitive load.
    2. #363 Remodel the design of the Filter bar

      • Redesigning the filter bar to create a design that is both functionally effective and aesthetically pleasing, requiring a balance between form and function.
    3. #307 Add tool tip for hidden users

      • Adding tooltips is a critical aspect of UI design for enhancing user understanding without cluttering the interface, to ensure that they appear in contexts where users most need guidance.
    4. #318 Add sorting by Status

      • Understanding of the most logical ways users might want to organize data, enhancing the application's usability.
    5. #337 Add icon for PRs without milestones

      • The use of icons to convey information is a staple in UI design, providing visual cues that help users quickly grasp the status of items.

    Working on these PRs likely provided a deep dive into the principles of user-centered design, focusing on enhancing the user's journey through intuitive layouts, actionable insights, and consistent behaviors across the application. The challenges often revolved around integrating new features without disrupting the existing user experience, requiring careful consideration of design continuity and user expectations.

    diff --git a/students/MadLamprey/knowledge.page-vue-render.js b/students/MadLamprey/knowledge.page-vue-render.js index 808fa2c63..6762742e9 100644 --- a/students/MadLamprey/knowledge.page-vue-render.js +++ b/students/MadLamprey/knowledge.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('h3',{attrs:{"id":"angular"}},[_v("Angular"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#angular","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Underpinning the development of CATcher and WATcher, it was of paramount importance to understand the nuances of the Angular framework. This presented a challenge, transitioning from ReactJs - a framework I was comfortable with. The structure of Angular, contrasted with React's flexibility, necessitated a deep and rigorous engagement with Angular's ecosystem.")]),_v(" "),_c('ul',[_c('li',[_c('strong',[_v("Transitioning from ReactJs")]),_v(":\n"),_c('ul',[_c('li',[_v("I was initially struck by Angular's comprehensive framework, which unlike ReactJs's straightforward library-based approach, provides a full suite of development tools. Angular mandates a structured environment that rigorously applies TypeScript for static typing, modules for encapsulation, and injectors for dependency management, ensuring robust, scalable applications. This all-inclusive nature required adapting to a relatively complex development environment.")])])]),_v(" "),_c('li',[_c('strong',[_v("Angular Directives and DOM Manipulation")]),_v(":\n"),_c('ul',[_c('li',[_v("Directives are essentially markers that Angular allows us to attach to elements to influence their behaviour in a specific way.")]),_v(" "),_c('li',[_v("These constructs allow for direct DOM manipulation, a capability not native to React. I leveraged structural directives like "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("*ngIf")]),_v(" for conditional rendering, and attribute directives to modify behaviors of DOM elements dynamically. This exploration provided practical insights into complex DOM operations without full page reloads, facilitating rich, responsive user interactions.")])])]),_v(" "),_c('li',[_c('strong',[_v("Form Validation with Angular Validators")]),_v(":\n"),_c('ul',[_c('li',[_v("Linking back to the use of Angular Directives, their coupling with Validators makes for robustness and expressiveness, especially in the case of forms, to allow for proper feedback to be given to the user.")]),_v(" "),_c('li',[_v("I learned about the creation and use of custom validators as part of the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("@angular/forms")]),_v(" library, which are a crucial aspect of an application that consists of Form-based components. Angular's form validation is highly robust, integrated deeply with its reactive and template-driven forms, facilitating complex form handling with built-in validators and custom validation functions. In contrast, React forms often require additional libraries for similar levels of validation robustness.")])])]),_v(" "),_c('li',[_c('strong',[_v("Software Maintenance")]),_v(":\n"),_c('ul',[_c('li',[_v("In a bid to keep the application and its dependencies up-to-date, constant upgrade to newer versions of the tech stack used, is crucial. This also falls in line with our goal to follow best software practices.")]),_v(" "),_c('li',[_v("My role extended to maintaining the application's health by upgrading Angular and its ecosystem. This task required a thorough understanding of semantic versioning, dependency conflicts, and the Angular update cycle. React, while flexible, typically requires third-party tools to manage similar tasks, leading to a more hands-on and sometimes fragmented maintenance experience.")])])])]),_v(" "),_c('p',[_v("Through contributions and an extensive understanding of the codebase, I have attained a certain degree of comfort with Angular as a frontend framework, and will further practice the use of Angular and its features in personal projects.")]),_v(" "),_c('h3',{attrs:{"id":"docker-integration-in-watcher-documentation"}},[_v("Docker Integration in WATcher Documentation"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#docker-integration-in-watcher-documentation","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Incorporating Docker into the WATcher documentation development process was a strategic move to standardize and streamline the development environment. My involvement with setting up a Dev Container using Docker provided valuable insights into containerization and its impact on development workflows.")]),_v(" "),_c('ul',[_c('li',[_c('strong',[_v("Understanding and Implementing Dev Containers")]),_v(":\n"),_c('ul',[_c('li',[_v("Dev Containers provide a consistent, isolated, and replicable development environment for all contributors, regardless of their local setup. This is crucial for eliminating differences observed in working on the development environment on different systems.")]),_v(" "),_c('li',[_v("I utilized Docker to encapsulate the build environment into a Docker Image, defined by a Dockerfile. This approach ensures that all dependencies and runtime environments are uniformly configured across different development setups.")])])]),_v(" "),_c('li',[_c('strong',[_v("Customization and Configuration")]),_v(":\n"),_c('ul',[_c('li',[_v("The use of the VSCode Dev Container as a base allowed for significant customization tailored to the specific needs of the WATcher documentation project. By parameterizing the build process ("),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("devcontainer.json")]),_v("), I was able to define and manage configurations such as environment variables, port forwarding, and startup commands efficiently.")]),_v(" "),_c('li',[_v("One of the key benefits of implementing Docker was significantly reducing the onboarding time for new developers. By providing a container that includes all necessary dependencies pre-installed and pre-configured, new team members could get up and running with minimal setup.")])])])]),_v(" "),_c('p',[_v("Working with Docker deepened my understanding of containerization technologies and their role in modern software development. It highlighted the importance of infrastructure as code (IaC) in automating and simplifying development processes. It reinforced best practices in DevOps, particularly in terms of environment standardization.")]),_v(" "),_c('h3',{attrs:{"id":"linters"}},[_v("Linters"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#linters","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("As part of maintaining development tools, I worked on migrating the project from using TSLint (which is now deprecated), to ESLint. This helped me understand the true role of linters, and how they are defined for a project.")]),_v(" "),_c('ul',[_c('li',[_c('strong',[_v("Understanding Linters")]),_v(":\n"),_c('ul',[_c('li',[_v("As studied in CS2103T, linters are vital tools in modern software development, used for static code analysis to enforce coding standards and identify problematic patterns in the code. My experience with linters deepened during the migration, reinforcing their role in improving code quality, reducing bugs, and maintaining consistency across large codebases.")])])]),_v(" "),_c('li',[_c('strong',[_v("The Migration Process")]),_v(":\n"),_c('ul',[_c('li',[_v("The migration from TSLint to ESLint involved a strategic review and translation of linting rules to ensure continuity and adherence to our established coding practices. Despite the availability of automated tools like "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("tslint-to-eslint")]),_v(", which attempts to convert configurations, many rules required manual adjustments to align with ESLint’s syntax and capabilities, as well as to not make too many disruptive changes to the codebase.")]),_v(" "),_c('li',[_v("This process was meticulous, involving:\n"),_c('ul',[_c('li',[_c('strong',[_v("Rule Assessment")]),_v(": Evaluating each TSLint rule and its impact on our codebase, determining essential rules, and mapping them to their ESLint counterparts.")]),_v(" "),_c('li',[_c('strong',[_v("Configuration Translation")]),_v(": Manually configuring ESLint rules where automated tools fell short, ensuring that our new linting setup maintained the integrity and intent of the original rules without compromising on code quality.")]),_v(" "),_c('li',[_c('strong',[_v("Testing and Adjustment")]),_v(": Rigorously testing the new ESLint configurations across our projects to identify any discrepancies and adjust rules to better fit our development practices and project specifics.")])])]),_v(" "),_c('li',[_v("ESLint provides comprehensive support for both JavaScript and TypeScript, offering a unified linting solution that reduces complexity and improves analysis accuracy. ESLint’s architecture allows for extensive customization and extension, enabling the integration of plugins that address specific needs such as React-specific linting rules or accessibility checks.")])])])]),_v(" "),_c('p',[_v("The migration to ESLint has not only streamlined the development environment but also enriched my understanding of effective coding practices.")]),_v(" "),_c('h3',{attrs:{"id":"jasmine"}},[_v("Jasmine"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#jasmine","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("While developing tests for the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("ErrorHandlingService")]),_v(" and "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("MilestoneService")]),_v(" in WATcher, I gained significant insights into Jasmine's powerful features and how they can be leveraged to create thorough, reliable, and maintainable test suites.")]),_v(" "),_c('ul',[_c('li',[_c('strong',[_v("Behavior-Driven Development Approach")]),_v(":\n"),_c('ul',[_c('li',[_v("Jasmine's BDD framework encourages a more descriptive and natural language style in writing tests, which aligns well with how software behavior is described in real-world scenarios.")])])]),_v(" "),_c('li',[_c('strong',[_v("Mocking and Spying")]),_v(":\n"),_c('ul',[_c('li',[_v("Jasmine's mocking and spying capabilities were instrumental in isolating the tests. By creating spy objects for dependencies like "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("MatSnackBar")]),_v(" and "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("LoggingService")]),_v(", I could simulate their behavior and assert that they were being called correctly without actually triggering real side effects.")]),_v(" "),_c('li',[_v("A spy object was created for "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("GithubService")]),_v(" using Jasmine's "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("createSpyObj")]),_v(" method, which allowed us to simulate its "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("fetchAllMilestones")]),_v(" method without actual HTTP requests. This approach isolates the test environment from external dependencies.")])])]),_v(" "),_c('li',[_c('strong',[_v("Asynchronous Testing")]),_v(":\n"),_c('ul',[_c('li',[_v("The use of RxJS's of function to return observable sequences makes the method calls predictable and easily testable.")]),_v(" "),_c('li',[_v("Jasmine's asynchronous testing capability, demonstrated with the done callback, was crucial. It ensures that tests involving observables only complete after all asynchronous operations have been resolved, providing an accurate assessment of the method's behavior.")])])]),_v(" "),_c('li',[_c('strong',[_v("Conditional Behavior Testing")]),_v(":\n"),_c('ul',[_c('li',[_v("The "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("handleError()")]),_v(" method's conditional logic, which dictates different responses based on the error type, highlighted the importance of comprehensive test paths. I learned to utilize Jasmine's "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("it")]),_v(" blocks effectively to specify and isolate each logical branch within the method. This practice ensures that every potential execution path is tested, which is crucial for error handling logic where different types of errors can lead to different user experiences.")])])])]),_v(" "),_c('p',[_v("This exploration into Jasmine's capabilities not only enhanced my technical skills but also deepened my understanding of strategic test planning and execution in a behavior-driven development context. The experience emphasized the value of detailed, well-structured tests in maintaining high software quality and reliability.")]),_v(" "),_c('h3',{attrs:{"id":"ui-ux-design"}},[_v("UI/UX Design"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#ui-ux-design","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("A rather inconspicuous but significant learning point, while working on WATcher and CATcher, was UI and UX design. Since the main aim of these applications is to assist students, tutors, professors to understand, contextualise and identify key information with ease, several design decisions had to made from the point of view of how it would most benefit the users.")]),_v(" "),_c('p',[_v("Some of these included:")]),_v(" "),_c('ol',[_c('li',[_c('p',[_c('strong',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/361"}},[_v("#361")]),_v(" Make ItemsPerPage common for all card views")])]),_v(" "),_c('ul',[_c('li',[_v("Implementing a consistent ItemsPerPage filter across different views ensures that users have a predictable and stable interface, improving usability and reducing cognitive load.")])])]),_v(" "),_c('li',[_c('p',[_c('strong',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/363"}},[_v("#363")]),_v(" Remodel the design of the Filter bar")])]),_v(" "),_c('ul',[_c('li',[_v("Redesigning the filter bar to create a design that is both functionally effective and aesthetically pleasing, requiring a balance between form and function.")])])]),_v(" "),_c('li',[_c('p',[_c('strong',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/307"}},[_v("#307")]),_v(" Add tool tip for hidden users")])]),_v(" "),_c('ul',[_c('li',[_v("Adding tooltips is a critical aspect of UI design for enhancing user understanding without cluttering the interface, to ensure that they appear in contexts where users most need guidance.")])])]),_v(" "),_c('li',[_c('p',[_c('strong',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/318"}},[_v("#318")]),_v(" Add sorting by Status")])]),_v(" "),_c('ul',[_c('li',[_v("Understanding of the most logical ways users might want to organize data, enhancing the application's usability.")])])]),_v(" "),_c('li',[_c('p',[_c('strong',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/337"}},[_v("#337")]),_v(" Add icon for PRs without milestones")])]),_v(" "),_c('ul',[_c('li',[_v("The use of icons to convey information is a staple in UI design, providing visual cues that help users quickly grasp the status of items.")])])])]),_v(" "),_c('p',[_v("Working on these PRs likely provided a deep dive into the principles of user-centered design, focusing on enhancing the user's journey through intuitive layouts, actionable insights, and consistent behaviors across the application. The challenges often revolved around integrating new features without disrupting the existing user experience, requiring careful consideration of design continuity and user expectations.")])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/MadLamprey/progress.html b/students/MadLamprey/progress.html index 835242972..ad267f10a 100644 --- a/students/MadLamprey/progress.html +++ b/students/MadLamprey/progress.html @@ -12,7 +12,7 @@ const baseUrl = '/2024' -

    Summary

    In WATcher, I primarily identified critical UI issues, significantly enhancing interface and service functionalities to boost user experience and application efficiency. I also contributed to the documentation of WATcher to aid future development. In CATcher, my focus was on migrating the linter from TSLint to ESLint, a crucial step that enhanced code quality and facilitated better maintainability.

    Details

    CATcher

    PRs Opened

    Week PR
    2 #1237 Add whitespace validation
    6 #1250 Migrate from TSLint to ESLint

    WATcher

    Issues Created

    Week Issue
    6 #266 Upgrade to Angular 12
    11 #361 Make ItemsPerPage common for all card views
    12 #363 Remodel the design of the Filter bar

    PRs Opened

    Week PR
    2 #228 Prevent redirection when repo not set
    4 #252 Upgrade to Angular 11
    6 #267 Upgrade to Angular 12
    7 #286 Remove sorting by assignees in Issue Sorter
    8 #303 Create tests for Milestone service
    9 #304 Create tests for Error Handling service
    9 #307 Add tool tip for hidden users
    10 #315 Split 'Without a milestone' option
    10 #318 Add sorting by Status
    11 #337 Add icon for PRs without milestones
    12 #362 Make ItemsPerPage common for all card views

    PRs Reviewed

    Week PR
    6 #260 Remove test cases for permissions service
    9 #313 Integrate Grouping Service
    10 #334 Fix default preset view
    10 #350 Deploy v1.2.1
    11 #351 Enable automated testing on the deploy branch
    12 #364 Create release V1.2.2

    WATcher-docs

    PRs Opened

    Week PR
    5 #13 Add devcontainer support
    5 #14 Update Design page
    +

    Summary

    In WATcher, I primarily identified critical UI issues, significantly enhancing interface and service functionalities to boost user experience and application efficiency. I also contributed to the documentation of WATcher to aid future development. In CATcher, my focus was on migrating the linter from TSLint to ESLint, a crucial step that enhanced code quality and facilitated better maintainability.

    Details

    CATcher

    PRs Opened

    Week PR
    2 #1237 Add whitespace validation
    6 #1250 Migrate from TSLint to ESLint

    WATcher

    Issues Created

    Week Issue
    6 #266 Upgrade to Angular 12
    11 #361 Make ItemsPerPage common for all card views
    12 #363 Remodel the design of the Filter bar

    PRs Opened

    Week PR
    2 #228 Prevent redirection when repo not set
    4 #252 Upgrade to Angular 11
    6 #267 Upgrade to Angular 12
    7 #286 Remove sorting by assignees in Issue Sorter
    8 #303 Create tests for Milestone service
    9 #304 Create tests for Error Handling service
    9 #307 Add tool tip for hidden users
    10 #315 Split 'Without a milestone' option
    10 #318 Add sorting by Status
    11 #337 Add icon for PRs without milestones
    12 #362 Make ItemsPerPage common for all card views

    PRs Reviewed

    Week PR
    6 #260 Remove test cases for permissions service
    9 #313 Integrate Grouping Service
    10 #334 Fix default preset view
    10 #350 Deploy v1.2.1
    11 #351 Enable automated testing on the deploy branch
    12 #364 Create release V1.2.2

    WATcher-docs

    PRs Opened

    Week PR
    5 #13 Add devcontainer support
    5 #14 Update Design page
    diff --git a/students/MadLamprey/progress.page-vue-render.js b/students/MadLamprey/progress.page-vue-render.js index 542610374..4293f4f1e 100644 --- a/students/MadLamprey/progress.page-vue-render.js +++ b/students/MadLamprey/progress.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('h3',{attrs:{"id":"summary"}},[_v("Summary"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#summary","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("In WATcher, I primarily identified critical UI issues, significantly enhancing interface and service functionalities to boost user experience and application efficiency. I also contributed to the documentation of WATcher to aid future development. In CATcher, my focus was on migrating the linter from TSLint to ESLint, a crucial step that enhanced code quality and facilitated better maintainability.")]),_v(" "),_c('h3',{attrs:{"id":"details"}},[_v("Details"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#details","onclick":"event.stopPropagation()"}})]),_v(" "),_c('h4',{attrs:{"id":"catcher"}},[_v("CATcher"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#catcher","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_c('strong',[_v("PRs Opened")])]),_v(" "),_c('div',{staticClass:"table-responsive"},[_c('table',{staticClass:"markbind-table table table-bordered table-striped"},[_c('thead',[_c('tr',[_c('th',[_v("Week")]),_v(" "),_c('th',[_v("PR")])])]),_v(" "),_c('tbody',[_c('tr',[_c('td',[_v("2")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher/pull/1237"}},[_v("#1237")]),_v(" Add whitespace validation")])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher/pull/1250"}},[_v("#1250")]),_v(" Migrate from TSLint to ESLint")])])])])]),_c('h4',{attrs:{"id":"watcher"}},[_v("WATcher"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#watcher","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_c('strong',[_v("Issues Created")])]),_v(" "),_c('div',{staticClass:"table-responsive"},[_c('table',{staticClass:"markbind-table table table-bordered table-striped"},[_c('thead',[_c('tr',[_c('th',[_v("Week")]),_v(" "),_c('th',[_v("Issue")])])]),_v(" "),_c('tbody',[_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/266"}},[_v("#266")]),_v(" Upgrade to Angular 12")])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/361"}},[_v("#361")]),_v(" Make ItemsPerPage common for all card views")])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/363"}},[_v("#363")]),_v(" Remodel the design of the Filter bar")])])])])]),_c('p',[_c('strong',[_v("PRs Opened")])]),_v(" "),_c('div',{staticClass:"table-responsive"},[_c('table',{staticClass:"markbind-table table table-bordered table-striped"},[_c('thead',[_c('tr',[_c('th',[_v("Week")]),_v(" "),_c('th',[_v("PR")])])]),_v(" "),_c('tbody',[_c('tr',[_c('td',[_v("2")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/228"}},[_v("#228")]),_v(" Prevent redirection when repo not set")])]),_v(" "),_c('tr',[_c('td',[_v("4")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/252"}},[_v("#252")]),_v(" Upgrade to Angular 11")])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/267"}},[_v("#267")]),_v(" Upgrade to Angular 12")])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/286"}},[_v("#286")]),_v(" Remove sorting by assignees in Issue Sorter")])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/303"}},[_v("#303")]),_v(" Create tests for Milestone service")])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/304"}},[_v("#304")]),_v(" Create tests for Error Handling service")])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/307"}},[_v("#307")]),_v(" Add tool tip for hidden users")])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/315"}},[_v("#315")]),_v(" Split 'Without a milestone' option")])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/318"}},[_v("#318")]),_v(" Add sorting by Status")])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/337"}},[_v("#337")]),_v(" Add icon for PRs without milestones")])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/362"}},[_v("#362")]),_v(" Make ItemsPerPage common for all card views")])])])])]),_c('p',[_c('strong',[_v("PRs Reviewed")])]),_v(" "),_c('div',{staticClass:"table-responsive"},[_c('table',{staticClass:"markbind-table table table-bordered table-striped"},[_c('thead',[_c('tr',[_c('th',[_v("Week")]),_v(" "),_c('th',[_v("PR")])])]),_v(" "),_c('tbody',[_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/260"}},[_v("#260")]),_v(" Remove test cases for permissions service")])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/313"}},[_v("#313")]),_v(" Integrate Grouping Service")])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/334"}},[_v("#334")]),_v(" Fix default preset view")])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"xhttps://github.com/CATcher-org/WATcher/pull/350"}},[_v("#350")]),_v(" Deploy v1.2.1")])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/351"}},[_v("#351")]),_v(" Enable automated testing on the deploy branch")])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/364"}},[_v("#364")]),_v(" Create release V1.2.2")])])])])]),_c('h4',{attrs:{"id":"watcher-docs"}},[_v("WATcher-docs"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#watcher-docs","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_c('strong',[_v("PRs Opened")])]),_v(" "),_c('div',{staticClass:"table-responsive"},[_c('table',{staticClass:"markbind-table table table-bordered table-striped"},[_c('thead',[_c('tr',[_c('th',[_v("Week")]),_v(" "),_c('th',[_v("PR")])])]),_v(" "),_c('tbody',[_c('tr',[_c('td',[_v("5")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher-docs/pull/13"}},[_v("#13")]),_v(" Add devcontainer support")])]),_v(" "),_c('tr',[_c('td',[_v("5")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher-docs/pull/14"}},[_v("#14")]),_v(" Update Design page")])])])])])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/MarcusTXK/info.html b/students/MarcusTXK/info.html index 921aa6392..bc90c61dc 100644 --- a/students/MarcusTXK/info.html +++ b/students/MarcusTXK/info.html @@ -12,7 +12,7 @@ const baseUrl = '/2024' - + diff --git a/students/MarcusTXK/info.page-vue-render.js b/students/MarcusTXK/info.page-vue-render.js index 2c07bd8f9..bd46dc8e5 100644 --- a/students/MarcusTXK/info.page-vue-render.js +++ b/students/MarcusTXK/info.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('p',[_c('span',{attrs:{"id":"github"}},[_c('a',{attrs:{"href":"https://www.github.com/MarcusTXK"}},[_v("https://www.github.com/MarcusTXK")])])]),_v(" "),_c('p',[_c('span',{attrs:{"id":"projects"}},[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense"}},[_v("RepoSense")])])])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/MarcusTXK/knowledge.html b/students/MarcusTXK/knowledge.html index 70b512130..6fcedbe9b 100644 --- a/students/MarcusTXK/knowledge.html +++ b/students/MarcusTXK/knowledge.html @@ -13,7 +13,7 @@

    DevOps

    Gradle

    Gradle is a build tool designed specifically to meet the requirements of building Java applications. Once it’s set up, building an application is as simple as running a single command on the command line. Gradle performs well and is also useful for managing dependencies via its advanced dependency management system.

    Learned about Gradle through a really helpful tutorial.

    Bash and Batch Scripting

    I learned how to write basic bash scripts via tutorialspoint, and had to implement batch scripts to perform environmental checks for all files tracked by git, to ensure they end with a newline, no prohibited line endings (\r\n) are present and no trailing whitespaces are present.

    Some interesting bugs were encountered when attempting to use pipes in batch files, particularly one that prevents delayed expansion of variables from being properly evaluated as per usual. This is due to variables not being evaluated in the batch context, as the lines are executed only in the cmd-line context. A more detailed analysis of the bug is done by a user of stackoverflow.

    Codecov

    As I explored Codecov to determine why it would intermittently fail for GitHub actions, I developed a greater appreciation for the role of code coverage analysis in ensuring software quality. I found its integration with popular CI/CD platforms to be seamless, making it easier to track and improve code coverage across projects. The visualization tools, such as the sunburst graph and diff coverage reports, were especially helpful in identifying areas that needed more testing attention. Furthermore, learning about Codecov's ability to enforce coverage thresholds and generate pull request comments reinforced the importance of maintaining high-quality test suites.

    Frontend

    Vue

    Vue is a progressive JavaScript framework that simplifies the creation of responsive and efficient web applications. Its reactive data-binding and component-based architecture promote modular programming, resulting in more maintainable and scalable code. Learning about Vue's component-based architecture also expanded my understanding of modular programming and how it can lead to more maintainable and scalable code.

    Pug

    Pug is a templating engine that integrates well with Vue, allowing for cleaner and more concise HTML code with the use of whitespace and indentation for structure. By removing the need for closing tags, Pug attempts to make code more readable and organized. Its support for variables, mixins, and inheritance facilitates code reusability and modular design, improving the overall structure and readability of templates.

    Cypress

    Cypress is an end-to-end testing framework that simplifies the process of writing and executing tests for web applications. Its intuitive syntax, real-time reloading, and support for network stubbing improve debugging and development efficiency, emphasizing thorough testing. I found its syntax and API to be intuitive and user-friendly, making the process of writing and executing tests more enjoyable. I was particularly impressed with the real-time reloading feature, which allows for faster debugging and development, simplifying E2E testing.

    Backend

    Bloch’s Builder Pattern

    Bloch’s Builder pattern is a design pattern that simplifies object instantiation in Java, particularly for classes with numerous constructor parameters, as it simplifies the process of object instantiation while maintaining immutability and improving readability. This was a particularly useful design pattern when refactoring the CliArguments.java class, as it had a large number of constructor parameters, and also required flexible construction as some of the fields were optional. The pattern facilitates immutability and reduces the risk of introducing errors in complex Java classes. Read more about here on Oracle's blog.

    Polymorphism

    Polymorphism is a core object-oriented programming concept in Java that allows objects to adopt multiple forms and behaviors based on their context. It promotes code cleanliness, extensibility, and reduces coupling between components, resulting in more flexible and modular applications that can evolve and scale easily. By leveraging polymorphism, I was able to reduce the amount of logic in the main method of RepoSense.java, by utilizing RunConfigurationDecider to return the appropriate RunConfiguration based on the CliArguments, where the config can be from getRepoConfigurations().

    Discrete Event Simulator (DES)

    Discrete event simulator (DES) is a method used to model real-world systems that can be decomposed into a set of logically separate processes that autonomously progress through time. This was a design that was well suited for designing a CLI Wizard, as it allows for maintaining of a deque of prompts that to be shown to the user, while also allowing the addition of new prompts into the deque depending on the user's responses.

    Misc

    Git Commmands/Functionalities

    In RepoSense, a variety of git commands are utilized to get information about the repository. Through undertaking DevOps tasks, I was also exposed to other interesting git commands. Here are some of the interesting ones that I was not aware of before.

    git shortlog - Summarizes git log output, where each commit will be grouped by author and title. This is used in RepoSense to easily count the commits by the users.

    git grep - A powerful tool that looks for specified patterns in the tracked files in the work tree, blobs registered in the index file, or blobs in given tree objects. Patterns are lists of one or more search expressions separated by newline characters. An empty string as search expression matches all lines. Utilized to write Reposense scripts to perform environmental checks for all files tracked by git, to ensure they end with a newline, no prohibited line endings (\r\n) are present and no trailing whitespaces are present. Used git docs to learn how to use git grep properly and what its various flags do.

    .mailmap - If the file .mailmap exists at the top-level of the repository, it can be used to map author and committer names and email addresses to canonical real names and email addresses. This is useful to map multiple authors and commenters and provides a way to share the mapping with all other users of the repository. Used git docs to learn how to configure git mailmap properly.

    URL Shortening

    Researched interesting solutions for free URL shortening, looking into 3 main ways to do it. Read about an in-depth writeup in the -Github issue here.

    +Github issue here.

    diff --git a/students/MarcusTXK/knowledge.page-vue-render.js b/students/MarcusTXK/knowledge.page-vue-render.js index 4f9297263..62d88b0ff 100644 --- a/students/MarcusTXK/knowledge.page-vue-render.js +++ b/students/MarcusTXK/knowledge.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('h2',{attrs:{"id":"devops"}},[_v("DevOps"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#devops","onclick":"event.stopPropagation()"}})]),_v(" "),_c('h3',{attrs:{"id":"gradle"}},[_v("Gradle"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#gradle","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Gradle is a build tool designed specifically to meet the requirements of building Java applications. Once it’s set up, building an application is as simple as running a single command on the command line. Gradle performs well and is also useful for managing dependencies via its advanced dependency management system.")]),_v(" "),_c('p',[_v("Learned about Gradle through a really "),_c('a',{attrs:{"href":"https://tomgregory.com/gradle-tutorial-for-complete-beginners/"}},[_v("helpful tutorial")]),_v(".")]),_v(" "),_c('h3',{attrs:{"id":"bash-and-batch-scripting"}},[_v("Bash and Batch Scripting"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#bash-and-batch-scripting","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("I learned how to write basic bash scripts via "),_c('a',{attrs:{"href":"https://www.tutorialspoint.com/batch_script/index.htm"}},[_v("tutorialspoint")]),_v(", and had to implement batch scripts to perform environmental checks for all files tracked by git, to ensure they end with a newline, no prohibited line endings ("),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("\\r\\n")]),_v(") are present and no trailing whitespaces are present.")]),_v(" "),_c('p',[_v("Some interesting bugs were encountered when attempting to use pipes in batch files, particularly one that prevents delayed expansion of variables from being properly evaluated as per usual. This is due to variables not being evaluated in the batch context, as the lines are executed only in the cmd-line context. A more detailed analysis of the bug is done by a user of "),_c('a',{attrs:{"href":"https://stackoverflow.com/questions/8192318/why-does-delayed-expansion-fail-when-inside-a-piped-block-of-code"}},[_v("stackoverflow")]),_v(".")]),_v(" "),_c('h3',{attrs:{"id":"codecov"}},[_v("Codecov"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#codecov","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("As I explored "),_c('a',{attrs:{"href":"https://about.codecov.io/"}},[_v("Codecov")]),_v(" to determine why it would intermittently fail for GitHub actions, I developed a greater appreciation for the role of code coverage analysis in ensuring software quality. I found its integration with popular CI/CD platforms to be seamless, making it easier to track and improve code coverage across projects. The visualization tools, such as the "),_c('a',{attrs:{"href":"https://docs.codecov.com/docs/graphs#sunburst"}},[_v("sunburst graph")]),_v(" and "),_c('a',{attrs:{"href":"https://docs.codecov.com/docs/comparing-commits"}},[_v("diff coverage reports")]),_v(", were especially helpful in identifying areas that needed more testing attention. Furthermore, learning about Codecov's ability to enforce coverage thresholds and generate pull request comments reinforced the importance of maintaining high-quality test suites.")]),_v(" "),_c('h2',{attrs:{"id":"frontend"}},[_v("Frontend"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#frontend","onclick":"event.stopPropagation()"}})]),_v(" "),_c('h3',{attrs:{"id":"vue"}},[_v("Vue"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#vue","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_c('a',{attrs:{"href":"https://vuejs.org/"}},[_v("Vue")]),_v(" is a progressive JavaScript framework that simplifies the creation of responsive and efficient web applications. Its reactive "),_c('a',{attrs:{"href":"https://www.javatpoint.com/vue-js-data-binding"}},[_v("data-binding")]),_v(" and "),_c('a',{attrs:{"href":"https://vuex.vuejs.org/guide/structure.html"}},[_v("component-based architecture")]),_v(" promote modular programming, resulting in more maintainable and scalable code. Learning about Vue's component-based architecture also expanded my understanding of modular programming and how it can lead to more maintainable and scalable code.")]),_v(" "),_c('h3',{attrs:{"id":"pug"}},[_v("Pug"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#pug","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_c('a',{attrs:{"href":"https://pugjs.org/api/getting-started.html"}},[_v("Pug")]),_v(" is a templating engine that integrates well with Vue, allowing for cleaner and more concise HTML code with the use of whitespace and indentation for structure. By removing the need for closing tags, Pug attempts to make code more readable and organized. Its support for variables, mixins, and inheritance facilitates code reusability and modular design, improving the overall structure and readability of templates.")]),_v(" "),_c('h3',{attrs:{"id":"cypress"}},[_v("Cypress"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#cypress","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_c('a',{attrs:{"href":"https://www.cypress.io/"}},[_v("Cypress")]),_v(" is an end-to-end testing framework that simplifies the process of writing and executing tests for web applications. Its intuitive syntax, real-time reloading, and support for network stubbing improve debugging and development efficiency, emphasizing thorough testing. I found its syntax and API to be intuitive and user-friendly, making the process of writing and executing tests more enjoyable. I was particularly impressed with the real-time reloading feature, which allows for faster debugging and development, simplifying "),_c('a',{attrs:{"href":"https://docs.cypress.io/guides/end-to-end-testing/writing-your-first-end-to-end-test"}},[_v("E2E")]),_v(" testing.")]),_v(" "),_c('h2',{attrs:{"id":"backend"}},[_v("Backend"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#backend","onclick":"event.stopPropagation()"}})]),_v(" "),_c('h3',{attrs:{"id":"bloch-s-builder-pattern"}},[_v("Bloch’s Builder Pattern"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#bloch-s-builder-pattern","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Bloch’s Builder pattern is a design pattern that simplifies object instantiation in Java, particularly for classes with numerous constructor parameters, as it simplifies the process of object instantiation while maintaining immutability and improving readability. This was a particularly useful design pattern when refactoring the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("CliArguments.java")]),_v(" class, as it had a large number of constructor parameters, and also required flexible construction as some of the fields were optional. The pattern facilitates immutability and reduces the risk of introducing errors in complex Java classes. Read more about "),_c('a',{attrs:{"href":"https://blogs.oracle.com/javamagazine/post/exploring-joshua-blochs-builder-design-pattern-in-java"}},[_v("here")]),_v(" on Oracle's blog.")]),_v(" "),_c('h3',{attrs:{"id":"polymorphism"}},[_v("Polymorphism"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#polymorphism","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Polymorphism is a core object-oriented programming concept in Java that allows objects to adopt multiple forms and behaviors based on their context. It promotes code cleanliness, extensibility, and reduces coupling between components, resulting in more flexible and modular applications that can evolve and scale easily. By leveraging polymorphism, I was able to reduce the amount of logic in the main method of "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("RepoSense.java")]),_v(", by utilizing "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("RunConfigurationDecider")]),_v(" to return the appropriate "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("RunConfiguration")]),_v(" based on the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("CliArguments")]),_v(", where the config can be from "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("getRepoConfigurations()")]),_v(".")]),_v(" "),_c('h3',{attrs:{"id":"discrete-event-simulator-des"}},[_v("Discrete Event Simulator (DES)"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#discrete-event-simulator-des","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Discrete event simulator (DES) is a method used to model real-world systems that can be decomposed into a set of logically separate processes that autonomously progress through time. This was a design that was well suited for designing a CLI Wizard, as it allows for maintaining of a deque of prompts that to be shown to the user, while also allowing the addition of new prompts into the deque depending on the user's responses.")]),_v(" "),_c('h2',{attrs:{"id":"misc"}},[_v("Misc"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#misc","onclick":"event.stopPropagation()"}})]),_v(" "),_c('h3',{attrs:{"id":"git-commmands-functionalities"}},[_v("Git Commmands/Functionalities"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#git-commmands-functionalities","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("In RepoSense, a variety of git commands are utilized to get information about the repository. Through undertaking DevOps tasks, I was also exposed to other interesting git commands. Here are some of the interesting ones that I was not aware of before.")]),_v(" "),_c('p',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("git shortlog")]),_v(" - Summarizes "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("git log")]),_v(" output, where each commit will be grouped by author and title. This is used in RepoSense to easily count the commits by the users.")]),_v(" "),_c('p',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("git grep")]),_v(" - A powerful tool that looks for specified patterns in the tracked files in the work tree, blobs registered in the index file, or blobs in given tree objects. Patterns are lists of one or more search expressions separated by newline characters. An empty string as search expression matches all lines. Utilized to write Reposense scripts to perform environmental checks for all files tracked by git, to ensure they end with a newline, no prohibited line endings ("),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("\\r\\n")]),_v(") are present and no trailing whitespaces are present. Used "),_c('a',{attrs:{"href":"https://git-scm.com/docs/git-grep"}},[_v("git docs")]),_v(" to learn how to use "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("git grep")]),_v(" properly and what its various flags do.")]),_v(" "),_c('p',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v(".mailmap")]),_v(" - If the file .mailmap exists at the top-level of the repository, it can be used to map author and committer names and email addresses to canonical real names and email addresses. This is useful to map multiple authors and commenters and provides a way to share the mapping with all other users of the repository. Used "),_c('a',{attrs:{"href":"https://git-scm.com/docs/git-grep"}},[_v("git docs")]),_v(" to learn how to configure git mailmap properly.")]),_v(" "),_c('h3',{attrs:{"id":"url-shortening"}},[_v("URL Shortening"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#url-shortening","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Researched interesting solutions for free URL shortening, looking into 3 main ways to do it. Read about an in-depth writeup in "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/issues/1898"}},[_v("the\nGithub issue here")]),_v(".")])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/MarcusTXK/observations.html b/students/MarcusTXK/observations.html index 4b9414fd7..75a8f07d0 100644 --- a/students/MarcusTXK/observations.html +++ b/students/MarcusTXK/observations.html @@ -12,7 +12,7 @@ const baseUrl = '/2024' -

    Project: Supabase

    Overview

    Supabase is a prominent open-source alternative to Firebase, aiming to replicate Firebase's features using enterprise-grade open-source tools. It offers a robust platform for developers to build scalable and reliable applications with ease.

    Supabase Auth, part of the Supabase ecosystem, is a user management and authentication server written in Go. It facilitates key functionalities such as JWT issuance, Row Level Security with PostgREST, comprehensive user management, and a variety of authentication methods including email/password, magic links, phone numbers, and external providers like Google, Apple, Facebook, and Discord. Originating from Netlify's Auth codebase, it has since evolved significantly in terms of features and capabilities.

    My Contributions

    Below is a summary of my contributions to Supabase, on both Supabase/supabase and Supabase/gotrue (to be renamed to supabase/auth):

    My Learning Record

    Through my contributions to Supabase, I've gained significant insights and knowledge:

    • Go Programming: Deepened understanding of Go, navigating and contributing to a sizable codebase.
    • Authentication Flows: Explored and learned various authentication mechanisms and flows.
    • Docker Usage: Enhanced skills in utilizing Docker for development and deployment purposes.

    Reflections on Contributing to Supabase

    • Contributing Guide: The Supabase Contributing Guide was instrumental in familiarizing myself with the contribution process.
    • Responsive Community: The responsiveness of the developer community greatly facilitated the contribution experience, as it made discussions for the PR easier
    • Issue Management: My experience on Supabase emphasized the importance of maintaining issues, particularly for first time issues. There weren't many first time issues, and for some of them, they were no longer required even though they were still open. This resulted in wasted work on a no longer relevant issue.
    • First-Come, First-Served Approach: Supabase chose to have a first come first served approach to issue assignment, which avoids the pitfall of issue hoarding or being occuipied by an inactive contributer, by being open to public contribution without explicit assignment.

    Suggestions for Improvement

    While my experience contributing to Supabase was largely positive, I identified areas for enhancement:

    • Issue Management: There's a need for more active management of issues, especially those labeled for beginners, to prevent contributors from spending time on outdated or resolved issues.

    Applying Supabase Practices to NUS-OSS Projects

    From my engagement with Supabase, I've identified practices that could benefit NUS-OSS projects, particularly the use of Docker for simplifying project setup and ensuring consistency across development environments. This helped save alot of time by avoiding complicated manual setups, and allowed me to focus on resolving the issues.

    +

    Project: Supabase

    Overview

    Supabase is a prominent open-source alternative to Firebase, aiming to replicate Firebase's features using enterprise-grade open-source tools. It offers a robust platform for developers to build scalable and reliable applications with ease.

    Supabase Auth, part of the Supabase ecosystem, is a user management and authentication server written in Go. It facilitates key functionalities such as JWT issuance, Row Level Security with PostgREST, comprehensive user management, and a variety of authentication methods including email/password, magic links, phone numbers, and external providers like Google, Apple, Facebook, and Discord. Originating from Netlify's Auth codebase, it has since evolved significantly in terms of features and capabilities.

    My Contributions

    Below is a summary of my contributions to Supabase, on both Supabase/supabase and Supabase/gotrue (to be renamed to supabase/auth):

    My Learning Record

    Through my contributions to Supabase, I've gained significant insights and knowledge:

    • Go Programming: Deepened understanding of Go, navigating and contributing to a sizable codebase.
    • Authentication Flows: Explored and learned various authentication mechanisms and flows.
    • Docker Usage: Enhanced skills in utilizing Docker for development and deployment purposes.

    Reflections on Contributing to Supabase

    • Contributing Guide: The Supabase Contributing Guide was instrumental in familiarizing myself with the contribution process.
    • Responsive Community: The responsiveness of the developer community greatly facilitated the contribution experience, as it made discussions for the PR easier
    • Issue Management: My experience on Supabase emphasized the importance of maintaining issues, particularly for first time issues. There weren't many first time issues, and for some of them, they were no longer required even though they were still open. This resulted in wasted work on a no longer relevant issue.
    • First-Come, First-Served Approach: Supabase chose to have a first come first served approach to issue assignment, which avoids the pitfall of issue hoarding or being occuipied by an inactive contributer, by being open to public contribution without explicit assignment.

    Suggestions for Improvement

    While my experience contributing to Supabase was largely positive, I identified areas for enhancement:

    • Issue Management: There's a need for more active management of issues, especially those labeled for beginners, to prevent contributors from spending time on outdated or resolved issues.

    Applying Supabase Practices to NUS-OSS Projects

    From my engagement with Supabase, I've identified practices that could benefit NUS-OSS projects, particularly the use of Docker for simplifying project setup and ensuring consistency across development environments. This helped save alot of time by avoiding complicated manual setups, and allowed me to focus on resolving the issues.

    diff --git a/students/MarcusTXK/observations.page-vue-render.js b/students/MarcusTXK/observations.page-vue-render.js index b8fcfea98..668171aac 100644 --- a/students/MarcusTXK/observations.page-vue-render.js +++ b/students/MarcusTXK/observations.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('h3',{attrs:{"id":"project-supabase"}},[_v("Project: Supabase"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#project-supabase","onclick":"event.stopPropagation()"}})]),_v(" "),_c('h4',{attrs:{"id":"overview"}},[_v("Overview"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#overview","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_c('a',{attrs:{"href":"https://supabase.io/"}},[_v("Supabase")]),_v(" is a prominent open-source alternative to Firebase, aiming to replicate Firebase's features using enterprise-grade open-source tools. It offers a robust platform for developers to build scalable and reliable applications with ease.")]),_v(" "),_c('p',[_v("Supabase Auth, part of the Supabase ecosystem, is a user management and authentication server written in Go. It facilitates key functionalities such as JWT issuance, Row Level Security with PostgREST, comprehensive user management, and a variety of authentication methods including email/password, magic links, phone numbers, and external providers like Google, Apple, Facebook, and Discord. Originating from Netlify's Auth codebase, it has since evolved significantly in terms of features and capabilities.")]),_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("Below is a summary of my contributions to Supabase, on both Supabase/supabase and Supabase/gotrue (to be renamed to supabase/auth):")]),_v(" "),_c('div',{staticClass:"table-responsive"},[_c('table',{staticClass:"markbind-table table table-bordered table-striped"},[_c('thead',[_c('tr',[_c('th',[_v("Date")]),_v(" "),_c('th',[_v("Achievement")])])]),_v(" "),_c('tbody',[_c('tr',[_c('td',[_v("12/23")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/supabase/supabase/pull/19974"}},[_v("[#19825] Update "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("SIGNED_IN")]),_v(" event documentation (#19974)")])])]),_v(" "),_c('tr',[_c('td',[_v("12/23")]),_v(" "),_c('td',[_v("Created issue for discovered security vulnerability: "),_c('a',{attrs:{"href":"https://github.com/supabase/gotrue/issues/1365"}},[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("signUp")]),_v(" leaking existing user role #1365")])])]),_v(" "),_c('tr',[_c('td',[_v("12/23")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/supabase/gotrue/pull/1366"}},[_v("fix: sanitizeUser leaks user role (#1366)")]),_v(" s")])]),_v(" "),_c('tr',[_c('td',[_v("12/23")]),_v(" "),_c('td',[_v("Created PR: "),_c('a',{attrs:{"href":"https://github.com/supabase/gotrue/pull/1367"}},[_v("[#880] Add function to get user by email identities (#1367)")])])]),_v(" "),_c('tr',[_c('td',[_v("12/23")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/supabase/gotrue/pull/1368"}},[_v("fix: add check for max password length (#1368)")])])]),_v(" "),_c('tr',[_c('td',[_v("12/23")]),_v(" "),_c('td',[_v("Discussion on potential solutions for: "),_c('a',{attrs:{"href":"https://github.com/supabase/gotrue/issues/1236"}},[_v("Email rate limit is triggered even in scenarios where an email doesn't end up being sent (#1236)")])])])])])]),_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("Through my contributions to Supabase, I've gained significant insights and knowledge:")]),_v(" "),_c('ul',[_c('li',[_c('strong',[_v("Go Programming:")]),_v(" Deepened understanding of Go, navigating and contributing to a sizable codebase.")]),_v(" "),_c('li',[_c('strong',[_v("Authentication Flows:")]),_v(" Explored and learned various authentication mechanisms and flows.")]),_v(" "),_c('li',[_c('strong',[_v("Docker Usage:")]),_v(" Enhanced skills in utilizing Docker for development and deployment purposes.")])]),_v(" "),_c('h4',{attrs:{"id":"reflections-on-contributing-to-supabase"}},[_v("Reflections on Contributing to Supabase"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#reflections-on-contributing-to-supabase","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ul',[_c('li',[_c('strong',[_v("Contributing Guide:")]),_v(" The "),_c('a',{attrs:{"href":"https://github.com/supabase/gotrue/blob/master/CONTRIBUTING.md"}},[_v("Supabase Contributing Guide")]),_v(" was instrumental in familiarizing myself with the contribution process.")]),_v(" "),_c('li',[_c('strong',[_v("Responsive Community:")]),_v(" The responsiveness of the developer community greatly facilitated the contribution experience, as it made discussions for the PR easier")]),_v(" "),_c('li',[_c('strong',[_v("Issue Management:")]),_v(" My experience on Supabase emphasized the importance of maintaining issues, particularly for first time issues. There weren't many first time issues, and for some of them, they were no longer required even though they were still open. This resulted in wasted work on a no longer relevant issue.")]),_v(" "),_c('li',[_c('strong',[_v("First-Come, First-Served Approach:")]),_v(" Supabase chose to have a first come first served approach to issue assignment, which avoids the pitfall of issue hoarding or being occuipied by an inactive contributer, by being open to public contribution without explicit assignment.")])]),_v(" "),_c('h4',{attrs:{"id":"suggestions-for-improvement"}},[_v("Suggestions for Improvement"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#suggestions-for-improvement","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("While my experience contributing to Supabase was largely positive, I identified areas for enhancement:")]),_v(" "),_c('ul',[_c('li',[_c('strong',[_v("Issue Management:")]),_v(" There's a need for more active management of issues, especially those labeled for beginners, to prevent contributors from spending time on outdated or resolved issues.")])]),_v(" "),_c('h4',{attrs:{"id":"applying-supabase-practices-to-nus-oss-projects"}},[_v("Applying Supabase Practices to NUS-OSS Projects"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#applying-supabase-practices-to-nus-oss-projects","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("From my engagement with Supabase, I've identified practices that could benefit NUS-OSS projects, particularly the use of Docker for simplifying project setup and ensuring consistency across development environments. This helped save alot of time by avoiding complicated manual setups, and allowed me to focus on resolving the issues.")])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/MarcusTXK/progress.html b/students/MarcusTXK/progress.html index da2c7ccfc..4e81524cd 100644 --- a/students/MarcusTXK/progress.html +++ b/students/MarcusTXK/progress.html @@ -12,7 +12,7 @@ const baseUrl = '/2024' -

    Summary

    • Reviewed PRs of CS3281 students and FYP for RepoSense
    • Created issues as well as suggested/discussed new issues for CS3281 students to create
    • Guided with CS3281 mentees physically as well as over telegram
    • Reviewed scripts and slides + had dry runs with CS3282 RepoSense members for lightning talks
    • Contributed to Supabase with 3 merged PRs and 1 issue (+ 1 unmerged PR)
    Week Achievements
    13/05/2023 Reviewed PR: Fix non-rendering PlantUML diagram #2005
    28/06/2023 Reviewed PR: Incorrect dropdown box for config in UG: Customizing Report #2009
    17/08/2023 Reviewed PR: Increase minimum version required for Git #2028
    01/10/2023 Reviewed PR: Migrate build.gradle from Groovy to Kotlin #2008
    01/10/2023 Reviewed PR: Migrate c-resizer.vue to typescript #2038
    01/10/2023 Reviewed PR: Migrate random-color-gen.js to typescript #2043
    30/10/2023 Reviewed PR: Update GitHub-specific references in codebase and docs #2050
    30/10/2023 Reviewed PR: Add dynamic positioning support for tooltips #2056
    30/10/2023 Reviewed PR: Fix tooltip zIndex such that it doesn't occlude next file title #2057
    30/10/2023 Reviewed PR: Add contributors section to the README #2062
    31/10/2023 Reviewed PR: Fix: Added contributors to the README.md #2064
    02/11/2023 Reviewed PR: Created CONTRIBUTING.md #2065
    23/12/2023 Reviewed PR: Reduce scope of try-catch block in ArgsParser::parse #2074
    23/12/2023 Reviewed PR: Move TimeUtil ParseException throwing to ArgsParser::parse method #2075
    23/12/2023 Commented on Issue: Reduce the scope of the try-catch block in ArgsParser::parse #1989
    23/12/2023 Created Issue: Refactor RepoConfigCsvParser::processLine method to avoid arrowhead style code #2073
    23/12/2023 Created Issue: Refactor RepoConfiguration to simplify constructor complexity #2076
    1 Reviewed PR: Bump follow-redirects from 1.15.2 to 1.15.4 in /frontend #2079
    1 Reviewed PR: Refactor RepoConfigCsvParser::processLine method to avoid arrowhead style code #2080
    2 Reviewed PR: Remove hash symbol from URL when decoding hash #2086
    2 Reviewed PR: Remove redundant User class #2093
    2 Reviewed PR: Add cypress tests for renderFilterHash #2017
    2 Reviewed PR: Improve memory usage by refactoring Regex compilation #2092
    3 Reviewed PR: Use syntax coloring for code blocks in docs #2099
    3 Closed Issue: Forward/Backward Navigation Using Browser Buttons #2090
    4 Reviewed PR: Updating SystemTestUtil::assertJson to compare Json objects instead of line-by-line analysis #2087
    4 Reviewed PR: Refactor RepoConfiguration to simplify constructor complexity #2078
    5 Created Issue: Fix failing cypress test for range changes in chartview #2111
    6 Reviewed PR: Refactor CliArguments to conform to RepoConfiguration's Builder Pattern #2118
    R Reviewed PR: Add originality threshold flag #2122
    7 Reviewed PR: Improve performance #2108
    9 Reviewed PR: Minor Enhancements to Existing Regex Code #2115
    9 Reviewed PR: Bump follow-redirects from 1.15.4 to 1.15.6 in /frontend #2160
    9 Reviewed PR: Revert "[#2109] Add search by tag functionality" #2165
    10 Reviewed PR: Fix Vulnerabilities #2143
    10 Reviewed PR: Update LoadingOverlay and Minor Versions of Node Dependencies #2152
    10 Reviewed PR: Bump webpack-dev-middleware from 5.3.3 to 5.3.4 in /frontend #2168
    11 Reviewed PR: Fix lint warnings #2182
    11 Reviewed PR: Fix Inconsistent Line Number Colours #2185
    12 Reviewed PR: Update CSS-related Major Dependencies #2154
    13 Reviewed PR: Implement authorship analysis #2140
    R Reviewed PR: Add optimise timeline feature #2180
    R Reviewed PR: Move from Vue CLI to Vite #2178
    +

    Summary

    • Reviewed PRs of CS3281 students and FYP for RepoSense
    • Created issues as well as suggested/discussed new issues for CS3281 students to create
    • Guided with CS3281 mentees physically as well as over telegram
    • Reviewed scripts and slides + had dry runs with CS3282 RepoSense members for lightning talks
    • Contributed to Supabase with 3 merged PRs and 1 issue (+ 1 unmerged PR)
    Week Achievements
    13/05/2023 Reviewed PR: Fix non-rendering PlantUML diagram #2005
    28/06/2023 Reviewed PR: Incorrect dropdown box for config in UG: Customizing Report #2009
    17/08/2023 Reviewed PR: Increase minimum version required for Git #2028
    01/10/2023 Reviewed PR: Migrate build.gradle from Groovy to Kotlin #2008
    01/10/2023 Reviewed PR: Migrate c-resizer.vue to typescript #2038
    01/10/2023 Reviewed PR: Migrate random-color-gen.js to typescript #2043
    30/10/2023 Reviewed PR: Update GitHub-specific references in codebase and docs #2050
    30/10/2023 Reviewed PR: Add dynamic positioning support for tooltips #2056
    30/10/2023 Reviewed PR: Fix tooltip zIndex such that it doesn't occlude next file title #2057
    30/10/2023 Reviewed PR: Add contributors section to the README #2062
    31/10/2023 Reviewed PR: Fix: Added contributors to the README.md #2064
    02/11/2023 Reviewed PR: Created CONTRIBUTING.md #2065
    23/12/2023 Reviewed PR: Reduce scope of try-catch block in ArgsParser::parse #2074
    23/12/2023 Reviewed PR: Move TimeUtil ParseException throwing to ArgsParser::parse method #2075
    23/12/2023 Commented on Issue: Reduce the scope of the try-catch block in ArgsParser::parse #1989
    23/12/2023 Created Issue: Refactor RepoConfigCsvParser::processLine method to avoid arrowhead style code #2073
    23/12/2023 Created Issue: Refactor RepoConfiguration to simplify constructor complexity #2076
    1 Reviewed PR: Bump follow-redirects from 1.15.2 to 1.15.4 in /frontend #2079
    1 Reviewed PR: Refactor RepoConfigCsvParser::processLine method to avoid arrowhead style code #2080
    2 Reviewed PR: Remove hash symbol from URL when decoding hash #2086
    2 Reviewed PR: Remove redundant User class #2093
    2 Reviewed PR: Add cypress tests for renderFilterHash #2017
    2 Reviewed PR: Improve memory usage by refactoring Regex compilation #2092
    3 Reviewed PR: Use syntax coloring for code blocks in docs #2099
    3 Closed Issue: Forward/Backward Navigation Using Browser Buttons #2090
    4 Reviewed PR: Updating SystemTestUtil::assertJson to compare Json objects instead of line-by-line analysis #2087
    4 Reviewed PR: Refactor RepoConfiguration to simplify constructor complexity #2078
    5 Created Issue: Fix failing cypress test for range changes in chartview #2111
    6 Reviewed PR: Refactor CliArguments to conform to RepoConfiguration's Builder Pattern #2118
    R Reviewed PR: Add originality threshold flag #2122
    7 Reviewed PR: Improve performance #2108
    9 Reviewed PR: Minor Enhancements to Existing Regex Code #2115
    9 Reviewed PR: Bump follow-redirects from 1.15.4 to 1.15.6 in /frontend #2160
    9 Reviewed PR: Revert "[#2109] Add search by tag functionality" #2165
    10 Reviewed PR: Fix Vulnerabilities #2143
    10 Reviewed PR: Update LoadingOverlay and Minor Versions of Node Dependencies #2152
    10 Reviewed PR: Bump webpack-dev-middleware from 5.3.3 to 5.3.4 in /frontend #2168
    11 Reviewed PR: Fix lint warnings #2182
    11 Reviewed PR: Fix Inconsistent Line Number Colours #2185
    12 Reviewed PR: Update CSS-related Major Dependencies #2154
    13 Reviewed PR: Implement authorship analysis #2140
    R Reviewed PR: Add optimise timeline feature #2180
    R Reviewed PR: Move from Vue CLI to Vite #2178
    diff --git a/students/MarcusTXK/progress.page-vue-render.js b/students/MarcusTXK/progress.page-vue-render.js index b524a4589..0118b97b8 100644 --- a/students/MarcusTXK/progress.page-vue-render.js +++ b/students/MarcusTXK/progress.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('h3',{attrs:{"id":"summary"}},[_v("Summary"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#summary","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ul',[_c('li',[_v("Reviewed PRs of CS3281 students and FYP for RepoSense")]),_v(" "),_c('li',[_v("Created issues as well as suggested/discussed new issues for CS3281 students to create")]),_v(" "),_c('li',[_v("Guided with CS3281 mentees physically as well as over telegram")]),_v(" "),_c('li',[_v("Reviewed scripts and slides + had dry runs with CS3282 RepoSense members for lightning talks")]),_v(" "),_c('li',[_v("Contributed to Supabase with 3 merged PRs and 1 issue (+ 1 unmerged PR)")])]),_v(" "),_c('div',{staticClass:"table-responsive"},[_c('table',{staticClass:"markbind-table table table-bordered table-striped"},[_c('thead',[_c('tr',[_c('th',[_v("Week")]),_v(" "),_c('th',[_v("Achievements")])])]),_v(" "),_c('tbody',[_c('tr',[_c('td',[_v("13/05/2023")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2005"}},[_v("Fix non-rendering PlantUML diagram #2005")])])]),_v(" "),_c('tr',[_c('td',[_v("28/06/2023")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2009"}},[_v("Incorrect dropdown box for config in UG: Customizing Report #2009")])])]),_v(" "),_c('tr',[_c('td',[_v("17/08/2023")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2028"}},[_v("Increase minimum version required for Git #2028")])])]),_v(" "),_c('tr',[_c('td',[_v("01/10/2023")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2008"}},[_v("Migrate build.gradle from Groovy to Kotlin #2008")])])]),_v(" "),_c('tr',[_c('td',[_v("01/10/2023")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2038"}},[_v("Migrate c-resizer.vue to typescript #2038")])])]),_v(" "),_c('tr',[_c('td',[_v("01/10/2023")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2043"}},[_v("Migrate random-color-gen.js to typescript #2043")])])]),_v(" "),_c('tr',[_c('td',[_v("30/10/2023")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2050"}},[_v("Update GitHub-specific references in codebase and docs #2050")])])]),_v(" "),_c('tr',[_c('td',[_v("30/10/2023")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2056"}},[_v("Add dynamic positioning support for tooltips #2056")])])]),_v(" "),_c('tr',[_c('td',[_v("30/10/2023")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2057"}},[_v("Fix tooltip zIndex such that it doesn't occlude next file title #2057")])])]),_v(" "),_c('tr',[_c('td',[_v("30/10/2023")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2062"}},[_v("Add contributors section to the README #2062")])])]),_v(" "),_c('tr',[_c('td',[_v("31/10/2023")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2064"}},[_v("Fix: Added contributors to the README.md #2064")])])]),_v(" "),_c('tr',[_c('td',[_v("02/11/2023")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2065"}},[_v("Created CONTRIBUTING.md #2065")])])]),_v(" "),_c('tr',[_c('td',[_v("23/12/2023")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2074"}},[_v("Reduce scope of try-catch block in ArgsParser::parse #2074")])])]),_v(" "),_c('tr',[_c('td',[_v("23/12/2023")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2075"}},[_v("Move TimeUtil ParseException throwing to ArgsParser::parse method #2075")])])]),_v(" "),_c('tr',[_c('td',[_v("23/12/2023")]),_v(" "),_c('td',[_v("Commented on Issue: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/issues/1989"}},[_v("Reduce the scope of the try-catch block in ArgsParser::parse #1989")])])]),_v(" "),_c('tr',[_c('td',[_v("23/12/2023")]),_v(" "),_c('td',[_v("Created Issue: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/issues/2073"}},[_v("Refactor RepoConfigCsvParser::processLine method to avoid arrowhead style code #2073")])])]),_v(" "),_c('tr',[_c('td',[_v("23/12/2023")]),_v(" "),_c('td',[_v("Created Issue: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/issues/2076"}},[_v("Refactor RepoConfiguration to simplify constructor complexity #2076")])])]),_v(" "),_c('tr',[_c('td',[_v("1")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2079"}},[_v("Bump follow-redirects from 1.15.2 to 1.15.4 in /frontend #2079")])])]),_v(" "),_c('tr',[_c('td',[_v("1")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2080"}},[_v("Refactor RepoConfigCsvParser::processLine method to avoid arrowhead style code #2080")])])]),_v(" "),_c('tr',[_c('td',[_v("2")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2086"}},[_v("Remove hash symbol from URL when decoding hash #2086")])])]),_v(" "),_c('tr',[_c('td',[_v("2")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2093"}},[_v("Remove redundant User class #2093")])])]),_v(" "),_c('tr',[_c('td',[_v("2")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2017"}},[_v("Add cypress tests for renderFilterHash #2017")])])]),_v(" "),_c('tr',[_c('td',[_v("2")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2092"}},[_v("Improve memory usage by refactoring Regex compilation #2092")])])]),_v(" "),_c('tr',[_c('td',[_v("3")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2099"}},[_v("Use syntax coloring for code blocks in docs #2099")])])]),_v(" "),_c('tr',[_c('td',[_v("3")]),_v(" "),_c('td',[_v("Closed Issue: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/issues/2090"}},[_v("Forward/Backward Navigation Using Browser Buttons #2090")])])]),_v(" "),_c('tr',[_c('td',[_v("4")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2087"}},[_v("Updating SystemTestUtil::assertJson to compare Json objects instead of line-by-line analysis #2087")])])]),_v(" "),_c('tr',[_c('td',[_v("4")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2078"}},[_v("Refactor RepoConfiguration to simplify constructor complexity #2078")])])]),_v(" "),_c('tr',[_c('td',[_v("5")]),_v(" "),_c('td',[_v("Created Issue: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/issues/2111"}},[_v("Fix failing cypress test for range changes in chartview #2111")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2118"}},[_v("Refactor CliArguments to conform to RepoConfiguration's Builder Pattern #2118")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2122"}},[_v("Add originality threshold flag #2122")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2108"}},[_v("Improve performance #2108")])])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2115"}},[_v("Minor Enhancements to Existing Regex Code #2115")])])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2160"}},[_v("Bump follow-redirects from 1.15.4 to 1.15.6 in /frontend #2160")])])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2165"}},[_v("Revert \"[#2109] Add search by tag functionality\" #2165")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2143"}},[_v("Fix Vulnerabilities #2143")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2152"}},[_v("Update LoadingOverlay and Minor Versions of Node Dependencies #2152")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2168"}},[_v("Bump webpack-dev-middleware from 5.3.3 to 5.3.4 in /frontend #2168")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2182"}},[_v("Fix lint warnings #2182")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2185"}},[_v("Fix Inconsistent Line Number Colours #2185")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2154"}},[_v("Update CSS-related Major Dependencies #2154")])])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2140"}},[_v("Implement authorship analysis #2140")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2180"}},[_v("Add optimise timeline feature #2180")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2178"}},[_v("Move from Vue CLI to Vite #2178")])])])])])])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/NereusWB922/info.html b/students/NereusWB922/info.html index 1c38a6142..01ca3e984 100644 --- a/students/NereusWB922/info.html +++ b/students/NereusWB922/info.html @@ -12,7 +12,7 @@ const baseUrl = '/2024' - + diff --git a/students/NereusWB922/info.page-vue-render.js b/students/NereusWB922/info.page-vue-render.js index 3b305cdf8..9a7ed9a2f 100644 --- a/students/NereusWB922/info.page-vue-render.js +++ b/students/NereusWB922/info.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('p',[_c('span',{attrs:{"id":"github"}},[_c('a',{attrs:{"href":"https://github.com/NereusWB922"}},[_v("https://github.com/NereusWB922")])])]),_v(" "),_c('p',[_c('span',{attrs:{"id":"projects"}},[_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher"}},[_v("CATcher")]),_v(", "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher"}},[_v("WATcher")])])])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/NereusWB922/knowledge.html b/students/NereusWB922/knowledge.html index e1627e02c..d4a1a23e0 100644 --- a/students/NereusWB922/knowledge.html +++ b/students/NereusWB922/knowledge.html @@ -42,7 +42,7 @@ expect(changeCurrentRepositorySpy).toHaveBeenCalledWith(WATCHER_REPO); });

    Design Pattern

    Strategy Design Pattern

    The Strategy design pattern allows for the selection of algorithms at runtime by defining a family of interchangeable algorithms and encapsulating each one. It enables flexibility and easy extension of functionality without modifying existing code.

    I utilized the Strategy Design Pattern to implement a "Group by" feature that organizes issues / prs based on different criteria.

    Implementation of group by feature :

    +
  • Context (GroupingContextService): This service is used to apply the grouping strategies based on user selection.
  • diff --git a/students/NereusWB922/knowledge.page-vue-render.js b/students/NereusWB922/knowledge.page-vue-render.js index c0d9df495..9f3cfcf73 100644 --- a/students/NereusWB922/knowledge.page-vue-render.js +++ b/students/NereusWB922/knowledge.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('h3',{attrs:{"id":"angular"}},[_v("Angular"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#angular","onclick":"event.stopPropagation()"}})]),_v(" "),_c('h4',{attrs:{"id":"components"}},[_v("Components"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#components","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Components are the main building blocks for Angular. Each components consists of 3 files:")]),_v(" "),_c('ul',[_c('li',[_c('strong',[_v("HTML")]),_v(": Defines the layout of the component's view.")]),_v(" "),_c('li',[_c('strong',[_v("CSS")]),_v(": Defines the component-specific styles.")]),_v(" "),_c('li',[_c('strong',[_v("Typescript")]),_v(": Implements the component's logic and behavior.")])]),_v(" "),_c('p',[_v("Refer to the "),_c('a',{attrs:{"href":"https://angular.io/guide/component-overview"}},[_v("Angular Documentation")]),_v(" for guidelines on creating components.")]),_v(" "),_c('h4',{attrs:{"id":"attribute-directive"}},[_v("Attribute Directive"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#attribute-directive","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Attribute directives can change the appearance or behavior of DOM elements and Angular components.")]),_v(" "),_c('p',[_v("For detailed guidance, refer to the "),_c('a',{attrs:{"href":"https://angular.io/guide/attribute-directives"}},[_v("Angular Documentation")]),_v(". It provides guidelines on creating and applying attribute directive, covering user events handling and passing values to attribute directive.")]),_v(" "),_c('p',[_v("In "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher/pull/1239"}},[_v("PR #1239")]),_v(", I implemented an attribute directive that listen to click event and will open error snackbar if the target link is an internal link.")]),_v(" "),_c('h4',{attrs:{"id":"ngtemplateoutlet"}},[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("NgTemplateOutlet")]),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#ngtemplateoutlet","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("NgTemplateOutlet")]),_v(" is a directive in Angular that allows for "),_c('strong',[_v("dynamic rendering")]),_v(" of templates. It allows the template to be specified along with the context data that should be injected into it.")]),_v(" "),_c('p',[_v("I utilized "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("NgTemplateOutlet")]),_v(" to dynamically render different headers for the card view component based on current grouping criteria. Refer to "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/blob/main/src/app/issues-viewer/card-view/card-view.component.html"}},[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("CardViewComponenet")])]),_v(" for implementation details.")]),_v(" "),_c('h3',{attrs:{"id":"jasmine"}},[_v("Jasmine"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#jasmine","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Jasmine is a behavior-driven development framewrok specific for JavaScript unit testing.")]),_v(" "),_c('p',[_v("I primarily learned how to use Jasmine from its "),_c('a',{attrs:{"href":"https://jasmine.github.io/api/edge/global"}},[_v("documentation")]),_v(". I utilized it extensively while working on WATcher test case refactoring. Some relevant PRs include: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/241"}},[_v("PR #241")]),_v(", "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/244"}},[_v("PR #244")]),_v(", "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/245"}},[_v("PR #245")]),_v(", "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/246"}},[_v("PR #246")]),_v(", "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/247"}},[_v("PR #247")])]),_v(" "),_c('ul',[_c('li',[_c('strong',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("describe")])]),_v(": Define a group of spec (suite)")]),_v(" "),_c('li',[_c('strong',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("it")])]),_v(": Define a single spec.")]),_v(" "),_c('li',[_c('strong',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("expect")])]),_v(": Create an expectation for a spec.")]),_v(" "),_c('li',[_c('strong',[_v("Class "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Spy")])]),_v(": Mock functions (spies) that can be used to track function calls.")])]),_v(" "),_c('h4',{attrs:{"id":"asynchronous-testing-with-observables"}},[_v("Asynchronous Testing with Observables"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#asynchronous-testing-with-observables","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("When dealing with asynchronous operations like observables, Jasmine provides support through the use of the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("done")]),_v(" function. This allows for effective testing of asynchronous behavior by signaling when a test has completed its execution.")]),_v(" "),_c('p',[_v("Here's an example from my "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/275"}},[_v("pull request")]),_v(":")]),_v(" "),_c('pre',[_c('code',{pre:true,attrs:{"class":"hljs javascript"}},[_c('span',[_v("it("),_c('span',{pre:true,attrs:{"class":"hljs-string"}},[_v("'should throw error for URL without repo parameter'")]),_v(", "),_c('span',{pre:true,attrs:{"class":"hljs-function"}},[_v("("),_c('span',{pre:true,attrs:{"class":"hljs-params"}},[_v("done")]),_v(") =>")]),_v(" {\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("const")]),_v(" urlWithoutRepo = "),_c('span',{pre:true,attrs:{"class":"hljs-string"}},[_v("'/issuesViewer'")]),_v(";\n")]),_c('span',[_v("\n")]),_c('span',[_v(" phaseService.setupFromUrl(urlWithoutRepo).subscribe({\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-attr"}},[_v("error")]),_v(": "),_c('span',{pre:true,attrs:{"class":"hljs-function"}},[_v("("),_c('span',{pre:true,attrs:{"class":"hljs-params"}},[_v("err")]),_v(") =>")]),_v(" {\n")]),_c('span',[_v(" expect(err).toEqual("),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("new")]),_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-built_in"}},[_v("Error")]),_v("(ErrorMessageService.invalidUrlMessage()));\n")]),_c('span',[_v(" done(); "),_c('span',{pre:true,attrs:{"class":"hljs-comment"}},[_v("// Signal that the test has completed")]),_v("\n")]),_c('span',[_v(" }\n")]),_c('span',[_v(" });\n")]),_c('span',[_v("});\n")])])]),_c('p',[_v("Resources: "),_c('a',{attrs:{"href":"https://medium.com/google-developer-experts/angular-2-unit-testing-with-jasmine-defe20421584#59a4"}},[_v("Angular — Unit Testing recipes (v2+)")])]),_v(" "),_c('h4',{attrs:{"id":"testing-for-behavior"}},[_v("Testing for Behavior"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#testing-for-behavior","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("It's essential to test for behavior rather than implementation details. This principle was emphasized by a senior in my pull reqeust. By focusing on behavior, tests become more resilient to changes in the codebase and provide better documentation for how components and functions should be used.")]),_v(" "),_c('p',[_v("Here's an example that illustrates the difference between testing behavior and implementation:")]),_v(" "),_c('p',[_v("Context: "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("changeRepositoryIfValid")]),_v(" will call "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("changeCurrentRepository")]),_v(" if repository is valid.")]),_v(" "),_c('pre',[_c('code',{pre:true,attrs:{"class":"hljs javascript"}},[_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-comment"}},[_v("// Test for behavior")]),_v("\n")]),_c('span',[_v("it("),_c('span',{pre:true,attrs:{"class":"hljs-string"}},[_v("'should set current repository if repository is valid'")]),_v(", "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("async")]),_v(" () => {\n")]),_c('span',[_v(" githubServiceSpy.isRepositoryPresent.and.returnValue("),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("of")]),_v("("),_c('span',{pre:true,attrs:{"class":"hljs-literal"}},[_v("true")]),_v("));\n")]),_c('span',[_v("\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("await")]),_v(" phaseService.changeRepositoryIfValid(WATCHER_REPO);\n")]),_c('span',[_v("\n")]),_c('span',[_v(" expect(phaseService.currentRepo).toEqual(WATCHER_REPO);\n")]),_c('span',[_v("});\n")]),_c('span',[_v("\n")]),_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-comment"}},[_v("// Test for implementation")]),_v("\n")]),_c('span',[_v("it("),_c('span',{pre:true,attrs:{"class":"hljs-string"}},[_v("'should call changeRepository method if repository is valid'")]),_v(", "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("async")]),_v(" () => {\n")]),_c('span',[_v(" githubServiceSpy.isRepositoryPresent.and.returnValue("),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("of")]),_v("("),_c('span',{pre:true,attrs:{"class":"hljs-literal"}},[_v("true")]),_v("));\n")]),_c('span',[_v("\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("const")]),_v(" changeCurrentRepositorySpy = spyOn(phaseService, "),_c('span',{pre:true,attrs:{"class":"hljs-string"}},[_v("'changeCurrentRepository'")]),_v(");\n")]),_c('span',[_v("\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("await")]),_v(" phaseService.changeRepositoryIfValid(WATCHER_REPO);\n")]),_c('span',[_v("\n")]),_c('span',[_v(" expect(changeCurrentRepositorySpy).toHaveBeenCalledWith(WATCHER_REPO);\n")]),_c('span',[_v("});\n")])])]),_c('h3',{attrs:{"id":"design-pattern"}},[_v("Design Pattern"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#design-pattern","onclick":"event.stopPropagation()"}})]),_v(" "),_c('h4',{attrs:{"id":"strategy-design-pattern"}},[_v("Strategy Design Pattern"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#strategy-design-pattern","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("The Strategy design pattern allows for the selection of algorithms at runtime by defining a family of interchangeable algorithms and encapsulating each one. It enables flexibility and easy extension of functionality without modifying existing code.")]),_v(" "),_c('p',[_v("I utilized the Strategy Design Pattern to implement a "),_c('strong',[_v("\"Group by\"")]),_v(" feature that organizes issues / prs based on different criteria.")]),_v(" "),_c('p',[_v("Implementation of group by feature :")]),_v(" "),_c('ul',[_c('li',[_v("Grouping Strategy Interface ("),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/blob/main/src/app/core/services/grouping/grouping-strategy.interface.ts"}},[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("GroupingStrategy")])]),_v("): Defines a common interface for all supported grouping strategies.")]),_v(" "),_c('li',[_v("Concrete Grouping Strategy: Each strategy groups the issues/prs based on different criterias.\n"),_c('ul',[_c('li',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/blob/main/src/app/core/services/grouping/assignee-grouping-strategy.service.ts"}},[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("AssigneeGroupingStrategy")])])]),_v(" "),_c('li',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/blob/main/src/app/core/services/grouping/milestone-grouping-strategy.service.ts"}},[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("MilestoneGroupingStrategy")])])])])]),_v(" "),_c('li',[_v("Context ("),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/blob/main/src/app/core/services/grouping/grouping-context.service.ts"}},[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("GroupingContextService")])]),_v("): This service is used to apply the grouping strategies based on user selection.")])])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/NereusWB922/progress.html b/students/NereusWB922/progress.html index b696b953e..af4934b0c 100644 --- a/students/NereusWB922/progress.html +++ b/students/NereusWB922/progress.html @@ -12,7 +12,7 @@ const baseUrl = '/2024' -

    Summary

    • Fix Bugs: Fix uncaught error for invalid link navigation in CATcher and some minor bugs found in WATcher preset view feature.
    • Testing Aspect: Refactored outdated test cases in WATcher and enable automated testing in pre-push hooks and GitHub Actions.
    • New Feature: Implemented an extensible group by feature for WATcher's Issue Viewer. Currently, it supports grouping by assignee and milestone.
    • User Experience: Improved WATcher's Activity Dashboard design. Implemented a dropdown menu for easier repo change in WATcher's Issue Viewer.
    • Managing: Deployed CATcher V1.2.0 in week 10.
    Week Achievements
    3 Merged PR: Uncaught error when invalid link is clicked #1239
    4 Merged PR: Improve activity dashboard design #233
    4 Merged PR: Refactor test cases for Login Component, Session Model and Conflict Model #241
    4 Merged PR: Remove markdown.css from test env stylesheets #243
    4 Merged PR: Refactor test cases for issue paginator #244
    4 Merged PR: Refactor test cases for issue sorter #245
    4 Merged PR: Refactor github label constants #246
    4 Merged PR: Refactor test cases for search filter #247
    6 Reviewed PR: Refactor certain filters into its own service #259
    6 Merged PR: Remove test cases for permissions service #260
    6 Submitted issue: Improve E2E testing #1251
    7 Merged PR: Refactor test cases for Issue Model #257
    7 Merged PR: Refactor test cases for Label Service #258
    7 Merged PR: Remove constants for DataFile and Team model #262
    7 Merged PR: Refactor test cases for Phase Service #263
    7 Submitted issue: Encounter error for npm run test after upgrading to Angular v11 #268
    7 Merged PR: Fix zone testing import error #269
    7 Merged PR: Refactor test cases for issue sorter #270
    7 Merged PR: Refactor test cases for user service #271
    7 Merged PR: Refactor test cases for label filter bar component #274
    7 Merged PR: Update test cases for phase service #275
    7 Merged PR: Enable pre push hook for npm run test #288
    8 Reviewed PR: Create tests for ErrorMessage, ErrorHandling and Milestone services #290
    8 Reviewed PR: Create tests for Milestone service #303
    9 Submitted issue: GroupBy Feature #306
    9 Reviewed PR: Keep filters when switching repos #281
    9 Reviewed PR: Add tool tip for hidden users #307
    9 Merged PR: Refactor Phase Service and remove Phase #291
    9 Merged PR: Setup grouping strategy and service #308
    10 Reviewed PR: Keep milestones when switching repo #311
    10 Merged PR: Integrate Grouping Service #313
    10 Submitted issue: Encode grouping to url #317
    10 Reviewed PR: Add preset views #320
    10 Merged PR: Implement group by milestone #316
    10 Submitted issue: Update IssueViewer's Repo on Back/Forward Navigation #321
    10 Merged PR: Include groupby params in url #319
    10 Merged PR: Update repo on back and forward navigation #322
    10 Merged PR: Refactor MilestoneGroupingStrategy to match the changes in #315 #323
    10 Merged PR: Reset GroupingContextService only if "keep filter" is selected #324
    10 Reviewed PR: Fix for no milestone case #326
    10 Reviewed PR: Add filters to url #314
    10 Merged PR: Enable npm run test in GitHub Action #325
    10 Merged PR: Deploy V1.2.0 #331
    11 Reviewed PR: Fix default preset view #334
    11 Reviewed PR: Fix preset view selection appearance #338
    11 Submitted issue: Provide preset value for groupby #341
    11 Submitted issue: Add filter for assignee #342
    11 Merged PR: Show prs without milestone #339
    11 Merged PR: Implement dropdown menu for repo change #347
    11 Reviewed PR: Remove quotation marks from url #345
    11 Reviewed PR: Hide column issue count #346
    11 Reviewed PR: Show preset view only when repo is set #355
    11 Reviewed PR: Fix top shadow hiding of columns #356
    11 Reviewed PR: Fix bottom shadow of columns #357
    12 Submitted issue: Milestone without deadline is not considered as currently active #358
    12 Reviewed PR: Fix top and bottom shadow of columns #357
    12 Reviewed PR: Optimise Github API calls #360
    12 Merged PR: Consider open milestone without deadline as currently active #359
    +

    Summary

    • Fix Bugs: Fix uncaught error for invalid link navigation in CATcher and some minor bugs found in WATcher preset view feature.
    • Testing Aspect: Refactored outdated test cases in WATcher and enable automated testing in pre-push hooks and GitHub Actions.
    • New Feature: Implemented an extensible group by feature for WATcher's Issue Viewer. Currently, it supports grouping by assignee and milestone.
    • User Experience: Improved WATcher's Activity Dashboard design. Implemented a dropdown menu for easier repo change in WATcher's Issue Viewer.
    • Managing: Deployed CATcher V1.2.0 in week 10.
    Week Achievements
    3 Merged PR: Uncaught error when invalid link is clicked #1239
    4 Merged PR: Improve activity dashboard design #233
    4 Merged PR: Refactor test cases for Login Component, Session Model and Conflict Model #241
    4 Merged PR: Remove markdown.css from test env stylesheets #243
    4 Merged PR: Refactor test cases for issue paginator #244
    4 Merged PR: Refactor test cases for issue sorter #245
    4 Merged PR: Refactor github label constants #246
    4 Merged PR: Refactor test cases for search filter #247
    6 Reviewed PR: Refactor certain filters into its own service #259
    6 Merged PR: Remove test cases for permissions service #260
    6 Submitted issue: Improve E2E testing #1251
    7 Merged PR: Refactor test cases for Issue Model #257
    7 Merged PR: Refactor test cases for Label Service #258
    7 Merged PR: Remove constants for DataFile and Team model #262
    7 Merged PR: Refactor test cases for Phase Service #263
    7 Submitted issue: Encounter error for npm run test after upgrading to Angular v11 #268
    7 Merged PR: Fix zone testing import error #269
    7 Merged PR: Refactor test cases for issue sorter #270
    7 Merged PR: Refactor test cases for user service #271
    7 Merged PR: Refactor test cases for label filter bar component #274
    7 Merged PR: Update test cases for phase service #275
    7 Merged PR: Enable pre push hook for npm run test #288
    8 Reviewed PR: Create tests for ErrorMessage, ErrorHandling and Milestone services #290
    8 Reviewed PR: Create tests for Milestone service #303
    9 Submitted issue: GroupBy Feature #306
    9 Reviewed PR: Keep filters when switching repos #281
    9 Reviewed PR: Add tool tip for hidden users #307
    9 Merged PR: Refactor Phase Service and remove Phase #291
    9 Merged PR: Setup grouping strategy and service #308
    10 Reviewed PR: Keep milestones when switching repo #311
    10 Merged PR: Integrate Grouping Service #313
    10 Submitted issue: Encode grouping to url #317
    10 Reviewed PR: Add preset views #320
    10 Merged PR: Implement group by milestone #316
    10 Submitted issue: Update IssueViewer's Repo on Back/Forward Navigation #321
    10 Merged PR: Include groupby params in url #319
    10 Merged PR: Update repo on back and forward navigation #322
    10 Merged PR: Refactor MilestoneGroupingStrategy to match the changes in #315 #323
    10 Merged PR: Reset GroupingContextService only if "keep filter" is selected #324
    10 Reviewed PR: Fix for no milestone case #326
    10 Reviewed PR: Add filters to url #314
    10 Merged PR: Enable npm run test in GitHub Action #325
    10 Merged PR: Deploy V1.2.0 #331
    11 Reviewed PR: Fix default preset view #334
    11 Reviewed PR: Fix preset view selection appearance #338
    11 Submitted issue: Provide preset value for groupby #341
    11 Submitted issue: Add filter for assignee #342
    11 Merged PR: Show prs without milestone #339
    11 Merged PR: Implement dropdown menu for repo change #347
    11 Reviewed PR: Remove quotation marks from url #345
    11 Reviewed PR: Hide column issue count #346
    11 Reviewed PR: Show preset view only when repo is set #355
    11 Reviewed PR: Fix top shadow hiding of columns #356
    11 Reviewed PR: Fix bottom shadow of columns #357
    12 Submitted issue: Milestone without deadline is not considered as currently active #358
    12 Reviewed PR: Fix top and bottom shadow of columns #357
    12 Reviewed PR: Optimise Github API calls #360
    12 Merged PR: Consider open milestone without deadline as currently active #359
    diff --git a/students/NereusWB922/progress.page-vue-render.js b/students/NereusWB922/progress.page-vue-render.js index 3df6ef998..293732d50 100644 --- a/students/NereusWB922/progress.page-vue-render.js +++ b/students/NereusWB922/progress.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('h3',{attrs:{"id":"summary"}},[_v("Summary"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#summary","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ul',[_c('li',[_c('strong',[_v("Fix Bugs")]),_v(": Fix uncaught error for invalid link navigation in CATcher and some minor bugs found in WATcher preset view feature.")]),_v(" "),_c('li',[_c('strong',[_v("Testing Aspect")]),_v(": Refactored outdated test cases in WATcher and enable automated testing in pre-push hooks and GitHub Actions.")]),_v(" "),_c('li',[_c('strong',[_v("New Feature")]),_v(": Implemented an extensible group by feature for WATcher's Issue Viewer. Currently, it supports grouping by assignee and milestone.")]),_v(" "),_c('li',[_c('strong',[_v("User Experience")]),_v(": Improved WATcher's Activity Dashboard design. Implemented a dropdown menu for easier repo change in WATcher's Issue Viewer.")]),_v(" "),_c('li',[_c('strong',[_v("Managing")]),_v(": Deployed CATcher V1.2.0 in week 10.")])]),_v(" "),_c('div',{staticClass:"table-responsive"},[_c('table',{staticClass:"markbind-table table table-bordered table-striped"},[_c('thead',[_c('tr',[_c('th',[_v("Week")]),_v(" "),_c('th',[_v("Achievements")])])]),_v(" "),_c('tbody',[_c('tr',[_c('td',[_v("3")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher/pull/1239"}},[_v("Uncaught error when invalid link is clicked #1239")])])]),_v(" "),_c('tr',[_c('td',[_v("4")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/233"}},[_v("Improve activity dashboard design #233")])])]),_v(" "),_c('tr',[_c('td',[_v("4")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/241"}},[_v("Refactor test cases for Login Component, Session Model and Conflict Model #241")])])]),_v(" "),_c('tr',[_c('td',[_v("4")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/243"}},[_v("Remove markdown.css from test env stylesheets #243")])])]),_v(" "),_c('tr',[_c('td',[_v("4")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/244"}},[_v("Refactor test cases for issue paginator #244")])])]),_v(" "),_c('tr',[_c('td',[_v("4")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/245"}},[_v("Refactor test cases for issue sorter #245")])])]),_v(" "),_c('tr',[_c('td',[_v("4")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/246"}},[_v("Refactor github label constants #246")])])]),_v(" "),_c('tr',[_c('td',[_v("4")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/247"}},[_v("Refactor test cases for search filter #247")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/259"}},[_v("Refactor certain filters into its own service #259")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/260"}},[_v("Remove test cases for permissions service #260")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Submitted issue: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher/issues/1251"}},[_v("Improve E2E testing #1251")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher/pull/257"}},[_v("Refactor test cases for Issue Model #257")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher/pull/258"}},[_v("Refactor test cases for Label Service #258")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher/pull/262"}},[_v("Remove constants for DataFile and Team model #262")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher/pull/263"}},[_v("Refactor test cases for Phase Service #263")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Submitted issue: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/268"}},[_v("Encounter error for npm run test after upgrading to Angular v11 #268")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher/pull/269"}},[_v("Fix zone testing import error #269")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher/pull/270"}},[_v("Refactor test cases for issue sorter #270")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher/pull/271"}},[_v("Refactor test cases for user service #271")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher/pull/274"}},[_v("Refactor test cases for label filter bar component #274")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher/pull/275"}},[_v("Update test cases for phase service #275")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/288"}},[_v("Enable pre push hook for npm run test #288")])])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/290"}},[_v("Create tests for ErrorMessage, ErrorHandling and Milestone services #290")])])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/303"}},[_v("Create tests for Milestone service #303")])])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_v("Submitted issue: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/306"}},[_v("GroupBy Feature #306")])])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/281"}},[_v("Keep filters when switching repos #281")])])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/307"}},[_v("Add tool tip for hidden users #307")])])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/291"}},[_v("Refactor Phase Service and remove Phase #291")])])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/308"}},[_v("Setup grouping strategy and service #308")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/311"}},[_v("Keep milestones when switching repo #311")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/313"}},[_v("Integrate Grouping Service #313")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Submitted issue: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/317"}},[_v("Encode grouping to url #317")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/320"}},[_v("Add preset views #320")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/316"}},[_v("Implement group by milestone #316")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Submitted issue: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/321"}},[_v("Update IssueViewer's Repo on Back/Forward Navigation #321")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/319"}},[_v("Include groupby params in url #319")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/322"}},[_v("Update repo on back and forward navigation #322")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/323"}},[_v("Refactor MilestoneGroupingStrategy to match the changes in #315 #323")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/324"}},[_v("Reset GroupingContextService only if \"keep filter\" is selected #324")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/326"}},[_v("Fix for no milestone case #326")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/314"}},[_v("Add filters to url #314")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/325"}},[_v("Enable npm run test in GitHub Action #325")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/331"}},[_v("Deploy V1.2.0 #331")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/334"}},[_v("Fix default preset view #334")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/338"}},[_v("Fix preset view selection appearance #338")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Submitted issue: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/341"}},[_v("Provide preset value for groupby #341")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Submitted issue: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/342"}},[_v("Add filter for assignee #342")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/339"}},[_v("Show prs without milestone #339")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/347"}},[_v("Implement dropdown menu for repo change #347")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/345"}},[_v("Remove quotation marks from url #345")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/346"}},[_v("Hide column issue count #346")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/355"}},[_v("Show preset view only when repo is set #355")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/356"}},[_v("Fix top shadow hiding of columns #356")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/357"}},[_v("Fix bottom shadow of columns #357")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Submitted issue: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/358"}},[_v("Milestone without deadline is not considered as currently active #358")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/357"}},[_v("Fix top and bottom shadow of columns #357")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/360"}},[_v("Optimise Github API calls #360")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/359"}},[_v("Consider open milestone without deadline as currently active #359")])])])])])])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/Nicolascwy/info.html b/students/Nicolascwy/info.html index a394b4ce3..f157b044d 100644 --- a/students/Nicolascwy/info.html +++ b/students/Nicolascwy/info.html @@ -12,7 +12,7 @@ const baseUrl = '/2024' - + diff --git a/students/Nicolascwy/info.page-vue-render.js b/students/Nicolascwy/info.page-vue-render.js index 2bb4337c2..c8d434fb3 100644 --- a/students/Nicolascwy/info.page-vue-render.js +++ b/students/Nicolascwy/info.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('p',[_c('span',{attrs:{"id":"github"}},[_c('a',{attrs:{"href":"https://github.com/NicolasCwy"}},[_v("https://github.com/NicolasCwy")])])]),_v(" "),_c('p',[_c('span',{attrs:{"id":"projects"}},[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates"}},[_v("TEAMMATES")])])])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/Nicolascwy/knowledge.html b/students/Nicolascwy/knowledge.html index ab4bcade5..e49f3010c 100644 --- a/students/Nicolascwy/knowledge.html +++ b/students/Nicolascwy/knowledge.html @@ -58,7 +58,7 @@ <url-pattern>/auto/*</url-pattern> <url-pattern>/worker/*</url-pattern> </servlet-mapping> -

    Above is a snippet from the web.xml file in TEAMMATES. The main 2 constructs used in routing are filters and servlets. Filters can be thought of as sieves, where a request that matches the pattern found in <filter-mapping> would execute the filter defined in filter-class before continuing execution in the web.xml file. Servlets follow the same pattern but start with the prefix servlet for example <servlet-mapping>. Unlike filters, servlets dead-end a request, the request gets passed on to the servlet that it matches and does not get passed down any further.

    https://cloud.google.com/appengine/docs/flexible/java/configuring-the-web-xml-deployment-descriptor#Servlets_and_URL_Paths

    Gradle

    Tasks and Gradle configuration

    Tasks are snippets of code that can be executed by gradle. There are a few tasks that are pre-configured to perform a task by configuring some variables. I used the javaexec task which executes a java script when run. One problem faced was that Gradle configures every task on build evaluating an expression and assigning it to the variable. This led to a null pointer exceptions even if the task was not run e.g user wants to use gradle to lint the project. This was because I had directly assigned the environment variable as the java class to be run. To get around this an if-statement which checks if the environment variable is present before assigning it to the variable. I had not done this previously as I had thought variables could only be assigned once and was not optional.

    https://docs.gradle.org/current/dsl/org.gradle.api.tasks.JavaExec.html https://stackoverflow.com/questions/31065193/passing-properties-to-a-gradle-build https://www.youtube.com/watch?v=g56O_HeefBE https://docs.gradle.org/current/userguide/build_lifecycle.html http://www.joantolos.com/blog/gradletask/

    Git

    Fetching

    During PR reviews, I learnt that it is sometimes better to see the changes a person has made directly in my browser. Previously, I was only familiar with git pull which under the hood combined the fetch and the merge into a single step, but required the branch to track a remote which was not feasible for PR reviewing since this remote would be used once or at most a few times. I then found that git fetch allowed you to specify the repository URL (the link used to clone a repo) and the name of the branch to fetch, assigning it to a reference called FETCH_HEAD, which can be checkout-ed. This allowed me to quickly fetch the branch and switch into it and make some testing, usually I would also create a temporary branch so that I can check on the changes at another time.

    https://www.atlassian.com/git/tutorials/syncing/git-fetch https://git-scm.com/docs/git-fetch

    Rebasing

    When my team started to work on the notification banner feature, we realised that no matter how much planning is done, it was sometimes inevitable for our code to be dependent on someone elses. Instead of more conventional methods such as copying pasting code, which does not have the benefit of resolving conflicts, merging branches into my working branch would also be messy since their branches are actively updated, sometimes even force pushed. Instead, I learnt how to rebase from my teammates, which lets you put a series of commits on your branch on top another branch. This can be done several times, if a branch X is in turn dependent on branch Y, and you require Y. One downside is that you would have to fetch and update each branch and perform a rebase ontop of this new branch, but this is a small cost instead of rushing out a PR or idling, when the code you require is completed but just not merged into master.

    +

    Above is a snippet from the web.xml file in TEAMMATES. The main 2 constructs used in routing are filters and servlets. Filters can be thought of as sieves, where a request that matches the pattern found in <filter-mapping> would execute the filter defined in filter-class before continuing execution in the web.xml file. Servlets follow the same pattern but start with the prefix servlet for example <servlet-mapping>. Unlike filters, servlets dead-end a request, the request gets passed on to the servlet that it matches and does not get passed down any further.

    https://cloud.google.com/appengine/docs/flexible/java/configuring-the-web-xml-deployment-descriptor#Servlets_and_URL_Paths

    Gradle

    Tasks and Gradle configuration

    Tasks are snippets of code that can be executed by gradle. There are a few tasks that are pre-configured to perform a task by configuring some variables. I used the javaexec task which executes a java script when run. One problem faced was that Gradle configures every task on build evaluating an expression and assigning it to the variable. This led to a null pointer exceptions even if the task was not run e.g user wants to use gradle to lint the project. This was because I had directly assigned the environment variable as the java class to be run. To get around this an if-statement which checks if the environment variable is present before assigning it to the variable. I had not done this previously as I had thought variables could only be assigned once and was not optional.

    https://docs.gradle.org/current/dsl/org.gradle.api.tasks.JavaExec.html https://stackoverflow.com/questions/31065193/passing-properties-to-a-gradle-build https://www.youtube.com/watch?v=g56O_HeefBE https://docs.gradle.org/current/userguide/build_lifecycle.html http://www.joantolos.com/blog/gradletask/

    Git

    Fetching

    During PR reviews, I learnt that it is sometimes better to see the changes a person has made directly in my browser. Previously, I was only familiar with git pull which under the hood combined the fetch and the merge into a single step, but required the branch to track a remote which was not feasible for PR reviewing since this remote would be used once or at most a few times. I then found that git fetch allowed you to specify the repository URL (the link used to clone a repo) and the name of the branch to fetch, assigning it to a reference called FETCH_HEAD, which can be checkout-ed. This allowed me to quickly fetch the branch and switch into it and make some testing, usually I would also create a temporary branch so that I can check on the changes at another time.

    https://www.atlassian.com/git/tutorials/syncing/git-fetch https://git-scm.com/docs/git-fetch

    Rebasing

    When my team started to work on the notification banner feature, we realised that no matter how much planning is done, it was sometimes inevitable for our code to be dependent on someone elses. Instead of more conventional methods such as copying pasting code, which does not have the benefit of resolving conflicts, merging branches into my working branch would also be messy since their branches are actively updated, sometimes even force pushed. Instead, I learnt how to rebase from my teammates, which lets you put a series of commits on your branch on top another branch. This can be done several times, if a branch X is in turn dependent on branch Y, and you require Y. One downside is that you would have to fetch and update each branch and perform a rebase ontop of this new branch, but this is a small cost instead of rushing out a PR or idling, when the code you require is completed but just not merged into master.

    diff --git a/students/Nicolascwy/knowledge.page-vue-render.js b/students/Nicolascwy/knowledge.page-vue-render.js index 8428a1b7c..aa5b49868 100644 --- a/students/Nicolascwy/knowledge.page-vue-render.js +++ b/students/Nicolascwy/knowledge.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('h3',{attrs:{"id":"angular"}},[_v("Angular"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#angular","onclick":"event.stopPropagation()"}})]),_v(" "),_c('h4',{attrs:{"id":"file-structure"}},[_v("File Structure"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#file-structure","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Unlike React which bundles structure and functionality into a single file, Angular divides this task for a few files such as:")]),_v(" "),_c('ul',[_c('li',[_v("Component file: Defines the functionality of the component using Typescript (x.component.ts)")]),_v(" "),_c('li',[_v("Template file: Define structure and what the component looks like in HTML (x.component.html)")]),_v(" "),_c('li',[_v("Specification file: Used to perform unit/ integration on the component (x.spec.ts)")])]),_v(" "),_c('h4',{attrs:{"id":"directives"}},[_v("Directives"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#directives","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("After defining the component it is still possible to use provide it with extra behaviour using directives. Directives are classes that can be added to the component when it is used on a page.\nThe directives I have encountered are")]),_v(" "),_c('ol',[_c('li',[_v("(NgIf)["),_c('a',{attrs:{"href":"https://angular.io/api/common/NgIf"}},[_v("https://angular.io/api/common/NgIf")]),_v("]: Allows conditional rendering for a component based on a boolean condition")]),_v(" "),_c('li',[_v("(NgbDropdown)["),_c('a',{attrs:{"href":"https://ng-bootstrap.github.io/#/components/dropdown/api"}},[_v("https://ng-bootstrap.github.io/#/components/dropdown/api")]),_v("]: Helps create dropdown menus - added from Angular Bootstrap")])]),_v(" "),_c('h4',{attrs:{"id":"event-emitters"}},[_c('a',{attrs:{"href":"https://angular.io/api/core/EventEmitter"}},[_v("Event Emitters")]),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#event-emitters","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Communication between components from the child to the parent are done through event emitters. These are helpful when a child component on a page has been clicked, and the parent has to have knowledge of which child has been selected before fetching data for the child to be displayed to the user. After defining an event emitter, the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("emit()")]),_v(" method can be called to return a value to the parent.")]),_v(" "),_c('p',[_v("This snippet uses the @Output decorator to informs the parent which row has been clicked when the function is called.")]),_v(" "),_c('pre',[_c('code',{pre:true,attrs:{"class":"hljs"}},[_c('span',[_v("// Component file - reminder.component.ts\n")]),_c('span',[_v("@Output()\n")]),_c('span',[_v("sendRemindersToAllNonSubmittersEvent: EventEmitter = new EventEmitter();\n")]),_c('span',[_v("\n")]),_c('span',[_v("sendRemindersToAllNonSubmitters(rowIndex: number): void {\n")]),_c('span',[_v(" this.sendRemindersToAllNonSubmittersEvent.emit(rowIndex);\n")]),_c('span',[_v(" }\n")]),_c('span',[_v("\n")]),_c('span',[_v("// child template file - child.component.html\n")]),_c('span',[_v("\n")]),_c('span',[_v("\n")]),_c('span',[_v("// parent template file - parent calls sendEmail function open receiving event from child.\n")]),_c('span',[_v("\n")])])]),_c('h4',{attrs:{"id":"flow-of-inputs-and-outputs"}},[_v("Flow of inputs and outputs"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#flow-of-inputs-and-outputs","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("There are 3 ways data can flow between components.")]),_v(" "),_c('ol',[_c('li',[_v("[disabled]=\"canViewSessionInSections\": [] bracket indicate data flows from parent's property canViewSessionInSections to the child's property disabled.")]),_v(" "),_c('li',[_v("(click)=\"sendRemindersToAllNonSubmitters(idx): () like the previous example, triggers the event emitter to inform the parent to send all reminders for the course on the xth row.")]),_v(" "),_c('li',[_v("[(size)]=\"fontSizePx\": A combination of 1 and 2 and is called 2 way binding, where data can flow between parent and child.")])]),_v(" "),_c('p',[_v("References: "),_c('a',{attrs:{"href":"https://angular.io/guide/inputs-outputs"}},[_v("Event Emitters inputs and outputs")])]),_v(" "),_c('h3',{attrs:{"id":"backend"}},[_v("Backend"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#backend","onclick":"event.stopPropagation()"}})]),_v(" "),_c('h4',{attrs:{"id":"servlets-and-backend-routing"}},[_v("Servlets and backend routing"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#servlets-and-backend-routing","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("My experience with the backend was limited to Express (a Node.JS framework), and did not even know that Java it was possible to have a backend in Java. TEAMMATES uses Jetty, a Java framework to route requests from users. The entry point to the backend is in "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("web.xml")]),_v(" a file that is read from top to bottom and can be thought of as a sieve which directs requests in that order.")]),_v(" "),_c('pre',[_c('code',{pre:true,attrs:{"class":"hljs xml"}},[_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-tag"}},[_v("<"),_c('span',{pre:true,attrs:{"class":"hljs-name"}},[_v("filter")]),_v(">")]),_v("\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-tag"}},[_v("<"),_c('span',{pre:true,attrs:{"class":"hljs-name"}},[_v("filter-name")]),_v(">")]),_v("WebSecurityHeaderFilter"),_c('span',{pre:true,attrs:{"class":"hljs-tag"}},[_v("")]),_v("\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-tag"}},[_v("<"),_c('span',{pre:true,attrs:{"class":"hljs-name"}},[_v("filter-class")]),_v(">")]),_v("teammates.ui.servlets.WebSecurityHeaderFilter"),_c('span',{pre:true,attrs:{"class":"hljs-tag"}},[_v("")]),_v("\n")]),_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-tag"}},[_v("")]),_v("\n")]),_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-tag"}},[_v("<"),_c('span',{pre:true,attrs:{"class":"hljs-name"}},[_v("filter-mapping")]),_v(">")]),_v("\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-tag"}},[_v("<"),_c('span',{pre:true,attrs:{"class":"hljs-name"}},[_v("filter-name")]),_v(">")]),_v("WebSecurityHeaderFilter"),_c('span',{pre:true,attrs:{"class":"hljs-tag"}},[_v("")]),_v("\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-tag"}},[_v("<"),_c('span',{pre:true,attrs:{"class":"hljs-name"}},[_v("url-pattern")]),_v(">")]),_v("/web/*"),_c('span',{pre:true,attrs:{"class":"hljs-tag"}},[_v("")]),_v("\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-tag"}},[_v("<"),_c('span',{pre:true,attrs:{"class":"hljs-name"}},[_v("url-pattern")]),_v(">")]),_v("/index.html"),_c('span',{pre:true,attrs:{"class":"hljs-tag"}},[_v("")]),_v("\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-tag"}},[_v("<"),_c('span',{pre:true,attrs:{"class":"hljs-name"}},[_v("url-pattern")]),_v(">")]),_v("/"),_c('span',{pre:true,attrs:{"class":"hljs-tag"}},[_v("")]),_v("\n")]),_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-tag"}},[_v("")]),_v("\n")]),_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-tag"}},[_v("<"),_c('span',{pre:true,attrs:{"class":"hljs-name"}},[_v("servlet")]),_v(">")]),_v("\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-tag"}},[_v("<"),_c('span',{pre:true,attrs:{"class":"hljs-name"}},[_v("description")]),_v(">")]),_v("Servlet that handles the single web page application"),_c('span',{pre:true,attrs:{"class":"hljs-tag"}},[_v("")]),_v("\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-tag"}},[_v("<"),_c('span',{pre:true,attrs:{"class":"hljs-name"}},[_v("servlet-name")]),_v(">")]),_v("WebPageServlet"),_c('span',{pre:true,attrs:{"class":"hljs-tag"}},[_v("")]),_v("\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-tag"}},[_v("<"),_c('span',{pre:true,attrs:{"class":"hljs-name"}},[_v("servlet-class")]),_v(">")]),_v("teammates.ui.servlets.WebPageServlet"),_c('span',{pre:true,attrs:{"class":"hljs-tag"}},[_v("")]),_v("\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-tag"}},[_v("<"),_c('span',{pre:true,attrs:{"class":"hljs-name"}},[_v("load-on-startup")]),_v(">")]),_v("0"),_c('span',{pre:true,attrs:{"class":"hljs-tag"}},[_v("")]),_v("\n")]),_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-tag"}},[_v("")]),_v("\n")]),_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-tag"}},[_v("<"),_c('span',{pre:true,attrs:{"class":"hljs-name"}},[_v("servlet-mapping")]),_v(">")]),_v("\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-tag"}},[_v("<"),_c('span',{pre:true,attrs:{"class":"hljs-name"}},[_v("servlet-name")]),_v(">")]),_v("WebPageServlet"),_c('span',{pre:true,attrs:{"class":"hljs-tag"}},[_v("")]),_v("\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-tag"}},[_v("<"),_c('span',{pre:true,attrs:{"class":"hljs-name"}},[_v("url-pattern")]),_v(">")]),_v("/web/*"),_c('span',{pre:true,attrs:{"class":"hljs-tag"}},[_v("")]),_v("\n")]),_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-tag"}},[_v("")]),_v("\n")]),_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-tag"}},[_v("<"),_c('span',{pre:true,attrs:{"class":"hljs-name"}},[_v("servlet")]),_v(">")]),_v("\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-tag"}},[_v("<"),_c('span',{pre:true,attrs:{"class":"hljs-name"}},[_v("description")]),_v(">")]),_v("REST API Servlet"),_c('span',{pre:true,attrs:{"class":"hljs-tag"}},[_v("")]),_v("\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-tag"}},[_v("<"),_c('span',{pre:true,attrs:{"class":"hljs-name"}},[_v("servlet-name")]),_v(">")]),_v("WebApiServlet"),_c('span',{pre:true,attrs:{"class":"hljs-tag"}},[_v("")]),_v("\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-tag"}},[_v("<"),_c('span',{pre:true,attrs:{"class":"hljs-name"}},[_v("servlet-class")]),_v(">")]),_v("teammates.ui.servlets.WebApiServlet"),_c('span',{pre:true,attrs:{"class":"hljs-tag"}},[_v("")]),_v("\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-tag"}},[_v("<"),_c('span',{pre:true,attrs:{"class":"hljs-name"}},[_v("load-on-startup")]),_v(">")]),_v("0"),_c('span',{pre:true,attrs:{"class":"hljs-tag"}},[_v("")]),_v("\n")]),_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-tag"}},[_v("")]),_v("\n")]),_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-tag"}},[_v("<"),_c('span',{pre:true,attrs:{"class":"hljs-name"}},[_v("servlet-mapping")]),_v(">")]),_v("\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-tag"}},[_v("<"),_c('span',{pre:true,attrs:{"class":"hljs-name"}},[_v("servlet-name")]),_v(">")]),_v("WebApiServlet"),_c('span',{pre:true,attrs:{"class":"hljs-tag"}},[_v("")]),_v("\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-tag"}},[_v("<"),_c('span',{pre:true,attrs:{"class":"hljs-name"}},[_v("url-pattern")]),_v(">")]),_v("/webapi/*"),_c('span',{pre:true,attrs:{"class":"hljs-tag"}},[_v("")]),_v("\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-tag"}},[_v("<"),_c('span',{pre:true,attrs:{"class":"hljs-name"}},[_v("url-pattern")]),_v(">")]),_v("/auto/*"),_c('span',{pre:true,attrs:{"class":"hljs-tag"}},[_v("")]),_v("\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-tag"}},[_v("<"),_c('span',{pre:true,attrs:{"class":"hljs-name"}},[_v("url-pattern")]),_v(">")]),_v("/worker/*"),_c('span',{pre:true,attrs:{"class":"hljs-tag"}},[_v("")]),_v("\n")]),_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-tag"}},[_v("")]),_v("\n")])])]),_c('p',[_v("Above is a snippet from the web.xml file in TEAMMATES. The main 2 constructs used in routing are "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("filters")]),_v(" and "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("servlets")]),_v(". Filters can be thought of as sieves, where a request that matches the pattern found in "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("")]),_v(" would execute the filter defined in "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("filter-class")]),_v(" before continuing execution in the web.xml file. Servlets follow the same pattern but start with the prefix "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("servlet")]),_v(" for example "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("")]),_v(". Unlike filters, servlets dead-end a request, the request gets passed on to the servlet that it matches and does not get passed down any further.")]),_v(" "),_c('p',[_c('a',{attrs:{"href":"https://cloud.google.com/appengine/docs/flexible/java/configuring-the-web-xml-deployment-descriptor#Servlets_and_URL_Paths"}},[_v("https://cloud.google.com/appengine/docs/flexible/java/configuring-the-web-xml-deployment-descriptor#Servlets_and_URL_Paths")])]),_v(" "),_c('h3',{attrs:{"id":"gradle"}},[_v("Gradle"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#gradle","onclick":"event.stopPropagation()"}})]),_v(" "),_c('h4',{attrs:{"id":"tasks-and-gradle-configuration"}},[_v("Tasks and Gradle configuration"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#tasks-and-gradle-configuration","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Tasks are snippets of code that can be executed by gradle. There are a few tasks that are pre-configured to perform a task by configuring some variables. I used the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("javaexec")]),_v(" task which executes a java script when run. One problem faced was that Gradle configures every task on build evaluating an expression and assigning it to the variable. This led to a null pointer exceptions even if the task was not run e.g user wants to use gradle to lint the project. This was because I had directly assigned the environment variable as the java class to be run. To get around this an if-statement which checks if the environment variable is present before assigning it to the variable. I had not done this previously as I had thought variables could only be assigned once and was not optional.")]),_v(" "),_c('p',[_c('a',{attrs:{"href":"https://docs.gradle.org/current/dsl/org.gradle.api.tasks.JavaExec.html"}},[_v("https://docs.gradle.org/current/dsl/org.gradle.api.tasks.JavaExec.html")]),_v(" "),_c('a',{attrs:{"href":"https://stackoverflow.com/questions/31065193/passing-properties-to-a-gradle-build"}},[_v("https://stackoverflow.com/questions/31065193/passing-properties-to-a-gradle-build")]),_v(" "),_c('a',{attrs:{"href":"https://www.youtube.com/watch?v=g56O_HeefBE"}},[_v("https://www.youtube.com/watch?v=g56O_HeefBE")]),_v(" "),_c('a',{attrs:{"href":"https://docs.gradle.org/current/userguide/build_lifecycle.html"}},[_v("https://docs.gradle.org/current/userguide/build_lifecycle.html")]),_v(" "),_c('a',{attrs:{"href":"http://www.joantolos.com/blog/gradletask/"}},[_v("http://www.joantolos.com/blog/gradletask/")])]),_v(" "),_c('h3',{attrs:{"id":"git"}},[_v("Git"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#git","onclick":"event.stopPropagation()"}})]),_v(" "),_c('h4',{attrs:{"id":"fetching"}},[_v("Fetching"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#fetching","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("During PR reviews, I learnt that it is sometimes better to see the changes a person has made directly in my browser. Previously, I was only familiar with "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("git pull")]),_v(" which under the hood combined the fetch and the merge into a single step, but required the branch to track a remote which was not feasible for PR reviewing since this remote would be used once or at most a few times. I then found that git fetch allowed you to specify the repository URL (the link used to clone a repo) and the name of the branch to fetch, assigning it to a reference called FETCH_HEAD, which can be checkout-ed. This allowed me to quickly fetch the branch and switch into it and make some testing, usually I would also create a temporary branch so that I can check on the changes at another time.")]),_v(" "),_c('p',[_c('a',{attrs:{"href":"https://www.atlassian.com/git/tutorials/syncing/git-fetch"}},[_v("https://www.atlassian.com/git/tutorials/syncing/git-fetch")]),_v(" "),_c('a',{attrs:{"href":"https://git-scm.com/docs/git-fetch"}},[_v("https://git-scm.com/docs/git-fetch")])]),_v(" "),_c('h4',{attrs:{"id":"rebasing"}},[_v("Rebasing"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#rebasing","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("When my team started to work on the notification banner feature, we realised that no matter how much planning is done, it was sometimes inevitable for our code to be dependent on someone elses. Instead of more conventional methods such as copying pasting code, which does not have the benefit of resolving conflicts, merging branches into my working branch would also be messy since their branches are actively updated, sometimes even force pushed. Instead, I learnt how to rebase from my teammates, which lets you put a series of commits on your branch on top another branch. This can be done several times, if a branch X is in turn dependent on branch Y, and you require Y. One downside is that you would have to fetch and update each branch and perform a rebase ontop of this new branch, but this is a small cost instead of rushing out a PR or idling, when the code you require is completed but just not merged into master.")])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/Nicolascwy/observations.html b/students/Nicolascwy/observations.html index 4625b633d..2b3dc9ec7 100644 --- a/students/Nicolascwy/observations.html +++ b/students/Nicolascwy/observations.html @@ -12,7 +12,7 @@ const baseUrl = '/2024' -

    Project: MermaidJS

    JavaScript based diagramming and charting tool that renders Markdown-inspired text definitions to create and modify diagrams dynamically.

    My Contributions

    While setting up the MermaidJS code base I realised that the recommended VSCode extension for Vitest (Community made) was deprecated and was replaced with the updated version maintained by the Vitest team. I had then filed an issue and made a PR to update this(merged).

    While understanding the codebase to solve this PR (to be solved) which involved adding additional funcionality to git diagrams, I realised that there was an undocumented feature that was merged a few versions ago. I had then filed an issue an added this to the documentation (merged)

    I am in the process of converting gitGraph functions from JS to TS in this PR. This is how Mermaid maintains an internal structure of what should be rendered. This would then be followed up by another PR to change the language parser used from BISON to Langium, which provide nicer features for users.

    My Learning Record

    BISON/ Langium Parser Generator

    I'm still in the midst of learning this, but I've learned that parsers can be generated using programs such as BISON and Langium. Mermaid is built on JIISON a BISON implementation in JS which has been unofficially deprecated and has been trying to make a move to move away from this to a maintained alternative Langium. I would be trying to learn BISON and rewrite some parts of the git graph parser to make it more flexible in allowing me to implement new features.

    Resources: GNU BISON Documentation

    Observations from contributing process

    • Github Issues from users: Issues are initiated from the ground up from users and are discussed with maintainers
    • Management of PRs: Maintainers will commit directly to the fork for branches if changes required are help push PRs to completion
    • Detailed Issues: Extensive communication in the issues about design decisions and proposals are in the issue allowing new contributors to follow the thought process and pick it up if they are interested.
    +

    Project: MermaidJS

    JavaScript based diagramming and charting tool that renders Markdown-inspired text definitions to create and modify diagrams dynamically.

    My Contributions

    While setting up the MermaidJS code base I realised that the recommended VSCode extension for Vitest (Community made) was deprecated and was replaced with the updated version maintained by the Vitest team. I had then filed an issue and made a PR to update this(merged).

    While understanding the codebase to solve this PR (to be solved) which involved adding additional funcionality to git diagrams, I realised that there was an undocumented feature that was merged a few versions ago. I had then filed an issue an added this to the documentation (merged)

    I am in the process of converting gitGraph functions from JS to TS in this PR. This is how Mermaid maintains an internal structure of what should be rendered. This would then be followed up by another PR to change the language parser used from BISON to Langium, which provide nicer features for users.

    My Learning Record

    BISON/ Langium Parser Generator

    I'm still in the midst of learning this, but I've learned that parsers can be generated using programs such as BISON and Langium. Mermaid is built on JIISON a BISON implementation in JS which has been unofficially deprecated and has been trying to make a move to move away from this to a maintained alternative Langium. I would be trying to learn BISON and rewrite some parts of the git graph parser to make it more flexible in allowing me to implement new features.

    Resources: GNU BISON Documentation

    Observations from contributing process

    • Github Issues from users: Issues are initiated from the ground up from users and are discussed with maintainers
    • Management of PRs: Maintainers will commit directly to the fork for branches if changes required are help push PRs to completion
    • Detailed Issues: Extensive communication in the issues about design decisions and proposals are in the issue allowing new contributors to follow the thought process and pick it up if they are interested.
    diff --git a/students/Nicolascwy/observations.page-vue-render.js b/students/Nicolascwy/observations.page-vue-render.js index bc821a336..e65072386 100644 --- a/students/Nicolascwy/observations.page-vue-render.js +++ b/students/Nicolascwy/observations.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('h3',{attrs:{"id":"project-mermaidjs"}},[_v("Project: MermaidJS"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#project-mermaidjs","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("JavaScript based diagramming and charting tool that renders Markdown-inspired text definitions to create and modify diagrams dynamically.")]),_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("While setting up the MermaidJS code base I realised that the recommended VSCode extension for Vitest (Community made) was deprecated and was replaced with the updated version maintained by the Vitest team. I had then filed an "),_c('a',{attrs:{"href":"https://github.com/mermaid-js/mermaid/issues/5321"}},[_v("issue")]),_v(" and made a "),_c('a',{attrs:{"href":"https://github.com/mermaid-js/mermaid/pull/5322"}},[_v("PR to update this(merged)")]),_v(".")]),_v(" "),_c('p',[_v("While understanding the codebase to solve this "),_c('a',{attrs:{"href":"https://github.com/mermaid-js/mermaid/issues/3801"}},[_v("PR")]),_v(" (to be solved) which involved adding additional funcionality to git diagrams, I realised that there was an undocumented feature that was merged a few versions ago. I had then filed an "),_c('a',{attrs:{"href":"https://github.com/mermaid-js/mermaid/issues/5324"}},[_v("issue")]),_v(" an "),_c('a',{attrs:{"href":"https://github.com/mermaid-js/mermaid/pull/5336"}},[_v("added this to the documentation (merged)")])]),_v(" "),_c('p',[_v("I am in the process of converting gitGraph functions from JS to TS in this "),_c('a',{attrs:{"href":"https://github.com/mermaid-js/mermaid/pull/5407"}},[_v("PR")]),_v(". This is how Mermaid maintains an internal structure of what should be rendered. This would then be followed up by another PR to change the language parser used from BISON to Langium, which provide nicer features for users.")]),_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('h4',{attrs:{"id":"bison-langium-parser-generator"}},[_v("BISON/ Langium Parser Generator"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#bison-langium-parser-generator","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("I'm still in the midst of learning this, but I've learned that parsers can be generated using programs such as BISON and Langium. Mermaid is built on JIISON a BISON implementation in JS which has been unofficially deprecated and has been trying to make a move to move away from this to a maintained alternative Langium. I would be trying to learn BISON and rewrite some parts of the git graph parser to make it more flexible in allowing me to implement new features.")]),_v(" "),_c('p',[_v("Resources: "),_c('a',{attrs:{"href":"https://www.gnu.org/software/bison/manual/html_node/index.html"}},[_v("GNU BISON Documentation")])]),_v(" "),_c('h4',{attrs:{"id":"observations-from-contributing-process"}},[_v("Observations from contributing process"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#observations-from-contributing-process","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ul',[_c('li',[_c('strong',[_v("Github Issues from users")]),_v(": Issues are initiated from the ground up from users and are discussed with maintainers")]),_v(" "),_c('li',[_c('strong',[_v("Management of PRs")]),_v(": Maintainers will commit directly to the fork for branches if changes required are help push PRs to completion")]),_v(" "),_c('li',[_c('strong',[_v("Detailed Issues")]),_v(": Extensive communication in the issues about design decisions and proposals are in the issue allowing new contributors to follow the thought process and pick it up if they are interested.")])])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/Nicolascwy/progress.html b/students/Nicolascwy/progress.html index e6437bcf3..a18e6443d 100644 --- a/students/Nicolascwy/progress.html +++ b/students/Nicolascwy/progress.html @@ -12,7 +12,7 @@ const baseUrl = '/2024' -

    TEAMMATES

    Overview

    • Led initial V9 non-course data migration.
    • Assisted in unit test migration.
    • Took part in Multiple course structure design
    • Contributed to V9 related documentations in maintainer guide.
    • Led V9 course data migration to onboard and manage a group of junior engineers.
    • Mentored and reviewed contributions by junior engineers

    Achievements by week

    Week Achievements
    Pre-3282 Reviewed PR: Update tzdb version to 2022a #11792
    Pre-3282 Reviewed PR: Add support for multiples of 5 for team contribution question #11842
    Pre-3282 Reviewed PR: Refactor NavigationService to use Angular's dependency injection for services
    Pre-3282 Reviewed PR: Differentiate button/dialog for individual/all-question submissions #11856
    Pre-3282 Reviewed PR: Warn user before deleting last course #11874
    Pre-3282 Reviewed PR: Disable 'Individual Deadline Extensions' link when creating a new session #11877
    Pre-3282 Reviewed PR: 'Session closing soon' email: highlight 'No action is required if you have already submitted' #11897
    Pre-3282 Reviewed PR: Apply lazy-loading of question responses in session results page #11905
    Pre-3282 Reviewed PR: Deleting the last instructor in the course leaves a dangling course object in the database #11930
    Pre-3282 Reviewed PR: Fix instructors with custom permissions cannot view student list #11940
    Pre-3282 Reviewed PR: InstructorFeedbackEditPage: include question type help in lightbox #11949
    Pre-3282 Reviewed PR: Fix bug with overflow of members count in error message #11953
    Pre-3282 Reviewed PR: Feedback Rubric Question: Suggestion for Statistics Per Recipient #11984
    Pre-3282 Reviewed PR: Add test in student course details page. #11990
    Pre-3282 Reviewed PR: Student home page: Make it easier to navigate courses #12493
    Pre-3282 Merged PR: Add verification step for Docker instance of Datastore in docs #12465
    3 Reviewed PR: Migrate CreateInstructorAction #12706
    4 Reviewed PR: Migrate instructor search indexing worker action #12731
    4 Reviewed PR: Migrate SubmitFeedbackResponseAction's Logic and Db methods
    4 Merged PR: Add SQL email generator unit test #12721
    4 Merged PR: Refactor email generator #12723
    5 Merged PR: Migrate Session Links Recovery Action #12712
    6 Reviewed PR: Migrate UpdateStudentAction #12727
    6 Reviewed PR: Add testcases for FeedbackResponseCommentsLogicTest #12769
    6 Reviewed PR: Bump up postgresql version #12784
    6 Reviewed PR: Add migration script for Usage Statistics #12798
    6 Reviewed PR: Add migration script for Account Request #12799
    6 Reviewed PR: Add testcases for FeedbackResponseCommentsDbTest #12755
    6 Reviewed PR: Add Account and Read Notification #12796
    6 Merged PR: Clean up seed script #12768
    6 Participated in Teammates hackathon Day 1
    Reading Merged PR: Create script to verify row count for non-course entities #12824
    Reading Merged PR: Add base script for verifying migrated attributes #12841
    Reading Merged PR: Add verification for account and notification #12843
    Reading Reviewed PR: Add migration script for Usage Statistics #12798
    Reading Reviewed PR: Add migration script for Account Request #12799
    Reading Reviewed PR: Revert getFilterQuery for Account Data Migration Script #12796
    7 Merged PR: Fix seeding for notification #12866
    7 Merged PR: Fix seeding of data for data migration #12873
    7 Merged PR: Change title and message field for notification to "TEXT" #12880
    8 Reviewed PR: V9 migration and verification script optimization #12896
    8 Merged PR: Add verification migration script #12890
    8 Migration Standby (10 March 2024)
    9 Merged PR: V9 migration verification script optimisation - fetch ReadNotifications for account comparison #12866
    9 Reviewed PR: Patch Usage Statistics Migration #12889
    9 Reviewed PR: Add SQL configuration into build.properties and build-dev.properties #12917
    9 Reviewed PR: Reintroduce AccountRequest search indexing #12923
    9 Reviewed PR: :Dev docs (E2E testing): update Chromedriver link #12924
    9 Reviewed PR: Add SQL description for postgres config #12931
    9 Reviewed PR: Fix AccountRequest migration script #12915
    10 Migration Standby (24 March 2024)
    10 Merged PR: Create script to migrate noSQL test data to SQL schema format #12922
    10 PR (Process of Review ): Update liquibase configuration #12930
    10 Merged PR: Relax read notif verification for migration verification script #12937
    10 Reviewed PR: Rerunnable Account Request Migration Script #12932
    10 Reviewed PR: add delay to task queuer for indexing account request #12936
    11 Merged PR: V9 Migration Schema Migration Tool (Liquibase) Documentation #37
    11 Merged PR: Remove feedbackSession attributes @fetch annotation #12992
    11 Reviewed PR: Configure connection pool using hikari #12978
    11 Reviewed PR: Data migration for course entities #12980
    11 Reviewed PR: Data migration for feedback session entities #12986
    11 Reviewed PR: SeedDb code for student entities #12990
    11 Reviewed PR: Data migration for section entities #12991
    12 Merged PR: Add v9.0.0 tag to liquibase changelog #13005
    12 Merged PR: Add note on Liquibase #38
    12 Reviewed PR: Data migration for team entities #13010
    13 Merged PR: Update changelog docs and changelog name #13062
    13 Merged PR: Update schema migration docs #40
    13 Reviewed PR: data migration student chain students #13036
    R Merged PR: Add patch script for account request and notifications to amend createdAt field #13077
    R Merged PR: Fix seed, migration and verification script for course verification #13086
    R Merged PR: Remove clear datastore function #13088
    R Merged PR: Add dangling course delete script #13090
    R Merged PR: Add unique field to patch account request timestamp script #13093
    R Reviewed PR: Data migration section chain fixs #13042
    R Reviewed PR: Data migration for feedback entities chain #13045
    R Reviewed PR: Data migration: ensure consistency when script is stopped and resumed #13046
    R Reviewed PR: Add composite index for data migration #13057
    R Reviewed PR: Add migration script for instructors and Deadline Extensions #13071
    R Reviewed PR: associate account to migrated users #13073
    R Reviewed PR: Add seed and verification scripts for feedback chain #13074
    R Reviewed PR: Delete redundant index #13095
    R Reviewed PR: Add note to check liquibase command run correctly #41
    R Standby for ARF release - support liquibase configuration
    R Standby for V9 course migration trial
    +

    TEAMMATES

    Overview

    • Led initial V9 non-course data migration.
    • Assisted in unit test migration.
    • Took part in Multiple course structure design
    • Contributed to V9 related documentations in maintainer guide.
    • Led V9 course data migration to onboard and manage a group of junior engineers.
    • Mentored and reviewed contributions by junior engineers

    Achievements by week

    Week Achievements
    Pre-3282 Reviewed PR: Update tzdb version to 2022a #11792
    Pre-3282 Reviewed PR: Add support for multiples of 5 for team contribution question #11842
    Pre-3282 Reviewed PR: Refactor NavigationService to use Angular's dependency injection for services
    Pre-3282 Reviewed PR: Differentiate button/dialog for individual/all-question submissions #11856
    Pre-3282 Reviewed PR: Warn user before deleting last course #11874
    Pre-3282 Reviewed PR: Disable 'Individual Deadline Extensions' link when creating a new session #11877
    Pre-3282 Reviewed PR: 'Session closing soon' email: highlight 'No action is required if you have already submitted' #11897
    Pre-3282 Reviewed PR: Apply lazy-loading of question responses in session results page #11905
    Pre-3282 Reviewed PR: Deleting the last instructor in the course leaves a dangling course object in the database #11930
    Pre-3282 Reviewed PR: Fix instructors with custom permissions cannot view student list #11940
    Pre-3282 Reviewed PR: InstructorFeedbackEditPage: include question type help in lightbox #11949
    Pre-3282 Reviewed PR: Fix bug with overflow of members count in error message #11953
    Pre-3282 Reviewed PR: Feedback Rubric Question: Suggestion for Statistics Per Recipient #11984
    Pre-3282 Reviewed PR: Add test in student course details page. #11990
    Pre-3282 Reviewed PR: Student home page: Make it easier to navigate courses #12493
    Pre-3282 Merged PR: Add verification step for Docker instance of Datastore in docs #12465
    3 Reviewed PR: Migrate CreateInstructorAction #12706
    4 Reviewed PR: Migrate instructor search indexing worker action #12731
    4 Reviewed PR: Migrate SubmitFeedbackResponseAction's Logic and Db methods
    4 Merged PR: Add SQL email generator unit test #12721
    4 Merged PR: Refactor email generator #12723
    5 Merged PR: Migrate Session Links Recovery Action #12712
    6 Reviewed PR: Migrate UpdateStudentAction #12727
    6 Reviewed PR: Add testcases for FeedbackResponseCommentsLogicTest #12769
    6 Reviewed PR: Bump up postgresql version #12784
    6 Reviewed PR: Add migration script for Usage Statistics #12798
    6 Reviewed PR: Add migration script for Account Request #12799
    6 Reviewed PR: Add testcases for FeedbackResponseCommentsDbTest #12755
    6 Reviewed PR: Add Account and Read Notification #12796
    6 Merged PR: Clean up seed script #12768
    6 Participated in Teammates hackathon Day 1
    Reading Merged PR: Create script to verify row count for non-course entities #12824
    Reading Merged PR: Add base script for verifying migrated attributes #12841
    Reading Merged PR: Add verification for account and notification #12843
    Reading Reviewed PR: Add migration script for Usage Statistics #12798
    Reading Reviewed PR: Add migration script for Account Request #12799
    Reading Reviewed PR: Revert getFilterQuery for Account Data Migration Script #12796
    7 Merged PR: Fix seeding for notification #12866
    7 Merged PR: Fix seeding of data for data migration #12873
    7 Merged PR: Change title and message field for notification to "TEXT" #12880
    8 Reviewed PR: V9 migration and verification script optimization #12896
    8 Merged PR: Add verification migration script #12890
    8 Migration Standby (10 March 2024)
    9 Merged PR: V9 migration verification script optimisation - fetch ReadNotifications for account comparison #12866
    9 Reviewed PR: Patch Usage Statistics Migration #12889
    9 Reviewed PR: Add SQL configuration into build.properties and build-dev.properties #12917
    9 Reviewed PR: Reintroduce AccountRequest search indexing #12923
    9 Reviewed PR: :Dev docs (E2E testing): update Chromedriver link #12924
    9 Reviewed PR: Add SQL description for postgres config #12931
    9 Reviewed PR: Fix AccountRequest migration script #12915
    10 Migration Standby (24 March 2024)
    10 Merged PR: Create script to migrate noSQL test data to SQL schema format #12922
    10 PR (Process of Review ): Update liquibase configuration #12930
    10 Merged PR: Relax read notif verification for migration verification script #12937
    10 Reviewed PR: Rerunnable Account Request Migration Script #12932
    10 Reviewed PR: add delay to task queuer for indexing account request #12936
    11 Merged PR: V9 Migration Schema Migration Tool (Liquibase) Documentation #37
    11 Merged PR: Remove feedbackSession attributes @fetch annotation #12992
    11 Reviewed PR: Configure connection pool using hikari #12978
    11 Reviewed PR: Data migration for course entities #12980
    11 Reviewed PR: Data migration for feedback session entities #12986
    11 Reviewed PR: SeedDb code for student entities #12990
    11 Reviewed PR: Data migration for section entities #12991
    12 Merged PR: Add v9.0.0 tag to liquibase changelog #13005
    12 Merged PR: Add note on Liquibase #38
    12 Reviewed PR: Data migration for team entities #13010
    13 Merged PR: Update changelog docs and changelog name #13062
    13 Merged PR: Update schema migration docs #40
    13 Reviewed PR: data migration student chain students #13036
    R Merged PR: Add patch script for account request and notifications to amend createdAt field #13077
    R Merged PR: Fix seed, migration and verification script for course verification #13086
    R Merged PR: Remove clear datastore function #13088
    R Merged PR: Add dangling course delete script #13090
    R Merged PR: Add unique field to patch account request timestamp script #13093
    R Reviewed PR: Data migration section chain fixs #13042
    R Reviewed PR: Data migration for feedback entities chain #13045
    R Reviewed PR: Data migration: ensure consistency when script is stopped and resumed #13046
    R Reviewed PR: Add composite index for data migration #13057
    R Reviewed PR: Add migration script for instructors and Deadline Extensions #13071
    R Reviewed PR: associate account to migrated users #13073
    R Reviewed PR: Add seed and verification scripts for feedback chain #13074
    R Reviewed PR: Delete redundant index #13095
    R Reviewed PR: Add note to check liquibase command run correctly #41
    R Standby for ARF release - support liquibase configuration
    R Standby for V9 course migration trial
    diff --git a/students/Nicolascwy/progress.page-vue-render.js b/students/Nicolascwy/progress.page-vue-render.js index e5636ecbf..678d49d7a 100644 --- a/students/Nicolascwy/progress.page-vue-render.js +++ b/students/Nicolascwy/progress.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('h3',{attrs:{"id":"teammates"}},[_v("TEAMMATES"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#teammates","onclick":"event.stopPropagation()"}})]),_v(" "),_c('h4',{attrs:{"id":"overview"}},[_v("Overview"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#overview","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ul',[_c('li',[_v("Led initial V9 non-course data migration.")]),_v(" "),_c('li',[_v("Assisted in unit test migration.")]),_v(" "),_c('li',[_v("Took part in Multiple course structure design")]),_v(" "),_c('li',[_v("Contributed to V9 related documentations in maintainer guide.")]),_v(" "),_c('li',[_v("Led V9 course data migration to onboard and manage a group of junior engineers.")]),_v(" "),_c('li',[_v("Mentored and reviewed contributions by junior engineers")])]),_v(" "),_c('h4',{attrs:{"id":"achievements-by-week"}},[_v("Achievements by week"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#achievements-by-week","onclick":"event.stopPropagation()"}})]),_v(" "),_c('div',{staticClass:"table-responsive"},[_c('table',{staticClass:"markbind-table table table-bordered table-striped"},[_c('thead',[_c('tr',[_c('th',[_v("Week")]),_v(" "),_c('th',[_v("Achievements")])])]),_v(" "),_c('tbody',[_c('tr',[_c('td',[_v("Pre-3282")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/11792"}},[_v("Update tzdb version to 2022a #11792")])])]),_v(" "),_c('tr',[_c('td',[_v("Pre-3282")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/11842"}},[_v("Add support for multiples of 5 for team contribution question #11842")])])]),_v(" "),_c('tr',[_c('td',[_v("Pre-3282")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/11855"}},[_v("Refactor NavigationService to use Angular's dependency injection for services")])])]),_v(" "),_c('tr',[_c('td',[_v("Pre-3282")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/11856"}},[_v("Differentiate button/dialog for individual/all-question submissions #11856")])])]),_v(" "),_c('tr',[_c('td',[_v("Pre-3282")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/11874"}},[_v("Warn user before deleting last course #11874")])])]),_v(" "),_c('tr',[_c('td',[_v("Pre-3282")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/11877"}},[_v("Disable 'Individual Deadline Extensions' link when creating a new session #11877")])])]),_v(" "),_c('tr',[_c('td',[_v("Pre-3282")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/11897"}},[_v("'Session closing soon' email: highlight 'No action is required if you have already submitted' #11897")])])]),_v(" "),_c('tr',[_c('td',[_v("Pre-3282")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/11905"}},[_v("Apply lazy-loading of question responses in session results page #11905")])])]),_v(" "),_c('tr',[_c('td',[_v("Pre-3282")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/11930"}},[_v("Deleting the last instructor in the course leaves a dangling course object in the database #11930")])])]),_v(" "),_c('tr',[_c('td',[_v("Pre-3282")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/11940"}},[_v("Fix instructors with custom permissions cannot view student list #11940")])])]),_v(" "),_c('tr',[_c('td',[_v("Pre-3282")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/11949"}},[_v("InstructorFeedbackEditPage: include question type help in lightbox #11949")])])]),_v(" "),_c('tr',[_c('td',[_v("Pre-3282")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/11953"}},[_v("Fix bug with overflow of members count in error message #11953")])])]),_v(" "),_c('tr',[_c('td',[_v("Pre-3282")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/11984"}},[_v("Feedback Rubric Question: Suggestion for Statistics Per Recipient #11984")])])]),_v(" "),_c('tr',[_c('td',[_v("Pre-3282")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/11990"}},[_v("Add test in student course details page. #11990")])])]),_v(" "),_c('tr',[_c('td',[_v("Pre-3282")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12493"}},[_v("Student home page: Make it easier to navigate courses #12493")])])]),_v(" "),_c('tr',[_c('td',[_v("Pre-3282")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12465"}},[_v("Add verification step for Docker instance of Datastore in docs #12465")])])]),_v(" "),_c('tr',[_c('td',[_v("3")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12706"}},[_v("Migrate CreateInstructorAction #12706")])])]),_v(" "),_c('tr',[_c('td',[_v("4")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12731"}},[_v("Migrate instructor search indexing worker action #12731")])])]),_v(" "),_c('tr',[_c('td',[_v("4")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12732"}},[_v("Migrate SubmitFeedbackResponseAction's Logic and Db methods")])])]),_v(" "),_c('tr',[_c('td',[_v("4")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12721"}},[_v("Add SQL email generator unit test #12721")])])]),_v(" "),_c('tr',[_c('td',[_v("4")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12723"}},[_v("Refactor email generator #12723")])])]),_v(" "),_c('tr',[_c('td',[_v("5")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12712"}},[_v("Migrate Session Links Recovery Action #12712")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12727"}},[_v("Migrate UpdateStudentAction #12727")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12769"}},[_v(" Add testcases for FeedbackResponseCommentsLogicTest #12769 ")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12784"}},[_v("Bump up postgresql version #12784")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12798"}},[_v("Add migration script for Usage Statistics #12798")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12799"}},[_v("Add migration script for Account Request #12799")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12755"}},[_v(" Add testcases for FeedbackResponseCommentsDbTest #12755 ")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12796"}},[_v(" Add Account and Read Notification #12796")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12768"}},[_v("Clean up seed script #12768 ")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Participated in Teammates hackathon Day 1")])]),_v(" "),_c('tr',[_c('td',[_v("Reading")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12824"}},[_v("Create script to verify row count for non-course entities #12824")])])]),_v(" "),_c('tr',[_c('td',[_v("Reading")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12841"}},[_v("Add base script for verifying migrated attributes #12841 ")])])]),_v(" "),_c('tr',[_c('td',[_v("Reading")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12727"}},[_v("Add verification for account and notification #12843 ")])])]),_v(" "),_c('tr',[_c('td',[_v("Reading")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12798"}},[_v("Add migration script for Usage Statistics #12798")])])]),_v(" "),_c('tr',[_c('td',[_v("Reading")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12799"}},[_v("Add migration script for Account Request #12799")])])]),_v(" "),_c('tr',[_c('td',[_v("Reading")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12796"}},[_v("Revert getFilterQuery for Account Data Migration Script #12796")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12866"}},[_v("Fix seeding for notification #12866 ")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12873"}},[_v("Fix seeding of data for data migration #12873 ")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12880"}},[_v("Change title and message field for notification to \"TEXT\" #12880 ")])])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12896"}},[_v("V9 migration and verification script optimization #12896")])])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12890"}},[_v("Add verification migration script #12890 ")])])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_v("Migration Standby (10 March 2024)")])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12905"}},[_v("V9 migration verification script optimisation - fetch ReadNotifications for account comparison #12866 ")])])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12889"}},[_v("Patch Usage Statistics Migration #12889")])])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12917"}},[_v("Add SQL configuration into build.properties and build-dev.properties #12917")])])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12796"}},[_v("Reintroduce AccountRequest search indexing #12923")])])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12924"}},[_v(":Dev docs (E2E testing): update Chromedriver link #12924")])])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12796"}},[_v("Add SQL description for postgres config #12931")])])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12915"}},[_v("Fix AccountRequest migration script #12915")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Migration Standby (24 March 2024)")])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12922"}},[_v("Create script to migrate noSQL test data to SQL schema format #12922 ")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("PR (Process of Review ): "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12930"}},[_v("Update liquibase configuration #12930 ")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12866"}},[_v("Relax read notif verification for migration verification script #12937 ")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12932"}},[_v("Rerunnable Account Request Migration Script #12932")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12936"}},[_v("add delay to task queuer for indexing account request #12936")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates-ops/pull/37"}},[_v("V9 Migration Schema Migration Tool (Liquibase) Documentation #37")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12992"}},[_v("Remove feedbackSession attributes @fetch annotation #12992")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12978"}},[_v("Configure connection pool using hikari #12978")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12980"}},[_v("Data migration for course entities #12980")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12986"}},[_v("Data migration for feedback session entities #12986")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12990"}},[_v("SeedDb code for student entities #12990")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12991"}},[_v("Data migration for section entities #12991")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13005"}},[_v("Add v9.0.0 tag to liquibase changelog #13005")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates-ops/pull/38"}},[_v("Add note on Liquibase #38")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13010"}},[_v("Data migration for team entities #13010")])])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13062"}},[_v("Update changelog docs and changelog name #13062")])])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12936"}},[_v("Update schema migration docs #40")])])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13036"}},[_v("data migration student chain students #13036")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13077"}},[_v("Add patch script for account request and notifications to amend createdAt field #13077")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13086"}},[_v("Fix seed, migration and verification script for course verification #13086")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13088"}},[_v("Remove clear datastore function #13088")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13090"}},[_v("Add dangling course delete script #13090")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13093"}},[_v("Add unique field to patch account request timestamp script #13093")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13042"}},[_v("Data migration section chain fixs #13042")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13045"}},[_v("Data migration for feedback entities chain #13045")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13046"}},[_v("Data migration: ensure consistency when script is stopped and resumed #13046")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13057"}},[_v("Add composite index for data migration #13057")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13071"}},[_v("Add migration script for instructors and Deadline Extensions #13071")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13073"}},[_v("associate account to migrated users #13073")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13074"}},[_v("Add seed and verification scripts for feedback chain #13074")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13095"}},[_v("Delete redundant index #13095")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates-ops/pull/41"}},[_v("Add note to check liquibase command run correctly #41")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Standby for ARF release - support liquibase configuration")])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Standby for V9 course migration trial")])])])])])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/Tim-Siu/info.html b/students/Tim-Siu/info.html index d25d55d87..75c354d75 100644 --- a/students/Tim-Siu/info.html +++ b/students/Tim-Siu/info.html @@ -12,7 +12,7 @@ const baseUrl = '/2024' - + diff --git a/students/Tim-Siu/info.page-vue-render.js b/students/Tim-Siu/info.page-vue-render.js index 1a3ad8715..8e1616733 100644 --- a/students/Tim-Siu/info.page-vue-render.js +++ b/students/Tim-Siu/info.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('p',[_c('span',{attrs:{"id":"github"}},[_c('a',{attrs:{"href":"https://www.github.com/Tim-Siu"}},[_v("https://www.github.com/Tim-Siu")])])]),_v(" "),_c('p',[_c('span',{attrs:{"id":"projects"}},[_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind"}},[_v("MarkBind")])])])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/Tim-Siu/knowledge.html b/students/Tim-Siu/knowledge.html index 07ab861fc..3878aae9b 100644 --- a/students/Tim-Siu/knowledge.html +++ b/students/Tim-Siu/knowledge.html @@ -93,7 +93,7 @@ export default { // Exported properties and methods } -

    ESM provides benefits such as static analysis, tree shaking, and better performance compared to CJS. However, CJS is still widely used, especially in older codebases and libraries.

    Differences between CJS and ESM

    • Syntax: CJS uses require() and module.exports, while ESM uses import and export.
    • Synchronous vs. Asynchronous: CJS imports are synchronous and blocking, while ESM imports are asynchronous and non-blocking.
    • Browser Support: ESM is supported natively in modern browsers, while CJS requires a bundler or transpiler for browser compatibility.
    • Interoperability: ESM and CJS modules can interoperate to some extent, but there are differences in how they handle default exports and named exports.

    Node.js supports both CJS and ESM, and the module system used depends on the file extension (.mjs for ESM and .js for CJS) or the "type": "module" field in the package.json file.

    HTML and DOM Rendering Order

    When a web page is loaded, the browser follows a specific order to render the content:

    1. Parsing HTML: The browser parses the HTML document and constructs the Document Object Model (DOM) tree.
    2. Loading External Resources: The browser loads external resources such as CSS files, JavaScript files, and images referenced in the HTML.
    3. Constructing the CSSOM: The browser parses the CSS and constructs the CSS Object Model (CSSOM) tree.
    4. Executing JavaScript: The browser executes JavaScript code, which can manipulate the DOM and CSSOM.
    5. Rendering: The browser combines the DOM and CSSOM to create the render tree, which represents the visual layout of the page. It then paints the pixels on the screen.

    Content partially generated by GenAI

    +

    ESM provides benefits such as static analysis, tree shaking, and better performance compared to CJS. However, CJS is still widely used, especially in older codebases and libraries.

    Differences between CJS and ESM

    • Syntax: CJS uses require() and module.exports, while ESM uses import and export.
    • Synchronous vs. Asynchronous: CJS imports are synchronous and blocking, while ESM imports are asynchronous and non-blocking.
    • Browser Support: ESM is supported natively in modern browsers, while CJS requires a bundler or transpiler for browser compatibility.
    • Interoperability: ESM and CJS modules can interoperate to some extent, but there are differences in how they handle default exports and named exports.

    Node.js supports both CJS and ESM, and the module system used depends on the file extension (.mjs for ESM and .js for CJS) or the "type": "module" field in the package.json file.

    HTML and DOM Rendering Order

    When a web page is loaded, the browser follows a specific order to render the content:

    1. Parsing HTML: The browser parses the HTML document and constructs the Document Object Model (DOM) tree.
    2. Loading External Resources: The browser loads external resources such as CSS files, JavaScript files, and images referenced in the HTML.
    3. Constructing the CSSOM: The browser parses the CSS and constructs the CSS Object Model (CSSOM) tree.
    4. Executing JavaScript: The browser executes JavaScript code, which can manipulate the DOM and CSSOM.
    5. Rendering: The browser combines the DOM and CSSOM to create the render tree, which represents the visual layout of the page. It then paints the pixels on the screen.

    Content partially generated by GenAI

    diff --git a/students/Tim-Siu/knowledge.page-vue-render.js b/students/Tim-Siu/knowledge.page-vue-render.js index aead81d32..106dd482c 100644 --- a/students/Tim-Siu/knowledge.page-vue-render.js +++ b/students/Tim-Siu/knowledge.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('h2',{attrs:{"id":"how-markbind-works"}},[_v("How MarkBind Works"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#how-markbind-works","onclick":"event.stopPropagation()"}})]),_v(" "),_c('h3',{attrs:{"id":"markbind-rendering-flow"}},[_v("MarkBind Rendering Flow"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#markbind-rendering-flow","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("The rendering flow for creating a complete website from Markdown using MarkBind involves several key components and processes:")]),_v(" "),_c('ol',[_c('li',[_c('strong',[_v("Site Initialization")]),_v(":")])]),_v(" "),_c('ul',[_c('li',[_v("The rendering process starts with the initialization of a "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Site")]),_v(" instance in "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Site/index.ts")]),_v(".")]),_v(" "),_c('li',[_v("The "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Site")]),_v(" constructor sets up the necessary paths, templates, and initializes various managers and processors.")])]),_v(" "),_c('ol',{attrs:{"start":"2"}},[_c('li',[_c('strong',[_v("Site Configuration")]),_v(":")])]),_v(" "),_c('ul',[_c('li',[_v("The "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("readSiteConfig")]),_v(" method in "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Site/index.ts")]),_v(" reads the site configuration file ("),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("site.json")]),_v(") using the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("SiteConfig")]),_v(" class.")]),_v(" "),_c('li',[_v("The site configuration includes settings such as base URL, page configuration, asset paths, and more.")])]),_v(" "),_c('ol',{attrs:{"start":"3"}},[_c('li',[_c('strong',[_v("Page Collection")]),_v(":")])]),_v(" "),_c('ul',[_c('li',[_v("The "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("collectAddressablePages")]),_v(" method in "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Site/index.ts")]),_v(" collects the addressable pages based on the site configuration.")]),_v(" "),_c('li',[_v("It processes the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("pages")]),_v(" and "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("pagesExclude")]),_v(" options to determine the valid pages.")])]),_v(" "),_c('ol',{attrs:{"start":"4"}},[_c('li',[_c('strong',[_v("Plugin Setup")]),_v(":")])]),_v(" "),_c('ul',[_c('li',[_v("The "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("PluginManager")]),_v(" class in "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("plugins/PluginManager.ts")]),_v(" handles the initialization and management of plugins.")]),_v(" "),_c('li',[_v("It collects the specified plugins from the site configuration and loads them using the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Plugin")]),_v(" class.")])]),_v(" "),_c('ol',{attrs:{"start":"5"}},[_c('li',[_c('strong',[_v("Asset Building")]),_v(":")])]),_v(" "),_c('ul',[_c('li',[_v("The "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("buildAssets")]),_v(" method in "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Site/index.ts")]),_v(" builds the necessary assets for the site.")]),_v(" "),_c('li',[_v("It copies the specified assets from the site's root path to the output path.")])]),_v(" "),_c('ol',{attrs:{"start":"6"}},[_c('li',[_c('strong',[_v("Markdown Processing")]),_v(":")])]),_v(" "),_c('ul',[_c('li',[_v("The "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("generatePages")]),_v(" method in "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Site/index.ts")]),_v(" initiates the rendering process for each page.")]),_v(" "),_c('li',[_v("It creates a "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Page")]),_v(" instance for each page using the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("createPage")]),_v(" method.")]),_v(" "),_c('li',[_v("The "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Page")]),_v(" class in "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Page/index.ts")]),_v(" handles the rendering of individual pages.")]),_v(" "),_c('li',[_v("It uses the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("process")]),_v(" method of the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("NodeProcessor")]),_v(" class to process the Markdown content.")])]),_v(" "),_c('ol',{attrs:{"start":"7"}},[_c('li',[_c('strong',[_v("Plugin Execution")]),_v(":")])]),_v(" "),_c('ul',[_c('li',[_v("During the page rendering process, the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("PluginManager")]),_v(" executes the relevant hooks for each plugin.")]),_v(" "),_c('li',[_v("Plugins can define hooks such as "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("beforeSiteGenerate")]),_v(", "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("processNode")]),_v(", "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("postRender")]),_v(", etc., to modify the page content or perform additional tasks.")])]),_v(" "),_c('ol',{attrs:{"start":"8"}},[_c('li',[_c('strong',[_v("Layout and Template Rendering")]),_v(":")])]),_v(" "),_c('ul',[_c('li',[_v("The "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("LayoutManager")]),_v(" class in "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Layout/LayoutManager.ts")]),_v(" handles the generation and combination of layouts with pages.")]),_v(" "),_c('li',[_v("It uses the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Layout")]),_v(" class to process and render the layout files.")]),_v(" "),_c('li',[_v("The rendered pages are then passed through the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("VariableProcessor")]),_v(" to replace variables with their corresponding values.")])]),_v(" "),_c('ol',{attrs:{"start":"9"}},[_c('li',[_c('strong',[_v("Post-rendering Tasks")]),_v(":")])]),_v(" "),_c('ul',[_c('li',[_v("After rendering, additional tasks such as writing site data and copying core web assets are performed.")])]),_v(" "),_c('ol',{attrs:{"start":"10"}},[_c('li',[_c('strong',[_v("Output Generation")]),_v(":")])]),_v(" "),_c('ul',[_c('li',[_v("Finally, the rendered pages and assets are written to the output directory specified during site initialization.")])]),_v(" "),_c('h3',{attrs:{"id":"vue-js-integration-in-markbind"}},[_v("Vue.js Integration in MarkBind"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#vue-js-integration-in-markbind","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("MarkBind integrates Vue.js for building user interfaces and enhancing the rendering process. Here's how Vue.js is used in MarkBind:")]),_v(" "),_c('ul',[_c('li',[_c('p',[_c('strong',[_v("Server-Side Rendering (SSR)")]),_v(": MarkBind utilizes Vue's server-side rendering capabilities to pre-render the pages on the server. The "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("pageVueServerRenderer")]),_v(" module in "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Page/PageVueServerRenderer.ts")]),_v(" handles the compilation of Vue pages and the creation of render functions.")])]),_v(" "),_c('li',[_c('p',[_c('strong',[_v("Client-Side Hydration")]),_v(": After the initial server-side rendering, the rendered HTML is sent to the client. On the client-side, Vue takes over and hydrates the pre-rendered HTML, making it interactive and reactive.")])]),_v(" "),_c('li',[_c('p',[_c('strong',[_v("Vue Components")]),_v(": MarkBind defines various Vue components to encapsulate reusable UI elements and functionality. These components are used throughout the rendered pages to enhance the user experience.")])]),_v(" "),_c('li',[_c('p',[_c('strong',[_v("Integration with MarkBind Plugins")]),_v(": MarkBind plugins can also utilize Vue.js to extend the functionality of the application. Plugins can define custom Vue components, directives, and hooks to interact with the rendering process.")])])]),_v(" "),_c('h3',{attrs:{"id":"build-process-and-asset-management"}},[_v("Build Process and Asset Management"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#build-process-and-asset-management","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("MarkBind follows a build process to generate the final website and manage the necessary assets:")]),_v(" "),_c('ul',[_c('li',[_c('p',[_c('strong',[_v("Asset Building")]),_v(": The "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("buildAssets")]),_v(" method in "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Site/index.ts")]),_v(" handles the building of assets for the site. It copies the specified assets from the site's root path to the output path.")])]),_v(" "),_c('li',[_c('p',[_c('strong',[_v("Core Web Assets")]),_v(": MarkBind relies on core web assets such as CSS and JavaScript files. The "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("copyCoreWebAsset")]),_v(" method in "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Site/index.ts")]),_v(" copies these assets from the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("@markbind/core-web")]),_v(" package to the output directory.")])]),_v(" "),_c('li',[_c('p',[_c('strong',[_v("Plugin Assets")]),_v(": Plugins can also provide their own assets, such as CSS and JavaScript files. The "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("PluginManager")]),_v(" handles the collection and copying of plugin assets to the output directory.")])]),_v(" "),_c('li',[_c('p',[_c('strong',[_v("Icon Assets")]),_v(": MarkBind supports various icon libraries, including Font Awesome, Glyphicons, Octicons, and Material Icons. The "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("copyFontAwesomeAsset")]),_v(", "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("copyOcticonsAsset")]),_v(", and "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("copyMaterialIconsAsset")]),_v(" methods in "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Site/index.ts")]),_v(" handle the copying of these icon assets to the output directory.")])]),_v(" "),_c('li',[_c('p',[_c('strong',[_v("Bootstrap Theme")]),_v(": MarkBind allows customization of the Bootstrap theme used in the site. The "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("copyBootstrapTheme")]),_v(" method in "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Site/index.ts")]),_v(" handles the copying of the selected Bootstrap theme to the output directory.")])])]),_v(" "),_c('hr'),_v(" "),_c('h2',{attrs:{"id":"libraries-used-in-markbind"}},[_v("Libraries used in MarkBind"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#libraries-used-in-markbind","onclick":"event.stopPropagation()"}})]),_v(" "),_c('h3',{attrs:{"id":"markdown-it"}},[_v("markdown-it"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#markdown-it","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("MarkBind uses "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("markdown-it")]),_v(" for rendering html from markdown files. "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("markdown-it")]),_v(" is a fast markdown parser and has very extensive plugins support and great extensibility.")]),_v(" "),_c('h4',{attrs:{"id":"adding-custom-rules-to-markdown-it-through-adding-a-rule-to-markdown-it-s-attribute"}},[_v("Adding custom rules to "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("markdown-it")]),_v(" through adding a rule to "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("markdown-it")]),_v("'s attribute"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#adding-custom-rules-to-markdown-it-through-adding-a-rule-to-markdown-it-s-attribute","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Adding custom rules to "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("markdown-it")]),_v(" can be done easily by adding a rule to the attribute.\nFor example, if we want to add our rules for rendering fenced code blocks, we can do so by adding a rule to the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("markdown-it")]),_v("'s attribute.")]),_v(" "),_c('pre',[_c('code',{pre:true,attrs:{"class":"hljs javascript"}},[_c('span',[_v("markdownIt.renderer.rules.fence = "),_c('span',{pre:true,attrs:{"class":"hljs-function"}},[_v("("),_c('span',{pre:true,attrs:{"class":"hljs-params"}},[_v("tokens: Token[],")])]),_v("\n")]),_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-params"}},[_c('span',{pre:true,attrs:{"class":"hljs-function"}},[_v(" idx: number, options: Options, env: any, slf: Renderer")]),_v(") =>")]),_v(" {}\n")])])]),_c('p',[_c('strong',[_v("Parameters")])]),_v(" "),_c('ul',[_c('li',[_c('strong',[_v("tokens (Token[]):")]),_v(" An array of Token objects. Each token represents a segment of the parsed Markdown content. Tokens of particular interest for the fence rule include:\n"),_c('ul',[_c('li',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("token.type")]),_v(": The type of the token (e.g., 'fence', 'code', 'paragraph').")]),_v(" "),_c('li',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("token.info")]),_v(": Contains the language specified after the opening set of backticks, if any, plus additional options.")]),_v(" "),_c('li',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("token.content")]),_v(": The text content within the fenced code block.")])])]),_v(" "),_c('li',[_c('strong',[_v("idx (number):")]),_v(" The index of the current "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("fence")]),_v(" token within the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("tokens")]),_v(" array. This lets us find tokens before and after the fence if needed.")]),_v(" "),_c('li',[_c('strong',[_v("options (Options):")]),_v(" This object contains global options passed to the Markdown-it parser. This could include settings specific to our setup.")]),_v(" "),_c('li',[_c('strong',[_v("env (any):")]),_v(" An object containing environment variables and potentially additional data derived from the parsed Markdown. This can be useful for accessing context when defining rendering logic.")]),_v(" "),_c('li',[_c('strong',[_v("slf (Renderer):")]),_v(" A reference to the Markdown-it Renderer object itself. This is primarily used when we need to call other rendering rules to process nested Markdown code within the fenced block.")])]),_v(" "),_c('p',[_c('strong',[_v("Purpose of the fence renderer rule")])]),_v(" "),_c('p',[_v("The "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("markdownIt.renderer.rules.fence")]),_v(" function is responsible for taking a "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("fence")]),_v(" token (representing a fenced code block) and converting it into the appropriate HTML output. This could include syntax highlighting, if our setup supports it.")]),_v(" "),_c('p',[_c('strong',[_v("How it Works")])]),_v(" "),_c('p',[_v("Inside the function, we have access to all the information in the tokens, options, and the environment. We can craft custom logic to generate the desired HTML structure for our fenced code blocks. Here's a very basic example:")]),_v(" "),_c('pre',[_c('code',{pre:true,attrs:{"class":"hljs javascript"}},[_c('span',[_v("markdownIt.renderer.rules.fence = "),_c('span',{pre:true,attrs:{"class":"hljs-function"}},[_v("("),_c('span',{pre:true,attrs:{"class":"hljs-params"}},[_v("tokens, idx, options, env, slf")]),_v(") =>")]),_v(" {\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("const")]),_v(" token = tokens[idx];\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("const")]),_v(" content = token.content;\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("const")]),_v(" language = token.info.trim(); "),_c('span',{pre:true,attrs:{"class":"hljs-comment"}},[_v("// Language after the opening backticks")]),_v("\n")]),_c('span',[_v("\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("return")]),_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-string"}},[_v("`
    "),_c('span',{pre:true,attrs:{"class":"hljs-subst"}},[_v("${content}")]),_v("
    `")]),_v(";\n")]),_c('span',[_v("};\n")])])]),_c('h3',{attrs:{"id":"cheerio"}},[_v("Cheerio"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#cheerio","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("MarkBind uses Cheerio for parsing and manipulating the HTML structure of Markdown files after they have been processed by "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("markdown-it")]),_v(". Cheerio is a fast, flexible, and lean implementation of core jQuery designed specifically for the server.")]),_v(" "),_c('h4',{attrs:{"id":"loading-html-into-cheerio"}},[_v("Loading HTML into Cheerio"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#loading-html-into-cheerio","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("To use Cheerio, we first need to load HTML into it. This is done by passing the HTML string to the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("cheerio.load")]),_v(" function.")]),_v(" "),_c('pre',[_c('code',{pre:true,attrs:{"class":"hljs javascript"}},[_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("const")]),_v(" $ = cheerio.load("),_c('span',{pre:true,attrs:{"class":"hljs-string"}},[_v("'

    Hello world

    '")]),_v(");\n")])])]),_c('p',[_v("The "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("$")]),_v(" variable now contains a Cheerio instance that wraps the parsed HTML, and can be used similarly to how we would use jQuery in the browser.")]),_v(" "),_c('h4',{attrs:{"id":"selecting-elements"}},[_v("Selecting Elements"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#selecting-elements","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Cheerio uses CSS selectors to select elements, just like jQuery. Here are some examples:")]),_v(" "),_c('pre',[_c('code',{pre:true,attrs:{"class":"hljs javascript"}},[_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-comment"}},[_v("// Select all h2 elements")]),_v("\n")]),_c('span',[_v("$("),_c('span',{pre:true,attrs:{"class":"hljs-string"}},[_v("'h2'")]),_v(");\n")]),_c('span',[_v("\n")]),_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-comment"}},[_v("// Select the element with id \"main\"")]),_v("\n")]),_c('span',[_v("$("),_c('span',{pre:true,attrs:{"class":"hljs-string"}},[_v("'#main'")]),_v(");\n")]),_c('span',[_v("\n")]),_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-comment"}},[_v("// Select all elements with class \"text\"")]),_v("\n")]),_c('span',[_v("$("),_c('span',{pre:true,attrs:{"class":"hljs-string"}},[_v("'.text'")]),_v(");\n")]),_c('span',[_v("\n")]),_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-comment"}},[_v("// Select all a tags within h2 elements")]),_v("\n")]),_c('span',[_v("$("),_c('span',{pre:true,attrs:{"class":"hljs-string"}},[_v("'h2 a'")]),_v(");\n")])])]),_c('h4',{attrs:{"id":"manipulating-elements"}},[_v("Manipulating Elements"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#manipulating-elements","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Once we have selected elements, we can manipulate them in various ways. Some common methods include:")]),_v(" "),_c('ul',[_c('li',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("addClass(className)")]),_v(": Adds the specified class to the selected elements.")]),_v(" "),_c('li',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("removeClass(className)")]),_v(": Removes the specified class from the selected elements.")]),_v(" "),_c('li',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("attr(attributeName, value)")]),_v(": Gets or sets the value of the specified attribute.")]),_v(" "),_c('li',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("text(newText)")]),_v(": Gets or sets the text content of the selected elements.")]),_v(" "),_c('li',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("html(newHtml)")]),_v(": Gets or sets the inner HTML of the selected elements.")]),_v(" "),_c('li',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("append(content)")]),_v(": Appends the specified content to the end of each selected element.")]),_v(" "),_c('li',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("prepend(content)")]),_v(": Prepends the specified content to the beginning of each selected element.")]),_v(" "),_c('li',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("remove()")]),_v(": Removes the selected elements from the DOM.")])]),_v(" "),_c('p',[_v("Here's an example that demonstrates some of these methods:")]),_v(" "),_c('pre',[_c('code',{pre:true,attrs:{"class":"hljs javascript"}},[_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-comment"}},[_v("// Add the class \"highlight\" to all h2 elements")]),_v("\n")]),_c('span',[_v("$("),_c('span',{pre:true,attrs:{"class":"hljs-string"}},[_v("'h2'")]),_v(").addClass("),_c('span',{pre:true,attrs:{"class":"hljs-string"}},[_v("'highlight'")]),_v(");\n")]),_c('span',[_v("\n")]),_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-comment"}},[_v("// Set the text of the element with id \"title\"")]),_v("\n")]),_c('span',[_v("$("),_c('span',{pre:true,attrs:{"class":"hljs-string"}},[_v("'#title'")]),_v(").text("),_c('span',{pre:true,attrs:{"class":"hljs-string"}},[_v("'New Title'")]),_v(");\n")]),_c('span',[_v("\n")]),_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-comment"}},[_v("// Append a span to each paragraph")]),_v("\n")]),_c('span',[_v("$("),_c('span',{pre:true,attrs:{"class":"hljs-string"}},[_v("'p'")]),_v(").append("),_c('span',{pre:true,attrs:{"class":"hljs-string"}},[_v("'Some appended text'")]),_v(");\n")])])]),_c('h4',{attrs:{"id":"rendering-back-to-html"}},[_v("Rendering Back to HTML"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#rendering-back-to-html","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("After manipulating the parsed HTML with Cheerio, we can render it back to an HTML string using the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("html")]),_v(" method.")]),_v(" "),_c('pre',[_c('code',{pre:true,attrs:{"class":"hljs javascript"}},[_c('span',[_v("$.html();\n")]),_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-comment"}},[_v("//=> '

    New Title

    Some textSome appended text

    '")]),_v("\n")])])]),_c('p',[_v("This is useful when we need to save the manipulated HTML back to a file or send it as a response in a web application.")]),_v(" "),_c('p',[_v("Cheerio provides a simple and efficient way to parse and manipulate HTML structures in MarkBind plugins, enabling powerful transformations of the rendered Markdown content.")]),_v(" "),_c('h3',{attrs:{"id":"vue-js-focusing-on-custom-directives"}},[_v("Vue.js (focusing on custom directives)"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#vue-js-focusing-on-custom-directives","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Vue.js is a progressive JavaScript framework for building user interfaces. It provides a declarative and component-based approach to UI development, making it easier to create and maintain complex applications.")]),_v(" "),_c('h4',{attrs:{"id":"custom-directives-in-vue"}},[_v("Custom Directives in Vue"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#custom-directives-in-vue","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Vue allows we to extend the behavior of HTML elements or Vue components through custom directives. Custom directives provide a way to encapsulate and reuse DOM manipulation logic across your application.")]),_v(" "),_c('pre',[_c('code',{pre:true,attrs:{"class":"hljs javascript"}},[_c('span',[_v("Vue.directive("),_c('span',{pre:true,attrs:{"class":"hljs-string"}},[_v("'my-directive'")]),_v(", {\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-function"}},[_c('span',{pre:true,attrs:{"class":"hljs-title"}},[_v("bind")]),_v("("),_c('span',{pre:true,attrs:{"class":"hljs-params"}},[_v("el, binding, vnode")]),_v(")")]),_v(" {\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-comment"}},[_v("// Directive initialization logic")]),_v("\n")]),_c('span',[_v(" },\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-function"}},[_c('span',{pre:true,attrs:{"class":"hljs-title"}},[_v("inserted")]),_v("("),_c('span',{pre:true,attrs:{"class":"hljs-params"}},[_v("el, binding, vnode")]),_v(")")]),_v(" {\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-comment"}},[_v("// Logic to be executed when the directive is inserted into the DOM")]),_v("\n")]),_c('span',[_v(" },\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-function"}},[_c('span',{pre:true,attrs:{"class":"hljs-title"}},[_v("update")]),_v("("),_c('span',{pre:true,attrs:{"class":"hljs-params"}},[_v("el, binding, vnode, oldVnode")]),_v(")")]),_v(" {\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-comment"}},[_v("// Logic to be executed when the directive's bound value changes")]),_v("\n")]),_c('span',[_v(" },\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-function"}},[_c('span',{pre:true,attrs:{"class":"hljs-title"}},[_v("componentUpdated")]),_v("("),_c('span',{pre:true,attrs:{"class":"hljs-params"}},[_v("el, binding, vnode, oldVnode")]),_v(")")]),_v(" {\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-comment"}},[_v("// Logic to be executed after the containing component's VNode has updated")]),_v("\n")]),_c('span',[_v(" },\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-function"}},[_c('span',{pre:true,attrs:{"class":"hljs-title"}},[_v("unbind")]),_v("("),_c('span',{pre:true,attrs:{"class":"hljs-params"}},[_v("el, binding, vnode")]),_v(")")]),_v(" {\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-comment"}},[_v("// Cleanup logic when the directive is unbound from the element")]),_v("\n")]),_c('span',[_v(" }\n")]),_c('span',[_v("})\n")])])]),_c('p',[_c('strong',[_v("Parameters")])]),_v(" "),_c('ul',[_c('li',[_c('strong',[_v("el (HTMLElement):")]),_v(" The DOM element the directive is bound to. This allows we to perform direct DOM manipulations or access the element's properties.")]),_v(" "),_c('li',[_c('strong',[_v("binding (DirectiveBinding):")]),_v(" An object containing the directive's binding information, including:\n"),_c('ul',[_c('li',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("binding.value")]),_v(": The value passed to the directive. It can be a primitive value, an object, or a function.")]),_v(" "),_c('li',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("binding.oldValue")]),_v(": The previous value of the directive, only available in the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("update")]),_v(" and "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("componentUpdated")]),_v(" hooks.")]),_v(" "),_c('li',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("binding.arg")]),_v(": The argument passed to the directive, if any, denoted by a colon (e.g., "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("v-my-directive:arg")]),_v(").")]),_v(" "),_c('li',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("binding.modifiers")]),_v(": An object containing any modifiers applied to the directive (e.g., "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("v-my-directive.modifier")]),_v(").")])])]),_v(" "),_c('li',[_c('strong',[_v("vnode (VNode):")]),_v(" The virtual node representing the bound element. It provides access to the Vue instance properties and methods.")]),_v(" "),_c('li',[_c('strong',[_v("oldVnode (VNode):")]),_v(" The previous virtual node, only available in the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("update")]),_v(" and "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("componentUpdated")]),_v(" hooks.")])]),_v(" "),_c('p',[_c('strong',[_v("Directive Lifecycle Hooks")])]),_v(" "),_c('p',[_v("Custom directives have access to several lifecycle hooks that allow we to execute logic at different stages:")]),_v(" "),_c('ul',[_c('li',[_c('strong',[_v("bind:")]),_v(" Called once when the directive is first bound to the element. This is where we can perform any one-time setup or initialization.")]),_v(" "),_c('li',[_c('strong',[_v("inserted:")]),_v(" Called when the bound element is inserted into the parent node. This is a good place to execute logic that relies on the element being in the DOM.")]),_v(" "),_c('li',[_c('strong',[_v("update:")]),_v(" Called whenever the bound value of the directive changes. we can compare the current and old values and perform updates accordingly.")]),_v(" "),_c('li',[_c('strong',[_v("componentUpdated:")]),_v(" Called after the containing component's VNode and the VNodes of its children have updated.")]),_v(" "),_c('li',[_c('strong',[_v("unbind:")]),_v(" Called when the directive is unbound from the element. This is where we can perform any necessary cleanup or teardown logic.")])]),_v(" "),_c('p',[_c('strong',[_v("Usage")])]),_v(" "),_c('p',[_v("To use a custom directive, we can attach it to an element or component using the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("v-")]),_v(" prefix followed by the directive name. For example:")]),_v(" "),_c('pre',[_c('code',{pre:true,attrs:{"class":"hljs html"}},[_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-tag"}},[_v("<"),_c('span',{pre:true,attrs:{"class":"hljs-name"}},[_v("div")]),_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-attr"}},[_v("v-my-directive")]),_v("="),_c('span',{pre:true,attrs:{"class":"hljs-string"}},[_v("\"value\"")]),_v(">")]),_c('span',{pre:true,attrs:{"class":"hljs-tag"}},[_v("")]),_v("\n")])])]),_c('p',[_v("In this case, "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("my-directive")]),_v(" is the name of the custom directive, and "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("value")]),_v(" is the value being passed to the directive.")]),_v(" "),_c('p',[_v("Custom directives provide a powerful way to encapsulate and reuse DOM manipulation logic in Vue applications. They allow we to extend the behavior of elements and solve specific problems related to integrating external libraries or custom functionality.")]),_v(" "),_c('h4',{attrs:{"id":"solving-issues-with-third-party-library-integration"}},[_v("Solving Issues with Third-Party Library Integration"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#solving-issues-with-third-party-library-integration","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("When integrating third-party libraries into Vue components, we may encounter scenarios where the library's initialization script doesn't work as expected within the component's lifecycle. This can happen due to timing differences between the library's initialization and the component's rendering process.")]),_v(" "),_c('p',[_v("One common issue is when a library relies on the presence of certain DOM elements during its initialization, but those elements are dynamically rendered by the Vue component and may not be available when the library's initialization script runs.")]),_v(" "),_c('p',[_v("To solve this problem, we can leverage Vue's custom directives. By creating a custom directive that handles the library's initialization logic, we can ensure that the initialization happens at the appropriate time within the component's lifecycle.")]),_v(" "),_c('p',[_v("Here's an example of how we can create a custom directive to initialize a third-party library on a specific element:")]),_v(" "),_c('pre',[_c('code',{pre:true,attrs:{"class":"hljs javascript"}},[_c('span',[_v("Vue.directive("),_c('span',{pre:true,attrs:{"class":"hljs-string"}},[_v("'my-library'")]),_v(", {\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-function"}},[_c('span',{pre:true,attrs:{"class":"hljs-title"}},[_v("inserted")]),_v("("),_c('span',{pre:true,attrs:{"class":"hljs-params"}},[_v("el")]),_v(")")]),_v(" {\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-comment"}},[_v("// Initialize the library on the element")]),_v("\n")]),_c('span',[_v(" myLibrary.init(el);\n")]),_c('span',[_v(" },\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-function"}},[_c('span',{pre:true,attrs:{"class":"hljs-title"}},[_v("unbind")]),_v("("),_c('span',{pre:true,attrs:{"class":"hljs-params"}},[_v("el")]),_v(")")]),_v(" {\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-comment"}},[_v("// Cleanup the library when the directive is unbound")]),_v("\n")]),_c('span',[_v(" myLibrary.destroy(el);\n")]),_c('span',[_v(" }\n")]),_c('span',[_v("})\n")])])]),_c('p',[_v("In this example, the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("my-library")]),_v(" directive is responsible for initializing the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("myLibrary")]),_v(" on the bound element when it is inserted into the DOM. It also handles the cleanup process when the directive is unbound from the element.")]),_v(" "),_c('p',[_v("To use this directive in a Vue component, we can simply attach it to the desired element:")]),_v(" "),_c('pre',[_c('code',{pre:true,attrs:{"class":"hljs html"}},[_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-tag"}},[_v("<"),_c('span',{pre:true,attrs:{"class":"hljs-name"}},[_v("template")]),_v(">")]),_v("\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-tag"}},[_v("<"),_c('span',{pre:true,attrs:{"class":"hljs-name"}},[_v("div")]),_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-attr"}},[_v("v-my-library")]),_v(">")]),_v("\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-comment"}},[_v("")]),_v("\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-tag"}},[_v("")]),_v("\n")]),_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-tag"}},[_v("")]),_v("\n")])])]),_c('p',[_v("By using the custom directive, we ensure that the library initialization happens at the appropriate time within the component's lifecycle, solving the issue of initialization timing.")]),_v(" "),_c('hr'),_v(" "),_c('h2',{attrs:{"id":"some-more-general-web-development-knowledge"}},[_v("Some more general web development knowledge"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#some-more-general-web-development-knowledge","onclick":"event.stopPropagation()"}})]),_v(" "),_c('h3',{attrs:{"id":"javascript-module-systems"}},[_v("JavaScript Module Systems"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#javascript-module-systems","onclick":"event.stopPropagation()"}})]),_v(" "),_c('h4',{attrs:{"id":"commonjs-cjs"}},[_v("CommonJS (CJS)"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#commonjs-cjs","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("CommonJS is a module system used in Node.js and other JavaScript environments. It uses the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("require()")]),_v(" function to import modules and "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("module.exports")]),_v(" or "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("exports")]),_v(" to export modules.")]),_v(" "),_c('pre',[_c('code',{pre:true,attrs:{"class":"hljs javascript"}},[_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-comment"}},[_v("// Importing a module")]),_v("\n")]),_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("const")]),_v(" myModule = "),_c('span',{pre:true,attrs:{"class":"hljs-built_in"}},[_v("require")]),_v("("),_c('span',{pre:true,attrs:{"class":"hljs-string"}},[_v("'./myModule'")]),_v(")\n")]),_c('span',[_v("\n")]),_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-comment"}},[_v("// Exporting a module")]),_v("\n")]),_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-built_in"}},[_v("module")]),_v(".exports = {\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-comment"}},[_v("// Exported properties and methods")]),_v("\n")]),_c('span',[_v("}\n")])])]),_c('h4',{attrs:{"id":"ecmascript-modules-esm"}},[_v("ECMAScript Modules (ESM)"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#ecmascript-modules-esm","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("ECMAScript Modules (ESM) is the standard module system introduced in JavaScript with ES6 (ECMAScript 2015). It uses the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("import")]),_v(" and "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("export")]),_v(" keywords for importing and exporting modules.")]),_v(" "),_c('pre',[_c('code',{pre:true,attrs:{"class":"hljs javascript"}},[_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-comment"}},[_v("// Importing a module")]),_v("\n")]),_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("import")]),_v(" myModule "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("from")]),_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-string"}},[_v("'./myModule'")]),_v("\n")]),_c('span',[_v("\n")]),_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-comment"}},[_v("// Exporting a module")]),_v("\n")]),_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("export")]),_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("default")]),_v(" {\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-comment"}},[_v("// Exported properties and methods")]),_v("\n")]),_c('span',[_v("}\n")])])]),_c('p',[_v("ESM provides benefits such as static analysis, tree shaking, and better performance compared to CJS. However, CJS is still widely used, especially in older codebases and libraries.")]),_v(" "),_c('h4',{attrs:{"id":"differences-between-cjs-and-esm"}},[_v("Differences between CJS and ESM"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#differences-between-cjs-and-esm","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ul',[_c('li',[_c('strong',[_v("Syntax:")]),_v(" CJS uses "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("require()")]),_v(" and "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("module.exports")]),_v(", while ESM uses "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("import")]),_v(" and "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("export")]),_v(".")]),_v(" "),_c('li',[_c('strong',[_v("Synchronous vs. Asynchronous:")]),_v(" CJS imports are synchronous and blocking, while ESM imports are asynchronous and non-blocking.")]),_v(" "),_c('li',[_c('strong',[_v("Browser Support:")]),_v(" ESM is supported natively in modern browsers, while CJS requires a bundler or transpiler for browser compatibility.")]),_v(" "),_c('li',[_c('strong',[_v("Interoperability:")]),_v(" ESM and CJS modules can interoperate to some extent, but there are differences in how they handle default exports and named exports.")])]),_v(" "),_c('p',[_v("Node.js supports both CJS and ESM, and the module system used depends on the file extension ("),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v(".mjs")]),_v(" for ESM and "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v(".js")]),_v(" for CJS) or the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("\"type\": \"module\"")]),_v(" field in the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("package.json")]),_v(" file.")]),_v(" "),_c('h3',{attrs:{"id":"html-and-dom-rendering-order"}},[_v("HTML and DOM Rendering Order"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#html-and-dom-rendering-order","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("When a web page is loaded, the browser follows a specific order to render the content:")]),_v(" "),_c('ol',[_c('li',[_c('strong',[_v("Parsing HTML:")]),_v(" The browser parses the HTML document and constructs the Document Object Model (DOM) tree.")]),_v(" "),_c('li',[_c('strong',[_v("Loading External Resources:")]),_v(" The browser loads external resources such as CSS files, JavaScript files, and images referenced in the HTML.")]),_v(" "),_c('li',[_c('strong',[_v("Constructing the CSSOM:")]),_v(" The browser parses the CSS and constructs the CSS Object Model (CSSOM) tree.")]),_v(" "),_c('li',[_c('strong',[_v("Executing JavaScript:")]),_v(" The browser executes JavaScript code, which can manipulate the DOM and CSSOM.")]),_v(" "),_c('li',[_c('strong',[_v("Rendering:")]),_v(" The browser combines the DOM and CSSOM to create the render tree, which represents the visual layout of the page. It then paints the pixels on the screen.")])]),_v(" "),_c('hr'),_v(" "),_c('p',[_c('em',[_v("Content partially generated by GenAI")])])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/Tim-Siu/progress.html b/students/Tim-Siu/progress.html index a5bd71e82..48a75aeaf 100644 --- a/students/Tim-Siu/progress.html +++ b/students/Tim-Siu/progress.html @@ -13,7 +13,7 @@

    Summary

    Over the semester, I worked on various aspects of Markbind, focusing on adding new features. -Some of the works include:

    I also merged a PR and reviewed a couple of PRs.

    Week Achievements
    2 Raised Issue: Broken link for emoticon shortcut in UG
    2 Authored PR: Correct broken UG external link
    3 Authored PR: Use a more noticeable color for highlight words in fenced code
    4 Investigated Printing related issues: Incorrect behavior for minimal panel transition, The collapsed page nav appears in the print view, Lower (white) navbar gets printed on mobile, #728, Support a way to generate table of content
    5 Authored PR: Add line-numbers when soft-wrapping
    6 Authored PR: Add line-numbers when wrapping is needed for printing
    6 Raised Issue: Code highlighting not visible in printing
    7 Authored PR: Add dataTable plugin
    7 Reviewed PR: Fix print code highlight
    9 Authored PR: Add the announcement component (aborted)
    10 Authored PR: Renewed efforts to add mermaid plugin
    11 Authored PR: [Add warning for including empty segments or files in optional mode](Add warning for including empty segments or files in optional mode)
    12 Merged PR: Add note on absolute links
    13 Reviewed two PRs: Set global variables using nunjucks syntax and Add pagefind
    +Some of the works include:

    I also merged a PR and reviewed a couple of PRs.

    Week Achievements
    2 Raised Issue: Broken link for emoticon shortcut in UG
    2 Authored PR: Correct broken UG external link
    3 Authored PR: Use a more noticeable color for highlight words in fenced code
    4 Investigated Printing related issues: Incorrect behavior for minimal panel transition, The collapsed page nav appears in the print view, Lower (white) navbar gets printed on mobile, #728, Support a way to generate table of content
    5 Authored PR: Add line-numbers when soft-wrapping
    6 Authored PR: Add line-numbers when wrapping is needed for printing
    6 Raised Issue: Code highlighting not visible in printing
    7 Authored PR: Add dataTable plugin
    7 Reviewed PR: Fix print code highlight
    9 Authored PR: Add the announcement component (aborted)
    10 Authored PR: Renewed efforts to add mermaid plugin
    11 Authored PR: [Add warning for including empty segments or files in optional mode](Add warning for including empty segments or files in optional mode)
    12 Merged PR: Add note on absolute links
    13 Reviewed two PRs: Set global variables using nunjucks syntax and Add pagefind
    diff --git a/students/Tim-Siu/progress.page-vue-render.js b/students/Tim-Siu/progress.page-vue-render.js index 27d8e65ce..6b7daa1aa 100644 --- a/students/Tim-Siu/progress.page-vue-render.js +++ b/students/Tim-Siu/progress.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('h3',{attrs:{"id":"summary"}},[_v("Summary"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#summary","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Over the semester, I worked on various aspects of Markbind, focusing on adding new features.\nSome of the works include:")]),_v(" "),_c('ul',[_c('li',[_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2431"}},[_v("Optimise Printing of Fenced Code Blocks #2413/#2431")])]),_v(" "),_c('li',[_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2446"}},[_v("Add dataTable plugin #2446")])]),_v(" "),_c('li',[_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2475"}},[_v("Renewed efforts to add mermaid plugin #2475")])])]),_v(" "),_c('p',[_v("I also merged a PR and reviewed a couple of PRs.")]),_v(" "),_c('div',{staticClass:"table-responsive"},[_c('table',{staticClass:"markbind-table table table-bordered table-striped"},[_c('thead',[_c('tr',[_c('th',[_v("Week")]),_v(" "),_c('th',[_v("Achievements")])])]),_v(" "),_c('tbody',[_c('tr',[_c('td',[_v("2")]),_v(" "),_c('td',[_v("Raised Issue: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2391"}},[_v("Broken link for emoticon shortcut in UG")])])]),_v(" "),_c('tr',[_c('td',[_v("2")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2392"}},[_v("Correct broken UG external link")])])]),_v(" "),_c('tr',[_c('td',[_v("3")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2394"}},[_v("Use a more noticeable color for highlight words in fenced code")])])]),_v(" "),_c('tr',[_c('td',[_v("4")]),_v(" "),_c('td',[_v("Investigated Printing related issues: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2347"}},[_v("Incorrect behavior for minimal panel transition")]),_v(", "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2157"}},[_v("The collapsed page nav appears in the print view")]),_v(", "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2109"}},[_v("Lower (white) navbar gets printed on mobile")]),_v(", "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/728"}},[_v("#728")]),_v(", "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/728"}},[_v("Support a way to generate table of content")])])]),_v(" "),_c('tr',[_c('td',[_v("5")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2413"}},[_v("Add line-numbers when soft-wrapping")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2431"}},[_v("Add line-numbers when wrapping is needed for printing")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Raised Issue: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/issues/2438"}},[_v("Code highlighting not visible in printing")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2446"}},[_v("Add dataTable plugin")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2445"}},[_v("Fix print code highlight")])])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2472"}},[_v("Add the announcement component")]),_v(" (aborted)")])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Authored PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2475"}},[_v("Renewed efforts to add mermaid plugin")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Authored PR: [Add warning for including empty segments or files in optional mode](Add warning for including empty segments or files in optional mode)")])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2507"}},[_v("Add note on absolute links")])])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_v("Reviewed two PRs: "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2474"}},[_v("Set global variables using nunjucks syntax")]),_v(" and "),_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2477"}},[_v("Add pagefind")])])])])])])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/asdfghjkxd/info.html b/students/asdfghjkxd/info.html index 7c466449f..f81308e2f 100644 --- a/students/asdfghjkxd/info.html +++ b/students/asdfghjkxd/info.html @@ -12,7 +12,7 @@ const baseUrl = '/2024' - + diff --git a/students/asdfghjkxd/info.page-vue-render.js b/students/asdfghjkxd/info.page-vue-render.js index 8024855d9..b47efc733 100644 --- a/students/asdfghjkxd/info.page-vue-render.js +++ b/students/asdfghjkxd/info.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('p',[_c('span',{attrs:{"id":"github"}},[_c('a',{attrs:{"href":"https://github.com/asdfghjkxd"}},[_v("https://github.com/asdfghjkxd")])])]),_v(" "),_c('p',[_c('span',{attrs:{"id":"projects"}},[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense"}},[_v("RepoSense")])])])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/asdfghjkxd/knowledge.html b/students/asdfghjkxd/knowledge.html index 1f5134664..3c0d2d6d6 100644 --- a/students/asdfghjkxd/knowledge.html +++ b/students/asdfghjkxd/knowledge.html @@ -21,7 +21,7 @@
    • It was also a challenge to integrate Docker with Github Actions for CI/CD purposes as it is not as easy to debug when things go wrong during the build and execution process. Every time changes are made, a new image needs to be created, tested and then deployed, all of which incurs precious Github Actions build time. Not to mention that the environment provided by Github Actions' Runners are distinctly different that my local environment (Github Runners run on x86 while my Mac environment runs on ARM64), making testing extremely difficult and time consuming

    Resources Used

    • Docker references
      • The references for the different Dockerfile syntax and Docker commands was referenced heavily during the creation of the different POC Dockerfiles
    • Stackoverflow and other online references
      • Some more obscure ways of doing things in Docker had to reference the code which others have written, as it was not readily available in the references for Docker
    • ChatGPT -
      • ChatGPT was used to debug and identify potential reasons as to why my Dockerfile might be buggy and fails builds when they are pushed onto Github
    +
    • ChatGPT was used to debug and identify potential reasons as to why my Dockerfile might be buggy and fails builds when they are pushed onto Github
    diff --git a/students/asdfghjkxd/knowledge.page-vue-render.js b/students/asdfghjkxd/knowledge.page-vue-render.js index 41eea4c9f..9dee766ca 100644 --- a/students/asdfghjkxd/knowledge.page-vue-render.js +++ b/students/asdfghjkxd/knowledge.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('h3',{attrs:{"id":"java"}},[_v("Java"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#java","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Java is used extensively in the backend for RepoSense, from the generation of the RepoSense report, to the different "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("git")]),_v(" commands required to clone repositories and analyse them. It was not difficult to pick up Java as I had some prior experience in Java in previous classes such as CS2030S, CS2040S and CS2103T, but the intricacies surrounding the different Java libraries was something that I was never properly exposed to and had to learn over time as I worked on the project.")]),_v(" "),_c('h4',{attrs:{"id":"aspects-learned"}},[_v("Aspects Learned"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#aspects-learned","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Some of the aspects I have learnt regarding Java:")]),_v(" "),_c('ul',[_c('li',[_v("Learning to read Java source code and using the built-in IntelliJ Java Profiler to identify possible optimisations in the current codebase\n"),_c('ul',[_c('li',[_v("One particular aspect of Java that was the target of optimisation was Regex. I realised that Regex was used extensively in the codebase in different contexts, whether to split up strings or to find a matching string pattern in a given string. However, after identifying some parts of the code that were potentially buggy or slow (especially snippets whereby Regex operations are used in conjunction with iteration) using the IntelliJ Java Profiler and consulting the Java source code, as well as some online sources, I was able to identify a latent anti-pattern in the way Regex code was written in the code base")]),_v(" "),_c('li',[_v("This experience taught me that Regex code should never be mixed with iteration and that we should precompile "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Pattern")]),_v(" objects for repeated use instead")])])]),_v(" "),_c('li',[_v("Learning more about different code design patterns such as the Builder pattern and how to adapt it to our codebase to suit our own needs\n"),_c('ul',[_c('li',[_v("The Builder pattern was one of the patterns that was not taught in the previous modules that I have taken, but I was aware of it due to reading up on coding patterns prior me taking up this project. At first, I thought that the Builder pattern could be adopted as is into the codebase without consideration of our use cases, however, through the guidance of my mentors, I soon realised that not all parts of the Builder pattern was relevant to what we needed the pattern for, and that we need to adapt the pattern to our use, and not the other way around.")])])])]),_v(" "),_c('h4',{attrs:{"id":"resources-used"}},[_v("Resources Used"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#resources-used","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ul',[_c('li',[_v("Java Source Code\n"),_c('ul',[_c('li',[_v("The source code for Java was used to verify the time and memory usage of the code given by the code profiler, by cross-referencing bottlenecks identified in the code profile with the source code to identify inefficient code in the codebase")])])]),_v(" "),_c('li',[_v("Online Java resources such as "),_c('a',{attrs:{"href":"https://www.baeldung.com/"}},[_v("baeldung.com")]),_v(" "),_c('ul',[_c('li',[_v("The resources provided alternative ways of achieving a certain results, which may help to increase the efficiency of the code")])])]),_v(" "),_c('li',[_v("Past modules taken that taught Java code\n"),_c('ul',[_c('li',[_v("CS2030S, CS2040S and CS2103T")])])])]),_v(" "),_c('h3',{attrs:{"id":"docker"}},[_v("Docker"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#docker","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Docker is something that I have always wanted to work with, especially so in combination with other container orchestration tools such as Kubernetes. I looked into the possibility of Docker being used to containerise RepoSense, enabling us to better test RepoSense, provide end users with a premade container with RepoSense's dependencies resolved for them, and a way to quickly deploy RepoSense to their favourite cloud providers (e.g. AWS ECS, etc.) for greater availability of RepoSense for their target users.")]),_v(" "),_c('h4',{attrs:{"id":"aspects-learned-2"}},[_v("Aspects Learned"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#aspects-learned-2","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Some of the aspects I have learnt:")]),_v(" "),_c('ul',[_c('li',[_v("Learning Dockerfile syntax\n"),_c('ul',[_c('li',[_v("While Docker is not exactly new to me as I have previously worked with Docker products in a past project, I have long forgotten the different syntax required for a Dockerfile, as well as the different Docker commands that work with building and running containers")])])]),_v(" "),_c('li',[_v("Docker integration with Github Actions\n"),_c('ul',[_c('li',[_v("It was also a challenge to integrate Docker with Github Actions for CI/CD purposes as it is not as easy to debug when things go wrong during the build and execution process. Every time changes are made, a new image needs to be created, tested and then deployed, all of which incurs precious Github Actions build time. Not to mention that the environment provided by Github Actions' Runners are distinctly different that my local environment (Github Runners run on x86 while my Mac environment runs on ARM64), making testing extremely difficult and time consuming")])])])]),_v(" "),_c('h4',{attrs:{"id":"resources-used-2"}},[_v("Resources Used"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#resources-used-2","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ul',[_c('li',[_v("Docker references\n"),_c('ul',[_c('li',[_v("The references for the different Dockerfile syntax and Docker commands was referenced heavily during the creation of the different POC Dockerfiles")])])]),_v(" "),_c('li',[_v("Stackoverflow and other online references\n"),_c('ul',[_c('li',[_v("Some more obscure ways of doing things in Docker had to reference the code which others have written, as it was not readily available in the references for Docker")])])]),_v(" "),_c('li',[_v("ChatGPT\n"),_c('ul',[_c('li',[_v("ChatGPT was used to debug and identify potential reasons as to why my Dockerfile might be buggy and fails builds when they are pushed onto Github")])])])])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/asdfghjkxd/progress.html b/students/asdfghjkxd/progress.html index 4c484ee44..e458830f3 100644 --- a/students/asdfghjkxd/progress.html +++ b/students/asdfghjkxd/progress.html @@ -12,7 +12,7 @@ const baseUrl = '/2024' -

    Progress

    Week Achievements
    1 Merged PR: [#2073] Refactor RepoConfigCsvParser::processLine method to avoid arrowhead style code #2080
    2 Reviewed PR: [#2003] Suppress Console Warning #2088
    2 Reviewed PR: [#1224] Update .stylelintrc.json to check for spacing #2094
    2 Submitted Issue: Suggestions on improvement for memory performance regarding Regex matching #2091
    2 Submitted Issue: Suggestions for reducing runtime and memory usage for StreamGobbler #2095
    3 Submitted Issue: Refactor parser package for greater organisation of classes #2103
    3 Merged PR: [#1958] Use syntax coloring for code blocks in docs #2099
    4 Merged PR: [#2103] Refactor parser package for greater organisation of classes #2104
    5 Merged PR: [#2076] Refactor RepoConfiguration to simplify constructor complexity #2078
    5 Submitted Issue: Refactor CliArguments to conform to RepoConfiguration's Builder Pattern #2117
    5 Submitted Issue: Implement Proper Deep Cloning for RepoConfiguration and CliArguments #2119
    5 Submitted Issue: Parameter Verification for RepoConfiguration and CliArguments #2121
    6 Reviewed PR: Fix Blurry Favicon #2129
    6 Drafted PR: [#2119] Implement Proper Deep Cloning for RepoConfiguration and CliArguments #2124
    7 Submitted Issue: Dockerisation of RepoSense #2145
    7 Merged PR: [#2117] Refactor CliArguments to conform to RepoConfiguration's Builder Pattern #2118
    8 Reviewed PR: [#944] Implement authorship analysis #2140
    10 Merged PR: [#2120] Update RepoSense contributors in documentation #2138
    10 Submitted Issue: Migrate to Java 11 Syntax and Features #2177
    10 Reviewed PR: [#2158] Add More Documentation for Title Component #2159
    10 Reviewed PR: [#2151] Update Stylelint #2153
    10 Reviewed PR: [#2151] Update LoadingOverlay and Minor Versions of Node Dependencies #2152
    12 Reviewed PR: [#2176] Move from Vue CLI to Vite #2178
    13 Reviewed PR: [#2001] Extract c-file-type-checkbox from Summary, Authorship and Zoom #2173
    13 Allow CI to pass if Codecov fails #2189
    Reading Week Merged PR: [#2177] Migrate to Java 11 Syntax and Features #2183
    Reading Week Merged PR: [#2184] Fix Inconsistent Line Number Colours #2185
    +

    Progress

    Week Achievements
    1 Merged PR: [#2073] Refactor RepoConfigCsvParser::processLine method to avoid arrowhead style code #2080
    2 Reviewed PR: [#2003] Suppress Console Warning #2088
    2 Reviewed PR: [#1224] Update .stylelintrc.json to check for spacing #2094
    2 Submitted Issue: Suggestions on improvement for memory performance regarding Regex matching #2091
    2 Submitted Issue: Suggestions for reducing runtime and memory usage for StreamGobbler #2095
    3 Submitted Issue: Refactor parser package for greater organisation of classes #2103
    3 Merged PR: [#1958] Use syntax coloring for code blocks in docs #2099
    4 Merged PR: [#2103] Refactor parser package for greater organisation of classes #2104
    5 Merged PR: [#2076] Refactor RepoConfiguration to simplify constructor complexity #2078
    5 Submitted Issue: Refactor CliArguments to conform to RepoConfiguration's Builder Pattern #2117
    5 Submitted Issue: Implement Proper Deep Cloning for RepoConfiguration and CliArguments #2119
    5 Submitted Issue: Parameter Verification for RepoConfiguration and CliArguments #2121
    6 Reviewed PR: Fix Blurry Favicon #2129
    6 Drafted PR: [#2119] Implement Proper Deep Cloning for RepoConfiguration and CliArguments #2124
    7 Submitted Issue: Dockerisation of RepoSense #2145
    7 Merged PR: [#2117] Refactor CliArguments to conform to RepoConfiguration's Builder Pattern #2118
    8 Reviewed PR: [#944] Implement authorship analysis #2140
    10 Merged PR: [#2120] Update RepoSense contributors in documentation #2138
    10 Submitted Issue: Migrate to Java 11 Syntax and Features #2177
    10 Reviewed PR: [#2158] Add More Documentation for Title Component #2159
    10 Reviewed PR: [#2151] Update Stylelint #2153
    10 Reviewed PR: [#2151] Update LoadingOverlay and Minor Versions of Node Dependencies #2152
    12 Reviewed PR: [#2176] Move from Vue CLI to Vite #2178
    13 Reviewed PR: [#2001] Extract c-file-type-checkbox from Summary, Authorship and Zoom #2173
    13 Allow CI to pass if Codecov fails #2189
    Reading Week Merged PR: [#2177] Migrate to Java 11 Syntax and Features #2183
    Reading Week Merged PR: [#2184] Fix Inconsistent Line Number Colours #2185
    diff --git a/students/asdfghjkxd/progress.page-vue-render.js b/students/asdfghjkxd/progress.page-vue-render.js index b20737973..0e91e666a 100644 --- a/students/asdfghjkxd/progress.page-vue-render.js +++ b/students/asdfghjkxd/progress.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('h1',{attrs:{"id":"progress"}},[_v("Progress"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#progress","onclick":"event.stopPropagation()"}})]),_v(" "),_c('div',{staticClass:"table-responsive"},[_c('table',{staticClass:"markbind-table table table-bordered table-striped"},[_c('thead',[_c('tr',[_c('th',[_v("Week")]),_v(" "),_c('th',[_v("Achievements")])])]),_v(" "),_c('tbody',[_c('tr',[_c('td',[_v("1")]),_v(" "),_c('td',[_v("Merged PR: [#2073] Refactor "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("RepoConfigCsvParser::processLine")]),_v(" method to avoid arrowhead style code #2080")])]),_v(" "),_c('tr',[_c('td',[_v("2")]),_v(" "),_c('td',[_v("Reviewed PR: [#2003] Suppress Console Warning #2088")])]),_v(" "),_c('tr',[_c('td',[_v("2")]),_v(" "),_c('td',[_v("Reviewed PR: [#1224] Update .stylelintrc.json to check for spacing #2094")])]),_v(" "),_c('tr',[_c('td',[_v("2")]),_v(" "),_c('td',[_v("Submitted Issue: Suggestions on improvement for memory performance regarding Regex matching #2091")])]),_v(" "),_c('tr',[_c('td',[_v("2")]),_v(" "),_c('td',[_v("Submitted Issue: Suggestions for reducing runtime and memory usage for "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("StreamGobbler")]),_v(" #2095")])]),_v(" "),_c('tr',[_c('td',[_v("3")]),_v(" "),_c('td',[_v("Submitted Issue: Refactor "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("parser")]),_v(" package for greater organisation of classes #2103")])]),_v(" "),_c('tr',[_c('td',[_v("3")]),_v(" "),_c('td',[_v("Merged PR: [#1958] Use syntax coloring for code blocks in docs #2099")])]),_v(" "),_c('tr',[_c('td',[_v("4")]),_v(" "),_c('td',[_v("Merged PR: [#2103] Refactor parser package for greater organisation of classes #2104")])]),_v(" "),_c('tr',[_c('td',[_v("5")]),_v(" "),_c('td',[_v("Merged PR: [#2076] Refactor RepoConfiguration to simplify constructor complexity #2078")])]),_v(" "),_c('tr',[_c('td',[_v("5")]),_v(" "),_c('td',[_v("Submitted Issue: Refactor "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("CliArguments")]),_v(" to conform to "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("RepoConfiguration")]),_v("'s Builder Pattern #2117")])]),_v(" "),_c('tr',[_c('td',[_v("5")]),_v(" "),_c('td',[_v("Submitted Issue: Implement Proper Deep Cloning for "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("RepoConfiguration")]),_v(" and "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("CliArguments")]),_v(" #2119")])]),_v(" "),_c('tr',[_c('td',[_v("5")]),_v(" "),_c('td',[_v("Submitted Issue: Parameter Verification for "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("RepoConfiguration")]),_v(" and "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("CliArguments")]),_v(" #2121")])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Reviewed PR: Fix Blurry Favicon #2129")])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Drafted PR: [#2119] Implement Proper Deep Cloning for "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("RepoConfiguration")]),_v(" and "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("CliArguments")]),_v(" #2124")])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Submitted Issue: Dockerisation of RepoSense #2145")])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Merged PR: [#2117] Refactor CliArguments to conform to RepoConfiguration's Builder Pattern #2118")])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_v("Reviewed PR: [#944] Implement authorship analysis #2140")])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Merged PR: [#2120] Update RepoSense contributors in documentation #2138")])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Submitted Issue: Migrate to Java 11 Syntax and Features #2177")])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Reviewed PR: [#2158] Add More Documentation for Title Component #2159")])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Reviewed PR: [#2151] Update Stylelint #2153")])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Reviewed PR: [#2151] Update LoadingOverlay and Minor Versions of Node Dependencies #2152")])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Reviewed PR: [#2176] Move from Vue CLI to Vite #2178")])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_v("Reviewed PR: [#2001] Extract c-file-type-checkbox from Summary, Authorship and Zoom #2173")])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_v("Allow CI to pass if Codecov fails #2189")])]),_v(" "),_c('tr',[_c('td',[_v("Reading Week")]),_v(" "),_c('td',[_v("Merged PR: [#2177] Migrate to Java 11 Syntax and Features #2183")])]),_v(" "),_c('tr',[_c('td',[_v("Reading Week")]),_v(" "),_c('td',[_v("Merged PR: [#2184] Fix Inconsistent Line Number Colours #2185")])])])])])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/cedricongjh/info.html b/students/cedricongjh/info.html index 65cc56f95..5009848f4 100644 --- a/students/cedricongjh/info.html +++ b/students/cedricongjh/info.html @@ -12,7 +12,7 @@ const baseUrl = '/2024' - + diff --git a/students/cedricongjh/info.page-vue-render.js b/students/cedricongjh/info.page-vue-render.js index 1899390cb..a7e0ea902 100644 --- a/students/cedricongjh/info.page-vue-render.js +++ b/students/cedricongjh/info.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('p',[_c('span',{attrs:{"id":"github"}},[_c('a',{attrs:{"href":"https://www.github.com/cedricongjh"}},[_v("https://www.github.com/cedricongjh")])])]),_v(" "),_c('p',[_c('span',{attrs:{"id":"projects"}},[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates"}},[_v("TEAMMATES")])])])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/cedricongjh/knowledge.html b/students/cedricongjh/knowledge.html index bfb0d36b2..07daf1a92 100644 --- a/students/cedricongjh/knowledge.html +++ b/students/cedricongjh/knowledge.html @@ -172,7 +172,7 @@ commits that are unncesary (for instance commits like fix checkstyle), and create a more meaningful commit chain for my PRs. Although the commits are squashed in the end when merged, I find that it is important especially for larger PRs to keep a meaningful commit history, to make it easier on reviewers.

    Here is an article by atlassian that provides more details about the rebase command.

    Github CLI

    Prior to this module, I've never used the github CLI, sticking with just git commands. However, I found it very useful to use the CLI, especially when reviewing PRs, as it allowed me to checkout someone's branch with just one command, which github provides on the review page, rather than having to add their remote repo, -fetching their branches and then checking out the branch.

    +fetching their branches and then checking out the branch.

    diff --git a/students/cedricongjh/knowledge.page-vue-render.js b/students/cedricongjh/knowledge.page-vue-render.js index 2dd7feac5..c981c8bc4 100644 --- a/students/cedricongjh/knowledge.page-vue-render.js +++ b/students/cedricongjh/knowledge.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('h2',{attrs:{"id":"angular"}},[_v("Angular"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#angular","onclick":"event.stopPropagation()"}})]),_v(" "),_c('h3',{attrs:{"id":"context"}},[_v("Context"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#context","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Having worked on CATcher for IWM last summer, I've gained familiarity with Angular. Working on TEAMMATES, I've deepened my knowledge\nof the framework, and there were two new things that I've picked up about Angular.")]),_v(" "),_c('h3',{attrs:{"id":"pipes"}},[_v("Pipes"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#pipes","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Although I was previously aware of the use of pipes, I was not aware of the performance aspect. In particular, using pipes\nare much more efficient than methods to render strings:")]),_v(" "),_c('pre',[_c('code',{pre:true,attrs:{"class":"hljs javascript"}},[_c('span',[_v("\n")]),_c('span',[_v("

    {{ name.toLowerCase() }}

    \n")]),_c('span',[_v("\n")]),_c('span',[_c('span',{pre:true,attrs:{"class":"xml"}},[_c('span',{pre:true,attrs:{"class":"hljs-tag"}},[_v("<"),_c('span',{pre:true,attrs:{"class":"hljs-name"}},[_v("h1")]),_v(">")]),_v("{{ name | lowercase }}"),_c('span',{pre:true,attrs:{"class":"hljs-tag"}},[_v("")])]),_v("\n")]),_c('span',[_v("\n")])])]),_c('p',[_v("When using a method, it is always run whenever the component is detecting changes. However, for pipes, they are only run\nwhen the input of the pipe, in this case "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("name")]),_v(", is changed.")]),_v(" "),_c('p',[_c('a',{attrs:{"href":"https://medium.com/angular-in-depth/tiny-angular-pipe-to-make-any-function-memoizable-f6c8fa917f2f"}},[_v("Here")]),_v(" is a medium article that\ndives more into the benefits of using pipes.")]),_v(" "),_c('h3',{attrs:{"id":"angular-template"}},[_v("Angular Template"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#angular-template","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("ES6 template literals and nested string interpolation aren't supported in Angular:")]),_v(" "),_c('pre',[_c('code',{pre:true,attrs:{"class":"hljs javascript"}},[_c('span',[_v("\n")]),_c('span',[_v("
    {{ "),_c('span',{pre:true,attrs:{"class":"hljs-string"}},[_v("`("),_c('span',{pre:true,attrs:{"class":"hljs-subst"}},[_v("${text}")]),_v(")`")]),_v(") }}
    \n")]),_c('span',[_v("\n")])])]),_c('p',[_v("This was something that I learnt from an open source contributor in "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12249"}},[_v("this")]),_v(" PR.")]),_v(" "),_c('h2',{attrs:{"id":"hibernate"}},[_v("Hibernate"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#hibernate","onclick":"event.stopPropagation()"}})]),_v(" "),_c('h3',{attrs:{"id":"context-2"}},[_v("Context"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#context-2","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Prior to taking CS3281, I've only used Java in CS2030S, CS2040S and of course CS2103T, never on a live system used by actual users.\nThis was hence my first experience in writing a Java backend, and I'm glad that I got the opportunity, and I am confident that\nI'm now able to work on backend systems with Hibernate, from defining database tables, specifying entity relations, and writing queries.\nThe following are a few aspects of Hibernate I'd like to highlight.")]),_v(" "),_c('h3',{attrs:{"id":"entities"}},[_v("Entities"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#entities","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("In Hibernate, each class created by the developer creates a corresponding table in the database. (with some exceptions, I'll get to that later) A typical Hibernate entity looks like this:")]),_v(" "),_c('pre',[_c('code',{pre:true,attrs:{"class":"hljs java"}},[_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-meta"}},[_v("@Entity")]),_v("\n")]),_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("public")]),_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-class"}},[_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("class")]),_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-title"}},[_v("Class")]),_v(" ")]),_v("{\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-meta"}},[_v("@Id")]),_v("\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-meta"}},[_v("@GeneratedValue")]),_v("\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("private")]),_v(" Long id;\n")]),_c('span',[_v("\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-meta"}},[_v("@Column(nullable=false)")]),_v("\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("private")]),_v(" String field;\n")]),_c('span',[_v("}\n")])])]),_c('p',[_v("There's quite alot going on here, so let's break it down:")]),_v(" "),_c('ul',[_c('li',[_v("On top of normal Java classes, Hibernate uses annotations (preceded with '@') to denote properties of classes and class fields.")]),_v(" "),_c('li',[_v("The "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("@Entity")]),_v(" annotation identifies a class as an entity class, whose fields are to be persisted to the database.")]),_v(" "),_c('li',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("@Id")]),_v(" specifies the primary key.")]),_v(" "),_c('li',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("@GeneratedValue")]),_v(" is typically used for primary key columns, to denote that a field should be generated by the database upon object creation.")]),_v(" "),_c('li',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("@Column")]),_v(" is an optional annotation that allows one to customise the mapping between the entity attribute and database column. In this case, "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("nullable=false")]),_v(" ensures that the database column "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("field")]),_v(" for the table "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Class")]),_v(" cannot have non-null values.")])]),_v(" "),_c('p',[_v("A database table corresponding to the class will be created, with columns "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("id")]),_v(" and "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("field")]),_v(".")]),_v(" "),_c('p',[_v("There are numerous annotations, and Thorben Janssen's "),_c('a',{attrs:{"href":"https://thorben-janssen.com/key-jpa-hibernate-annotations/"}},[_v("guide")]),_v(" gives a in depth overview of the most essential ones.")]),_v(" "),_c('h3',{attrs:{"id":"entity-lifecycle"}},[_v("Entity lifecycle"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#entity-lifecycle","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Once the entities are defined, we can perform create, update and delete operations, and these effects will be persisted to the database.")]),_v(" "),_c('p',[_v("For instance, when we have a "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Student")]),_v(" class with a "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("name")]),_v(" field, and we would like to update it, we simply call the field's setter, "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("student.setName(\"newName\");")]),_v(" to update the student's name.")]),_v(" "),_c('p',[_v("Hibernate will persist the changes to the database automatically, without the developer having to explicitly do so.")]),_v(" "),_c('p',[_v("There's a great guide on the entity lifecycle "),_c('a',{attrs:{"href":"https://thorben-janssen.com/entity-lifecycle-model/"}},[_v("here")])]),_v(" "),_c('h3',{attrs:{"id":"inheritance"}},[_v("Inheritance"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#inheritance","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Inheritance is a key feature of OOP languages such as Java, and is also supported by Hibernate.")]),_v(" "),_c('p',[_v("There are a few different ways that inherited entities are mapped to database tables.")]),_v(" "),_c('p',[_v("One of which is the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("SingleTable")]),_v(" inheritance strategy.")]),_v(" "),_c('p',[_v("As per its namesake, in "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("SingleTable")]),_v(" inheritance, all child classes are mapped to one table.")]),_v(" "),_c('p',[_v("For example, the classes below,")]),_v(" "),_c('pre',[_c('code',{pre:true,attrs:{"class":"hljs java"}},[_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-meta"}},[_v("@Entity")]),_v("\n")]),_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-meta"}},[_v("@Inheritance(strategy = InheritanceType.SINGLE_TABLE)")]),_v("\n")]),_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("public")]),_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-class"}},[_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("class")]),_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-title"}},[_v("Class")]),_v(" ")]),_v("{\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-meta"}},[_v("@Id")]),_v("\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-meta"}},[_v("@GeneratedValue")]),_v("\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("private")]),_v(" Long id;\n")]),_c('span',[_v("}\n")]),_c('span',[_v("\n")]),_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-meta"}},[_v("@Entity")]),_v("\n")]),_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("public")]),_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-class"}},[_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("class")]),_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-title"}},[_v("ClassA")]),_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("extends")]),_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-title"}},[_v("Class")]),_v(" ")]),_v("{\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-meta"}},[_v("@Column")]),_v("\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("private")]),_v(" String description;\n")]),_c('span',[_v("}\n")]),_c('span',[_v("\n")]),_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-meta"}},[_v("@Entity")]),_v("\n")]),_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("public")]),_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-class"}},[_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("class")]),_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-title"}},[_v("ClassB")]),_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("extends")]),_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-title"}},[_v("Class")]),_v(" ")]),_v("{\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-meta"}},[_v("@Column")]),_v("\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("private")]),_v(" Integer quantity;\n")]),_c('span',[_v("}\n")])])]),_c('p',[_v("Will be mapped onto a single table, "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Class")]),_v(", with the fields "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("id")]),_v(", "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("description")]),_v(" and "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("quantity")]),_v(".")]),_v(" "),_c('p',[_v("A drawback would be that we cannot enforce non-null constraints on any of the database columns, since for records of "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("ClassA")]),_v(", they\nwould have the attribute "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("description")]),_v(" but not "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("quantity")]),_v(", and for records of "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("ClassB")]),_v(", they would not have the attribute "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("description")]),_v("\nbut have "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("quantity")]),_v(".")]),_v(" "),_c('p',[_v("An advantage of "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("SingleTable")]),_v(" strategy compared to others is that there is no need for joins. For instance, in the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Joined Table")]),_v(" strategy,\neach subclass will have its own table, and when querying, it is joined with the parent class' table. This was one of the reasons why\n"),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("SingleTable")]),_v(" inheritance was ultimately chosen for "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("FeedbackQuestion")]),_v(" and "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("FeedbackResponse")]),_v(" entities, as they had many subclasses.")]),_v(" "),_c('p',[_v("Baeldung's "),_c('a',{attrs:{"href":"https://www.baeldung.com/hibernate-inheritance"}},[_v("guide")]),_v(" on inheritance strategies was extremely helpful to me in understanding the differences between them, and the tradeoffs one needs to consider when choosing among them.")]),_v(" "),_c('h2',{attrs:{"id":"testing"}},[_v("Testing"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#testing","onclick":"event.stopPropagation()"}})]),_v(" "),_c('h3',{attrs:{"id":"context-3"}},[_v("Context"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#context-3","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Prior to working on TEAMMATES, the only exposure to software testing I had was in CS2103T. Working on the migration to postgresql involved writing tests, and\nthrough that I've gained a slightly better understanding of the different types of tests, and a much greater appreciation of the importance of tests. When\nmigrating the system to postgres, having the old test cases provided us with some reassurance that the changes we made to the system would not impact the\nexisting functionalities, which is absolutely essential for a live system.")]),_v(" "),_c('h3',{attrs:{"id":"unit-vs-integration-testing"}},[_v("Unit vs Integration testing"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#unit-vs-integration-testing","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Unit testing is testing individual components, in isolation. For components with dependancies, these dependancies are mocked to ensure that any errors\nwould be due to bugs in the component itself, and not its underlying dependancies. An example of this in TEAMMATES would be that when doing unit testing\nfor the logic layer, which depends on the database layer, we mock the database layer.")]),_v(" "),_c('p',[_v("Integration testing on the other hand, tests if the various components are working when combined together. Building upon the unit testing example, when doing\nintegration testing for the logic layer, we would not mock the database layer, but rather have the database layer actually perform its operations.")]),_v(" "),_c('p',[_v("Having both of these types of tests are necessary in a big system like TEAMMATES: unit testing gives us the reassurance that the invididual components\nare working on its own, while integration testing ensures that they work together. With good unit testing, we can be certain that any issues in integration\ntesting is most likely due to the interaction between the components, rather than the component itself, making debugging easier. The tests together ensures that no\nbreaking changes are introduced to the system, and is thus essential in a live system like TEAMMATES.")]),_v(" "),_c('p',[_c('a',{attrs:{"href":"https://www.softwaretestinghelp.com/the-difference-between-unit-integration-and-functional-testing/"}},[_v("Here")]),_v(" is an article that summarises the differences between\nunit testing, integration testing and")]),_v(" "),_c('h2',{attrs:{"id":"oop-patterns"}},[_v("OOP patterns"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#oop-patterns","onclick":"event.stopPropagation()"}})]),_v(" "),_c('h3',{attrs:{"id":"builder-pattern"}},[_v("Builder pattern"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#builder-pattern","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("The builder pattern is useful when a class has many fields that are optional upon instantiation.\nImagine a Java class that has 3 fields:")]),_v(" "),_c('pre',[_c('code',{pre:true,attrs:{"class":"hljs java"}},[_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("public")]),_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-class"}},[_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("class")]),_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-title"}},[_v("Foo")]),_v(" ")]),_v("{\n")]),_c('span',[_v(" String a;\n")]),_c('span',[_v(" Integer b;\n")]),_c('span',[_v(" Long c;\n")]),_c('span',[_v("}\n")])])]),_c('p',[_v("For this class, say that a, b and c are optional, and that they are not needed when creating a "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Foo")]),_v(" object.\nTo cater for every combination, we would require many constructors:")]),_v(" "),_c('pre',[_c('code',{pre:true,attrs:{"class":"hljs java"}},[_c('span',[_v("Foo(String a) {\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("this")]),_v(".a = a;\n")]),_c('span',[_v("}\n")]),_c('span',[_v("\n")]),_c('span',[_v("Foo(String a, Integer b) {\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("this")]),_v(".a = a;\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("this")]),_v(".b = b;\n")]),_c('span',[_v("}\n")]),_c('span',[_v("\n")]),_c('span',[_v("Foo(String a, Integer b, Long c) {\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("this")]),_v(".a = a;\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("this")]),_v(".b = b;\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("this")]),_v(".c = c;\n")]),_c('span',[_v("}\n")]),_c('span',[_v("\n")])])]),_c('p',[_v("And many more for the other combinations...")]),_v(" "),_c('p',[_v("To solve this issue, we can make use of the builder pattern, creating a static builder class inside "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Foo")]),_v(":")]),_v(" "),_c('pre',[_c('code',{pre:true,attrs:{"class":"hljs java"}},[_c('span',[_v("\n")]),_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-function"}},[_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("public")]),_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("static")]),_v(" class "),_c('span',{pre:true,attrs:{"class":"hljs-title"}},[_v("FooBuilder")]),_c('span',{pre:true,attrs:{"class":"hljs-params"}},[_v("()")]),_v(" ")]),_v("{\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-function"}},[_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("public")]),_v(" Foo "),_c('span',{pre:true,attrs:{"class":"hljs-title"}},[_v("setA")]),_c('span',{pre:true,attrs:{"class":"hljs-params"}},[_v("(String a)")]),_v(" ")]),_v("{\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("this")]),_v(".a = a;\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("return")]),_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("this")]),_v(";\n")]),_c('span',[_v(" }\n")]),_c('span',[_v("\n")]),_c('span',[_v("\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-function"}},[_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("public")]),_v(" Foo "),_c('span',{pre:true,attrs:{"class":"hljs-title"}},[_v("setB")]),_c('span',{pre:true,attrs:{"class":"hljs-params"}},[_v("(Integer b)")]),_v(" ")]),_v("{\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("this")]),_v(".b = b;\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("return")]),_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("this")]),_v(";\n")]),_c('span',[_v(" }\n")]),_c('span',[_v("\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-function"}},[_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("public")]),_v(" Foo "),_c('span',{pre:true,attrs:{"class":"hljs-title"}},[_v("setC")]),_c('span',{pre:true,attrs:{"class":"hljs-params"}},[_v("(Long c)")]),_v(" ")]),_v("{\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("this")]),_v(".c = c;\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("return")]),_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("this")]),_v(";\n")]),_c('span',[_v(" }\n")]),_c('span',[_v("\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-function"}},[_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("public")]),_v(" Foo "),_c('span',{pre:true,attrs:{"class":"hljs-title"}},[_v("build")]),_c('span',{pre:true,attrs:{"class":"hljs-params"}},[_v("()")]),_v(" ")]),_v("{\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("return")]),_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("new")]),_v(" Foo("),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("this")]),_v(");\n")]),_c('span',[_v(" }\n")]),_c('span',[_v("}\n")]),_c('span',[_v("\n")])])]),_c('p',[_v("We can then create "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Foo")]),_v(", with a b or c being optional without having to create numerous constructors:")]),_v(" "),_c('pre',[_c('code',{pre:true,attrs:{"class":"hljs java"}},[_c('span',[_v("Foo foo = "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("new")]),_v(" Foo.FooBuilder().setA("),_c('span',{pre:true,attrs:{"class":"hljs-string"}},[_v("\"string\"")]),_v(").setC("),_c('span',{pre:true,attrs:{"class":"hljs-number"}},[_v("100")]),_v(").build();\n")])])]),_c('h3',{attrs:{"id":"factory-pattern"}},[_v("Factory pattern"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#factory-pattern","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("The factory pattern should be used when an object needs to be created, but the object to be created is dependant on criteria.\nThe creation logic should then be encapsulated in a factory method.")]),_v(" "),_c('p',[_v("A simple example would be creation of "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("SomeClass")]),_v(" below:")]),_v(" "),_c('pre',[_c('code',{pre:true,attrs:{"class":"hljs java"}},[_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("public")]),_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("abstract")]),_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-class"}},[_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("class")]),_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-title"}},[_v("SomeClass")]),_v(" ")]),_v("{\n")]),_c('span',[_v("}\n")]),_c('span',[_v("\n")]),_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("public")]),_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-class"}},[_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("class")]),_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-title"}},[_v("SomeClassA")]),_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("extends")]),_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-title"}},[_v("SomeClass")]),_v(" ")]),_v("{\n")]),_c('span',[_v(" Integer a;\n")]),_c('span',[_v("}\n")]),_c('span',[_v("\n")]),_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("public")]),_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-class"}},[_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("class")]),_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-title"}},[_v("SomeClassB")]),_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("extends")]),_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-title"}},[_v("SomeClass")]),_v(" ")]),_v("{\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("boolean")]),_v(" b;\n")]),_c('span',[_v("}\n")])])]),_c('p',[_v("Say that "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("SomeClass")]),_v(" is required to be created, and whether we create "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("SomeClassA")]),_v(" or "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("SomeClassB")]),_v(" depends on an enum:")]),_v(" "),_c('pre',[_c('code',{pre:true,attrs:{"class":"hljs java"}},[_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-class"}},[_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("enum")]),_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-title"}},[_v("Type")]),_v(" ")]),_v("{\n")]),_c('span',[_v(" A,\n")]),_c('span',[_v(" B\n")]),_c('span',[_v("}\n")]),_c('span',[_v("\n")]),_c('span',[_v("Type type = Type.A;\n")]),_c('span',[_v("SomeClass someClass;\n")]),_c('span',[_v("\n")]),_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("switch")]),_v("(type) {\n")]),_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("case")]),_v(" Type.A:\n")]),_c('span',[_v(" someClass = "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("new")]),_v(" SomeClassA("),_c('span',{pre:true,attrs:{"class":"hljs-number"}},[_v("1")]),_v(");\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("break")]),_v(";\n")]),_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("case")]),_v(" Type.B:\n")]),_c('span',[_v(" someClass = "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("new")]),_v(" SomeClassB("),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("true")]),_v(");\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("break")]),_v(";\n")]),_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("default")]),_v(":\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("break")]),_v(";\n")]),_c('span',[_v("}\n")])])]),_c('p',[_v("It would be much better to encapsulate this logic in "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("SomeClass")]),_v(":")]),_v(" "),_c('pre',[_c('code',{pre:true,attrs:{"class":"hljs java"}},[_c('span',[_v("\n")]),_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("public")]),_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("abstract")]),_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-class"}},[_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("class")]),_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-title"}},[_v("SomeClass")]),_v(" ")]),_v("{\n")]),_c('span',[_v(" \n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-function"}},[_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("public")]),_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("static")]),_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-title"}},[_v("createSomeClass")]),_c('span',{pre:true,attrs:{"class":"hljs-params"}},[_v("(Type type)")]),_v(" ")]),_v("{\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("switch")]),_v("(type) {\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("case")]),_v(" Type.A:\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("return")]),_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("new")]),_v(" SomeClassA("),_c('span',{pre:true,attrs:{"class":"hljs-number"}},[_v("1")]),_v(");\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("case")]),_v(" Type.B:\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("return")]),_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("new")]),_v(" SomeClassB("),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("true")]),_v(");\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("default")]),_v(":\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("return")]),_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("null")]),_v(";\n")]),_c('span',[_v(" }\n")]),_c('span',[_v(" }\n")]),_c('span',[_v("}\n")]),_c('span',[_v("\n")]),_c('span',[_v("SomeClass someClass = SomeClass.createSomeClass(type);\n")]),_c('span',[_v("\n")])])]),_c('p',[_v("This way, the creation logic is able to be reused throughout the application, and also any changes, such as adding a new subclass, can be more easily done,\nallowing for more extensible code.\n"),_c('a',{attrs:{"href":"https://sergeyzhuk.me/2017/05/22/when-to-factory/"}},[_v("Here")]),_v(" is a great article on why the factory method is useful.")]),_v(" "),_c('h2',{attrs:{"id":"misc"}},[_v("Misc"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#misc","onclick":"event.stopPropagation()"}})]),_v(" "),_c('h3',{attrs:{"id":"migrations"}},[_v("Migrations"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#migrations","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Observing how the migration from datastore to postgresql is carried out for a live system used by users worldwide, with no impact to them is pretty amazing to me.\nOur dualDB approach, where we still query the datastore for courses that are not migrated yet, ensures that functionalities are still avaliabile for the users,\neven when we make huge changes to the system. This is also known as a trickle migration.")]),_v(" "),_c('p',[_c('a',{attrs:{"href":"https://www.talend.com/resources/understanding-data-migration-strategies-best-practices/"}},[_v("Here")]),_v(" is an article I came across when searching up on\nthe types of migration strategies used.")]),_v(" "),_c('h3',{attrs:{"id":"github-web-editor"}},[_v("Github web editor"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#github-web-editor","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Credits to Samuel for this, but I was previously unaware that github had a web editor. By pressing "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v(".")]),_v(" on PRs, it opens the web editor which is\nextremely useful for reviewing PRs, especially those that make changes to large files, so that we can easily view the changes made with the context\nof the entire file, and also its various dependencies.")]),_v(" "),_c('h3',{attrs:{"id":"git-interactive-rebase"}},[_v("Git interactive rebase"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#git-interactive-rebase","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("I've learnt the use of interactive rebase, and how I can use it to rewrite my commit history. This is particularly useful when I would like to remove\ncommits that are unncesary (for instance commits like "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("fix checkstyle")]),_v("), and create a more meaningful commit chain for my PRs. Although the commits are\nsquashed in the end when merged, I find that it is important especially for larger PRs to keep a meaningful commit history, to make it easier on reviewers.")]),_v(" "),_c('p',[_c('a',{attrs:{"href":"https://www.atlassian.com/git/tutorials/rewriting-history/git-rebase"}},[_v("Here")]),_v(" is an article by atlassian that provides more details about the rebase command.")]),_v(" "),_c('h3',{attrs:{"id":"github-cli"}},[_v("Github CLI"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#github-cli","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Prior to this module, I've never used the github CLI, sticking with just "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("git")]),_v(" commands. However, I found it very useful to use the CLI, especially when reviewing\nPRs, as it allowed me to checkout someone's branch with just one command, which github provides on the review page, rather than having to add their remote repo,\nfetching their branches and then checking out the branch.")])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/cedricongjh/observations.html b/students/cedricongjh/observations.html index 46fd65922..f72a3fed1 100644 --- a/students/cedricongjh/observations.html +++ b/students/cedricongjh/observations.html @@ -16,7 +16,7 @@ Mattermost is self-deployable and enables full control over one's data. Mattermost has many intergrations with tools such as GitHub, Jenkins, Jira, to enable technical teams to collaborate more productively.

    My Contributions

    Contributed 2 PRs to Mattermost's mobile application:

    The first was a UX bug fix: link, where the save button on editing a message was not greyed out when the message was too long. To solve this, I edited the styling of the button, changing its opacity for when its disabled. I then replicated the issue locally to add a screenshot to my PR.

    The second was removal of a feature flag: link, to enable timezone support permanently in the application. -To tackle this issue, I had to look at every location where there the feature flag was used in the codebase. When removing the flag, I had to make sure that the logic was correct, behaving as if the feature flag was true and that irrelevant code was removed.

    My Learning Record

    React Native

    The technology used in Mattermost's mobile application is React Native. React Native is a framework for building mobile applications using Javascript and React, and allows developers to create cross-platform applications for iOS and android using a single codebase. React Native utilizes native components and APIs, providing a user experience similar to native apps.

    I used React Native's documentation to learn more about it while contributing.

    Observations from Mattermost

    • PRs are reviewed extensively, with clear steps. Each step is labelled clearly. (Dev Review, QA review, PM review) TEAMMATES also has a similar system in place in terms of labelling the stage of a PR review.
    • Issues are labelled with the technology required (e.g. React, ReactNative, go), the difficulty level (from 1-4), and whether it is currently being worked on by someone. This makes it easier for potential contributors to select issues based on their own confidence level. In TEAMMATES, we only have good first issue as any indicator of difficulty level, but given that most difficult issues are handled by the internal team, there is unlikely a need for difficulty level. For technology required, TEAMMATES also does not have a label, but it should be quite clear when reading the issue if it requires Backend or Frontend. TEAMMATES also has a a-UIX tag that is meant for UIUX related issues, which is very often used to tag Frontend issues.
    • Mattermost also has their own deployed instance of itself, where contributors can ask questions. It was really useful for me when I ran into issues trying to login to my locally setup Mattermost, and asking for PR reviews. TEAMMATES does not have this, but it would be really costly for us to maintain.
    +To tackle this issue, I had to look at every location where there the feature flag was used in the codebase. When removing the flag, I had to make sure that the logic was correct, behaving as if the feature flag was true and that irrelevant code was removed.

    My Learning Record

    React Native

    The technology used in Mattermost's mobile application is React Native. React Native is a framework for building mobile applications using Javascript and React, and allows developers to create cross-platform applications for iOS and android using a single codebase. React Native utilizes native components and APIs, providing a user experience similar to native apps.

    I used React Native's documentation to learn more about it while contributing.

    Observations from Mattermost

    • PRs are reviewed extensively, with clear steps. Each step is labelled clearly. (Dev Review, QA review, PM review) TEAMMATES also has a similar system in place in terms of labelling the stage of a PR review.
    • Issues are labelled with the technology required (e.g. React, ReactNative, go), the difficulty level (from 1-4), and whether it is currently being worked on by someone. This makes it easier for potential contributors to select issues based on their own confidence level. In TEAMMATES, we only have good first issue as any indicator of difficulty level, but given that most difficult issues are handled by the internal team, there is unlikely a need for difficulty level. For technology required, TEAMMATES also does not have a label, but it should be quite clear when reading the issue if it requires Backend or Frontend. TEAMMATES also has a a-UIX tag that is meant for UIUX related issues, which is very often used to tag Frontend issues.
    • Mattermost also has their own deployed instance of itself, where contributors can ask questions. It was really useful for me when I ran into issues trying to login to my locally setup Mattermost, and asking for PR reviews. TEAMMATES does not have this, but it would be really costly for us to maintain.
    diff --git a/students/cedricongjh/observations.page-vue-render.js b/students/cedricongjh/observations.page-vue-render.js index 16fb3ea12..a987d33ef 100644 --- a/students/cedricongjh/observations.page-vue-render.js +++ b/students/cedricongjh/observations.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('h3',{attrs:{"id":"project-mattermost"}},[_v("Project: Mattermost"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#project-mattermost","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_c('a',{attrs:{"href":"https://mattermost.com"}},[_v("Mattermost")]),_v(" is an open-source alternative to slack and mircosoft teams, used by notable companies such as Samsung, NASA, DuckDuckGo.\nMattermost is self-deployable and enables full control over one's data. Mattermost has many intergrations with tools such as GitHub, Jenkins, Jira, to enable technical teams to collaborate more productively.")]),_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("Contributed 2 PRs to Mattermost's mobile application:")]),_v(" "),_c('p',[_v("The first was a UX bug fix: "),_c('a',{attrs:{"href":"https://github.com/mattermost/mattermost-mobile/pull/7763"}},[_v("link")]),_v(", where the save button on editing a message was not greyed out when the message was too long.\nTo solve this, I edited the styling of the button, changing its opacity for when its disabled.\nI then replicated the issue locally to add a screenshot to my PR.")]),_v(" "),_c('p',[_v("The second was removal of a feature flag: "),_c('a',{attrs:{"href":"https://github.com/mattermost/mattermost-mobile/pull/7769"}},[_v("link")]),_v(", to enable timezone support permanently in the application.\nTo tackle this issue, I had to look at every location where there the feature flag was used in the codebase. When removing the flag, I had to make sure that the logic was correct, behaving as if the feature flag was "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("true")]),_v(" and that irrelevant code was removed.")]),_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('h4',{attrs:{"id":"react-native"}},[_v("React Native"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#react-native","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("The technology used in Mattermost's mobile application is React Native. React Native is a framework for building mobile applications using Javascript and React, and allows developers to create cross-platform applications for iOS and android using a single codebase. React Native utilizes native components and APIs, providing a user experience similar to native apps.")]),_v(" "),_c('p',[_v("I used React Native's "),_c('a',{attrs:{"href":"https://reactnative.dev/docs/getting-started"}},[_v("documentation")]),_v(" to learn more about it while contributing.")]),_v(" "),_c('h3',{attrs:{"id":"observations-from-mattermost"}},[_v("Observations from Mattermost"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#observations-from-mattermost","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ul',[_c('li',[_v("PRs are reviewed extensively, with clear steps. Each step is labelled clearly. (Dev Review, QA review, PM review) TEAMMATES also has a similar system in place in terms of labelling the stage of a PR review.")]),_v(" "),_c('li',[_v("Issues are labelled with the technology required (e.g. React, ReactNative, go), the difficulty level (from 1-4), and whether it is currently being worked on by someone. This makes it easier for potential contributors to select issues based on their own confidence level. In TEAMMATES, we only have "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("good first issue")]),_v(" as any indicator of difficulty level, but given that most difficult issues are handled by the internal team, there is unlikely a need for difficulty level. For technology required, TEAMMATES also does not have a label, but it should be quite clear when reading the issue if it requires Backend or Frontend. TEAMMATES also has a "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("a-UIX")]),_v(" tag that is meant for UIUX related issues, which is very often used to tag Frontend issues.")]),_v(" "),_c('li',[_v("Mattermost also has their own deployed instance of itself, where contributors can ask questions. It was really useful for me when I ran into issues trying to login to my locally setup Mattermost, and asking for PR reviews. TEAMMATES does not have this, but it would be really costly for us to maintain.")])])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/cedricongjh/progress.html b/students/cedricongjh/progress.html index e48d1d84b..071003429 100644 --- a/students/cedricongjh/progress.html +++ b/students/cedricongjh/progress.html @@ -12,7 +12,7 @@ const baseUrl = '/2024' -

    Summary

    • Led the migration of the remaining actions for V9.
    • Led the team in ensuring that there were no regressions in V9-beta (dual DB) through automated and manual testing.
    • Led LOGS project.
    • Reviewed workflows for release with the new SQL DB.

    CS3282 Pre-Sem Progress

    CS3282 Progress

    Week Achievements
    2 Reviewed PR: Migrate UpdateInstructorAction #12434
    2 Reviewed PR: Update Angular to 16 and Node to 18 #12694
    2 Reviewed PR: Migrate SearchInstructorsAction #12340
    2 Reviewed PR: Migrate FeedbackSession*RemindersAction classes #12711
    3 Merged PR: Fix update and create feedbackquestion actions #12716
    3 Reviewed PR: Migrate RemoveDataBundle #12709
    3 Reviewed PR: Migrate GetOngoingSessionsAction for V9 #12710
    3 Reviewed PR: Migrate GetCourseJoinStatusAction #12713
    4 Reviewed PR: Migrate CreateInstructorAction #12706
    4 Reviewed PR: Migrate join course action #12722
    4 Reviewed PR: Support for twin db for search + replace datastore test #12728
    4 Reviewed PR: Add SQL email generator unit test #12721
    5 Merged PR: Finish partial testcases #12742
    5 Reviewed PR: Migrate search students action #12735
    5 Merged PR: Move getTypicalEntity functions to BaseTestCase #12744
    5 Reviewed PR: Migrate StudentSearchIndexingWorkerAction #12733
    5 Reviewed PR: Migrate Session Links Recovery Action #12712
    5 Reviewed PR: Add tests for CoursesLogic #12746
    5 Reviewed PR: Update restoreDeletedFeedbackSession to save updated entity to db #12751
    5 Reviewed PR: Migrate instructor search indexing worker action #12731
    5 Merged PR: Remove typical data bundle from feedbackquestionlogic test #12750
    5 Reviewed PR: Migrate SubmitFeedbackResponseAction's Logic and Db methods #12732
    6 Merged PR: Add test for getUsageStatisticsForTimeRange #12748
    6 Reviewed PR: Add testcases for FeedbackResponseCommentsDbTest #12755
    6 Reviewed PR: Migrate feedbackSessionPublishedRemindersAction #12741
    6 Reviewed PR: Migrate FeedbackSessionOpeningSoonRemindersAction #12740
    6 Reviewed PR: Migrate SubmitFeedbackResponseAction #12720
    6 Reviewed PR: Migrate FeedbackSessionClosingRemindersAction #12743
    6 Reviewed PR: Migrate AccountRequestSearchIndexingWorkerAction #12757
    6 Reviewed PR: Add test cases for FeedbackSessionsDb #12752
    6 Reviewed PR: Merge in current v9-migration #12771
    6 Reviewed PR: Fix GetSessionResponseStatsActionIT #12777
    6 Reviewed PR: Migrate instructor notification page e2e test #12792
    6 Merged PR: migrate InstructorCourseJoinConfirmationPageE2ETest #12790
    6 Merged PR: Migrate instructor courses page e2e test #12789
    6 Reviewed PR: Fix incorrect usage of recipient as param for E2E test #12797
    6 Merged PR: migrate AdminHomePageE2ETest #12794
    6 Reviewed PR: Move accounts JSON for AdminSessionsPageE2ETest #12802
    6 Merged PR: Migrate instructor feedback edit page e2e test #12795
    6 Merged PR: migrate StudentHomePageE2ETest #12807
    6 Merged PR: migrate AdminAccountsPageE2ETest #12806
    6 Reviewed PR: Add locale for java datetime formatter #12826
    6 Reviewed PR: Move accounts JSON for FeedbackConstSumRecipientQuestionE2ETest #12805
    6 Reviewed PR: Move accounts JSON for FeedbackContributionQuestionE2ETest #12808
    6 Reviewed PR: Move accounts JSON for FeedbackMcqQuestionE2ETest #12809
    6 Reviewed PR: Fix failing component tests #12837
    6 Reviewed PR: Move accounts JSON for FeedbackMsqQuestionE2ETest #12810
    6 Reviewed PR: Move accounts JSON for FeedbackNumScaleQuestionE2ETest #12812
    6 Reviewed PR: Move accounts JSON for FeedbackRankOptionQuestionE2ETest #12813
    6 Reviewed PR: Move accounts JSON for FeedbackRankRecipientQuestionE2ETest #12814
    6 Reviewed PR: Move accounts JSON for AutomatedSessionRemindersE2ETest #12803
    6 Reviewed PR: Migrate Admin Notifications E2E Test #12793
    6 Merged PR: Revert createaccountaction #12835
    6 Reviewed PR: Move accounts JSON for InstructorFeedbackReportPageE2ETest #12833
    6 Reviewed PR: Move accounts JSON for InstructorCourseStudentDetailsEditPageE2ETest #12829
    6 Reviewed PR: Move accounts JSON for InstructorCourseStudentDetailsPageE2ETest #12831
    6 Reviewed PR: Move accounts JSON for InstructorCourseEnrollPageE2ETest #12827
    Recess Reviewed PR: Migrate AdminSearchPageE2ETest #12838
    Recess Reviewed PR: Migrate Notification Banner E2E #12840
    Recess Merged PR: fix InstructorHomePageE2ETest #12839
    Recess Reviewed PR: Migrate GetSessionResultsAction #12719
    Recess Merged PR: Fix GitHub actions #12850
    Recess Reviewed PR: Add tests for CourseDbIT #12786
    Recess Merged PR: SQL injection test for UsersDbIT #12851
    Recess Reviewed PR: Add SQL injection tests in NotificationDbIT #12858
    Recess Reviewed PR: Migrate GetFeedbackSessionLogsAction #12862
    Recess Merged PR: Fix FeedbackResultsPageE2ETest #12855
    7 Reviewed PR: Add tests for FeedbackQuestionsDb #12759
    7 Reviewed PR: Migrate StudentCourseJoinConfirmationPageE2ETest #12815
    7 Merged PR: add check for sql tests in TestNgXml #12870
    7 Merged PR: Fix account creation #12871
    7 Submitted Issue: Release V9.0.0-beta.0 #12876
    7 Reviewed PR: Prepare Patch Data Migration Script for Account #12883
    7 Reviewed PR: Patch account and read notification migration #12884
    8 Reviewed PR: Add tests for FeedbackQuestionsDbIT #12781
    8 Merged PR: Fix get feedback sessions action #12886
    8 Reviewed PR: Add integration tests for FeedbackResponseCommentsDb #12849
    8 Reviewed PR: Migrate InstructorSearchPageE2ETest #12891
    8 Reviewed PR: Docs: Upgrade to latest MarkBind version #12893
    9 Reviewed PR: Create FeedbackSessionLog entity and cron job action #12895
    9 Reviewed PR: Migrate InstructorNotificationsPageE2E #12906
    9 Reviewed PR: Add deep comparison for entities in verifyEquals for E2E #12892
    9 Reviewed PR: Migrate FeedbackMsqQuestionE2ETest #12904
    9 Reviewed PR: Add SQL configuration into build.properties and build-dev.properties #12917
    9 Reviewed PR: Create script to migrate noSQL test data to SQL schema format #12922
    10 Merged PR: add delay to task queuer for indexing account request #12936
    10 Reviewed PR: Migrate Feedback Rank Option E2E test #12902
    10 Submitted Issue: Release V9.0.0-beta.1 #12939
    10 Merged PR: fix resetAccountAction #12934
    10 Reviewed PR: Migrate FeedbackMcqQuestionE2ETest #12820
    10 Reviewed PR: Remove unnecessary loading of datastore entities in InstructorNotificationsPageE2ETest #12911
    10 Reviewed PR: Migrate InstructorCourseDetailsPageE2ETest #12908
    10 Merged PR: Release V9.0.0-beta.1 #12958
    10 Reviewed PR: Create Logic and Db layer for FeedbackSessionLogs #12914
    10 Reviewed PR: Migrate AdminSearchPageE2ETest SQL #12811
    10 Merged PR: Release V9.0.0-beta.1 #12960
    10 Merged PR: Merge pull request #12960 from TEAMMATES/master #12961
    10 Merged PR: Fix account request indexing #12967
    10 Submitted Issue: Release V9.0.0-beta.2 #12968
    10 Merged PR: Merge master to release #12969
    10 Merged PR: configure agroal connection pool #12971
    11 Submitted Issue: Release V9.0.0-beta.3 #12976
    11 Reviewed PR: Configure connection pool using hikari #12978
    11 Submitted Issue: Release V9.0.0-beta.4 #12979
    11 Reviewed PR: Update GetFeedbackSessionLogsAction to use SQL db #12938
    11 Reviewed PR: Create Update Account Request Action #12982
    11 Reviewed PR: Update liquibase configuration #12930
    11 Reviewed PR: Fix Account Request Update Search Indexing #12984
    12 Reviewed PR: Migrate AccountRequestsLogicTest #12780
    12 Reviewed PR: Remove feedbackSession attributes @fetch annotation #12992
    12 Reviewed PR: Remove unused modal in AdminHomePage #12998
    12 Reviewed PR: Convert RejectAccountRequestAction to use transactions #13001
    12 Reviewed PR: Update DeleteAccountRequest to reference by ID #12997
    12 Reviewed PR: Migrate FeedbackNumScaleQuestionE2ETest #12940
    12 Reviewed PR: Update front end for session activity logs #12973
    12 Reviewed PR: Add v9.0.0 tag to liquibase changelog #13005
    12 Merged PR: Fix flaky component test #13003
    12 Merged PR: Get account request by uuid #13007
    12 Reviewed PR: Reference account requests by ID in tests #13017
    13 Reviewed PR: Fix FeedBackResponsesLogic bug #13024
    13 Reviewed PR: Fix getSessionResultAction bugs #13023
    13 Reviewed PR: Fix front end bugs #13037
    13 Reviewed PR: Remove ref by email and institute #13044
    13 Reviewed PR: Account request form #13048
    13 Reviewed PR: Migrate committers #13052
    13 Reviewed PR: Merge student-activity-logs into master #13041
    13 Reviewed PR: Update backend libraries versions, support Java 21 #12885
    13 Reviewed PR: Add beta 5 liquibase changelog and developers json #13061
    Reading Reviewed PR: Use AccountRequestUpdateRequest as parameter #13068
    +

    Summary

    • Led the migration of the remaining actions for V9.
    • Led the team in ensuring that there were no regressions in V9-beta (dual DB) through automated and manual testing.
    • Led LOGS project.
    • Reviewed workflows for release with the new SQL DB.

    CS3282 Pre-Sem Progress

    CS3282 Progress

    Week Achievements
    2 Reviewed PR: Migrate UpdateInstructorAction #12434
    2 Reviewed PR: Update Angular to 16 and Node to 18 #12694
    2 Reviewed PR: Migrate SearchInstructorsAction #12340
    2 Reviewed PR: Migrate FeedbackSession*RemindersAction classes #12711
    3 Merged PR: Fix update and create feedbackquestion actions #12716
    3 Reviewed PR: Migrate RemoveDataBundle #12709
    3 Reviewed PR: Migrate GetOngoingSessionsAction for V9 #12710
    3 Reviewed PR: Migrate GetCourseJoinStatusAction #12713
    4 Reviewed PR: Migrate CreateInstructorAction #12706
    4 Reviewed PR: Migrate join course action #12722
    4 Reviewed PR: Support for twin db for search + replace datastore test #12728
    4 Reviewed PR: Add SQL email generator unit test #12721
    5 Merged PR: Finish partial testcases #12742
    5 Reviewed PR: Migrate search students action #12735
    5 Merged PR: Move getTypicalEntity functions to BaseTestCase #12744
    5 Reviewed PR: Migrate StudentSearchIndexingWorkerAction #12733
    5 Reviewed PR: Migrate Session Links Recovery Action #12712
    5 Reviewed PR: Add tests for CoursesLogic #12746
    5 Reviewed PR: Update restoreDeletedFeedbackSession to save updated entity to db #12751
    5 Reviewed PR: Migrate instructor search indexing worker action #12731
    5 Merged PR: Remove typical data bundle from feedbackquestionlogic test #12750
    5 Reviewed PR: Migrate SubmitFeedbackResponseAction's Logic and Db methods #12732
    6 Merged PR: Add test for getUsageStatisticsForTimeRange #12748
    6 Reviewed PR: Add testcases for FeedbackResponseCommentsDbTest #12755
    6 Reviewed PR: Migrate feedbackSessionPublishedRemindersAction #12741
    6 Reviewed PR: Migrate FeedbackSessionOpeningSoonRemindersAction #12740
    6 Reviewed PR: Migrate SubmitFeedbackResponseAction #12720
    6 Reviewed PR: Migrate FeedbackSessionClosingRemindersAction #12743
    6 Reviewed PR: Migrate AccountRequestSearchIndexingWorkerAction #12757
    6 Reviewed PR: Add test cases for FeedbackSessionsDb #12752
    6 Reviewed PR: Merge in current v9-migration #12771
    6 Reviewed PR: Fix GetSessionResponseStatsActionIT #12777
    6 Reviewed PR: Migrate instructor notification page e2e test #12792
    6 Merged PR: migrate InstructorCourseJoinConfirmationPageE2ETest #12790
    6 Merged PR: Migrate instructor courses page e2e test #12789
    6 Reviewed PR: Fix incorrect usage of recipient as param for E2E test #12797
    6 Merged PR: migrate AdminHomePageE2ETest #12794
    6 Reviewed PR: Move accounts JSON for AdminSessionsPageE2ETest #12802
    6 Merged PR: Migrate instructor feedback edit page e2e test #12795
    6 Merged PR: migrate StudentHomePageE2ETest #12807
    6 Merged PR: migrate AdminAccountsPageE2ETest #12806
    6 Reviewed PR: Add locale for java datetime formatter #12826
    6 Reviewed PR: Move accounts JSON for FeedbackConstSumRecipientQuestionE2ETest #12805
    6 Reviewed PR: Move accounts JSON for FeedbackContributionQuestionE2ETest #12808
    6 Reviewed PR: Move accounts JSON for FeedbackMcqQuestionE2ETest #12809
    6 Reviewed PR: Fix failing component tests #12837
    6 Reviewed PR: Move accounts JSON for FeedbackMsqQuestionE2ETest #12810
    6 Reviewed PR: Move accounts JSON for FeedbackNumScaleQuestionE2ETest #12812
    6 Reviewed PR: Move accounts JSON for FeedbackRankOptionQuestionE2ETest #12813
    6 Reviewed PR: Move accounts JSON for FeedbackRankRecipientQuestionE2ETest #12814
    6 Reviewed PR: Move accounts JSON for AutomatedSessionRemindersE2ETest #12803
    6 Reviewed PR: Migrate Admin Notifications E2E Test #12793
    6 Merged PR: Revert createaccountaction #12835
    6 Reviewed PR: Move accounts JSON for InstructorFeedbackReportPageE2ETest #12833
    6 Reviewed PR: Move accounts JSON for InstructorCourseStudentDetailsEditPageE2ETest #12829
    6 Reviewed PR: Move accounts JSON for InstructorCourseStudentDetailsPageE2ETest #12831
    6 Reviewed PR: Move accounts JSON for InstructorCourseEnrollPageE2ETest #12827
    Recess Reviewed PR: Migrate AdminSearchPageE2ETest #12838
    Recess Reviewed PR: Migrate Notification Banner E2E #12840
    Recess Merged PR: fix InstructorHomePageE2ETest #12839
    Recess Reviewed PR: Migrate GetSessionResultsAction #12719
    Recess Merged PR: Fix GitHub actions #12850
    Recess Reviewed PR: Add tests for CourseDbIT #12786
    Recess Merged PR: SQL injection test for UsersDbIT #12851
    Recess Reviewed PR: Add SQL injection tests in NotificationDbIT #12858
    Recess Reviewed PR: Migrate GetFeedbackSessionLogsAction #12862
    Recess Merged PR: Fix FeedbackResultsPageE2ETest #12855
    7 Reviewed PR: Add tests for FeedbackQuestionsDb #12759
    7 Reviewed PR: Migrate StudentCourseJoinConfirmationPageE2ETest #12815
    7 Merged PR: add check for sql tests in TestNgXml #12870
    7 Merged PR: Fix account creation #12871
    7 Submitted Issue: Release V9.0.0-beta.0 #12876
    7 Reviewed PR: Prepare Patch Data Migration Script for Account #12883
    7 Reviewed PR: Patch account and read notification migration #12884
    8 Reviewed PR: Add tests for FeedbackQuestionsDbIT #12781
    8 Merged PR: Fix get feedback sessions action #12886
    8 Reviewed PR: Add integration tests for FeedbackResponseCommentsDb #12849
    8 Reviewed PR: Migrate InstructorSearchPageE2ETest #12891
    8 Reviewed PR: Docs: Upgrade to latest MarkBind version #12893
    9 Reviewed PR: Create FeedbackSessionLog entity and cron job action #12895
    9 Reviewed PR: Migrate InstructorNotificationsPageE2E #12906
    9 Reviewed PR: Add deep comparison for entities in verifyEquals for E2E #12892
    9 Reviewed PR: Migrate FeedbackMsqQuestionE2ETest #12904
    9 Reviewed PR: Add SQL configuration into build.properties and build-dev.properties #12917
    9 Reviewed PR: Create script to migrate noSQL test data to SQL schema format #12922
    10 Merged PR: add delay to task queuer for indexing account request #12936
    10 Reviewed PR: Migrate Feedback Rank Option E2E test #12902
    10 Submitted Issue: Release V9.0.0-beta.1 #12939
    10 Merged PR: fix resetAccountAction #12934
    10 Reviewed PR: Migrate FeedbackMcqQuestionE2ETest #12820
    10 Reviewed PR: Remove unnecessary loading of datastore entities in InstructorNotificationsPageE2ETest #12911
    10 Reviewed PR: Migrate InstructorCourseDetailsPageE2ETest #12908
    10 Merged PR: Release V9.0.0-beta.1 #12958
    10 Reviewed PR: Create Logic and Db layer for FeedbackSessionLogs #12914
    10 Reviewed PR: Migrate AdminSearchPageE2ETest SQL #12811
    10 Merged PR: Release V9.0.0-beta.1 #12960
    10 Merged PR: Merge pull request #12960 from TEAMMATES/master #12961
    10 Merged PR: Fix account request indexing #12967
    10 Submitted Issue: Release V9.0.0-beta.2 #12968
    10 Merged PR: Merge master to release #12969
    10 Merged PR: configure agroal connection pool #12971
    11 Submitted Issue: Release V9.0.0-beta.3 #12976
    11 Reviewed PR: Configure connection pool using hikari #12978
    11 Submitted Issue: Release V9.0.0-beta.4 #12979
    11 Reviewed PR: Update GetFeedbackSessionLogsAction to use SQL db #12938
    11 Reviewed PR: Create Update Account Request Action #12982
    11 Reviewed PR: Update liquibase configuration #12930
    11 Reviewed PR: Fix Account Request Update Search Indexing #12984
    12 Reviewed PR: Migrate AccountRequestsLogicTest #12780
    12 Reviewed PR: Remove feedbackSession attributes @fetch annotation #12992
    12 Reviewed PR: Remove unused modal in AdminHomePage #12998
    12 Reviewed PR: Convert RejectAccountRequestAction to use transactions #13001
    12 Reviewed PR: Update DeleteAccountRequest to reference by ID #12997
    12 Reviewed PR: Migrate FeedbackNumScaleQuestionE2ETest #12940
    12 Reviewed PR: Update front end for session activity logs #12973
    12 Reviewed PR: Add v9.0.0 tag to liquibase changelog #13005
    12 Merged PR: Fix flaky component test #13003
    12 Merged PR: Get account request by uuid #13007
    12 Reviewed PR: Reference account requests by ID in tests #13017
    13 Reviewed PR: Fix FeedBackResponsesLogic bug #13024
    13 Reviewed PR: Fix getSessionResultAction bugs #13023
    13 Reviewed PR: Fix front end bugs #13037
    13 Reviewed PR: Remove ref by email and institute #13044
    13 Reviewed PR: Account request form #13048
    13 Reviewed PR: Migrate committers #13052
    13 Reviewed PR: Merge student-activity-logs into master #13041
    13 Reviewed PR: Update backend libraries versions, support Java 21 #12885
    13 Reviewed PR: Add beta 5 liquibase changelog and developers json #13061
    Reading Reviewed PR: Use AccountRequestUpdateRequest as parameter #13068
    diff --git a/students/cedricongjh/progress.page-vue-render.js b/students/cedricongjh/progress.page-vue-render.js index 27929d779..686a845c4 100644 --- a/students/cedricongjh/progress.page-vue-render.js +++ b/students/cedricongjh/progress.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('h2',{attrs:{"id":"summary"}},[_v("Summary"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#summary","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ul',[_c('li',[_v("Led the migration of the remaining actions for V9.")]),_v(" "),_c('li',[_v("Led the team in ensuring that there were no regressions in V9-beta (dual DB) through automated and manual testing.")]),_v(" "),_c('li',[_v("Led LOGS project.")]),_v(" "),_c('li',[_v("Reviewed workflows for release with the new SQL DB.")])]),_v(" "),_c('h2',{attrs:{"id":"cs3282-pre-sem-progress"}},[_v("CS3282 Pre-Sem Progress"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#cs3282-pre-sem-progress","onclick":"event.stopPropagation()"}})]),_v(" "),_c('div',{staticClass:"table-responsive"},[_c('table',{staticClass:"markbind-table table table-bordered table-striped"},[_c('thead',[_c('tr',[_c('th',[_v("Date")]),_v(" "),_c('th',[_v("Achievements")])])]),_v(" "),_c('tbody',[_c('tr',[_c('td',[_v("Nov 27, 2023")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12601"}},[_v("Fix deadline extensions update issue #12601")])])]),_v(" "),_c('tr',[_c('td',[_v("Dec 11, 2023")]),_v(" "),_c('td',[_v("Submitted Issue: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/issues/12652"}},[_v("Copying feedback session: mark session name as mandatory field when copying feedback session")])])]),_v(" "),_c('tr',[_c('td',[_v("Dec 11, 2023")]),_v(" "),_c('td',[_v("Submitted Issue: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/issues/12653"}},[_v("Copy course modal: Mandatory fields not highlighted #12653")])])])])])]),_c('h2',{attrs:{"id":"cs3282-progress"}},[_v("CS3282 Progress"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#cs3282-progress","onclick":"event.stopPropagation()"}})]),_v(" "),_c('div',{staticClass:"table-responsive"},[_c('table',{staticClass:"markbind-table table table-bordered table-striped"},[_c('thead',[_c('tr',[_c('th',[_v("Week")]),_v(" "),_c('th',[_v("Achievements")])])]),_v(" "),_c('tbody',[_c('tr',[_c('td',[_v("2")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12434"}},[_v("Migrate UpdateInstructorAction #12434")])])]),_v(" "),_c('tr',[_c('td',[_v("2")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12694"}},[_v("Update Angular to 16 and Node to 18 #12694")])])]),_v(" "),_c('tr',[_c('td',[_v("2")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12340"}},[_v("Migrate SearchInstructorsAction #12340")])])]),_v(" "),_c('tr',[_c('td',[_v("2")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12711"}},[_v("Migrate FeedbackSession*RemindersAction classes #12711")])])]),_v(" "),_c('tr',[_c('td',[_v("3")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12716"}},[_v("Fix update and create feedbackquestion actions #12716")])])]),_v(" "),_c('tr',[_c('td',[_v("3")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12709"}},[_v("Migrate RemoveDataBundle #12709")])])]),_v(" "),_c('tr',[_c('td',[_v("3")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12710"}},[_v("Migrate GetOngoingSessionsAction for V9 #12710")])])]),_v(" "),_c('tr',[_c('td',[_v("3")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12713"}},[_v("Migrate GetCourseJoinStatusAction #12713")])])]),_v(" "),_c('tr',[_c('td',[_v("4")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12706"}},[_v("Migrate CreateInstructorAction #12706")])])]),_v(" "),_c('tr',[_c('td',[_v("4")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12722"}},[_v("Migrate join course action #12722")])])]),_v(" "),_c('tr',[_c('td',[_v("4")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12728"}},[_v("Support for twin db for search + replace datastore test #12728")])])]),_v(" "),_c('tr',[_c('td',[_v("4")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12721"}},[_v("Add SQL email generator unit test #12721")])])]),_v(" "),_c('tr',[_c('td',[_v("5")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12742"}},[_v("Finish partial testcases #12742")])])]),_v(" "),_c('tr',[_c('td',[_v("5")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12735"}},[_v("Migrate search students action #12735")])])]),_v(" "),_c('tr',[_c('td',[_v("5")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12744"}},[_v("Move getTypicalEntity functions to BaseTestCase #12744")])])]),_v(" "),_c('tr',[_c('td',[_v("5")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12733"}},[_v("Migrate StudentSearchIndexingWorkerAction #12733")])])]),_v(" "),_c('tr',[_c('td',[_v("5")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12712"}},[_v("Migrate Session Links Recovery Action #12712")])])]),_v(" "),_c('tr',[_c('td',[_v("5")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12746"}},[_v("Add tests for CoursesLogic #12746")])])]),_v(" "),_c('tr',[_c('td',[_v("5")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12751"}},[_v("Update restoreDeletedFeedbackSession to save updated entity to db #12751")])])]),_v(" "),_c('tr',[_c('td',[_v("5")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12731"}},[_v("Migrate instructor search indexing worker action #12731")])])]),_v(" "),_c('tr',[_c('td',[_v("5")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12750"}},[_v("Remove typical data bundle from feedbackquestionlogic test #12750")])])]),_v(" "),_c('tr',[_c('td',[_v("5")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12732"}},[_v("Migrate SubmitFeedbackResponseAction's Logic and Db methods #12732")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12748"}},[_v("Add test for getUsageStatisticsForTimeRange #12748")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12755"}},[_v("Add testcases for FeedbackResponseCommentsDbTest #12755")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12741"}},[_v("Migrate feedbackSessionPublishedRemindersAction #12741")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12740"}},[_v("Migrate FeedbackSessionOpeningSoonRemindersAction #12740")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12720"}},[_v("Migrate SubmitFeedbackResponseAction #12720")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12743"}},[_v("Migrate FeedbackSessionClosingRemindersAction #12743")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12757"}},[_v("Migrate AccountRequestSearchIndexingWorkerAction #12757")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12752"}},[_v("Add test cases for FeedbackSessionsDb #12752")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12771"}},[_v("Merge in current v9-migration #12771")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12777"}},[_v("Fix GetSessionResponseStatsActionIT #12777")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12792"}},[_v("Migrate instructor notification page e2e test #12792")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12790"}},[_v("migrate InstructorCourseJoinConfirmationPageE2ETest #12790")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12789"}},[_v("Migrate instructor courses page e2e test #12789")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12797"}},[_v("Fix incorrect usage of "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("recipient")]),_v(" as param for E2E test #12797")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12794"}},[_v("migrate AdminHomePageE2ETest #12794")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12802"}},[_v("Move accounts JSON for AdminSessionsPageE2ETest #12802")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12795"}},[_v("Migrate instructor feedback edit page e2e test #12795")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12807"}},[_v("migrate StudentHomePageE2ETest #12807")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12806"}},[_v("migrate AdminAccountsPageE2ETest #12806")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12826"}},[_v("Add locale for java datetime formatter #12826")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12805"}},[_v("Move accounts JSON for FeedbackConstSumRecipientQuestionE2ETest #12805")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12808"}},[_v("Move accounts JSON for FeedbackContributionQuestionE2ETest #12808")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12809"}},[_v("Move accounts JSON for FeedbackMcqQuestionE2ETest #12809")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12837"}},[_v("Fix failing component tests #12837")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12810"}},[_v("Move accounts JSON for FeedbackMsqQuestionE2ETest #12810")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12812"}},[_v("Move accounts JSON for FeedbackNumScaleQuestionE2ETest #12812")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12813"}},[_v("Move accounts JSON for FeedbackRankOptionQuestionE2ETest #12813")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12814"}},[_v("Move accounts JSON for FeedbackRankRecipientQuestionE2ETest #12814")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12803"}},[_v("Move accounts JSON for AutomatedSessionRemindersE2ETest #12803")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12793"}},[_v("Migrate Admin Notifications E2E Test #12793")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12835"}},[_v("Revert createaccountaction #12835")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12833"}},[_v("Move accounts JSON for InstructorFeedbackReportPageE2ETest #12833")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12829"}},[_v("Move accounts JSON for InstructorCourseStudentDetailsEditPageE2ETest #12829")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12831"}},[_v("Move accounts JSON for InstructorCourseStudentDetailsPageE2ETest #12831")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12827"}},[_v("Move accounts JSON for InstructorCourseEnrollPageE2ETest #12827")])])]),_v(" "),_c('tr',[_c('td',[_v("Recess")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12838"}},[_v("Migrate AdminSearchPageE2ETest #12838")])])]),_v(" "),_c('tr',[_c('td',[_v("Recess")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12840"}},[_v("Migrate Notification Banner E2E #12840")])])]),_v(" "),_c('tr',[_c('td',[_v("Recess")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12839"}},[_v("fix InstructorHomePageE2ETest #12839")])])]),_v(" "),_c('tr',[_c('td',[_v("Recess")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12719"}},[_v("Migrate GetSessionResultsAction #12719")])])]),_v(" "),_c('tr',[_c('td',[_v("Recess")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12850"}},[_v("Fix GitHub actions #12850")])])]),_v(" "),_c('tr',[_c('td',[_v("Recess")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12786"}},[_v("Add tests for CourseDbIT #12786")])])]),_v(" "),_c('tr',[_c('td',[_v("Recess")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12851"}},[_v("SQL injection test for UsersDbIT #12851")])])]),_v(" "),_c('tr',[_c('td',[_v("Recess")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12858"}},[_v("Add SQL injection tests in NotificationDbIT #12858")])])]),_v(" "),_c('tr',[_c('td',[_v("Recess")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12862"}},[_v("Migrate GetFeedbackSessionLogsAction #12862")])])]),_v(" "),_c('tr',[_c('td',[_v("Recess")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12855"}},[_v("Fix FeedbackResultsPageE2ETest #12855")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12759"}},[_v("Add tests for FeedbackQuestionsDb #12759")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12815"}},[_v("Migrate StudentCourseJoinConfirmationPageE2ETest #12815")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12870"}},[_v("add check for sql tests in TestNgXml #12870")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12871"}},[_v("Fix account creation #12871")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Submitted Issue: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/issues/12876"}},[_v("Release V9.0.0-beta.0 #12876")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12883"}},[_v("Prepare Patch Data Migration Script for Account #12883")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12884"}},[_v("Patch account and read notification migration #12884")])])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12781"}},[_v("Add tests for FeedbackQuestionsDbIT #12781")])])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12886"}},[_v("Fix get feedback sessions action #12886")])])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12849"}},[_v("Add integration tests for FeedbackResponseCommentsDb #12849")])])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12891"}},[_v("Migrate InstructorSearchPageE2ETest #12891")])])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12893"}},[_v("Docs: Upgrade to latest MarkBind version #12893")])])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12895"}},[_v("Create FeedbackSessionLog entity and cron job action #12895")])])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12906"}},[_v("Migrate InstructorNotificationsPageE2E #12906")])])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12892"}},[_v("Add deep comparison for entities in "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("verifyEquals")]),_v(" for E2E #12892")])])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12904"}},[_v("Migrate FeedbackMsqQuestionE2ETest #12904")])])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12917"}},[_v("Add SQL configuration into build.properties and build-dev.properties #12917")])])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12922"}},[_v("Create script to migrate noSQL test data to SQL schema format #12922")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12936"}},[_v("add delay to task queuer for indexing account request #12936")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12902"}},[_v("Migrate Feedback Rank Option E2E test #12902")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Submitted Issue: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/issues/12939"}},[_v("Release V9.0.0-beta.1 #12939")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12934"}},[_v("fix resetAccountAction #12934")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12820"}},[_v("Migrate FeedbackMcqQuestionE2ETest #12820")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12911"}},[_v("Remove unnecessary loading of datastore entities in InstructorNotificationsPageE2ETest #12911")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12908"}},[_v("Migrate InstructorCourseDetailsPageE2ETest #12908")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12958"}},[_v("Release V9.0.0-beta.1 #12958")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12914"}},[_v("Create Logic and Db layer for FeedbackSessionLogs #12914")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12811"}},[_v("Migrate AdminSearchPageE2ETest SQL #12811")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12960"}},[_v("Release V9.0.0-beta.1 #12960")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12961"}},[_v("Merge pull request #12960 from TEAMMATES/master #12961")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12967"}},[_v("Fix account request indexing #12967")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Submitted Issue: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/issues/12968"}},[_v("Release V9.0.0-beta.2 #12968")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12969"}},[_v("Merge master to release #12969")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12971"}},[_v("configure agroal connection pool #12971")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Submitted Issue: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/issues/12976"}},[_v("Release V9.0.0-beta.3 #12976")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12978"}},[_v("Configure connection pool using hikari #12978")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Submitted Issue: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/issues/12979"}},[_v("Release V9.0.0-beta.4 #12979")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12938"}},[_v("Update GetFeedbackSessionLogsAction to use SQL db #12938")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12982"}},[_v("Create Update Account Request Action #12982")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12930"}},[_v("Update liquibase configuration #12930")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12984"}},[_v("Fix Account Request Update Search Indexing #12984")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12780"}},[_v("Migrate AccountRequestsLogicTest #12780")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12992"}},[_v("Remove feedbackSession attributes @fetch annotation #12992")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12998"}},[_v("Remove unused modal in AdminHomePage #12998")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13001"}},[_v("Convert RejectAccountRequestAction to use transactions #13001")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12997"}},[_v("Update DeleteAccountRequest to reference by ID #12997")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12940"}},[_v("Migrate FeedbackNumScaleQuestionE2ETest #12940")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12973"}},[_v("Update front end for session activity logs #12973")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13005"}},[_v("Add v9.0.0 tag to liquibase changelog #13005")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13003"}},[_v("Fix flaky component test #13003")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13007"}},[_v("Get account request by uuid #13007")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13017"}},[_v("Reference account requests by ID in tests #13017")])])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13024"}},[_v("Fix FeedBackResponsesLogic bug #13024")])])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13023"}},[_v("Fix getSessionResultAction bugs #13023")])])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13037"}},[_v("Fix front end bugs #13037")])])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13044"}},[_v("Remove ref by email and institute #13044")])])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13048"}},[_v("Account request form #13048")])])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13052"}},[_v("Migrate committers #13052")])])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13041"}},[_v("Merge student-activity-logs into master #13041")])])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12885"}},[_v("Update backend libraries versions, support Java 21 #12885")])])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13061"}},[_v("Add beta 5 liquibase changelog and developers json #13061")])])]),_v(" "),_c('tr',[_c('td',[_v("Reading")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13068"}},[_v("Use AccountRequestUpdateRequest as parameter #13068")])])])])])])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/cheehongw/info.html b/students/cheehongw/info.html index 8b01d29ac..fba6c8748 100644 --- a/students/cheehongw/info.html +++ b/students/cheehongw/info.html @@ -12,7 +12,7 @@ const baseUrl = '/2024' - + diff --git a/students/cheehongw/info.page-vue-render.js b/students/cheehongw/info.page-vue-render.js index 112bbd82b..ba6c76cde 100644 --- a/students/cheehongw/info.page-vue-render.js +++ b/students/cheehongw/info.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('p',[_c('span',{attrs:{"id":"github"}},[_c('a',{attrs:{"href":"https://www.github.com/cheehongw"}},[_v("https://www.github.com/cheehongw")])])]),_v(" "),_c('p',[_c('span',{attrs:{"id":"projects"}},[_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher"}},[_v("CATcher")])]),_v(" "),_c('span',{attrs:{"id":"projects"}},[_c('a',{attrs:{"href":"https://github.com/source-academy/frontend"}},[_v("SourceAcademy Frontend")])])])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/cheehongw/knowledge.html b/students/cheehongw/knowledge.html index d36b9d765..1c51766e4 100644 --- a/students/cheehongw/knowledge.html +++ b/students/cheehongw/knowledge.html @@ -13,7 +13,7 @@

    CS3282

    This semester, I focused my efforts on trying to upgrade the outdated dependencies in CATcher. This was a challenging task as I had to understand the dependencies of the project. Even though the current state of the repository is not what I have hoped to achieve, I hope future devs reading this might find some insights on how to approach this task.

    Node Package Manager (npm) and Yarn

    From working with CATcher and SourceAcademy, I have gotten a more solid understanding of how package managers work. Before this, I only saw Node and npm as something we had to install before we can start developing our project. However, the fact is that package managers are a crucial aspect of any project, since they manage the dependencies of the project.

    Dependency Management

    In CATcher, I focused on identifying the dependencies that needed to be updated. I learned that dependencies are managed in the package.json file, and that the package-lock.json file is used to lock the dependencies to a specific version. This is important as it ensures that the project is reproducible across different machines. Unfortunately, this is not used in CATcher, but i believe CATcher will benefit from using a lockfile in the future.

    Upgrading Dependencies

    Beyond that, I have learnt how to use npm outdated, npm-check etc to identify outdated dependencies. I also learnt how to use npm ls to print out the dependency tree of a given package. This was useful in identifying the dependencies that needed to be updated.

    Resources

    ESLint migration

    I also assisted with the tslint to eslint migration in CATcher. While initially a PR done by a mentee, I had to stay involved and understand the changes made as well. I had to understand how to configure eslint to work with the project. This was a challenging task, but I am glad that I managed to complete it.

    Resources:

    i18next

    Beyond work done in CATcher, I also worked on SourceAcademy, where I implemented an i18n framework. i18next is a powerful library that allows for easy translation of text in a project. During my implementation of the i18n framework in SourceAcademy, I referenced several implementations of i18n across various established open source repos such as HospitalRun and FreeCodeCamp for any best practices. From these references, I learned how to structure the i18n files and the various translation resources to make it easy for future translators to add on new translations.

    Resources:

    Angular Essentials

    I had contributed to CATcher as part of IWM, but I have never really approached the Angular aspects of the project.

    Essentially, the core ideas behind Angular involves:

    • Components, a TypeScript class with @Component decorator, an HTML template and styles. -
      • 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.
      • 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.
    • An HTML template that instructs Angular how to render the component
    • An optional set of CSS styles that define the appearance of the template's HTML elements

    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 WATcher PR#57.

    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.

    • 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.
    • Also, it seems like most of WATcher and CATcher's services are provided at the root level.

    Finally, as part of fixing "Remove label-filter-bar as module export #92", 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.

    Resources:

    E2E Testing with Playwright

    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.

    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.

    Mocking services

    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.

    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.

    Aspects Learnt

    • Configuring and setting up Playwright for a project.
    • Learned about how Playwright/Cypress/Protractor identifies and interacts with HTML elements using selectors.
    • Learned about how CATcher API calls are mocked during E2E testing

    Resources:

    Github Actions

    I also picked up Github Actions when contributing to the CI/CD pipeline in Enable linting in Github workflow #81. I learned how Github Actions are set up and how they can be triggered upon pushing to main/master and also on pull requests.

    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.

    Resources:

    RxJS and the Observer Pattern

    Part of working with CATcher source code was frequently encountering Observables and Observers. RxJS supports Observers and Observables, allowing updates to some Observable to be received by some Observer that is subscribed to it. With this pattern, we can trigger updates in many dependent objects automatically and asynchronously when some object state changes.

    Resources:

    +
    • 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.
    • 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.
  • An HTML template that instructs Angular how to render the component
  • An optional set of CSS styles that define the appearance of the template's HTML elements
  • 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 WATcher PR#57.

    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.

    • 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.
    • Also, it seems like most of WATcher and CATcher's services are provided at the root level.

    Finally, as part of fixing "Remove label-filter-bar as module export #92", 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.

    Resources:

    E2E Testing with Playwright

    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.

    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.

    Mocking services

    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.

    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.

    Aspects Learnt

    • Configuring and setting up Playwright for a project.
    • Learned about how Playwright/Cypress/Protractor identifies and interacts with HTML elements using selectors.
    • Learned about how CATcher API calls are mocked during E2E testing

    Resources:

    Github Actions

    I also picked up Github Actions when contributing to the CI/CD pipeline in Enable linting in Github workflow #81. I learned how Github Actions are set up and how they can be triggered upon pushing to main/master and also on pull requests.

    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.

    Resources:

    RxJS and the Observer Pattern

    Part of working with CATcher source code was frequently encountering Observables and Observers. RxJS supports Observers and Observables, allowing updates to some Observable to be received by some Observer that is subscribed to it. With this pattern, we can trigger updates in many dependent objects automatically and asynchronously when some object state changes.

    Resources:

    diff --git a/students/cheehongw/knowledge.page-vue-render.js b/students/cheehongw/knowledge.page-vue-render.js index 062e339d3..3d48d88e7 100644 --- a/students/cheehongw/knowledge.page-vue-render.js +++ b/students/cheehongw/knowledge.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('h1',{attrs:{"id":"cs3282"}},[_v("CS3282"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#cs3282","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("This semester, I focused my efforts on trying to upgrade the outdated dependencies in CATcher. This was a challenging task as I had to understand the dependencies of the project. Even though the current state of the repository is not what I have hoped to achieve, I hope future devs reading this might find some insights on how to approach this task.")]),_v(" "),_c('h3',{attrs:{"id":"node-package-manager-npm-and-yarn"}},[_v("Node Package Manager (npm) and Yarn"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#node-package-manager-npm-and-yarn","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("From working with CATcher and SourceAcademy, I have gotten a more solid understanding of how package managers work. Before this, I only saw Node and npm as something we had to install before we can start developing our project. However, the fact is that package managers are a crucial aspect of any project, since they manage the dependencies of the project.")]),_v(" "),_c('h3',{attrs:{"id":"dependency-management"}},[_v("Dependency Management"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#dependency-management","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("In CATcher, I focused on identifying the dependencies that needed to be updated. I learned that dependencies are managed in the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("package.json")]),_v(" file, and that the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("package-lock.json")]),_v(" file is used to lock the dependencies to a specific version. This is important as it ensures that the project is reproducible across different machines. Unfortunately, this is not used in CATcher, but i believe CATcher will benefit from using a lockfile in the future.")]),_v(" "),_c('h3',{attrs:{"id":"upgrading-dependencies"}},[_v("Upgrading Dependencies"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#upgrading-dependencies","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Beyond that, I have learnt how to use "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("npm outdated")]),_v(", "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("npm-check")]),_v(" etc to identify outdated dependencies. I also learnt how to use "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("npm ls")]),_v(" to print out the dependency tree of a given package. This was useful in identifying the dependencies that needed to be updated.")]),_v(" "),_c('p',[_v("Resources")]),_v(" "),_c('ul',[_c('li',[_c('a',{attrs:{"href":"https://docs.npmjs.com/cli/v6/commands/npm-outdated"}},[_v("https://docs.npmjs.com/cli/v6/commands/npm-outdated")])]),_v(" "),_c('li',[_c('a',{attrs:{"href":"https://www.npmjs.com/package/npm-check"}},[_v("https://www.npmjs.com/package/npm-check")])]),_v(" "),_c('li',[_c('a',{attrs:{"href":"https://docs.npmjs.com/cli/v6/commands/npm-ls"}},[_v("https://docs.npmjs.com/cli/v6/commands/npm-ls")])]),_v(" "),_c('li')]),_v(" "),_c('h3',{attrs:{"id":"eslint-migration"}},[_v("ESLint migration"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#eslint-migration","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("I also assisted with the tslint to eslint migration in CATcher. While initially a PR done by a mentee, I had to stay involved and understand the changes made as well. I had to understand how to configure eslint to work with the project. This was a challenging task, but I am glad that I managed to complete it.")]),_v(" "),_c('p',[_v("Resources:")]),_v(" "),_c('ul',[_c('li',[_c('a',{attrs:{"href":"https://eslint.org/docs/user-guide/configuring"}},[_v("https://eslint.org/docs/user-guide/configuring")])]),_v(" "),_c('li',[_c('a',{attrs:{"href":"https://github.com/angular-eslint/angular-eslint/blob/main/docs/MIGRATING_FROM_TSLINT.md"}},[_v("https://github.com/angular-eslint/angular-eslint/blob/main/docs/MIGRATING_FROM_TSLINT.md")])])]),_v(" "),_c('h3',{attrs:{"id":"i18next"}},[_v("i18next"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#i18next","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Beyond work done in CATcher, I also worked on SourceAcademy, where I implemented an i18n framework. i18next is a powerful library that allows for easy translation of text in a project. During my implementation of the i18n framework in SourceAcademy, I referenced several implementations of i18n across various established open source repos such as HospitalRun and FreeCodeCamp for any best practices. From these references, I learned how to structure the i18n files and the various translation resources to make it easy for future translators to add on new translations.")]),_v(" "),_c('p',[_v("Resources:")]),_v(" "),_c('ul',[_c('li',[_c('a',{attrs:{"href":"https://www.i18next.com/"}},[_v("https://www.i18next.com/")])]),_v(" "),_c('li',[_c('a',{attrs:{"href":"https://react.i18next.com/"}},[_v("https://react.i18next.com/")])])]),_v(" "),_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/")])])])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/cheehongw/observations.html b/students/cheehongw/observations.html index dabe78792..36d9f0580 100644 --- a/students/cheehongw/observations.html +++ b/students/cheehongw/observations.html @@ -12,7 +12,7 @@ const baseUrl = '/2024' -

    Project: SourceAcademy Frontend

    Sourceacademy is the an online experiential environment used for teaching students computational thinking and is used by the School of Computing in NUS and Uppsala University in Sweden to teach introductory programming modules. The frontend is built using React and Redux.

    My Contributions

    In this project, I have authored and merged two PRs. They are listed as follows:

    • Fix double window prompt when uploading users #2943

      In this PR, I fixed a long standing bug regarding the UI where two file prompts show up upon clicking a "upload csv" button. To solve this, I first reproduced the issue on my local development environment, and then identified the issue, which happened to be the incorrect use of a <FileInput> react component within a <CSVReader> component. The components were imported from a theming library and a CSV parser library respectively.

    • i18n framework #2946

      In this PR, I laid the groundwork for future internationalization work to be done on SourceAcademy. SourceAcademy started out as a project in NUS but has plans to go international, as seen by its use in Uppsala university in Sweden. As such, adding i18n to the project will be crucial for its future.

      In this PR, I introduced the use of react-i18next library, as well as define data structures to allow future translators to easily add on new translations and languages.

    My Learning Record

    React & Redux

    Sourceacademy is built in React and Redux, and as such, I have had to learn how to work with these two libraries. While I have used React and Redux before, I have not seen how it can be used in a large scale project like Sourceacademy. In Sourceacademy, I have seen how Redux and Redux Toolkit was used to create a typesafe global state that is shared across the entire application and I appreciate how well structured the code was in the repository.

    i18next

    i18next is a library that allows for internationalization in a React project. It is a powerful library that allows for easy translation of text in a project. During my implementation of the i18n framework in Sourceacademy, I referenced several implementations of i18n across various established open source repos such as HospitalRun and FreeCodeCamp for any best practices. From these references, I learned how to structure the i18n files and the various translation resources to make it easy for future translators to add on new translations.

    Furthermore, the i18n framework that I contributed to has strong type safety and only allows keys that are defined in the translation files to be used, making it easier for future developers to see what keys are allowed on what file. I am grateful for the Sourceacademy maintainers for their guidance in this implementation.

    Practices and tools from SourceAcademy that could be adopted by CATcher

    SourceAcademy utilises Yarn as their package manager. From almost all points of view, yarn has the exact same functionality as npm, but it is faster and more reliable. As such, we could consider moving over to using Yarn in CATcher as well.

    Furthermore, I was particularly impressed with the testing framework that they had to ensure any new changes were not breaking. They made use of jest and had an interactive UI test runner that allowed the developer to see which tests were failing and why. This is something that CATcher could consider adopting as well.

    +

    Project: SourceAcademy Frontend

    Sourceacademy is the an online experiential environment used for teaching students computational thinking and is used by the School of Computing in NUS and Uppsala University in Sweden to teach introductory programming modules. The frontend is built using React and Redux.

    My Contributions

    In this project, I have authored and merged two PRs. They are listed as follows:

    • Fix double window prompt when uploading users #2943

      In this PR, I fixed a long standing bug regarding the UI where two file prompts show up upon clicking a "upload csv" button. To solve this, I first reproduced the issue on my local development environment, and then identified the issue, which happened to be the incorrect use of a <FileInput> react component within a <CSVReader> component. The components were imported from a theming library and a CSV parser library respectively.

    • i18n framework #2946

      In this PR, I laid the groundwork for future internationalization work to be done on SourceAcademy. SourceAcademy started out as a project in NUS but has plans to go international, as seen by its use in Uppsala university in Sweden. As such, adding i18n to the project will be crucial for its future.

      In this PR, I introduced the use of react-i18next library, as well as define data structures to allow future translators to easily add on new translations and languages.

    My Learning Record

    React & Redux

    Sourceacademy is built in React and Redux, and as such, I have had to learn how to work with these two libraries. While I have used React and Redux before, I have not seen how it can be used in a large scale project like Sourceacademy. In Sourceacademy, I have seen how Redux and Redux Toolkit was used to create a typesafe global state that is shared across the entire application and I appreciate how well structured the code was in the repository.

    i18next

    i18next is a library that allows for internationalization in a React project. It is a powerful library that allows for easy translation of text in a project. During my implementation of the i18n framework in Sourceacademy, I referenced several implementations of i18n across various established open source repos such as HospitalRun and FreeCodeCamp for any best practices. From these references, I learned how to structure the i18n files and the various translation resources to make it easy for future translators to add on new translations.

    Furthermore, the i18n framework that I contributed to has strong type safety and only allows keys that are defined in the translation files to be used, making it easier for future developers to see what keys are allowed on what file. I am grateful for the Sourceacademy maintainers for their guidance in this implementation.

    Practices and tools from SourceAcademy that could be adopted by CATcher

    SourceAcademy utilises Yarn as their package manager. From almost all points of view, yarn has the exact same functionality as npm, but it is faster and more reliable. As such, we could consider moving over to using Yarn in CATcher as well.

    Furthermore, I was particularly impressed with the testing framework that they had to ensure any new changes were not breaking. They made use of jest and had an interactive UI test runner that allowed the developer to see which tests were failing and why. This is something that CATcher could consider adopting as well.

    diff --git a/students/cheehongw/observations.page-vue-render.js b/students/cheehongw/observations.page-vue-render.js index 017f307f5..d52da3e15 100644 --- a/students/cheehongw/observations.page-vue-render.js +++ b/students/cheehongw/observations.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('h3',{attrs:{"id":"project-sourceacademy-frontend"}},[_v("Project: SourceAcademy Frontend"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#project-sourceacademy-frontend","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Sourceacademy is the an online experiential environment used for teaching students computational thinking and is used by the School of Computing in NUS and Uppsala University in Sweden to teach introductory programming modules. The frontend is built using React and Redux.")]),_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("In this project, I have authored and merged two PRs. They are listed as follows:")]),_v(" "),_c('ul',[_c('li',[_c('p',[_c('a',{attrs:{"href":"https://github.com/source-academy/frontend/pull/2943"}},[_v("Fix double window prompt when uploading users #2943")])]),_v(" "),_c('p',[_v("In this PR, I fixed a long standing bug regarding the UI where two file prompts show up upon clicking a \"upload csv\" button. To solve this, I first reproduced the issue on my local development environment, and then identified the issue, which happened to be the incorrect use of a "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("")]),_v(" react component within a "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("")]),_v(" component. The components were imported from a "),_c('a',{attrs:{"href":"https://blueprintjs.com/"}},[_v("theming library")]),_v(" and a "),_c('a',{attrs:{"href":"https://www.papaparse.com/"}},[_v("CSV parser library")]),_v(" respectively.")])]),_v(" "),_c('li',[_c('p',[_c('a',{attrs:{"href":"https://github.com/source-academy/frontend/pull/2946"}},[_v("i18n framework #2946")])]),_v(" "),_c('p',[_v("In this PR, I laid the groundwork for future internationalization work to be done on SourceAcademy. SourceAcademy started out as a project in NUS but has plans to go international, as seen by its use in Uppsala university in Sweden. As such, adding i18n to the project will be crucial for its future.")]),_v(" "),_c('p',[_v("In this PR, I introduced the use of "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("react-i18next")]),_v(" library, as well as define data structures to allow future translators to easily add on new translations and languages.")])])]),_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',[_c('strong',[_v("React & Redux")])]),_v(" "),_c('p',[_v("Sourceacademy is built in React and Redux, and as such, I have had to learn how to work with these two libraries. While I have used React and Redux before, I have not seen how it can be used in a large scale project like Sourceacademy. In Sourceacademy, I have seen how Redux and Redux Toolkit was used to create a typesafe global state that is shared across the entire application and I appreciate how well structured the code was in the repository.")]),_v(" "),_c('p',[_c('strong',[_v("i18next")])]),_v(" "),_c('p',[_v("i18next is a library that allows for internationalization in a React project. It is a powerful library that allows for easy translation of text in a project. During my implementation of the i18n framework in Sourceacademy, I referenced several implementations of i18n across various established open source repos such as HospitalRun and FreeCodeCamp for any best practices. From these references, I learned how to structure the i18n files and the various translation resources to make it easy for future translators to add on new translations.")]),_v(" "),_c('p',[_v("Furthermore, the i18n framework that I contributed to has strong type safety and only allows keys that are defined in the translation files to be used, making it easier for future developers to see what keys are allowed on what file. I am grateful for the Sourceacademy maintainers for their guidance in this implementation.")]),_v(" "),_c('p',[_c('strong',[_v("Practices and tools from SourceAcademy that could be adopted by CATcher")])]),_v(" "),_c('p',[_v("SourceAcademy utilises Yarn as their package manager. From almost all points of view, yarn has the exact same functionality as npm, but it is faster and more reliable. As such, we could consider moving over to using Yarn in CATcher as well.")]),_v(" "),_c('p',[_v("Furthermore, I was particularly impressed with the testing framework that they had to ensure any new changes were not breaking. They made use of jest and had an interactive UI test runner that allowed the developer to see which tests were failing and why. This is something that CATcher could consider adopting as well.")])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/cheehongw/progress.html b/students/cheehongw/progress.html index 89e0c4052..f6745c1b6 100644 --- a/students/cheehongw/progress.html +++ b/students/cheehongw/progress.html @@ -12,7 +12,7 @@ const baseUrl = '/2024' -

    CS3282 Progress

    Summary

    • Reviewed PRs of CS3281 students and external contributors in CATcher and WATcher
    • In-person guidance with CS3281 mentees over telegram
    • Maintained and upgraded libraries in CATcher
    • Created two PRs in external project - SourceAcademy

    Before-semester contributions

    CATcher

    Date Role Description Key Achievements
    13 Jun 2023 Mentor Question: @angular/common version to use #1191 Provided guidance on how to resolve the issue
    12 Jun 2023 PR author Fix peer dependencies #1193
    19 Jul 2023 Issue Reporter Documentation for CATcher's parser #1204 Created issue to discuss documentation for CATcher's parser
    19 Sep 2023 PR author Upgrade to Angular 11 #1203

    WATcher

    Date Role Description Key Achievements
    29 Jun 2023 PR Reviewer Detail page detail list #131
    29 Jun 2023 PR Reviewer Add wrap for username in issues-viewer's card-view #147
    29 Jun 2023 PR Reviewer Disable milestone filter if there are no milestones #149
    29 Jun - 18 Jul PR Reviewer Add reset labels feature #150 Mentored PR author to improve code quality and readability
    30 Jun 2023 PR Reviewer Show loading spinner on switch repository #151
    28 Oct 2023 PR Reviewer Option to Limit Repository Access #215

    CATcher

    Date Role Description Key Achievements
    Week 2 PR Reviewer Uncaught error when invalid link is clicked #1239
    Week 4 PR Reviewer Default branch to main #1234
    Week 4 PR Author Angular 12 #1242
    Week 5 PR Reviewer Faulty list view when back navigating #1243
    Week 6 PR Reviewer Fix markdown blockquote preview difference #1245
    Week 6 Issue Reporter Migrate to ESLint #1247
    Week 7 PR Reviewer Assisted in the creation of new CATcher release
    Week 7 - 8 Issue Reporter & PR Author Address neglected depenedencies in CATcher
    Week 11 PR Reviewer Add documentation for CATcher's parser #1240
    Week 13 PR Reviewer Add login redirect #1256
    Reading Week PR Reviewer & Co-author Migrate from TSLint to ESLint #1250 Had to step in to complete the PR
    Reading Week PR Author Upgrade to Angular 13 #1249
    Reading Week PR Author Fix e2e regression caused by changes in AuthService #1275

    WATcher

    Date Role Description Key Achievements
    Week 4 PR Reviewer Show list of hidden users #235
    Week 4 PR Reviewer Build in Github Actions #239
    Week 5 PR Reviewer Remove unused session-fix-confirmation component #250
    Week 5 PR Reviewer Remove unused models #253
    Week 6 PR Reviewer Upgrade to Angular 11 #252
    Recess PR Reviewer Fix zone testing import error #269

    External Project - SourceAcademy

    Date Role Description Key Achievements
    Week 13 PR Author Fix double window prompt when uploading users #2943 Fixed a bug
    Week 13 PR Author i18n framework #2946 Laid the groundwork for internationalization in source academy
    +

    CS3282 Progress

    Summary

    • Reviewed PRs of CS3281 students and external contributors in CATcher and WATcher
    • In-person guidance with CS3281 mentees over telegram
    • Maintained and upgraded libraries in CATcher
    • Created two PRs in external project - SourceAcademy

    Before-semester contributions

    CATcher

    Date Role Description Key Achievements
    13 Jun 2023 Mentor Question: @angular/common version to use #1191 Provided guidance on how to resolve the issue
    12 Jun 2023 PR author Fix peer dependencies #1193
    19 Jul 2023 Issue Reporter Documentation for CATcher's parser #1204 Created issue to discuss documentation for CATcher's parser
    19 Sep 2023 PR author Upgrade to Angular 11 #1203

    WATcher

    Date Role Description Key Achievements
    29 Jun 2023 PR Reviewer Detail page detail list #131
    29 Jun 2023 PR Reviewer Add wrap for username in issues-viewer's card-view #147
    29 Jun 2023 PR Reviewer Disable milestone filter if there are no milestones #149
    29 Jun - 18 Jul PR Reviewer Add reset labels feature #150 Mentored PR author to improve code quality and readability
    30 Jun 2023 PR Reviewer Show loading spinner on switch repository #151
    28 Oct 2023 PR Reviewer Option to Limit Repository Access #215

    CATcher

    Date Role Description Key Achievements
    Week 2 PR Reviewer Uncaught error when invalid link is clicked #1239
    Week 4 PR Reviewer Default branch to main #1234
    Week 4 PR Author Angular 12 #1242
    Week 5 PR Reviewer Faulty list view when back navigating #1243
    Week 6 PR Reviewer Fix markdown blockquote preview difference #1245
    Week 6 Issue Reporter Migrate to ESLint #1247
    Week 7 PR Reviewer Assisted in the creation of new CATcher release
    Week 7 - 8 Issue Reporter & PR Author Address neglected depenedencies in CATcher
    Week 11 PR Reviewer Add documentation for CATcher's parser #1240
    Week 13 PR Reviewer Add login redirect #1256
    Reading Week PR Reviewer & Co-author Migrate from TSLint to ESLint #1250 Had to step in to complete the PR
    Reading Week PR Author Upgrade to Angular 13 #1249
    Reading Week PR Author Fix e2e regression caused by changes in AuthService #1275

    WATcher

    Date Role Description Key Achievements
    Week 4 PR Reviewer Show list of hidden users #235
    Week 4 PR Reviewer Build in Github Actions #239
    Week 5 PR Reviewer Remove unused session-fix-confirmation component #250
    Week 5 PR Reviewer Remove unused models #253
    Week 6 PR Reviewer Upgrade to Angular 11 #252
    Recess PR Reviewer Fix zone testing import error #269

    External Project - SourceAcademy

    Date Role Description Key Achievements
    Week 13 PR Author Fix double window prompt when uploading users #2943 Fixed a bug
    Week 13 PR Author i18n framework #2946 Laid the groundwork for internationalization in source academy
    diff --git a/students/cheehongw/progress.page-vue-render.js b/students/cheehongw/progress.page-vue-render.js index f5c6f53e1..6c28eda11 100644 --- a/students/cheehongw/progress.page-vue-render.js +++ b/students/cheehongw/progress.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('h1',{attrs:{"id":"cs3282-progress"}},[_v("CS3282 Progress"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#cs3282-progress","onclick":"event.stopPropagation()"}})]),_v(" "),_c('h2',{attrs:{"id":"summary"}},[_v("Summary"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#summary","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ul',[_c('li',[_v("Reviewed PRs of CS3281 students and external contributors in CATcher and WATcher")]),_v(" "),_c('li',[_v("In-person guidance with CS3281 mentees over telegram")]),_v(" "),_c('li',[_v("Maintained and upgraded libraries in CATcher")]),_v(" "),_c('li',[_v("Created two PRs in external project - SourceAcademy")])]),_v(" "),_c('h2',{attrs:{"id":"before-semester-contributions"}},[_v("Before-semester contributions"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#before-semester-contributions","onclick":"event.stopPropagation()"}})]),_v(" "),_c('h3',{attrs:{"id":"catcher"}},[_v("CATcher"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#catcher","onclick":"event.stopPropagation()"}})]),_v(" "),_c('div',{staticClass:"table-responsive"},[_c('table',{staticClass:"markbind-table table table-bordered table-striped"},[_c('thead',[_c('tr',[_c('th',[_v("Date")]),_v(" "),_c('th',[_v("Role")]),_v(" "),_c('th',[_v("Description")]),_v(" "),_c('th',[_v("Key Achievements")])])]),_v(" "),_c('tbody',[_c('tr',[_c('td',[_v("13 Jun 2023")]),_v(" "),_c('td',[_v("Mentor")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher/issues/1191"}},[_v("Question: @angular/common version to use #1191")])]),_v(" "),_c('td',[_v("Provided guidance on how to resolve the issue")])]),_v(" "),_c('tr',[_c('td',[_v("12 Jun 2023")]),_v(" "),_c('td',[_v("PR author")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher/pull/1193"}},[_v("Fix peer dependencies #1193")])]),_v(" "),_c('td')]),_v(" "),_c('tr',[_c('td',[_v("19 Jul 2023")]),_v(" "),_c('td',[_v("Issue Reporter")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher/issues/1204"}},[_v("Documentation for CATcher's parser #1204")])]),_v(" "),_c('td',[_v("Created issue to discuss documentation for CATcher's parser")])]),_v(" "),_c('tr',[_c('td',[_v("19 Sep 2023")]),_v(" "),_c('td',[_v("PR author")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher/pull/1203"}},[_v("Upgrade to Angular 11 #1203")])]),_v(" "),_c('td')])])])]),_c('h3',{attrs:{"id":"watcher"}},[_v("WATcher"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#watcher","onclick":"event.stopPropagation()"}})]),_v(" "),_c('div',{staticClass:"table-responsive"},[_c('table',{staticClass:"markbind-table table table-bordered table-striped"},[_c('thead',[_c('tr',[_c('th',[_v("Date")]),_v(" "),_c('th',[_v("Role")]),_v(" "),_c('th',[_v("Description")]),_v(" "),_c('th',[_v("Key Achievements")])])]),_v(" "),_c('tbody',[_c('tr',[_c('td',[_v("29 Jun 2023")]),_v(" "),_c('td',[_v("PR Reviewer")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/131"}},[_v("Detail page detail list #131")])]),_v(" "),_c('td')]),_v(" "),_c('tr',[_c('td',[_v("29 Jun 2023")]),_v(" "),_c('td',[_v("PR Reviewer")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/147"}},[_v("Add wrap for username in issues-viewer's card-view #147")])]),_v(" "),_c('td')]),_v(" "),_c('tr',[_c('td',[_v("29 Jun 2023")]),_v(" "),_c('td',[_v("PR Reviewer")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/149"}},[_v("Disable milestone filter if there are no milestones #149")])]),_v(" "),_c('td')]),_v(" "),_c('tr',[_c('td',[_v("29 Jun - 18 Jul")]),_v(" "),_c('td',[_v("PR Reviewer")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/150"}},[_v("Add reset labels feature #150")])]),_v(" "),_c('td',[_v("Mentored PR author to improve code quality and readability")])]),_v(" "),_c('tr',[_c('td',[_v("30 Jun 2023")]),_v(" "),_c('td',[_v("PR Reviewer")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/151"}},[_v("Show loading spinner on switch repository #151")])]),_v(" "),_c('td')]),_v(" "),_c('tr',[_c('td',[_v("28 Oct 2023")]),_v(" "),_c('td',[_v("PR Reviewer")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/215"}},[_v("Option to Limit Repository Access #215")])]),_v(" "),_c('td')])])])]),_c('h3',{attrs:{"id":"catcher-2"}},[_v("CATcher"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#catcher-2","onclick":"event.stopPropagation()"}})]),_v(" "),_c('div',{staticClass:"table-responsive"},[_c('table',{staticClass:"markbind-table table table-bordered table-striped"},[_c('thead',[_c('tr',[_c('th',[_v("Date")]),_v(" "),_c('th',[_v("Role")]),_v(" "),_c('th',[_v("Description")]),_v(" "),_c('th',[_v("Key Achievements")])])]),_v(" "),_c('tbody',[_c('tr',[_c('td',[_v("Week 2")]),_v(" "),_c('td',[_v("PR Reviewer")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher/pull/1239"}},[_v("Uncaught error when invalid link is clicked #1239")])]),_v(" "),_c('td')]),_v(" "),_c('tr',[_c('td',[_v("Week 4")]),_v(" "),_c('td',[_v("PR Reviewer")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher/pull/1234"}},[_v("Default branch to main #1234")])]),_v(" "),_c('td')]),_v(" "),_c('tr',[_c('td',[_v("Week 4")]),_v(" "),_c('td',[_v("PR Author")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher/pull/1242"}},[_v("Angular 12 #1242")])]),_v(" "),_c('td')]),_v(" "),_c('tr',[_c('td',[_v("Week 5")]),_v(" "),_c('td',[_v("PR Reviewer")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher/pull/1243"}},[_v("Faulty list view when back navigating #1243")])]),_v(" "),_c('td')]),_v(" "),_c('tr',[_c('td',[_v("Week 6")]),_v(" "),_c('td',[_v("PR Reviewer")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher/pull/1245"}},[_v("Fix markdown blockquote preview difference #1245")])]),_v(" "),_c('td')]),_v(" "),_c('tr',[_c('td',[_v("Week 6")]),_v(" "),_c('td',[_v("Issue Reporter")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher/issues/1247"}},[_v("Migrate to ESLint #1247")])]),_v(" "),_c('td')]),_v(" "),_c('tr',[_c('td',[_v("Week 7")]),_v(" "),_c('td',[_v("PR Reviewer")]),_v(" "),_c('td',[_c('ul',[_c('li',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher/pull/1252"}},[_v("Create release 3.5.3 #1252")])]),_c('li',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher/pull/1254"}},[_v("New release for 3.5.3 #1254")])])])]),_v(" "),_c('td',[_v("Assisted in the creation of new CATcher release")])]),_v(" "),_c('tr',[_c('td',[_v("Week 7 - 8")]),_v(" "),_c('td',[_v("Issue Reporter & PR Author")]),_v(" "),_c('td',[_c('ul',[_c('li',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher/pull/1248"}},[_v("Clean up dependencies #1248")])]),_c('li',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher/issues/1244"}},[_v("Remove wait-on from devDep #1244")])]),_c('li',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher/issues/1246"}},[_v("tslib unused #1246")])]),_c('li',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher/issues/1253"}},[_v("Remove node-fetch as direct dependency #1253")])])])]),_v(" "),_c('td',[_v("Address neglected depenedencies in CATcher")])]),_v(" "),_c('tr',[_c('td',[_v("Week 11")]),_v(" "),_c('td',[_v("PR Reviewer")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher/pull/1240"}},[_v("Add documentation for CATcher's parser #1240")])]),_v(" "),_c('td')]),_v(" "),_c('tr',[_c('td',[_v("Week 13")]),_v(" "),_c('td',[_v("PR Reviewer")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher/pull/1256"}},[_v("Add login redirect #1256")])]),_v(" "),_c('td')]),_v(" "),_c('tr',[_c('td',[_v("Reading Week")]),_v(" "),_c('td',[_v("PR Reviewer & Co-author")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher/pull/1250"}},[_v("Migrate from TSLint to ESLint #1250")])]),_v(" "),_c('td',[_v("Had to step in to complete the PR")])]),_v(" "),_c('tr',[_c('td',[_v("Reading Week")]),_v(" "),_c('td',[_v("PR Author")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher/pull/1249"}},[_v("Upgrade to Angular 13 #1249")])]),_v(" "),_c('td')]),_v(" "),_c('tr',[_c('td',[_v("Reading Week")]),_v(" "),_c('td',[_v("PR Author")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher/pull/1275"}},[_v("Fix e2e regression caused by changes in AuthService #1275")])]),_v(" "),_c('td')])])])]),_c('h3',{attrs:{"id":"watcher-2"}},[_v("WATcher"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#watcher-2","onclick":"event.stopPropagation()"}})]),_v(" "),_c('div',{staticClass:"table-responsive"},[_c('table',{staticClass:"markbind-table table table-bordered table-striped"},[_c('thead',[_c('tr',[_c('th',[_v("Date")]),_v(" "),_c('th',[_v("Role")]),_v(" "),_c('th',[_v("Description")]),_v(" "),_c('th',[_v("Key Achievements")])])]),_v(" "),_c('tbody',[_c('tr',[_c('td',[_v("Week 4")]),_v(" "),_c('td',[_v("PR Reviewer")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/235"}},[_v("Show list of hidden users #235")])]),_v(" "),_c('td')]),_v(" "),_c('tr',[_c('td',[_v("Week 4")]),_v(" "),_c('td',[_v("PR Reviewer")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/239"}},[_v("Build in Github Actions #239")])]),_v(" "),_c('td')]),_v(" "),_c('tr',[_c('td',[_v("Week 5")]),_v(" "),_c('td',[_v("PR Reviewer")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/250"}},[_v("Remove unused session-fix-confirmation component #250")])]),_v(" "),_c('td')]),_v(" "),_c('tr',[_c('td',[_v("Week 5")]),_v(" "),_c('td',[_v("PR Reviewer")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/253"}},[_v("Remove unused models #253")])]),_v(" "),_c('td')]),_v(" "),_c('tr',[_c('td',[_v("Week 6")]),_v(" "),_c('td',[_v("PR Reviewer")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/252"}},[_v("Upgrade to Angular 11 #252")])]),_v(" "),_c('td')]),_v(" "),_c('tr',[_c('td',[_v("Recess")]),_v(" "),_c('td',[_v("PR Reviewer")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/269"}},[_v("Fix zone testing import error #269")])]),_v(" "),_c('td')])])])]),_c('h3',{attrs:{"id":"external-project-sourceacademy"}},[_v("External Project - SourceAcademy"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#external-project-sourceacademy","onclick":"event.stopPropagation()"}})]),_v(" "),_c('div',{staticClass:"table-responsive"},[_c('table',{staticClass:"markbind-table table table-bordered table-striped"},[_c('thead',[_c('tr',[_c('th',[_v("Date")]),_v(" "),_c('th',[_v("Role")]),_v(" "),_c('th',[_v("Description")]),_v(" "),_c('th',[_v("Key Achievements")])])]),_v(" "),_c('tbody',[_c('tr',[_c('td',[_v("Week 13")]),_v(" "),_c('td',[_v("PR Author")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/source-academy/frontend/pull/2943"}},[_v("Fix double window prompt when uploading users #2943")])]),_v(" "),_c('td',[_v("Fixed a bug")])]),_v(" "),_c('tr',[_c('td',[_v("Week 13")]),_v(" "),_c('td',[_v("PR Author")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/source-academy/frontend/pull/2946"}},[_v("i18n framework #2946")])]),_v(" "),_c('td',[_v("Laid the groundwork for internationalization in source academy")])])])])])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/ckcherry23/info.html b/students/ckcherry23/info.html index 77d9bde3d..c0f4767c4 100644 --- a/students/ckcherry23/info.html +++ b/students/ckcherry23/info.html @@ -13,7 +13,7 @@ +date-fns

    diff --git a/students/ckcherry23/info.page-vue-render.js b/students/ckcherry23/info.page-vue-render.js index d681e78c1..3f0c72b79 100644 --- a/students/ckcherry23/info.page-vue-render.js +++ b/students/ckcherry23/info.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('p',[_c('span',{attrs:{"id":"github"}},[_c('a',{attrs:{"href":"https://www.github.com/ckcherry23"}},[_v("https://www.github.com/ckcherry23")])])]),_v(" "),_c('p',[_c('span',{attrs:{"id":"projects"}},[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense"}},[_v("RepoSense")]),_v(",\n"),_c('a',{attrs:{"href":"https://github.com/date-fns/date-fns"}},[_v("date-fns")])])])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/ckcherry23/knowledge.html b/students/ckcherry23/knowledge.html index 2c3dcfe0d..9a571319a 100644 --- a/students/ckcherry23/knowledge.html +++ b/students/ckcherry23/knowledge.html @@ -116,7 +116,7 @@ breaking down the PRs into smaller ones would make the review process easier. Based on this feedback, I have made a conscious effort to create smaller PRs going forward.

    3.1.4 Understanding Versioning

    Contributing to RepoSense has provided me with insights into versioning and how it is maintained for open-source projects. The process of maintaining separate web pages for documentation of released versions and the master version has been an -important lesson. To deepen my understanding of project management, I am planning on making a release myself in the near future.

    +important lesson. To deepen my understanding of project management, I am planning on making a release myself in the near future.

    diff --git a/students/ckcherry23/knowledge.page-vue-render.js b/students/ckcherry23/knowledge.page-vue-render.js index c0fc74a47..1fd3fcc58 100644 --- a/students/ckcherry23/knowledge.page-vue-render.js +++ b/students/ckcherry23/knowledge.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('h2',{attrs:{"id":"cs3282"}},[_v("CS3282"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#cs3282","onclick":"event.stopPropagation()"}})]),_v(" "),_c('h3',{attrs:{"id":"1-expertise-area-frontend-engineering"}},[_v("1. Expertise Area: Frontend Engineering"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#1-expertise-area-frontend-engineering","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("In CS3282, I've chosen frontend engineering as my \"expertise\" area. Given its breadth, I narrowed my focus to the most popular frontend technology stack today: Next.js, TypeScript, React, and Tailwind CSS. The majority of my recent projects, as listed in "),_c('a',{attrs:{"href":"https://ckcherry23.github.io/archive/"}},[_v("my project archive")]),_v(", have been built using these technologies. As a UI/UX enthusiast, I am also interested in the usability and accessibility aspects of frontend development.")]),_v(" "),_c('h4',{attrs:{"id":"1-1-open-source-contributions"}},[_v("1.1 Open Source Contributions"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#1-1-open-source-contributions","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("My involvement as a RepoSense mentor primarily centers around the frontend in Vue.js, TypeScript and Cypress.")]),_v(" "),_c('p',[_v("Additionally, I've chosen to contribute to an external project that uses TypeScript and React: "),_c('a',{attrs:{"href":"https://date-fns.org/"}},[_v("date-fns")]),_v(". Having utilized date-fns in my own projects extensively, I've found it to be an efficient solution for handling dates in JavaScript. I've detailed my insights from contributing to date-fns "),_c('a',{attrs:{"href":"/2024/students/ckcherry23/observations.html"}},[_v("here")]),_v(".")]),_v(" "),_c('h4',{attrs:{"id":"1-2-lightning-talks"}},[_v("1.2 Lightning Talks"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#1-2-lightning-talks","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("I have been using Tailwind CSS for a while now, and I find it to be a very efficient way to style web applications. In fact, one of my projects, "),_c('a',{attrs:{"href":"https://www.artisan.land/"}},[_v("artisan.land")]),_v(", depends on the atomic classes of Tailwind to "),_c('a',{attrs:{"href":"https://www.artisan.land/components"}},[_v("dynamically style components")]),_v(" with user-selected options and generate React code for them. Such a project would not have been possible without the utility-first nature of Tailwind CSS. I also delivered one of my lightning talks on "),_c('a',{attrs:{"href":"https://tailwindcss.com/"}},[_v("Tailwind CSS")]),_v(", to evangelize it to the class.")]),_v(" "),_c('p',[_v("Driven by my interest in frontend technologies, I took up the role of Frontend Lead in Developer Student Club. This experience provided valuable insights into frontend development best practices while allowing me to mentor junior developers. Additionally, I implemented quality-of-life enhancements such as setting up ESLint and Husky pre-commit hooks, and refining the CI/CD pipeline. Subsequently, I delivered a lightning talk on improving DevEx, which would benefit NUS-OSS mentors as well. In fact, we've begun slowly integrating these practices into RepoSense, adopting tools like "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2178"}},[_v("Vite")]),_v(" and "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2102#issuecomment-1950123596"}},[_v("Vitest")]),_v(" for faster development and testing on the frontend, and enhancing CI runs for "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2189"}},[_v("improved accuracy")]),_v(".")]),_v(" "),_c('h4',{attrs:{"id":"1-3-q-a-community"}},[_v("1.3 Q/A Community"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#1-3-q-a-community","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("I tried contributing to Stack Overflow by providing answers to questions related to frontend technologies such as Next.js, React, and component libraries. Some of my answers can be found "),_c('a',{attrs:{"href":"https://stackoverflow.com/users/15226661/charisma-kausar?tab=answers&sort=activity"}},[_v("here")]),_v(".")]),_v(" "),_c('p',[_v("Engaging with the Stack Overflow community was a good way to reinforce my understanding of these technologies while enabling me to assist others effectively and explain complex concepts in a simple manner. Yet, looking back, I realize that contributing more frequently is difficult as it may seem forced and inauthentic. I believe that contributing organically when I encounter a question that I can answer is more beneficial in the long run.")]),_v(" "),_c('h3',{attrs:{"id":"2-tools-and-technologies"}},[_v("2. Tools and Technologies"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#2-tools-and-technologies","onclick":"event.stopPropagation()"}})]),_v(" "),_c('h4',{attrs:{"id":"2-1-vue-js"}},[_v("2.1 Vue.js"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#2-1-vue-js","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_c('strong',[_v("2.1.1 Single-File Components (SFCs)")])]),_v(" "),_c('p',[_v("I have been working with Vue.js for a while now, and I find Single-File Components (SFCs) to be a very efficient way to organize Vue components. SFCs allow you to define the template, script, and styles of a component within a single file, making it easier to maintain the component.")]),_v(" "),_c('p',[_v("When componentizing our frontend, one of the proposed approaches was to split the template, script, and styles into separate files. While this approach does break down the huge file into smaller chunks, it creates multiple files that are highly interrelated instead of multiple loosely coupled components with good separation of concerns.")]),_v(" "),_c('p',[_v("We decided it was better if we did our modularization by continuing to follow the Single-File Component pattern of Vue. The separation of concerns in SFCs also helps in keeping the codebase clean and reduces context switching when working on a single component, enhancing overall code quality.")]),_v(" "),_c('h4',{attrs:{"id":"2-2-yaml"}},[_v("2.2 YAML"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#2-2-yaml","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("For our title component, we decided to migrate from a JSON format "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("report-config.json")]),_v(" to a YAML format "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("report-config.yaml")]),_v(". This choice was because of YAML's superior readability and compact syntax for defining configurations compared to JSON or XML.")]),_v(" "),_c('p',[_c('strong',[_v("2.2.1 YAML Frontmatter")])]),_v(" "),_c('p',[_v("YAML Frontmatter is a YAML block that is placed at the beginning of a file and is used to store metadata about the file. This metadata can be accessed to provide additional information or functionality based on the metadata.")]),_v(" "),_c('p',[_v("I explored the usage of "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2102#issuecomment-1919095515"}},[_v("frontmatter for a custom navbar")]),_v(" for the RepoSense report. We proposed integrating YAML frontmatter into the user-provided markdown files. The frontmatter obtained (for example, a list of links and the header color) using a tool such as "),_c('a',{attrs:{"href":"https://github.com/jonschlinkert/gray-matter"}},[_v("gray-matter")]),_v(" could be injected into a template header component as props, dynamically rendering the RepoSense HTML report.")]),_v(" "),_c('h4',{attrs:{"id":"2-3-quality-assurance"}},[_v("2.3 Quality Assurance"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#2-3-quality-assurance","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_c('strong',[_v("2.3.1 Frontend Testing Methodologies")])]),_v(" "),_c('p',[_v("In addressing a bug within the RepoSense report where all charts were erroneously grouped under one team, we realised that our end-to-end tests mainly focus on testing features rather than data representation. To avoid this in the future, we decided we needed any of the following:")]),_v(" "),_c('ul',[_c('li',[_v("Data-driven testing: Add tests to check if the actual JSON data is being represented in the expected manner.")]),_v(" "),_c('li',[_v("Snapshot testing: Implement snapshot testing to ensure there are no visual regressions.")])]),_v(" "),_c('p',[_v("We added more repositories to the Cypress testing data to ensure that the tests cover a wider range of scenarios. This will help us in identifying more bugs and ensuring that the report is accurate and reliable in the future.")]),_v(" "),_c('p',[_c('strong',[_v("2.3.2 Frontend Security Best Practices")])]),_v(" "),_c('p',[_v("When working with mentees for the "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2102"}},[_v("Add title component PR")]),_v(", I realized that we need to be more cautious about the security of our frontend code. So I researched about the library we were using for markdown parsing, "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("markdown-init")]),_v(", which had no security vulnerabilities and was also being used extensively by MarkBind. I also learned about the importance of sanitizing user input to prevent XSS attacks. However, since we were using a self-defined title component, we did not need to sanitize the input as we assumed good intentions from the user on their own report.")]),_v(" "),_c('h3',{attrs:{"id":"3-project-management"}},[_v("3. Project Management"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#3-project-management","onclick":"event.stopPropagation()"}})]),_v(" "),_c('h4',{attrs:{"id":"3-1-guiding-new-contributors"}},[_v("3.1 Guiding New Contributors"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#3-1-guiding-new-contributors","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Guiding contributors through a project was definitely a new challenge as a mentor. Each mentee had different working styles and areas of expertise, so I had to adapt my guidance to suit their needs.")]),_v(" "),_c('p',[_v("In the beginning, my focus was on recommending issues that were suitable for the mentees' skill levels and expertise. Then, it was about communicating project needs and expectations clearly.")]),_v(" "),_c('p',[_v("The biggest challenge was pushing the mentees to partake in more managerial responsibilities within the project. I had to learn how to provide clear instructions and set expectations for the mentees to take on more substantial roles without micromanaging them.")]),_v(" "),_c('h4',{attrs:{"id":"3-2-reviewing-prs"}},[_v("3.2 Reviewing PRs"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#3-2-reviewing-prs","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("While exploring topics for my lightning talk, I came across a "),_c('a',{attrs:{"href":"https://www.youtube.com/watch?v=Y9sp8gONv9M"}},[_v("YouTube video")]),_v(" where a Staff Software Engineer discusses the best practices for reviewing PRs. I also found another "),_c('a',{attrs:{"href":"https://mtlynch.io/human-code-reviews-2"}},[_v("article")]),_v(" by an ex-Google engineer that talks about reviewing PRs like a human. These resources gave me a good understanding of how to review PRs constructively.")]),_v(" "),_c('p',[_v("Sometimes we got some pretty big PRs (eg. "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2140"}},[_v("PR #2140")]),_v("), and it was difficult to review them in one go. I learned how to break down the review into smaller chunks, focusing on specific aspects of the code, and providing feedback for improvement by starting at the higher product design and system design level, and only then discussing smaller code quality improvements. The "),_c('a',{attrs:{"href":"https://marketplace.visualstudio.com/items?itemName=GitHub.vscode-pull-request-github"}},[_v("GitHub Pull Requests")]),_v(" extension for VS Code was also very helpful in reviewing PRs.")]),_v(" "),_c('p',[_v("Lastly, I learned that a good rule to follow is to aim to bring the code up by a letter grade or two. This means that the reviewer should aim to improve the code quality by a small amount with each review, rather than trying to make it perfect in one go.")]),_v(" "),_c('hr'),_v(" "),_c('h2',{attrs:{"id":"cs3281"}},[_v("CS3281"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#cs3281","onclick":"event.stopPropagation()"}})]),_v(" "),_c('h3',{attrs:{"id":"1-tools-and-technologies"}},[_v("1. Tools and Technologies"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#1-tools-and-technologies","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("The RepoSense frontend is built with Vue.js and Pug, with most of the JavaScript files being migrated to TypeScript over\nthe semester. Node.js is used to manage the packages, while static code analysis is performed with ESLint.\nCypress is the tool of choice for testing the frontend.")]),_v(" "),_c('h4',{attrs:{"id":"1-1-vue-js"}},[_v("1.1 Vue.js"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#1-1-vue-js","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Prior to working on RepoSense, I had experienced working with Vue.js using Vuetify components and the\n"),_c('a',{attrs:{"href":"https://vuejs.org/api/options-state.html"}},[_v("Options API")]),_v(". However, working on the project allowed me to delve deeper into\nthe intricacies of Vue and how to fully utilize its features.")]),_v(" "),_c('p',[_c('strong',[_v("1.1.1 MVVM Architecture Pattern")])]),_v(" "),_c('p',[_v("Vue.js focuses on the 'ViewModel' layer of the MVVM (Model-View-ViewModel) architectural pattern. This is because it connects\nthe Views and Models via 2-way data bindings. In this case, the view is the DOM (Document Object Model), and the models are\nthe plain JavaScript objects.")]),_v(" "),_c('p',[_c('strong',[_v("1.1.2 Leveraging Template Refs for Custom Behaviors")])]),_v(" "),_c('p',[_v("While Vue has a rendering model that abstracts away direct manipulation of the DOM, sometimes it is necessary to have access\nto the DOM to programmatically control an element. Hence, Vue gives us access to "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("$refs")]),_v(", which are similar to\n"),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("document.querySelector('.element')")]),_v(" in JavaScript, but are more efficient as they give direct access to the element needed\nrather than returning the first element that matches the given selector. This allowed me to implement custom behaviour such as\n"),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/1860"}},[_v("pinning the file title")]),_v(" within Vue.")]),_v(" "),_c('p',[_c('strong',[_v("1.1.3 Reusability with Custom Directives")])]),_v(" "),_c('p',[_v("Reuse of code is an essential concept in software engineering, which is why Vue offers custom directives.\nCustom directives allow the reuse of logic that involves low-level DOM access. They are basically objects containing\nlifecycle hooks similar to those of a component.")]),_v(" "),_c('p',[_v("One of the custom directives that RepoSense was already utilizing was a plugin called\n"),_c('a',{attrs:{"href":"https://github.com/Akryum/vue-observe-visibility/tree/next"}},[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("vue-observe-visibility")])]),_v(". This made use of the\n"),_c('a',{attrs:{"href":"https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserverEntry"}},[_v("IntersectionObserverEntry Web API")]),_v(" to observe\nwhether an element is in view and execute a function accordingly.")]),_v(" "),_c('p',[_v("During my work on the "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/1860"}},[_v("pin file title PR")]),_v(", I encountered a bug where\ntooltips appeared out of the viewport when at the top of the page. As the file title would be pinned to the top of the\npage, this issue needed to be resolved before my PR could be merged. To address this, I thought of using a custom\ndirective, and I utilized the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("vue-observe-visibility")]),_v(" directive to modify the CSS of the tooltip to be bottom-aligned\nbased on visibility changes. While this solution was successful, we required more customization as the tooltip needed\nto move back to being top-aligned when scrolling up. I eventually used template refs to address this issue, but this\nexperience allowed me to understand better about custom directives.")]),_v(" "),_c('h4',{attrs:{"id":"1-2-vuex"}},[_v("1.2 Vuex"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#1-2-vuex","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Vuex is a state management pattern and library for Vue that serves as the centralized source for all components. It\nenforces rules to ensure that the state can only be mutated in a predictable manner.")]),_v(" "),_c('p',[_c('strong',[_v("1.2.1 Single Source of Truth")])]),_v(" "),_c('p',[_v("During my work on a "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/1939"}},[_v("PR")]),_v(" to differentiate between authors when using\nthe 'merge group' option in RepoSense, I faced an issue with unsynchronised data copies. Initially, I had stored the\ncolors assigned to authors in both a local "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("data()")]),_v(" variable and the Vuex store. To resolve this, I employed "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("mapState")]),_v("\nas a Vue "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("computed")]),_v(" property to access the Vuex state from Vue components. This approach allowed me to re-evaluate the\ncomputed property every time the data changed, which triggered DOM updates and allowed a single source of truth.\nHowever, relying on the global store singleton could potentially be considered an anti-pattern as it would make the code\ndifficult to test.")]),_v(" "),_c('h4',{attrs:{"id":"1-3-javascript"}},[_v("1.3 JavaScript"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#1-3-javascript","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_c('strong',[_v("1.3.1 Dot vs Bracket Notation for Accessing Object Properties:")])]),_v(" "),_c('p',[_v("The dot notation ("),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("objectName.propertyName")]),_v(") is commonly used to access properties in a clean manner. However, it limits\nproperty identifiers to alphanumeric characters, "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("_")]),_v(", and "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("$")]),_v(". On the other hand, the bracket notation\n("),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("objectName['propertyName']")]),_v(") can use all UTF-8 characters in property names or even variables that finally resolve to\na string. This notation is useful when the property name is only known during runtime, as in this\n"),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/1860"}},[_v("PR")]),_v(" where "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("this.$refs[file.path]")]),_v(" is used because the reference to\n"),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("file.path")]),_v(" is only resolved based on the file being interacted with.")]),_v(" "),_c('p',[_c('strong',[_v("1.3.2 ES6 String Interpolation for Cleaner Code")])]),_v(" "),_c('p',[_v("ES6 introduced template strings as a concise and readable way to insert values into strings. In contrast, the string\nconcatenation approach can be harder to read and edit, and requires creating multiple strings that need to be put\ntogether. Moreover, string concatenation would take up more memory and computation compared to creating just one string.")]),_v(" "),_c('h4',{attrs:{"id":"1-4-typescript"}},[_v("1.4 TypeScript"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#1-4-typescript","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("TypeScript is an object-oriented programming language that allows for classes, interfaces, and inheritance support in\nthe frontend. It provides static typing and type inference, making it easier to catch errors before runtime.\nTherefore, we decided to migrate our codebase from JavaScript to TypeScript to align our frontend with our OOP Java backend.")]),_v(" "),_c('p',[_c('strong',[_v("1.4.1 Class vs Interface for Typing")])]),_v(" "),_c('p',[_v("When working on "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/1852"}},[_v("my first PR")]),_v(" for defining Vue prop types explicitly,\nI initially used classes in TypeScript. However, after gaining more knowledge about TypeScript, I realized that\ninterfaces are more suitable for type-checking at compile time. Interfaces have less overhead since they do not exist at\nruntime and are erased when the code is transpiled to JS. Although classes can define methods relevant to class objects,\nthis feature was not useful for us. In a "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/1965"}},[_v("later PR")]),_v(", we decided to\nswitch to using an interface to improve the performance of the frontend.")]),_v(" "),_c('h4',{attrs:{"id":"1-5-pug"}},[_v("1.5 Pug"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#1-5-pug","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Pug is a templating language that makes it easier to write reusable HTML components with cleaner syntax. It is useful\nwhen working with data-driven web applications like RepoSense. Although it can be challenging to find resources that\nprovide documentation on\n"),_c('a',{attrs:{"href":"https://medium.com/@martinsOnuoha/building-vue-components-with-pug-stylus-564615ed289"}},[_v("using Vue and Pug together")]),_v(",\nPug's syntax is much faster to develop in than HTML once you get used to it.")]),_v(" "),_c('h4',{attrs:{"id":"1-6-sass-and-css"}},[_v("1.6 Sass and CSS"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#1-6-sass-and-css","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Sass is a CSS pre-processor and an extension of CSS. It helps reduce repetition in CSS and saves programming time by\nproviding features like variables, mixins, imports, and inheritance. A Sass pre-processor transpiles Sass code into\nstandard CSS as browsers can only understand plain CSS code.")]),_v(" "),_c('p',[_c('strong',[_v("1.6.1 Choosing between Placeholders and Mixins")])]),_v(" "),_c('p',[_v("The difference between mixins and placeholders is that placeholders consolidate mutually-shared code, whereas mixins just\nassign the properties to the individual classes — along with whatever was specific to that class. Because of this, it’s\npreferred to use placeholders. But since placeholders aren’t able to take parameters, it’s better to use mixins in such\ncases.")]),_v(" "),_c('p',[_v("I had to decide between placeholders and mixins when trying to consolidate the code required for a tooltip tail, and assign\nit along with some specific properties depending on whether the tooltip was top-aligned or bottom-aligned. Hence, I made use\nof placeholders for this as they group together mutually-shared code. In another\n"),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/1979"}},[_v("PR")]),_v(", I used mixins to standardize the fonts used throughout the\nfrontend as fonts only need to be assigned to the CSS classes along with their other properties.")]),_v(" "),_c('h4',{attrs:{"id":"1-7-cypress"}},[_v("1.7 Cypress"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#1-7-cypress","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Cypress is a powerful web testing framework designed for end-to-end testing. Unlike Selenium, it operates within the application,\nallowing high flexibility to access any objects in the app, including DOM objects and the window, similar to how we do\nwithin the code itself.")]),_v(" "),_c('p',[_c('strong',[_v("1.7.1 Effective and efficient test case design")])]),_v(" "),_c('p',[_v("To ensure effective and efficient test case design, I have targeted potential fault points with each of my Cypress test\ncases. However, I noticed repetitive Cypress commands in these test cases, which can be extracted into a common function\nfor better reusability. While the rest of the codebase also uses such repetitive commands in all test cases\nfor setup, we should plan to extract all the setup commands into a common function to allow for reusability.")]),_v(" "),_c('h4',{attrs:{"id":"1-8-linting"}},[_v("1.8 Linting"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#1-8-linting","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Linting is the process of performing static analysis on code to identify programming or code style errors. While I have used\ncode analysis tools of IDEs, I had not explicitly enforced custom coding rules using lints before.")]),_v(" "),_c('p',[_c('strong',[_v("1.8.1 Enforcing Custom Coding Rules with ESLint")])]),_v(" "),_c('p',[_v("During the migration to TypeScript, we decided to use the Airbnb style guide, similar to how we used it for JavaScript.\nBesides, we defined other "),_c('a',{attrs:{"href":"https://typescript-eslint.io/rules/"}},[_v("custom rules")]),_v(", and I created a\n"),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/issues/1980"}},[_v("first-timer issue")]),_v(" that deals with the consistent use of "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("T[]")]),_v(" or\n"),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Array")]),_v(" throughout the codebase. This helps enforce coding standards and make the code more consistent and maintainable.")]),_v(" "),_c('hr'),_v(" "),_c('p',[_v("The Backend for RepoSense is written in Java, and testing is done using JUnit. Since RepoSense is for contribution analysis,\nGit commands are highly used within the project. Gradle is used to manage the project dependencies and for DevOps tasks.")]),_v(" "),_c('h4',{attrs:{"id":"1-9-git"}},[_v("1.9 Git"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#1-9-git","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_c('strong',[_v("1.9.1 Understanding "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("git log")])])]),_v(" "),_c('p',[_v("For working on the "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/1882"}},[_v("PR to include merge commits")]),_v(" in the web dashboard, some\nbackend changes were required as merge commits were not included in the generated report itself. Hence, I had to look into the\ndocs of git commands, specifically "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("git log")]),_v(", to understand what flags I could make use of to include all the desired\ncommits in the report. Previously, we were using the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("--no-merges")]),_v(" flag to remove all merges from the report. However, simply\nremoving this flag did not help in including all the merge commits in the new report. This may be because git continues to\nsimplify “uninteresting” merges in the default mode. Finally, the use of "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("--full-history")]),_v(" helped include all commits without\nmerging any same content commits together. "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("git log")]),_v(" also had to option to format its output with a "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("")]),_v(", and\nthis formatted output makes it easy for us to parse the results and generate our repository analysis reports.")]),_v(" "),_c('p',[_c('strong',[_v("1.9.2 Spoofing for Good")])]),_v(" "),_c('p',[_v("I was surprised by how easy it is to commit as someone else using Git as long as one has write access. I had to make use of this\ntechnique when I had to create a test commit, as only commits from a selected group of users are part of the Cypress test\ndashboard. I "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/commit/ffbc714a11c39fae870d1ea994ce200008c63756"}},[_v("spoofed")]),_v(" one of\nthese users so that the commit to test appears on the test dashboard.")]),_v(" "),_c('hr'),_v(" "),_c('h3',{attrs:{"id":"2-software-engineering"}},[_v("2. Software Engineering"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#2-software-engineering","onclick":"event.stopPropagation()"}})]),_v(" "),_c('h4',{attrs:{"id":"2-1-design-choices"}},[_v("2.1 Design choices"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#2-1-design-choices","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_c('strong',[_v("2.1.1 Object parameter vs multiple parameters for constructors")])]),_v(" "),_c('p',[_v("While creating a "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("User")]),_v(" object in TypeScript, I encountered the challenge of passing in a large number of arguments (~10)\nto construct the object. This made me wonder what the best way of initialising such objects with large number of\nattributes is. I was exploring the use of a single object parameter, as it makes the code much cleaner. However, there\nis a tradeoff of whether it would be type safe to just pass an object without any type as a parameter into the function.\nYet, I decided to continue with the method of using an object argument as this issue of type safety could be mitigated\nin the future by checking that the object being passed in as the argument implements the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("User")]),_v(" interface,\nwhen migrating to TypeScript, which was eventually done.")]),_v(" "),_c('h4',{attrs:{"id":"2-2-reflections"}},[_v("2.2 Reflections"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#2-2-reflections","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_c('strong',[_v("2.2.1 Understanding a Language/Tool Before Working with It")])]),_v(" "),_c('p',[_v("Previously, I had the mindset of just making things work without understanding the inner workings of a language or tool.\nHowever, I realized that this approach only led to superficial knowledge, making each challenge as difficult as the last.\nThis semester, I gained a new perspective on how understanding the language/tool can make things easier down the road.\nI now strive for a good balance of theory and practical knowledge to accumulate my understanding and improve over time.")]),_v(" "),_c('p',[_c('strong',[_v("2.2.2 Applying the \"Make it Work, Make it Right, Make it Fast\" Principle")])]),_v(" "),_c('p',[_v("While working on a "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/1939"}},[_v("PR")]),_v(" to differentiate between authors while using\n'merge group', I applied the principle of "),_c('em',[_v("\"Make it work, Make it right, Make it fast.\"")]),_v(" Initially, I focused on making\nit work and fixing any edge cases. Later on, I refactored the code to optimize it. Additionally, I conducted performance\nanalysis for the PR after it was complete, which can be accessed\n"),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/1939#issuecomment-1518718579"}},[_v("here")]),_v(".")]),_v(" "),_c('p',[_c('strong',[_v("2.2.3 Full-Stack Development Experience")])]),_v(" "),_c('p',[_v("Working on the "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/1882"}},[_v("show merge commits PR")]),_v(" provided a chance to work on\nall aspects of the codebase as a frontend developer. I researched Git to find out how to include all merge commits,\nedited the Java backend parsers to include an additional field for whether a commit is a merge commit, and made frontend\nchanges to include merge commits within the HTML report. Furthermore, I wrote test cases for frontend Cypress, backend\nunit tests, and system tests. This experience was rewarding as it allowed me to do full-stack development and learn how\nall the components work together while solving a single problem.")]),_v(" "),_c('hr'),_v(" "),_c('h3',{attrs:{"id":"3-project-management-2"}},[_v("3. Project Management"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#3-project-management-2","onclick":"event.stopPropagation()"}})]),_v(" "),_c('h4',{attrs:{"id":"3-1-lessons-learned-from-contributing-to-an-open-source-project"}},[_v("3.1 Lessons Learned from Contributing to an Open-Source Project"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#3-1-lessons-learned-from-contributing-to-an-open-source-project","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_c('strong',[_v("3.1.1 Understanding the Contribution Workflow")])]),_v(" "),_c('p',[_v("Contributing to RepoSense has provided me with valuable insights into the contribution workflow for open-source projects.\nIt has helped me understand the quality expectations that are necessary for maintaining a high-quality codebase.\nHowever, having strict rules can sometimes hinder the PR review process, leading to longer review cycles. Hence, to\nstrike a balance between quality and speed, setting guidelines and maintaining effective communication channels is\nessential.")]),_v(" "),_c('p',[_c('strong',[_v("3.1.2 Importance of Documentation")])]),_v(" "),_c('p',[_v("Documentation is an integral part of open-source projects, and its importance cannot be overemphasized. It's easy to forget to\nupdate the documentation after making changes in a PR, leading to outdated documentation. Going forward, I recognize the need to\nmaintain an up-to-date documentation to ensure that future contributors have access to accurate and comprehensive information.\nTo this end, I suggest having a checklist in the PR issue template to remind contributors of the need to update documentation.")]),_v(" "),_c('p',[_c('strong',[_v("3.1.3 Optimal PR Length")])]),_v(" "),_c('p',[_v("I received feedback from my mentors that my PRs were too long, leading to difficulty in reviewing. It was suggested that\nbreaking down the PRs into smaller ones would make the review process easier. Based on this feedback, I have made a conscious\neffort to create smaller PRs going forward.")]),_v(" "),_c('p',[_c('strong',[_v("3.1.4 Understanding Versioning")])]),_v(" "),_c('p',[_v("Contributing to RepoSense has provided me with insights into versioning and how it is maintained for open-source projects.\nThe process of maintaining separate web pages for documentation of released versions and the master version has been an\nimportant lesson. To deepen my understanding of project management, I am planning on making a release myself in the near future.")])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/ckcherry23/observations.html b/students/ckcherry23/observations.html index 002069423..28409246d 100644 --- a/students/ckcherry23/observations.html +++ b/students/ckcherry23/observations.html @@ -12,7 +12,7 @@ const baseUrl = '/2024' -

    Project: date-fns

    date-fns is a modern TypeScript date utility library. It provides the most comprehensive, yet simple and consistent toolset for manipulating JavaScript dates in a browser & Node.js.

    It is like Lodash for dates. It has 200+ functions to manipulate dates, is modular and immutable, uses native dates, provides I18n support, and is built using pure functions.

    The project has a main library, date-fns, and a documentation website, date-fns.org.

    My Contributions

    Having utilized the date-fns library in an event management system previously, I decided to contribute to the project. I did this by setting up the function aliases system and then focused on improving Duration support.

    Function Aliases and Documentation Site

    My first PR was to add aliases to functions in date-fns. I added an alias formatDate for the format function in PR#3653 and reached out to the project maintainer @kossnocorp for guidance regarding long-term contributions and getting more PR visibility. He agreed to provide weekly reviews to facilitate my contributions and we set up a communication channel on Discord.

    He suggested that I work on the documentation website, date-fns.org as the docs did not support displaying function aliases yet. I then added aliases to functions in the TypeDoc documentation website in PR#216.

    Duration Support

    Next, as per the project's current needs shared by the maintainer, I focussed on improving Duration support in date-fns. I submitted a proposal to improve Duration support to the project maintainer and got started with reviewing issues and PRs related to Duration support. Since one of the PR authors was unresponsive, I took over the PR, fixed the issues, added extensive tests and updated the documentation in PR#3768 for parseISODuration.

    Timeline of Contributions

    Date Contribution Links
    08 Jan 24 Authored PR #1 Add alias formatDate for format function #3653
    11 Jan 24 Authored PR #2 Add aliases to functions in typedoc #216
    11 Jan 24 Created issue Blockstyle quotes not readable in light mode #217
    Week 2 Reviewed PR Add alias isExisting for isExists #3673
    Week 2 Submitted proposal Proposal to improve Duration support, Discussion comment
    Week 3 Contributed to discussion Formatting duration options #3693
    Week 3-5 Reviewed PR feat: add parseISODuration #3151
    Week 6-8 Suggested improvements ExtendedDuration and Temporal proposal
    Week 12-13 Authored PR #3 Add parseISODuration function #3768

    Other Projects

    Before date-fns, I also tried contributing to other OSS projects to make a decision on which project to choose.

    matplotlib

    When applying for CS3281, I contributed to matplotlib, a Python plotting library. I added an ellipse class for annotation box styles in PR#24596. The PR was merged and I learned how to contribute to open-source projects by following the contributing guide. The maintainers were responsive to issues and PRs; however, I sought a project that aligned better with my interests and chosen area of expertise.

    react-awesome-loaders

    I also tried contributing to react-awesome-loaders, a React component library, in Dec 2023. Although the library had amazing loader designs, it used Node 12 and could not be utilized in modern projects using Next.js, which has a minimum Node requirement of Node 18. I successfully updated the node version in the project and used ncu or npm-check-updates to update old dependencies in PR#24. Unfortunately, the documentation site could not be updated to Node 18 as it was created with smooth-doc, which was not compatible with Node 18. Considering that I needed to migrate the entire documentation site to a new framework, I put the PR on hold and it was not merged.

    checkstyle

    Then I tried my hand at checkstyle, a Java static code analysis tool, in Jan 2024. I removed //ok comments for the equalavoidsnull module in PR#14215 and the PR was merged. The project maintainers were responsive and the issues for new contributors were handpicked by maintainers and labelled as "good first issue", "good second issue", "good third issue" and "good fourth issue" (1 - 3 each). This facilitated easy identification of issues for new contributors and progression through the contribution process.

    My Learning Record

    1. Tools and Technologies

    1.1 Learning why date-fns over others

    Working with a popular npm package, I learned extensively about the library's perks from the documentation itself. I discovered that date-fns utilizes tree-shaking to reduce the size of the final bundle and read the webpack documentation to understand its functionality. Tree shaking involves dead code elimination to ensure production-ready code with minimal file size, allowing compatibility with tools like webpack, Rollup, etc.

    The project also employs a function-based API where each function is a pure function, enabling better immutability and testability. Moreover, it allows for importing only the necessary functions, enhancing performance. Additionally, the project offers a functional-programming submodule facilitating improved function composition, which allowed revisiting some concepts taught in CS1101S.

    1.2 Testing npm packages

    Since I worked on an npm package, I learned various methods to test npm packages locally beyond standard unit testing. Instead of repeatedly publishing the package to npm (which I would have done a year ago -_-), I utilized npm link to test the package locally in other JavaScript projects. I learned about this approach from Urban Sanden's blog. Additionally, I used npm tsx to get a TypeScript REPL (Read-Eval-Print-Loop) and required the respective date-fns function to test them within the terminal. This was facilitated by tsx, which stands for TypeScript Execute, and enables running TypeScript in Node.js with improved Developer Experience (watch mode, scripts, etc).

    1.3 Generating documentation

    date-fns uses TypeDoc to generate documentation for the project. I used the official TypeDoc docs to understand its functionality. The documentation site generator created documentation based on the TSDoc comments deployed on Firebase. The TSDoc standard was used for documenting the code, akin to JavaDoc. Having worked with multiple TypeScript projects before, this was my first experience using a TypeScript documentation generator, and it was smooth.

    1.4 Date manipulation in JavaScript

    Exploring the history of date manipulation in JavaScript and its evolution over time was enlightening. I learned about various methods for date manipulation in JavaScript and compared date-fns with competing libraries like Moment.js and Day.js.

    Additionally, considering date-fns aims to improve Duration support, I explored the experimental ECMAScript Temporal proposal that seeks to provide native support for Durations in JavaScript. This proposal could potentially enhance duration functions without using our library, however, polyfills like these tend to be heavy, prompting date-fns to implement a lightweight solution as an interim API with a minimal subset of the Temporal proposal.

    2. Reflections on contributing to date-fns

    date-fns has a Contributing Guide detailing how to contribute to the project.

    2.1 Good: No more "Move fast and break things"

    Having worked in fast-paced environments before, I generally embrace the "move fast and break things" mentality (maybe a bit too much :3 -> RepoSense issues #2164 and #2184). However, you do not have that "freedom" when working on an npm package with 20 million weekly downloads. This was a good learning experience for me as even a simple function such as parseISODuration required extensive discussions regarding design decisions, for example, whether undefined values should be preserved, what rules should be followed for parsing, etc., and all these should consider the standard proposals, the competitor libraries' features, and the community's feedback.

    2.2 Good: Making a difference

    While many other OSS projects I contributed to involved fixing bugs or adding small features, date-fns was more about making a difference. Since date-fns is a modular library with pure functions, contributors get to work on actual features that can be used by millions of developers worldwide. This was a great motivation for me to contribute to date-fns.

    2.3 Good: Targeted mentorship

    I reached out to the maintainers of date-fns and they were very helpful in guiding me on how to contribute to the project. This helped me work on the project for a longer period of time and make more meaningful contributions based on the project's needs instead of randomly picking issues to work on.

    2.4 To improve: Community management

    date-fns has a large community and a lot of issues are opened every day. However, the 3-5 maintainers of the project do not have the bandwidth to manage all the issues. This makes it difficult for new contributors to find issues to work on. Moreover, repetitive issues are opened multiple times, leading to duplicated efforts in PRs. This is something that can be improved in date-fns.

    Since there are too many PRs opened, the maintainers have decided to only focus on those PRs that contribute towards the project's long-term goals, which is a good strategy to ensure that the project is moving in the right direction. Sometimes, contributors are not responsive to maintainers' feedback and this leads to abandoned PRs. Instead of starting from scratch, I learned how to handle abandoned PRs by taking over one and completing the work.

    2.5 To improve: Documentation contrasts

    While date-fns has a very comprehensive documentation website, the documentation website generator did not have any contribution guidelines, because it was mainly handled by the core team. This made it difficult for me to understand how to contribute to the custom documentation website generator, and I had to reach out to the maintainers for guidance. This is understandable as the documentation site generator does not expect much community contributions, but is still something that can be improved in date-fns.

    3. Suggestions for RepoSense

    3.1 One-to-one mentorship

    date-fns has a system where maintainers provide weekly advice to contributors to help them make meaningful contributions to the project. This is a great way to guide new contributors and help them understand the project better. This is something that can be adopted by RepoSense to help new contributors make contributions that align with project goals.

    3.2 Automatic documentation generation

    Looking at the custom documentation generator for date-fns got me thinking about whether there is a way to automatically generate documentation for RepoSense, especially for the CLI arguments and the configuration files. This would help new contributors understand the project better and also assist in maintaining up-to-date documentation. Although the work required to set up the documentation generator might be substantial, it could prove to be a worthwhile investment in the long run, particularly if well-documented.

    3.3 New contributor issues

    If we aim to attract more first-time contributors to NUS-OSS projects as opposed to long-term contributors, we could establish a system akin to checkstyle's approach by labelling issues as "good first issue," "good second issue," and so on. By doing this, RepoSense can streamline the onboarding process and foster a welcoming community for a diverse pool of contributors. This would also help in managing the influx of new contributors and ensure that they have a smooth onboarding experience.

    +

    Project: date-fns

    date-fns is a modern TypeScript date utility library. It provides the most comprehensive, yet simple and consistent toolset for manipulating JavaScript dates in a browser & Node.js.

    It is like Lodash for dates. It has 200+ functions to manipulate dates, is modular and immutable, uses native dates, provides I18n support, and is built using pure functions.

    The project has a main library, date-fns, and a documentation website, date-fns.org.

    My Contributions

    Having utilized the date-fns library in an event management system previously, I decided to contribute to the project. I did this by setting up the function aliases system and then focused on improving Duration support.

    Function Aliases and Documentation Site

    My first PR was to add aliases to functions in date-fns. I added an alias formatDate for the format function in PR#3653 and reached out to the project maintainer @kossnocorp for guidance regarding long-term contributions and getting more PR visibility. He agreed to provide weekly reviews to facilitate my contributions and we set up a communication channel on Discord.

    He suggested that I work on the documentation website, date-fns.org as the docs did not support displaying function aliases yet. I then added aliases to functions in the TypeDoc documentation website in PR#216.

    Duration Support

    Next, as per the project's current needs shared by the maintainer, I focussed on improving Duration support in date-fns. I submitted a proposal to improve Duration support to the project maintainer and got started with reviewing issues and PRs related to Duration support. Since one of the PR authors was unresponsive, I took over the PR, fixed the issues, added extensive tests and updated the documentation in PR#3768 for parseISODuration.

    Timeline of Contributions

    Date Contribution Links
    08 Jan 24 Authored PR #1 Add alias formatDate for format function #3653
    11 Jan 24 Authored PR #2 Add aliases to functions in typedoc #216
    11 Jan 24 Created issue Blockstyle quotes not readable in light mode #217
    Week 2 Reviewed PR Add alias isExisting for isExists #3673
    Week 2 Submitted proposal Proposal to improve Duration support, Discussion comment
    Week 3 Contributed to discussion Formatting duration options #3693
    Week 3-5 Reviewed PR feat: add parseISODuration #3151
    Week 6-8 Suggested improvements ExtendedDuration and Temporal proposal
    Week 12-13 Authored PR #3 Add parseISODuration function #3768

    Other Projects

    Before date-fns, I also tried contributing to other OSS projects to make a decision on which project to choose.

    matplotlib

    When applying for CS3281, I contributed to matplotlib, a Python plotting library. I added an ellipse class for annotation box styles in PR#24596. The PR was merged and I learned how to contribute to open-source projects by following the contributing guide. The maintainers were responsive to issues and PRs; however, I sought a project that aligned better with my interests and chosen area of expertise.

    react-awesome-loaders

    I also tried contributing to react-awesome-loaders, a React component library, in Dec 2023. Although the library had amazing loader designs, it used Node 12 and could not be utilized in modern projects using Next.js, which has a minimum Node requirement of Node 18. I successfully updated the node version in the project and used ncu or npm-check-updates to update old dependencies in PR#24. Unfortunately, the documentation site could not be updated to Node 18 as it was created with smooth-doc, which was not compatible with Node 18. Considering that I needed to migrate the entire documentation site to a new framework, I put the PR on hold and it was not merged.

    checkstyle

    Then I tried my hand at checkstyle, a Java static code analysis tool, in Jan 2024. I removed //ok comments for the equalavoidsnull module in PR#14215 and the PR was merged. The project maintainers were responsive and the issues for new contributors were handpicked by maintainers and labelled as "good first issue", "good second issue", "good third issue" and "good fourth issue" (1 - 3 each). This facilitated easy identification of issues for new contributors and progression through the contribution process.

    My Learning Record

    1. Tools and Technologies

    1.1 Learning why date-fns over others

    Working with a popular npm package, I learned extensively about the library's perks from the documentation itself. I discovered that date-fns utilizes tree-shaking to reduce the size of the final bundle and read the webpack documentation to understand its functionality. Tree shaking involves dead code elimination to ensure production-ready code with minimal file size, allowing compatibility with tools like webpack, Rollup, etc.

    The project also employs a function-based API where each function is a pure function, enabling better immutability and testability. Moreover, it allows for importing only the necessary functions, enhancing performance. Additionally, the project offers a functional-programming submodule facilitating improved function composition, which allowed revisiting some concepts taught in CS1101S.

    1.2 Testing npm packages

    Since I worked on an npm package, I learned various methods to test npm packages locally beyond standard unit testing. Instead of repeatedly publishing the package to npm (which I would have done a year ago -_-), I utilized npm link to test the package locally in other JavaScript projects. I learned about this approach from Urban Sanden's blog. Additionally, I used npm tsx to get a TypeScript REPL (Read-Eval-Print-Loop) and required the respective date-fns function to test them within the terminal. This was facilitated by tsx, which stands for TypeScript Execute, and enables running TypeScript in Node.js with improved Developer Experience (watch mode, scripts, etc).

    1.3 Generating documentation

    date-fns uses TypeDoc to generate documentation for the project. I used the official TypeDoc docs to understand its functionality. The documentation site generator created documentation based on the TSDoc comments deployed on Firebase. The TSDoc standard was used for documenting the code, akin to JavaDoc. Having worked with multiple TypeScript projects before, this was my first experience using a TypeScript documentation generator, and it was smooth.

    1.4 Date manipulation in JavaScript

    Exploring the history of date manipulation in JavaScript and its evolution over time was enlightening. I learned about various methods for date manipulation in JavaScript and compared date-fns with competing libraries like Moment.js and Day.js.

    Additionally, considering date-fns aims to improve Duration support, I explored the experimental ECMAScript Temporal proposal that seeks to provide native support for Durations in JavaScript. This proposal could potentially enhance duration functions without using our library, however, polyfills like these tend to be heavy, prompting date-fns to implement a lightweight solution as an interim API with a minimal subset of the Temporal proposal.

    2. Reflections on contributing to date-fns

    date-fns has a Contributing Guide detailing how to contribute to the project.

    2.1 Good: No more "Move fast and break things"

    Having worked in fast-paced environments before, I generally embrace the "move fast and break things" mentality (maybe a bit too much :3 -> RepoSense issues #2164 and #2184). However, you do not have that "freedom" when working on an npm package with 20 million weekly downloads. This was a good learning experience for me as even a simple function such as parseISODuration required extensive discussions regarding design decisions, for example, whether undefined values should be preserved, what rules should be followed for parsing, etc., and all these should consider the standard proposals, the competitor libraries' features, and the community's feedback.

    2.2 Good: Making a difference

    While many other OSS projects I contributed to involved fixing bugs or adding small features, date-fns was more about making a difference. Since date-fns is a modular library with pure functions, contributors get to work on actual features that can be used by millions of developers worldwide. This was a great motivation for me to contribute to date-fns.

    2.3 Good: Targeted mentorship

    I reached out to the maintainers of date-fns and they were very helpful in guiding me on how to contribute to the project. This helped me work on the project for a longer period of time and make more meaningful contributions based on the project's needs instead of randomly picking issues to work on.

    2.4 To improve: Community management

    date-fns has a large community and a lot of issues are opened every day. However, the 3-5 maintainers of the project do not have the bandwidth to manage all the issues. This makes it difficult for new contributors to find issues to work on. Moreover, repetitive issues are opened multiple times, leading to duplicated efforts in PRs. This is something that can be improved in date-fns.

    Since there are too many PRs opened, the maintainers have decided to only focus on those PRs that contribute towards the project's long-term goals, which is a good strategy to ensure that the project is moving in the right direction. Sometimes, contributors are not responsive to maintainers' feedback and this leads to abandoned PRs. Instead of starting from scratch, I learned how to handle abandoned PRs by taking over one and completing the work.

    2.5 To improve: Documentation contrasts

    While date-fns has a very comprehensive documentation website, the documentation website generator did not have any contribution guidelines, because it was mainly handled by the core team. This made it difficult for me to understand how to contribute to the custom documentation website generator, and I had to reach out to the maintainers for guidance. This is understandable as the documentation site generator does not expect much community contributions, but is still something that can be improved in date-fns.

    3. Suggestions for RepoSense

    3.1 One-to-one mentorship

    date-fns has a system where maintainers provide weekly advice to contributors to help them make meaningful contributions to the project. This is a great way to guide new contributors and help them understand the project better. This is something that can be adopted by RepoSense to help new contributors make contributions that align with project goals.

    3.2 Automatic documentation generation

    Looking at the custom documentation generator for date-fns got me thinking about whether there is a way to automatically generate documentation for RepoSense, especially for the CLI arguments and the configuration files. This would help new contributors understand the project better and also assist in maintaining up-to-date documentation. Although the work required to set up the documentation generator might be substantial, it could prove to be a worthwhile investment in the long run, particularly if well-documented.

    3.3 New contributor issues

    If we aim to attract more first-time contributors to NUS-OSS projects as opposed to long-term contributors, we could establish a system akin to checkstyle's approach by labelling issues as "good first issue," "good second issue," and so on. By doing this, RepoSense can streamline the onboarding process and foster a welcoming community for a diverse pool of contributors. This would also help in managing the influx of new contributors and ensure that they have a smooth onboarding experience.

    diff --git a/students/ckcherry23/observations.page-vue-render.js b/students/ckcherry23/observations.page-vue-render.js index f1faae427..702be4559 100644 --- a/students/ckcherry23/observations.page-vue-render.js +++ b/students/ckcherry23/observations.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('h3',{attrs:{"id":"project-date-fns"}},[_v("Project: date-fns"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#project-date-fns","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("date-fns is a modern TypeScript date utility library. It provides the most comprehensive, yet simple and consistent toolset for manipulating JavaScript dates in a browser & Node.js.")]),_v(" "),_c('p',[_v("It is like Lodash for dates. It has 200+ functions to manipulate dates, is modular and immutable, uses native dates, provides I18n support, and is built using pure functions.")]),_v(" "),_c('p',[_v("The project has a main library, "),_c('a',{attrs:{"href":"https://github.com/date-fns/date-fns"}},[_v("date-fns")]),_v(", and a documentation website, "),_c('a',{attrs:{"href":"https://github.com/date-fns/date-fns.org"}},[_v("date-fns.org")]),_v(".")]),_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("Having utilized the date-fns library in an event management system previously, I decided to contribute to the project. I did this by setting up the function aliases system and then focused on improving Duration support.")]),_v(" "),_c('p',[_c('strong',[_v("Function Aliases and Documentation Site")])]),_v(" "),_c('p',[_v("My first PR was to add aliases to functions in date-fns. I added an alias "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("formatDate")]),_v(" for the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("format")]),_v(" function in "),_c('a',{attrs:{"href":"https://github.com/date-fns/date-fns/pull/3653"}},[_v("PR#3653")]),_v(" and reached out to the project maintainer "),_c('a',{attrs:{"href":"https://github.com/kossnocorp"}},[_v("@kossnocorp")]),_v(" for guidance regarding long-term contributions and getting more PR visibility. He agreed to provide weekly reviews to facilitate my contributions and we set up a communication channel on Discord.")]),_v(" "),_c('p',[_v("He suggested that I work on the documentation website, "),_c('a',{attrs:{"href":"https://github.com/date-fns/date-fns.org"}},[_v("date-fns.org")]),_v(" as the docs did not support displaying function aliases yet. I then added aliases to functions in the TypeDoc documentation website in "),_c('a',{attrs:{"href":"https://github.com/date-fns/date-fns.org/pull/216"}},[_v("PR#216")]),_v(".")]),_v(" "),_c('p',[_c('strong',[_v("Duration Support")])]),_v(" "),_c('p',[_v("Next, as per the project's current needs shared by the maintainer, I focussed on improving Duration support in date-fns. I submitted a "),_c('a',{attrs:{"href":"https://gist.github.com/ckcherry23/e7641d65122259c699b2e1437f33d4c9"}},[_v("proposal to improve Duration support")]),_v(" to the project maintainer and got started with reviewing issues and PRs related to Duration support. Since one of the PR authors was unresponsive, I took over the PR, fixed the issues, added extensive tests and updated the documentation in "),_c('a',{attrs:{"href":"https://github.com/date-fns/date-fns/pull/3768"}},[_v("PR#3768")]),_v(" for "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("parseISODuration")]),_v(".")]),_v(" "),_c('p',[_c('strong',[_v("Timeline of Contributions")])]),_v(" "),_c('div',{staticClass:"table-responsive"},[_c('table',{staticClass:"markbind-table table table-bordered table-striped"},[_c('thead',[_c('tr',[_c('th',[_v("Date")]),_v(" "),_c('th',[_v("Contribution")]),_v(" "),_c('th',[_v("Links")])])]),_v(" "),_c('tbody',[_c('tr',[_c('td',[_v("08 Jan 24")]),_v(" "),_c('td',[_v("Authored PR #1")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/date-fns/date-fns/pull/3653"}},[_v("Add alias formatDate for format function #3653")])])]),_v(" "),_c('tr',[_c('td',[_v("11 Jan 24")]),_v(" "),_c('td',[_v("Authored PR #2")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/date-fns/date-fns.org/pull/216"}},[_v("Add aliases to functions in typedoc #216")])])]),_v(" "),_c('tr',[_c('td',[_v("11 Jan 24")]),_v(" "),_c('td',[_v("Created issue")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/date-fns/date-fns.org/issues/217"}},[_v("Blockstyle quotes not readable in light mode #217")])])]),_v(" "),_c('tr',[_c('td',[_v("Week 2")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/date-fns/date-fns/pull/3673"}},[_v("Add alias isExisting for isExists #3673")])])]),_v(" "),_c('tr',[_c('td',[_v("Week 2")]),_v(" "),_c('td',[_v("Submitted proposal")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://gist.github.com/ckcherry23/e7641d65122259c699b2e1437f33d4c9"}},[_v("Proposal to improve Duration support")]),_v(", "),_c('a',{attrs:{"href":"https://github.com/orgs/date-fns/discussions/3666#discussioncomment-8341732"}},[_v("Discussion comment")])])]),_v(" "),_c('tr',[_c('td',[_v("Week 3")]),_v(" "),_c('td',[_v("Contributed to discussion")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/orgs/date-fns/discussions/3693"}},[_v("Formatting duration options #3693")])])]),_v(" "),_c('tr',[_c('td',[_v("Week 3-5")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/date-fns/date-fns/pull/3151"}},[_v("feat: add parseISODuration #3151")])])]),_v(" "),_c('tr',[_c('td',[_v("Week 6-8")]),_v(" "),_c('td',[_v("Suggested improvements")]),_v(" "),_c('td',[_v("ExtendedDuration and "),_c('a',{attrs:{"href":"https://tc39.es/proposal-temporal/docs/duration.html"}},[_v("Temporal proposal")])])]),_v(" "),_c('tr',[_c('td',[_v("Week 12-13")]),_v(" "),_c('td',[_v("Authored PR #3")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/date-fns/date-fns/pull/3768"}},[_v("Add parseISODuration function #3768")])])])])])]),_c('h4',{attrs:{"id":"other-projects"}},[_v("Other Projects"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#other-projects","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Before date-fns, I also tried contributing to other OSS projects to make a decision on which project to choose.")]),_v(" "),_c('p',[_c('strong',[_v("matplotlib")])]),_v(" "),_c('p',[_v("When applying for CS3281, I contributed to "),_c('a',{attrs:{"href":"https://github.com/matplotlib/matplotlib"}},[_v("matplotlib")]),_v(", a Python plotting library. I added an ellipse class for annotation box styles in "),_c('a',{attrs:{"href":"https://github.com/matplotlib/matplotlib/pull/24596"}},[_v("PR#24596")]),_v(". The PR was merged and I learned how to contribute to open-source projects by following the contributing guide. The maintainers were responsive to issues and PRs; however, I sought a project that aligned better with my interests and chosen area of expertise.")]),_v(" "),_c('p',[_c('strong',[_v("react-awesome-loaders")])]),_v(" "),_c('p',[_v("I also tried contributing to "),_c('a',{attrs:{"href":"https://github.com/ashutosh1919/react-awesome-loaders"}},[_v("react-awesome-loaders")]),_v(", a React component library, in Dec 2023. Although the library had amazing loader designs, it used Node 12 and could not be utilized in modern projects using Next.js, which has a minimum Node requirement of Node 18. I successfully updated the node version in the project and used "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("ncu")]),_v(" or "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("npm-check-updates")]),_v(" to update old dependencies in "),_c('a',{attrs:{"href":"https://github.com/ashutosh1919/react-awesome-loaders/pull/24"}},[_v("PR#24")]),_v(". Unfortunately, the documentation site could not be updated to Node 18 as it was created with "),_c('a',{attrs:{"href":"https://github.com/gregberge/smooth-doc"}},[_v("smooth-doc")]),_v(", which was not compatible with Node 18. Considering that I needed to migrate the entire documentation site to a new framework, I put the PR on hold and it was not merged.")]),_v(" "),_c('p',[_c('strong',[_v("checkstyle")])]),_v(" "),_c('p',[_v("Then I tried my hand at "),_c('a',{attrs:{"href":"https://github.com/checkstyle/checkstyle"}},[_v("checkstyle")]),_v(", a Java static code analysis tool, in Jan 2024. I removed //ok comments for the equalavoidsnull module in "),_c('a',{attrs:{"href":"https://github.com/checkstyle/checkstyle/pull/14215"}},[_v("PR#14215")]),_v(" and the PR was merged. The project maintainers were responsive and the issues for new contributors were handpicked by maintainers and labelled as \"good first issue\", \"good second issue\", \"good third issue\" and \"good fourth issue\" (1 - 3 each). This facilitated easy identification of issues for new contributors and progression through the contribution process.")]),_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('h4',{attrs:{"id":"1-tools-and-technologies"}},[_v("1. Tools and Technologies"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#1-tools-and-technologies","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_c('strong',[_v("1.1 Learning why date-fns over others")])]),_v(" "),_c('p',[_v("Working with a popular npm package, I learned extensively about the library's perks from the documentation itself. I discovered that date-fns utilizes tree-shaking to reduce the size of the final bundle and read the "),_c('a',{attrs:{"href":"https://webpack.js.org/guides/tree-shaking/"}},[_v("webpack documentation")]),_v(" to understand its functionality. Tree shaking involves dead code elimination to ensure production-ready code with minimal file size, allowing compatibility with tools like webpack, Rollup, etc.")]),_v(" "),_c('p',[_v("The project also employs a function-based API where each function is a pure function, enabling better immutability and testability. Moreover, it allows for importing only the necessary functions, enhancing performance. Additionally, the project offers a functional-programming submodule facilitating improved function composition, which allowed revisiting some concepts taught in CS1101S.")]),_v(" "),_c('p',[_c('strong',[_v("1.2 Testing npm packages")])]),_v(" "),_c('p',[_v("Since I worked on an npm package, I learned various methods to test npm packages locally beyond standard unit testing. Instead of repeatedly publishing the package to npm (which I would have done a year ago -_-), I utilized "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("npm link")]),_v(" to test the package locally in other JavaScript projects. I learned about this approach from "),_c('a',{attrs:{"href":"https://urre.me/writings/test-local-npm-packages/"}},[_v("Urban Sanden's blog")]),_v(". Additionally, I used "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("npm tsx")]),_v(" to get a TypeScript REPL (Read-Eval-Print-Loop) and required the respective date-fns function to test them within the terminal. This was facilitated by "),_c('a',{attrs:{"href":"https://tsx.is/"}},[_v("tsx")]),_v(", which stands for TypeScript Execute, and enables running TypeScript in Node.js with improved Developer Experience (watch mode, scripts, etc).")]),_v(" "),_c('p',[_c('strong',[_v("1.3 Generating documentation")])]),_v(" "),_c('p',[_v("date-fns uses TypeDoc to generate documentation for the project. I used "),_c('a',{attrs:{"href":"https://typedoc.org/guides/overview/"}},[_v("the official TypeDoc docs")]),_v(" to understand its functionality. The documentation site generator created documentation based on the TSDoc comments deployed on Firebase. The TSDoc standard was used for documenting the code, akin to JavaDoc. Having worked with multiple TypeScript projects before, this was my first experience using a TypeScript documentation generator, and it was smooth.")]),_v(" "),_c('p',[_c('strong',[_v("1.4 Date manipulation in JavaScript")])]),_v(" "),_c('p',[_v("Exploring the history of "),_c('a',{attrs:{"href":"https://medium.com/@vitorbritto/mastering-date-an-time-in-javascript-a4c12501aa6a"}},[_v("date manipulation in JavaScript")]),_v(" and its evolution over time was enlightening. I learned about various methods for date manipulation in JavaScript and compared date-fns with competing libraries like "),_c('a',{attrs:{"href":"https://momentjs.com/"}},[_v("Moment.js")]),_v(" and "),_c('a',{attrs:{"href":"https://day.js.org/"}},[_v("Day.js")]),_v(".")]),_v(" "),_c('p',[_v("Additionally, considering date-fns aims to improve Duration support, I explored the experimental ECMAScript "),_c('a',{attrs:{"href":"https://tc39.es/proposal-temporal/docs/duration.html"}},[_v("Temporal proposal")]),_v(" that seeks to provide native support for Durations in JavaScript. This proposal could potentially enhance duration functions without using our library, however, polyfills like these tend to be heavy, prompting date-fns to implement a lightweight solution as an interim API with a minimal subset of the Temporal proposal.")]),_v(" "),_c('h4',{attrs:{"id":"2-reflections-on-contributing-to-date-fns"}},[_v("2. Reflections on contributing to date-fns"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#2-reflections-on-contributing-to-date-fns","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("date-fns has a "),_c('a',{attrs:{"href":"https://date-fns.org/docs/Contributing"}},[_v("Contributing Guide")]),_v(" detailing how to contribute to the project.")]),_v(" "),_c('p',[_c('strong',[_v("2.1 Good: No more \"Move fast and break things\"")])]),_v(" "),_c('p',[_v("Having worked in fast-paced environments before, I generally embrace the \"move fast and break things\" mentality (maybe a bit too much :3 -> RepoSense issues "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/issues/2164"}},[_v("#2164")]),_v(" and "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/issues/2184"}},[_v("#2184")]),_v("). However, you do not have that \"freedom\" when working on an npm package with 20 million weekly downloads. This was a good learning experience for me as even a simple function such as "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("parseISODuration")]),_v(" required extensive discussions regarding design decisions, for example, whether undefined values should be preserved, what rules should be followed for parsing, etc., and all these should consider the standard proposals, the competitor libraries' features, and the community's feedback.")]),_v(" "),_c('p',[_c('strong',[_v("2.2 Good: Making a difference")])]),_v(" "),_c('p',[_v("While many other OSS projects I contributed to involved fixing bugs or adding small features, date-fns was more about making a difference. Since date-fns is a modular library with pure functions, contributors get to work on actual features that can be used by millions of developers worldwide. This was a great motivation for me to contribute to date-fns.")]),_v(" "),_c('p',[_c('strong',[_v("2.3 Good: Targeted mentorship")])]),_v(" "),_c('p',[_v("I reached out to the maintainers of date-fns and they were very helpful in guiding me on how to contribute to the project. This helped me work on the project for a longer period of time and make more meaningful contributions based on the project's needs instead of randomly picking issues to work on.")]),_v(" "),_c('p',[_c('strong',[_v("2.4 To improve: Community management")])]),_v(" "),_c('p',[_v("date-fns has a large community and a lot of issues are opened every day. However, the 3-5 maintainers of the project do not have the bandwidth to manage all the issues. This makes it difficult for new contributors to find issues to work on. Moreover, repetitive issues are opened multiple times, leading to duplicated efforts in PRs. This is something that can be improved in date-fns.")]),_v(" "),_c('p',[_v("Since there are too many PRs opened, the maintainers have decided to only focus on those PRs that contribute towards the project's long-term goals, which is a good strategy to ensure that the project is moving in the right direction. Sometimes, contributors are not responsive to maintainers' feedback and this leads to abandoned PRs. Instead of starting from scratch, I learned how to handle abandoned PRs by taking over one and completing the work.")]),_v(" "),_c('p',[_c('strong',[_v("2.5 To improve: Documentation contrasts")])]),_v(" "),_c('p',[_v("While date-fns has a very comprehensive documentation website, the "),_c('a',{attrs:{"href":"https://github.com/date-fns/date-fns.org"}},[_v("documentation website generator")]),_v(" did not have any contribution guidelines, because it was mainly handled by the core team. This made it difficult for me to understand how to contribute to the custom documentation website generator, and I had to reach out to the maintainers for guidance. This is understandable as the documentation site generator does not expect much community contributions, but is still something that can be improved in date-fns.")]),_v(" "),_c('h4',{attrs:{"id":"3-suggestions-for-reposense"}},[_v("3. Suggestions for RepoSense"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#3-suggestions-for-reposense","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_c('strong',[_v("3.1 One-to-one mentorship")])]),_v(" "),_c('p',[_v("date-fns has a system where maintainers provide weekly advice to contributors to help them make meaningful contributions to the project. This is a great way to guide new contributors and help them understand the project better. This is something that can be adopted by RepoSense to help new contributors make contributions that align with project goals.")]),_v(" "),_c('p',[_c('strong',[_v("3.2 Automatic documentation generation")])]),_v(" "),_c('p',[_v("Looking at the custom documentation generator for date-fns got me thinking about whether there is a way to automatically generate documentation for RepoSense, especially for the CLI arguments and the configuration files. This would help new contributors understand the project better and also assist in maintaining up-to-date documentation. Although the work required to set up the documentation generator might be substantial, it could prove to be a worthwhile investment in the long run, particularly if well-documented.")]),_v(" "),_c('p',[_c('strong',[_v("3.3 New contributor issues")])]),_v(" "),_c('p',[_v("If we aim to attract more first-time contributors to NUS-OSS projects as opposed to long-term contributors, we could establish a system akin to checkstyle's approach by labelling issues as \"good first issue,\" \"good second issue,\" and so on. By doing this, RepoSense can streamline the onboarding process and foster a welcoming community for a diverse pool of contributors. This would also help in managing the influx of new contributors and ensure that they have a smooth onboarding experience.")])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/ckcherry23/progress.html b/students/ckcherry23/progress.html index 528d917e9..594750d69 100644 --- a/students/ckcherry23/progress.html +++ b/students/ckcherry23/progress.html @@ -14,7 +14,7 @@

    Pre-Semester Progress

    Before the semester started, I made a release of RepoSense v2.5. I was mainly involved in guiding the NUS-ISC contributors and reviewing PRs for the FYP project. I also created issues and helped to manage the labels and milestones -in the issue tracker.

    Date Contribution Links
    05 May 23 Authored PR [#1996] Update frontend documentation #1999
    08 May 23 Made release RepoSense v2.5
    08 May 23 Created issue Explicit return type annotation for TypeScript functions #2002
    10 May 23 Created issue Suppress unexpected console statement warnings #2003
    11 May 23 Created issue Duplicate interface and class for Segment #2004
    25 Jun 23 Reviewed PR [#1899] Add graphic for commit diffstat #2010
    01 Jul 23 Reviewed PR [#2011] Fix bugs in UG #2013
    22 Jul 23 Reviewed PR [#1940] Increasing Cypress Timeout Configuration #2020
    22 Jul 23 Reviewed PR [#1769] Implement more Checkstyle checks #2022
    25 Jul 23 Reviewed PR [#1917] Commits view: sort everything in reverse chronological order #2024
    25 Jul 23 Reviewed PR [#1931] Update frontend integration tests for summary and zoom view #2015
    29 Jul 23 Reviewed PR [#1986] Add cypress tests for renderFilterHash #2017
    19 Aug 23 Reviewed PR [#1998] Fix hard to read text in dark labels #2029
    19 Aug 23 Reviewed PR [#1998] Fix hard to read text in dark labels #2029
    29 Aug 23 Created issue Improve frontend integration tests between summary and zoom view #2031
    19 Sep 23 Reviewed PR [#2027] Fix date range bug #2034
    19 Sep 23 Reviewed PR [#1936] Migrate c-segment.vue to typescript #2035
    19 Sep 23 Reviewed PR [#1936] Migrate c-segment-collection.vue to typescript #2036
    30 Sep 23 Reviewed PR [#1936] Migrate load-font-awesome-icons.js to typescript #2040
    30 Sep 23 Reviewed PR [#2039] Update cypress minimum requirement to 12.15.0 #2041
    04 Oct 23 Reviewed PR [#1936] Migrate random-color-gen.js to typescript #2043
    04 Oct 23 Reviewed PR [#2045] Fix cypress zoom feature test #2047
    08 Oct 23 Reviewed PR [#1936] Migrate c-ramp.vue to typescript #2037
    17 Oct 23 Reviewed PR [#1726] Update GitHub-specific references in codebase and docs #2050
    17 Oct 23 Reviewed PR [#1936] Migrate repo-sorter.js to typescript #2052
    21 Oct 23 Reviewed PR [#1936] Migrate safari_date.js to typescript #2053
    21 Oct 23 Reviewed PR [#2054] Fix zoom view bug #2055
    21 Oct 23 Reviewed PR [#1929] Add dynamic positioning support for tooltips #2056
    21 Oct 23 Reviewed PR [#1928] Fix tooltip zIndex such that it doesn't occlude next file title #2057
    20 Nov 23 Reviewed PR [#944] Improve visualization for full and partial credit #2070
    28 Dec 23 Reviewed PR [#1989] Reduce scope of try-catch block in ArgsParser::parse #2074
    28 Dec 23 Reviewed PR [#1990] Move TimeUtil ParseException throwing to ArgsParser::parse method #2075
    08 Jan 24 Reviewed PR [#944] Change to originality score and new threshold value #2072
    08 Jan 24 Reviewed PR [#2061] Add contributors section to the README #2062
    13 Jan 24 Reviewed PR Bump follow-redirects from 1.15.2 to 1.15.4 in /frontend #2079
    13 Jan 24     Reviewed PR     [#2073] Refactor RepoConfigCsvParser::processLine method to avoid arrowhead style code #2080

    CS3282 Semester Progress

    During the semester, I was actively involved in mentoring the CS3281 students and guiding them in their PRs. I met with CS3281 students at least biweekly to discuss their progress and help them with their issues. I also reviewed their PRs and provided guidance on picking up management tasks in the project. Lastly, I merged PRs and helped to manage the project's issue tracker.

    Week Contribution Links
    2 Reviewed PR [#2082] Fix typo in command in Setting Up page #2083
    2 Reviewed PR [#1980] Standardise Array Style for Frontend Files #2084
    2 Reviewed PR [#2004] Remove redundant Segment class #2085
    2 Reviewed PR [#2016] Remove hash symbol from URL when decoding hash #2086
    2 Reviewed PR [#944] Differentiate full and partial credit when group is merged #2089
    2 Reviewed PR [#1973] Remove redundant User class #2093
    2 Reviewed PR [#1224] Update .stylelintrc.json to check for spacing #2094
    3 Created issue Add date range and footer to widget #2100
    3 Reviewed PR [#2001] Extract c-authorship-file component from views/c-authorship #2096
    3 Reviewed PR [#2103] Refactor parser package for greater organisation of classes #2104
    3 Reviewed PR [#1933] Fix broken DevOps Guide link in Learning Basics #2107
    3-5 Reviewed PR [#467] Add Title Component #2102
    3-5 Reviewed PR [#2098] Add show more button for error messages #2105
    5 Created issue Update RepoSense contributors in documentation #2120
    5 Created issue Align report title with right panel #2127
    5 Reviewed PR [#2112] Move Segment CSS into segment.vue #2113
    5 Reviewed PR [#2111] Fix failing zoomFeature cypress test #2114
    5 Reviewed PR [#1532] Change mergegroups in URL to be group index for concision #2101
    6 Created issue Fix broken code highlighting in Code Panel #2134
    6 Authored PR [#2134] Fix broken code highlighting in Code Panel #2135
    6 Created issue Test code highlighting in Code Panel #2136
    6 Reviewed PR [#2128] Fix Blurry Favicon #2129
    6 Reviewed PR [#1872] Update Node version to 18 #2081
    6 Reviewed PR [#2002] Add explicit return type annotations to TypeScript functions #2125
    6 Reviewed PR Bump ip from 2.0.0 to 2.0.1 in /frontend #2133
    6 - Recess Reviewed PR [#2120] Update RepoSense contributors in documentation #2138
    Recess Reviewed PR [#944] Add originality threshold flag #2122
    Recess Reviewed PR [#2136] Add Tests for Segment CSS #2137
    Recess - 7 Reviewed PR [#2109] Add search by tag functionality #2116
    7 Reviewed PR [#944] Resolve Merge Conflict #2139
    7 Reviewed PR [#2142] Fix Vulnerabilities #2143
    8 Created issue Allow GitHub organizations to set up RepoSense reports for their repositories #2155
    8 Reviewed PR [#2123] Fix zoom bug if zUser is undefined #2126
    8 Reviewed PR [#2001] Extract c-zoom-commit-message component from views/c-zoom #2132
    8-10 Reviewed PR [#2130] Add highlight and scroll to group #2131
    10 Reviewed PR [#2151] Update LoadingOverlay and Minor Versions of Node Dependencies #2152
    10 Reviewed PR [#2109] Add search by tag functionality #2167
    10 Reviewed PR [#2158] Add More Documentation for Title Component #2159
    10 - 11 Reviewed PR [#944] Implement authorship analysis #2140
    11 Reviewed PR [#2002] Add explicit return type annotations to TypeScript functions in *.vue files #2125
    11 Reviewed PR [#2151] Update Stylelint #2153
    11 Reviewed PR Add bin/ to .gitignore #2179
    12 Reviewed PR [#2151] Update CSS-related Major Dependencies #2154
    12 Reviewed PR Fix lint warnings #2182
    12 Reviewed PR Add more repos to cypress tests #2188
    12 Reviewed PR [#2177] Migrate to Java 11 Syntax and Features #2183
    12 Reviewed PR [#2184] Fix Inconsistent Line Number Colours #2185
    12 Reviewed PR [#2151] Update Typescript-related Major Dependencies #2166
    13 Reviewed PR Allow CI to pass if Codecov fails #2189
    13 Reviewed PR [#2001] Extract c-file-type-checkboxes from Summary, Authorship and Zoom #2173
    13 Investigated issue Lines changed not appearing correctly #2193
    13 - Recess Reviewed PR Add optimise timeline feature #2180
    Recess Created issue Surge preview deployments for many of our latest PRs are not working #2194
    Recess Reviewed PR [#2148] Show tags on the ramp chart #2163

    Other Internal Project Contributions

    I also contributed to some of the internal projects by reviewing PRs and creating issues.

    Week Contribution Links Notes
    5 Created issue in TEAMMATES Autosave and restore progress if user navigates away #12749 Requested for periodic autosave and default restore progress feature to be implemented in TEAMMATES.
    8 Reviewed PR in MarkBind MarkBind Template for Student Portfolio #2398 Reviewed portfolio design and requested for more documentation. Got RepoSense widget to be included in the portfolio to showcase code projects.
    +in the issue tracker.

    Date Contribution Links
    05 May 23 Authored PR [#1996] Update frontend documentation #1999
    08 May 23 Made release RepoSense v2.5
    08 May 23 Created issue Explicit return type annotation for TypeScript functions #2002
    10 May 23 Created issue Suppress unexpected console statement warnings #2003
    11 May 23 Created issue Duplicate interface and class for Segment #2004
    25 Jun 23 Reviewed PR [#1899] Add graphic for commit diffstat #2010
    01 Jul 23 Reviewed PR [#2011] Fix bugs in UG #2013
    22 Jul 23 Reviewed PR [#1940] Increasing Cypress Timeout Configuration #2020
    22 Jul 23 Reviewed PR [#1769] Implement more Checkstyle checks #2022
    25 Jul 23 Reviewed PR [#1917] Commits view: sort everything in reverse chronological order #2024
    25 Jul 23 Reviewed PR [#1931] Update frontend integration tests for summary and zoom view #2015
    29 Jul 23 Reviewed PR [#1986] Add cypress tests for renderFilterHash #2017
    19 Aug 23 Reviewed PR [#1998] Fix hard to read text in dark labels #2029
    19 Aug 23 Reviewed PR [#1998] Fix hard to read text in dark labels #2029
    29 Aug 23 Created issue Improve frontend integration tests between summary and zoom view #2031
    19 Sep 23 Reviewed PR [#2027] Fix date range bug #2034
    19 Sep 23 Reviewed PR [#1936] Migrate c-segment.vue to typescript #2035
    19 Sep 23 Reviewed PR [#1936] Migrate c-segment-collection.vue to typescript #2036
    30 Sep 23 Reviewed PR [#1936] Migrate load-font-awesome-icons.js to typescript #2040
    30 Sep 23 Reviewed PR [#2039] Update cypress minimum requirement to 12.15.0 #2041
    04 Oct 23 Reviewed PR [#1936] Migrate random-color-gen.js to typescript #2043
    04 Oct 23 Reviewed PR [#2045] Fix cypress zoom feature test #2047
    08 Oct 23 Reviewed PR [#1936] Migrate c-ramp.vue to typescript #2037
    17 Oct 23 Reviewed PR [#1726] Update GitHub-specific references in codebase and docs #2050
    17 Oct 23 Reviewed PR [#1936] Migrate repo-sorter.js to typescript #2052
    21 Oct 23 Reviewed PR [#1936] Migrate safari_date.js to typescript #2053
    21 Oct 23 Reviewed PR [#2054] Fix zoom view bug #2055
    21 Oct 23 Reviewed PR [#1929] Add dynamic positioning support for tooltips #2056
    21 Oct 23 Reviewed PR [#1928] Fix tooltip zIndex such that it doesn't occlude next file title #2057
    20 Nov 23 Reviewed PR [#944] Improve visualization for full and partial credit #2070
    28 Dec 23 Reviewed PR [#1989] Reduce scope of try-catch block in ArgsParser::parse #2074
    28 Dec 23 Reviewed PR [#1990] Move TimeUtil ParseException throwing to ArgsParser::parse method #2075
    08 Jan 24 Reviewed PR [#944] Change to originality score and new threshold value #2072
    08 Jan 24 Reviewed PR [#2061] Add contributors section to the README #2062
    13 Jan 24 Reviewed PR Bump follow-redirects from 1.15.2 to 1.15.4 in /frontend #2079
    13 Jan 24     Reviewed PR     [#2073] Refactor RepoConfigCsvParser::processLine method to avoid arrowhead style code #2080

    CS3282 Semester Progress

    During the semester, I was actively involved in mentoring the CS3281 students and guiding them in their PRs. I met with CS3281 students at least biweekly to discuss their progress and help them with their issues. I also reviewed their PRs and provided guidance on picking up management tasks in the project. Lastly, I merged PRs and helped to manage the project's issue tracker.

    Week Contribution Links
    2 Reviewed PR [#2082] Fix typo in command in Setting Up page #2083
    2 Reviewed PR [#1980] Standardise Array Style for Frontend Files #2084
    2 Reviewed PR [#2004] Remove redundant Segment class #2085
    2 Reviewed PR [#2016] Remove hash symbol from URL when decoding hash #2086
    2 Reviewed PR [#944] Differentiate full and partial credit when group is merged #2089
    2 Reviewed PR [#1973] Remove redundant User class #2093
    2 Reviewed PR [#1224] Update .stylelintrc.json to check for spacing #2094
    3 Created issue Add date range and footer to widget #2100
    3 Reviewed PR [#2001] Extract c-authorship-file component from views/c-authorship #2096
    3 Reviewed PR [#2103] Refactor parser package for greater organisation of classes #2104
    3 Reviewed PR [#1933] Fix broken DevOps Guide link in Learning Basics #2107
    3-5 Reviewed PR [#467] Add Title Component #2102
    3-5 Reviewed PR [#2098] Add show more button for error messages #2105
    5 Created issue Update RepoSense contributors in documentation #2120
    5 Created issue Align report title with right panel #2127
    5 Reviewed PR [#2112] Move Segment CSS into segment.vue #2113
    5 Reviewed PR [#2111] Fix failing zoomFeature cypress test #2114
    5 Reviewed PR [#1532] Change mergegroups in URL to be group index for concision #2101
    6 Created issue Fix broken code highlighting in Code Panel #2134
    6 Authored PR [#2134] Fix broken code highlighting in Code Panel #2135
    6 Created issue Test code highlighting in Code Panel #2136
    6 Reviewed PR [#2128] Fix Blurry Favicon #2129
    6 Reviewed PR [#1872] Update Node version to 18 #2081
    6 Reviewed PR [#2002] Add explicit return type annotations to TypeScript functions #2125
    6 Reviewed PR Bump ip from 2.0.0 to 2.0.1 in /frontend #2133
    6 - Recess Reviewed PR [#2120] Update RepoSense contributors in documentation #2138
    Recess Reviewed PR [#944] Add originality threshold flag #2122
    Recess Reviewed PR [#2136] Add Tests for Segment CSS #2137
    Recess - 7 Reviewed PR [#2109] Add search by tag functionality #2116
    7 Reviewed PR [#944] Resolve Merge Conflict #2139
    7 Reviewed PR [#2142] Fix Vulnerabilities #2143
    8 Created issue Allow GitHub organizations to set up RepoSense reports for their repositories #2155
    8 Reviewed PR [#2123] Fix zoom bug if zUser is undefined #2126
    8 Reviewed PR [#2001] Extract c-zoom-commit-message component from views/c-zoom #2132
    8-10 Reviewed PR [#2130] Add highlight and scroll to group #2131
    10 Reviewed PR [#2151] Update LoadingOverlay and Minor Versions of Node Dependencies #2152
    10 Reviewed PR [#2109] Add search by tag functionality #2167
    10 Reviewed PR [#2158] Add More Documentation for Title Component #2159
    10 - 11 Reviewed PR [#944] Implement authorship analysis #2140
    11 Reviewed PR [#2002] Add explicit return type annotations to TypeScript functions in *.vue files #2125
    11 Reviewed PR [#2151] Update Stylelint #2153
    11 Reviewed PR Add bin/ to .gitignore #2179
    12 Reviewed PR [#2151] Update CSS-related Major Dependencies #2154
    12 Reviewed PR Fix lint warnings #2182
    12 Reviewed PR Add more repos to cypress tests #2188
    12 Reviewed PR [#2177] Migrate to Java 11 Syntax and Features #2183
    12 Reviewed PR [#2184] Fix Inconsistent Line Number Colours #2185
    12 Reviewed PR [#2151] Update Typescript-related Major Dependencies #2166
    13 Reviewed PR Allow CI to pass if Codecov fails #2189
    13 Reviewed PR [#2001] Extract c-file-type-checkboxes from Summary, Authorship and Zoom #2173
    13 Investigated issue Lines changed not appearing correctly #2193
    13 - Recess Reviewed PR Add optimise timeline feature #2180
    Recess Created issue Surge preview deployments for many of our latest PRs are not working #2194
    Recess Reviewed PR [#2148] Show tags on the ramp chart #2163

    Other Internal Project Contributions

    I also contributed to some of the internal projects by reviewing PRs and creating issues.

    Week Contribution Links Notes
    5 Created issue in TEAMMATES Autosave and restore progress if user navigates away #12749 Requested for periodic autosave and default restore progress feature to be implemented in TEAMMATES.
    8 Reviewed PR in MarkBind MarkBind Template for Student Portfolio #2398 Reviewed portfolio design and requested for more documentation. Got RepoSense widget to be included in the portfolio to showcase code projects.
    diff --git a/students/ckcherry23/progress.page-vue-render.js b/students/ckcherry23/progress.page-vue-render.js index 43fc8be05..ecbb37f49 100644 --- a/students/ckcherry23/progress.page-vue-render.js +++ b/students/ckcherry23/progress.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('h3',{attrs:{"id":"pre-semester-progress"}},[_v("Pre-Semester Progress"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#pre-semester-progress","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Before the semester started, I made a release of RepoSense v2.5. I was mainly involved in guiding the NUS-ISC\ncontributors and reviewing PRs for the FYP project. I also created issues and helped to manage the labels and milestones\nin the issue tracker.")]),_v(" "),_c('div',{staticClass:"table-responsive"},[_c('table',{staticClass:"markbind-table table table-bordered table-striped"},[_c('thead',[_c('tr',[_c('th',[_v("Date")]),_v(" "),_c('th',[_v("Contribution")]),_v(" "),_c('th',[_v("Links")])])]),_v(" "),_c('tbody',[_c('tr',[_c('td',[_v("05 May 23")]),_v(" "),_c('td',[_v("Authored PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/1999"}},[_v("[#1996] Update frontend documentation #1999")])])]),_v(" "),_c('tr',[_c('td',[_v("08 May 23")]),_v(" "),_c('td',[_v("Made release")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/releases/tag/v2.5"}},[_v("RepoSense v2.5")])])]),_v(" "),_c('tr',[_c('td',[_v("08 May 23")]),_v(" "),_c('td',[_v("Created issue")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/issues/2002"}},[_v("Explicit return type annotation for TypeScript functions #2002")])])]),_v(" "),_c('tr',[_c('td',[_v("10 May 23")]),_v(" "),_c('td',[_v("Created issue")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/issues/2003"}},[_v("Suppress unexpected console statement warnings #2003")])])]),_v(" "),_c('tr',[_c('td',[_v("11 May 23")]),_v(" "),_c('td',[_v("Created issue")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/issues/2004"}},[_v("Duplicate interface and class for Segment #2004")])])]),_v(" "),_c('tr',[_c('td',[_v("25 Jun 23")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2010"}},[_v("[#1899] Add graphic for commit diffstat #2010")])])]),_v(" "),_c('tr',[_c('td',[_v("01 Jul 23")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2013"}},[_v("[#2011] Fix bugs in UG #2013")])])]),_v(" "),_c('tr',[_c('td',[_v("22 Jul 23")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2020"}},[_v("[#1940] Increasing Cypress Timeout Configuration #2020")])])]),_v(" "),_c('tr',[_c('td',[_v("22 Jul 23")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2022"}},[_v("[#1769] Implement more Checkstyle checks #2022")])])]),_v(" "),_c('tr',[_c('td',[_v("25 Jul 23")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2024"}},[_v("[#1917] Commits view: sort everything in reverse chronological order #2024")])])]),_v(" "),_c('tr',[_c('td',[_v("25 Jul 23")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2015"}},[_v("[#1931] Update frontend integration tests for summary and zoom view #2015")])])]),_v(" "),_c('tr',[_c('td',[_v("29 Jul 23")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2017"}},[_v("[#1986] Add cypress tests for renderFilterHash #2017")])])]),_v(" "),_c('tr',[_c('td',[_v("19 Aug 23")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2029"}},[_v("[#1998] Fix hard to read text in dark labels #2029")])])]),_v(" "),_c('tr',[_c('td',[_v("19 Aug 23")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2029"}},[_v("[#1998] Fix hard to read text in dark labels #2029")])])]),_v(" "),_c('tr',[_c('td',[_v("29 Aug 23")]),_v(" "),_c('td',[_v("Created issue")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/issues/2031"}},[_v("Improve frontend integration tests between summary and zoom view #2031")])])]),_v(" "),_c('tr',[_c('td',[_v("19 Sep 23")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2034"}},[_v("[#2027] Fix date range bug #2034")])])]),_v(" "),_c('tr',[_c('td',[_v("19 Sep 23")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2035"}},[_v("[#1936] Migrate c-segment.vue to typescript #2035")])])]),_v(" "),_c('tr',[_c('td',[_v("19 Sep 23")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2036"}},[_v("[#1936] Migrate c-segment-collection.vue to typescript #2036")])])]),_v(" "),_c('tr',[_c('td',[_v("30 Sep 23")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2040"}},[_v("[#1936] Migrate load-font-awesome-icons.js to typescript #2040")])])]),_v(" "),_c('tr',[_c('td',[_v("30 Sep 23")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2041"}},[_v("[#2039] Update cypress minimum requirement to 12.15.0 #2041")])])]),_v(" "),_c('tr',[_c('td',[_v("04 Oct 23")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2043"}},[_v("[#1936] Migrate random-color-gen.js to typescript #2043")])])]),_v(" "),_c('tr',[_c('td',[_v("04 Oct 23")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2047"}},[_v("[#2045] Fix cypress zoom feature test #2047")])])]),_v(" "),_c('tr',[_c('td',[_v("08 Oct 23")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2037"}},[_v("[#1936] Migrate c-ramp.vue to typescript #2037")])])]),_v(" "),_c('tr',[_c('td',[_v("17 Oct 23")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2050"}},[_v("[#1726] Update GitHub-specific references in codebase and docs #2050")])])]),_v(" "),_c('tr',[_c('td',[_v("17 Oct 23")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2052"}},[_v("[#1936] Migrate repo-sorter.js to typescript #2052")])])]),_v(" "),_c('tr',[_c('td',[_v("21 Oct 23")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2053"}},[_v("[#1936] Migrate safari_date.js to typescript #2053")])])]),_v(" "),_c('tr',[_c('td',[_v("21 Oct 23")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2055"}},[_v("[#2054] Fix zoom view bug #2055")])])]),_v(" "),_c('tr',[_c('td',[_v("21 Oct 23")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2056"}},[_v("[#1929] Add dynamic positioning support for tooltips #2056")])])]),_v(" "),_c('tr',[_c('td',[_v("21 Oct 23")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2057"}},[_v("[#1928] Fix tooltip zIndex such that it doesn't occlude next file title #2057")])])]),_v(" "),_c('tr',[_c('td',[_v("20 Nov 23")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2070"}},[_v("[#944] Improve visualization for full and partial credit #2070")])])]),_v(" "),_c('tr',[_c('td',[_v("28 Dec 23")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2074"}},[_v("[#1989] Reduce scope of try-catch block in ArgsParser::parse #2074")])])]),_v(" "),_c('tr',[_c('td',[_v("28 Dec 23")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2075"}},[_v("[#1990] Move TimeUtil ParseException throwing to ArgsParser::parse method #2075")])])]),_v(" "),_c('tr',[_c('td',[_v("08 Jan 24")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2072"}},[_v("[#944] Change to originality score and new threshold value #2072")])])]),_v(" "),_c('tr',[_c('td',[_v("08 Jan 24")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2062"}},[_v("[#2061] Add contributors section to the README #2062")])])]),_v(" "),_c('tr',[_c('td',[_v("13 Jan 24")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2079"}},[_v("Bump follow-redirects from 1.15.2 to 1.15.4 in /frontend #2079")])])]),_v(" "),_c('tr',[_c('td',[_v("13 Jan 24    ")]),_v(" "),_c('td',[_v("Reviewed PR    ")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2080"}},[_v("[#2073] Refactor RepoConfigCsvParser::processLine method to avoid arrowhead style code #2080")])])])])])]),_c('h3',{attrs:{"id":"cs3282-semester-progress"}},[_v("CS3282 Semester Progress"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#cs3282-semester-progress","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("During the semester, I was actively involved in mentoring the CS3281 students and guiding them in their PRs. I met with CS3281 students at least biweekly to discuss their progress and help them with their issues. I also reviewed their PRs and provided guidance on picking up management tasks in the project. Lastly, I merged PRs and helped to manage the project's issue tracker.")]),_v(" "),_c('div',{staticClass:"table-responsive"},[_c('table',{staticClass:"markbind-table table table-bordered table-striped"},[_c('thead',[_c('tr',[_c('th',[_v("Week")]),_v(" "),_c('th',[_v("Contribution")]),_v(" "),_c('th',[_v("Links")])])]),_v(" "),_c('tbody',[_c('tr',[_c('td',[_v("2")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2083"}},[_v("[#2082] Fix typo in command in Setting Up page #2083")])])]),_v(" "),_c('tr',[_c('td',[_v("2")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2084"}},[_v("[#1980] Standardise Array Style for Frontend Files #2084")])])]),_v(" "),_c('tr',[_c('td',[_v("2")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2085"}},[_v("[#2004] Remove redundant Segment class #2085")])])]),_v(" "),_c('tr',[_c('td',[_v("2")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2086"}},[_v("[#2016] Remove hash symbol from URL when decoding hash #2086")])])]),_v(" "),_c('tr',[_c('td',[_v("2")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2089"}},[_v("[#944] Differentiate full and partial credit when group is merged #2089")])])]),_v(" "),_c('tr',[_c('td',[_v("2")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2093"}},[_v("[#1973] Remove redundant User class #2093")])])]),_v(" "),_c('tr',[_c('td',[_v("2")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2094"}},[_v("[#1224] Update .stylelintrc.json to check for spacing #2094")])])]),_v(" "),_c('tr',[_c('td',[_v("3")]),_v(" "),_c('td',[_v("Created issue")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/issues/2100"}},[_v("Add date range and footer to widget #2100")])])]),_v(" "),_c('tr',[_c('td',[_v("3")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2096"}},[_v("[#2001] Extract c-authorship-file component from views/c-authorship #2096")])])]),_v(" "),_c('tr',[_c('td',[_v("3")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2104"}},[_v("[#2103] Refactor parser package for greater organisation of classes #2104")])])]),_v(" "),_c('tr',[_c('td',[_v("3")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2107"}},[_v("[#1933] Fix broken DevOps Guide link in Learning Basics #2107")])])]),_v(" "),_c('tr',[_c('td',[_v("3-5")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2102"}},[_v("[#467] Add Title Component #2102")])])]),_v(" "),_c('tr',[_c('td',[_v("3-5")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2105"}},[_v("[#2098] Add show more button for error messages #2105")])])]),_v(" "),_c('tr',[_c('td',[_v("5")]),_v(" "),_c('td',[_v("Created issue")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/issues/2120"}},[_v("Update RepoSense contributors in documentation #2120")])])]),_v(" "),_c('tr',[_c('td',[_v("5")]),_v(" "),_c('td',[_v("Created issue")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/issues/2127"}},[_v("Align report title with right panel #2127")])])]),_v(" "),_c('tr',[_c('td',[_v("5")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2113"}},[_v("[#2112] Move Segment CSS into segment.vue #2113")])])]),_v(" "),_c('tr',[_c('td',[_v("5")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2114"}},[_v("[#2111] Fix failing zoomFeature cypress test #2114")])])]),_v(" "),_c('tr',[_c('td',[_v("5")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2101"}},[_v("[#1532] Change mergegroups in URL to be group index for concision #2101")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Created issue")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/issues/2134"}},[_v("Fix broken code highlighting in Code Panel #2134")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Authored PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2135"}},[_v("[#2134] Fix broken code highlighting in Code Panel #2135")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Created issue")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/issues/2136"}},[_v("Test code highlighting in Code Panel #2136")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2129"}},[_v("[#2128] Fix Blurry Favicon #2129")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2081"}},[_v("[#1872] Update Node version to 18 #2081")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2125"}},[_v("[#2002] Add explicit return type annotations to TypeScript functions #2125")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2133"}},[_v("Bump ip from 2.0.0 to 2.0.1 in /frontend #2133")])])]),_v(" "),_c('tr',[_c('td',[_v("6 - Recess")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2138"}},[_v("[#2120] Update RepoSense contributors in documentation #2138")])])]),_v(" "),_c('tr',[_c('td',[_v("Recess")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2122"}},[_v("[#944] Add originality threshold flag #2122")])])]),_v(" "),_c('tr',[_c('td',[_v("Recess")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2137"}},[_v("[#2136] Add Tests for Segment CSS #2137")])])]),_v(" "),_c('tr',[_c('td',[_v("Recess - 7")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2116"}},[_v("[#2109] Add search by tag functionality #2116")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2139"}},[_v("[#944] Resolve Merge Conflict #2139")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2143"}},[_v("[#2142] Fix Vulnerabilities #2143")])])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_v("Created issue")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/issues/2155"}},[_v("Allow GitHub organizations to set up RepoSense reports for their repositories #2155")])])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2126"}},[_v("[#2123] Fix zoom bug if zUser is undefined #2126")])])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2132"}},[_v("[#2001] Extract c-zoom-commit-message component from views/c-zoom #2132")])])]),_v(" "),_c('tr',[_c('td',[_v("8-10")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2131"}},[_v("[#2130] Add highlight and scroll to group #2131")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2152"}},[_v("[#2151] Update LoadingOverlay and Minor Versions of Node Dependencies #2152")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2167"}},[_v("[#2109] Add search by tag functionality #2167")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2159"}},[_v("[#2158] Add More Documentation for Title Component #2159")])])]),_v(" "),_c('tr',[_c('td',[_v("10 - 11")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2140"}},[_v("[#944] Implement authorship analysis #2140")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2125"}},[_v("[#2002] Add explicit return type annotations to TypeScript functions in *.vue files #2125")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2153"}},[_v("[#2151] Update Stylelint #2153")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2179"}},[_v("Add bin/ to .gitignore #2179")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2154"}},[_v("[#2151] Update CSS-related Major Dependencies #2154")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2182"}},[_v("Fix lint warnings #2182")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2188"}},[_v("Add more repos to cypress tests #2188")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2183"}},[_v("[#2177] Migrate to Java 11 Syntax and Features #2183")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2185"}},[_v("[#2184] Fix Inconsistent Line Number Colours #2185")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2166"}},[_v("[#2151] Update Typescript-related Major Dependencies #2166")])])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2189"}},[_v("Allow CI to pass if Codecov fails #2189")])])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2173"}},[_v("[#2001] Extract c-file-type-checkboxes from Summary, Authorship and Zoom #2173")])])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_v("Investigated issue")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/issues/2193"}},[_v("Lines changed not appearing correctly #2193")])])]),_v(" "),_c('tr',[_c('td',[_v("13 - Recess")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2180"}},[_v("Add optimise timeline feature #2180")])])]),_v(" "),_c('tr',[_c('td',[_v("Recess")]),_v(" "),_c('td',[_v("Created issue")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/issues/2194"}},[_v("Surge preview deployments for many of our latest PRs are not working #2194")])])]),_v(" "),_c('tr',[_c('td',[_v("Recess")]),_v(" "),_c('td',[_v("Reviewed PR")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2163"}},[_v("[#2148] Show tags on the ramp chart #2163")])])])])])]),_c('h3',{attrs:{"id":"other-internal-project-contributions"}},[_v("Other Internal Project Contributions"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#other-internal-project-contributions","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("I also contributed to some of the internal projects by reviewing PRs and creating issues.")]),_v(" "),_c('div',{staticClass:"table-responsive"},[_c('table',{staticClass:"markbind-table table table-bordered table-striped"},[_c('thead',[_c('tr',[_c('th',[_v("Week")]),_v(" "),_c('th',[_v("Contribution")]),_v(" "),_c('th',[_v("Links")]),_v(" "),_c('th',[_v("Notes")])])]),_v(" "),_c('tbody',[_c('tr',[_c('td',[_v("5")]),_v(" "),_c('td',[_v("Created issue in TEAMMATES")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/issues/12749"}},[_v("Autosave and restore progress if user navigates away #12749")])]),_v(" "),_c('td',[_v("Requested for periodic autosave and default restore progress feature to be implemented in TEAMMATES.")])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_v("Reviewed PR in MarkBind")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind/pull/2398"}},[_v("MarkBind Template for Student Portfolio #2398")])]),_v(" "),_c('td',[_v("Reviewed portfolio design and requested for more documentation. Got RepoSense widget to be included in the portfolio to showcase code projects.")])])])])])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/dishenggg/info.html b/students/dishenggg/info.html index 304475fdf..7ebc676bf 100644 --- a/students/dishenggg/info.html +++ b/students/dishenggg/info.html @@ -12,7 +12,7 @@ const baseUrl = '/2024' - + diff --git a/students/dishenggg/info.page-vue-render.js b/students/dishenggg/info.page-vue-render.js index 0af3c9cb3..c0e851a36 100644 --- a/students/dishenggg/info.page-vue-render.js +++ b/students/dishenggg/info.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('p',[_c('span',{attrs:{"id":"github"}},[_c('a',{attrs:{"href":"https://www.github.com/dishenggg"}},[_v("https://www.github.com/dishenggg")])])]),_v(" "),_c('p',[_c('span',{attrs:{"id":"projects"}},[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates"}},[_v("TEAMMATES")])])])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/dishenggg/knowledge.html b/students/dishenggg/knowledge.html index f4a36399c..efc09ecd6 100644 --- a/students/dishenggg/knowledge.html +++ b/students/dishenggg/knowledge.html @@ -12,7 +12,7 @@ const baseUrl = '/2024' -

    Hibernate

    session.flush()

    EntityManagers do not always immediate execute the underly SQL statement. One such example is when we create and persist a new entity, the createdAt timestamp is not updated in the entity object in our application until we call flush().

    This is because by calling flush() we can ensure that all outstanding SQL statements are executed and that the persistence context and the db is synchronized.

    Persistent entities

    Persistent entities are entities that are known by the persistence provider, Hibernate in this case. An entity(object) can be made persistent by either saving or reading an object from a session. Any changes (e.g., calling a setter) made to persistent entities are automatically persisted into the database.

    We can stop hibernate from tracking and automatically updating the entities by calling detach(Entity) or evict(Entity). This will result in the entity becoming detached. While detached, Hibernate will have no longer track the changes made to the entity. To save the changes to the database or make the entity persistent again, we can use merge(Entity).

    References

    While using the new SQL db, we often find ourselves needing to refer to another related entity for example FeedbackSessionLogs.setStudent(studentEntity). This would often require us to query the db for the object and then call the setter. This is inefficient especially if we already have information like the studentEntity's primary key.

    Hibernate provides a getReference() method which returns a proxy to an entity, that only contains a primary key, and other information are lazily fetched. While creating the proxy, Hibernate does not query the db. Here is an article that goes through different scenarios using reference to see which operations would result in Hibernate performing a SELECT query and which does not. It also includes some information on cached entities in Hibernate.

    It is important to note that, since Hibernate does not check that the entity actually exists in the db on creation of the proxy, the proxy might contain a primary key that does not exist in the db. The application should be designed to handle such scenarios when using references. Here is more information on the difference between getReference() and find().

    Testing

    Mockito

    In unit testing, a single component is isolated and tested by replacing its dependencies with stubs/mocks. This allows us to test only the behaviour of the SUT.

    Mockito provides multiple methods that help to verify the behaviour of the SUT and also determine how the mocked dependencies are supposed to behave.

    • verify() this method allows us to verify that a method of a mocked class is called. It can be combined with other methods like times(x) which allowsus to verify that the method is only called x times.

    • Argument matchers like anyInt(), anyString() and allows us to define a custom matcher using argThat(). These argument matchers can be used to ensure that the correct arguments are being passed to the other dependencies. This is useful if the method you are testing does not return a value useful for determining the correctness of the method.

    • when() and thenReturn() These are methods that allow us to define the behaviour of other dependencies that are not under test.

      For e.g., when(mockLogic.someMethod(args)).thenReturn(value) makes it such that when the SUT invokes someMethod() with args from the mockLogic class, value is will be returned by someMethod(args).

    GCP

    Learnt about how the different features that are provided by GCP and other third parties come together to make Teammates possible.

    Most of the information is from the Platform Guide in the teammates-ops repo.

    • Setting up OAuth 2.0 to allow users to login with their google credentials
    • Google cloud storage
    • Google cloud SQL
    • Debugging using logs from Google Cloud's logging service
    • Setting up a cron job
    • Using email sending services like Mailjet
    • Using DBeaver to insepct and manipulate the SQL database
    +

    Hibernate

    session.flush()

    EntityManagers do not always immediate execute the underly SQL statement. One such example is when we create and persist a new entity, the createdAt timestamp is not updated in the entity object in our application until we call flush().

    This is because by calling flush() we can ensure that all outstanding SQL statements are executed and that the persistence context and the db is synchronized.

    Persistent entities

    Persistent entities are entities that are known by the persistence provider, Hibernate in this case. An entity(object) can be made persistent by either saving or reading an object from a session. Any changes (e.g., calling a setter) made to persistent entities are automatically persisted into the database.

    We can stop hibernate from tracking and automatically updating the entities by calling detach(Entity) or evict(Entity). This will result in the entity becoming detached. While detached, Hibernate will have no longer track the changes made to the entity. To save the changes to the database or make the entity persistent again, we can use merge(Entity).

    References

    While using the new SQL db, we often find ourselves needing to refer to another related entity for example FeedbackSessionLogs.setStudent(studentEntity). This would often require us to query the db for the object and then call the setter. This is inefficient especially if we already have information like the studentEntity's primary key.

    Hibernate provides a getReference() method which returns a proxy to an entity, that only contains a primary key, and other information are lazily fetched. While creating the proxy, Hibernate does not query the db. Here is an article that goes through different scenarios using reference to see which operations would result in Hibernate performing a SELECT query and which does not. It also includes some information on cached entities in Hibernate.

    It is important to note that, since Hibernate does not check that the entity actually exists in the db on creation of the proxy, the proxy might contain a primary key that does not exist in the db. The application should be designed to handle such scenarios when using references. Here is more information on the difference between getReference() and find().

    Testing

    Mockito

    In unit testing, a single component is isolated and tested by replacing its dependencies with stubs/mocks. This allows us to test only the behaviour of the SUT.

    Mockito provides multiple methods that help to verify the behaviour of the SUT and also determine how the mocked dependencies are supposed to behave.

    • verify() this method allows us to verify that a method of a mocked class is called. It can be combined with other methods like times(x) which allowsus to verify that the method is only called x times.

    • Argument matchers like anyInt(), anyString() and allows us to define a custom matcher using argThat(). These argument matchers can be used to ensure that the correct arguments are being passed to the other dependencies. This is useful if the method you are testing does not return a value useful for determining the correctness of the method.

    • when() and thenReturn() These are methods that allow us to define the behaviour of other dependencies that are not under test.

      For e.g., when(mockLogic.someMethod(args)).thenReturn(value) makes it such that when the SUT invokes someMethod() with args from the mockLogic class, value is will be returned by someMethod(args).

    GCP

    Learnt about how the different features that are provided by GCP and other third parties come together to make Teammates possible.

    Most of the information is from the Platform Guide in the teammates-ops repo.

    • Setting up OAuth 2.0 to allow users to login with their google credentials
    • Google cloud storage
    • Google cloud SQL
    • Debugging using logs from Google Cloud's logging service
    • Setting up a cron job
    • Using email sending services like Mailjet
    • Using DBeaver to insepct and manipulate the SQL database
    diff --git a/students/dishenggg/knowledge.page-vue-render.js b/students/dishenggg/knowledge.page-vue-render.js index c777c9521..6eedf7a96 100644 --- a/students/dishenggg/knowledge.page-vue-render.js +++ b/students/dishenggg/knowledge.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('h3',{attrs:{"id":"hibernate"}},[_v("Hibernate"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#hibernate","onclick":"event.stopPropagation()"}})]),_v(" "),_c('h4',{attrs:{"id":"session-flush"}},[_c('a',{attrs:{"href":"https://www.baeldung.com/spring-jpa-flush"}},[_v("session.flush()")]),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#session-flush","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("EntityManagers do not always immediate execute the underly SQL statement. One such example is when we create and persist a new entity, the createdAt timestamp is not updated in the entity object in our application until we call flush().")]),_v(" "),_c('p',[_v("This is because by calling flush() we can ensure that all outstanding SQL statements are executed and that the persistence context and the db is synchronized.")]),_v(" "),_c('h4',{attrs:{"id":"persistent-entities"}},[_v("Persistent entities"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#persistent-entities","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_c('a',{attrs:{"href":"https://www.baeldung.com/hibernate-session-object-states"}},[_v("Persistent entities")]),_v(" are entities that are known by the persistence provider, Hibernate in this case. An entity(object) can be made persistent by either saving or reading an object from a session. Any "),_c('a',{attrs:{"href":"https://docs.jboss.org/hibernate/orm/4.0/devguide/en-US/html_single/#d0e1739"}},[_v("changes (e.g., calling a setter) made to persistent entities are automatically persisted into the database")]),_v(".")]),_v(" "),_c('p',[_v("We can stop hibernate from tracking and automatically updating the entities by calling "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("detach(Entity)")]),_v(" or "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("evict(Entity)")]),_v(". This will result in the entity becoming detached. While detached, Hibernate will have no longer track the changes made to the entity. To save the changes to the database or make the entity persistent again, we can use "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("merge(Entity)")]),_v(".")]),_v(" "),_c('h4',{attrs:{"id":"references"}},[_v("References"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#references","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("While using the new SQL db, we often find ourselves needing to refer to another related entity for example "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("FeedbackSessionLogs.setStudent(studentEntity)")]),_v(". This would often require us to query the db for the object and then call the setter. This is inefficient especially if we already have information like the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("studentEntity")]),_v("'s primary key.")]),_v(" "),_c('p',[_v("Hibernate provides a "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("getReference()")]),_v(" method which returns a proxy to an entity, that only contains a primary key, and other information are lazily fetched. While creating the proxy, Hibernate does not query the db. "),_c('a',{attrs:{"href":"https://www.baeldung.com/jpa-entity-manager-get-reference"}},[_v("Here")]),_v(" is an article that goes through different scenarios using reference to see which operations would result in Hibernate performing a SELECT query and which does not. It also includes some information on cached entities in Hibernate.")]),_v(" "),_c('p',[_v("It is important to note that, since Hibernate does not check that the entity actually exists in the db on creation of the proxy, the proxy might contain a primary key that does not exist in the db. The application should be designed to handle such scenarios when using references. "),_c('a',{attrs:{"href":"https://thorben-janssen.com/jpa-getreference/#the-getreference-method"}},[_v("Here")]),_v(" is more information on the difference between "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("getReference()")]),_v(" and "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("find()")]),_v(".")]),_v(" "),_c('h3',{attrs:{"id":"testing"}},[_v("Testing"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#testing","onclick":"event.stopPropagation()"}})]),_v(" "),_c('h4',{attrs:{"id":"mockito"}},[_v("Mockito"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#mockito","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("In unit testing, a single component is isolated and tested by replacing its dependencies with stubs/mocks. This allows us to test only the behaviour of the SUT.")]),_v(" "),_c('p',[_c('a',{attrs:{"href":"https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html"}},[_v("Mockito")]),_v(" provides multiple methods that help to verify the behaviour of the SUT and also determine how the mocked dependencies are supposed to behave.")]),_v(" "),_c('ul',[_c('li',[_c('p',[_c('a',{attrs:{"href":"https://www.baeldung.com/mockito-verify"}},[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("verify()")])]),_v(" this method allows us to verify that a method of a mocked class is called. It can be combined with other methods like "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("times(x)")]),_v(" which allowsus to verify that the method is only called "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("x")]),_v(" times.")])]),_v(" "),_c('li',[_c('p',[_c('a',{attrs:{"href":"https://www.baeldung.com/mockito-argument-matchers"}},[_v("Argument matchers")]),_v(" like "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("anyInt()")]),_v(", "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("anyString()")]),_v(" and allows us to define a custom matcher using "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("argThat()")]),_v(". These argument matchers can be used to ensure that the correct arguments are being passed to the other dependencies. This is useful if the method you are testing does not return a value useful for determining the correctness of the method.")])]),_v(" "),_c('li',[_c('p',[_c('a',{attrs:{"href":"https://www.baeldung.com/mockito-behavior"}},[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("when()")]),_v(" and "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("thenReturn()")])]),_v(" These are methods that allow us to define the behaviour of other dependencies that are not under test.")]),_v(" "),_c('p',[_v("For e.g., "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("when(mockLogic.someMethod(args)).thenReturn(value)")]),_v(" makes it such that when the SUT invokes "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("someMethod()")]),_v(" with "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("args")]),_v(" from the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("mockLogic")]),_v(" class, "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("value")]),_v(" is will be returned by "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("someMethod(args)")]),_v(".")])])]),_v(" "),_c('h3',{attrs:{"id":"gcp"}},[_v("GCP"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#gcp","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Learnt about how the different features that are provided by GCP and other third parties come together to make Teammates possible.")]),_v(" "),_c('p',[_v("Most of the information is from the "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates-ops/blob/master/platform-guide.md"}},[_v("Platform Guide")]),_v(" in the teammates-ops repo.")]),_v(" "),_c('ul',[_c('li',[_v("Setting up OAuth 2.0 to allow users to login with their google credentials")]),_v(" "),_c('li',[_v("Google cloud storage")]),_v(" "),_c('li',[_v("Google cloud SQL")]),_v(" "),_c('li',[_v("Debugging using logs from Google Cloud's logging service")]),_v(" "),_c('li',[_c('a',{attrs:{"href":"https://cloud.google.com/appengine/docs/flexible/scheduling-jobs-with-cron-yaml"}},[_v("Setting up a cron job")])]),_v(" "),_c('li',[_v("Using email sending services like "),_c('a',{attrs:{"href":"https://www.mailjet.com/"}},[_v("Mailjet")])]),_v(" "),_c('li',[_v("Using "),_c('a',{attrs:{"href":"https://dbeaver.io/"}},[_v("DBeaver")]),_v(" to insepct and manipulate the SQL database")])])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/dishenggg/progress.html b/students/dishenggg/progress.html index bfa303e0a..63a51b012 100644 --- a/students/dishenggg/progress.html +++ b/students/dishenggg/progress.html @@ -12,7 +12,7 @@ const baseUrl = '/2024' -

    TEAMMATES

    Overview

    • Assisted in migration of GetCourseJoinStatusAction and PutDataBundleDocumentsAction
    • Created test cases for methods in FeedbackSessionsDb and FeedbackQuestionsDb
    • Migrated several E2E tests to use Sql entities
    • Participated in MTS design discussions
    • Adhoc tasks and E2E test for ARF project
    • Backend(db, logic, cronjob) and frontend work on logs project
    • Set up staging environment for logs project

    Achievements by Week

    Week Achievements
    3 Merged PR: [#12048] Migrate GetCourseJoinStatusAction #12713
    4 Merged PR: [#12048] Migrate PutDataBundleDocumentsAction #12734
    5 Merged PR: [#12048] Update restoreDeletedFeedbackSession to save updated entity to db #12751
    5 Merged PR: [#12048] Add test cases for FeedbackSessionsDb #12752
    R Merged PR: [#12048] Add tests for FeedbackQuestionsDbIT #12781
    R Merged PR: [#12048] Migrate instructor notification page e2e test #12792
    R Merged PR: [#12048] Migrate FeedbackMcqQuestionE2ETest #12820
    8 Merged PR: [#11843] Create FeedbackSessionLog entity and cron job action #12895
    8 Merged PR: [#12048] Migrate FeedbackMsqQuestionE2ETest #12904
    9 Merged PR: [#12048] Remove unnecessary loading of datastore entities in InstructorNotificationsPageE2ETest #12911
    9 Merged PR: [#11843] Create Logic and Db layer for FeedbackSessionLogs #12914
    10 Merged PR: [#11843] Update GetFeedbackSessionLogsAction to use SQL db #12938
    11 Merged PR: [#11843] Update front end for session activity logs #12973
    12 Merged PR: [#11878] Update DeleteAccountRequest to reference by ID #12997
    12 Merged PR: [#11878] Remove unused modal in AdminHomePage #12998
    12 Merged PR: [#11878] Update ResetAccountRequest to reference by ID #13002
    12 Reviewed PR: [#11878] Get account request by uuid #13007
    12 Reviewed PR: [#12048] Migrate StudentCourseJoinConfirmationPageE2ETest #13008
    12 Merged PR: [#11878] Request Page E2E #13015
    12 Reviewed PR: [#11878] Reference account requests by ID in tests #13017
    13 Reviewed PR: [#11878] Add Admin E2E Tests #13020
    13 Merged PR: [#11843] Fix front end bugs #13037
    13 Merged PR: [#11843] Merge student-activity-logs into master #13041
    13 Merged PR: [#11878] Remove ref by email and institute #13044
    +

    TEAMMATES

    Overview

    • Assisted in migration of GetCourseJoinStatusAction and PutDataBundleDocumentsAction
    • Created test cases for methods in FeedbackSessionsDb and FeedbackQuestionsDb
    • Migrated several E2E tests to use Sql entities
    • Participated in MTS design discussions
    • Adhoc tasks and E2E test for ARF project
    • Backend(db, logic, cronjob) and frontend work on logs project
    • Set up staging environment for logs project

    Achievements by Week

    Week Achievements
    3 Merged PR: [#12048] Migrate GetCourseJoinStatusAction #12713
    4 Merged PR: [#12048] Migrate PutDataBundleDocumentsAction #12734
    5 Merged PR: [#12048] Update restoreDeletedFeedbackSession to save updated entity to db #12751
    5 Merged PR: [#12048] Add test cases for FeedbackSessionsDb #12752
    R Merged PR: [#12048] Add tests for FeedbackQuestionsDbIT #12781
    R Merged PR: [#12048] Migrate instructor notification page e2e test #12792
    R Merged PR: [#12048] Migrate FeedbackMcqQuestionE2ETest #12820
    8 Merged PR: [#11843] Create FeedbackSessionLog entity and cron job action #12895
    8 Merged PR: [#12048] Migrate FeedbackMsqQuestionE2ETest #12904
    9 Merged PR: [#12048] Remove unnecessary loading of datastore entities in InstructorNotificationsPageE2ETest #12911
    9 Merged PR: [#11843] Create Logic and Db layer for FeedbackSessionLogs #12914
    10 Merged PR: [#11843] Update GetFeedbackSessionLogsAction to use SQL db #12938
    11 Merged PR: [#11843] Update front end for session activity logs #12973
    12 Merged PR: [#11878] Update DeleteAccountRequest to reference by ID #12997
    12 Merged PR: [#11878] Remove unused modal in AdminHomePage #12998
    12 Merged PR: [#11878] Update ResetAccountRequest to reference by ID #13002
    12 Reviewed PR: [#11878] Get account request by uuid #13007
    12 Reviewed PR: [#12048] Migrate StudentCourseJoinConfirmationPageE2ETest #13008
    12 Merged PR: [#11878] Request Page E2E #13015
    12 Reviewed PR: [#11878] Reference account requests by ID in tests #13017
    13 Reviewed PR: [#11878] Add Admin E2E Tests #13020
    13 Merged PR: [#11843] Fix front end bugs #13037
    13 Merged PR: [#11843] Merge student-activity-logs into master #13041
    13 Merged PR: [#11878] Remove ref by email and institute #13044
    diff --git a/students/dishenggg/progress.page-vue-render.js b/students/dishenggg/progress.page-vue-render.js index 2cb468a94..aeeca3584 100644 --- a/students/dishenggg/progress.page-vue-render.js +++ b/students/dishenggg/progress.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('h3',{attrs:{"id":"teammates"}},[_v("TEAMMATES"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#teammates","onclick":"event.stopPropagation()"}})]),_v(" "),_c('h4',{attrs:{"id":"overview"}},[_v("Overview"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#overview","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ul',[_c('li',[_v("Assisted in migration of "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("GetCourseJoinStatusAction")]),_v(" and "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("PutDataBundleDocumentsAction")])]),_v(" "),_c('li',[_v("Created test cases for methods in "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("FeedbackSessionsDb")]),_v(" and "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("FeedbackQuestionsDb")])]),_v(" "),_c('li',[_v("Migrated several E2E tests to use Sql entities")]),_v(" "),_c('li',[_v("Participated in MTS design discussions")]),_v(" "),_c('li',[_v("Adhoc tasks and E2E test for ARF project")]),_v(" "),_c('li',[_v("Backend(db, logic, cronjob) and frontend work on logs project")]),_v(" "),_c('li',[_v("Set up staging environment for logs project")])]),_v(" "),_c('h4',{attrs:{"id":"achievements-by-week"}},[_v("Achievements by Week"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#achievements-by-week","onclick":"event.stopPropagation()"}})]),_v(" "),_c('div',{staticClass:"table-responsive"},[_c('table',{staticClass:"markbind-table table table-bordered table-striped"},[_c('thead',[_c('tr',[_c('th',[_v("Week")]),_v(" "),_c('th',[_v("Achievements")])])]),_v(" "),_c('tbody',[_c('tr',[_c('td',[_v("3")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12713"}},[_v("[#12048] Migrate GetCourseJoinStatusAction #12713")])])]),_v(" "),_c('tr',[_c('td',[_v("4")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12734"}},[_v("[#12048] Migrate PutDataBundleDocumentsAction #12734")])])]),_v(" "),_c('tr',[_c('td',[_v("5")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12751"}},[_v("[#12048] Update restoreDeletedFeedbackSession to save updated entity to db #12751")])])]),_v(" "),_c('tr',[_c('td',[_v("5")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12752"}},[_v("[#12048] Add test cases for FeedbackSessionsDb #12752")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12781"}},[_v("[#12048] Add tests for FeedbackQuestionsDbIT #12781")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12792"}},[_v("[#12048] Migrate instructor notification page e2e test #12792")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12820"}},[_v("[#12048] Migrate FeedbackMcqQuestionE2ETest #12820")])])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12895"}},[_v("[#11843] Create FeedbackSessionLog entity and cron job action #12895")])])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12904"}},[_v("[#12048] Migrate FeedbackMsqQuestionE2ETest #12904")])])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12911"}},[_v("[#12048] Remove unnecessary loading of datastore entities in InstructorNotificationsPageE2ETest #12911")])])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12914"}},[_v("[#11843] Create Logic and Db layer for FeedbackSessionLogs #12914")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12938"}},[_v("[#11843] Update GetFeedbackSessionLogsAction to use SQL db #12938")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12973"}},[_v("[#11843] Update front end for session activity logs #12973")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12997"}},[_v("[#11878] Update DeleteAccountRequest to reference by ID #12997")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12998"}},[_v("[#11878] Remove unused modal in AdminHomePage #12998")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13002"}},[_v("[#11878] Update ResetAccountRequest to reference by ID #13002")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13007"}},[_v("[#11878] Get account request by uuid #13007")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13008"}},[_v("[#12048] Migrate StudentCourseJoinConfirmationPageE2ETest #13008")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13015"}},[_v("[#11878] Request Page E2E #13015")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13017"}},[_v("[#11878] Reference account requests by ID in tests #13017")])])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13020"}},[_v("[#11878] Add Admin E2E Tests #13020")])])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13037"}},[_v("[#11843] Fix front end bugs #13037")])])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13041"}},[_v("[#11843] Merge student-activity-logs into master #13041")])])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13044"}},[_v("[#11878] Remove ref by email and institute #13044")])])])])])])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/domlimm/info.html b/students/domlimm/info.html index a0f470fc0..a9f1f379b 100644 --- a/students/domlimm/info.html +++ b/students/domlimm/info.html @@ -12,7 +12,7 @@ const baseUrl = '/2024' - + diff --git a/students/domlimm/info.page-vue-render.js b/students/domlimm/info.page-vue-render.js index f5aa19a5a..9167e4843 100644 --- a/students/domlimm/info.page-vue-render.js +++ b/students/domlimm/info.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('p',[_c('span',{attrs:{"id":"github"}},[_c('a',{attrs:{"href":"https://www.github.com/domlimm"}},[_v("https://www.github.com/domlimm")])])]),_v(" "),_c('p',[_c('span',{attrs:{"id":"projects"}},[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates"}},[_v("TEAMMATES")])])])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/domlimm/knowledge.html b/students/domlimm/knowledge.html index 29d48fb0d..28c0471ae 100644 --- a/students/domlimm/knowledge.html +++ b/students/domlimm/knowledge.html @@ -32,7 +32,7 @@ git fetch ANY_FORK_NAME git checkout BRANCH_IN_PR

    This worked fine! But at one point, I could not get this working.

    I spent quite awhile to search on why but to no avail.

    There was a suggestion on Stackoverflow that proposed others to use the GitHub CLI.

    This was a plug-and-play tool, especially developing on Windows some setup could be rather cumbersome. All I had to do was visit the link above and install this CLI. Next, it was just a single line command...

    gh pr checkout PR_NUMBER
    -

    This was a life saver! Checking out to the developer's branch in his/her fork and reviewing a PR now have never been simpler!

    Lightning Talks

    A small section dedicated to the Lightning Talks we had throughout the semester.

    I have learnt quite a few things from the talks given by my course mates. There were many interesting technologies that were introduced -- some of which I have heard of, and some that I have used before.

    My takeaways from these talks were:

    1. Got to learn new technologies. Even though each talk is 7 minutes long, it was a great way to get started and I will be sure to try them out in the future!
    2. Some talks were non-technical but more on the soft skills e.g., Fergus' talk on Tiny PRs, Charisma's talk on how we can improve developers' experience, etc.
    3. Or the AI-related talks too.

    Soft Skills

    I believe that CS3282 is a great second part of the Thematic Systems Project pair. I thoroughly enjoyed interacing with the 81 juniors, and more so working with some of them.

    It was nice to for a change, take on the role of managing a project.

    Reviewing Pull Requests don't look as easy as it seems as I have to understand the changes made and the context of the problem.

    It was a really great experience!

    Database Migration

    I am glad to have been a part of working on the database migration, not rewriting the functionalities and tests in the codebase, but to actually migration data over to Google Cloud NoSQL.

    Scripts

    It was my first time performing database migration. TEAMMATES' mentor Wilson said (roughly), this might be your only chance to migrate a database.

    Before this, I had a high level understanding of how database migration would work. However, it was not as I have thought.

    There are so many more components to it such as understanding the constraints/restrictions e.g., When we could, and could not, do X, Y and Z., technical challenges imposed by the cloud provider, and writing the scripts to perform the migration.

    In my opinion, the learnings of this database migration is actually higher due to the fact that we are migrating from NoSQL to SQL. This means having to map the NoSQL documents over to SQL entities and ensuring that the affected relations' constraints are being complied with e.g., Foreign key constraints between 2 related/associated entities.

    Aside from these, I have also learnt the steps needed to perform data migration and careful planning is a necessity as each next step relies on the previous.

    The cursor figured by Fergus and Nicolas brought back what we were taught in CS2102 too!

    +

    This was a life saver! Checking out to the developer's branch in his/her fork and reviewing a PR now have never been simpler!

    Lightning Talks

    A small section dedicated to the Lightning Talks we had throughout the semester.

    I have learnt quite a few things from the talks given by my course mates. There were many interesting technologies that were introduced -- some of which I have heard of, and some that I have used before.

    My takeaways from these talks were:

    1. Got to learn new technologies. Even though each talk is 7 minutes long, it was a great way to get started and I will be sure to try them out in the future!
    2. Some talks were non-technical but more on the soft skills e.g., Fergus' talk on Tiny PRs, Charisma's talk on how we can improve developers' experience, etc.
    3. Or the AI-related talks too.

    Soft Skills

    I believe that CS3282 is a great second part of the Thematic Systems Project pair. I thoroughly enjoyed interacing with the 81 juniors, and more so working with some of them.

    It was nice to for a change, take on the role of managing a project.

    Reviewing Pull Requests don't look as easy as it seems as I have to understand the changes made and the context of the problem.

    It was a really great experience!

    Database Migration

    I am glad to have been a part of working on the database migration, not rewriting the functionalities and tests in the codebase, but to actually migration data over to Google Cloud NoSQL.

    Scripts

    It was my first time performing database migration. TEAMMATES' mentor Wilson said (roughly), this might be your only chance to migrate a database.

    Before this, I had a high level understanding of how database migration would work. However, it was not as I have thought.

    There are so many more components to it such as understanding the constraints/restrictions e.g., When we could, and could not, do X, Y and Z., technical challenges imposed by the cloud provider, and writing the scripts to perform the migration.

    In my opinion, the learnings of this database migration is actually higher due to the fact that we are migrating from NoSQL to SQL. This means having to map the NoSQL documents over to SQL entities and ensuring that the affected relations' constraints are being complied with e.g., Foreign key constraints between 2 related/associated entities.

    Aside from these, I have also learnt the steps needed to perform data migration and careful planning is a necessity as each next step relies on the previous.

    The cursor figured by Fergus and Nicolas brought back what we were taught in CS2102 too!

    diff --git a/students/domlimm/knowledge.page-vue-render.js b/students/domlimm/knowledge.page-vue-render.js index 571207685..9b51283a3 100644 --- a/students/domlimm/knowledge.page-vue-render.js +++ b/students/domlimm/knowledge.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('h1',{attrs:{"id":"angular"}},[_v("Angular"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#angular","onclick":"event.stopPropagation()"}})]),_v(" "),_c('h2',{attrs:{"id":"context"}},[_v("Context"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#context","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Before TEAMMATES, I have only ever used React. To help me get started on Angular, I looked up videos on YouTube, specifically "),_c('a',{attrs:{"href":"https://www.youtube.com/playlist?list=PL0vfts4VzfNjsTV_6i9a9iczMnthWqHzM"}},[_v("Fireship's Angular playlist")]),_v(", to get an overview. I tried doing a Udemy course too but I thought it was a little far-fetched.")]),_v(" "),_c('p',[_v("With a background in React, I went onto look for the similarities and differences between these two popular frontend web frameworks which led me to decide to dive into TEAMMATES' codebase.")]),_v(" "),_c('h2',{attrs:{"id":"passing-data-between-parent-and-child-components"}},[_v("Passing data between Parent and Child components"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#passing-data-between-parent-and-child-components","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Similar to passing of props in React, Angular has its way to pass data between parent and child components.")]),_v(" "),_c('p',[_v("In Angular, we use "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Output")]),_v(" for sending data to parent and "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Input")]),_v(" for sending data to child. It took me awhile to get used to the terms of "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("in/output")]),_v(".")]),_v(" "),_c('p',[_v("What helped me through this was the "),_c('a',{attrs:{"href":"https://angular.io/guide/inputs-outputs"}},[_v("Angular docs")]),_v(" on this exact matter, it was a perfect read! It starts off with the introduction of Input and Output, and was surprised it's said to be like a pattern. This page was really well written as it goes straight to the subject and it takes a step by step approach with sufficient amount of examples.")]),_v(" "),_c('h2',{attrs:{"id":"services"}},[_v("Services"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#services","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Working on the onboarding task (Per Receiver Submission project), I have learned how Angular, a frontend framework, communicates with the backend that uses Java EE.")]),_v(" "),_c('p',[_v("For the frontend to send a HTTP request to TEAMMATES server, we have to make use of a library/dependency to handle this action. Similar to packages used in React apps such as Fetch API, Axios, etc.")]),_v(" "),_c('p',[_v("TEAMMATES makes use of "),_c('a',{attrs:{"href":"https://angular.io/api/core/Injectable"}},[_v("Injectable")]),_v(" as part of Angular's core package to create a service. In this case, a service to an entity class. An injectable service is created and in it consists of functions that work with HTTP requests e.g., A method to get entities, that calls another service, the custom written HTTP service.")]),_v(" "),_c('p',[_v("Angular recommends to make use of services for tasks that do not involve the view or application logic. These services are mainly used to communicate with the backend server. Here is a guide on "),_c('a',{attrs:{"href":"https://angular.io/guide/architecture-services#introduction-to-services-and-dependency-injection"}},[_v("Introduction to services and dependency injection")]),_v(".")]),_v(" "),_c('p',[_v("While working with HTTP requests, we need to handle the operations that are involved with each request sent. TEAMMATES backend uses a "),_c('a',{attrs:{"href":"https://teammates.github.io/teammates/design.html#architecture"}},[_v("RESTful API architectural style")]),_v(". These RESTful endpoints mainly involve asynchronous operations.")]),_v(" "),_c('p',[_v("To work with such operations, we use "),_c('a',{attrs:{"href":"https://angular.io/guide/observables-in-angular"}},[_v("Observables")]),_v(" to ensure we resolve or reject them properly. Observables are part of the "),_c('a',{attrs:{"href":"https://rxjs.dev/guide/observable"}},[_v("RxJS library")]),_v(".")]),_v(" "),_c('p',[_v("With Observables, we are able to not only handle the basic outcomes of calling these RESTful APIs, but we are able to chain each response that is returned to us and make use of it to perform further operations.")]),_v(" "),_c('h1',{attrs:{"id":"testing"}},[_v("Testing"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#testing","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("I have never written tests of this extent. Aside from CS4218 which I am currently reading, the work done in TEAMMATES has really helped me to improve the way I write tests, and fully understand the importance of tests.")]),_v(" "),_c('h2',{attrs:{"id":"spy-es-spies"}},[_v("Spy-es/Spies"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#spy-es-spies","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("I have used "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("spy")]),_v(" before. Ironically, I never knew how to use it properly till I had to write tests on the work done.")]),_v(" "),_c('p',[_v("I was struggling to figure how to pass a check in a method of this object, let's define object as A. Object A has a method, "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("a()")]),_v(", that has a condition in it "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("if b(...)")]),_v(".")]),_v(" "),_c('p',[_v("Method "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("b()")]),_v(" belongs to object A. I could not set this condition to be true when I was writing the test. However, spy did the trick!")]),_v(" "),_c('p',[_v("All I had to do was write this powerful line of code:")]),_v(" "),_c('pre',[_c('code',{pre:true,attrs:{"class":"hljs java"}},[_c('span',[_v("A spyA = spy(A.class);\n")]),_c('span',[_v("doReturn("),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("true")]),_v(").when(spyA).b(...);\n")])])]),_c('p',[_v("And it worked! Sounds pretty trivial and silly I know... But Today I Learned (TIL)!")]),_v(" "),_c('p',[_v("Spying on an object allows us to dig deep into its methods and intentionally set the outcome of what we expect a variable/object or method outcome to be, we are in control and we define the result.")]),_v(" "),_c('p',[_v("Here is a good read on "),_c('a',{attrs:{"href":"https://www.baeldung.com/mockito-spy"}},[_v("spies")]),_v(". Love baeldung!")]),_v(" "),_c('h2',{attrs:{"id":"integration-tests"}},[_v("Integration Tests"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#integration-tests","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("My mentor said something that will have me remember for life - \"We should not use mocks for Integration Tests.\". This was a 'Today I Learned' moment.")]),_v(" "),_c('h1',{attrs:{"id":"hibernate"}},[_v("Hibernate"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#hibernate","onclick":"event.stopPropagation()"}})]),_v(" "),_c('h2',{attrs:{"id":"context-2"}},[_v("Context"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#context-2","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("I have only ever used Java in my school work, mainly those small OOP projects. If I can recall, the extent was up till using "),_c('a',{attrs:{"href":"https://www.javatpoint.com/java-jdbc"}},[_v("JDBC")]),_v(" connecting to MySQL, building a MVC architecture, that was pretty much it.")]),_v(" "),_c('p',[_v("But wow! Java has its own framework for building a backend. I have also heard of Spring Boot (I believe it's another backend framework!) but never used or looked into it before.")]),_v(" "),_c('p',[_v("At least for me, learning Hibernate has been really eye opening and refreshing! It has not only expanded my technical skillset in the realm of Java but it drills me on my fundamentals of Object Oriented Programming.")]),_v(" "),_c('p',[_v("The evidence is that Hibernate expects developers to write out the entity classes in an OOP fashion and it does all the setup behind the scenes, e.g., Setting up of the schemas in the chosen database.")]),_v(" "),_c('h2',{attrs:{"id":"annotations"}},[_v("Annotations"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#annotations","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("These said classes contain "),_c('a',{attrs:{"href":"https://thorben-janssen.com/key-jpa-hibernate-annotations/"}},[_v("annotations")]),_v(" provided by Hibernate where we specify what we would like to see in our relational schemas from non-nullable columns, connecting schemas via associations and foreign keys, working with natural keys, etc. Pretty cool and interesting stuff!")]),_v(" "),_c('h2',{attrs:{"id":"database-functionalities-of-hibernate-s-api"}},[_v("Database Functionalities of Hibernate's API"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#database-functionalities-of-hibernate-s-api","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Enough of the OOP stuff! Let's dive into the database functionalities.")]),_v(" "),_c('p',[_v("Hibernate provides out of the box in-built database functionalities in its API. These functions are closely similar to how we write SQL queries.")]),_v(" "),_c('p',[_v("Let's take a look at an example.")]),_v(" "),_c('p',[_v("Here, we have 2 entities - Instructor and Account. An Account is linked to an Instructor via a One to Many relationship i.e., An Account to many Instructors, and an attribute is in the Instructors schema. Hibernate does the work of linking these entities via the association we just specified.")]),_v(" "),_c('p',[_v("We would like to find all Instructors of a specified "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("accountId")]),_v(" and "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("courseId")]),_v(".")]),_v(" "),_c('p',[_v("In Hibernate, this is what we will write:")]),_v(" "),_c('pre',[_c('code',{pre:true,attrs:{"class":"hljs java"}},[_c('span',[_v("cr.select(instructorTable).where(cb.and(\n")]),_c('span',[_v(" cb.equal(instructorTable.get("),_c('span',{pre:true,attrs:{"class":"hljs-string"}},[_v("\"courseId\"")]),_v("), courseId),\n")]),_c('span',[_v(" cb.equal(instructorTable.get("),_c('span',{pre:true,attrs:{"class":"hljs-string"}},[_v("\"accountId\"")]),_v("), accountId)));\n")])])]),_c('p',[_v("In native SQL, this is what we would have written (PostgreSQL format, might not be entirely correct, off the top of my head):")]),_v(" "),_c('pre',[_c('code',{pre:true,attrs:{"class":"hljs sql"}},[_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("SELECT")]),_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-operator"}},[_v("*")]),_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("FROM")]),_v(" instructors\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("JOIN")]),_v(" accounts\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("ON")]),_v(" instructors.account "),_c('span',{pre:true,attrs:{"class":"hljs-operator"}},[_v("=")]),_v(" accounts.accountId;\n")])])]),_c('p',[_v("Hence, Hibernate provides plug-and-play functionalities that closely relate to SQL operations.")]),_v(" "),_c('h2',{attrs:{"id":"data-persistence-through-jpa"}},[_v("Data Persistence through JPA"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#data-persistence-through-jpa","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Another thing to highlight is the data persistency that Hibernate promises.")]),_v(" "),_c('blockquote',[_c('p',[_v("Hibernate is a standard implementation of the Java Persistence API (JPA) specification.")])]),_v(" "),_c('p',[_v("An evident example on persistency is...")]),_v(" "),_c('p',[_v("For example, we have a Person that we would like to update his/her name. Since we have written Person class in an OOP fashion as mentioned above, we could simply just update the name via the setter of the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("name")]),_v(" attribute by "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("person.setName(\"NewName\");")]),_v(", and that's it!")]),_v(" "),_c('p',[_v("You might ask, \"How about telling your database above this person's name change?\".")]),_v(" "),_c('p',[_v("Hibernate does this behind the scenes for you! This is all thanks to JPA.")]),_v(" "),_c('p',[_v("Also with the help of unit tests between the Logic and Db Layers, I was able to guarantee that this worked.")]),_v(" "),_c('h2',{attrs:{"id":"cascade-types-delete"}},[_v("Cascade Types (Delete)"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#cascade-types-delete","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("In SQL systems, when we delete a parent entity that references to a child entity or a list of child entities, all the child entites get deleted along with it.")]),_v(" "),_c('p',[_v("To do this in Hibernate, we can make use of a few different types of annotation, each has its own specific use.")]),_v(" "),_c('h3',{attrs:{"id":"specifying-cascade-cascadetype-remove-when-declaring-the-association-between-2-entities-parent-and-child"}},[_v("Specifying "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("cascade = CascadeType.REMOVE")]),_v(" when declaring the association between 2 entities, parent and child"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#specifying-cascade-cascadetype-remove-when-declaring-the-association-between-2-entities-parent-and-child","onclick":"event.stopPropagation()"}})]),_v(" "),_c('pre',[_c('code',{pre:true,attrs:{"class":"hljs java"}},[_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-meta"}},[_v("@OneToMany(mappedBy = \"parent\", cascade = CascadeType.REMOVE)")]),_v("\n")]),_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("private")]),_v(" List children = "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("new")]),_v(" ArrayList<>();\n")])])]),_c('p',[_v("This snippet says many child entities belong to one and only 1 parent. When we delete this parent entity, we'd want to also cascade this deletion/removal onto all of the child entities linked to this parent.")]),_v(" "),_c('p',[_v("This is the go-to for a simple cascade removal operation.")]),_v(" "),_c('h3',{attrs:{"id":"specifying-orphanremoval-true-when-declaring-the-association-between-2-entities-parent-and-child"}},[_v("Specifying "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("orphanRemoval = true")]),_v(" when declaring the association between 2 entities, parent and child"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#specifying-orphanremoval-true-when-declaring-the-association-between-2-entities-parent-and-child","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Firstly, this is very similar as to what we have above.")]),_v(" "),_c('pre',[_c('code',{pre:true,attrs:{"class":"hljs java"}},[_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-meta"}},[_v("@OneToOne(mappedBy = \"parent\", orphanRemoval = true)")]),_v("\n")]),_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("private")]),_v(" Child child;\n")])])]),_c('p',[_v("The difference is that "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("orphanRemoval")]),_v(" acts on the address of the parent entity. In other words, when we have a single child entity that references to a parent entity and we happen to use the setter method of this attribute "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("child")]),_v(".")]),_v(" "),_c('p',[_v("I.e., Doing this.")]),_v(" "),_c('pre',[_c('code',{pre:true,attrs:{"class":"hljs java"}},[_c('span',[_v("parent.setChild("),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("null")]),_v(");\n")])])]),_c('p',[_v("Hibernate will automatically detach the child entity from the parent entity and when a child entity is left alone without a parent, orphaned in this case, Hibernate will remove this child entity from the database.")]),_v(" "),_c('h3',{attrs:{"id":"using-ondelete-action-ondeleteaction-cascade"}},[_v("Using "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("@OnDelete(action = OnDeleteAction.CASCADE)")]),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#using-ondelete-action-ondeleteaction-cascade","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("I found this out when I was figuring how to remove an entity that does not have any association/relationship to the current entity except a 'reference' like this:")]),_v(" "),_c('pre',[_c('code',{pre:true,attrs:{"class":"hljs java"}},[_c('span',[_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("public")]),_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-class"}},[_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("class")]),_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-title"}},[_v("SomeClass")]),_v(" ")]),_v("{\n")]),_c('span',[_v(" "),_c('span',{pre:true,attrs:{"class":"hljs-keyword"}},[_v("private")]),_v(" ClassWeDelete classWeDelete;\n")]),_c('span',[_v("}\n")])])]),_c('p',[_v("This means that there is no purpose in keeping an entity of SomeClass when it only makes sense if an entity "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("classWeDelete")]),_v(" exists. It really does sound as if it's overlapping with the above two scenarios.")]),_v(" "),_c('p',[_v("But again, the key here is that there is no form of association/relation between these two different entities.")]),_v(" "),_c('p',[_v("Here are some resources that helped me on understanding this:")]),_v(" "),_c('ul',[_c('li',[_v("From "),_c('a',{attrs:{"href":"https://docs.jboss.org/hibernate/orm/6.1/userguide/html_single/Hibernate_User_Guide.html#pc-cascade-on-delete"}},[_v("Hibernate Docs")])]),_v(" "),_c('li',[_v("From "),_c('a',{attrs:{"href":"https://www.baeldung.com/jpa-cascade-remove-vs-orphanremoval"}},[_v("Baeldung")])]),_v(" "),_c('li',[_v("From "),_c('a',{attrs:{"href":"https://stackoverflow.com/questions/4329577/how-does-jpa-orphanremoval-true-differ-from-the-on-delete-cascade-dml-clause"}},[_v("Stackoverflow")])])]),_v(" "),_c('h2',{attrs:{"id":"inheritance-strategies"}},[_v("Inheritance Strategies"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#inheritance-strategies","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("As mentioned above, Hibernate as a framework works with OOP heavily. To start off, in order to model the relationship between entities, we need to define the java classes in an OOP fashion. Hibernate as an Object Relational Mapping tool does the heavylifting for us - we just need to tell it what we want in the OOP 'language' that Hibernate interprets really well in.")]),_v(" "),_c('p',[_v("I picked this up when I was tasked to design the parent-child relationship for the User's entity (in this "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12071"}},[_v("PR #12071")]),_v("). "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("User")]),_v(" is the parent entity that has child entities i.e., These child entities extend this parent "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("User")]),_v(" class.")]),_v(" "),_c('p',[_v("When considering which strategy to use, there were other factors to consider - performance, scalability, maintainability.")]),_v(" "),_c('p',[_v("These were what I found during the research of the 4 inheritance strategies that Hibernate provides.")]),_v(" "),_c('hr'),_v(" "),_c('p',[_v("Below are the findings for the 4 available inheritance strategies in "),_c('a',{attrs:{"href":"https://docs.jboss.org/hibernate/orm/6.1/userguide/html_single/Hibernate_User_Guide.html#entity-inheritance"}},[_v("Hibernate")]),_v(":")]),_v(" "),_c('h3',{attrs:{"id":"mappedsuperclass"}},[_v("MappedSuperclass"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#mappedsuperclass","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ul',[_c('li',[_v("Not scalable. If we use this, ancestors cannot contain associations with other entities.")]),_v(" "),_c('li',[_v("Each DB table contains both base and sub classes properties.")])]),_v(" "),_c('h3',{attrs:{"id":"single-table"}},[_v("Single Table"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#single-table","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ul',[_c('li',[_v("Performant (polymorphic query performance) as only 1 table needs to be accessed when querying parent entities. Best performance among the other strategies.")]),_v(" "),_c('li',[_v("However, can no longer use NOT NULL constraints on subclass entity properties. I think this means that the identifying attributes of the rows of subclasses can be nullable?")]),_v(" "),_c('li',[_v("For our case of Student/Instructor IS-A User, we will only have 1 table in the DB, i.e., User, with all the fields combined. This means Single Table is out of our options? Student is a User but it shouldn't have Instructor attributes/data.")]),_v(" "),_c('li',[_v("Could use discriminator values which is used to differentiate between rows belonging to separate subclass types.")])]),_v(" "),_c('h3',{attrs:{"id":"joined-table-aka-table-per-subclass-mapping-strategy"}},[_v("Joined Table aka Table-per-subclass mapping strategy"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#joined-table-aka-table-per-subclass-mapping-strategy","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ul',[_c('li',[_v("TLDR: An inherited state is retrieved by joining with the table of the superclass.")]),_v(" "),_c('li',[_v("Great because the PK of User appears in its child classes, e.g., In Student/Instructor.")]),_v(" "),_c('li',[_v("Performance issues as retrieving entities requires joins between the tables, expensive for large number of records. Number of joins is higher when we query parent class as it will join with every single related child.")]),_v(" "),_c('li',[_v("Discriminator column not required. But each subclass must declare a table column holding the object identifier (which is kind of what we want as each subclass table contains the FKs to the base class, User; PKs of sub class tables are also FKs to the superclass table PK. If "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("@PKJoinCol")]),_v(" not set, the PK/FK cols are assumed to have the same names as the PK cols of primary table of the superclass).")]),_v(" "),_c('li',[_v("When using polymorphic queries, base class table must be joined with all subclass tables to fetch every associated subclass instance.")])]),_v(" "),_c('h3',{attrs:{"id":"table-per-class"}},[_v("Table per Class"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#table-per-class","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ul',[_c('li',[_v("Performance issue because we union in the background when we query the base class i.e., User.")]),_v(" "),_c('li',[_v("Each table defines all persistent states of the class, including the inherited state.")]),_v(" "),_c('li',[_v("If we want to use polymorphic associations (eg An association to the superclass of our hierarchy), we need to use union subclass mapping. This requires multiple "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("UNION")]),_v(" queries, be aware of performance implications of a large class hierarchy. Also, not all database systems support "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("UNION ALL")]),_v(". "),_c('a',{attrs:{"href":"https://docs.jboss.org/hibernate/orm/5.4/javadocs/org/hibernate/dialect/PostgreSQL81Dialect.html"}},[_v("PostgreSQL81Dialect")]),_v(" supports "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("UNION ALL")]),_v(".")])]),_v(" "),_c('p',[_v("Some resources I used to help me work out the different inheritance strategies")]),_v(" "),_c('ul',[_c('li',[_v("Directly from the "),_c('a',{attrs:{"href":"https://docs.jboss.org/hibernate/orm/6.1/userguide/html_single/Hibernate_User_Guide.html#entity-inheritance"}},[_v("Hibernate documentation")])]),_v(" "),_c('li',[_v("From "),_c('a',{attrs:{"href":"https://www.baeldung.com/hibernate-inheritance"}},[_v("Baeldung")]),_v(". This was slightly out of date compared to the Hibernate docs")])]),_v(" "),_c('hr'),_v(" "),_c('h2',{attrs:{"id":"conclusion"}},[_v("Conclusion"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#conclusion","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Hibernate does provide way more than the above but let's look forward to what else we can learn in the future tasks!")]),_v(" "),_c('p',[_v("Alright that's it for now, stick around folks!")]),_v(" "),_c('h2',{attrs:{"id":"resources"}},[_v("Resources"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#resources","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Below are some wonderful resources that have helped me along the way:")]),_v(" "),_c('ul',[_c('li',[_v("Baeldung's take on Hibernate "),_c('a',{attrs:{"href":"https://www.baeldung.com/learn-jpa-hibernate"}},[_v("here")])]),_v(" "),_c('li',[_v("Official Documentation of Hibernate "),_c('a',{attrs:{"href":"https://docs.jboss.org/hibernate/orm/6.1/userguide/html_single/Hibernate_User_Guide.html"}},[_v("here")]),_v(", literally the bible but I find some examples to be quite bare and the rest of the resources here and have helped me tremendously!")]),_v(" "),_c('li',[_v("The man himself Thorben Janssen! Over "),_c('a',{attrs:{"href":"https://thorben-janssen.com/tutorials/"}},[_v("here")])])]),_v(" "),_c('h1',{attrs:{"id":"miscellaneous"}},[_v("Miscellaneous"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#miscellaneous","onclick":"event.stopPropagation()"}})]),_v(" "),_c('h2',{attrs:{"id":"large-modifications-to-a-live-system"}},[_v("Large Modifications to a Live System"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#large-modifications-to-a-live-system","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Crediting my teammate, Kevin, for bringing up this point.")]),_v(" "),_c('p',[_v("This semestral project, v9-migration - moving from NoSQL to SQL, could be detrimental to a live system that relies on huge chunks of data to function if not done with caution.")]),_v(" "),_c('p',[_v("In order for the team to carefully perform such a huge operation, a migrated check on the documents (previously NoSQL) is done before paving the way for an endpoint to take when called for.")]),_v(" "),_c('p',[_v("This allows us to work independently on migrating the relevant parts of this live system, dual DB as said by my mentors, without affecting the current state that the hundreds of thousands users see.")]),_v(" "),_c('p',[_v("In my opinion, it is really neat!")]),_v(" "),_c('h2',{attrs:{"id":"a-good-follow-up-after-submitting-a-pr"}},[_v("A good follow-up after submitting a PR"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#a-good-follow-up-after-submitting-a-pr","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Through the PRs that I have submitted, I learned that we should always set it as a draft first and look at the PR from the reviewer's perspective to ensure that we did not miss out anything or if there is any section of code that can be further improved on.")]),_v(" "),_c('p',[_v("A helpful part of the UI for a PR in GitHub is the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Files Changed")]),_v(" tab. This allows us to get a full overview of the changes that were made, additions or deletions, to each file.")]),_v(" "),_c('p',[_v("This can definitely go a long way, especially when we have a large PR.")]),_v(" "),_c('h2',{attrs:{"id":"a-different-view-when-looking-at-a-pr"}},[_v("A different view when looking at a PR"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#a-different-view-when-looking-at-a-pr","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Crediting my mentor, Samuel, for introducing this.")]),_v(" "),_c('p',[_v("When looking at a Pull Request on GitHub, tapping on the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v(".")]),_v(" key on our keyboard brings us to another page - "),_c('a',{attrs:{"href":"https://docs.github.com/en/codespaces/the-githubdev-web-based-editor"}},[_v("GitHub's built-in Visual Studio Code in the web browser")]),_v(". Extremely cool stuff!")]),_v(" "),_c('h2',{attrs:{"id":"github-cli"}},[_v("GitHub CLI"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#github-cli","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Prior to reviewing PRs in TEAMMATES, I haven't really experienced any trouble with pulling the branch I am reviewing locally.")]),_v(" "),_c('p',[_v("I faced troubles in doing so when reviewing my first TEAMMATE's PR. The reason was that this branch in the PR resides in the developer's own fork.")]),_v(" "),_c('p',[_v("The process was different as to what I have always been in when reviewing a PR - was a remote branch that resides in the same repository and not a fork.")]),_v(" "),_c('p',[_v("My first go-to solution to this was to add the developer's fork as a remote repository for me to track locally by using (some parts of this "),_c('a',{attrs:{"href":"https://www.freecodecamp.org/news/how-to-sync-your-fork-with-the-original-git-repository/"}},[_v("guide")]),_v(" helped!):")]),_v(" "),_c('pre',[_c('code',{pre:true,attrs:{"class":"hljs"}},[_c('span',[_v("git remote add ANY_FORK_NAME FORK_URL\n")]),_c('span',[_v("git fetch ANY_FORK_NAME\n")]),_c('span',[_v("git checkout BRANCH_IN_PR\n")])])]),_c('p',[_v("This worked fine! But at one point, I could not get this working.")]),_v(" "),_c('p',[_v("I spent quite awhile to search on why but to no avail.")]),_v(" "),_c('p',[_v("There was a suggestion on Stackoverflow that proposed others to use the "),_c('a',{attrs:{"href":"https://cli.github.com/"}},[_v("GitHub CLI")]),_v(".")]),_v(" "),_c('p',[_v("This was a plug-and-play tool, especially developing on Windows some setup could be rather cumbersome. All I had to do was visit the link above and install this CLI. Next, it was just a single line command...")]),_v(" "),_c('pre',[_c('code',{pre:true,attrs:{"class":"hljs"}},[_c('span',[_v("gh pr checkout PR_NUMBER\n")])])]),_c('p',[_v("This was a "),_c('strong',[_c('em',[_v("life saver")])]),_v("! Checking out to the developer's branch in his/her fork and reviewing a PR now have never been simpler!")]),_v(" "),_c('h2',{attrs:{"id":"lightning-talks"}},[_v("Lightning Talks"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#lightning-talks","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("A small section dedicated to the Lightning Talks we had throughout the semester.")]),_v(" "),_c('p',[_v("I have learnt quite a few things from the talks given by my course mates. There were many interesting technologies that were introduced -- some of which I have heard of, and some that I have used before.")]),_v(" "),_c('p',[_v("My takeaways from these talks were:")]),_v(" "),_c('ol',[_c('li',[_v("Got to learn new technologies. Even though each talk is 7 minutes long, it was a great way to get started and I will be sure to try them out in the future!")]),_v(" "),_c('li',[_v("Some talks were non-technical but more on the soft skills e.g., Fergus' talk on Tiny PRs, Charisma's talk on how we can improve developers' experience, etc.")]),_v(" "),_c('li',[_v("Or the AI-related talks too.")])]),_v(" "),_c('h2',{attrs:{"id":"soft-skills"}},[_v("Soft Skills"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#soft-skills","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("I believe that CS3282 is a great second part of the Thematic Systems Project pair. I thoroughly enjoyed interacing with the 81 juniors, and more so working with some of them.")]),_v(" "),_c('p',[_v("It was nice to for a change, take on the role of managing a project.")]),_v(" "),_c('p',[_v("Reviewing Pull Requests don't look as easy as it seems as I have to understand the changes made and the context of the problem.")]),_v(" "),_c('p',[_v("It was a really great experience!")]),_v(" "),_c('h1',{attrs:{"id":"database-migration"}},[_v("Database Migration"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#database-migration","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("I am glad to have been a part of working on the database migration, not rewriting the functionalities and tests in the codebase, but to actually migration data over to Google Cloud NoSQL.")]),_v(" "),_c('h2',{attrs:{"id":"scripts"}},[_v("Scripts"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#scripts","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("It was my first time performing database migration. TEAMMATES' mentor Wilson said (roughly), this might be your only chance to migrate a database.")]),_v(" "),_c('p',[_v("Before this, I had a high level understanding of how database migration would work. However, it was not as I have thought.")]),_v(" "),_c('p',[_v("There are so many more components to it such as understanding the constraints/restrictions e.g., When we could, and could not, do X, Y and Z., technical challenges imposed by the cloud provider, and writing the "),_c('strong',[_v("scripts")]),_v(" to perform the migration.")]),_v(" "),_c('p',[_v("In my opinion, the learnings of this database migration is actually higher due to the fact that we are migrating from NoSQL to SQL. This means having to map the NoSQL documents over to SQL entities and ensuring that the affected relations' constraints are being complied with e.g., Foreign key constraints between 2 related/associated entities.")]),_v(" "),_c('p',[_v("Aside from these, I have also learnt the steps needed to perform data migration and careful planning is a necessity as each next step relies on the previous.")]),_v(" "),_c('p',[_v("The cursor figured by Fergus and Nicolas brought back what we were taught in CS2102 too!")])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/domlimm/observations.html b/students/domlimm/observations.html index 23ea3948f..8b60cf397 100644 --- a/students/domlimm/observations.html +++ b/students/domlimm/observations.html @@ -14,7 +14,7 @@

    Project: freeCodeCamp

    freeCodeCamp is an open-source codebase and curriculum to learn and code for free.

    My Contributions

    PR Link: https://github.com/freeCodeCamp/freeCodeCamp/pull/53233

    My first PR in this project was improving the description and hint of a feature (i.e., Writing a function for the equivalent of =FORMULA in Excel) in a Spreadsheet Project.

    My Learning Record

    Tools/Technologies learned:

    • Gitpod

    Gitpod

    This was the first time I have come across Gitpod (and it was the topic for my Lightning Talk in Round A2).

    As freeCodecamp's codebase is extremely large, there are many different configurations and areas to get the project up and running locally. Hence, first-time contributors were encouraged to use Gitpod to start the project.

    Observations from freeCodeCamp

    • The set up was the most complicated that I have come across. There were many steps to do as it is a large project. However, the documentation is great such that it's comprehensive and concise in helping first time contributors to set up the project successfully. Alternatively to setting up locally, the team has integrated Gitpod into its project that really helped me as with limited time trying to speed up the contribution set up process.
    • With a project that is this large scale, there is an active team available to manage and guide contributors i.e., Most issues and PRs are looked at rather quickly. However, overlapping with the previous point, the documentation speaks volumes and it helps saves developer productivity.

    Project: date-fns

    date-fns is a modern JavaScript date utility library. It provides the most comprehensive, yet simple and consistent toolset for manipulating JavaScript dates in a browser & Node.js.

    My Contributions

    PR Link: https://github.com/date-fns/date-fns/pull/3687

    My first PR in this project was enhancing an existing function in the date-fns library. The action item was to create an alias for the more generic name that was initially given to the function.

    My Learning Record

    Tools/Technologies learned:

    • How an npm package actually works
      • This was my first time working on an npm package. I got to see and understand how a package is built and deployed onto the npm servers for use in other projects.

    Observations from date-fns

    • Compared to freeCodeCamp, it seems as though this project is managed by only 1 person. Responses on issues and PRs are rather slow (till this date, I am still waiting for a reply on my PR) which really is understandable.
    • It lacks a contribution documentation too.

    Project: stdlib

    stdlib is a standard library for JavaScript and Node.js. It has an emphasis on numerical and scientific computing applications. This library provides a conglomerate of libraries for mathematics, statistics, data processing, streams, etc.

    My Contributions

    PR Link: https://github.com/stdlib-js/stdlib/pull/2008

    My PR in this project was to add more examples into the math/iter/ops (iter == iterator, ops == operations) namespace and to provide examples on the usage in this library.

    My Learning Record

    Tools/Technologies learned:

    • What's in a standard library for a programming language/framework -
      • This was my first time working on such a project. I got to see and understand what is in a standard library.
    • Considering the fact that it's a standard library, the GNU Make tool comes in really handy and running most of the project's features e.g., Tests, installing dependencies, etc.
    • The reason why I picked this namespace to work on was because I came across generators in Python when I was reading in some of the more advanced concepts of the language. I thought this will be a good opportunity to apply what I have learnt and I was able to understand how similar this stdlib's namespace is.

    Observations from stdlib

    • Similar to date-fns, this project is managed by 3-5 active contributors.
    • Even though there is a small team managing this project, the issues management and responses to comments in them are great! Issues all around are well labelled.
    • This project's contribution docs is only in a single README file, considering its scale, this suffices. It's actually really well written too, providing well rounded help in starting!
    +
    • This was my first time working on such a project. I got to see and understand what is in a standard library.
  • Considering the fact that it's a standard library, the GNU Make tool comes in really handy and running most of the project's features e.g., Tests, installing dependencies, etc.
  • The reason why I picked this namespace to work on was because I came across generators in Python when I was reading in some of the more advanced concepts of the language. I thought this will be a good opportunity to apply what I have learnt and I was able to understand how similar this stdlib's namespace is.
  • Observations from stdlib

    • Similar to date-fns, this project is managed by 3-5 active contributors.
    • Even though there is a small team managing this project, the issues management and responses to comments in them are great! Issues all around are well labelled.
    • This project's contribution docs is only in a single README file, considering its scale, this suffices. It's actually really well written too, providing well rounded help in starting!
    diff --git a/students/domlimm/observations.page-vue-render.js b/students/domlimm/observations.page-vue-render.js index a60e79845..1ce4e2081 100644 --- a/students/domlimm/observations.page-vue-render.js +++ b/students/domlimm/observations.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('h3',{attrs:{"id":"project-freecodecamp"}},[_v("Project: freeCodeCamp"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#project-freecodecamp","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("freeCodeCamp is an open-source codebase and curriculum to learn and code for free.")]),_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("PR Link: "),_c('a',{attrs:{"href":"https://github.com/freeCodeCamp/freeCodeCamp/pull/53233"}},[_v("https://github.com/freeCodeCamp/freeCodeCamp/pull/53233")])]),_v(" "),_c('p',[_v("My first PR in this project was improving the description and hint of a feature (i.e., Writing a function for the equivalent of "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("=FORMULA")]),_v(" in Excel) in a Spreadsheet Project.")]),_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("Tools/Technologies learned:")]),_v(" "),_c('ul',[_c('li',[_v("Gitpod")])]),_v(" "),_c('h4',{attrs:{"id":"gitpod"}},[_v("Gitpod"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#gitpod","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("This was the first time I have come across Gitpod (and it was the topic for my Lightning Talk in Round A2).")]),_v(" "),_c('p',[_v("As freeCodecamp's codebase is extremely large, there are many different configurations and areas to get the project up and running locally. Hence, first-time contributors were encouraged to use Gitpod to start the project.")]),_v(" "),_c('h3',{attrs:{"id":"observations-from-freecodecamp"}},[_v("Observations from freeCodeCamp"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#observations-from-freecodecamp","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ul',[_c('li',[_v("The set up was the most complicated that I have come across. There were many steps to do as it is a large project. However, the documentation is great such that it's comprehensive and concise in helping first time contributors to set up the project successfully. Alternatively to setting up locally, the team has integrated Gitpod into its project that really helped me as with limited time trying to speed up the contribution set up process.")]),_v(" "),_c('li',[_v("With a project that is this large scale, there is an active team available to manage and guide contributors i.e., Most issues and PRs are looked at rather quickly. However, overlapping with the previous point, the documentation speaks volumes and it helps saves developer productivity.")])]),_v(" "),_c('h3',{attrs:{"id":"project-date-fns"}},[_v("Project: date-fns"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#project-date-fns","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("date-fns is a modern JavaScript date utility library. It provides the most comprehensive, yet simple and consistent toolset for manipulating JavaScript dates in a browser & Node.js.")]),_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("PR Link: "),_c('a',{attrs:{"href":"https://github.com/date-fns/date-fns/pull/3687"}},[_v("https://github.com/date-fns/date-fns/pull/3687")])]),_v(" "),_c('p',[_v("My first PR in this project was enhancing an existing function in the date-fns library. The action item was to create an alias for the more generic name that was initially given to the function.")]),_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("Tools/Technologies learned:")]),_v(" "),_c('ul',[_c('li',[_v("How an npm package actually works\n"),_c('ul',[_c('li',[_v("This was my first time working on an npm package. I got to see and understand how a package is built and deployed onto the npm servers for use in other projects.")])])])]),_v(" "),_c('h4',{attrs:{"id":"observations-from-date-fns"}},[_v("Observations from date-fns"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#observations-from-date-fns","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ul',[_c('li',[_v("Compared to freeCodeCamp, it seems as though this project is managed by only 1 person. Responses on issues and PRs are rather slow (till this date, I am still waiting for a reply on my PR) which really is understandable.")]),_v(" "),_c('li',[_v("It lacks a contribution documentation too.")])]),_v(" "),_c('h3',{attrs:{"id":"project-stdlib"}},[_v("Project: stdlib"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#project-stdlib","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("stdlib is a standard library for JavaScript and Node.js. It has an emphasis on numerical and scientific computing applications. This library provides a conglomerate of libraries for mathematics, statistics, data processing, streams, etc.")]),_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("PR Link: "),_c('a',{attrs:{"href":"https://github.com/stdlib-js/stdlib/pull/2008"}},[_v("https://github.com/stdlib-js/stdlib/pull/2008")])]),_v(" "),_c('p',[_v("My PR in this project was to add more examples into the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("math/iter/ops")]),_v(" (iter == iterator, ops == operations) namespace and to provide examples on the usage in this library.")]),_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("Tools/Technologies learned:")]),_v(" "),_c('ul',[_c('li',[_v("What's in a standard library for a programming language/framework\n"),_c('ul',[_c('li',[_v("This was my first time working on such a project. I got to see and understand what is in a standard library.")])])]),_v(" "),_c('li',[_v("Considering the fact that it's a standard library, the GNU Make tool comes in really handy and running most of the project's features e.g., Tests, installing dependencies, etc.")]),_v(" "),_c('li',[_v("The reason why I picked this namespace to work on was because I came across generators in Python when I was reading in some of the more advanced concepts of the language. I thought this will be a good opportunity to apply what I have learnt and I was able to understand how similar this stdlib's namespace is.")])]),_v(" "),_c('h4',{attrs:{"id":"observations-from-stdlib"}},[_v("Observations from stdlib"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#observations-from-stdlib","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ul',[_c('li',[_v("Similar to date-fns, this project is managed by 3-5 active contributors.")]),_v(" "),_c('li',[_v("Even though there is a small team managing this project, the issues management and responses to comments in them are great! Issues all around are well labelled.")]),_v(" "),_c('li',[_v("This project's contribution docs is only in a single README file, considering its scale, this suffices. It's actually really well written too, providing well rounded help in starting!")])])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/domlimm/progress.html b/students/domlimm/progress.html index 40f266327..0a42b00b1 100644 --- a/students/domlimm/progress.html +++ b/students/domlimm/progress.html @@ -16,7 +16,7 @@
    • Working alongside the team to contribute wherever I can e.g., Scripts, reviewing of PRs
    • Involved in discussios
  • Migration of actions
  • Did just 1 E2E test migration (will continue contributing/working on this after exams)
  • Refactoring of entities that use certain attributes as string when they should have been unique identifiers i.e., Foreign Keys, linking to another entity (in the Hibernate way) (will continue work on this after exams)
    • Updated our ERD to reflect the new changes between the tables in the DB
  • Multiple Course Structures (MCS) project
    • Involved in the first discussion we had with the team
    • Vetting Technical Design Docs written by CS3281 students under this project
    • Updated entities with the necessary attributes for MCS to work (just the base for future batches)
    • Involved in further discussions with Kevin and Wei Qing
  • External contributions to 3 projects -
    • Though they were small, I have learnt several things from these 3 projects and could see the contrast between them and TEAMMATES too
    • Had tried to do a more technical heavy one but couldn't get it working and unfortunately vs. the effort and time spent (https://github.com/mattermost/mattermost/issues/24291)
  • CS3282 Pre-Semester's Progress

    Date Type Achievements
    12 May 2023 Reviewed [#12267] Instructor getting started page: Fix scroll to top #12419
    15 May 2023 Reviewed [#12407] Sort icons in info table headings are hard to see #12429
    16 May 2023 Reviewed [#12283] Add a download button for instructor view session result (course-wide) #12431
    21 May 2023 Reviewed [#10976] Document frontend standardizations #12436
    23 May 2023 Reviewed [#12430] Include student email in 'distribute points' type question summary table CSV #12435
    24 May 2023 Reviewed [#12010] Notifications box overlaps with the page menu in the instructor help page #12428
    27 May 2023 Reviewed [#10920] Add test for restoreCourse in Instructor Courses Page #12443
    30 May 2024 Reviewed [#10920] Add testing for sortCoursesBy method in instructor home page. #12440
    04 Jun 2023 Reviewed [#12099] Add 'course -> copy' option to the instructor home page #12439
    04 Jun 2023 Reviewed [#12442] Massive string is not correctly treated #12456
    05 Jun 2023 Reviewed [#10920] Added test for Instructor Course Edit Page #12462
    08 Jun 2023 Reviewed [#12464] Add verification step for Docker instance of Datastore in docs #12465
    13 Jun 2023 Reviewed [#12466] Clarify masquerade mode in docs #12470
    17 Jun 2023 Reviewed [#12269] Instructor edit sessions page: Fix add question button overflow. #12476
    25 Jun 2023 Reviewed [#1501] Add tests cases to FeedbackRankOptionsQuestionDetails #12475
    25 Jun 2023 Reviewed [#12481] Fix running of component tests using Windows Powershell #12482
    29 Jun 2023 Reviewed [#12400] Instructor editing questions: warning about visibility is removed if the edit is cancelled. #12495
    29 Jun 2023 Reviewed [#12268] Make instructor getting started page more prominent #12496
    02 Jul 2023 Reviewed [#12269] Instructor edit sessions page: Fix add question button overflow. #12477
    04 Jul 2023 Reviewed [#12457] Make the table buttons easier to use on mobile devices #12463
    06 Jul 2023 Reviewed [#12280] Improve display for create course card header #12500
    14 Jul 2023 Reviewed [#12517] Instructors creating sessions: response visible time should be 'not now' by default #12518
    17 Jul 2023 Reviewed [#12473] Add steps on how to use the masquerade mode in developer guide #12506
    02 Aug 2023 Reviewed [#12455] Limit word and character count for text editor. #12503
    06 Aug 2023 Reviewed [#12538] Instructor sessions page: Empty deleted sessions table is not displayed #12546
    19 Aug 2023 Reviewed [#12544] Rubric Question Statistics: Handle empty weights #12545
    01 Oct 2023 Reviewed [#12466] Docs: Clarify masquerade mode #12595
    20 Dec 2023 Reviewed [#12665] Instructor's Student Records Page: Misleading name for canceling of comment edit #12667
    20 Dec 2023 Reviewed [#12671] Remove redundant newline in Development section of Docs #12672
    23 Dec 2023 Reviewed [#12652] Copying feedback session: mark session name as mandatory field when copying feedback session #12670
    24 Dec 2023 Reviewed [#12656] Student Home Page: Indicate default sort #12660
    24 Dec 2023 Reviewed [#12658] Instructor Home Page: Dropdown buttons on mobile #12662
    25 Dec 2023 Reviewed [#12654] Instructor Edit Session Page: Bug in Grace Period Tooltip #12675
    28 Dec 2023 Reviewed [#12663] Instructor's Student Records Page: Tooltips for comments #12676
    30 Dec 2023 Reviewed [#12664] Instructor's Student Records Page: Accessibility issue for comment buttons #12683
    30 Dec 2023 Reviewed [#12669] Update Documentation to include updating of snapshot tests #12684
    31 Dec 2023 Reviewed [#12649] When adding a comment while submitting responses, show visibility of the comment as well #12659
    02 Jan 2024 Reviewed [#12375] Incorrect Developer Website link in Contact page #12686

    CS3282 Semester's Progress

    Week Type Achievements
    1 Merged [#12052] Per Receiver Submission #12053
    1 Reviewed [#12657] Instructor Home Page: Students dropdown buttons of the wrong colour . #12691
    2 Reviewed [#12048] Migrate UpdateInstructorAction #12434
    2 Reviewed [#12699] Replace ng command in setting-up.md #12701
    2 Reviewed [#12699] Replace ng command in setting-up.md #12701
    3 Merged [#12048] Migrate RemoveDataBundle #12709
    3 Reviewed [#12048] Migrate enroll students action #12715
    4 Reviewed [#12048] Migrate search account requests action #12726
    4 Reviewed [#12048] Support for twin db for search + replace datastore test #12728
    4 Reviewed [#12693] Excess padding on edit course details component #12737
    6 Reviewed [#12048] Migrate GetSessionResultsAction #12719
    6, R, 7 Data Migration Together with the team
    R Reviewed [#12048] Bump up postgresql version #12784
    R Reviewed [#12048] Add tests for CourseDbIT #12786
    R Reviewed [#12048] migrate InstructorCourseJoinConfirmationPageE2ETest #12790
    R Reviewed [#12048] migrate AdminHomePageE2ETest #12794
    R Merged [#12048] Fix incorrect usage of recipient as param for E2E test #12797
    R Reviewed [#12048] Add migration script for Account Request #12799
    R Reviewed [#12048] Move accounts JSON for InstructorStudentRecordsPageE2ETest #12828
    R Reviewed [#12048] Move accounts JSON for InstructorStudentListPageE2ETest #12830
    R Reviewed [#12048] Move accounts JSON for InstructorSessionIndividualExtensionPageE2ETest #12832
    R Reviewed [#12048] Move accounts JSON for InstructorFeedbackSessionsPageE2ETest #12834
    R Authored (WIP) [#12048] Refactor FeedbackResponses and FeedbackResponseComments attributes
    7 Reviewed [#12048] Add integration tests for FeedbackResponsesDb #12856
    7 Contributed [#12048] Fix account creation #12871
    8 Merged [#12048] Add deep comparison for entities in verifyEquals for E2E
    9 Reviewed [#12588] Improve test code coverage of core components - ToastComponent
    9 Reviewed [#12588] Improve test code coverage of core components - ViewResultsPanelComponent
    10 Reviewed [#12946] Enable CI on Multiple Course Structures branch
    10 Merged [#12946] Initialise Entities for Course Structure
    11 Merged [#12946] Revert attributes removed in initialisation of MCS entitie
    12 Reviewed [#12048] Fix flaky component test
    12 Authored [#12048] Migrate InstructorCourseEnrollPageE2ETest
    13 Reviewed [#12954] CreateAccountAction seems to have redundant code
    +
    • Though they were small, I have learnt several things from these 3 projects and could see the contrast between them and TEAMMATES too
    • Had tried to do a more technical heavy one but couldn't get it working and unfortunately vs. the effort and time spent (https://github.com/mattermost/mattermost/issues/24291)

    CS3282 Pre-Semester's Progress

    Date Type Achievements
    12 May 2023 Reviewed [#12267] Instructor getting started page: Fix scroll to top #12419
    15 May 2023 Reviewed [#12407] Sort icons in info table headings are hard to see #12429
    16 May 2023 Reviewed [#12283] Add a download button for instructor view session result (course-wide) #12431
    21 May 2023 Reviewed [#10976] Document frontend standardizations #12436
    23 May 2023 Reviewed [#12430] Include student email in 'distribute points' type question summary table CSV #12435
    24 May 2023 Reviewed [#12010] Notifications box overlaps with the page menu in the instructor help page #12428
    27 May 2023 Reviewed [#10920] Add test for restoreCourse in Instructor Courses Page #12443
    30 May 2024 Reviewed [#10920] Add testing for sortCoursesBy method in instructor home page. #12440
    04 Jun 2023 Reviewed [#12099] Add 'course -> copy' option to the instructor home page #12439
    04 Jun 2023 Reviewed [#12442] Massive string is not correctly treated #12456
    05 Jun 2023 Reviewed [#10920] Added test for Instructor Course Edit Page #12462
    08 Jun 2023 Reviewed [#12464] Add verification step for Docker instance of Datastore in docs #12465
    13 Jun 2023 Reviewed [#12466] Clarify masquerade mode in docs #12470
    17 Jun 2023 Reviewed [#12269] Instructor edit sessions page: Fix add question button overflow. #12476
    25 Jun 2023 Reviewed [#1501] Add tests cases to FeedbackRankOptionsQuestionDetails #12475
    25 Jun 2023 Reviewed [#12481] Fix running of component tests using Windows Powershell #12482
    29 Jun 2023 Reviewed [#12400] Instructor editing questions: warning about visibility is removed if the edit is cancelled. #12495
    29 Jun 2023 Reviewed [#12268] Make instructor getting started page more prominent #12496
    02 Jul 2023 Reviewed [#12269] Instructor edit sessions page: Fix add question button overflow. #12477
    04 Jul 2023 Reviewed [#12457] Make the table buttons easier to use on mobile devices #12463
    06 Jul 2023 Reviewed [#12280] Improve display for create course card header #12500
    14 Jul 2023 Reviewed [#12517] Instructors creating sessions: response visible time should be 'not now' by default #12518
    17 Jul 2023 Reviewed [#12473] Add steps on how to use the masquerade mode in developer guide #12506
    02 Aug 2023 Reviewed [#12455] Limit word and character count for text editor. #12503
    06 Aug 2023 Reviewed [#12538] Instructor sessions page: Empty deleted sessions table is not displayed #12546
    19 Aug 2023 Reviewed [#12544] Rubric Question Statistics: Handle empty weights #12545
    01 Oct 2023 Reviewed [#12466] Docs: Clarify masquerade mode #12595
    20 Dec 2023 Reviewed [#12665] Instructor's Student Records Page: Misleading name for canceling of comment edit #12667
    20 Dec 2023 Reviewed [#12671] Remove redundant newline in Development section of Docs #12672
    23 Dec 2023 Reviewed [#12652] Copying feedback session: mark session name as mandatory field when copying feedback session #12670
    24 Dec 2023 Reviewed [#12656] Student Home Page: Indicate default sort #12660
    24 Dec 2023 Reviewed [#12658] Instructor Home Page: Dropdown buttons on mobile #12662
    25 Dec 2023 Reviewed [#12654] Instructor Edit Session Page: Bug in Grace Period Tooltip #12675
    28 Dec 2023 Reviewed [#12663] Instructor's Student Records Page: Tooltips for comments #12676
    30 Dec 2023 Reviewed [#12664] Instructor's Student Records Page: Accessibility issue for comment buttons #12683
    30 Dec 2023 Reviewed [#12669] Update Documentation to include updating of snapshot tests #12684
    31 Dec 2023 Reviewed [#12649] When adding a comment while submitting responses, show visibility of the comment as well #12659
    02 Jan 2024 Reviewed [#12375] Incorrect Developer Website link in Contact page #12686

    CS3282 Semester's Progress

    Week Type Achievements
    1 Merged [#12052] Per Receiver Submission #12053
    1 Reviewed [#12657] Instructor Home Page: Students dropdown buttons of the wrong colour . #12691
    2 Reviewed [#12048] Migrate UpdateInstructorAction #12434
    2 Reviewed [#12699] Replace ng command in setting-up.md #12701
    2 Reviewed [#12699] Replace ng command in setting-up.md #12701
    3 Merged [#12048] Migrate RemoveDataBundle #12709
    3 Reviewed [#12048] Migrate enroll students action #12715
    4 Reviewed [#12048] Migrate search account requests action #12726
    4 Reviewed [#12048] Support for twin db for search + replace datastore test #12728
    4 Reviewed [#12693] Excess padding on edit course details component #12737
    6 Reviewed [#12048] Migrate GetSessionResultsAction #12719
    6, R, 7 Data Migration Together with the team
    R Reviewed [#12048] Bump up postgresql version #12784
    R Reviewed [#12048] Add tests for CourseDbIT #12786
    R Reviewed [#12048] migrate InstructorCourseJoinConfirmationPageE2ETest #12790
    R Reviewed [#12048] migrate AdminHomePageE2ETest #12794
    R Merged [#12048] Fix incorrect usage of recipient as param for E2E test #12797
    R Reviewed [#12048] Add migration script for Account Request #12799
    R Reviewed [#12048] Move accounts JSON for InstructorStudentRecordsPageE2ETest #12828
    R Reviewed [#12048] Move accounts JSON for InstructorStudentListPageE2ETest #12830
    R Reviewed [#12048] Move accounts JSON for InstructorSessionIndividualExtensionPageE2ETest #12832
    R Reviewed [#12048] Move accounts JSON for InstructorFeedbackSessionsPageE2ETest #12834
    R Authored (WIP) [#12048] Refactor FeedbackResponses and FeedbackResponseComments attributes
    7 Reviewed [#12048] Add integration tests for FeedbackResponsesDb #12856
    7 Contributed [#12048] Fix account creation #12871
    8 Merged [#12048] Add deep comparison for entities in verifyEquals for E2E
    9 Reviewed [#12588] Improve test code coverage of core components - ToastComponent
    9 Reviewed [#12588] Improve test code coverage of core components - ViewResultsPanelComponent
    10 Reviewed [#12946] Enable CI on Multiple Course Structures branch
    10 Merged [#12946] Initialise Entities for Course Structure
    11 Merged [#12946] Revert attributes removed in initialisation of MCS entitie
    12 Reviewed [#12048] Fix flaky component test
    12 Authored [#12048] Migrate InstructorCourseEnrollPageE2ETest
    13 Reviewed [#12954] CreateAccountAction seems to have redundant code
    diff --git a/students/domlimm/progress.page-vue-render.js b/students/domlimm/progress.page-vue-render.js index 97397428e..52567753b 100644 --- a/students/domlimm/progress.page-vue-render.js +++ b/students/domlimm/progress.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('h1',{attrs:{"id":"summary"}},[_v("Summary"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#summary","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Since CS3281, I have tried my best to keep up as a maintainer by reviewing PRs and contribute to conversations in Issues and Discussions.")]),_v(" "),_c('p',[_v("In CS3282, about 80% of the work done was from PR reviews.")]),_v(" "),_c('p',[_v("Aside from the technicalities, I was also a mentor to Dominic Berzin where I do check-ins with him, review his work done and providing guidance wherever necessary.")]),_v(" "),_c('p',[_v("The focus for me in CS3282 was over multiple action items/projects. I did a bit of everything except SQL Injection (but was kept in the loop).")]),_v(" "),_c('ul',[_c('li',[_v("Per-Receiver Submission wrap up")]),_v(" "),_c('li',[_v("Database Migration\n"),_c('ul',[_c('li',[_v("Working alongside the team to contribute wherever I can e.g., Scripts, reviewing of PRs")]),_v(" "),_c('li',[_v("Involved in discussios")])])]),_v(" "),_c('li',[_v("Migration of actions")]),_v(" "),_c('li',[_v("Did just 1 E2E test migration (will continue contributing/working on this after exams)")]),_v(" "),_c('li',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12791"}},[_v("Refactoring of entities")]),_v(" that use certain attributes as "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("string")]),_v(" when they should have been unique identifiers i.e., Foreign Keys, linking to another entity (in the Hibernate way) (will continue work on this after exams)\n"),_c('ul',[_c('li',[_v("Updated our ERD to reflect the new changes between the tables in the DB")])])]),_v(" "),_c('li',[_v("Multiple Course Structures (MCS) project\n"),_c('ul',[_c('li',[_v("Involved in the first discussion we had with the team")]),_v(" "),_c('li',[_v("Vetting Technical Design Docs written by CS3281 students under this project")]),_v(" "),_c('li',[_v("Updated entities with the necessary attributes for MCS to work (just the base for future batches)")]),_v(" "),_c('li',[_v("Involved in further discussions with Kevin and Wei Qing")])])]),_v(" "),_c('li',[_v("External contributions to 3 projects\n"),_c('ul',[_c('li',[_v("Though they were small, I have learnt several things from these 3 projects and could see the contrast between them and TEAMMATES too")]),_v(" "),_c('li',[_v("Had tried to do a more technical heavy one but couldn't get it working and unfortunately vs. the effort and time spent ("),_c('a',{attrs:{"href":"https://github.com/mattermost/mattermost/issues/24291"}},[_v("https://github.com/mattermost/mattermost/issues/24291")]),_v(")")])])])]),_v(" "),_c('h1',{attrs:{"id":"cs3282-pre-semester-s-progress"}},[_v("CS3282 Pre-Semester's Progress"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#cs3282-pre-semester-s-progress","onclick":"event.stopPropagation()"}})]),_v(" "),_c('div',{staticClass:"table-responsive"},[_c('table',{staticClass:"markbind-table table table-bordered table-striped"},[_c('thead',[_c('tr',[_c('th',[_v("Date")]),_v(" "),_c('th',[_v("Type")]),_v(" "),_c('th',[_v("Achievements")])])]),_v(" "),_c('tbody',[_c('tr',[_c('td',[_v("12 May 2023")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12419"}},[_v("[#12267] Instructor getting started page: Fix scroll to top #12419")])])]),_v(" "),_c('tr',[_c('td',[_v("15 May 2023")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12429"}},[_v("[#12407] Sort icons in info table headings are hard to see #12429")])])]),_v(" "),_c('tr',[_c('td',[_v("16 May 2023")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12431"}},[_v("[#12283] Add a download button for instructor view session result (course-wide) #12431")])])]),_v(" "),_c('tr',[_c('td',[_v("21 May 2023")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12436"}},[_v("[#10976] Document frontend standardizations #12436")])])]),_v(" "),_c('tr',[_c('td',[_v("23 May 2023")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12435"}},[_v("[#12430] Include student email in 'distribute points' type question summary table CSV #12435")])])]),_v(" "),_c('tr',[_c('td',[_v("24 May 2023")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12428"}},[_v("[#12010] Notifications box overlaps with the page menu in the instructor help page #12428")])])]),_v(" "),_c('tr',[_c('td',[_v("27 May 2023")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12443"}},[_v("[#10920] Add test for restoreCourse in Instructor Courses Page #12443")])])]),_v(" "),_c('tr',[_c('td',[_v("30 May 2024")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12440"}},[_v("[#10920] Add testing for sortCoursesBy method in instructor home page. #12440")])])]),_v(" "),_c('tr',[_c('td',[_v("04 Jun 2023")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12439"}},[_v("[#12099] Add 'course -> copy' option to the instructor home page #12439")])])]),_v(" "),_c('tr',[_c('td',[_v("04 Jun 2023")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12456"}},[_v("[#12442] Massive string is not correctly treated #12456")])])]),_v(" "),_c('tr',[_c('td',[_v("05 Jun 2023")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12462"}},[_v("[#10920] Added test for Instructor Course Edit Page #12462")])])]),_v(" "),_c('tr',[_c('td',[_v("08 Jun 2023")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12465"}},[_v("[#12464] Add verification step for Docker instance of Datastore in docs #12465")])])]),_v(" "),_c('tr',[_c('td',[_v("13 Jun 2023")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12470"}},[_v("[#12466] Clarify masquerade mode in docs #12470")])])]),_v(" "),_c('tr',[_c('td',[_v("17 Jun 2023")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12476"}},[_v("[#12269] Instructor edit sessions page: Fix add question button overflow. #12476")])])]),_v(" "),_c('tr',[_c('td',[_v("25 Jun 2023")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12475"}},[_v("[#1501] Add tests cases to FeedbackRankOptionsQuestionDetails #12475")])])]),_v(" "),_c('tr',[_c('td',[_v("25 Jun 2023")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12482"}},[_v("[#12481] Fix running of component tests using Windows Powershell #12482")])])]),_v(" "),_c('tr',[_c('td',[_v("29 Jun 2023")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12495"}},[_v("[#12400] Instructor editing questions: warning about visibility is removed if the edit is cancelled. #12495")])])]),_v(" "),_c('tr',[_c('td',[_v("29 Jun 2023")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12496"}},[_v("[#12268] Make instructor getting started page more prominent #12496")])])]),_v(" "),_c('tr',[_c('td',[_v("02 Jul 2023")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12477"}},[_v("[#12269] Instructor edit sessions page: Fix add question button overflow. #12477")])])]),_v(" "),_c('tr',[_c('td',[_v("04 Jul 2023")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12463"}},[_v("[#12457] Make the table buttons easier to use on mobile devices #12463")])])]),_v(" "),_c('tr',[_c('td',[_v("06 Jul 2023")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12500"}},[_v("[#12280] Improve display for create course card header #12500")])])]),_v(" "),_c('tr',[_c('td',[_v("14 Jul 2023")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12518"}},[_v("[#12517] Instructors creating sessions: response visible time should be 'not now' by default #12518")])])]),_v(" "),_c('tr',[_c('td',[_v("17 Jul 2023")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12506"}},[_v("[#12473] Add steps on how to use the masquerade mode in developer guide #12506")])])]),_v(" "),_c('tr',[_c('td',[_v("02 Aug 2023")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12503"}},[_v("[#12455] Limit word and character count for text editor. #12503")])])]),_v(" "),_c('tr',[_c('td',[_v("06 Aug 2023")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12546"}},[_v("[#12538] Instructor sessions page: Empty deleted sessions table is not displayed #12546")])])]),_v(" "),_c('tr',[_c('td',[_v("19 Aug 2023")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12545"}},[_v("[#12544] Rubric Question Statistics: Handle empty weights #12545")])])]),_v(" "),_c('tr',[_c('td',[_v("01 Oct 2023")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12595"}},[_v("[#12466] Docs: Clarify masquerade mode #12595")])])]),_v(" "),_c('tr',[_c('td',[_v("20 Dec 2023")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12667"}},[_v("[#12665] Instructor's Student Records Page: Misleading name for canceling of comment edit #12667")])])]),_v(" "),_c('tr',[_c('td',[_v("20 Dec 2023")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12672"}},[_v("[#12671] Remove redundant newline in Development section of Docs #12672")])])]),_v(" "),_c('tr',[_c('td',[_v("23 Dec 2023")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12670"}},[_v("[#12652] Copying feedback session: mark session name as mandatory field when copying feedback session #12670")])])]),_v(" "),_c('tr',[_c('td',[_v("24 Dec 2023")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12660"}},[_v("[#12656] Student Home Page: Indicate default sort #12660")])])]),_v(" "),_c('tr',[_c('td',[_v("24 Dec 2023")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12662"}},[_v("[#12658] Instructor Home Page: Dropdown buttons on mobile #12662")])])]),_v(" "),_c('tr',[_c('td',[_v("25 Dec 2023")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12675"}},[_v("[#12654] Instructor Edit Session Page: Bug in Grace Period Tooltip #12675")])])]),_v(" "),_c('tr',[_c('td',[_v("28 Dec 2023")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12676"}},[_v("[#12663] Instructor's Student Records Page: Tooltips for comments #12676")])])]),_v(" "),_c('tr',[_c('td',[_v("30 Dec 2023")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12683"}},[_v("[#12664] Instructor's Student Records Page: Accessibility issue for comment buttons #12683")])])]),_v(" "),_c('tr',[_c('td',[_v("30 Dec 2023")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12684"}},[_v("[#12669] Update Documentation to include updating of snapshot tests #12684")])])]),_v(" "),_c('tr',[_c('td',[_v("31 Dec 2023")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12659"}},[_v("[#12649] When adding a comment while submitting responses, show visibility of the comment as well #12659")])])]),_v(" "),_c('tr',[_c('td',[_v("02 Jan 2024")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12686"}},[_v("[#12375] Incorrect Developer Website link in Contact page #12686")])])])])])]),_c('h1',{attrs:{"id":"cs3282-semester-s-progress"}},[_v("CS3282 Semester's Progress"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#cs3282-semester-s-progress","onclick":"event.stopPropagation()"}})]),_v(" "),_c('div',{staticClass:"table-responsive"},[_c('table',{staticClass:"markbind-table table table-bordered table-striped"},[_c('thead',[_c('tr',[_c('th',[_v("Week")]),_v(" "),_c('th',[_v("Type")]),_v(" "),_c('th',[_v("Achievements")])])]),_v(" "),_c('tbody',[_c('tr',[_c('td',[_v("1")]),_v(" "),_c('td',[_v("Merged")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12053"}},[_v("[#12052] Per Receiver Submission #12053")])])]),_v(" "),_c('tr',[_c('td',[_v("1")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12691"}},[_v("[#12657] Instructor Home Page: Students dropdown buttons of the wrong colour . #12691")])])]),_v(" "),_c('tr',[_c('td',[_v("2")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12434"}},[_v("[#12048] Migrate UpdateInstructorAction #12434")])])]),_v(" "),_c('tr',[_c('td',[_v("2")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12701"}},[_v("[#12699] Replace ng command in setting-up.md #12701")])])]),_v(" "),_c('tr',[_c('td',[_v("2")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12701"}},[_v("[#12699] Replace ng command in setting-up.md #12701")])])]),_v(" "),_c('tr',[_c('td',[_v("3")]),_v(" "),_c('td',[_v("Merged")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12709"}},[_v("[#12048] Migrate RemoveDataBundle #12709")])])]),_v(" "),_c('tr',[_c('td',[_v("3")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12715"}},[_v("[#12048] Migrate enroll students action #12715")])])]),_v(" "),_c('tr',[_c('td',[_v("4")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12726"}},[_v("[#12048] Migrate search account requests action #12726")])])]),_v(" "),_c('tr',[_c('td',[_v("4")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12728"}},[_v("[#12048] Support for twin db for search + replace datastore test #12728")])])]),_v(" "),_c('tr',[_c('td',[_v("4")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12737"}},[_v("[#12693] Excess padding on edit course details component #12737")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12719"}},[_v("[#12048] Migrate GetSessionResultsAction #12719")])])]),_v(" "),_c('tr',[_c('td',[_v("6, R, 7")]),_v(" "),_c('td',[_v("Data Migration")]),_v(" "),_c('td',[_v("Together with the team")])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12784"}},[_v("[#12048] Bump up postgresql version #12784")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12786"}},[_v("[#12048] Add tests for CourseDbIT #12786")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12790"}},[_v("[#12048] migrate InstructorCourseJoinConfirmationPageE2ETest #12790")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12794"}},[_v("[#12048] migrate AdminHomePageE2ETest #12794")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Merged")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12797"}},[_v("[#12048] Fix incorrect usage of recipient as param for E2E test #12797")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12799"}},[_v("[#12048] Add migration script for Account Request #12799")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12828"}},[_v("[#12048] Move accounts JSON for InstructorStudentRecordsPageE2ETest #12828")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12830"}},[_v("[#12048] Move accounts JSON for InstructorStudentListPageE2ETest #12830")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12832"}},[_v("[#12048] Move accounts JSON for InstructorSessionIndividualExtensionPageE2ETest #12832")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12834"}},[_v("[#12048] Move accounts JSON for InstructorFeedbackSessionsPageE2ETest #12834")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Authored (WIP)")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12791"}},[_v("[#12048] Refactor FeedbackResponses and FeedbackResponseComments attributes")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12856"}},[_v("[#12048] Add integration tests for FeedbackResponsesDb #12856")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Contributed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12871"}},[_v("[#12048] Fix account creation #12871")])])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_v("Merged")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12892"}},[_v("[#12048] Add deep comparison for entities in verifyEquals for E2E")])])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12916"}},[_v("[#12588] Improve test code coverage of core components - ToastComponent")])])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12918"}},[_v("[#12588] Improve test code coverage of core components - ViewResultsPanelComponent")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12947"}},[_v("[#12946] Enable CI on Multiple Course Structures branch")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Merged")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12948"}},[_v("[#12946] Initialise Entities for Course Structure")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Merged")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12983"}},[_v("[#12946] Revert attributes removed in initialisation of MCS entitie")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13003"}},[_v("[#12048] Fix flaky component test")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Authored")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13022"}},[_v("[#12048] Migrate InstructorCourseEnrollPageE2ETest")])])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_v("Reviewed")]),_v(" "),_c('td',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13039"}},[_v("[#12954] CreateAccountAction seems to have redundant code")])])])])])])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/domoberzin/info.html b/students/domoberzin/info.html index 1f20f1dee..5dd4d01bf 100644 --- a/students/domoberzin/info.html +++ b/students/domoberzin/info.html @@ -12,7 +12,7 @@ const baseUrl = '/2024' - + diff --git a/students/domoberzin/info.page-vue-render.js b/students/domoberzin/info.page-vue-render.js index c53324089..a97efd359 100644 --- a/students/domoberzin/info.page-vue-render.js +++ b/students/domoberzin/info.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('p',[_c('span',{attrs:{"id":"github"}},[_c('a',{attrs:{"href":"https://www.github.com/domoberzin"}},[_v("https://www.github.com/domoberzin")])])]),_v(" "),_c('p',[_c('span',{attrs:{"id":"projects"}},[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates"}},[_v("TEAMMATES")])])])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/domoberzin/knowledge.html b/students/domoberzin/knowledge.html index 79c997589..7c0c58dd0 100644 --- a/students/domoberzin/knowledge.html +++ b/students/domoberzin/knowledge.html @@ -12,7 +12,7 @@ const baseUrl = '/2024' -

    Hibernate

    As part of the v9-migration, I had to familiarise myself with the Hibernate ORM. It is my first time using Hibernate ORM, as I was only familiar with the Eloquent ORM from Laravel, as well as the ORM from Django. ORMs are extremely beneficial as they essentially translate between data representations used in the application and those in the database. It also makes your code more readable as it simplifies complex queries and makes transitioning between various database engines seamless, should the need arise.

    Aspects Learnt:

    • Learnt the fundamentals of Object-Relational Mapping (ORM), enabling the conversion of data between the database and object-oriented programming languages, in particular Java
    • Usage of persist and merge to insert or update an entity respectively
    • Learnt about Hibernate's internal caching mechanisms
    • Managing transactions

    Resources

    Solr

    TEAMMATES uses Solr for full-text search, and is structured to function for both the datastore and SQL databases.

    Aspects Learnt:

    • Gained proficiency in Solr's query syntax to perform powerful searches, including filtering, sorting, and faceting to retrieve relevant documents efficiently
    • Understood how Solr is integrated into the TEAMMATES backend for searching or indexing

    Resources:

    PostgreSQL

    Having only used SQLite and MySQL in the past, I had to familiarise myself with PostgreSQL as it is the SQL database used in TEAMMATES.

    Aspects Learnt:

    • Learnt about PostgreSQL's architecture, including its use of processes for client connections, MVCC (Multiversion Concurrency Control), and its write-ahead logging (WAL) for data integrity
    • Write-Ahead Logging (WAL) involves recording changes to a log before any changes are made to the actual database. This method is crucial for recovery after a crash, as it ensures that all committed transactions are saved.
    • MVCC allows multiple users to access the database concurrently without locking the data. This means readers don't block writers and vice-versa, leading to increased performance and lower waiting times during operations, which is a significant advantage over MySQL's more traditional locking mechanisms
    • Learnt about the differences between the 3 SQL database engines

    Resources:

    Angular

    Having had no experience utilising Angular prior to working on TEAMMATES, I was introduced to several neat features that Angular has to offer.

    Aspects Learnt:

    • Angular's component-based architecture makes it easy to build and maintain large applications. Each component is encapsulated with its own functionality and is responsible for a specific UI element. This modularity allowed me to quickly understand and contribute to the project, as I could focus on individual components without being overwhelmed by the entire codebase.

    • Angular's dependency injection system is a design pattern in which a class receives its dependencies from external sources rather than creating them itself. This approach simplifies the development of large applications by making it easier to manage and test components.

    • Angular offers the trackBy function, which I used in conjunction with the *ngFor directive to manage lists more efficiently. Normally, *ngFor can be inefficient because it re-renders the entire list when the data changes. However, by implementing trackBy, Angular can track each item's identity and only re-render items that have actually changed. This reduces the performance cost, especially in large lists where only a few items change.

    Google Cloud

    When deploying the staging environment for the ARF upgrade, I managed to work with and gain familiarity with the deployment workflow, as well as several GCP tools and the gcloud sdk.

    Aspects Learnt

    • Navigating GCP and the services they have to offer
    • Setting up OAuth 2.0 Client and Gmail API credentials
    • Configuring up a VPC for communication between various services
    • Deployment using gcloud
    • Navigating server logs to investigate issues

    Resources:

    Snapshot Testing

    Snapshot testing with Jest is an effective strategy to ensure that user interfaces remain consistent despite code changes. It's important for developers to maintain updated snapshots and commit these changes as part of their regular development process.

    Snapshot tests are particularly useful for detecting unexpected changes in the UI. By capturing the "snapshot" of an output, developers can compare the current component render against a stored version. If changes occur that aren't captured in a new snapshot, the test will fail, signaling the need for a review.

    Unit Testing with Mockito

    Mockito is a popular Java-based framework used primarily for unit testing. It allows developers to isolate the units of code they are testing, to focus solely on the component of software that is being tested.

    Mockito allows developers to create mock implementations of dependencies for a particular class. This way, developers can isolate the behavior of the class itself without needing the actual dependencies to be active. By using mock objects instead of real ones, tests can be simplified as they don’t have to cater to the complexities of actual dependencies, such as database connections or external services. Mockito also provides tools to verify that certain behaviors happened during the test. For example, it can verify that a method was called with certain parameters or a certain number of times.

    Resources:

    E2E Testing

    E2E Testing allows us to ensure that the application functions as expected from the perspective of the user. This type of testing simulates real user scenarios to validate the complete functionality of the application. Common tools for conducting E2E testing include Selenium, Playwright, and Cypress.

    Throughout the semester, I had to migrate several E2E tests and also create some new ones as part of the ARF project, which exposed me to the Page Object Model, which allows for easier testing and maintenance. It enhances code reusability as the same Page Object Model can be reused across related test cases.

    E2E Tests may be the most complicated type of test to write, as it involves multiple components of the application; testing it as a whole, rather than in isolated components. As such, pinpointing the sources of errors or failures can be difficult. E2E Tests can also be flaky at times, passing in one run, and failing on others, which could occur due to numerous reasons such as timing issues, concurrency problems or subtle bugs that occur under specific circumstances. However, it is still highly useful as it helps to identify issues in the interaction between integrated components, and also simulates real user scenarios.

    Resources:

    +

    Hibernate

    As part of the v9-migration, I had to familiarise myself with the Hibernate ORM. It is my first time using Hibernate ORM, as I was only familiar with the Eloquent ORM from Laravel, as well as the ORM from Django. ORMs are extremely beneficial as they essentially translate between data representations used in the application and those in the database. It also makes your code more readable as it simplifies complex queries and makes transitioning between various database engines seamless, should the need arise.

    Aspects Learnt:

    • Learnt the fundamentals of Object-Relational Mapping (ORM), enabling the conversion of data between the database and object-oriented programming languages, in particular Java
    • Usage of persist and merge to insert or update an entity respectively
    • Learnt about Hibernate's internal caching mechanisms
    • Managing transactions

    Resources

    Solr

    TEAMMATES uses Solr for full-text search, and is structured to function for both the datastore and SQL databases.

    Aspects Learnt:

    • Gained proficiency in Solr's query syntax to perform powerful searches, including filtering, sorting, and faceting to retrieve relevant documents efficiently
    • Understood how Solr is integrated into the TEAMMATES backend for searching or indexing

    Resources:

    PostgreSQL

    Having only used SQLite and MySQL in the past, I had to familiarise myself with PostgreSQL as it is the SQL database used in TEAMMATES.

    Aspects Learnt:

    • Learnt about PostgreSQL's architecture, including its use of processes for client connections, MVCC (Multiversion Concurrency Control), and its write-ahead logging (WAL) for data integrity
    • Write-Ahead Logging (WAL) involves recording changes to a log before any changes are made to the actual database. This method is crucial for recovery after a crash, as it ensures that all committed transactions are saved.
    • MVCC allows multiple users to access the database concurrently without locking the data. This means readers don't block writers and vice-versa, leading to increased performance and lower waiting times during operations, which is a significant advantage over MySQL's more traditional locking mechanisms
    • Learnt about the differences between the 3 SQL database engines

    Resources:

    Angular

    Having had no experience utilising Angular prior to working on TEAMMATES, I was introduced to several neat features that Angular has to offer.

    Aspects Learnt:

    • Angular's component-based architecture makes it easy to build and maintain large applications. Each component is encapsulated with its own functionality and is responsible for a specific UI element. This modularity allowed me to quickly understand and contribute to the project, as I could focus on individual components without being overwhelmed by the entire codebase.

    • Angular's dependency injection system is a design pattern in which a class receives its dependencies from external sources rather than creating them itself. This approach simplifies the development of large applications by making it easier to manage and test components.

    • Angular offers the trackBy function, which I used in conjunction with the *ngFor directive to manage lists more efficiently. Normally, *ngFor can be inefficient because it re-renders the entire list when the data changes. However, by implementing trackBy, Angular can track each item's identity and only re-render items that have actually changed. This reduces the performance cost, especially in large lists where only a few items change.

    Google Cloud

    When deploying the staging environment for the ARF upgrade, I managed to work with and gain familiarity with the deployment workflow, as well as several GCP tools and the gcloud sdk.

    Aspects Learnt

    • Navigating GCP and the services they have to offer
    • Setting up OAuth 2.0 Client and Gmail API credentials
    • Configuring up a VPC for communication between various services
    • Deployment using gcloud
    • Navigating server logs to investigate issues

    Resources:

    Snapshot Testing

    Snapshot testing with Jest is an effective strategy to ensure that user interfaces remain consistent despite code changes. It's important for developers to maintain updated snapshots and commit these changes as part of their regular development process.

    Snapshot tests are particularly useful for detecting unexpected changes in the UI. By capturing the "snapshot" of an output, developers can compare the current component render against a stored version. If changes occur that aren't captured in a new snapshot, the test will fail, signaling the need for a review.

    Unit Testing with Mockito

    Mockito is a popular Java-based framework used primarily for unit testing. It allows developers to isolate the units of code they are testing, to focus solely on the component of software that is being tested.

    Mockito allows developers to create mock implementations of dependencies for a particular class. This way, developers can isolate the behavior of the class itself without needing the actual dependencies to be active. By using mock objects instead of real ones, tests can be simplified as they don’t have to cater to the complexities of actual dependencies, such as database connections or external services. Mockito also provides tools to verify that certain behaviors happened during the test. For example, it can verify that a method was called with certain parameters or a certain number of times.

    Resources:

    E2E Testing

    E2E Testing allows us to ensure that the application functions as expected from the perspective of the user. This type of testing simulates real user scenarios to validate the complete functionality of the application. Common tools for conducting E2E testing include Selenium, Playwright, and Cypress.

    Throughout the semester, I had to migrate several E2E tests and also create some new ones as part of the ARF project, which exposed me to the Page Object Model, which allows for easier testing and maintenance. It enhances code reusability as the same Page Object Model can be reused across related test cases.

    E2E Tests may be the most complicated type of test to write, as it involves multiple components of the application; testing it as a whole, rather than in isolated components. As such, pinpointing the sources of errors or failures can be difficult. E2E Tests can also be flaky at times, passing in one run, and failing on others, which could occur due to numerous reasons such as timing issues, concurrency problems or subtle bugs that occur under specific circumstances. However, it is still highly useful as it helps to identify issues in the interaction between integrated components, and also simulates real user scenarios.

    Resources:

    diff --git a/students/domoberzin/knowledge.page-vue-render.js b/students/domoberzin/knowledge.page-vue-render.js index d8b0d8f2c..dd87cc14d 100644 --- a/students/domoberzin/knowledge.page-vue-render.js +++ b/students/domoberzin/knowledge.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('h3',{attrs:{"id":"hibernate"}},[_v("Hibernate"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#hibernate","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("As part of the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("v9-migration")]),_v(", I had to familiarise myself with the Hibernate ORM. It is my first time using Hibernate ORM, as I was only familiar with the Eloquent ORM from Laravel, as well as the ORM from Django. ORMs are extremely beneficial as they essentially translate between data representations used in the application and those in the database. It also makes your code more readable as it simplifies complex queries and makes transitioning between various database engines seamless, should the need arise.")]),_v(" "),_c('p',[_v("Aspects Learnt:")]),_v(" "),_c('ul',[_c('li',[_v("Learnt the fundamentals of Object-Relational Mapping (ORM), enabling the conversion of data between the database and object-oriented programming languages, in particular Java")]),_v(" "),_c('li',[_v("Usage of "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("persist")]),_v(" and "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("merge")]),_v(" to insert or update an entity respectively")]),_v(" "),_c('li',[_v("Learnt about Hibernate's internal caching mechanisms")]),_v(" "),_c('li',[_v("Managing transactions")])]),_v(" "),_c('p',[_v("Resources")]),_v(" "),_c('ul',[_c('li',[_c('a',{attrs:{"href":"https://www.geeksforgeeks.org/hibernate-caching/"}},[_v("GeeksForGeeks Article on Hibernate Caching")])]),_v(" "),_c('li',[_c('a',{attrs:{"href":"https://hibernate.org/orm/"}},[_v("Hibernate docs")])])]),_v(" "),_c('h3',{attrs:{"id":"solr"}},[_v("Solr"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#solr","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("TEAMMATES uses Solr for full-text search, and is structured to function for both the datastore and SQL databases.")]),_v(" "),_c('p',[_v("Aspects Learnt:")]),_v(" "),_c('ul',[_c('li',[_v("Gained proficiency in Solr's query syntax to perform powerful searches, including filtering, sorting, and faceting to retrieve relevant documents efficiently")]),_v(" "),_c('li',[_v("Understood how Solr is integrated into the TEAMMATES backend for searching or indexing")])]),_v(" "),_c('p',[_v("Resources:")]),_v(" "),_c('ul',[_c('li',[_c('a',{attrs:{"href":"https://solr.apache.org/guide/solr/latest/query-guide/json-request-api.html"}},[_v("Solr JSON Request API guide")])]),_v(" "),_c('li',[_c('a',{attrs:{"href":"https://solr.apache.org/docs/6_0_0/quickstart.html"}},[_v("Solr Quickstart guide")])])]),_v(" "),_c('h3',{attrs:{"id":"postgresql"}},[_v("PostgreSQL"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#postgresql","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Having only used "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("SQLite")]),_v(" and "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("MySQL")]),_v(" in the past, I had to familiarise myself with PostgreSQL as it is the SQL database used in TEAMMATES.")]),_v(" "),_c('p',[_v("Aspects Learnt:")]),_v(" "),_c('ul',[_c('li',[_v("Learnt about PostgreSQL's architecture, including its use of processes for client connections, MVCC (Multiversion Concurrency Control), and its write-ahead logging (WAL) for data integrity")]),_v(" "),_c('li',[_v("Write-Ahead Logging (WAL) involves recording changes to a log before any changes are made to the actual database. This method is crucial for recovery after a crash, as it ensures that all committed transactions are saved.")]),_v(" "),_c('li',[_v("MVCC allows multiple users to access the database concurrently without locking the data. This means readers don't block writers and vice-versa, leading to increased performance and lower waiting times during operations, which is a significant advantage over MySQL's more traditional locking mechanisms")]),_v(" "),_c('li',[_v("Learnt about the differences between the 3 SQL database engines")])]),_v(" "),_c('p',[_v("Resources:")]),_v(" "),_c('ul',[_c('li',[_c('a',{attrs:{"href":"https://www.digitalocean.com/community/tutorials/sqlite-vs-mysql-vs-postgresql-a-comparison-of-relational-database-management-systems"}},[_v("Differences between "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("MySQL")]),_v(", "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("SQLite")]),_v(" and "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("PostgreSQL")])])])]),_v(" "),_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 no experience utilising Angular prior to working on TEAMMATES, I was introduced to several neat features that Angular has to offer.")]),_v(" "),_c('p',[_v("Aspects Learnt:")]),_v(" "),_c('ul',[_c('li',[_c('p',[_v("Angular's component-based architecture makes it easy to build and maintain large applications. Each component is encapsulated with its own functionality and is responsible for a specific UI element. This modularity allowed me to quickly understand and contribute to the project, as I could focus on individual components without being overwhelmed by the entire codebase.")])]),_v(" "),_c('li',[_c('p',[_v("Angular's dependency injection system is a design pattern in which a class receives its dependencies from external sources rather than creating them itself. This approach simplifies the development of large applications by making it easier to manage and test components.")])]),_v(" "),_c('li',[_c('p',[_v("Angular offers the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("trackBy")]),_v(" function, which I used in conjunction with the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("*ngFor")]),_v(" directive to manage lists more efficiently. Normally, "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("*ngFor")]),_v(" can be inefficient because it re-renders the entire list when the data changes. However, by implementing trackBy, Angular can track each item's identity and only re-render items that have actually changed. This reduces the performance cost, especially in large lists where only a few items change.")])])]),_v(" "),_c('h3',{attrs:{"id":"google-cloud"}},[_v("Google Cloud"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#google-cloud","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("When deploying the staging environment for the ARF upgrade, I managed to work with and gain familiarity with the deployment workflow, as well as several GCP tools and the "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("gcloud")]),_v(" sdk.")]),_v(" "),_c('p',[_v("Aspects Learnt")]),_v(" "),_c('ul',[_c('li',[_v("Navigating GCP and the services they have to offer")]),_v(" "),_c('li',[_v("Setting up OAuth 2.0 Client and Gmail API credentials")]),_v(" "),_c('li',[_v("Configuring up a VPC for communication between various services")]),_v(" "),_c('li',[_v("Deployment using gcloud")]),_v(" "),_c('li',[_v("Navigating server logs to investigate issues")])]),_v(" "),_c('p',[_v("Resources:")]),_v(" "),_c('ul',[_c('li',[_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates-ops/blob/master/platform-guide.md#deploying-to-a-staging-server"}},[_v("Guide created by mentors")])])]),_v(" "),_c('h3',{attrs:{"id":"snapshot-testing"}},[_v("Snapshot Testing"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#snapshot-testing","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Snapshot testing with Jest is an effective strategy to ensure that user interfaces remain consistent despite code changes. It's important for developers to maintain updated snapshots and commit these changes as part of their regular development process.")]),_v(" "),_c('p',[_v("Snapshot tests are particularly useful for detecting unexpected changes in the UI. By capturing the \"snapshot\" of an output, developers can compare the current component render against a stored version. If changes occur that aren't captured in a new snapshot, the test will fail, signaling the need for a review.")]),_v(" "),_c('h3',{attrs:{"id":"unit-testing-with-mockito"}},[_v("Unit Testing with Mockito"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#unit-testing-with-mockito","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Mockito is a popular Java-based framework used primarily for unit testing. It allows developers to isolate the units of code they are testing, to focus solely on the component of software that is being tested.")]),_v(" "),_c('p',[_v("Mockito allows developers to create mock implementations of dependencies for a particular class. This way, developers can isolate the behavior of the class itself without needing the actual dependencies to be active. By using mock objects instead of real ones, tests can be simplified as they don’t have to cater to the complexities of actual dependencies, such as database connections or external services. Mockito also provides tools to verify that certain behaviors happened during the test. For example, it can verify that a method was called with certain parameters or a certain number of times.")]),_v(" "),_c('p',[_v("Resources:")]),_v(" "),_c('ul',[_c('li',[_c('a',{attrs:{"href":"https://www.toptal.com/java/a-guide-to-everyday-mockito"}},[_v("Mockito Tutorials")])])]),_v(" "),_c('h3',{attrs:{"id":"e2e-testing"}},[_v("E2E Testing"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#e2e-testing","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("E2E Testing allows us to ensure that the application functions as expected from the perspective of the user. This type of testing simulates real user scenarios to validate the complete functionality of the application. Common tools for conducting E2E testing include Selenium, Playwright, and Cypress.")]),_v(" "),_c('p',[_v("Throughout the semester, I had to migrate several E2E tests and also create some new ones as part of the ARF project, which exposed me to the Page Object Model, which allows for easier testing and maintenance. It enhances code reusability as the same Page Object Model can be reused across related test cases.")]),_v(" "),_c('p',[_v("E2E Tests may be the most complicated type of test to write, as it involves multiple components of the application; testing it as a whole, rather than in isolated components. As such, pinpointing the sources of errors or failures can be difficult. E2E Tests can also be flaky at times, passing in one run, and failing on others, which could occur due to numerous reasons such as timing issues, concurrency problems or subtle bugs that occur under specific circumstances. However, it is still highly useful as it helps to identify issues in the interaction between integrated components, and also simulates real user scenarios.")]),_v(" "),_c('p',[_v("Resources:")]),_v(" "),_c('ul',[_c('li',[_c('a',{attrs:{"href":"https://www.selenium.dev/documentation/overview/"}},[_v("Selenium documentation")])]),_v(" "),_c('li',[_c('a',{attrs:{"href":"https://www.browserstack.com/guide/page-object-model-in-selenium"}},[_v("Page Object Model")])])])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/domoberzin/progress.html b/students/domoberzin/progress.html index 810f90b00..84875c037 100644 --- a/students/domoberzin/progress.html +++ b/students/domoberzin/progress.html @@ -12,7 +12,7 @@ const baseUrl = '/2024' -

    TEAMMATES

    Overview

    • Assisted in migration of EnrollStudentsAction, SearchAccountRequestsAction, AccountRequestSearchIndexingWorkerAction
    • Created test cases for methods in CoursesLogic
    • Created integration tests for GetFeedbackSessionSubmittedGiverSetAction and CoursesDb
    • Fix issue with GetSessionResponseStatsActionIT
    • Migrated AdminNotificationsE2ETest and AdminSearchPageE2ETest
    • Fix issues with dual search
    • Created wireframes for ARF upgrade
    • Updated Admin Search Page and Home Page UI for Account Requests Display
    • Created Action for Updating Account Requests (i.e. Editing and Approving)
    • Set up staging server for Account Request Form feature
    • Created E2E Tests for new features related to Account Requests
    • Investigated and rectified bugs found on staging server
    • Contributed code reviews for several ARF-related pull requests
    • Create script and workflow for updating account requests id in Solr

    Achievements by Week

    Week Achievements
    2 Submitted Issue: Excess padding on edit course details component #12693
    3 Merged PR: [#12048] Migrate enroll students action #12715
    4 Merged PR: [#12048] Migrate search account requests action #12726
    5 Merged PR: [#12048] Add tests for CoursesLogic #12746
    5 Merged PR: [#12048] Migrate AccountRequestSearchIndexingWorkerAction #12757
    6 Merged PR: [#12048] Fix GetSessionResponseStatsActionIT #12777
    6 Merged PR: [#12048] Create IT for GetFeedbackSessionSubmittedGiverSetAction #12778
    6 Merged PR: [#12048] Add tests for CoursesDbIT #12786
    R Merged PR: [#12048] Migrate Admin Notifications E2E Test #12793
    R Merged PR: [#12048] Migrate AdminSearchPageE2ETest SQL #12811
    R Merged PR: [#12048] Migrate AdminSearchPageE2ETest #12838
    7 Worked on design document for Account Request Form Upgrade
    7 Created wireframes for new Admin UI for Account Request Form Upgrade
    8 Merged PR: [#12048] Migrate InstructorSearchPageE2ETest #12891
    9 Merged PR: [#11878] Update Admin Home Page UI for ARF #12933
    9 Reviewed PR: [#11878] Remove AccountRequest unique constraint #12899
    10 Merged PR: [#11878] Update Admin Search UI for ARF #12941
    10 Reviewed PR: [#11878] Add GetAllPendingAccountRequests API #12927
    10 Reviewed PR: [#11878] Add snapshot tests for instructor request form UI #12942
    11 Reviewed PR: [#11878] Update SearchAccountRequests endpoint #12950
    11 Reviewed PR: [#11878] Merge master into account-request-form #12972
    11 Merged PR: [#11878] Create Update Account Request Action #12982
    11 Reviewed PR: [#11878] Change institute length limit #12974
    11 Reviewed PR: [#11878] Foundation for getting by ID in account request endpoints #12957
    11 Reviewed PR: [#11878] Add AccountRequest Rejection email generator. #12987
    11 Merged PR: [#11878] Add Edit and Approve Account Requests functionality #12975
    11 Merged PR: [#11878] Fix Account Request Update Search Indexing #12984
    12 Merged PR: [#11878] Create Rejection Modal for Account Requests #12989
    12 Merged PR: [#11878] Convert RejectAccountRequestAction to use transactions #13001
    12 Reviewed PR: [#11878] Update ResetAccountRequest to reference by ID #13002
    12 Merged PR: [#11878] Add Error Message for Approving Existing Account #13004
    12 Merged PR: [#11878] Handle Duplicate Approved Account Requests #13009
    12 Reviewed PR: [#11878] Merge master into feature #13011
    12 Reviewed PR: [#11878] Remove unused modal in AdminHomePage #12998
    12 Merged PR: [#11878] Add tests for Account Request Table #12977
    12 Merged PR: [#11878] Add Admin E2E Tests #13020
    12 Set-up the staging environment for testing the new Account Request Form features
    13 Reviewed PR: [#11878] Add sort by created_at for getAllPendingRequests #13038
    13 Reviewed PR: [#11878] Request Page E2E #13015
    13 Reviewed PR: [#11878] Migrate AccountRequestsLogic unit tests #13043
    13 Merged PR: [#11878] Add Toasts #13028
    13 Merged PR: [#11878] Fix Approval Email Bug #13027
    13 Merged PR: [#11878] Fix Overlapping Tooltip #13026
    13 Merged PR: [#11878] Fix Highlighting and Null Statuses #13031
    13 Merged PR: [#11878] Fix Edit #13056
    13 Merged PR: [#11878] Fix Rejection Modal #13059
    13 Merged PR: [#11878] Fix console errors #13058
    Reading Merged PR: [#11878] Account Request Indexing Script #13076
    +

    TEAMMATES

    Overview

    • Assisted in migration of EnrollStudentsAction, SearchAccountRequestsAction, AccountRequestSearchIndexingWorkerAction
    • Created test cases for methods in CoursesLogic
    • Created integration tests for GetFeedbackSessionSubmittedGiverSetAction and CoursesDb
    • Fix issue with GetSessionResponseStatsActionIT
    • Migrated AdminNotificationsE2ETest and AdminSearchPageE2ETest
    • Fix issues with dual search
    • Created wireframes for ARF upgrade
    • Updated Admin Search Page and Home Page UI for Account Requests Display
    • Created Action for Updating Account Requests (i.e. Editing and Approving)
    • Set up staging server for Account Request Form feature
    • Created E2E Tests for new features related to Account Requests
    • Investigated and rectified bugs found on staging server
    • Contributed code reviews for several ARF-related pull requests
    • Create script and workflow for updating account requests id in Solr

    Achievements by Week

    Week Achievements
    2 Submitted Issue: Excess padding on edit course details component #12693
    3 Merged PR: [#12048] Migrate enroll students action #12715
    4 Merged PR: [#12048] Migrate search account requests action #12726
    5 Merged PR: [#12048] Add tests for CoursesLogic #12746
    5 Merged PR: [#12048] Migrate AccountRequestSearchIndexingWorkerAction #12757
    6 Merged PR: [#12048] Fix GetSessionResponseStatsActionIT #12777
    6 Merged PR: [#12048] Create IT for GetFeedbackSessionSubmittedGiverSetAction #12778
    6 Merged PR: [#12048] Add tests for CoursesDbIT #12786
    R Merged PR: [#12048] Migrate Admin Notifications E2E Test #12793
    R Merged PR: [#12048] Migrate AdminSearchPageE2ETest SQL #12811
    R Merged PR: [#12048] Migrate AdminSearchPageE2ETest #12838
    7 Worked on design document for Account Request Form Upgrade
    7 Created wireframes for new Admin UI for Account Request Form Upgrade
    8 Merged PR: [#12048] Migrate InstructorSearchPageE2ETest #12891
    9 Merged PR: [#11878] Update Admin Home Page UI for ARF #12933
    9 Reviewed PR: [#11878] Remove AccountRequest unique constraint #12899
    10 Merged PR: [#11878] Update Admin Search UI for ARF #12941
    10 Reviewed PR: [#11878] Add GetAllPendingAccountRequests API #12927
    10 Reviewed PR: [#11878] Add snapshot tests for instructor request form UI #12942
    11 Reviewed PR: [#11878] Update SearchAccountRequests endpoint #12950
    11 Reviewed PR: [#11878] Merge master into account-request-form #12972
    11 Merged PR: [#11878] Create Update Account Request Action #12982
    11 Reviewed PR: [#11878] Change institute length limit #12974
    11 Reviewed PR: [#11878] Foundation for getting by ID in account request endpoints #12957
    11 Reviewed PR: [#11878] Add AccountRequest Rejection email generator. #12987
    11 Merged PR: [#11878] Add Edit and Approve Account Requests functionality #12975
    11 Merged PR: [#11878] Fix Account Request Update Search Indexing #12984
    12 Merged PR: [#11878] Create Rejection Modal for Account Requests #12989
    12 Merged PR: [#11878] Convert RejectAccountRequestAction to use transactions #13001
    12 Reviewed PR: [#11878] Update ResetAccountRequest to reference by ID #13002
    12 Merged PR: [#11878] Add Error Message for Approving Existing Account #13004
    12 Merged PR: [#11878] Handle Duplicate Approved Account Requests #13009
    12 Reviewed PR: [#11878] Merge master into feature #13011
    12 Reviewed PR: [#11878] Remove unused modal in AdminHomePage #12998
    12 Merged PR: [#11878] Add tests for Account Request Table #12977
    12 Merged PR: [#11878] Add Admin E2E Tests #13020
    12 Set-up the staging environment for testing the new Account Request Form features
    13 Reviewed PR: [#11878] Add sort by created_at for getAllPendingRequests #13038
    13 Reviewed PR: [#11878] Request Page E2E #13015
    13 Reviewed PR: [#11878] Migrate AccountRequestsLogic unit tests #13043
    13 Merged PR: [#11878] Add Toasts #13028
    13 Merged PR: [#11878] Fix Approval Email Bug #13027
    13 Merged PR: [#11878] Fix Overlapping Tooltip #13026
    13 Merged PR: [#11878] Fix Highlighting and Null Statuses #13031
    13 Merged PR: [#11878] Fix Edit #13056
    13 Merged PR: [#11878] Fix Rejection Modal #13059
    13 Merged PR: [#11878] Fix console errors #13058
    Reading Merged PR: [#11878] Account Request Indexing Script #13076
    diff --git a/students/domoberzin/progress.page-vue-render.js b/students/domoberzin/progress.page-vue-render.js index 0977a4a01..94f7e1711 100644 --- a/students/domoberzin/progress.page-vue-render.js +++ b/students/domoberzin/progress.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('h3',{attrs:{"id":"teammates"}},[_v("TEAMMATES"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#teammates","onclick":"event.stopPropagation()"}})]),_v(" "),_c('h4',{attrs:{"id":"overview"}},[_v("Overview"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#overview","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ul',[_c('li',[_v("Assisted in migration of "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("EnrollStudentsAction")]),_v(", "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("SearchAccountRequestsAction")]),_v(", "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("AccountRequestSearchIndexingWorkerAction")])]),_v(" "),_c('li',[_v("Created test cases for methods in "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("CoursesLogic")])]),_v(" "),_c('li',[_v("Created integration tests for "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("GetFeedbackSessionSubmittedGiverSetAction")]),_v(" and "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("CoursesDb")])]),_v(" "),_c('li',[_v("Fix issue with "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("GetSessionResponseStatsActionIT")])]),_v(" "),_c('li',[_v("Migrated "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("AdminNotificationsE2ETest")]),_v(" and "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("AdminSearchPageE2ETest")])]),_v(" "),_c('li',[_v("Fix issues with dual search")]),_v(" "),_c('li',[_v("Created wireframes for ARF upgrade")]),_v(" "),_c('li',[_v("Updated Admin Search Page and Home Page UI for Account Requests Display")]),_v(" "),_c('li',[_v("Created Action for Updating Account Requests (i.e. Editing and Approving)")]),_v(" "),_c('li',[_v("Set up staging server for Account Request Form feature")]),_v(" "),_c('li',[_v("Created E2E Tests for new features related to Account Requests")]),_v(" "),_c('li',[_v("Investigated and rectified bugs found on staging server")]),_v(" "),_c('li',[_v("Contributed code reviews for several ARF-related pull requests")]),_v(" "),_c('li',[_v("Create script and workflow for updating account requests id in Solr")])]),_v(" "),_c('h4',{attrs:{"id":"achievements-by-week"}},[_v("Achievements by Week"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#achievements-by-week","onclick":"event.stopPropagation()"}})]),_v(" "),_c('div',{staticClass:"table-responsive"},[_c('table',{staticClass:"markbind-table table table-bordered table-striped"},[_c('thead',[_c('tr',[_c('th',[_v("Week")]),_v(" "),_c('th',[_v("Achievements")])])]),_v(" "),_c('tbody',[_c('tr',[_c('td',[_v("2")]),_v(" "),_c('td',[_v("Submitted Issue: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/issues/12693"}},[_v("Excess padding on edit course details component #12693")])])]),_v(" "),_c('tr',[_c('td',[_v("3")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12715"}},[_v("[#12048] Migrate enroll students action #12715")])])]),_v(" "),_c('tr',[_c('td',[_v("4")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12726"}},[_v("[#12048] Migrate search account requests action #12726")])])]),_v(" "),_c('tr',[_c('td',[_v("5")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12746"}},[_v("[#12048] Add tests for CoursesLogic #12746")])])]),_v(" "),_c('tr',[_c('td',[_v("5")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12757"}},[_v("[#12048] Migrate AccountRequestSearchIndexingWorkerAction #12757")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12777"}},[_v("[#12048] Fix GetSessionResponseStatsActionIT #12777")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12778"}},[_v("[#12048] Create IT for GetFeedbackSessionSubmittedGiverSetAction #12778")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12786"}},[_v("[#12048] Add tests for CoursesDbIT #12786")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12793"}},[_v("[#12048] Migrate Admin Notifications E2E Test #12793")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12811"}},[_v("[#12048] Migrate AdminSearchPageE2ETest SQL #12811")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12838"}},[_v("[#12048] Migrate AdminSearchPageE2ETest #12838")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Worked on design document for Account Request Form Upgrade")])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Created wireframes for new Admin UI for Account Request Form Upgrade")])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12891"}},[_v("[#12048] Migrate InstructorSearchPageE2ETest #12891")])])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12933"}},[_v("[#11878] Update Admin Home Page UI for ARF #12933")])])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12899"}},[_v("[#11878] Remove AccountRequest unique constraint #12899")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12941"}},[_v("[#11878] Update Admin Search UI for ARF #12941")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12927"}},[_v("[#11878] Add GetAllPendingAccountRequests API #12927")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12942"}},[_v("[#11878] Add snapshot tests for instructor request form UI #12942")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12950"}},[_v("[#11878] Update SearchAccountRequests endpoint #12950")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12972"}},[_v("[#11878] Merge master into account-request-form #12972")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12982"}},[_v("[#11878] Create Update Account Request Action #12982")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12974"}},[_v("[#11878] Change institute length limit #12974")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12957"}},[_v("[#11878] Foundation for getting by ID in account request endpoints #12957")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12987"}},[_v("[#11878] Add AccountRequest Rejection email generator. #12987")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12975"}},[_v("[#11878] Add Edit and Approve Account Requests functionality #12975")])])]),_v(" "),_c('tr',[_c('td',[_v("11")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12984"}},[_v("[#11878] Fix Account Request Update Search Indexing #12984")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12989"}},[_v("[#11878] Create Rejection Modal for Account Requests #12989")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13001"}},[_v("[#11878] Convert RejectAccountRequestAction to use transactions #13001")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13002"}},[_v("[#11878] Update ResetAccountRequest to reference by ID #13002")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13004"}},[_v("[#11878] Add Error Message for Approving Existing Account #13004")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13009"}},[_v("[#11878] Handle Duplicate Approved Account Requests #13009")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13011"}},[_v("[#11878] Merge master into feature #13011")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12998"}},[_v("[#11878] Remove unused modal in AdminHomePage #12998")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/12977"}},[_v("[#11878] Add tests for Account Request Table #12977")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13020"}},[_v("[#11878] Add Admin E2E Tests #13020")])])]),_v(" "),_c('tr',[_c('td',[_v("12")]),_v(" "),_c('td',[_v("Set-up the staging environment for testing the new Account Request Form features")])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13038"}},[_v("[#11878] Add sort by created_at for getAllPendingRequests #13038")])])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13015"}},[_v("[#11878] Request Page E2E #13015")])])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13043"}},[_v("[#11878] Migrate AccountRequestsLogic unit tests #13043")])])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13028"}},[_v("[#11878] Add Toasts #13028")])])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13027"}},[_v("[#11878] Fix Approval Email Bug #13027")])])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13026"}},[_v("[#11878] Fix Overlapping Tooltip #13026")])])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13031"}},[_v("[#11878] Fix Highlighting and Null Statuses #13031")])])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13056"}},[_v("[#11878] Fix Edit #13056")])])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13059"}},[_v("[#11878] Fix Rejection Modal #13059")])])]),_v(" "),_c('tr',[_c('td',[_v("13")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13058"}},[_v("[#11878] Fix console errors #13058")])])]),_v(" "),_c('tr',[_c('td',[_v("Reading")]),_v(" "),_c('td',[_v("Merged PR: "),_c('a',{attrs:{"href":"https://github.com/TEAMMATES/teammates/pull/13076"}},[_v("[#11878] Account Request Indexing Script #13076")])])])])])])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/gok99/info.html b/students/gok99/info.html index c8896a717..f7975e6b6 100644 --- a/students/gok99/info.html +++ b/students/gok99/info.html @@ -12,7 +12,7 @@ const baseUrl = '/2024' - + diff --git a/students/gok99/info.page-vue-render.js b/students/gok99/info.page-vue-render.js index 96d67c168..87eb141f9 100644 --- a/students/gok99/info.page-vue-render.js +++ b/students/gok99/info.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('p',[_c('span',{attrs:{"id":"github"}},[_c('a',{attrs:{"href":"https://www.github.com/gok99"}},[_v("https://www.github.com/gok99")])])]),_v(" "),_c('p',[_c('span',{attrs:{"id":"projects"}},[_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense"}},[_v("RepoSense")])])])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/gok99/knowledge.html b/students/gok99/knowledge.html index 50821733b..95ac88198 100644 --- a/students/gok99/knowledge.html +++ b/students/gok99/knowledge.html @@ -12,7 +12,7 @@ const baseUrl = '/2024' -

    CS3282

    In general, the theme of my explorations and work in CS3282 revolves around ideas in programming language research and functional programming, which are all things I'd like to pursue in the future. The lightning talks exposed me to new ideas in programming languages (some described below). The book review assignment gave me the valuable counter-opinion that formal methods and newer fancy-type systems might actually limit the flexibility of real-world software. Java, which is very much an unfancy language, is certainly very practical and doesn't have support for many of these techniques. Regardless, we can borrow ideas like immutability and apply them to any practical system. To that effect, I've also tried to start refactors of the RepoSense backend to introduce principles like immutability and optional monads to make things easier to maintain and reason about.

    Overall, I really appreciated the flexibility afforded by CS3282, which allowed me to explore more fringe and niche ideas that are starting to make their way into the programming practitioner's toolkit.

    Functional logic programming

    In my explorations for the first lightning talk, I also came across functional logic programming. I had previously been separately familiar with functional and logic programming, and it was nice to see a foundational work for a core calculus for the combination of these paradigms, each of which has rich literature. The Verse Calculus provides a minimal language that can be evaluated with a consistent set of rewrite rules that have a number of nice properties. This work comes out of Epic Games by researchers like Simon Peyton Jones, Lennart Augustsson, Guy Steele, and Ranjit Jhala, all people I've heard of before relating to other highly influential work.

    Effect systems

    Research for my second lightning talk got me interested in and learning about effect systems. Effect systems refer to systems that track and allow reasoning about unobvious side effects that functions and routines could have, like mutation, divergence (possible nontermination), network access, exceptions, etc. I found several real-world (used in practice) examples of effect systems like Scala Zio, Effect-TS (inspired heavily by Zio), and algebraic effects in OCaml (which very recently got significant syntactical updates in OCaml 5.3). The theory for algebraic effect systems is very rich and shows that effect systems are at least as expressive as monadic effects, which are widely adopted in pure functional programming languages like Haskell.


    CS3281

    Gradle

    Gradle is a very flexible build automation tool used for everything from testing and formatting, to builds and deployments. Unlike with other build automation tools like Maven where build scripts written in XML (a widely hated feature of the tool), Gradle build scripts are written in a domain specific language based on Groovy or Kotlin, which are both JVM based languages. This means that it can interact seamlessly with Java libraries.

    Gradle is also much more performant than alternatives like Maven because of its:

    • Build caching: Only reruns tasks whose inputs have been changed.
    • Gradle daemon: A background process that stores information about the project in memory so that startup time can be cut down during builds.

    RepoSense recently added functionality for hot reload on frontend as a Gradle task, which made frontend development a lot more productive. Unfortunately, the feature isn't available on Linux because the package we were using (Apache Ant's condition package) could not specifically check for it. Migrating to Gradle's own platform package recently taken out of incubation, allowed us to support all 3 prominent operating systems.

    References:

    GitHub Actions and API

    Like Gradle, Github Actions help with automation of workflows like CI/CD and project management, and can be triggered by a variety of events (pull requests, issues, releases, forks, etc). It also has a growing library of plugins that make workflows a lot easier to set-up. I was surprised that there is some nice tooling support for GitHub actions on IntelliJ.

    GitHub actions allows users to run CI on a variety of operating systems, such as Ubuntu XX.04, macOS and Windows Server (which is virtually the same as Windows 10/11 but with better hardware support and more stringent security features).

    GitHub also provides a variety of API to interact with these objects. One quirk I came across with the API was that posting single comments on pull requests need to go through the issues endpoint instead of the pulls endpoint (the endpoint for pulls requires code to be referenced). This doesn't cause problems since issues and pulls will never have identical IDs.

    GitHub deployment APIs also returns deployment information in pages, which is a sensible thing to do but can cause slight inconvenience when long running PRs have more deployments than can fit in a page.

    Actions and APIs also have some great documentation:

    Git Remotes

    Git exploded in popularity in large part due to Git hosting providers like GitHub. GitLab and Bitbucket are also commonly used Git hosts. RepoSense has thus far only largely supported GitHub, but there is a clear incentive to support other commonly used remotes. This is made a little challenging due to differences in conventions between the sites:

    base_url Commit View Blame View
    GitHub github.com {base_url}/{org}/{repo_name}/commit/{commit_hash} {base_url}/{org}/{repo_name}/blame/{branch}/{file_path}
    GitLab gitlab.com {base_url}/{org}/{repo_name}/-/commit/{commit_hash} {base_url}/{org}/{repo_name}/-/blame/{branch}/{file_path}
    Bitbucket bitbucket.org {base_url}/{org}/{repo_name}/commits/{commit_hash} {base_url}/{org}/{repo_name}/annotate/{branch}/{file_path}

    For example, Bitbucket uses the term 'annotate' instead of 'blame' because the word 'blame' is insufficiently positive.

    Triangular Git workflows

    In investigating the output of git remote -v, I noticed there were 2 remotes (fetch and push) for each remote name, which I was confused by. The utility of the separation of fetch and push remotes is for triangular workflows.

    We are probably familiar with the common workflow for updating a branch on a forked repo which involves first pulling updates from upstream master, then making changes and pushing to our own fork. This requires remembering to fetch and push to separate repos. With triangular workflows, you can have fetch and push apply to separate repos but with the same remote name, which makes this process much more convenient.

    Cypress Tests

    Cypress is a frontend testing tool for testing applications that run in the browser, with tests that are easy to read and write. It uses browser automation (similar to Selenium) and comes with a browser and relevant dependencies out of the box, so it's very easy to set-up. Cypress also provides a dashboard for convenient monitoring of test runs.

    https://docs.cypress.io/guides/overview/why-cypress#In-a-nutshell

    Bash Scripting

    Bash scripts can be run in a github action workflow, which greatly expands the scope of things you can do with actions. Bash is quite expressive (I hadn't realised just how much it could do). some cool things I learned you could do:

    • {$VAR,,} to lowercase string in $VAR.
    • $* gives parameter values separated by the value in IFS (Internal File Separator).
    • Pipe output into python3 with a -c flag and perform more complex processing with a single line python program.
    • Standard output and error can be redirected separately (e.g. ls 1> out 2> err)

    Vue

    Being relatively new to frontend tools, I found Vue.js to be quite interesting. Vue allows code reusability and abstractions through components. While I didn’t work extensively on the frontend, what I learned from the bits that I did work on was quite cool:

    Vue state: I found it interesting that you could have computed properties that are accessed the same way as properties, but can depend on other properties and can dynamically update when these properties change. This is often more elegant than using a Vue watcher to update a field. You can even have computed setters that update dependent properties when set. A watcher, however, can be more appropriate when responses to changing data are expensive or need to be done asynchronously.

    Vue custom directives: Directives are ways to reuse lower level DOM logic. Directives can define vue life-cycle hooks and later be bound to components (can actually take in any JavaScript object literal). For implementing lazy loads, I needed to use the vue-observe-visibility (external library) directive with slight modification to the hooks to be compatible with Vue3.

    References:

    Pug

    Pug is a templating language that compiles to HTML. It is less verbose and much more maintainable than HTML, and also allows basic presentation logic with conditionals, loops and case statements.

    JavaScript Quirks

    There are a lot of these, and most just remain quirks but some result in actual unintended bugs in production (often in edge cases). It was interesting to see this in our contribution bar logic. A technique sometimes used to extract the integer part of a number is to use parseInt (it's even suggested in a Stack Overflow answer). It turns out we were using this for calculating the number of contribution bars to display for a user. This works for most values, but breaks when numbers become very large or small (less than 10^-7). In this unlikely situation, we'd display anywhere from 1 to 9 extra bars (moral: use Math.floor instead!).

    Browser Engines

    An investigation into string representations in browsers led me down a rabbit hole of JavaScript runtimes and engines, and ultimately improved my understanding of JavaScript in general. Different browsers have different JS engines - Chrome uses V8, Firefox uses SpiderMonkey (the original JS engine written by Brendan Eich), Edge used to use Chakra but now also uses V8, Safari uses WebKit, etc. Engines often differ significantly in terms of the pipeline for code execution, garbage collection, and more.

    The V8 engine as an example, first parses JavaScript into an Abstract Syntax Tree (AST) which is then compiled into bytecode. This bytecode is interpreted by the Ignition interpreter (Ignition also handles compilation of the AST into bytecode). Code that is revisited often during interpretation is marked "hot" and compiled further into highly efficient machine code. This technique of optimising compilation based on run-time profiling (Just-In-Time (JIT) compilation) is also used in other browser engines like SpiderMonkey and the JVM.

    The engine is used for running things that are on the browser stack. JS is run in a single thread, and asynchronous tasks are done through callbacks in a task queue. The main script is first run, with things like promises and timeouts inserting tasks into a task queue. Tasks (and microtasks which are more urgent, lower overhead tasks that can execute when the call stack is empty even while the main script is running) in a task queue wait for the stack to be empty before being executed. Page re-renders are also blocked by running code on the stack (long delays between re-renders are undesirable). Using callbacks and hence not blocking the task queue, allows re-rendering to be done more regularly, improving responsiveness. The precise behaviour of task de-queueing (and lower overhead microtasks) can actually differ between browsers, which causes considerable headache.

    References:

    General Software Engineering/Design Considerations

    Discussions over PRs, issues and generally attempting to solve issues, were a great way to explore design considerations. Here is a non-exhaustive list of interesting points that came up this semester:

    In-house vs External Library

    In implementing new functionality or extending existing functionality (Git interface for example), there is usually a question of whether it would be easier to maintain features in-house, or use external libraries. It might be a good idea to maintain core functionality in-house since we'd want more fine-grained control over these features and new features can be added/fixed quickly as needed. At the same time, external libraries save time and cost of learning about and solving possibly complex problems.

    External libraries can however introduce vulnerabilities (several incidences of dependency sabotage with npm packages like color.js and node-ipc hit fairly close to home over the course of the semester). Hence, selection of libraries should be a well-deliberated process and should include considerations like active-ness of the project and diversity of maintainers.

    Recency vs Ubiquity

    In maintaining versions of dependencies, it is often important to weigh upgrading to a new version to get the newest features against possibly alienating users who don't already have that version. Neither is necessarily better than the other and will likely depend on the nature of the product. A new product for developers would probably have users who want new versions with the bleeding edge of features. On the other hand products that already have a large user base and aimed at less technical users might want to favour ubiquitous versions. Since RepoSense is aimed at users of all skill levels, including novice developers, we often default to the later approach.

    In a similar vein, it might be important to make sure that new features don't break backward compatibility so that the end-user won't face significant hindrances with making upgrades. At the same time, the need to be backwards compatible can be a root of evil, introducing all manners of hacks and fixes. This highlights the importance of foresight in the early stages of development. Also, deciding when to stop backwards compatibility with a significant version bump can be a non-trivial decision. Doing so should come with thorough migration documentation (sparse documentation for Vue2 -> Vue3 migration caused a lot of developer grievances).

    Isolated Testing

    While it's fairly obvious that modularity with tests is important and that components should be tested in isolation with unchanging inputs, it is easy to let slip lapses in the form of hidden dependencies that prevent components from being isolated, or having inputs that are actually non-static. Some of these issues came up over the course of the semester but it struck me just how easy it was for them to slip by unnoticed. There aren't necessarily language-level features that enforce coupling rules for the most part since many of these dependencies can be quite implicit.

    This had me thinking about the importance of being explicit in crucial sections of code, as described below.

    Being Explicit

    It is important that programmers make the behaviour of certain crucial sections of code as explicit as possible. One way of doing this is through good naming of methods and variables, and grouping statements semantically into methods or classes. Large chunks of code is detrimental and allows implicit slips in behaviour that can go unnoticed. So we might even want to make new special classes that do very specific things to make it clear that it is an important subroutine/behaviour that deserves its own abstraction.

    At the same time, high reliance on object orientation can lead to too many classes, each class doing trivial things and with high coupling between the classes leading to spaghetti logic that doesn't do very much to alleviate implicit behaviour. There exists a delicate middle ground characterised by semantically well partitioned code.

    Behavioural Consistency

    The earlier section on Javascript quirks were a result of an overly accommodating feature integration during the early stages of development. It's become a cautionary tale of sorts of the importance of consistency and predictability in behaviour. In adding new features, it was personally very tempting to allow small inconsistencies in behaviour in favour of simplicity of implementation. While simplicity is a desirable outcome, I'd argue that consistency is more important (small inconsistencies can runaway into larger un-fixable differences).

    Consistency can be with respect to various things. For example, we might want that identical inputs behave the same under similar conditions (differing in non-semantic respects) or that similar inputs (differing in non-semantic respects) behave the same under the identical conditions, etc.

    Miscellaneous helpful tools

    • The command line tool GitHub cli provides a very handy way to access GitHub API, and has been useful for checking out PRs, interacting with issues, managing workflows, etc right from the command line.
    • git bisect is a very nice way to find problematic commits. Given a bad commit and a previously good commit, git bisect does a binary search (either automatically with a test or with manual intervention) to find the problematic commit where the issue was introduced.
    • Search through previously run commands (with the first few characters) with ctrl-r in a bash shell.
    • GitHub issues and PRs have advanced search syntax like involves:USER for all items that involve a user. This was very useful for updating progress.md. More features here.
    +

    CS3282

    In general, the theme of my explorations and work in CS3282 revolves around ideas in programming language research and functional programming, which are all things I'd like to pursue in the future. The lightning talks exposed me to new ideas in programming languages (some described below). The book review assignment gave me the valuable counter-opinion that formal methods and newer fancy-type systems might actually limit the flexibility of real-world software. Java, which is very much an unfancy language, is certainly very practical and doesn't have support for many of these techniques. Regardless, we can borrow ideas like immutability and apply them to any practical system. To that effect, I've also tried to start refactors of the RepoSense backend to introduce principles like immutability and optional monads to make things easier to maintain and reason about.

    Overall, I really appreciated the flexibility afforded by CS3282, which allowed me to explore more fringe and niche ideas that are starting to make their way into the programming practitioner's toolkit.

    Functional logic programming

    In my explorations for the first lightning talk, I also came across functional logic programming. I had previously been separately familiar with functional and logic programming, and it was nice to see a foundational work for a core calculus for the combination of these paradigms, each of which has rich literature. The Verse Calculus provides a minimal language that can be evaluated with a consistent set of rewrite rules that have a number of nice properties. This work comes out of Epic Games by researchers like Simon Peyton Jones, Lennart Augustsson, Guy Steele, and Ranjit Jhala, all people I've heard of before relating to other highly influential work.

    Effect systems

    Research for my second lightning talk got me interested in and learning about effect systems. Effect systems refer to systems that track and allow reasoning about unobvious side effects that functions and routines could have, like mutation, divergence (possible nontermination), network access, exceptions, etc. I found several real-world (used in practice) examples of effect systems like Scala Zio, Effect-TS (inspired heavily by Zio), and algebraic effects in OCaml (which very recently got significant syntactical updates in OCaml 5.3). The theory for algebraic effect systems is very rich and shows that effect systems are at least as expressive as monadic effects, which are widely adopted in pure functional programming languages like Haskell.


    CS3281

    Gradle

    Gradle is a very flexible build automation tool used for everything from testing and formatting, to builds and deployments. Unlike with other build automation tools like Maven where build scripts written in XML (a widely hated feature of the tool), Gradle build scripts are written in a domain specific language based on Groovy or Kotlin, which are both JVM based languages. This means that it can interact seamlessly with Java libraries.

    Gradle is also much more performant than alternatives like Maven because of its:

    • Build caching: Only reruns tasks whose inputs have been changed.
    • Gradle daemon: A background process that stores information about the project in memory so that startup time can be cut down during builds.

    RepoSense recently added functionality for hot reload on frontend as a Gradle task, which made frontend development a lot more productive. Unfortunately, the feature isn't available on Linux because the package we were using (Apache Ant's condition package) could not specifically check for it. Migrating to Gradle's own platform package recently taken out of incubation, allowed us to support all 3 prominent operating systems.

    References:

    GitHub Actions and API

    Like Gradle, Github Actions help with automation of workflows like CI/CD and project management, and can be triggered by a variety of events (pull requests, issues, releases, forks, etc). It also has a growing library of plugins that make workflows a lot easier to set-up. I was surprised that there is some nice tooling support for GitHub actions on IntelliJ.

    GitHub actions allows users to run CI on a variety of operating systems, such as Ubuntu XX.04, macOS and Windows Server (which is virtually the same as Windows 10/11 but with better hardware support and more stringent security features).

    GitHub also provides a variety of API to interact with these objects. One quirk I came across with the API was that posting single comments on pull requests need to go through the issues endpoint instead of the pulls endpoint (the endpoint for pulls requires code to be referenced). This doesn't cause problems since issues and pulls will never have identical IDs.

    GitHub deployment APIs also returns deployment information in pages, which is a sensible thing to do but can cause slight inconvenience when long running PRs have more deployments than can fit in a page.

    Actions and APIs also have some great documentation:

    Git Remotes

    Git exploded in popularity in large part due to Git hosting providers like GitHub. GitLab and Bitbucket are also commonly used Git hosts. RepoSense has thus far only largely supported GitHub, but there is a clear incentive to support other commonly used remotes. This is made a little challenging due to differences in conventions between the sites:

    base_url Commit View Blame View
    GitHub github.com {base_url}/{org}/{repo_name}/commit/{commit_hash} {base_url}/{org}/{repo_name}/blame/{branch}/{file_path}
    GitLab gitlab.com {base_url}/{org}/{repo_name}/-/commit/{commit_hash} {base_url}/{org}/{repo_name}/-/blame/{branch}/{file_path}
    Bitbucket bitbucket.org {base_url}/{org}/{repo_name}/commits/{commit_hash} {base_url}/{org}/{repo_name}/annotate/{branch}/{file_path}

    For example, Bitbucket uses the term 'annotate' instead of 'blame' because the word 'blame' is insufficiently positive.

    Triangular Git workflows

    In investigating the output of git remote -v, I noticed there were 2 remotes (fetch and push) for each remote name, which I was confused by. The utility of the separation of fetch and push remotes is for triangular workflows.

    We are probably familiar with the common workflow for updating a branch on a forked repo which involves first pulling updates from upstream master, then making changes and pushing to our own fork. This requires remembering to fetch and push to separate repos. With triangular workflows, you can have fetch and push apply to separate repos but with the same remote name, which makes this process much more convenient.

    Cypress Tests

    Cypress is a frontend testing tool for testing applications that run in the browser, with tests that are easy to read and write. It uses browser automation (similar to Selenium) and comes with a browser and relevant dependencies out of the box, so it's very easy to set-up. Cypress also provides a dashboard for convenient monitoring of test runs.

    https://docs.cypress.io/guides/overview/why-cypress#In-a-nutshell

    Bash Scripting

    Bash scripts can be run in a github action workflow, which greatly expands the scope of things you can do with actions. Bash is quite expressive (I hadn't realised just how much it could do). some cool things I learned you could do:

    • {$VAR,,} to lowercase string in $VAR.
    • $* gives parameter values separated by the value in IFS (Internal File Separator).
    • Pipe output into python3 with a -c flag and perform more complex processing with a single line python program.
    • Standard output and error can be redirected separately (e.g. ls 1> out 2> err)

    Vue

    Being relatively new to frontend tools, I found Vue.js to be quite interesting. Vue allows code reusability and abstractions through components. While I didn’t work extensively on the frontend, what I learned from the bits that I did work on was quite cool:

    Vue state: I found it interesting that you could have computed properties that are accessed the same way as properties, but can depend on other properties and can dynamically update when these properties change. This is often more elegant than using a Vue watcher to update a field. You can even have computed setters that update dependent properties when set. A watcher, however, can be more appropriate when responses to changing data are expensive or need to be done asynchronously.

    Vue custom directives: Directives are ways to reuse lower level DOM logic. Directives can define vue life-cycle hooks and later be bound to components (can actually take in any JavaScript object literal). For implementing lazy loads, I needed to use the vue-observe-visibility (external library) directive with slight modification to the hooks to be compatible with Vue3.

    References:

    Pug

    Pug is a templating language that compiles to HTML. It is less verbose and much more maintainable than HTML, and also allows basic presentation logic with conditionals, loops and case statements.

    JavaScript Quirks

    There are a lot of these, and most just remain quirks but some result in actual unintended bugs in production (often in edge cases). It was interesting to see this in our contribution bar logic. A technique sometimes used to extract the integer part of a number is to use parseInt (it's even suggested in a Stack Overflow answer). It turns out we were using this for calculating the number of contribution bars to display for a user. This works for most values, but breaks when numbers become very large or small (less than 10^-7). In this unlikely situation, we'd display anywhere from 1 to 9 extra bars (moral: use Math.floor instead!).

    Browser Engines

    An investigation into string representations in browsers led me down a rabbit hole of JavaScript runtimes and engines, and ultimately improved my understanding of JavaScript in general. Different browsers have different JS engines - Chrome uses V8, Firefox uses SpiderMonkey (the original JS engine written by Brendan Eich), Edge used to use Chakra but now also uses V8, Safari uses WebKit, etc. Engines often differ significantly in terms of the pipeline for code execution, garbage collection, and more.

    The V8 engine as an example, first parses JavaScript into an Abstract Syntax Tree (AST) which is then compiled into bytecode. This bytecode is interpreted by the Ignition interpreter (Ignition also handles compilation of the AST into bytecode). Code that is revisited often during interpretation is marked "hot" and compiled further into highly efficient machine code. This technique of optimising compilation based on run-time profiling (Just-In-Time (JIT) compilation) is also used in other browser engines like SpiderMonkey and the JVM.

    The engine is used for running things that are on the browser stack. JS is run in a single thread, and asynchronous tasks are done through callbacks in a task queue. The main script is first run, with things like promises and timeouts inserting tasks into a task queue. Tasks (and microtasks which are more urgent, lower overhead tasks that can execute when the call stack is empty even while the main script is running) in a task queue wait for the stack to be empty before being executed. Page re-renders are also blocked by running code on the stack (long delays between re-renders are undesirable). Using callbacks and hence not blocking the task queue, allows re-rendering to be done more regularly, improving responsiveness. The precise behaviour of task de-queueing (and lower overhead microtasks) can actually differ between browsers, which causes considerable headache.

    References:

    General Software Engineering/Design Considerations

    Discussions over PRs, issues and generally attempting to solve issues, were a great way to explore design considerations. Here is a non-exhaustive list of interesting points that came up this semester:

    In-house vs External Library

    In implementing new functionality or extending existing functionality (Git interface for example), there is usually a question of whether it would be easier to maintain features in-house, or use external libraries. It might be a good idea to maintain core functionality in-house since we'd want more fine-grained control over these features and new features can be added/fixed quickly as needed. At the same time, external libraries save time and cost of learning about and solving possibly complex problems.

    External libraries can however introduce vulnerabilities (several incidences of dependency sabotage with npm packages like color.js and node-ipc hit fairly close to home over the course of the semester). Hence, selection of libraries should be a well-deliberated process and should include considerations like active-ness of the project and diversity of maintainers.

    Recency vs Ubiquity

    In maintaining versions of dependencies, it is often important to weigh upgrading to a new version to get the newest features against possibly alienating users who don't already have that version. Neither is necessarily better than the other and will likely depend on the nature of the product. A new product for developers would probably have users who want new versions with the bleeding edge of features. On the other hand products that already have a large user base and aimed at less technical users might want to favour ubiquitous versions. Since RepoSense is aimed at users of all skill levels, including novice developers, we often default to the later approach.

    In a similar vein, it might be important to make sure that new features don't break backward compatibility so that the end-user won't face significant hindrances with making upgrades. At the same time, the need to be backwards compatible can be a root of evil, introducing all manners of hacks and fixes. This highlights the importance of foresight in the early stages of development. Also, deciding when to stop backwards compatibility with a significant version bump can be a non-trivial decision. Doing so should come with thorough migration documentation (sparse documentation for Vue2 -> Vue3 migration caused a lot of developer grievances).

    Isolated Testing

    While it's fairly obvious that modularity with tests is important and that components should be tested in isolation with unchanging inputs, it is easy to let slip lapses in the form of hidden dependencies that prevent components from being isolated, or having inputs that are actually non-static. Some of these issues came up over the course of the semester but it struck me just how easy it was for them to slip by unnoticed. There aren't necessarily language-level features that enforce coupling rules for the most part since many of these dependencies can be quite implicit.

    This had me thinking about the importance of being explicit in crucial sections of code, as described below.

    Being Explicit

    It is important that programmers make the behaviour of certain crucial sections of code as explicit as possible. One way of doing this is through good naming of methods and variables, and grouping statements semantically into methods or classes. Large chunks of code is detrimental and allows implicit slips in behaviour that can go unnoticed. So we might even want to make new special classes that do very specific things to make it clear that it is an important subroutine/behaviour that deserves its own abstraction.

    At the same time, high reliance on object orientation can lead to too many classes, each class doing trivial things and with high coupling between the classes leading to spaghetti logic that doesn't do very much to alleviate implicit behaviour. There exists a delicate middle ground characterised by semantically well partitioned code.

    Behavioural Consistency

    The earlier section on Javascript quirks were a result of an overly accommodating feature integration during the early stages of development. It's become a cautionary tale of sorts of the importance of consistency and predictability in behaviour. In adding new features, it was personally very tempting to allow small inconsistencies in behaviour in favour of simplicity of implementation. While simplicity is a desirable outcome, I'd argue that consistency is more important (small inconsistencies can runaway into larger un-fixable differences).

    Consistency can be with respect to various things. For example, we might want that identical inputs behave the same under similar conditions (differing in non-semantic respects) or that similar inputs (differing in non-semantic respects) behave the same under the identical conditions, etc.

    Miscellaneous helpful tools

    • The command line tool GitHub cli provides a very handy way to access GitHub API, and has been useful for checking out PRs, interacting with issues, managing workflows, etc right from the command line.
    • git bisect is a very nice way to find problematic commits. Given a bad commit and a previously good commit, git bisect does a binary search (either automatically with a test or with manual intervention) to find the problematic commit where the issue was introduced.
    • Search through previously run commands (with the first few characters) with ctrl-r in a bash shell.
    • GitHub issues and PRs have advanced search syntax like involves:USER for all items that involve a user. This was very useful for updating progress.md. More features here.
    diff --git a/students/gok99/knowledge.page-vue-render.js b/students/gok99/knowledge.page-vue-render.js index 3f062f12a..54a1ff1d8 100644 --- a/students/gok99/knowledge.page-vue-render.js +++ b/students/gok99/knowledge.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('h2',{attrs:{"id":"cs3282"}},[_v("CS3282"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#cs3282","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("In general, the theme of my explorations and work in CS3282 revolves around ideas in programming language research and functional programming, which are all things I'd like to pursue in the future. The lightning talks exposed me to new ideas in programming languages (some described below). The book review assignment gave me the valuable counter-opinion that formal methods and newer fancy-type systems might actually limit the flexibility of real-world software. Java, which is very much an unfancy language, is certainly very practical and doesn't have support for many of these techniques. Regardless, we can borrow ideas like immutability and apply them to any practical system. To that effect, I've also tried to start refactors of the RepoSense backend to introduce principles like immutability and optional monads to make things easier to maintain and reason about.")]),_v(" "),_c('p',[_v("Overall, I really appreciated the flexibility afforded by CS3282, which allowed me to explore more fringe and niche ideas that are starting to make their way into the programming practitioner's toolkit.")]),_v(" "),_c('h3',{attrs:{"id":"functional-logic-programming"}},[_v("Functional logic programming"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#functional-logic-programming","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("In my explorations for the first lightning talk, I also came across functional logic programming. I had previously been separately familiar with functional and logic programming, and it was nice to see a foundational work for a core calculus for the combination of these paradigms, each of which has rich literature. The "),_c('a',{attrs:{"href":"https://simon.peytonjones.org/assets/pdfs/verse-conf.pdf"}},[_v("Verse Calculus")]),_v(" provides a minimal language that can be evaluated with a consistent set of rewrite rules that have a number of nice properties. This work comes out of Epic Games by researchers like Simon Peyton Jones, Lennart Augustsson, Guy Steele, and Ranjit Jhala, all people I've heard of before relating to other highly influential work.")]),_v(" "),_c('h3',{attrs:{"id":"effect-systems"}},[_v("Effect systems"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#effect-systems","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Research for my second lightning talk got me interested in and learning about effect systems. Effect systems refer to systems that track and allow reasoning about unobvious side effects that functions and routines could have, like mutation, divergence (possible nontermination), network access, exceptions, etc. I found several real-world (used in practice) examples of effect systems like Scala Zio, Effect-TS (inspired heavily by Zio), and algebraic effects in OCaml (which very recently got significant syntactical updates in OCaml 5.3). The theory for algebraic effect systems is very rich and shows that effect systems are at least as expressive as monadic effects, which are widely adopted in pure functional programming languages like Haskell.")]),_v(" "),_c('hr'),_v(" "),_c('h2',{attrs:{"id":"cs3281"}},[_v("CS3281"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#cs3281","onclick":"event.stopPropagation()"}})]),_v(" "),_c('h3',{attrs:{"id":"gradle"}},[_v("Gradle"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#gradle","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Gradle is a very flexible build automation tool used for everything from testing and formatting, to builds and deployments. Unlike with other build automation tools like Maven where build scripts written in XML (a widely hated feature of the tool), Gradle build scripts are written in a domain specific language based on Groovy or Kotlin, which are both JVM based languages. This means that it can interact seamlessly with Java libraries.")]),_v(" "),_c('p',[_v("Gradle is also much more performant than alternatives like Maven because of its:")]),_v(" "),_c('ul',[_c('li',[_v("Build caching: Only reruns tasks whose inputs have been changed.")]),_v(" "),_c('li',[_v("Gradle daemon: A background process that stores information about the project in memory so that startup time can be cut down during builds.")])]),_v(" "),_c('p',[_v("RepoSense recently added functionality for hot reload on frontend as a Gradle task, which made frontend development a lot more productive. Unfortunately, the feature isn't available on Linux because the package we were using (Apache Ant's "),_c('a',{attrs:{"href":"https://ant.apache.org/manual/api/org/apache/tools/ant/taskdefs/condition/package-summary.html"}},[_v("condition package")]),_v(") could not specifically check for it. Migrating to Gradle's own "),_c('a',{attrs:{"href":"https://docs.gradle.org/current/javadoc/org/gradle/nativeplatform/platform/package-summary.html"}},[_v("platform package")]),_v(" recently taken out of incubation, allowed us to support all 3 prominent operating systems.")]),_v(" "),_c('p',[_v("References:")]),_v(" "),_c('ul',[_c('li',[_c('a',{attrs:{"href":"https://docs.gradle.org/current/userguide/userguide.html"}},[_v("https://docs.gradle.org/current/userguide/userguide.html")])]),_v(" "),_c('li',[_c('a',{attrs:{"href":"https://docs.gradle.org/current/userguide/gradle_daemon.html#sec:why_the_daemon"}},[_v("https://docs.gradle.org/current/userguide/gradle_daemon.html#sec:why_the_daemon")])]),_v(" "),_c('li',[_c('a',{attrs:{"href":"https://docs.gradle.org/current/javadoc/index.html?overview-summary.html"}},[_v("https://docs.gradle.org/current/javadoc/index.html?overview-summary.html")])]),_v(" "),_c('li',[_c('a',{attrs:{"href":"https://docs.gradle.org/current/javadoc/org/gradle/nativeplatform/platform/package-summary.html"}},[_v("https://docs.gradle.org/current/javadoc/org/gradle/nativeplatform/platform/package-summary.html")])]),_v(" "),_c('li',[_c('a',{attrs:{"href":"https://ant.apache.org/manual/api/org/apache/tools/ant/taskdefs/condition/package-summary.html"}},[_v("https://ant.apache.org/manual/api/org/apache/tools/ant/taskdefs/condition/package-summary.html")])]),_v(" "),_c('li',[_c('a',{attrs:{"href":"https://stackoverflow.com/a/31443955"}},[_v("https://stackoverflow.com/a/31443955")])])]),_v(" "),_c('h3',{attrs:{"id":"github-actions-and-api"}},[_v("GitHub Actions and API"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#github-actions-and-api","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Like Gradle, Github Actions help with automation of workflows like CI/CD and project management, and can be triggered by a variety of events (pull requests, issues, releases, forks, etc). It also has a growing library of plugins that make workflows a lot easier to set-up. I was surprised that there is some nice tooling support for GitHub actions on IntelliJ.")]),_v(" "),_c('p',[_v("GitHub actions allows users to run CI on a variety of operating systems, such as Ubuntu XX.04, macOS and Windows Server (which is virtually the same as Windows 10/11 but with better hardware support and more stringent security features).")]),_v(" "),_c('p',[_v("GitHub also provides a variety of API to interact with these objects. One quirk I came across with the API was that posting single comments on pull requests need to go through the issues endpoint instead of the pulls endpoint (the endpoint for pulls requires code to be referenced). This doesn't cause problems since issues and pulls will never have identical IDs.")]),_v(" "),_c('p',[_v("GitHub deployment APIs also returns deployment information in pages, which is a sensible thing to do but can cause slight inconvenience when long running PRs have more deployments than can fit in a page.")]),_v(" "),_c('p',[_v("Actions and APIs also have some great documentation:")]),_v(" "),_c('ul',[_c('li',[_c('a',{attrs:{"href":"https://docs.github.com/en/rest/guides/getting-started-with-the-rest-api"}},[_v("https://docs.github.com/en/rest/guides/getting-started-with-the-rest-api")])]),_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',[_c('a',{attrs:{"href":"https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows"}},[_v("https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows")])])]),_v(" "),_c('h3',{attrs:{"id":"git-remotes"}},[_v("Git Remotes"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#git-remotes","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Git exploded in popularity in large part due to Git hosting providers like GitHub. GitLab and Bitbucket are also commonly used Git hosts. RepoSense has thus far only largely supported GitHub, but there is a clear incentive to support other commonly used remotes. This is made a little challenging due to differences in conventions between the sites:")]),_v(" "),_c('div',{staticClass:"table-responsive"},[_c('table',{staticClass:"markbind-table table table-bordered table-striped"},[_c('thead',[_c('tr',[_c('th',{staticStyle:{"text-align":"center"}}),_v(" "),_c('th',{staticStyle:{"text-align":"center"}},[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("base_url")])]),_v(" "),_c('th',{staticStyle:{"text-align":"center"}},[_v("Commit View")]),_v(" "),_c('th',{staticStyle:{"text-align":"center"}},[_v("Blame View")])])]),_v(" "),_c('tbody',[_c('tr',[_c('td',{staticStyle:{"text-align":"center"}},[_v("GitHub")]),_v(" "),_c('td',{staticStyle:{"text-align":"center"}},[_v("github.com")]),_v(" "),_c('td',{staticStyle:{"text-align":"center"}},[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("{base_url}/{org}/{repo_name}/commit/{commit_hash}")])]),_v(" "),_c('td',{staticStyle:{"text-align":"center"}},[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("{base_url}/{org}/{repo_name}/blame/{branch}/{file_path}")])])]),_v(" "),_c('tr',[_c('td',{staticStyle:{"text-align":"center"}},[_v("GitLab")]),_v(" "),_c('td',{staticStyle:{"text-align":"center"}},[_v("gitlab.com")]),_v(" "),_c('td',{staticStyle:{"text-align":"center"}},[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("{base_url}/{org}/{repo_name}/-/commit/{commit_hash}")])]),_v(" "),_c('td',{staticStyle:{"text-align":"center"}},[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("{base_url}/{org}/{repo_name}/-/blame/{branch}/{file_path}")])])]),_v(" "),_c('tr',[_c('td',{staticStyle:{"text-align":"center"}},[_v("Bitbucket")]),_v(" "),_c('td',{staticStyle:{"text-align":"center"}},[_v("bitbucket.org")]),_v(" "),_c('td',{staticStyle:{"text-align":"center"}},[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("{base_url}/{org}/{repo_name}/commits/{commit_hash}")])]),_v(" "),_c('td',{staticStyle:{"text-align":"center"}},[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("{base_url}/{org}/{repo_name}/annotate/{branch}/{file_path}")])])])])])]),_c('p',[_v("For example, Bitbucket uses the term 'annotate' instead of 'blame' because the word 'blame' is insufficiently positive.")]),_v(" "),_c('h3',{attrs:{"id":"triangular-git-workflows"}},[_v("Triangular Git workflows"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#triangular-git-workflows","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("In investigating the output of "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("git remote -v")]),_v(", I noticed there were 2 remotes (fetch and push) for each remote name, which I was confused by. The utility of the separation of fetch and push remotes is for triangular workflows.")]),_v(" "),_c('p',[_v("We are probably familiar with the common workflow for updating a branch on a forked repo which involves first pulling updates from upstream master, then making changes and pushing to our own fork. This requires remembering to fetch and push to separate repos. With triangular workflows, you can have fetch and push apply to separate repos but with the same remote name, which makes this process much more convenient.")]),_v(" "),_c('h3',{attrs:{"id":"cypress-tests"}},[_v("Cypress Tests"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#cypress-tests","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Cypress is a frontend testing tool for testing applications that run in the browser, with tests that are easy to read and write. It uses browser automation (similar to Selenium) and comes with a browser and relevant dependencies out of the box, so it's very easy to set-up. Cypress also provides a dashboard for convenient monitoring of test runs.")]),_v(" "),_c('p',[_c('a',{attrs:{"href":"https://docs.cypress.io/guides/overview/why-cypress#In-a-nutshell"}},[_v("https://docs.cypress.io/guides/overview/why-cypress#In-a-nutshell")])]),_v(" "),_c('h3',{attrs:{"id":"bash-scripting"}},[_v("Bash Scripting"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#bash-scripting","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Bash scripts can be run in a github action workflow, which greatly expands the scope of things you can do with actions. Bash is quite expressive (I hadn't realised just how much it could do). some cool things I learned you could do:")]),_v(" "),_c('ul',[_c('li',[_v("{$VAR,,} to lowercase string in $VAR.")]),_v(" "),_c('li',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("$*")]),_v(" gives parameter values separated by the value in "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("IFS")]),_v(" (Internal File Separator).")]),_v(" "),_c('li',[_v("Pipe output into "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("python3")]),_v(" with a "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("-c")]),_v(" flag and perform more complex processing with a single line python program.")]),_v(" "),_c('li',[_v("Standard output and error can be redirected separately (e.g. "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("ls 1> out 2> err")]),_v(")")])]),_v(" "),_c('h3',{attrs:{"id":"vue"}},[_v("Vue"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#vue","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Being relatively new to frontend tools, I found Vue.js to be quite interesting. Vue allows code reusability and abstractions through components. While I didn’t work extensively on the frontend, what I learned from the bits that I did work on was quite cool:")]),_v(" "),_c('p',[_c('strong',[_v("Vue state")]),_v(": I found it interesting that you could have computed properties that are accessed the same way as properties, but can depend on other properties and can dynamically update when these properties change. This is often more elegant than using a Vue watcher to update a field. You can even have computed setters that update dependent properties when set. A watcher, however, can be more appropriate when responses to changing data are expensive or need to be done asynchronously.")]),_v(" "),_c('p',[_c('strong',[_v("Vue custom directives")]),_v(": Directives are ways to reuse lower level DOM logic. Directives can define vue life-cycle hooks and later be bound to components (can actually take in any JavaScript object literal). For implementing lazy loads, I needed to use the vue-observe-visibility (external library) directive with slight modification to the hooks to be compatible with Vue3.")]),_v(" "),_c('p',[_v("References:")]),_v(" "),_c('ul',[_c('li',[_c('a',{attrs:{"href":"https://v2.vuejs.org/v2/guide/computed.html"}},[_v("https://v2.vuejs.org/v2/guide/computed.html")])]),_v(" "),_c('li',[_c('a',{attrs:{"href":"https://vuejs.org/guide/reusability/custom-directives.html"}},[_v("https://vuejs.org/guide/reusability/custom-directives.html")])])]),_v(" "),_c('h3',{attrs:{"id":"pug"}},[_v("Pug"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#pug","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Pug is a templating language that compiles to HTML. It is less verbose and much more maintainable than HTML, and also allows basic presentation logic with conditionals, loops and case statements.")]),_v(" "),_c('h3',{attrs:{"id":"javascript-quirks"}},[_v("JavaScript Quirks"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#javascript-quirks","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("There are a lot of these, and most just remain quirks but some result in actual unintended bugs in production (often in edge cases). It was interesting to see this in our contribution bar logic. A technique sometimes used to extract the integer part of a number is to use "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("parseInt")]),_v(" (it's even suggested in a Stack Overflow "),_c('a',{attrs:{"href":"https://stackoverflow.com/a/48262505"}},[_v("answer")]),_v("). It turns out we were using this for calculating the number of contribution bars to display for a user. This works for most values, but breaks when numbers become very large or small (less than 10^-7). In this unlikely situation, we'd display anywhere from 1 to 9 extra bars (moral: use "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("Math.floor")]),_v(" instead!).")]),_v(" "),_c('h3',{attrs:{"id":"browser-engines"}},[_v("Browser Engines"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#browser-engines","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("An investigation into string representations in browsers led me down a rabbit hole of JavaScript runtimes and engines, and ultimately improved my understanding of JavaScript in general. Different browsers have different JS engines - Chrome uses V8, Firefox uses SpiderMonkey (the original JS engine written by Brendan Eich), Edge used to use Chakra but now also uses V8, Safari uses WebKit, etc. Engines often differ significantly in terms of the pipeline for code execution, garbage collection, and more.")]),_v(" "),_c('p',[_v("The V8 engine as an example, first parses JavaScript into an Abstract Syntax Tree (AST) which is then compiled into bytecode. This bytecode is interpreted by the Ignition interpreter (Ignition also handles compilation of the AST into bytecode). Code that is revisited often during interpretation is marked \"hot\" and compiled further into highly efficient machine code. This technique of optimising compilation based on run-time profiling (Just-In-Time (JIT) compilation) is also used in other browser engines like SpiderMonkey and the JVM.")]),_v(" "),_c('p',[_v("The engine is used for running things that are on the browser stack. JS is run in a single thread, and asynchronous tasks are done through callbacks in a task queue. The main script is first run, with things like promises and timeouts inserting tasks into a task queue. Tasks (and microtasks which are more urgent, lower overhead tasks that can execute when the call stack is empty even while the main script is running) in a task queue wait for the stack to be empty before being executed. Page re-renders are also blocked by running code on the stack (long delays between re-renders are undesirable). Using callbacks and hence not blocking the task queue, allows re-rendering to be done more regularly, improving responsiveness. The precise behaviour of task de-queueing (and lower overhead microtasks) can actually differ between browsers, which causes considerable headache.")]),_v(" "),_c('p',[_v("References:")]),_v(" "),_c('ul',[_c('li',[_c('a',{attrs:{"href":"https://cabulous.medium.com/how-v8-javascript-engine-works-5393832d80a7"}},[_v("https://cabulous.medium.com/how-v8-javascript-engine-works-5393832d80a7")])]),_v(" "),_c('li',[_c('a',{attrs:{"href":"https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/"}},[_v("https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/")])]),_v(" "),_c('li',[_c('a',{attrs:{"href":"https://www.youtube.com/watch?v=8aGhZQkoFbQ"}},[_v("https://www.youtube.com/watch?v=8aGhZQkoFbQ")])])]),_v(" "),_c('h3',{attrs:{"id":"general-software-engineering-design-considerations"}},[_v("General Software Engineering/Design Considerations"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#general-software-engineering-design-considerations","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Discussions over PRs, issues and generally attempting to solve issues, were a great way to explore design considerations. Here is a non-exhaustive list of interesting points that came up this semester:")]),_v(" "),_c('p',[_c('strong',[_v("In-house vs External Library")])]),_v(" "),_c('p',[_v("In implementing new functionality or extending existing functionality (Git interface for example), there is usually a question of whether it would be easier to maintain features in-house, or use external libraries. It might be a good idea to maintain core functionality in-house since we'd want more fine-grained control over these features and new features can be added/fixed quickly as needed. At the same time, external libraries save time and cost of learning about and solving possibly complex problems.")]),_v(" "),_c('p',[_v("External libraries can however introduce vulnerabilities (several incidences of dependency sabotage with npm packages like color.js and node-ipc hit fairly close to home over the course of the semester). Hence, selection of libraries should be a well-deliberated process and should include considerations like active-ness of the project and diversity of maintainers.")]),_v(" "),_c('p',[_c('strong',[_v("Recency vs Ubiquity")])]),_v(" "),_c('p',[_v("In maintaining versions of dependencies, it is often important to weigh upgrading to a new version to get the newest features against possibly alienating users who don't already have that version. Neither is necessarily better than the other and will likely depend on the nature of the product. A new product for developers would probably have users who want new versions with the bleeding edge of features. On the other hand products that already have a large user base and aimed at less technical users might want to favour ubiquitous versions. Since RepoSense is aimed at users of all skill levels, including novice developers, we often default to the later approach.")]),_v(" "),_c('p',[_v("In a similar vein, it might be important to make sure that new features don't break backward compatibility so that the end-user won't face significant hindrances with making upgrades. At the same time, the need to be backwards compatible can be a root of evil, introducing all manners of hacks and fixes. This highlights the importance of foresight in the early stages of development. Also, deciding when to stop backwards compatibility with a significant version bump can be a non-trivial decision. Doing so should come with thorough migration documentation (sparse documentation for Vue2 -> Vue3 migration caused a lot of developer grievances).")]),_v(" "),_c('p',[_c('strong',[_v("Isolated Testing")])]),_v(" "),_c('p',[_v("While it's fairly obvious that modularity with tests is important and that components should be tested in isolation with unchanging inputs, it is easy to let slip lapses in the form of hidden dependencies that prevent components from being isolated, or having inputs that are actually non-static. Some of these issues came up over the course of the semester but it struck me just how easy it was for them to slip by unnoticed. There aren't necessarily language-level features that enforce coupling rules for the most part since many of these dependencies can be quite implicit.")]),_v(" "),_c('p',[_v("This had me thinking about the importance of being explicit in crucial sections of code, as described below.")]),_v(" "),_c('p',[_c('strong',[_v("Being Explicit")])]),_v(" "),_c('p',[_v("It is important that programmers make the behaviour of certain crucial sections of code as explicit as possible. One way of doing this is through good naming of methods and variables, and grouping statements semantically into methods or classes. Large chunks of code is detrimental and allows implicit slips in behaviour that can go unnoticed. So we might even want to make new special classes that do very specific things to make it clear that it is an important subroutine/behaviour that deserves its own abstraction.")]),_v(" "),_c('p',[_v("At the same time, high reliance on object orientation can lead to too many classes, each class doing trivial things and with high coupling between the classes leading to spaghetti logic that doesn't do very much to alleviate implicit behaviour. There exists a delicate middle ground characterised by semantically well partitioned code.")]),_v(" "),_c('p',[_c('strong',[_v("Behavioural Consistency")])]),_v(" "),_c('p',[_v("The earlier section on Javascript quirks were a result of an overly accommodating feature integration during the early stages of development. It's become a cautionary tale of sorts of the importance of consistency and predictability in behaviour. In adding new features, it was personally very tempting to allow small inconsistencies in behaviour in favour of simplicity of implementation. While simplicity is a desirable outcome, I'd argue that consistency is more important (small inconsistencies can runaway into larger un-fixable differences).")]),_v(" "),_c('p',[_v("Consistency can be with respect to various things. For example, we might want that identical inputs behave the same under similar conditions (differing in non-semantic respects) or that similar inputs (differing in non-semantic respects) behave the same under the identical conditions, etc.")]),_v(" "),_c('h3',{attrs:{"id":"miscellaneous-helpful-tools"}},[_v("Miscellaneous helpful tools"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#miscellaneous-helpful-tools","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ul',[_c('li',[_v("The command line tool "),_c('a',{attrs:{"href":"https://github.com/cli/cli"}},[_v("GitHub cli")]),_v(" provides a very handy way to access GitHub API, and has been useful for checking out PRs, interacting with issues, managing workflows, etc right from the command line.")]),_v(" "),_c('li',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("git bisect")]),_v(" is a very nice way to find problematic commits. Given a bad commit and a previously good commit, "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("git bisect")]),_v(" does a binary search (either automatically with a test or with manual intervention) to find the problematic commit where the issue was introduced.")]),_v(" "),_c('li',[_v("Search through previously run commands (with the first few characters) with ctrl-r in a bash shell.")]),_v(" "),_c('li',[_v("GitHub issues and PRs have advanced search syntax like "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("involves:USER")]),_v(" for all items that involve a user. This was very useful for updating "),_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("progress.md")]),_v(". More features "),_c('a',{attrs:{"href":"https://docs.github.com/en/search-github/searching-on-github/searching-issues-and-pull-requests"}},[_v("here")]),_v(".")])])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/gok99/observations.html b/students/gok99/observations.html index 7315854bd..b0520922b 100644 --- a/students/gok99/observations.html +++ b/students/gok99/observations.html @@ -12,7 +12,7 @@ const baseUrl = '/2024' -

    Project: Pandoc

    Pandoc is a Haskell library and command-line tool for converting between various document formats. It is a powerful tool that can convert between many different formats, including Markdown, LaTeX, HTML, and many others. It is also extensible, allowing for the creation of custom readers and writers for new formats. Pandoc has 31.8k stars on GitHub and is used widely by individuals for personal workflows and within deployment pipelines by larger organizations.

    My Contributions

    My Learning Record

    The Haskell tooling ecosystem (GHC, Cabal, Stack, Haskell LSP, etc) makes writing Haskell quite enjoyable. In particular, Haskell features like abstract data types, parametric polymorphism, and type inferencing make understanding and modifying code in a general and well-abstracted way really easy to do. The language also allows for strong editor tooling that also helps improve the developer experience. Contributing to Pandoc allowed me to get a deep look at practical Haskell in a widely adopted and loved tool—something I've always wanted to do.

    Pandoc is also a really great and flexible tool that has taught me a great deal about software design practices. Pandoc has lofty goals of providing good document conversion from a large number of input formats to a really large number of output formats. This is done by converting to and from Pandoc's own document intermediate representation, which has a large subset of the intersection of features of the input and output formats. By being very clear about the extent and specification of the intermediate representation, it is easy for several developers to concurrently add, modify, and fix existing readers and writers by mapping the semantics of the source or target specification to those of the Pandoc intermediate representation. In general, being very clear and thorough with interfaces between software segments seems to be an important and crucial aspect of any sufficiently sophisticated system. To a first approximation, Pandoc does a really good job of picking good defaults for the output format; if users want additional customizability, they can have that by writing their own custom Lua filters.

    Observations from contribution process

    Great practices:

    • The maintainer, John MacFarlane (a philosophy professor at Berkeley), and other core maintainers are incredibly active. Both my PRs got attention within a day. The first PR was merged in under a day, and the second PR was merged in under an hour! Fast and active review provides contributors with quick feedback and, personally, was a very strong motivator for making more contributions. I definitely see myself tackling deeper issues over the summer.
    • Great user documentation: The user documentation is really thorough and covers just about everything a user might need to get started and to get going with advanced features like Lua filters.
    • good first issue tags are a great entry point to the codebase. They cover issues that can be tackled without a very deep understanding of the codebase, but that still familiarize the contributor with the workflow of dealing with an issue and adding tests.

    Possible improvements:

    • Since not as many people contribute to Pandoc (likely due to the Haskell learning curve) outside of the core team compared to other large open source projects, there has not been much of a need for PR workflow automation. While CI's are run, more checks could be conducted with bots and other tools provided by Github actions to automate more of the review process (as is quite common with most big open source projects).
    • I found developer documentation to be a little lacking (again likely due to the small number of contributors). It would have been nice to see details of things like editor set-up with the Haskell LSP, build instructions for particular pandoc applications, and a more detailed look at the codebase architecture.

    Suggestions for the internal project based on external project observations

    • I think the biggest takeaway personally was the importance of active maintenance and support. A community is only as active as its maintainers, and knowing that work will be promptly reviewed is crucial for the life and longevity of the community. This is definitely something we can improve on with RepoSense. It is, however, certainly a challenge with nus-oss, given that students come and go fairly frequently and attention has to contend with school work and other activities.
    • Experience with Pandoc and Haskell has convinced me that advanced-type systems and function style programming help programmers write safer and more resilient software. Unfortunately, Java's type system (even with newer versions) is not nearly as powerful as Haskell's and limits how far we can take these ideas. Nevertheless, we can make some progress with making Reposense easier to reason about with refactors involving immutability and optional monads.
    +

    Project: Pandoc

    Pandoc is a Haskell library and command-line tool for converting between various document formats. It is a powerful tool that can convert between many different formats, including Markdown, LaTeX, HTML, and many others. It is also extensible, allowing for the creation of custom readers and writers for new formats. Pandoc has 31.8k stars on GitHub and is used widely by individuals for personal workflows and within deployment pipelines by larger organizations.

    My Contributions

    My Learning Record

    The Haskell tooling ecosystem (GHC, Cabal, Stack, Haskell LSP, etc) makes writing Haskell quite enjoyable. In particular, Haskell features like abstract data types, parametric polymorphism, and type inferencing make understanding and modifying code in a general and well-abstracted way really easy to do. The language also allows for strong editor tooling that also helps improve the developer experience. Contributing to Pandoc allowed me to get a deep look at practical Haskell in a widely adopted and loved tool—something I've always wanted to do.

    Pandoc is also a really great and flexible tool that has taught me a great deal about software design practices. Pandoc has lofty goals of providing good document conversion from a large number of input formats to a really large number of output formats. This is done by converting to and from Pandoc's own document intermediate representation, which has a large subset of the intersection of features of the input and output formats. By being very clear about the extent and specification of the intermediate representation, it is easy for several developers to concurrently add, modify, and fix existing readers and writers by mapping the semantics of the source or target specification to those of the Pandoc intermediate representation. In general, being very clear and thorough with interfaces between software segments seems to be an important and crucial aspect of any sufficiently sophisticated system. To a first approximation, Pandoc does a really good job of picking good defaults for the output format; if users want additional customizability, they can have that by writing their own custom Lua filters.

    Observations from contribution process

    Great practices:

    • The maintainer, John MacFarlane (a philosophy professor at Berkeley), and other core maintainers are incredibly active. Both my PRs got attention within a day. The first PR was merged in under a day, and the second PR was merged in under an hour! Fast and active review provides contributors with quick feedback and, personally, was a very strong motivator for making more contributions. I definitely see myself tackling deeper issues over the summer.
    • Great user documentation: The user documentation is really thorough and covers just about everything a user might need to get started and to get going with advanced features like Lua filters.
    • good first issue tags are a great entry point to the codebase. They cover issues that can be tackled without a very deep understanding of the codebase, but that still familiarize the contributor with the workflow of dealing with an issue and adding tests.

    Possible improvements:

    • Since not as many people contribute to Pandoc (likely due to the Haskell learning curve) outside of the core team compared to other large open source projects, there has not been much of a need for PR workflow automation. While CI's are run, more checks could be conducted with bots and other tools provided by Github actions to automate more of the review process (as is quite common with most big open source projects).
    • I found developer documentation to be a little lacking (again likely due to the small number of contributors). It would have been nice to see details of things like editor set-up with the Haskell LSP, build instructions for particular pandoc applications, and a more detailed look at the codebase architecture.

    Suggestions for the internal project based on external project observations

    • I think the biggest takeaway personally was the importance of active maintenance and support. A community is only as active as its maintainers, and knowing that work will be promptly reviewed is crucial for the life and longevity of the community. This is definitely something we can improve on with RepoSense. It is, however, certainly a challenge with nus-oss, given that students come and go fairly frequently and attention has to contend with school work and other activities.
    • Experience with Pandoc and Haskell has convinced me that advanced-type systems and function style programming help programmers write safer and more resilient software. Unfortunately, Java's type system (even with newer versions) is not nearly as powerful as Haskell's and limits how far we can take these ideas. Nevertheless, we can make some progress with making Reposense easier to reason about with refactors involving immutability and optional monads.
    diff --git a/students/gok99/observations.page-vue-render.js b/students/gok99/observations.page-vue-render.js index 0b2abdaea..cdb9cc791 100644 --- a/students/gok99/observations.page-vue-render.js +++ b/students/gok99/observations.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('h3',{attrs:{"id":"project-pandoc"}},[_v("Project: Pandoc"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#project-pandoc","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Pandoc is a Haskell library and command-line tool for converting between various document formats. It is a powerful tool that can convert between many different formats, including Markdown, LaTeX, HTML, and many others. It is also extensible, allowing for the creation of custom readers and writers for new formats. Pandoc has 31.8k stars on GitHub and is used widely by individuals for personal workflows and within deployment pipelines by larger organizations.")]),_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('ul',[_c('li',[_v("Fixed an issue involving Pandoc's Texinfo Writer: "),_c('a',{attrs:{"href":"https://github.com/jgm/pandoc/pull/9359"}},[_v("Add @var support in Texinfo Writer #8534")]),_v(" (merged)")]),_v(" "),_c('li',[_v("Fixed an issue involving Pandoc's RST Reader: "),_c('a',{attrs:{"href":"https://github.com/jgm/pandoc/pull/9744"}},[_v("RST reader: fix figclass and align annotations for figures")]),_v(" (merged)")])]),_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("The Haskell tooling ecosystem (GHC, Cabal, Stack, Haskell LSP, etc) makes writing Haskell quite enjoyable. In particular, Haskell features like abstract data types, parametric polymorphism, and type inferencing make understanding and modifying code in a general and well-abstracted way really easy to do. The language also allows for strong editor tooling that also helps improve the developer experience. Contributing to Pandoc allowed me to get a deep look at practical Haskell in a widely adopted and loved tool—something I've always wanted to do.")]),_v(" "),_c('p',[_v("Pandoc is also a really great and flexible tool that has taught me a great deal about software design practices. Pandoc has lofty goals of providing good document conversion from a large number of input formats to a really large number of output formats. This is done by converting to and from Pandoc's own document intermediate representation, which has a large subset of the intersection of features of the input and output formats. By being very clear about the extent and specification of the intermediate representation, it is easy for several developers to concurrently add, modify, and fix existing readers and writers by mapping the semantics of the source or target specification to those of the Pandoc intermediate representation. In general, being very clear and thorough with interfaces between software segments seems to be an important and crucial aspect of any sufficiently sophisticated system. To a first approximation, Pandoc does a really good job of picking good defaults for the output format; if users want additional customizability, they can have that by writing their own custom Lua filters.")]),_v(" "),_c('h4',{attrs:{"id":"observations-from-contribution-process"}},[_v("Observations from contribution process"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#observations-from-contribution-process","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Great practices:")]),_v(" "),_c('ul',[_c('li',[_v("The maintainer, John MacFarlane (a philosophy professor at Berkeley), and other core maintainers are incredibly active. Both my PRs got attention within a day. The first PR was merged in under a day, and the second PR was merged in under an hour! Fast and active review provides contributors with quick feedback and, personally, was a very strong motivator for making more contributions. I definitely see myself tackling deeper issues over the summer.")]),_v(" "),_c('li',[_v("Great user documentation: The user documentation is really thorough and covers just about everything a user might need to get started and to get going with advanced features like Lua filters.")]),_v(" "),_c('li',[_c('code',{pre:true,attrs:{"class":"hljs inline no-lang"}},[_v("good first issue")]),_v(" tags are a great entry point to the codebase. They cover issues that can be tackled without a very deep understanding of the codebase, but that still familiarize the contributor with the workflow of dealing with an issue and adding tests.")])]),_v(" "),_c('p',[_v("Possible improvements:")]),_v(" "),_c('ul',[_c('li',[_v("Since not as many people contribute to Pandoc (likely due to the Haskell learning curve) outside of the core team compared to other large open source projects, there has not been much of a need for PR workflow automation. While CI's are run, more checks could be conducted with bots and other tools provided by Github actions to automate more of the review process (as is quite common with most big open source projects).")]),_v(" "),_c('li',[_v("I found developer documentation to be a little lacking (again likely due to the small number of contributors). It would have been nice to see details of things like editor set-up with the Haskell LSP, build instructions for particular pandoc applications, and a more detailed look at the codebase architecture.")])]),_v(" "),_c('h4',{attrs:{"id":"suggestions-for-the-internal-project-based-on-external-project-observations"}},[_v("Suggestions for the internal project based on external project observations"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#suggestions-for-the-internal-project-based-on-external-project-observations","onclick":"event.stopPropagation()"}})]),_v(" "),_c('ul',[_c('li',[_v("I think the biggest takeaway personally was the importance of active maintenance and support. A community is only as active as its maintainers, and knowing that work will be promptly reviewed is crucial for the life and longevity of the community. This is definitely something we can improve on with RepoSense. It is, however, certainly a challenge with nus-oss, given that students come and go fairly frequently and attention has to contend with school work and other activities.")]),_v(" "),_c('li',[_v("Experience with Pandoc and Haskell has convinced me that advanced-type systems and function style programming help programmers write safer and more resilient software. Unfortunately, Java's type system (even with newer versions) is not nearly as powerful as Haskell's and limits how far we can take these ideas. Nevertheless, we can make some progress with making Reposense easier to reason about with refactors involving "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2144"}},[_v("immutability and optional monads")]),_v(".")])])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/gok99/progress.html b/students/gok99/progress.html index c1690a22b..eb222b4e8 100644 --- a/students/gok99/progress.html +++ b/students/gok99/progress.html @@ -12,7 +12,7 @@ const baseUrl = '/2024' -
    Week Contribution
    06/05/22 Opened PR: Increase total character threshold in code view #1773
    07/05/22 Reviewed PR: Docs: fix broken links in about.md #1777
    08/05/22 Reviewed PR: Fix unintended behavior related to --since d1 #1776
    06/05/22 Contributed to discussion in: Code panel collapses files even if there are only a few files #1772
    01/07/22 Contributed to discussion in: Tracking tasks related to supporting other types of remote repo URLs in PR#1644
    17/07/22 Contributed to discussion in: Refactoring processLine in RepoConfigCsvParser class #1753
    17/08/22 Contributed to discussion in: User Guide: Give more info on the File Size Limit #1825
    17/08/22 Reviewed PR: Fix filter glob user input #1827
    20/08/22 Opened PR: Give more info on the File Size Limit in UG #1829
    27/08/22 Reviewed PR: Disable links when they are broken #1830
    30/08/22 Contributed to discussion in: Glob filter is not editable #1831
    06/07/23 Reviewed PR: Migrate build.gradle from Groovy to Kotlin #2008
    05/07/23 Reviewed PR: Fix bugs in UG #2013
    01/08/23 Contributed to discussion in: Implement authorship analysis #2030
    01/10/23 Openend Issue: Broken environment cleanup #2044
    1 Reviewed PR: Refactor RepoConfigCsvParser::processLine method to avoid arrowhead style code #2080
    2 Contributed to discussion in: Suggestions on improvement for memory performance regarding Regex matching #2091
    2 Reviewed PR: Suppress Console Warning #2088
    2 Reviewed PR: Improve memory usage by refactoring Regex compilation #2092
    3 Reviewed PR: Refactor RepoConfiguration to simplify constructor complexity #2078
    3 Reviewed PR: Updating SystemTestUtil::assertJson to compare Json objects instead of line-by-line analysis #2087
    3 Reviewed PR: Refactor parser package for greater organisation of classes #2104
    4 Reviewed PR: Fix broken DevOps Guide link in Learning Basics #2107
    5 Contributed to discussion in: Implement Proper Deep Cloning for RepoConfiguration and CliArguments #2119
    5 Reviewed PR: Minor Enhancements to Existing Regex Code #2115
    6 Reviewed PR: Refactor CliArguments to conform to RepoConfiguration's Builder Pattern #2118
    6 Reviewed PR: Update RepoSense contributors in documentation #2138
    7 Opened Issue: Use optionals for return values that may be null to enforce a client check #2141
    7 Reviewed PR: Improve performance #2108
    7 Reviewed PR: Add originality threshold flag #2122
    7 Reviewed PR: Resolve Merge Conflict #2139
    9 Reviewed PR: [#2141] Use optionals for return values that may be null to enforce a client check
    9 Reviewed PR: [#2164] Revert "[#2109] Add search by tag functionality"
    10 Reviewed PR: [#944] Implement authorship analysis
    10 Reviewed PR: Add more testcases
    R Reviewied PR: [#2177] Migrate to Java 11 Syntax and Features
    R Reviewed PR: [#2170] Add Blurbs for Repos
    R Reviewed PR: [#2161] One-Stop Config File for Code Portfolio
    R Contributed to discussion in: Surge preview deployments for many of our latest PRs are not working
    R Opened Issue: Use GitBlameLineInfo for processing git blame output in aggregateBlameAuthorModifiedAndDateInfo
    R Contributed to discussion in: Simplify Config File Creation and Project Scaffolding Process
    +
    Week Contribution
    06/05/22 Opened PR: Increase total character threshold in code view #1773
    07/05/22 Reviewed PR: Docs: fix broken links in about.md #1777
    08/05/22 Reviewed PR: Fix unintended behavior related to --since d1 #1776
    06/05/22 Contributed to discussion in: Code panel collapses files even if there are only a few files #1772
    01/07/22 Contributed to discussion in: Tracking tasks related to supporting other types of remote repo URLs in PR#1644
    17/07/22 Contributed to discussion in: Refactoring processLine in RepoConfigCsvParser class #1753
    17/08/22 Contributed to discussion in: User Guide: Give more info on the File Size Limit #1825
    17/08/22 Reviewed PR: Fix filter glob user input #1827
    20/08/22 Opened PR: Give more info on the File Size Limit in UG #1829
    27/08/22 Reviewed PR: Disable links when they are broken #1830
    30/08/22 Contributed to discussion in: Glob filter is not editable #1831
    06/07/23 Reviewed PR: Migrate build.gradle from Groovy to Kotlin #2008
    05/07/23 Reviewed PR: Fix bugs in UG #2013
    01/08/23 Contributed to discussion in: Implement authorship analysis #2030
    01/10/23 Openend Issue: Broken environment cleanup #2044
    1 Reviewed PR: Refactor RepoConfigCsvParser::processLine method to avoid arrowhead style code #2080
    2 Contributed to discussion in: Suggestions on improvement for memory performance regarding Regex matching #2091
    2 Reviewed PR: Suppress Console Warning #2088
    2 Reviewed PR: Improve memory usage by refactoring Regex compilation #2092
    3 Reviewed PR: Refactor RepoConfiguration to simplify constructor complexity #2078
    3 Reviewed PR: Updating SystemTestUtil::assertJson to compare Json objects instead of line-by-line analysis #2087
    3 Reviewed PR: Refactor parser package for greater organisation of classes #2104
    4 Reviewed PR: Fix broken DevOps Guide link in Learning Basics #2107
    5 Contributed to discussion in: Implement Proper Deep Cloning for RepoConfiguration and CliArguments #2119
    5 Reviewed PR: Minor Enhancements to Existing Regex Code #2115
    6 Reviewed PR: Refactor CliArguments to conform to RepoConfiguration's Builder Pattern #2118
    6 Reviewed PR: Update RepoSense contributors in documentation #2138
    7 Opened Issue: Use optionals for return values that may be null to enforce a client check #2141
    7 Reviewed PR: Improve performance #2108
    7 Reviewed PR: Add originality threshold flag #2122
    7 Reviewed PR: Resolve Merge Conflict #2139
    9 Reviewed PR: [#2141] Use optionals for return values that may be null to enforce a client check
    9 Reviewed PR: [#2164] Revert "[#2109] Add search by tag functionality"
    10 Reviewed PR: [#944] Implement authorship analysis
    10 Reviewed PR: Add more testcases
    R Reviewied PR: [#2177] Migrate to Java 11 Syntax and Features
    R Reviewed PR: [#2170] Add Blurbs for Repos
    R Reviewed PR: [#2161] One-Stop Config File for Code Portfolio
    R Contributed to discussion in: Surge preview deployments for many of our latest PRs are not working
    R Opened Issue: Use GitBlameLineInfo for processing git blame output in aggregateBlameAuthorModifiedAndDateInfo
    R Contributed to discussion in: Simplify Config File Creation and Project Scaffolding Process
    diff --git a/students/gok99/progress.page-vue-render.js b/students/gok99/progress.page-vue-render.js index 9fc531af0..590b34b84 100644 --- a/students/gok99/progress.page-vue-render.js +++ b/students/gok99/progress.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('div',{staticClass:"table-responsive"},[_c('table',{staticClass:"markbind-table table table-bordered table-striped"},[_c('thead',[_c('tr',[_c('th',[_v("Week")]),_v(" "),_c('th',[_v("Contribution")])])]),_v(" "),_c('tbody',[_c('tr',[_c('td',[_v("06/05/22")]),_v(" "),_c('td',[_v("Opened PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/1773"}},[_v("Increase total character threshold in code view #1773")])])]),_v(" "),_c('tr',[_c('td',[_v("07/05/22")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/1777"}},[_v("Docs: fix broken links in about.md #1777")])])]),_v(" "),_c('tr',[_c('td',[_v("08/05/22")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/1776"}},[_v("Fix unintended behavior related to --since d1 #1776")])])]),_v(" "),_c('tr',[_c('td',[_v("06/05/22")]),_v(" "),_c('td',[_v("Contributed to discussion in: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/issues/1772"}},[_v("Code panel collapses files even if there are only a few files #1772")])])]),_v(" "),_c('tr',[_c('td',[_v("01/07/22")]),_v(" "),_c('td',[_v("Contributed to discussion in: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/issues/1726"}},[_v("Tracking tasks related to supporting other types of remote repo URLs in PR#1644")])])]),_v(" "),_c('tr',[_c('td',[_v("17/07/22")]),_v(" "),_c('td',[_v("Contributed to discussion in: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/issues/1753"}},[_v("Refactoring processLine in RepoConfigCsvParser class #1753")])])]),_v(" "),_c('tr',[_c('td',[_v("17/08/22")]),_v(" "),_c('td',[_v("Contributed to discussion in: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/issues/1825"}},[_v("User Guide: Give more info on the File Size Limit #1825")])])]),_v(" "),_c('tr',[_c('td',[_v("17/08/22")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/1827"}},[_v("Fix filter glob user input #1827")])])]),_v(" "),_c('tr',[_c('td',[_v("20/08/22")]),_v(" "),_c('td',[_v("Opened PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/1829"}},[_v("Give more info on the File Size Limit in UG #1829")])])]),_v(" "),_c('tr',[_c('td',[_v("27/08/22")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/1830"}},[_v("Disable links when they are broken #1830")])])]),_v(" "),_c('tr',[_c('td',[_v("30/08/22")]),_v(" "),_c('td',[_v("Contributed to discussion in: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/issues/1831"}},[_v("Glob filter is not editable #1831")])])]),_v(" "),_c('tr',[_c('td',[_v("06/07/23")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2008"}},[_v("Migrate build.gradle from Groovy to Kotlin #2008")])])]),_v(" "),_c('tr',[_c('td',[_v("05/07/23")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2013"}},[_v("Fix bugs in UG #2013")])])]),_v(" "),_c('tr',[_c('td',[_v("01/08/23")]),_v(" "),_c('td',[_v("Contributed to discussion in: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2030"}},[_v("Implement authorship analysis #2030")])])]),_v(" "),_c('tr',[_c('td',[_v("01/10/23")]),_v(" "),_c('td',[_v("Openend Issue: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/issues/2044"}},[_v("Broken environment cleanup #2044")])])]),_v(" "),_c('tr',[_c('td',[_v("1")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2080"}},[_v("Refactor RepoConfigCsvParser::processLine method to avoid arrowhead style code #2080")])])]),_v(" "),_c('tr',[_c('td',[_v("2")]),_v(" "),_c('td',[_v("Contributed to discussion in: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/issues/2091"}},[_v("Suggestions on improvement for memory performance regarding Regex matching #2091")])])]),_v(" "),_c('tr',[_c('td',[_v("2")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2088"}},[_v("Suppress Console Warning #2088")])])]),_v(" "),_c('tr',[_c('td',[_v("2")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2092"}},[_v("Improve memory usage by refactoring Regex compilation #2092")])])]),_v(" "),_c('tr',[_c('td',[_v("3")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2078"}},[_v("Refactor RepoConfiguration to simplify constructor complexity #2078")])])]),_v(" "),_c('tr',[_c('td',[_v("3")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2087"}},[_v("Updating SystemTestUtil::assertJson to compare Json objects instead of line-by-line analysis #2087")])])]),_v(" "),_c('tr',[_c('td',[_v("3")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2104"}},[_v("Refactor parser package for greater organisation of classes #2104")])])]),_v(" "),_c('tr',[_c('td',[_v("4")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2107"}},[_v("Fix broken DevOps Guide link in Learning Basics #2107")])])]),_v(" "),_c('tr',[_c('td',[_v("5")]),_v(" "),_c('td',[_v("Contributed to discussion in: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/issues/2119"}},[_v("Implement Proper Deep Cloning for RepoConfiguration and CliArguments #2119")])])]),_v(" "),_c('tr',[_c('td',[_v("5")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2115"}},[_v("Minor Enhancements to Existing Regex Code #2115")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2118"}},[_v("Refactor CliArguments to conform to RepoConfiguration's Builder Pattern #2118")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2138"}},[_v("Update RepoSense contributors in documentation #2138")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Opened Issue: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/issues/2141"}},[_v("Use optionals for return values that may be null to enforce a client check #2141")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2108"}},[_v("Improve performance #2108")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2122"}},[_v("Add originality threshold flag #2122")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2139"}},[_v("Resolve Merge Conflict #2139")])])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2144"}},[_v("[#2141] Use optionals for return values that may be null to enforce a client check")])])]),_v(" "),_c('tr',[_c('td',[_v("9")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2165"}},[_v("[#2164] Revert \"[#2109] Add search by tag functionality\"")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2140"}},[_v("[#944] Implement authorship analysis")])])]),_v(" "),_c('tr',[_c('td',[_v("10")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/testrepo-Alpha/pull/21"}},[_v("Add more testcases")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Reviewied PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2183"}},[_v("[#2177] Migrate to Java 11 Syntax and Features")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2191"}},[_v("[#2170] Add Blurbs for Repos")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/pull/2192"}},[_v("[#2161] One-Stop Config File for Code Portfolio")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Contributed to discussion in: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/issues/2194"}},[_v("Surge preview deployments for many of our latest PRs are not working")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Opened Issue: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/issues/2196"}},[_v("Use GitBlameLineInfo for processing git blame output in aggregateBlameAuthorModifiedAndDateInfo")])])]),_v(" "),_c('tr',[_c('td',[_v("R")]),_v(" "),_c('td',[_v("Contributed to discussion in: "),_c('a',{attrs:{"href":"https://github.com/reposense/RepoSense/issues/2199"}},[_v("Simplify Config File Creation and Project Scaffolding Process")])])])])])])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/gycgabriel/info.html b/students/gycgabriel/info.html index 7590efac1..026d08361 100644 --- a/students/gycgabriel/info.html +++ b/students/gycgabriel/info.html @@ -12,7 +12,7 @@ const baseUrl = '/2024' - + diff --git a/students/gycgabriel/info.page-vue-render.js b/students/gycgabriel/info.page-vue-render.js index c3732efa2..fc9cce2be 100644 --- a/students/gycgabriel/info.page-vue-render.js +++ b/students/gycgabriel/info.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('p',[_c('span',{attrs:{"id":"github"}},[_c('a',{attrs:{"href":"https://www.github.com/gycgabriel"}},[_v("https://www.github.com/gycgabriel")])])]),_v(" "),_c('p',[_c('span',{attrs:{"id":"projects"}},[_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher"}},[_v("CATcher")]),_v(", "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher"}},[_v("WATcher")])])])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/gycgabriel/knowledge.html b/students/gycgabriel/knowledge.html index 236be0643..b65e61b67 100644 --- a/students/gycgabriel/knowledge.html +++ b/students/gycgabriel/knowledge.html @@ -22,7 +22,7 @@ [ngStyle]="this.labelService.setLabelStyle(this.labelService.getColorOfLabel('Rejected'))" >

    The dynamic expression can be evaluated in the context of the corresponding .ts file of the html file.

    Event binding

    Parenthesis within html tags, for example (click) are used to call the component's corresponding method on click. In the example above, $event.stopPropagation() is a Javascript call that prevents the label Disagree 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.

    Resources:

    Git Rebase

    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.

    Resource:

    Github File Upload API: CreateFile vs CreateTree

    The API for committing a single file and committing multiple files at once are different. -Attempting 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.

    Resources:

    +Attempting 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.

    Resources:

    diff --git a/students/gycgabriel/knowledge.page-vue-render.js b/students/gycgabriel/knowledge.page-vue-render.js index c570582b4..05bbbc419 100644 --- a/students/gycgabriel/knowledge.page-vue-render.js +++ b/students/gycgabriel/knowledge.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_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")])])])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/gycgabriel/observations.html b/students/gycgabriel/observations.html index ec0265a6d..9fc1116ae 100644 --- a/students/gycgabriel/observations.html +++ b/students/gycgabriel/observations.html @@ -12,7 +12,7 @@ const baseUrl = '/2024' -

    Project: FreeCodeCamp.org

    An open source platform providing free resources to learn coding.

    My Contributions

    Give a description of your contributions, including links to relevant PRs

    Merged fix(curriculum): update instructions for step 110 for rpg project #53564

    Awaiting Review fix(client): Add live image URL validation for portfolio images #53617

    Adding image URL validation for frontend

    Learnt how we can use image() html object to verify if the image URL is live.

    Debugging CI/CD tests

    Learnt that the previous test cases can affect the next test cases, so I should run all test cases in order to check if there's problems with loading and saving state.

    Learnt to check if I forgot to check logic with loading saved states (adding a portfolio section in user settings, and loading that section portfolio)

    My Learning Record

    Give tools/technologies you learned here. Include resources you used, and a brief summary of the resource.

    Setting up a GitHub repository with Windows Subsystem for Linux (WSL)

    Learnt to use VSCode to access code on the WSL. Git clone repository on the WSL, not on windows.

    Discord server and forums

    FreeCodeCamp has live Discord server and forums with active and dedicated contributors.

    Setting up was difficult, and while instructions could be clearer separated into Windows and Mac users (for Windows users, for Mac users), it was good they had detailed instructions.

    Wait time for help

    As with all open source projects, getting help or code reviews can take time. I was fortunate my first PR was an easy fix and quickly reviewed within 15 mins, but my second PR is still awaiting review. Nonetheless, the contributors are helpful and helped point out the cause of my CI/CD issues.

    +

    Project: FreeCodeCamp.org

    An open source platform providing free resources to learn coding.

    My Contributions

    Give a description of your contributions, including links to relevant PRs

    Merged fix(curriculum): update instructions for step 110 for rpg project #53564

    Awaiting Review fix(client): Add live image URL validation for portfolio images #53617

    Adding image URL validation for frontend

    Learnt how we can use image() html object to verify if the image URL is live.

    Debugging CI/CD tests

    Learnt that the previous test cases can affect the next test cases, so I should run all test cases in order to check if there's problems with loading and saving state.

    Learnt to check if I forgot to check logic with loading saved states (adding a portfolio section in user settings, and loading that section portfolio)

    My Learning Record

    Give tools/technologies you learned here. Include resources you used, and a brief summary of the resource.

    Setting up a GitHub repository with Windows Subsystem for Linux (WSL)

    Learnt to use VSCode to access code on the WSL. Git clone repository on the WSL, not on windows.

    Discord server and forums

    FreeCodeCamp has live Discord server and forums with active and dedicated contributors.

    Setting up was difficult, and while instructions could be clearer separated into Windows and Mac users (for Windows users, for Mac users), it was good they had detailed instructions.

    Wait time for help

    As with all open source projects, getting help or code reviews can take time. I was fortunate my first PR was an easy fix and quickly reviewed within 15 mins, but my second PR is still awaiting review. Nonetheless, the contributors are helpful and helped point out the cause of my CI/CD issues.

    diff --git a/students/gycgabriel/observations.page-vue-render.js b/students/gycgabriel/observations.page-vue-render.js index 2d1a91b35..57a23e9df 100644 --- a/students/gycgabriel/observations.page-vue-render.js +++ b/students/gycgabriel/observations.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('h3',{attrs:{"id":"project-freecodecamp-org"}},[_v("Project: FreeCodeCamp.org"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#project-freecodecamp-org","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("An open source platform providing free resources to learn coding.")]),_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('p',[_v("Merged "),_c('a',{attrs:{"href":"https://github.com/freeCodeCamp/freeCodeCamp/pull/53564"}},[_v("fix(curriculum): update instructions for step 110 for rpg project #53564")])]),_v(" "),_c('p',[_v("Awaiting Review "),_c('a',{attrs:{"href":"https://github.com/freeCodeCamp/freeCodeCamp/pull/53617"}},[_v("fix(client): Add live image URL validation for portfolio images #53617")])]),_v(" "),_c('h4',{attrs:{"id":"adding-image-url-validation-for-frontend"}},[_v("Adding image URL validation for frontend"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#adding-image-url-validation-for-frontend","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Learnt how we can use image() html object to verify if the image URL is live.")]),_v(" "),_c('h4',{attrs:{"id":"debugging-ci-cd-tests"}},[_v("Debugging CI/CD tests"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#debugging-ci-cd-tests","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Learnt that the previous test cases can affect the next test cases, so I should run all test cases in order to check if there's problems with loading and saving state.")]),_v(" "),_c('p',[_v("Learnt to check if I forgot to check logic with loading saved states (adding a portfolio section in user settings, and loading that section portfolio)")]),_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.")]),_v(" "),_c('h4',{attrs:{"id":"setting-up-a-github-repository-with-windows-subsystem-for-linux-wsl"}},[_v("Setting up a GitHub repository with Windows Subsystem for Linux (WSL)"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#setting-up-a-github-repository-with-windows-subsystem-for-linux-wsl","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("Learnt to use VSCode to access code on the WSL. Git clone repository on the WSL, not on windows.")]),_v(" "),_c('h4',{attrs:{"id":"discord-server-and-forums"}},[_v("Discord server and forums"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#discord-server-and-forums","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("FreeCodeCamp has live Discord server and forums with active and dedicated contributors.")]),_v(" "),_c('p',[_v("Setting up was difficult, and while instructions could be clearer separated into Windows and Mac users (for Windows users, for Mac users), it was good they had detailed instructions.")]),_v(" "),_c('h4',{attrs:{"id":"wait-time-for-help"}},[_v("Wait time for help"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#wait-time-for-help","onclick":"event.stopPropagation()"}})]),_v(" "),_c('p',[_v("As with all open source projects, getting help or code reviews can take time. I was fortunate my first PR was an easy fix and quickly reviewed within 15 mins, but my second PR is still awaiting review. Nonetheless, the contributors are helpful and helped point out the cause of my CI/CD issues.")])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/gycgabriel/progress.html b/students/gycgabriel/progress.html index 6dd2ca896..5c445f76a 100644 --- a/students/gycgabriel/progress.html +++ b/students/gycgabriel/progress.html @@ -12,7 +12,7 @@ const baseUrl = '/2024' -

    CS3282 Progress

    Issues - WATcher

    PR Reviews - WATcher

    PR Contributed - WATcher

    Week Achievements
    4 Contributed PR: Build in Github Actions #239

    PR Reviews - CATcher

    Week Achievements
    1 Commented on PR: Redirect invalid routes to 404 not found page #1238
    +

    CS3282 Progress

    Issues - WATcher

    PR Reviews - WATcher

    PR Contributed - WATcher

    Week Achievements
    4 Contributed PR: Build in Github Actions #239

    PR Reviews - CATcher

    Week Achievements
    1 Commented on PR: Redirect invalid routes to 404 not found page #1238
    diff --git a/students/gycgabriel/progress.page-vue-render.js b/students/gycgabriel/progress.page-vue-render.js index 19673a648..cbbff5e56 100644 --- a/students/gycgabriel/progress.page-vue-render.js +++ b/students/gycgabriel/progress.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('h2',{attrs:{"id":"cs3282-progress"}},[_v("CS3282 Progress"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#cs3282-progress","onclick":"event.stopPropagation()"}})]),_v(" "),_c('h3',{attrs:{"id":"issues-watcher"}},[_v("Issues - WATcher"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#issues-watcher","onclick":"event.stopPropagation()"}})]),_v(" "),_c('div',{staticClass:"table-responsive"},[_c('table',{staticClass:"markbind-table table table-bordered table-striped"},[_c('thead',[_c('tr',[_c('th',[_v("Week")]),_v(" "),_c('th',[_v("Achievements")])])]),_v(" "),_c('tbody',[_c('tr',[_c('td',[_v("1")]),_v(" "),_c('td',[_v("Submitted Issue: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/221"}},[_v("Tasks To Self-Test Knowledge Unhide Activity Dashboard #221")])])]),_v(" "),_c('tr',[_c('td',[_v("1")]),_v(" "),_c('td',[_v("Submitted Issue: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/224"}},[_v("Bug when not entering anything into Select repo dialog #224")])])]),_v(" "),_c('tr',[_c('td',[_v("1")]),_v(" "),_c('td',[_v("Submitted Issue: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/225"}},[_v("Show a list of hidden users at the end #225")])])]),_v(" "),_c('tr',[_c('td',[_v("1")]),_v(" "),_c('td',[_v("Submitted Issue: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/227"}},[_v("Error toast shown on selecting p.Low or priority.Low label on WATcher repository #227")])])]),_v(" "),_c('tr',[_c('td',[_v("2")]),_v(" "),_c('td',[_v("Submitted Issue: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/232"}},[_v("Move Activity Dashboard from prototype to release #232")])])]),_v(" "),_c('tr',[_c('td',[_v("4")]),_v(" "),_c('td',[_v("Commented on Issue: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/236"}},[_v("Bypass logging in if viewing public repos only #236")])])]),_v(" "),_c('tr',[_c('td',[_v("4")]),_v(" "),_c('td',[_v("Commented on Issue: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/issues/240"}},[_v("Hiding labels do not work as expected #240")])])])])])]),_c('h3',{attrs:{"id":"pr-reviews-watcher"}},[_v("PR Reviews - WATcher"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#pr-reviews-watcher","onclick":"event.stopPropagation()"}})]),_v(" "),_c('div',{staticClass:"table-responsive"},[_c('table',{staticClass:"markbind-table table table-bordered table-striped"},[_c('thead',[_c('tr',[_c('th',[_v("Week")]),_v(" "),_c('th',[_v("Achievements")])])]),_v(" "),_c('tbody',[_c('tr',[_c('td',[_v("1")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/223"}},[_v("Hide 0 issue columns #223")])])]),_v(" "),_c('tr',[_c('td',[_v("1-4")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/226"}},[_v("Keep filters option when switching repos #226")])])]),_v(" "),_c('tr',[_c('td',[_v("2")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/228"}},[_v("Prevent redirection when repo not set #228")])])]),_v(" "),_c('tr',[_c('td',[_v("2-4")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/230"}},[_v("Fix label filter not working #230")])])]),_v(" "),_c('tr',[_c('td',[_v("4")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/233"}},[_v("Improve activity dashboard design #233")])])]),_v(" "),_c('tr',[_c('td',[_v("4")]),_v(" "),_c('td',[_v("Commented on PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/234"}},[_v("Refactor test cases (In progress) #234")])])]),_v(" "),_c('tr',[_c('td',[_v("4")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/235"}},[_v("Show list of hidden users #235")])])]),_v(" "),_c('tr',[_c('td',[_v("4")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/238"}},[_v("Remove unused services #238")])])]),_v(" "),_c('tr',[_c('td',[_v("5")]),_v(" "),_c('td',[_v("Commented on PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/254"}},[_v("Refactor Label model #254")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/255"}},[_v("Add shareable repo-specific URL #255")])])]),_v(" "),_c('tr',[_c('td',[_v("6")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/259"}},[_v("Refactor certain filters into its own service #259")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/260"}},[_v("Remove test cases for permissions service #260")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/272"}},[_v("Automatic deployment #272")])])]),_v(" "),_c('tr',[_c('td',[_v("7")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/288"}},[_v("Enable pre push hook for npm run test #288")])])]),_v(" "),_c('tr',[_c('td',[_v("8")]),_v(" "),_c('td',[_v("Reviewed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/289"}},[_v("Refactor milestones to save by name #289")])])])])])]),_c('h3',{attrs:{"id":"pr-contributed-watcher"}},[_v("PR Contributed - WATcher"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#pr-contributed-watcher","onclick":"event.stopPropagation()"}})]),_v(" "),_c('div',{staticClass:"table-responsive"},[_c('table',{staticClass:"markbind-table table table-bordered table-striped"},[_c('thead',[_c('tr',[_c('th',[_v("Week")]),_v(" "),_c('th',[_v("Achievements")])])]),_v(" "),_c('tbody',[_c('tr',[_c('td',[_v("4")]),_v(" "),_c('td',[_v("Contributed PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/WATcher/pull/239"}},[_v("Build in Github Actions #239")])])])])])]),_c('h3',{attrs:{"id":"pr-reviews-catcher"}},[_v("PR Reviews - CATcher"),_c('a',{staticClass:"fa fa-anchor",attrs:{"href":"#pr-reviews-catcher","onclick":"event.stopPropagation()"}})]),_v(" "),_c('div',{staticClass:"table-responsive"},[_c('table',{staticClass:"markbind-table table table-bordered table-striped"},[_c('thead',[_c('tr',[_c('th',[_v("Week")]),_v(" "),_c('th',[_v("Achievements")])])]),_v(" "),_c('tbody',[_c('tr',[_c('td',[_v("1")]),_v(" "),_c('td',[_v("Commented on PR: "),_c('a',{attrs:{"href":"https://github.com/CATcher-org/CATcher/pull/1238"}},[_v("Redirect invalid routes to 404 not found page #1238")])])])])])])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/itsyme/info.html b/students/itsyme/info.html index f492129d5..cfd017bae 100644 --- a/students/itsyme/info.html +++ b/students/itsyme/info.html @@ -12,7 +12,7 @@ const baseUrl = '/2024' - + diff --git a/students/itsyme/info.page-vue-render.js b/students/itsyme/info.page-vue-render.js index 6b19955cc..73cda0e68 100644 --- a/students/itsyme/info.page-vue-render.js +++ b/students/itsyme/info.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_c('p',[_c('span',{attrs:{"id":"github"}},[_c('a',{attrs:{"href":"https://www.github.com/itsyme"}},[_v("https://www.github.com/itsyme")])])]),_v(" "),_c('p',[_c('span',{attrs:{"id":"projects"}},[_c('a',{attrs:{"href":"https://github.com/MarkBind/markbind"}},[_v("MarkBind")])])])])} },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.5.2")])]),_v(" on Sun, 12 May 2024, 14:03:36 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")])])])])])])])} +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.5.2")])]),_v(" on Sun, 12 May 2024, 15:16:31 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/students/itsyme/knowledge.html b/students/itsyme/knowledge.html index fbc380326..7ba836cc5 100644 --- a/students/itsyme/knowledge.html +++ b/students/itsyme/knowledge.html @@ -12,7 +12,7 @@ const baseUrl = '/2024' -

    Vue.js

    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 Vue.js documentation, and referencing examples of already implemented Vue components in MarkBind, I quickly understood the use of <template>, <style> and <script>. Through Markbind's Developer Guide, I learnt how to easily create different kinds of Vue components and implement them in MarkBind.

    As I implemented my first Vue component, Add autogenerated breadcrumbs component #2193, I delved deeper into Vue, exploring the use of data(), to manage the internal state of Vue components, and methods() to define methods to be used within the component. I also learnt more about Vue lifecycle hooks, in which I used the mounted hook to allow the Breadcrumb component to query the SiteNav to figure out the hierarchy of the current page.

    As I continued working on improving MarkBind's frontend, I learnt more about Vue's <transition> component, in particular using transition hooks. While I was working on Fix Quiz expanding between questions #2184, I came realize how useful these hooks were, helping to create seamless transitions for different situations. I relied heavily on Vue.js documentation and StackOverflow Posts as I was researching about Vue's transition hooks.

    Document Object Model (DOM) Manipulation

    When I was working on implementing the new Breadcrumb and Collapse/Expand All Buttons components, I had to extensively use Document.querySelector() and other related methods. I was new to this and had to do some research about how the methods work, what happens if the object cannot be found and handling edge cases. By practicing these while implementing the two components mentioned above, I believe that I have become more proficient in doing this. As a side-effect of this, I have also gained a deeper understanding on how the DOM works.

    Resources:

    Jest/Vue Test Utils

    Jest and Vue Test Utils were something that I was new to coming into MarkBind. MarkBind uses Jest together with Vue Test Utils for its snapshot tests, which test Vue components against their expected snapshots. As I was updating and implementing Vue components, I had to update and create the relevant test suites to ensure that the Vue components that I was updating or creating were working as expected. I explored mounting the components, attaching components to a document to allow another component to interact with them.

    Resources:

    Typescript

    As MarkBind is undergoing a migration to Typescript, I put in some time to learn basic Typescript. This was important as mid-way through the semester, as many of the files were being migrated to Typescript. This has also helped me in reviewing PRs that deals with Typescript migration and PRs which affect the Typscript files in MarkBind.

    Resources:

    UI

    When updating the looks of old components and creating new ones, I had to do some research about what makes a website visually pleasing. My most interesting finds were about the use of golden ratios in design and choosing complementary colours with tools such as Canva's Colour Wheel. I also learnt the different meanings of different icons through exploration and discussions with Update Breadcrumb icons #2265 and Add CollapseExpandButtons component.

    I also internalized how to create transitions and effects that fit with the theme of the project, for MarkBind, had a more minimal theme. This was done when updating designs of components in Tweak sitenav design #2204, Update Question/Quiz component design #2131.

    Project Management

    As I progressed to start managing the project, I started reviewing and merging PRs. Initially as I reviewed smaller PRs, I had little problem understanding the code and understanding where it can be improved. However, as I reviewed more complex PRs, I began having difficulties understanding the changes quickly. I came across a method to understand code in a more simple manner, the Rubber Duck Debugging method. Using this helped me to try and understand the code line by line and handle more complex changes more managably, helping me to understanding them better.

    Upgrading dependencies

    As I worked on bump nunjucks to 3.2.4 #2411, I was initially not confident what to look out for when upgrading dependencies. However, after I worked on this I understood how to look out for breaking changes and to find out how your project is using it in order to confidently upgrade it without breaking things in the project.

    GitHub Actions

    I gained a more in depth understanding about GitHub Actions when I was working on Add install setuptools to ci #2530. Utilizing conditional runs for the macos platform which required a brew install to get the CI to run properly which would throw errors for other platforms which do not use Homebrew.

    Husky

    As I researched on improving code cleanliness in my projects and found that Husky was a tool that could be used to not only maintain the code cleanliness of projects but could be used for things like running tests as well. Husky has become a mainstay in all my JS projects together with ESLint, Prettier and lint-staged. I spent some time understanding how Husky has changed the way it should be used by deprecating the use of Husky within the package.json and rather is now in the .husky folder.

    AWS SageMaker

    As I researched on AWS SageMaker for my lightning talk and used it during my internship, I got to understand more about AWS SageMaker and its benefits for hosting AI models in the cloud. AWS SageMaker is beneficial smaller players, or applications which have a pattern of use that comes in sporadic bursts as it reduces the upfront cost of expensive AI infrastructure. SageMaker also offers many services that helpes to simplify the development and deployment of AI models.

    Micro-frontends

    As I worked on researching on micro-frontends for my internship, I gained a deeper understanding of micro-frontends. Micro-frontends are what micro-services for backends, but for the front-end. Micro-frontends allows the splitting up of the front-end and this brings many benefits. From allowing teams to manage their own vertical stack, by owning their own micro-frontend, to reducing the bundle size, micro-frontends are beneficial to large teams. I also worked on a POC of migrating parts of the application using WebPack 5 Module Federation for Next.js which allowed me to fully appreciate it.

    +

    Vue.js

    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 Vue.js documentation, and referencing examples of already implemented Vue components in MarkBind, I quickly understood the use of <template>, <style> and <script>. Through Markbind's Developer Guide, I learnt how to easily create different kinds of Vue components and implement them in MarkBind.

    As I implemented my first Vue component, Add autogenerated breadcrumbs component #2193, I delved deeper into Vue, exploring the use of data(), to manage the internal state of Vue components, and methods() to define methods to be used within the component. I also learnt more about Vue lifecycle hooks, in which I used the mounted hook to allow the Breadcrumb component to query the SiteNav to figure out the hierarchy of the current page.

    As I continued working on improving MarkBind's frontend, I learnt more about Vue's <transition> component, in particular using transition hooks. While I was working on Fix Quiz expanding between questions #2184, I came realize how useful these hooks were, helping to create seamless transitions for different situations. I relied heavily on Vue.js documentation and StackOverflow Posts as I was researching about Vue's transition hooks.

    Document Object Model (DOM) Manipulation

    When I was working on implementing the new Breadcrumb and Collapse/Expand All Buttons components, I had to extensively use Document.querySelector() and other related methods. I was new to this and had to do some research about how the methods work, what happens if the object cannot be found and handling edge cases. By practicing these while implementing the two components mentioned above, I believe that I have become more proficient in doing this. As a side-effect of this, I have also gained a deeper understanding on how the DOM works.

    Resources:

    Jest/Vue Test Utils

    Jest and Vue Test Utils were something that I was new to coming into MarkBind. MarkBind uses Jest together with Vue Test Utils for its snapshot tests, which test Vue components against their expected snapshots. As I was updating and implementing Vue components, I had to update and create the relevant test suites to ensure that the Vue components that I was updating or creating were working as expected. I explored mounting the components, attaching components to a document to allow another component to interact with them.

    Resources:

    Typescript

    As MarkBind is undergoing a migration to Typescript, I put in some time to learn basic Typescript. This was important as mid-way through the semester, as many of the files were being migrated to Typescript. This has also helped me in reviewing PRs that deals with Typescript migration and PRs which affect the Typscript files in MarkBind.

    Resources:

    UI

    When updating the looks of old components and creating new ones, I had to do some research about what makes a website visually pleasing. My most interesting finds were about the use of golden ratios in design and choosing complementary colours with tools such as Canva's Colour Wheel. I also learnt the different meanings of different icons through exploration and discussions with Update Breadcrumb icons #2265 and Add CollapseExpandButtons component.

    I also internalized how to create transitions and effects that fit with the theme of the project, for MarkBind, had a more minimal theme. This was done when updating designs of components in Tweak sitenav design #2204, Update Question/Quiz component design #2131.

    Project Management

    As I progressed to start managing the project, I started reviewing and merging PRs. Initially as I reviewed smaller PRs, I had little problem understanding the code and understanding where it can be improved. However, as I reviewed more complex PRs, I began having difficulties understanding the changes quickly. I came across a method to understand code in a more simple manner, the Rubber Duck Debugging method. Using this helped me to try and understand the code line by line and handle more complex changes more managably, helping me to understanding them better.

    Upgrading dependencies

    As I worked on bump nunjucks to 3.2.4 #2411, I was initially not confident what to look out for when upgrading dependencies. However, after I worked on this I understood how to look out for breaking changes and to find out how your project is using it in order to confidently upgrade it without breaking things in the project.

    GitHub Actions

    I gained a more in depth understanding about GitHub Actions when I was working on Add install setuptools to ci #2530. Utilizing conditional runs for the macos platform which required a brew install to get the CI to run properly which would throw errors for other platforms which do not use Homebrew.

    Husky

    As I researched on improving code cleanliness in my projects and found that Husky was a tool that could be used to not only maintain the code cleanliness of projects but could be used for things like running tests as well. Husky has become a mainstay in all my JS projects together with ESLint, Prettier and lint-staged. I spent some time understanding how Husky has changed the way it should be used by deprecating the use of Husky within the package.json and rather is now in the .husky folder.

    AWS SageMaker

    As I researched on AWS SageMaker for my lightning talk and used it during my internship, I got to understand more about AWS SageMaker and its benefits for hosting AI models in the cloud. AWS SageMaker is beneficial smaller players, or applications which have a pattern of use that comes in sporadic bursts as it reduces the upfront cost of expensive AI infrastructure. SageMaker also offers many services that helpes to simplify the development and deployment of AI models.

    Micro-frontends

    As I worked on researching on micro-frontends for my internship, I gained a deeper understanding of micro-frontends. Micro-frontends are what micro-services for backends, but for the front-end. Micro-frontends allows the splitting up of the front-end and this brings many benefits. From allowing teams to manage their own vertical stack, by owning their own micro-frontend, to reducing the bundle size, micro-frontends are beneficial to large teams. I also worked on a POC of migrating parts of the application using WebPack 5 Module Federation for Next.js which allowed me to fully appreciate it.

    diff --git a/students/itsyme/knowledge.page-vue-render.js b/students/itsyme/knowledge.page-vue-render.js index c0fcf9411..7df153d8a 100644 --- a/students/itsyme/knowledge.page-vue-render.js +++ b/students/itsyme/knowledge.page-vue-render.js @@ -8,6 +8,6 @@ with(this){return _c('div',{attrs:{"id":"app"}},[_c('header',{attrs:{"fixed":""} with(this){return _c('div',{staticClass:"fixed-header-padding",attrs:{"id":"content-wrapper"}},[_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("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("