qt9FQKbO^HmV;bfH*{5IPSRmIN<0E)bu|Xys-mID#>RS!{Zsxf
zYb3};GIY_&20-EDtPlotc)AL?)2~bpp*{&}1@=1BTIM{ZJf44r-HY55mJUr7nZQEEPL6rxH5Xhk#uGajg
zAUuH()Dc^^%>wr1Qj_u*HAa*buf>nf7)_p!m^zMpc%qg%Uc1*OR<5UK478m|MD6Vf
ztC^Ip>@LsbtF~OAAO4%n*B<|t?qzxruw!<@R9bqge0*x!QBg5`iws|$Ft>hULEaL6
z&nE-)y4qN!Ij`$+wWihI4#?s4)15Dsmw6R=zhZI#u2>e)D!qdd%nD7{k3VMzM8XX3
z!Y~EzJtOXsCg%?WqkJrqaB!K1_8UKHjI7wmXSoUX{*j=@X34>9c~o~~sGTtFB^MC%
zA^Z2sf@7p4yq&n&!E$~`yzp(qiKIN1rUW0hxJg~RI1aA9Jh1(cOI^{OE~N~ivpOl;
zB46xo*-A)~^1ZXJK-rAGET}U$_ZjXRwW!h5XL%%Dz^DsLyEI{pXv_53*eCDLGO}iN
zL#@uE@5~*IoqIr{#j&hMe=oyt0v8zP_zzBwzPfdFVwBBOGdem-MzkLxm=d37G;`jy
zAV*e_T{^i9d*q9oT`z0RW;L`73K-To%2}SXNQHtTGDv|X~1--5jtBL
zhyh1=`&~5R<^HCmnUm`2PJL#$Vo2-O9(G<{Z{Cb0CywDs?6L35SL%b#K!Lu~&?Zli
zg>z2e2X%p`)$^9MN9uMKZBa59DBjg?`muEZA!ZP%jOj?!`cxnBMxGns>-eB=vecX
z`57W{VZl_+_jF+K8?l-BK+p}<(T{j8&Zdjeeusg7)C);1wkWD;Bq@YT>R6h5Qrj
z$@b8Pi0dbA#YRyo`7B4euz)*p4?(1Gac5_(Nl4hZJzd~-CCe@ahj2+0Q(_fl*4-?z
zAX8fB0TW7ov$?(=fgR_T@DZ@9dw(tEpjBq@4BBFTBfFY3>dtN9-(#nixF-Aj
z6b>$q2e2&eZ7*(OACBejF1NE(J1p`8TXqVHY|Hm7+`mCam$XopU;~ir)O+1QV;#*e
zTa}O&+8hhBJk~ywd=?SW-$5tNVj%r2W-q*E`V+O}WIU?8A@uA(Bif!^*=PX|q+WNW
zFnYf$uz-yr1wNaos?`YAq9G{L24$Tz(La60Zyh2)&awfTdq4D3Z|}0}#_{oUDxYo_
z*mZsErjDULCG9yx)*&S=-5~GpAymdT`%@4{-ZoB8`CvgrZ^H~QZew1svF$A`>m_Yf
zb?gKTb}0PWO`PL=U3FnH@O6I8Obt=15(H6d0XbtDbb9!}q$4{|Omi@OHuF1|&{aYm
z>9|XyoBx}c>8mB%%qlZ?TLUn-CzT}XI5b|46+<>DIjlAQ7L5#VGyfEAFLIMsNVjlu
zK@w(-TmCu}0<_%j=S9P2!A@IhL#aaRE>k&M!0fy|glt)nk(KmbR1Ysd2h~JOhiLcy
z;@fCeQ?#y+we5B>k0Wg&P{;r;H*}aki_;?jpDNxHS?V0L6CZgIA6q584Qma8`s&j)$hB
z>*{K9b|vOw$J1G~Y6TEb1&}Y9{WvmXa&)##92~uBBus&{;#7UgKfJ$JUOZmv#LdhD
z1ta+CYRBnH_dZsYG#-D42l8kK1mf$svMY&t2a9^-%9jvm&7)%?hFzSLCmp_2$o-{O
zJl2y<$T?I)yRmaP6v=hGF^*6jaNd&ZxF!Yyk#m?$`n>6dbX_T&icmQ=+awVUvl!9>
zON0X)hM1#lA07K*&4vY9A<FKfF59{o2({vRl&YLjplV`njltI6!N;}MOzI;ygB
zdVrR7E_iKVv1yVweATZ;uiKvh_heQPgddhbonTB
zC4oYQNFmc%cvmekD;T@DQ<1@={e%lT*gMert-=~s9o2K{zlo!N5EJ+CL|ri|MKDBE
z=G9wdUU<}fM*b;X;tAngpGwsm?4qXv(SB2EL_uG41^6qAs
zp~tq5fk8=m#`ho*CZ?!}81cRbBMudIgMdZsBERMEoj~htB4Kc{7{@VUs2nQLPbpWG
z5T6j_6;$voV)#T6%%HZ`}L5LP(CJ
zR-;L}im3p4gw7j3kK!vr717?21@;fNJxhIf4EApqIRNC4C
zjZU}E4n0dw<%#g2aoIxDyQin+ZB>)M(Tc;6N6Pl^%7O?b|)XMN(!Z*IYjJpH~zb
zi3MF663MCH{#5_NKE2AFx)XMQY;&qLy(%5%WTSr&<+z#1Bkg-2QC-ZaT@DY~joX~(
z6;Ef#RLM843Cdc+5`-TiZ&o0|M90&75{j564dL@XkN#FyQB@Cey{B>dRDLI4#GhzO#+_
zdMCu3;(-ofpJ=Y!RR~-d`XOEyT>bmvPs%{w^xMUc#sZ7+rKArKEldRCpFE1~zl*gC
z!JY<)*i_$)XZklLFaOMIx4hdV^=222C%esh=dI1&>kQD&$R%`?M{G|`!$L!mq4(Z8
zJCEx*KE18kmG>_o@a@ypRffLQQcqc+-+SK{Ds~stRQ>Au%tB-Y+*yg^dP*wTkBhUo
zOda-<@Zr*YV2*RV(J)U#qpyr;ne~XZ=p^RBa)RSk{@v&{1F+BGp9m3~i{7M7lyrf<
z>H-ZD=?HZ2O%>lanU?HtGd`*6gdmGffNW7i`jA;$VhgDwZD)Wm5$ocOal_{6n8nJu
zA6$ir3$^ZVga=DMOWBjp$*?rVl}|$EQs-HOxKG~P$z7<)G#g4bXzN$G`E$fYLF^&wRbQclrI
z&Myqx&hEehXYEr|a#yB0h<|N!*Tb@zQsXvx)rh&E4Z=B}=yfQRjU9kNf}DvHb0UX^
zY|Vi?$)TpcmhyMH=pH6$zjaQGl+KswYa-VU9j~DBsP7GZ79LoeBnVXqrvR*^Rnp23r&RQ(dY(xNVe%U~qJdMs`Smck*SGWwmU}
zjZ(+9l24XRzdb!2iR&bZQKYGVZwO&C>0*r22x7Imz;BG3P8e?6FVSQ<&uE!yO!}DD
ze8()9D5Eu@AjT>CDm+CHYJTxOhfb~v63?rX@TKWpR!FX34DG+4(M5h9?%bj4Ep&o~
zpR{D}5l4Cwa0>1HV89{wEwBVn*Xoyd4-M1lsq||G?2Ul&1ecZeg6ssS#_NGboTptg
z8e~xV{O5w%ezJeSJH3Y{4BfW1>g6
zLdOlSRhqM64-R8LD?`v$s^GNChVg7ecF9pi8ozhU7s+=psHw>Y2#r#oRB-a#@(aC_YH>ZdE`Eivpo9I~5G9thS&kED=Edg$6<=3Q3
z1{>*kPkO2O3RS=TO3Ql3yba1{Sw!ySG|WTEp>ONOCmhd};3e^$GHOWMucCc`zY7q0
z)@id463EX36P6Q%pGKQ3-P#2RyDxPNWfCy5hUS(JWrM^ou!YjKRSPnyKSm9^;zQob
z&brMUH~jdq(mMA_LZWzNmiBEQ6drn@f{jR(^
z4P=tVJmO9G)T^MEyJdeGY}5NRC4lRR-8*w6nE!MFIvVFf9r?IA)_v)Za+?LJb2)`y
zqWG_7&`eu)ae-}5SGu!*cx!83<*Ziq7ebL%S>$g5f`c^
zkplx62eZCdb8OzsQdh>n1a^!oL&KZ<$IUvM$v#eAc93?O_=*HQUIHOmqGZM5co9!8
zvK9HFPBVtdHKmDqQ0S?o*WcJaR!lp|3%Z%29YmruRD7HDL#)?8;MKh_+XCLUOBgJO
zF*w#+d8_#w_;_WdR50Vo$gQZE;o1UDklOwR0v8?`Hb~KFxS{BkpSNivw3_ZOzPw
zKoOqj%pu_T&)ikXz|`rdh;DzIJx(^On-xy
zQQB+6MMXv11`xe7DfyzHGOApEUHkGL`l21NRifG*rOwLy%2Fsd3
zAE=x&GNxKM`mxagfdtX*lBK*=tkSe*T~deBeQ|L>6sTTMFkZ6hx+eApAi?z2^RkKw
zrsO$6UOjlutt-khUN`=^O+oWPn415}?|-VVP=|L={J%~ZS*(Q^;b8Lkv*xtcng7ds
z$GUVP%codES4zMDsXE``SK%g5`OtpyJ4PN)GCMvq_RKamCwdzgY?L1r^JYD+HCs9w
zmXis2Re)ziC8fGQZ(jj@!FI>x9mhgfRtEHIp7~2eujq&@ER+q90>bVZeP|*#bDEna
z@z?z#BYaEF_m>lVYJatjHga9VmKU$ZS`bcma$drUu%EwD^ZyOmMoF(EpX(E5nkBqd
z|0r5r)%xe@NZ|BON!MUa(!24W_l#bSzxVbG*o-*P!qEJ>YxMH_mklH;D+JrC
zTBSO$uSM98ubI(T#MBLwFFo)l>29tr6|;>}l9IFKGQs^TB^%$F2GG(PidI0*@gjcl
z60&TJn8xS1tVRoPR7^k9x57e46(ey;uqQk%e{t=kV$HDreqI}Czw8GLDd^i`m5ZBe
zb^E*1yEF1RegO^a3Lp^37dxl7VC{8$p3GMdnAg{MNq%_Kd6yREIwj$!Ld6_=P4nz(
zbh3frW*1(+JSoFcW^dDQkDq9skhRM|6WA=hy7Dac1FW*5b?h-|Y~n8qqZOm?6GzhJ
zxRd(K^mKZ=G~>q(iUH+feMI*s1u}R8g{BTU>DCbuTvUdv%o{+@HDMqZxd~{liLldM
z9efyuisd&a6r@`_U)DS)s>h$VP%e}8nSPN{+(U+3qeB%7y}nA(aNaw&j_J}jD~nbJ
zS-Y+=4k!=eg%h7h))@(XJ+~gG~S4l3%;oO&b=ESv79SC@{XJU_lHsK=zq49$=`6TTqwk8OOQIUgCe~f
zo5?d7s%FLV?@34BGE+*WOYXQcAUq1om{+1SIbrS~SW(G(;@sHUI_4EzstN*Kn!1I!
zKLgHIR2uP8AYaWPgu=@-qOX1K`tT2I{LAJEyN9mGuP+xzbGR`JML3X(;b0TiHIi<8Lxd^zHYccDaRf5x1
zs>C=0Jct2d3WH?FBcuItSnvg>>Zgm|s(^}72X1ZlzHt*sd~0BvmtU2aUtVcCbGi!EDx
zI&&;A=wz5>dwWq-DE?^qaJ40h3hoXu*Y!f?fOO-?csv%-L%q+sm;X2`OQPzOhwLN_
z53owuxo`lBv)#rN6dgCGySA`uB>dq!UvSS%wv3o4A!0#C*AshQP~PpMi+8sSdi9Fv
zn-7$cfim&`=<~Y1{650=k;maJdhKHGJI=*MhY|_6y>aQ4xpU-o35}UXDHWw_fdNe=
zj*qbug{|D?k);)_hfx?2dLG(0{45L%0G8?1kzb#n+Y)Rh4O>&A4f^(>K&`m}A-T!V
zx>aM_xScP%^RllIM#V#y-+5^9E0%$A&V{~8`%!!HZX3oNL3I}fJ6y{qE^^fT$O9NW
zFjXMCyr>{FryO-V7V$mHw&%s;
ziGqMo*gIYcNXpJElUq?g*{&EJRf~hIciusO`RVWeJz3j+?&5NGRqS@CC8O!(Q2~%P|^cCu5-F^!flbbx)f3FCN%x7Y{nvRnFc5ubbzC;sHo6HIgqyt
z<0Rg;kkPS0HSXY4U-3u5ebNhJ<-iQYjNkiVEHgdm3`yTC%WXE=s1B2-&n`0>AnW;=
zf~WexnfrH*7&piSpx(yR%g`{NogFL`^3xSL3`5ktZ6oB4@mbh
zDU?^d>j4pu`pK}6oc!#LST?amZ@K$e+;yBWw&UkZt_DbZL%_xQ_9^gZ76TGt3b#}3
ztF)6U3BashkO;*(0OP)IieF&uC(2k_N}uUB&-gBi`cXFIF38(Mv;adVfFHeX$@aqI
z*etc`YFprS+|Kl`X=VSXWZNM^!Yxzodw?kSxtVpht@n6v`bfmez~*?04|a=VhRf=2
z4kXLMbplG3-kI?_F<+W~kl{z493d`GHl+cXxMJVw##IwbEZWjEAn{UPc=F{b?=2
zhOho>&xD8nZZ}a&JjF^((gX%dyDE{P+do}=%Qk}#bbzDb2_ORl^Oi&=Unwp*!IPtXNB-;Pikh;vQq?P~
GkN*WepL25n
literal 0
HcmV?d00001
diff --git a/Week3/homework/part1/index.html b/Week3/homework/part1/index.html
new file mode 100644
index 000000000..f9cc7119e
--- /dev/null
+++ b/Week3/homework/part1/index.html
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ HYF-GITHUB
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Week3/homework/part1/index.js b/Week3/homework/part1/index.js
new file mode 100644
index 000000000..4e4cbc7e9
--- /dev/null
+++ b/Week3/homework/part1/index.js
@@ -0,0 +1,175 @@
+'use strict';
+
+{
+ // root div declaration
+ const root = document.getElementById('root');
+
+ // this function will fetch JSON data using async/await and axios
+ async function fetchJSON(url) {
+
+ try {
+
+ const response = await axios.get(url);
+ // throw the error if exists
+ if (!response.statusText) {
+ throw new Error(`Network error: ${response.status},${response.statusText}`);
+ }
+ const resData = await response.data;
+ // return the fetched data
+ return resData;
+
+ }
+ catch (error) {
+ // catch the error if exists
+ printError(error);
+
+ }
+ }
+
+ // this function create and append elements
+ function createAndAppend(name, parent, options = {}) {
+ const elem = document.createElement(name);
+ parent.appendChild(elem);
+ Object.entries(options).forEach(([key, value]) => {
+ if (key === 'text') {
+ elem.textContent = value;
+ } else {
+ elem.setAttribute(key, value);
+ }
+ });
+ return elem;
+ }
+
+ // this function render the selected Repository details
+ function renderRepoDetails(repo, repoContainer) {
+ // create Repository table
+ const table = createAndAppend('table', repoContainer);
+
+ // create Repository title row
+ const titleTr = createAndAppend('tr', table);
+ createAndAppend('td', titleTr, { text: 'Repository:', class: 'title' });
+ const td = createAndAppend('td', titleTr);
+ createAndAppend('a', td, {
+ href: repo.html_url,
+ text: repo.name,
+ target: '_blank'
+ });
+
+ // create Description row
+ const descriptionTr = createAndAppend('tr', table);
+ createAndAppend('td', descriptionTr, { text: 'Description:', class: 'title' });
+ createAndAppend('td', descriptionTr, { text: repo.description });
+
+ // create Fork row
+ const forksTr = createAndAppend('tr', table);
+ createAndAppend('td', forksTr, { text: 'Forks:', class: 'title' });
+ createAndAppend('td', forksTr, { text: repo.forks });
+
+ // create Updated row
+ const updatedTr = createAndAppend('tr', table);
+ createAndAppend('td', updatedTr, { text: 'Updated:', class: 'title' });
+ createAndAppend('td', updatedTr, { text: repo.updated_at });
+ }
+
+ // this function render the Contributions details
+ async function renderContributorsDetails(repo, contributorsContainer) {
+ // create section title
+ const ul = createAndAppend('ul', contributorsContainer, {
+ text: 'Contributions',
+ class: 'contributors-ul'
+ });
+
+ // fetch contributors data
+ try {
+ const contributors = await fetchJSON(repo.contributors_url);
+ // create contributors list
+ contributors.forEach( Contributor => {
+ const li = createAndAppend('li', ul, { class: 'Contributor-li' });
+ const ContributorDiv = createAndAppend('div', li, { class: 'Contributor-div' });
+
+ // create contributor image
+ createAndAppend('img', ContributorDiv, {
+ class: 'contributors-img',
+ src: Contributor.avatar_url,
+ });
+
+ // create contributor name
+ createAndAppend('a', ContributorDiv, {
+ class: 'contributors-a',
+ text: Contributor.login,
+ href: Contributor.html_url,
+ target: '_blank',
+ });
+
+ // create contributors number
+ createAndAppend('span', ContributorDiv, {
+ class: 'contributors-span',
+ text: Contributor.contributions,
+ });
+ });
+ }
+ catch(err) {
+ // catch the error if exists
+ printError(err);
+ }
+ }
+
+ // this function removes all childs of passed element
+ function removeElems(elem) {
+ while (elem.lastElementChild) {
+ elem.removeChild(elem.lastElementChild);
+ }
+ }
+
+ // this function print the catched error to window
+ function printError(err) {
+ createAndAppend('div', root, {
+ text: err.message,
+ class: 'alert-error',
+ });
+ }
+
+ // this is the main function
+ async function main(url) {
+ // fetch Repositories data
+ try {
+ const repos = await fetchJSON(url);
+ // declare the DOM elements for list and containers
+ const reposList = document.getElementById('repos-List');
+ const repoContainer = document.querySelector('.repo-container');
+ const contributorsContainer = document.querySelector('.contributors-container');
+
+ // sorting the repositories form A to Z
+ repos.sort((currentRepo, nextRepo) => currentRepo.name.localeCompare(nextRepo.name));
+
+ // filling the dropdown list with sorted repositories titles
+ repos.forEach(repo => {
+ createAndAppend('option', reposList, { text: repo.name, value: repo.name });
+ });
+
+ // display information about the first repository
+ renderRepoDetails(repos[0], repoContainer);
+ renderContributorsDetails(repos[0], contributorsContainer);
+
+ // refreshed for the newly selected repository when the user changes the selection
+ reposList.addEventListener('change', () => {
+ // empty the containers from old data when the user changes the selection
+ removeElems(repoContainer);
+ removeElems(contributorsContainer);
+ // find the selected repository and render the details
+ let currentRepo = repos.filter( repo => repo.name == reposList.value );
+ renderRepoDetails(currentRepo[0], repoContainer);
+ renderContributorsDetails(currentRepo[0], contributorsContainer);
+ });
+
+ }
+ catch(err) {
+ // catch the error if exists
+ printError(err);
+ }
+ }
+
+ const HYF_REPOS_URL =
+ 'https://api.github.com/orgs/HackYourFuture/repos?per_page=100';
+ window.onload = () => main(HYF_REPOS_URL);
+}
\ No newline at end of file
diff --git a/Week3/homework/part1/style.css b/Week3/homework/part1/style.css
new file mode 100644
index 000000000..9913dba3f
--- /dev/null
+++ b/Week3/homework/part1/style.css
@@ -0,0 +1,146 @@
+body {
+ margin: 0;
+ padding: 0;
+ font-size: 16px;
+ font-family: Arial, Helvetica, sans-serif;
+ }
+
+ #root {
+ width: 80%;
+ margin: auto;
+ }
+
+ .alert-error {
+ color: #9D1C24;
+ background-color: #F8D7DA;
+ height: 50px;
+ padding: 20px 0 0 10px;
+ margin-top: 5px;
+ }
+
+ .head {
+ background-color: #3F51B5;
+ color: #ffffff;
+ height: 100px;
+ padding: 0px;
+ margin-top: 5px;
+ display: flex;
+ }
+
+ .head > h1 {
+ padding: 0.5rem 0 0 1rem;
+ }
+
+ #repos-List {
+ height: auto;
+ width: 20rem;
+ margin: auto 1rem ;
+ font-size: large;
+ }
+
+ .title {
+ font-weight: bold;
+ padding: 5px 0 5px 5px;
+ }
+
+ .main-container {
+ display: flex;
+ }
+
+ .repo-container, .contributors-container {
+ box-shadow: 2px 2px 15px -2px rgba(133,126,133,1);
+ margin: 7px 0 7px 0;
+ width: 50%;
+ }
+
+ .repo-container {
+ height: 8rem;
+ margin-right: 0.5rem;
+ }
+
+ .contributors-ul {
+ font-weight: bold;
+ padding: 5px 0 5px 5px;
+ list-style: none;
+ }
+
+ .Contributor-li {
+ margin: 1rem 0 1rem 0;
+ border-bottom: 1px solid #dfdcdc;
+ }
+
+ .Contributor-div {
+ height: 4.5rem;
+ }
+
+ .contributors-img {
+ width: 50px;
+ margin-left: 1rem;
+ }
+
+ .contributors-a {
+ margin: auto 1rem;
+ font-weight: normal;
+ position: relative;
+ bottom: 1.5rem;
+ }
+
+ .contributors-span {
+ margin: 1rem 1rem 0 0;
+ float: right;
+ font-weight: normal;
+ font-size: small;
+ text-align: center;
+ width: 2rem;
+ color: #ffffff;
+ background-color: #5f5d5d;
+ border-radius: 0.2rem;
+ }
+
+ /* Change style to be responsive to ---Mobile devices--- */
+
+ @media (max-width: 600px) {
+ #root {
+ width: 100%;
+ font-size: 14px;
+ }
+
+ .head > h1 {
+ font-size: 1rem;
+ padding: 2rem 0 0 1rem;
+ }
+
+ #repos-List {
+ width: 5rem;
+ margin: auto 1rem ;
+ font-size: small;
+ position: relative;
+
+ }
+
+ #repos-List option{
+ width: 5rem;
+
+ }
+
+ .main-container {
+ display: block;
+ }
+ .repo-container, .contributors-container {
+ width: 100%;
+ }
+ }
+
+ /* Change style to be responsive to --Tablets devices--*/
+
+ @media (min-width: 600px) and (max-width: 1024px) {
+ #root {
+ width: 95%;
+ font-size: 14px;
+ }
+
+ .head > h1 {
+ font-size: 1.5rem;
+ padding: 1rem 0 0 1rem;
+ }
+ }
\ No newline at end of file
diff --git a/Week3/homework/part2/App.js b/Week3/homework/part2/App.js
new file mode 100644
index 000000000..316fb93a7
--- /dev/null
+++ b/Week3/homework/part2/App.js
@@ -0,0 +1,56 @@
+use strict';
+
+{
+ const accounts = {
+ hyf: {
+ name: 'HackYourFuture',
+ type: 'org',
+ },
+ microsoft: {
+ name: 'Microsoft',
+ type: 'org',
+ },
+ jim: {
+ name: 'remarcmij',
+ type: 'user',
+ },
+ };
+
+ const { Model, HeaderView, RepoView, ContributorsView, ErrorView } = window;
+ const { createAndAppend } = window.Util;
+
+ class App {
+ constructor(account) {
+ const containers = App.renderContainers();
+
+ const model = new Model(account);
+ const fetchData = model.fetchData.bind(model);
+
+ model.subscribe(new HeaderView(account, containers.header, fetchData));
+ model.subscribe(new RepoView(containers.repo));
+ model.subscribe(new ContributorsView(containers.contributors));
+ model.subscribe(new ErrorView(containers.error));
+
+ fetchData();
+ }
+
+ static renderContainers() {
+ const root = document.getElementById('root');
+ const header = createAndAppend('header', root, { class: 'header' });
+ const error = createAndAppend('div', root);
+ const main = createAndAppend('main', root, {
+ class: 'main-container',
+ });
+ const repo = createAndAppend('section', main, {
+ class: 'repo-container whiteframe',
+ });
+ const contributors = createAndAppend('section', main, {
+ class: 'contributors-container whiteframe',
+ });
+ return { header, error, main, repo, contributors };
+ }
+ }
+
+ const ACCOUNT_KEY = 'hyf';
+ window.onload = () => new App(accounts[ACCOUNT_KEY]);
+}
\ No newline at end of file
diff --git a/Week3/homework/part2/ContributorsView.js b/Week3/homework/part2/ContributorsView.js
new file mode 100644
index 000000000..9161a3ddb
--- /dev/null
+++ b/Week3/homework/part2/ContributorsView.js
@@ -0,0 +1,62 @@
+'use strict';
+
+{
+ const { createAndAppend } = window.Util;
+
+ class ContributorsView {
+ constructor(container) {
+ this.container = container;
+ }
+
+ update(state) {
+ if (!state.error) {
+ this.render(state.contributors);
+ }
+ }
+
+ /**
+ * Renders the list of contributors
+ * @param {Object[]} contributors An array of contributor objects
+ */
+ render(contributors) {
+ // TODO: replace this comment and the console.log with your own code
+
+ // empty the conatainer from its old data
+ this.container.textContent = '';
+
+ // create section title
+ const ul = createAndAppend('ul', this.container, {
+ text: 'Contributions',
+ class: 'contributors-ul'
+ });
+
+ // create the contributors list
+ contributors.forEach( Contributor => {
+ const li = createAndAppend('li', ul, { class: 'Contributor-li' });
+ const ContributorDiv = createAndAppend('div', li, { class: 'Contributor-div' });
+
+ // create contributor image
+ createAndAppend('img', ContributorDiv, {
+ class: 'contributors-img',
+ src: Contributor.avatar_url,
+ });
+
+ // create contributor name
+ createAndAppend('a', ContributorDiv, {
+ class: 'contributors-a',
+ text: Contributor.login,
+ href: Contributor.html_url,
+ target: '_blank',
+ });
+
+ // create contributors number
+ createAndAppend('span', ContributorDiv, {
+ class: 'contributors-span',
+ text: Contributor.contributions,
+ });
+ });
+ }
+ }
+
+ window.ContributorsView = ContributorsView;
+}
\ No newline at end of file
diff --git a/Week3/homework/part2/ErrorView.js b/Week3/homework/part2/ErrorView.js
new file mode 100644
index 000000000..d71aec290
--- /dev/null
+++ b/Week3/homework/part2/ErrorView.js
@@ -0,0 +1,31 @@
+use strict';
+
+{
+ const { createAndAppend } = window.Util;
+
+ class ErrorView {
+ constructor(container) {
+ this.container = container;
+ }
+
+ update(state) {
+ this.render(state.error);
+ }
+
+ /**
+ * Renders an error for the 'error' message type.
+ * @param {Error} error An Error object
+ */
+ render(error) {
+ this.container.innerHTML = '';
+ if (error) {
+ createAndAppend('div', this.container, {
+ text: error.message,
+ class: 'alert alert-error',
+ });
+ }
+ }
+ }
+
+ window.ErrorView = ErrorView;
+}
\ No newline at end of file
diff --git a/Week3/homework/part2/HeaderView.js b/Week3/homework/part2/HeaderView.js
new file mode 100644
index 000000000..f49c3e77e
--- /dev/null
+++ b/Week3/homework/part2/HeaderView.js
@@ -0,0 +1,46 @@
+'use strict';
+
+{
+ const { createAndAppend } = window.Util;
+
+ class HeaderView {
+ constructor(account, header, fetchData) {
+ this.account = account;
+ this.header = header;
+ this.fetchData = fetchData;
+ this.select = null;
+ }
+
+ update(state) {
+ if (!this.select && !state.error) {
+ this.render(state.repos);
+ }
+ }
+
+ /**
+ * Renders the data for the 'select' message type. Create a