From 17e360dd9bb1458cffbe670bca76fbfc3bd66d24 Mon Sep 17 00:00:00 2001
From: jyu65 <jyu65@illinois.edu>
Date: Mon, 29 Oct 2018 10:57:15 -0500
Subject: [PATCH] assignment3.1

---
 .DS_Store                                     | Bin 6148 -> 8196 bytes
 README.md                                     |   2 +-
 mp3/.DS_Store                                 | Bin 0 -> 6148 bytes
 mp3/__tests__/Screen-test.js                  |  87 ++
 mp3/__tests__/__snapshots__/App-test.js.snap  | 796 ++++++++++++++++++
 .../__snapshots__/Screen-test.js.snap         | 265 ++++++
 .../__snapshots__/StyledText-test.js.snap     |  19 +
 mp3/navigation/MainTabNavigator.js            |   2 +-
 mp3/package-lock.json                         | 725 +++++++++++++++-
 mp3/package.json                              |   5 +-
 mp3/screens/FollowerScreen.js                 | 175 +++-
 mp3/screens/FollowingScreen.js                | 240 +++++-
 mp3/screens/Profile/Detail.js                 |  37 +-
 mp3/screens/Profile/Header.js                 |   2 +-
 mp3/screens/Profile/Intro.js                  |  20 +-
 mp3/screens/Profile/ProfileScreen.js          | 296 ++++++-
 mp3/screens/RepoScreen.js                     |  93 +-
 17 files changed, 2644 insertions(+), 120 deletions(-)
 create mode 100644 mp3/.DS_Store
 create mode 100644 mp3/__tests__/Screen-test.js
 create mode 100644 mp3/__tests__/__snapshots__/App-test.js.snap
 create mode 100644 mp3/__tests__/__snapshots__/Screen-test.js.snap
 create mode 100644 mp3/components/__tests__/__snapshots__/StyledText-test.js.snap

diff --git a/.DS_Store b/.DS_Store
index 2dc296fcb6e4b3372bd4752c1674abacd624a1ed..91a9ae24f3e68eeda67e6662e655a0ef7af967b3 100644
GIT binary patch
literal 8196
zcmeHLU2GLa6h5adFuVM8S_*V8La(h=graS!Z4|1vKWH0D+R#FOrR=@C!ph#=>)pM*
zK&e)JG0Kw(AUyf^AmL5ogNZN3MBzbAunE<~2OoUU7axsA6VJ?S3l#dQ26mF2Z|2N7
zGxvP+-QCOp0CpCvCV*-HVDt#&tEsw65#!>yqm)FJ6@*Cf5aiOXpQhfmbnXuC*bp-i
zGY~TnGY~TnGw^?4fWFzHuw}mcYBa8624V*8O9sUIAxV$GRD`n%<*S1#c?2LVBeN{j
z=AuEEj4&19tU?;0f-00yg<^EXKow5*WaO8Ma8{uT2aFCM7_E%a2?gcqG=EaM1Ev(l
zb<9A_z?}?;vwJCIAqTtC#aqwst`mffjW@8Qv~0!7RZP>EwpM$7@R(m549&0*bej2b
z(Hk(sW9g_p<ooVo+e{yF?BXP^>hitNbUZsRgB{Bzmx*D=v;1PGU+}Cz&NHY6<U*6Y
zdV0FGsktH9($q53keqI7YozwB)|nZNZK`i-?>&+|d20If%*z*4Mi{*npnOS&7jLF#
z1sOL@KTvo?8N0z$m%6bic{`m`8P6|ftgkkDdi8xHPR92Jom2KCFApf;Ug{3y?I}ub
zIODs8tQSo3ij3)I3a%O29j+^!gOSia5sKDW;OE0G={U)GA+QhF<mXJ;-Q-Q7m13s;
zT<G{-aLCRFgmtM#m4|kD&4w+t5ASGv;;E;*=GLw&=X#}HH9X}6PTI8(79A@*HfjbL
z+p`?+=onGxh0Y6(o!2U`K^yYStUb4JQ#Cgd#skYmF<!?;3Tfx1f)k!pYt$GIYWx#6
zVbL$#?^|L<OO6;dMm=NW!rqm)skY|$y7IM;Y%}zsfO6#~)1;+gr>+kjr#<F@rYud(
zx^d7o)3(bkjY+50Hr*JWQYrI&k#TpWZj5C7Y?e|9$R?6DQbs4^SJ`2)aGx23{W;qc
zYj3LF*j-~7qr%={S+>O(t4nQD<jM3kF1{=V)ItmFfdLo=3yN?C&cZo(A1=cc_!Pc?
zZ{S<F4&T8%`~<(iZ}12F34g)gxDv~eV<oP~BtDAUaR;_x3isl3*n_=z0EclD$8a1i
zd=XvDqK8F%1z*M2@O3<cXYm}K$9M5P`~W}1EBG0HiC^JWyoT5D2F|NrS+XGAKGk2S
z@ds+%)M<3HRx)}wohJ4^t9SgTI{ki)*r$rh^;H|T)@|F_+_opRxQR=4?N;?j(I{0&
zwJfMXZr$zjBN-cs&H9$*WPFgsW}jd}_k7iyLCUB}CK6o8hRN<j_0%mPSu^pMF!b#S
z@-!JQmEFYSdJ`jM@)c^dMQ_zeySz+|KB@0!BvHOnPSw6y*Ex`|#WEfB37sR;mI`lK
z*<FH<;dA(!1UC;q!q4z4{EmPO*I_ko#Tu-|I;_XXuo0Va7q(zKK7$?DiCx%-`>`Jf
zNO<EofroJtO%mR5DZCt>#8Y@0XGnl=;G6iC6ySM$2QT1765vNm<kqtwG=+HSrrf3m
z^PcN_N6E4v&fA^i-aWxUsmh{Sod5SOfB%0^<QgXtGY~UycLuPmd$7Bc#+G~Ai?eo;
zo+I>#BK&3*$`Gn<y9l6ubR3tyNpcl2sR(Bk%22Y)P{M!dA|U?$3;H4c{!1F}+v*?H
C_Sq5u

delta 145
zcmZp1XfcprU|?W$DortDU=RQ@Ie-{MGpJ516gFlAGME{1844JTQ;L&wlJfI&KyqNf
z1f@Z0fLMS5BEPY48vDcs;l=D69D>XcB?8<)+7*aZHx_<pp3E<!$jCU^R7RTzXavYU
NkP{d-$Mei#1^@wM6_o%0

diff --git a/README.md b/README.md
index 0a635c5..7b2b2e7 100644
--- a/README.md
+++ b/README.md
@@ -2,4 +2,4 @@
 1. Source code in `./screens`.
 2. Navigators in `./navigation`.
 3. Citations: Expo initiate doc.
-
+4. Username and Password for my github is required;
diff --git a/mp3/.DS_Store b/mp3/.DS_Store
new file mode 100644
index 0000000000000000000000000000000000000000..88bed5d2a6d5d839c7961075035f66a5e2242460
GIT binary patch
literal 6148
zcmeHKyH3ME5S)b+k)TLPdB4CPoTBgrd;kcXF5n_c?~3orr!o5w!g7#kXwa;*J9q1y
zJ9!GP7l3U~!#%J8u%<iW!^6`2x%<MdDq}=C&v?QcMhrONu&BPAaPBSMgSDUW_c#v6
z*Tc&={`RcPHz+Fwq<|EV0#ZN<d{@AGFKvC3s3--bfE4&rz`qZT?$`^b#Q1bD#0WrK
zF&)Nr%o4=r31Tmt5}Bb{Qi(~m8Zj*C%(trRg;QeEVKsbM-E1|XSlrI@Ta?3kqM{U#
z0&@kfbGz~W|3Lp?{-2YylLAuUUnyX#-Q#Y{SE}B+cscL2js8scnls&v>!2`1J0?au
h=EmFcT@+<q^EIFM!YMK6%m<yQp8?lJCI$XlflrXF7HR+h

literal 0
HcmV?d00001

diff --git a/mp3/__tests__/Screen-test.js b/mp3/__tests__/Screen-test.js
new file mode 100644
index 0000000..4241984
--- /dev/null
+++ b/mp3/__tests__/Screen-test.js
@@ -0,0 +1,87 @@
+import 'react-native';
+import React from 'react';
+import renderer from 'react-test-renderer';
+import NavigationTestUtils from 'react-navigation/NavigationTestUtils';
+import { AsyncStorage } from 'react-native';
+import ProfileScreen from '../screens/Profile/ProfileScreen';
+import RepoScreen from '../screens/RepoScreen';
+import FollowerScreen from '../screens/FollowerScreen';
+import FollowingScreen from '../screens/FollowingScreen';
+
+// Test case will run a new empty AsyncStorage, thus can prove that
+// every first time, the app communicates with API.
+test('My profile storage is working', async () => {
+  const data = await AsyncStorage.getItem('cs242HW');
+  expect(data).toBe(null);
+});
+
+test('My repo storage is working', async () => {
+  const data = await AsyncStorage.getItem('cs242HWRepos');
+  expect(data).toBe(null);
+});
+
+test('My follower storage is working', async () => {
+  const data = await AsyncStorage.getItem('cs242HWFollowers');
+  expect(data).toBe(null);
+});
+
+test('My following storage is working', async () => {
+  const data = await AsyncStorage.getItem('cs242HWFollowing');
+  expect(data).toBe(null);
+});
+
+test('Profile renders correctly', () => {
+  const tree = renderer.create(<ProfileScreen />).toJSON();
+  expect(tree).toMatchSnapshot();
+});
+
+test('Get number of repo correctly', async () => {
+    let profile = renderer.create(<ProfileScreen />).getInstance();
+    profile._retrieveData('cs242HW');
+    expect(profile.state.data.repo).not.toBe(null);
+});
+
+test('Get number of followers correctly', async () => {
+    let profile = renderer.create(<ProfileScreen />).getInstance();
+    profile._retrieveData('cs242HW');
+    expect(profile.state.data.followers).not.toBe(null);
+});
+
+test('Get number of following correctly', async () => {
+    let profile = renderer.create(<ProfileScreen />).getInstance();
+    profile._retrieveData('cs242HW');
+    expect(profile.state.data.following).not.toBe(null);
+});
+
+test('Profile refresh works correctly', async () => {
+    let profile = renderer.create(<ProfileScreen />).getInstance();
+    profile._handleRefresh();
+    expect(profile.state.data).not.toBe(null);
+});
+
+test('Repo renders correctly', () => {
+  const tree = renderer.create(<RepoScreen />).toJSON();
+  expect(tree).toMatchSnapshot();
+});
+
+test('Follower renders correctly', () => {
+  const tree = renderer.create(<FollowerScreen />).toJSON();
+  expect(tree).toMatchSnapshot();
+});
+
+test('Followers refresh works correctly', async () => {
+    let followers = renderer.create(<FollowerScreen />).getInstance();
+    followers._handlePress();
+    expect(followers.state.data).not.toBe(null);
+});
+
+test('Following renders correctly', () => {
+  const tree = renderer.create(<FollowingScreen />).toJSON();
+  expect(tree).toMatchSnapshot();
+});
+
+test('Following refresh works correctly', async () => {
+    let following = renderer.create(<FollowingScreen />).getInstance();
+    following._handlePress();
+    expect(following.state.data).not.toBe(null);
+});
diff --git a/mp3/__tests__/__snapshots__/App-test.js.snap b/mp3/__tests__/__snapshots__/App-test.js.snap
new file mode 100644
index 0000000..30f89a2
--- /dev/null
+++ b/mp3/__tests__/__snapshots__/App-test.js.snap
@@ -0,0 +1,796 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`App snapshot renders the loading screen 1`] = `null`;
+
+exports[`App snapshot renders the root without loading screen 1`] = `
+<View
+  style={
+    Object {
+      "backgroundColor": "#fff",
+      "flex": 1,
+    }
+  }
+>
+  <View
+    style={
+      Object {
+        "flex": 1,
+        "overflow": "hidden",
+      }
+    }
+  >
+    <View
+      style={
+        Object {
+          "flex": 1,
+        }
+      }
+    >
+      <View
+        collapsable={false}
+        pointerEvents="auto"
+        removeClippedSubviews={false}
+        style={
+          Array [
+            Object {
+              "flex": 1,
+              "overflow": "hidden",
+            },
+            Array [
+              Object {
+                "bottom": 0,
+                "left": 0,
+                "position": "absolute",
+                "right": 0,
+                "top": 0,
+              },
+              Object {
+                "opacity": 1,
+              },
+            ],
+          ]
+        }
+      >
+        <View
+          style={
+            Object {
+              "flex": 1,
+            }
+          }
+        >
+          <View
+            onLayout={[Function]}
+            style={
+              Object {
+                "flex": 1,
+              }
+            }
+          >
+            <View
+              onMoveShouldSetResponder={[Function]}
+              onMoveShouldSetResponderCapture={[Function]}
+              onResponderEnd={[Function]}
+              onResponderGrant={[Function]}
+              onResponderMove={[Function]}
+              onResponderReject={[Function]}
+              onResponderRelease={[Function]}
+              onResponderStart={[Function]}
+              onResponderTerminate={[Function]}
+              onResponderTerminationRequest={[Function]}
+              onStartShouldSetResponder={[Function]}
+              onStartShouldSetResponderCapture={[Function]}
+              style={
+                Array [
+                  Object {
+                    "flex": 1,
+                    "flexDirection": "column-reverse",
+                    "overflow": "hidden",
+                  },
+                  Object {
+                    "backgroundColor": "#000",
+                  },
+                ]
+              }
+            >
+              <View
+                style={
+                  Object {
+                    "flex": 1,
+                  }
+                }
+              >
+                <View
+                  accessibilityElementsHidden={false}
+                  pointerEvents="auto"
+                  style={
+                    Object {
+                      "backgroundColor": "#E9E9EF",
+                      "bottom": 0,
+                      "left": 0,
+                      "opacity": 1,
+                      "paddingTop": 64,
+                      "position": "absolute",
+                      "right": 0,
+                      "shadowColor": "black",
+                      "shadowOffset": Object {
+                        "height": 0,
+                        "width": 0,
+                      },
+                      "shadowOpacity": 0.2,
+                      "shadowRadius": 5,
+                      "top": 0,
+                      "transform": Array [
+                        Object {
+                          "translateX": 0,
+                        },
+                        Object {
+                          "translateY": 0,
+                        },
+                      ],
+                    }
+                  }
+                />
+              </View>
+              <View
+                onLayout={[Function]}
+                pointerEvents="box-none"
+                style={
+                  Object {
+                    "left": 0,
+                    "position": "absolute",
+                    "right": 0,
+                    "top": 0,
+                  }
+                }
+              >
+                <View
+                  style={
+                    Object {
+                      "backgroundColor": "#FFF",
+                      "transform": Array [
+                        Object {
+                          "translateX": 0,
+                        },
+                      ],
+                    }
+                  }
+                >
+                  <View
+                    onLayout={[Function]}
+                    pointerEvents="box-none"
+                    style={
+                      Object {
+                        "backgroundColor": "#FFF",
+                        "borderBottomColor": "#A7A7AA",
+                        "borderBottomWidth": 0.5,
+                        "height": 64,
+                        "paddingBottom": 0,
+                        "paddingLeft": 0,
+                        "paddingRight": 0,
+                        "paddingTop": 20,
+                      }
+                    }
+                  >
+                    <View
+                      style={
+                        Object {
+                          "flex": 1,
+                        }
+                      }
+                    >
+                      <View
+                        style={
+                          Object {
+                            "bottom": 0,
+                            "flexDirection": "row",
+                            "left": 0,
+                            "position": "absolute",
+                            "right": 0,
+                            "top": 0,
+                          }
+                        }
+                      >
+                        <View
+                          pointerEvents="box-none"
+                          style={
+                            Object {
+                              "alignItems": "center",
+                              "backgroundColor": "transparent",
+                              "bottom": 0,
+                              "flexDirection": "row",
+                              "justifyContent": "center",
+                              "left": 0,
+                              "opacity": 1,
+                              "position": "absolute",
+                              "right": 0,
+                              "top": 0,
+                            }
+                          }
+                        >
+                          <Text
+                            accessibilityTraits="header"
+                            accessible={false}
+                            allowFontScaling={true}
+                            ellipsizeMode="tail"
+                            numberOfLines={1}
+                            onLayout={[Function]}
+                            style={
+                              Object {
+                                "color": "rgba(0, 0, 0, .9)",
+                                "fontSize": 17,
+                                "fontWeight": "600",
+                                "marginHorizontal": 16,
+                                "textAlign": "center",
+                              }
+                            }
+                          >
+                            Profile
+                          </Text>
+                        </View>
+                      </View>
+                    </View>
+                  </View>
+                </View>
+              </View>
+            </View>
+          </View>
+        </View>
+      </View>
+    </View>
+    <View
+      onLayout={[Function]}
+      pointerEvents="box-none"
+      style={
+        Object {
+          "backgroundColor": "#fff",
+          "borderTopColor": "rgba(0, 0, 0, .3)",
+          "borderTopWidth": 0.5,
+          "flexDirection": "row",
+          "height": 49,
+          "paddingBottom": 0,
+          "paddingLeft": 0,
+          "paddingRight": 0,
+          "paddingTop": 0,
+        }
+      }
+    >
+      <View
+        accessibilityLabel="Profile"
+        accessible={true}
+        onResponderGrant={[Function]}
+        onResponderMove={[Function]}
+        onResponderRelease={[Function]}
+        onResponderTerminate={[Function]}
+        onResponderTerminationRequest={[Function]}
+        onStartShouldSetResponder={[Function]}
+        style={
+          Array [
+            Object {
+              "alignItems": "center",
+              "flex": 1,
+            },
+            Object {
+              "backgroundColor": "transparent",
+            },
+            Object {
+              "flexDirection": "column",
+              "justifyContent": "flex-end",
+            },
+            undefined,
+          ]
+        }
+      >
+        <View
+          style={
+            Array [
+              Object {
+                "height": 29,
+              },
+              false,
+              Object {
+                "flex": 1,
+              },
+            ]
+          }
+        >
+          <View
+            style={
+              Object {
+                "alignItems": "center",
+                "alignSelf": "center",
+                "height": "100%",
+                "justifyContent": "center",
+                "minWidth": 25,
+                "opacity": 1,
+                "position": "absolute",
+                "width": "100%",
+              }
+            }
+          >
+            <Text
+              accessible={true}
+              allowFontScaling={false}
+              ellipsizeMode="tail"
+              style={
+                Array [
+                  Object {
+                    "color": "#2f95dc",
+                    "fontSize": 26,
+                  },
+                  Object {
+                    "marginBottom": -3,
+                  },
+                  Object {
+                    "fontFamily": "ionicons",
+                    "fontStyle": "normal",
+                    "fontWeight": "normal",
+                  },
+                ]
+              }
+            >
+              
+            </Text>
+          </View>
+          <View
+            style={
+              Object {
+                "alignItems": "center",
+                "alignSelf": "center",
+                "height": "100%",
+                "justifyContent": "center",
+                "minWidth": 25,
+                "opacity": 0,
+                "position": "absolute",
+                "width": "100%",
+              }
+            }
+          >
+            <Text
+              accessible={true}
+              allowFontScaling={false}
+              ellipsizeMode="tail"
+              style={
+                Array [
+                  Object {
+                    "color": "#ccc",
+                    "fontSize": 26,
+                  },
+                  Object {
+                    "marginBottom": -3,
+                  },
+                  Object {
+                    "fontFamily": "ionicons",
+                    "fontStyle": "normal",
+                    "fontWeight": "normal",
+                  },
+                ]
+              }
+            >
+              
+            </Text>
+          </View>
+        </View>
+        <Text
+          accessible={true}
+          allowFontScaling={true}
+          ellipsizeMode="tail"
+          numberOfLines={1}
+          style={
+            Object {
+              "backgroundColor": "transparent",
+              "color": "#3478f6",
+              "fontSize": 11,
+              "marginBottom": 1.5,
+              "textAlign": "center",
+            }
+          }
+        >
+          Profile
+        </Text>
+      </View>
+      <View
+        accessibilityLabel="Repo"
+        accessible={true}
+        onResponderGrant={[Function]}
+        onResponderMove={[Function]}
+        onResponderRelease={[Function]}
+        onResponderTerminate={[Function]}
+        onResponderTerminationRequest={[Function]}
+        onStartShouldSetResponder={[Function]}
+        style={
+          Array [
+            Object {
+              "alignItems": "center",
+              "flex": 1,
+            },
+            Object {
+              "backgroundColor": "transparent",
+            },
+            Object {
+              "flexDirection": "column",
+              "justifyContent": "flex-end",
+            },
+            undefined,
+          ]
+        }
+      >
+        <View
+          style={
+            Array [
+              Object {
+                "height": 29,
+              },
+              false,
+              Object {
+                "flex": 1,
+              },
+            ]
+          }
+        >
+          <View
+            style={
+              Object {
+                "alignItems": "center",
+                "alignSelf": "center",
+                "height": "100%",
+                "justifyContent": "center",
+                "minWidth": 25,
+                "opacity": 0,
+                "position": "absolute",
+                "width": "100%",
+              }
+            }
+          >
+            <Text
+              accessible={true}
+              allowFontScaling={false}
+              ellipsizeMode="tail"
+              style={
+                Array [
+                  Object {
+                    "color": "#2f95dc",
+                    "fontSize": 26,
+                  },
+                  Object {
+                    "marginBottom": -3,
+                  },
+                  Object {
+                    "fontFamily": "ionicons",
+                    "fontStyle": "normal",
+                    "fontWeight": "normal",
+                  },
+                ]
+              }
+            >
+              
+            </Text>
+          </View>
+          <View
+            style={
+              Object {
+                "alignItems": "center",
+                "alignSelf": "center",
+                "height": "100%",
+                "justifyContent": "center",
+                "minWidth": 25,
+                "opacity": 1,
+                "position": "absolute",
+                "width": "100%",
+              }
+            }
+          >
+            <Text
+              accessible={true}
+              allowFontScaling={false}
+              ellipsizeMode="tail"
+              style={
+                Array [
+                  Object {
+                    "color": "#ccc",
+                    "fontSize": 26,
+                  },
+                  Object {
+                    "marginBottom": -3,
+                  },
+                  Object {
+                    "fontFamily": "ionicons",
+                    "fontStyle": "normal",
+                    "fontWeight": "normal",
+                  },
+                ]
+              }
+            >
+              
+            </Text>
+          </View>
+        </View>
+        <Text
+          accessible={true}
+          allowFontScaling={true}
+          ellipsizeMode="tail"
+          numberOfLines={1}
+          style={
+            Object {
+              "backgroundColor": "transparent",
+              "color": "#929292",
+              "fontSize": 11,
+              "marginBottom": 1.5,
+              "textAlign": "center",
+            }
+          }
+        >
+          Repo
+        </Text>
+      </View>
+      <View
+        accessibilityLabel="Follower"
+        accessible={true}
+        onResponderGrant={[Function]}
+        onResponderMove={[Function]}
+        onResponderRelease={[Function]}
+        onResponderTerminate={[Function]}
+        onResponderTerminationRequest={[Function]}
+        onStartShouldSetResponder={[Function]}
+        style={
+          Array [
+            Object {
+              "alignItems": "center",
+              "flex": 1,
+            },
+            Object {
+              "backgroundColor": "transparent",
+            },
+            Object {
+              "flexDirection": "column",
+              "justifyContent": "flex-end",
+            },
+            undefined,
+          ]
+        }
+      >
+        <View
+          style={
+            Array [
+              Object {
+                "height": 29,
+              },
+              false,
+              Object {
+                "flex": 1,
+              },
+            ]
+          }
+        >
+          <View
+            style={
+              Object {
+                "alignItems": "center",
+                "alignSelf": "center",
+                "height": "100%",
+                "justifyContent": "center",
+                "minWidth": 25,
+                "opacity": 0,
+                "position": "absolute",
+                "width": "100%",
+              }
+            }
+          >
+            <Text
+              accessible={true}
+              allowFontScaling={false}
+              ellipsizeMode="tail"
+              style={
+                Array [
+                  Object {
+                    "color": "#2f95dc",
+                    "fontSize": 26,
+                  },
+                  Object {
+                    "marginBottom": -3,
+                  },
+                  Object {
+                    "fontFamily": "ionicons",
+                    "fontStyle": "normal",
+                    "fontWeight": "normal",
+                  },
+                ]
+              }
+            >
+              
+            </Text>
+          </View>
+          <View
+            style={
+              Object {
+                "alignItems": "center",
+                "alignSelf": "center",
+                "height": "100%",
+                "justifyContent": "center",
+                "minWidth": 25,
+                "opacity": 1,
+                "position": "absolute",
+                "width": "100%",
+              }
+            }
+          >
+            <Text
+              accessible={true}
+              allowFontScaling={false}
+              ellipsizeMode="tail"
+              style={
+                Array [
+                  Object {
+                    "color": "#ccc",
+                    "fontSize": 26,
+                  },
+                  Object {
+                    "marginBottom": -3,
+                  },
+                  Object {
+                    "fontFamily": "ionicons",
+                    "fontStyle": "normal",
+                    "fontWeight": "normal",
+                  },
+                ]
+              }
+            >
+              
+            </Text>
+          </View>
+        </View>
+        <Text
+          accessible={true}
+          allowFontScaling={true}
+          ellipsizeMode="tail"
+          numberOfLines={1}
+          style={
+            Object {
+              "backgroundColor": "transparent",
+              "color": "#929292",
+              "fontSize": 11,
+              "marginBottom": 1.5,
+              "textAlign": "center",
+            }
+          }
+        >
+          Follower
+        </Text>
+      </View>
+      <View
+        accessibilityLabel="Following"
+        accessible={true}
+        onResponderGrant={[Function]}
+        onResponderMove={[Function]}
+        onResponderRelease={[Function]}
+        onResponderTerminate={[Function]}
+        onResponderTerminationRequest={[Function]}
+        onStartShouldSetResponder={[Function]}
+        style={
+          Array [
+            Object {
+              "alignItems": "center",
+              "flex": 1,
+            },
+            Object {
+              "backgroundColor": "transparent",
+            },
+            Object {
+              "flexDirection": "column",
+              "justifyContent": "flex-end",
+            },
+            undefined,
+          ]
+        }
+      >
+        <View
+          style={
+            Array [
+              Object {
+                "height": 29,
+              },
+              false,
+              Object {
+                "flex": 1,
+              },
+            ]
+          }
+        >
+          <View
+            style={
+              Object {
+                "alignItems": "center",
+                "alignSelf": "center",
+                "height": "100%",
+                "justifyContent": "center",
+                "minWidth": 25,
+                "opacity": 0,
+                "position": "absolute",
+                "width": "100%",
+              }
+            }
+          >
+            <Text
+              accessible={true}
+              allowFontScaling={false}
+              ellipsizeMode="tail"
+              style={
+                Array [
+                  Object {
+                    "color": "#2f95dc",
+                    "fontSize": 26,
+                  },
+                  Object {
+                    "marginBottom": -3,
+                  },
+                  Object {
+                    "fontFamily": "ionicons",
+                    "fontStyle": "normal",
+                    "fontWeight": "normal",
+                  },
+                ]
+              }
+            >
+              ï’³
+            </Text>
+          </View>
+          <View
+            style={
+              Object {
+                "alignItems": "center",
+                "alignSelf": "center",
+                "height": "100%",
+                "justifyContent": "center",
+                "minWidth": 25,
+                "opacity": 1,
+                "position": "absolute",
+                "width": "100%",
+              }
+            }
+          >
+            <Text
+              accessible={true}
+              allowFontScaling={false}
+              ellipsizeMode="tail"
+              style={
+                Array [
+                  Object {
+                    "color": "#ccc",
+                    "fontSize": 26,
+                  },
+                  Object {
+                    "marginBottom": -3,
+                  },
+                  Object {
+                    "fontFamily": "ionicons",
+                    "fontStyle": "normal",
+                    "fontWeight": "normal",
+                  },
+                ]
+              }
+            >
+              ï’²
+            </Text>
+          </View>
+        </View>
+        <Text
+          accessible={true}
+          allowFontScaling={true}
+          ellipsizeMode="tail"
+          numberOfLines={1}
+          style={
+            Object {
+              "backgroundColor": "transparent",
+              "color": "#929292",
+              "fontSize": 11,
+              "marginBottom": 1.5,
+              "textAlign": "center",
+            }
+          }
+        >
+          Following
+        </Text>
+      </View>
+    </View>
+  </View>
+</View>
+`;
diff --git a/mp3/__tests__/__snapshots__/Screen-test.js.snap b/mp3/__tests__/__snapshots__/Screen-test.js.snap
new file mode 100644
index 0000000..adc9bd5
--- /dev/null
+++ b/mp3/__tests__/__snapshots__/Screen-test.js.snap
@@ -0,0 +1,265 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Follower renders correctly 1`] = `
+<View>
+  <View
+    style={
+      Array [
+        Object {
+          "backgroundColor": "#ffffff",
+          "borderColor": "#bbb",
+          "borderTopWidth": 1,
+          "marginTop": 20,
+        },
+        Object {
+          "borderBottomWidth": 0,
+          "borderTopWidth": 0,
+          "marginTop": 0,
+        },
+      ]
+    }
+  />
+  <View
+    style={
+      Array [
+        Object {
+          "marginLeft": 15,
+          "marginRight": 15,
+        },
+        undefined,
+        undefined,
+        undefined,
+      ]
+    }
+  >
+    <View
+      accessible={true}
+      isTVSelectable={true}
+      onResponderGrant={[Function]}
+      onResponderMove={[Function]}
+      onResponderRelease={[Function]}
+      onResponderTerminate={[Function]}
+      onResponderTerminationRequest={[Function]}
+      onStartShouldSetResponder={[Function]}
+      style={null}
+    >
+      <View
+        pointerEvents="box-only"
+        style={
+          Array [
+            Object {
+              "alignItems": "center",
+              "backgroundColor": "#9E9E9E",
+              "flexDirection": "row",
+              "justifyContent": "center",
+              "padding": 19,
+            },
+            undefined,
+            undefined,
+            undefined,
+            undefined,
+            undefined,
+            Object {
+              "backgroundColor": "#AF7AC5",
+            },
+            undefined,
+            Object {
+              "padding": 12,
+            },
+            undefined,
+            undefined,
+            undefined,
+            Object {
+              "alignSelf": "center",
+              "marginTop": "2%",
+              "width": "50%",
+            },
+            undefined,
+            undefined,
+          ]
+        }
+      >
+        <Text
+          accessible={true}
+          allowFontScaling={true}
+          ellipsizeMode="tail"
+          style={
+            Array [
+              Object {},
+              undefined,
+              undefined,
+              undefined,
+              undefined,
+              undefined,
+              undefined,
+              undefined,
+              undefined,
+              undefined,
+              Array [
+                Object {
+                  "color": "white",
+                  "fontSize": 20,
+                },
+                undefined,
+                Object {
+                  "fontSize": 17.5,
+                },
+                undefined,
+                undefined,
+                undefined,
+                undefined,
+                undefined,
+              ],
+            ]
+          }
+        >
+          REFRESH
+        </Text>
+      </View>
+    </View>
+  </View>
+</View>
+`;
+
+exports[`Following renders correctly 1`] = `
+<View>
+  <View
+    style={
+      Array [
+        Object {
+          "backgroundColor": "#ffffff",
+          "borderColor": "#bbb",
+          "borderTopWidth": 1,
+          "marginTop": 20,
+        },
+        Object {
+          "borderBottomWidth": 0,
+          "borderTopWidth": 0,
+          "marginTop": 0,
+        },
+      ]
+    }
+  />
+  <View
+    style={
+      Array [
+        Object {
+          "marginLeft": 15,
+          "marginRight": 15,
+        },
+        undefined,
+        undefined,
+        undefined,
+      ]
+    }
+  >
+    <View
+      accessible={true}
+      isTVSelectable={true}
+      onResponderGrant={[Function]}
+      onResponderMove={[Function]}
+      onResponderRelease={[Function]}
+      onResponderTerminate={[Function]}
+      onResponderTerminationRequest={[Function]}
+      onStartShouldSetResponder={[Function]}
+      style={null}
+    >
+      <View
+        pointerEvents="box-only"
+        style={
+          Array [
+            Object {
+              "alignItems": "center",
+              "backgroundColor": "#9E9E9E",
+              "flexDirection": "row",
+              "justifyContent": "center",
+              "padding": 19,
+            },
+            undefined,
+            undefined,
+            undefined,
+            undefined,
+            undefined,
+            Object {
+              "backgroundColor": "#AF7AC5",
+            },
+            undefined,
+            Object {
+              "padding": 12,
+            },
+            undefined,
+            undefined,
+            undefined,
+            Object {
+              "alignSelf": "center",
+              "marginTop": "2%",
+              "width": "50%",
+            },
+            undefined,
+            undefined,
+          ]
+        }
+      >
+        <Text
+          accessible={true}
+          allowFontScaling={true}
+          ellipsizeMode="tail"
+          style={
+            Array [
+              Object {},
+              undefined,
+              undefined,
+              undefined,
+              undefined,
+              undefined,
+              undefined,
+              undefined,
+              undefined,
+              undefined,
+              Array [
+                Object {
+                  "color": "white",
+                  "fontSize": 20,
+                },
+                undefined,
+                Object {
+                  "fontSize": 17.5,
+                },
+                undefined,
+                undefined,
+                undefined,
+                undefined,
+                undefined,
+              ],
+            ]
+          }
+        >
+          REFRESH
+        </Text>
+      </View>
+    </View>
+  </View>
+</View>
+`;
+
+exports[`Profile renders correctly 1`] = `null`;
+
+exports[`Repo renders correctly 1`] = `
+<View
+  style={
+    Array [
+      Object {
+        "backgroundColor": "#ffffff",
+        "borderColor": "#bbb",
+        "borderTopWidth": 1,
+        "marginTop": 20,
+      },
+      Object {
+        "borderBottomWidth": 0,
+        "borderTopWidth": 0,
+        "marginTop": 0,
+      },
+    ]
+  }
+/>
+`;
diff --git a/mp3/components/__tests__/__snapshots__/StyledText-test.js.snap b/mp3/components/__tests__/__snapshots__/StyledText-test.js.snap
new file mode 100644
index 0000000..32610a0
--- /dev/null
+++ b/mp3/components/__tests__/__snapshots__/StyledText-test.js.snap
@@ -0,0 +1,19 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders correctly 1`] = `
+<Text
+  accessible={true}
+  allowFontScaling={true}
+  ellipsizeMode="tail"
+  style={
+    Array [
+      undefined,
+      Object {
+        "fontFamily": "space-mono",
+      },
+    ]
+  }
+>
+  Snapshot test!
+</Text>
+`;
diff --git a/mp3/navigation/MainTabNavigator.js b/mp3/navigation/MainTabNavigator.js
index a34811b..39a96ae 100644
--- a/mp3/navigation/MainTabNavigator.js
+++ b/mp3/navigation/MainTabNavigator.js
@@ -64,7 +64,7 @@ FollowingStack.navigationOptions = {
   tabBarIcon: ({ focused }) => (
     <TabBarIcon
       focused={focused}
-      name={Platform.OS === 'ios' ? `ios-options${focused ? '' : '-outline'}` : 'md-options'}
+      name={Platform.OS === 'ios' ? `ios-star${focused ? '' : '-outline'}` : 'md-options'}
     />
   ),
 };
diff --git a/mp3/package-lock.json b/mp3/package-lock.json
index 685fdc0..87c9307 100644
--- a/mp3/package-lock.json
+++ b/mp3/package-lock.json
@@ -1452,13 +1452,13 @@
       }
     },
     "babel-jest": {
-      "version": "22.4.4",
-      "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-22.4.4.tgz",
-      "integrity": "sha512-A9NB6/lZhYyypR9ATryOSDcqBaqNdzq4U+CN+/wcMsLcmKkPxQEoTKLajGfd3IkxNyVBT8NewUK2nWyGbSzHEQ==",
+      "version": "23.6.0",
+      "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-23.6.0.tgz",
+      "integrity": "sha512-lqKGG6LYXYu+DQh/slrQ8nxXQkEkhugdXsU6St7GmhVS7Ilc/22ArwqXNJrf0QaOBjZB0360qZMwXqDYQHXaew==",
       "dev": true,
       "requires": {
         "babel-plugin-istanbul": "4.1.6",
-        "babel-preset-jest": "22.4.4"
+        "babel-preset-jest": "23.2.0"
       }
     },
     "babel-messages": {
@@ -1498,9 +1498,9 @@
       }
     },
     "babel-plugin-jest-hoist": {
-      "version": "22.4.4",
-      "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-22.4.4.tgz",
-      "integrity": "sha512-DUvGfYaAIlkdnygVIEl0O4Av69NtuQWcrjMOv6DODPuhuGLDnbsARz3AwiiI/EkIMMlxQDUcrZ9yoyJvTNjcVQ==",
+      "version": "23.2.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-23.2.0.tgz",
+      "integrity": "sha1-5h+uBaHKiAGq3uV6bWa4zvr0QWc=",
       "dev": true
     },
     "babel-plugin-module-resolver": {
@@ -1953,12 +1953,12 @@
       }
     },
     "babel-preset-jest": {
-      "version": "22.4.4",
-      "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-22.4.4.tgz",
-      "integrity": "sha512-+dxMtOFwnSYWfum0NaEc0O03oSdwBsjx4tMSChRDPGwu/4wSY6Q6ANW3wkjKpJzzguaovRs/DODcT4hbSN8yiA==",
+      "version": "23.2.0",
+      "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-23.2.0.tgz",
+      "integrity": "sha1-jsegOhOPABoaj7HoETZSvxpV2kY=",
       "dev": true,
       "requires": {
-        "babel-plugin-jest-hoist": "22.4.4",
+        "babel-plugin-jest-hoist": "23.2.0",
         "babel-plugin-syntax-object-rest-spread": "6.13.0"
       }
     },
@@ -4916,6 +4916,509 @@
         "handlebars": "4.0.12"
       }
     },
+    "jest": {
+      "version": "23.6.0",
+      "resolved": "https://registry.npmjs.org/jest/-/jest-23.6.0.tgz",
+      "integrity": "sha512-lWzcd+HSiqeuxyhG+EnZds6iO3Y3ZEnMrfZq/OTGvF/C+Z4fPMCdhWTGSAiO2Oym9rbEXfwddHhh6jqrTF3+Lw==",
+      "dev": true,
+      "requires": {
+        "import-local": "1.0.0",
+        "jest-cli": "23.6.0"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+          "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
+          "dev": true
+        },
+        "ansi-styles": {
+          "version": "3.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+          "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+          "dev": true,
+          "requires": {
+            "color-convert": "1.9.3"
+          }
+        },
+        "babel-jest": {
+          "version": "23.6.0",
+          "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-23.6.0.tgz",
+          "integrity": "sha512-lqKGG6LYXYu+DQh/slrQ8nxXQkEkhugdXsU6St7GmhVS7Ilc/22ArwqXNJrf0QaOBjZB0360qZMwXqDYQHXaew==",
+          "dev": true,
+          "requires": {
+            "babel-plugin-istanbul": "4.1.6",
+            "babel-preset-jest": "23.2.0"
+          }
+        },
+        "babel-plugin-jest-hoist": {
+          "version": "23.2.0",
+          "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-23.2.0.tgz",
+          "integrity": "sha1-5h+uBaHKiAGq3uV6bWa4zvr0QWc=",
+          "dev": true
+        },
+        "babel-preset-jest": {
+          "version": "23.2.0",
+          "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-23.2.0.tgz",
+          "integrity": "sha1-jsegOhOPABoaj7HoETZSvxpV2kY=",
+          "dev": true,
+          "requires": {
+            "babel-plugin-jest-hoist": "23.2.0",
+            "babel-plugin-syntax-object-rest-spread": "6.13.0"
+          }
+        },
+        "chalk": {
+          "version": "2.4.1",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz",
+          "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "3.2.1",
+            "escape-string-regexp": "1.0.5",
+            "supports-color": "5.5.0"
+          }
+        },
+        "cliui": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz",
+          "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==",
+          "dev": true,
+          "requires": {
+            "string-width": "2.1.1",
+            "strip-ansi": "4.0.0",
+            "wrap-ansi": "2.1.0"
+          }
+        },
+        "expect": {
+          "version": "23.6.0",
+          "resolved": "https://registry.npmjs.org/expect/-/expect-23.6.0.tgz",
+          "integrity": "sha512-dgSoOHgmtn/aDGRVFWclQyPDKl2CQRq0hmIEoUAuQs/2rn2NcvCWcSCovm6BLeuB/7EZuLGu2QfnR+qRt5OM4w==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "3.2.1",
+            "jest-diff": "23.6.0",
+            "jest-get-type": "22.4.3",
+            "jest-matcher-utils": "23.6.0",
+            "jest-message-util": "23.4.0",
+            "jest-regex-util": "23.3.0"
+          }
+        },
+        "jest-changed-files": {
+          "version": "23.4.2",
+          "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-23.4.2.tgz",
+          "integrity": "sha512-EyNhTAUWEfwnK0Is/09LxoqNDOn7mU7S3EHskG52djOFS/z+IT0jT3h3Ql61+dklcG7bJJitIWEMB4Sp1piHmA==",
+          "dev": true,
+          "requires": {
+            "throat": "4.1.0"
+          }
+        },
+        "jest-cli": {
+          "version": "23.6.0",
+          "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-23.6.0.tgz",
+          "integrity": "sha512-hgeD1zRUp1E1zsiyOXjEn4LzRLWdJBV//ukAHGlx6s5mfCNJTbhbHjgxnDUXA8fsKWN/HqFFF6X5XcCwC/IvYQ==",
+          "dev": true,
+          "requires": {
+            "ansi-escapes": "3.1.0",
+            "chalk": "2.4.1",
+            "exit": "0.1.2",
+            "glob": "7.1.3",
+            "graceful-fs": "4.1.11",
+            "import-local": "1.0.0",
+            "is-ci": "1.2.1",
+            "istanbul-api": "1.3.7",
+            "istanbul-lib-coverage": "1.2.1",
+            "istanbul-lib-instrument": "1.10.2",
+            "istanbul-lib-source-maps": "1.2.6",
+            "jest-changed-files": "23.4.2",
+            "jest-config": "23.6.0",
+            "jest-environment-jsdom": "23.4.0",
+            "jest-get-type": "22.4.3",
+            "jest-haste-map": "23.6.0",
+            "jest-message-util": "23.4.0",
+            "jest-regex-util": "23.3.0",
+            "jest-resolve-dependencies": "23.6.0",
+            "jest-runner": "23.6.0",
+            "jest-runtime": "23.6.0",
+            "jest-snapshot": "23.6.0",
+            "jest-util": "23.4.0",
+            "jest-validate": "23.6.0",
+            "jest-watcher": "23.4.0",
+            "jest-worker": "23.2.0",
+            "micromatch": "2.3.11",
+            "node-notifier": "5.3.0",
+            "prompts": "0.1.14",
+            "realpath-native": "1.0.2",
+            "rimraf": "2.6.2",
+            "slash": "1.0.0",
+            "string-length": "2.0.0",
+            "strip-ansi": "4.0.0",
+            "which": "1.3.1",
+            "yargs": "11.1.0"
+          }
+        },
+        "jest-config": {
+          "version": "23.6.0",
+          "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-23.6.0.tgz",
+          "integrity": "sha512-i8V7z9BeDXab1+VNo78WM0AtWpBRXJLnkT+lyT+Slx/cbP5sZJ0+NDuLcmBE5hXAoK0aUp7vI+MOxR+R4d8SRQ==",
+          "dev": true,
+          "requires": {
+            "babel-core": "6.26.3",
+            "babel-jest": "23.6.0",
+            "chalk": "2.4.1",
+            "glob": "7.1.3",
+            "jest-environment-jsdom": "23.4.0",
+            "jest-environment-node": "23.4.0",
+            "jest-get-type": "22.4.3",
+            "jest-jasmine2": "23.6.0",
+            "jest-regex-util": "23.3.0",
+            "jest-resolve": "23.6.0",
+            "jest-util": "23.4.0",
+            "jest-validate": "23.6.0",
+            "micromatch": "2.3.11",
+            "pretty-format": "23.6.0"
+          }
+        },
+        "jest-diff": {
+          "version": "23.6.0",
+          "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-23.6.0.tgz",
+          "integrity": "sha512-Gz9l5Ov+X3aL5L37IT+8hoCUsof1CVYBb2QEkOupK64XyRR3h+uRpYIm97K7sY8diFxowR8pIGEdyfMKTixo3g==",
+          "dev": true,
+          "requires": {
+            "chalk": "2.4.1",
+            "diff": "3.5.0",
+            "jest-get-type": "22.4.3",
+            "pretty-format": "23.6.0"
+          }
+        },
+        "jest-docblock": {
+          "version": "23.2.0",
+          "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-23.2.0.tgz",
+          "integrity": "sha1-8IXh8YVI2Z/dabICB+b9VdkTg6c=",
+          "dev": true,
+          "requires": {
+            "detect-newline": "2.1.0"
+          }
+        },
+        "jest-environment-jsdom": {
+          "version": "23.4.0",
+          "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-23.4.0.tgz",
+          "integrity": "sha1-BWp5UrP+pROsYqFAosNox52eYCM=",
+          "dev": true,
+          "requires": {
+            "jest-mock": "23.2.0",
+            "jest-util": "23.4.0",
+            "jsdom": "11.12.0"
+          }
+        },
+        "jest-environment-node": {
+          "version": "23.4.0",
+          "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-23.4.0.tgz",
+          "integrity": "sha1-V+gO0IQd6jAxZ8zozXlSHeuv3hA=",
+          "dev": true,
+          "requires": {
+            "jest-mock": "23.2.0",
+            "jest-util": "23.4.0"
+          }
+        },
+        "jest-haste-map": {
+          "version": "23.6.0",
+          "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-23.6.0.tgz",
+          "integrity": "sha512-uyNhMyl6dr6HaXGHp8VF7cK6KpC6G9z9LiMNsst+rJIZ8l7wY0tk8qwjPmEghczojZ2/ZhtEdIabZ0OQRJSGGg==",
+          "dev": true,
+          "requires": {
+            "fb-watchman": "2.0.0",
+            "graceful-fs": "4.1.11",
+            "invariant": "2.2.4",
+            "jest-docblock": "23.2.0",
+            "jest-serializer": "23.0.1",
+            "jest-worker": "23.2.0",
+            "micromatch": "2.3.11",
+            "sane": "2.5.2"
+          }
+        },
+        "jest-jasmine2": {
+          "version": "23.6.0",
+          "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-23.6.0.tgz",
+          "integrity": "sha512-pe2Ytgs1nyCs8IvsEJRiRTPC0eVYd8L/dXJGU08GFuBwZ4sYH/lmFDdOL3ZmvJR8QKqV9MFuwlsAi/EWkFUbsQ==",
+          "dev": true,
+          "requires": {
+            "babel-traverse": "6.26.0",
+            "chalk": "2.4.1",
+            "co": "4.6.0",
+            "expect": "23.6.0",
+            "is-generator-fn": "1.0.0",
+            "jest-diff": "23.6.0",
+            "jest-each": "23.6.0",
+            "jest-matcher-utils": "23.6.0",
+            "jest-message-util": "23.4.0",
+            "jest-snapshot": "23.6.0",
+            "jest-util": "23.4.0",
+            "pretty-format": "23.6.0"
+          }
+        },
+        "jest-leak-detector": {
+          "version": "23.6.0",
+          "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-23.6.0.tgz",
+          "integrity": "sha512-f/8zA04rsl1Nzj10HIyEsXvYlMpMPcy0QkQilVZDFOaPbv2ur71X5u2+C4ZQJGyV/xvVXtCCZ3wQ99IgQxftCg==",
+          "dev": true,
+          "requires": {
+            "pretty-format": "23.6.0"
+          }
+        },
+        "jest-matcher-utils": {
+          "version": "23.6.0",
+          "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-23.6.0.tgz",
+          "integrity": "sha512-rosyCHQfBcol4NsckTn01cdelzWLU9Cq7aaigDf8VwwpIRvWE/9zLgX2bON+FkEW69/0UuYslUe22SOdEf2nog==",
+          "dev": true,
+          "requires": {
+            "chalk": "2.4.1",
+            "jest-get-type": "22.4.3",
+            "pretty-format": "23.6.0"
+          }
+        },
+        "jest-message-util": {
+          "version": "23.4.0",
+          "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-23.4.0.tgz",
+          "integrity": "sha1-F2EMUJQjSVCNAaPR4L2iwHkIap8=",
+          "dev": true,
+          "requires": {
+            "@babel/code-frame": "7.0.0",
+            "chalk": "2.4.1",
+            "micromatch": "2.3.11",
+            "slash": "1.0.0",
+            "stack-utils": "1.0.1"
+          }
+        },
+        "jest-mock": {
+          "version": "23.2.0",
+          "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-23.2.0.tgz",
+          "integrity": "sha1-rRxg8p6HGdR8JuETgJi20YsmETQ=",
+          "dev": true
+        },
+        "jest-regex-util": {
+          "version": "23.3.0",
+          "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-23.3.0.tgz",
+          "integrity": "sha1-X4ZylUfCeFxAAs6qj4Sf6MpHG8U=",
+          "dev": true
+        },
+        "jest-resolve": {
+          "version": "23.6.0",
+          "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-23.6.0.tgz",
+          "integrity": "sha512-XyoRxNtO7YGpQDmtQCmZjum1MljDqUCob7XlZ6jy9gsMugHdN2hY4+Acz9Qvjz2mSsOnPSH7skBmDYCHXVZqkA==",
+          "dev": true,
+          "requires": {
+            "browser-resolve": "1.11.3",
+            "chalk": "2.4.1",
+            "realpath-native": "1.0.2"
+          }
+        },
+        "jest-resolve-dependencies": {
+          "version": "23.6.0",
+          "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-23.6.0.tgz",
+          "integrity": "sha512-EkQWkFWjGKwRtRyIwRwI6rtPAEyPWlUC2MpzHissYnzJeHcyCn1Hc8j7Nn1xUVrS5C6W5+ZL37XTem4D4pLZdA==",
+          "dev": true,
+          "requires": {
+            "jest-regex-util": "23.3.0",
+            "jest-snapshot": "23.6.0"
+          }
+        },
+        "jest-runner": {
+          "version": "23.6.0",
+          "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-23.6.0.tgz",
+          "integrity": "sha512-kw0+uj710dzSJKU6ygri851CObtCD9cN8aNkg8jWJf4ewFyEa6kwmiH/r/M1Ec5IL/6VFa0wnAk6w+gzUtjJzA==",
+          "dev": true,
+          "requires": {
+            "exit": "0.1.2",
+            "graceful-fs": "4.1.11",
+            "jest-config": "23.6.0",
+            "jest-docblock": "23.2.0",
+            "jest-haste-map": "23.6.0",
+            "jest-jasmine2": "23.6.0",
+            "jest-leak-detector": "23.6.0",
+            "jest-message-util": "23.4.0",
+            "jest-runtime": "23.6.0",
+            "jest-util": "23.4.0",
+            "jest-worker": "23.2.0",
+            "source-map-support": "0.5.9",
+            "throat": "4.1.0"
+          }
+        },
+        "jest-runtime": {
+          "version": "23.6.0",
+          "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-23.6.0.tgz",
+          "integrity": "sha512-ycnLTNPT2Gv+TRhnAYAQ0B3SryEXhhRj1kA6hBPSeZaNQkJ7GbZsxOLUkwg6YmvWGdX3BB3PYKFLDQCAE1zNOw==",
+          "dev": true,
+          "requires": {
+            "babel-core": "6.26.3",
+            "babel-plugin-istanbul": "4.1.6",
+            "chalk": "2.4.1",
+            "convert-source-map": "1.6.0",
+            "exit": "0.1.2",
+            "fast-json-stable-stringify": "2.0.0",
+            "graceful-fs": "4.1.11",
+            "jest-config": "23.6.0",
+            "jest-haste-map": "23.6.0",
+            "jest-message-util": "23.4.0",
+            "jest-regex-util": "23.3.0",
+            "jest-resolve": "23.6.0",
+            "jest-snapshot": "23.6.0",
+            "jest-util": "23.4.0",
+            "jest-validate": "23.6.0",
+            "micromatch": "2.3.11",
+            "realpath-native": "1.0.2",
+            "slash": "1.0.0",
+            "strip-bom": "3.0.0",
+            "write-file-atomic": "2.3.0",
+            "yargs": "11.1.0"
+          }
+        },
+        "jest-serializer": {
+          "version": "23.0.1",
+          "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-23.0.1.tgz",
+          "integrity": "sha1-o3dq6zEekP6D+rnlM+hRAr0WQWU=",
+          "dev": true
+        },
+        "jest-snapshot": {
+          "version": "23.6.0",
+          "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-23.6.0.tgz",
+          "integrity": "sha512-tM7/Bprftun6Cvj2Awh/ikS7zV3pVwjRYU2qNYS51VZHgaAMBs5l4o/69AiDHhQrj5+LA2Lq4VIvK7zYk/bswg==",
+          "dev": true,
+          "requires": {
+            "babel-types": "6.26.0",
+            "chalk": "2.4.1",
+            "jest-diff": "23.6.0",
+            "jest-matcher-utils": "23.6.0",
+            "jest-message-util": "23.4.0",
+            "jest-resolve": "23.6.0",
+            "mkdirp": "0.5.1",
+            "natural-compare": "1.4.0",
+            "pretty-format": "23.6.0",
+            "semver": "5.6.0"
+          }
+        },
+        "jest-util": {
+          "version": "23.4.0",
+          "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-23.4.0.tgz",
+          "integrity": "sha1-TQY8uSe68KI4Mf9hvsLLv0l5NWE=",
+          "dev": true,
+          "requires": {
+            "callsites": "2.0.0",
+            "chalk": "2.4.1",
+            "graceful-fs": "4.1.11",
+            "is-ci": "1.2.1",
+            "jest-message-util": "23.4.0",
+            "mkdirp": "0.5.1",
+            "slash": "1.0.0",
+            "source-map": "0.6.1"
+          }
+        },
+        "jest-validate": {
+          "version": "23.6.0",
+          "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-23.6.0.tgz",
+          "integrity": "sha512-OFKapYxe72yz7agrDAWi8v2WL8GIfVqcbKRCLbRG9PAxtzF9b1SEDdTpytNDN12z2fJynoBwpMpvj2R39plI2A==",
+          "dev": true,
+          "requires": {
+            "chalk": "2.4.1",
+            "jest-get-type": "22.4.3",
+            "leven": "2.1.0",
+            "pretty-format": "23.6.0"
+          }
+        },
+        "jest-worker": {
+          "version": "23.2.0",
+          "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-23.2.0.tgz",
+          "integrity": "sha1-+vcGqNo2+uYOsmlXJX+ntdjqArk=",
+          "dev": true,
+          "requires": {
+            "merge-stream": "1.0.1"
+          }
+        },
+        "pretty-format": {
+          "version": "23.6.0",
+          "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-23.6.0.tgz",
+          "integrity": "sha512-zf9NV1NSlDLDjycnwm6hpFATCGl/K1lt0R/GdkAK2O5LN/rwJoB+Mh93gGJjut4YbmecbfgLWVGSTCr0Ewvvbw==",
+          "dev": true,
+          "requires": {
+            "ansi-regex": "3.0.0",
+            "ansi-styles": "3.2.1"
+          }
+        },
+        "source-map": {
+          "version": "0.6.1",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+          "dev": true
+        },
+        "source-map-support": {
+          "version": "0.5.9",
+          "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.9.tgz",
+          "integrity": "sha512-gR6Rw4MvUlYy83vP0vxoVNzM6t8MUXqNuRsuBmBHQDu1Fh6X015FrLdgoDKcNdkwGubozq0P4N0Q37UyFVr1EA==",
+          "dev": true,
+          "requires": {
+            "buffer-from": "1.1.1",
+            "source-map": "0.6.1"
+          }
+        },
+        "strip-ansi": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+          "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+          "dev": true,
+          "requires": {
+            "ansi-regex": "3.0.0"
+          }
+        },
+        "supports-color": {
+          "version": "5.5.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+          "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+          "dev": true,
+          "requires": {
+            "has-flag": "3.0.0"
+          }
+        },
+        "write-file-atomic": {
+          "version": "2.3.0",
+          "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.3.0.tgz",
+          "integrity": "sha512-xuPeK4OdjWqtfi59ylvVL0Yn35SF3zgcAcv7rBPFHVaEapaDr4GdGgm3j7ckTwH9wHL7fGmgfAnb0+THrHb8tA==",
+          "dev": true,
+          "requires": {
+            "graceful-fs": "4.1.11",
+            "imurmurhash": "0.1.4",
+            "signal-exit": "3.0.2"
+          }
+        },
+        "yargs": {
+          "version": "11.1.0",
+          "resolved": "http://registry.npmjs.org/yargs/-/yargs-11.1.0.tgz",
+          "integrity": "sha512-NwW69J42EsCSanF8kyn5upxvjp5ds+t3+udGBeTbFnERA+lF541DDpMawzo4z6W/QrzNM18D+BPMiOBibnFV5A==",
+          "dev": true,
+          "requires": {
+            "cliui": "4.1.0",
+            "decamelize": "1.2.0",
+            "find-up": "2.1.0",
+            "get-caller-file": "1.0.3",
+            "os-locale": "2.1.0",
+            "require-directory": "2.1.1",
+            "require-main-filename": "1.0.1",
+            "set-blocking": "2.0.0",
+            "string-width": "2.1.1",
+            "which-module": "2.0.0",
+            "y18n": "3.2.1",
+            "yargs-parser": "9.0.2"
+          }
+        },
+        "yargs-parser": {
+          "version": "9.0.2",
+          "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-9.0.2.tgz",
+          "integrity": "sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc=",
+          "dev": true,
+          "requires": {
+            "camelcase": "4.1.0"
+          }
+        }
+      }
+    },
     "jest-changed-files": {
       "version": "22.4.3",
       "resolved": "http://registry.npmjs.org/jest-changed-files/-/jest-changed-files-22.4.3.tgz",
@@ -5058,6 +5561,63 @@
         "detect-newline": "2.1.0"
       }
     },
+    "jest-each": {
+      "version": "23.6.0",
+      "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-23.6.0.tgz",
+      "integrity": "sha512-x7V6M/WGJo6/kLoissORuvLIeAoyo2YqLOoCDkohgJ4XOXSqOtyvr8FbInlAWS77ojBsZrafbozWoKVRdtxFCg==",
+      "dev": true,
+      "requires": {
+        "chalk": "2.4.1",
+        "pretty-format": "23.6.0"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+          "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
+          "dev": true
+        },
+        "ansi-styles": {
+          "version": "3.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+          "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+          "dev": true,
+          "requires": {
+            "color-convert": "1.9.3"
+          }
+        },
+        "chalk": {
+          "version": "2.4.1",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz",
+          "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "3.2.1",
+            "escape-string-regexp": "1.0.5",
+            "supports-color": "5.5.0"
+          }
+        },
+        "pretty-format": {
+          "version": "23.6.0",
+          "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-23.6.0.tgz",
+          "integrity": "sha512-zf9NV1NSlDLDjycnwm6hpFATCGl/K1lt0R/GdkAK2O5LN/rwJoB+Mh93gGJjut4YbmecbfgLWVGSTCr0Ewvvbw==",
+          "dev": true,
+          "requires": {
+            "ansi-regex": "3.0.0",
+            "ansi-styles": "3.2.1"
+          }
+        },
+        "supports-color": {
+          "version": "5.5.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+          "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+          "dev": true,
+          "requires": {
+            "has-flag": "3.0.0"
+          }
+        }
+      }
+    },
     "jest-environment-jsdom": {
       "version": "22.4.3",
       "resolved": "http://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-22.4.3.tgz",
@@ -5088,7 +5648,7 @@
         "babel-jest": "22.4.4",
         "jest": "22.4.4",
         "json5": "0.5.1",
-        "react-test-renderer": "16.5.2"
+        "react-test-renderer": "16.6.0"
       },
       "dependencies": {
         "ansi-regex": {
@@ -5106,6 +5666,32 @@
             "color-convert": "1.9.3"
           }
         },
+        "babel-jest": {
+          "version": "22.4.4",
+          "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-22.4.4.tgz",
+          "integrity": "sha512-A9NB6/lZhYyypR9ATryOSDcqBaqNdzq4U+CN+/wcMsLcmKkPxQEoTKLajGfd3IkxNyVBT8NewUK2nWyGbSzHEQ==",
+          "dev": true,
+          "requires": {
+            "babel-plugin-istanbul": "4.1.6",
+            "babel-preset-jest": "22.4.4"
+          }
+        },
+        "babel-plugin-jest-hoist": {
+          "version": "22.4.4",
+          "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-22.4.4.tgz",
+          "integrity": "sha512-DUvGfYaAIlkdnygVIEl0O4Av69NtuQWcrjMOv6DODPuhuGLDnbsARz3AwiiI/EkIMMlxQDUcrZ9yoyJvTNjcVQ==",
+          "dev": true
+        },
+        "babel-preset-jest": {
+          "version": "22.4.4",
+          "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-22.4.4.tgz",
+          "integrity": "sha512-+dxMtOFwnSYWfum0NaEc0O03oSdwBsjx4tMSChRDPGwu/4wSY6Q6ANW3wkjKpJzzguaovRs/DODcT4hbSN8yiA==",
+          "dev": true,
+          "requires": {
+            "babel-plugin-jest-hoist": "22.4.4",
+            "babel-plugin-syntax-object-rest-spread": "6.13.0"
+          }
+        },
         "chalk": {
           "version": "2.4.1",
           "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz",
@@ -5579,6 +6165,32 @@
             "color-convert": "1.9.3"
           }
         },
+        "babel-jest": {
+          "version": "22.4.4",
+          "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-22.4.4.tgz",
+          "integrity": "sha512-A9NB6/lZhYyypR9ATryOSDcqBaqNdzq4U+CN+/wcMsLcmKkPxQEoTKLajGfd3IkxNyVBT8NewUK2nWyGbSzHEQ==",
+          "dev": true,
+          "requires": {
+            "babel-plugin-istanbul": "4.1.6",
+            "babel-preset-jest": "22.4.4"
+          }
+        },
+        "babel-plugin-jest-hoist": {
+          "version": "22.4.4",
+          "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-22.4.4.tgz",
+          "integrity": "sha512-DUvGfYaAIlkdnygVIEl0O4Av69NtuQWcrjMOv6DODPuhuGLDnbsARz3AwiiI/EkIMMlxQDUcrZ9yoyJvTNjcVQ==",
+          "dev": true
+        },
+        "babel-preset-jest": {
+          "version": "22.4.4",
+          "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-22.4.4.tgz",
+          "integrity": "sha512-+dxMtOFwnSYWfum0NaEc0O03oSdwBsjx4tMSChRDPGwu/4wSY6Q6ANW3wkjKpJzzguaovRs/DODcT4hbSN8yiA==",
+          "dev": true,
+          "requires": {
+            "babel-plugin-jest-hoist": "22.4.4",
+            "babel-plugin-syntax-object-rest-spread": "6.13.0"
+          }
+        },
         "chalk": {
           "version": "2.4.1",
           "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz",
@@ -5839,6 +6451,48 @@
         }
       }
     },
+    "jest-watcher": {
+      "version": "23.4.0",
+      "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-23.4.0.tgz",
+      "integrity": "sha1-0uKM50+NrWxq/JIrksq+9u0FyRw=",
+      "dev": true,
+      "requires": {
+        "ansi-escapes": "3.1.0",
+        "chalk": "2.4.1",
+        "string-length": "2.0.0"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "3.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+          "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+          "dev": true,
+          "requires": {
+            "color-convert": "1.9.3"
+          }
+        },
+        "chalk": {
+          "version": "2.4.1",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz",
+          "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "3.2.1",
+            "escape-string-regexp": "1.0.5",
+            "supports-color": "5.5.0"
+          }
+        },
+        "supports-color": {
+          "version": "5.5.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+          "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+          "dev": true,
+          "requires": {
+            "has-flag": "3.0.0"
+          }
+        }
+      }
+    },
     "jest-worker": {
       "version": "22.2.2",
       "resolved": "http://registry.npmjs.org/jest-worker/-/jest-worker-22.2.2.tgz",
@@ -5993,6 +6647,12 @@
         "graceful-fs": "4.1.11"
       }
     },
+    "kleur": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/kleur/-/kleur-2.0.2.tgz",
+      "integrity": "sha512-77XF9iTllATmG9lSlIv0qdQ2BQ/h9t0bJllHlbvsQ0zUWfU7Yi0S8L5JXzPZgkefIiajLmBJJ4BsMJmqcf7oxQ==",
+      "dev": true
+    },
     "lcid": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz",
@@ -9900,6 +10560,16 @@
         "asap": "2.0.6"
       }
     },
+    "prompts": {
+      "version": "0.1.14",
+      "resolved": "https://registry.npmjs.org/prompts/-/prompts-0.1.14.tgz",
+      "integrity": "sha512-rxkyiE9YH6zAz/rZpywySLKkpaj0NMVyNw1qhsubdbjjSgcayjTShDreZGlFMcGSu5sab3bAKPfFk78PB90+8w==",
+      "dev": true,
+      "requires": {
+        "kleur": "2.0.2",
+        "sisteransi": "0.1.1"
+      }
+    },
     "prop-types": {
       "version": "15.6.2",
       "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.6.2.tgz",
@@ -10019,9 +10689,9 @@
       }
     },
     "react-is": {
-      "version": "16.5.2",
-      "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.5.2.tgz",
-      "integrity": "sha512-hSl7E6l25GTjNEZATqZIuWOgSnpXb3kD0DVCujmg46K5zLxsbiKaaT6VO9slkSBDPZfYs30lwfJwbOFOnoEnKQ==",
+      "version": "16.6.0",
+      "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.6.0.tgz",
+      "integrity": "sha512-q8U7k0Fi7oxF1HvQgyBjPwDXeMplEsArnKt2iYhuIF86+GBbgLHdAmokL3XUFjTd7Q363OSNG55FOGUdONVn1g==",
       "dev": true
     },
     "react-lifecycles-compat": {
@@ -10352,15 +11022,15 @@
       }
     },
     "react-test-renderer": {
-      "version": "16.5.2",
-      "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-16.5.2.tgz",
-      "integrity": "sha512-AGbJYbCVx1J6jdUgI4s0hNp+9LxlgzKvXl0ROA3DHTrtjAr00Po1RhDZ/eAq2VC/ww8AHgpDXULh5V2rhEqqJg==",
+      "version": "16.6.0",
+      "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-16.6.0.tgz",
+      "integrity": "sha512-w+Y3YT7OX1LP5KO7HCd0YR34Ol1qmISHaooPNMRYa6QzmwtcWhEGuZPr34wO8UCBIokswuhyLQUq7rjPDcEtJA==",
       "dev": true,
       "requires": {
         "object-assign": "4.1.1",
         "prop-types": "15.6.2",
-        "react-is": "16.5.2",
-        "schedule": "0.5.0"
+        "react-is": "16.6.0",
+        "scheduler": "0.10.0"
       }
     },
     "react-timer-mixin": {
@@ -10983,12 +11653,13 @@
       "resolved": "http://registry.npmjs.org/sax/-/sax-1.1.6.tgz",
       "integrity": "sha1-XWFr6KXmB9VOEUr65Vt+ry/MMkA="
     },
-    "schedule": {
-      "version": "0.5.0",
-      "resolved": "https://registry.npmjs.org/schedule/-/schedule-0.5.0.tgz",
-      "integrity": "sha512-HUcJicG5Ou8xfR//c2rPT0lPIRR09vVvN81T9fqfVgBmhERUbDEQoYKjpBxbueJnCPpSu2ujXzOnRQt6x9o/jw==",
+    "scheduler": {
+      "version": "0.10.0",
+      "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.10.0.tgz",
+      "integrity": "sha512-+TSTVTCBAA3h8Anei3haDc1IRwMeDmtI/y/o3iBe3Mjl2vwYF9DtPDt929HyRmV/e7au7CLu8sc4C4W0VOs29w==",
       "dev": true,
       "requires": {
+        "loose-envify": "1.4.0",
         "object-assign": "4.1.1"
       }
     },
@@ -11162,6 +11833,12 @@
         }
       }
     },
+    "sisteransi": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-0.1.1.tgz",
+      "integrity": "sha512-PmGOd02bM9YO5ifxpw36nrNMBTptEtfRl4qUYl9SndkolplkrZZOW7PGHjrZL53QvMVj9nQ+TKqUnRsw4tJa4g==",
+      "dev": true
+    },
     "slash": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz",
diff --git a/mp3/package.json b/mp3/package.json
index eb5d375..ff78f66 100644
--- a/mp3/package.json
+++ b/mp3/package.json
@@ -24,6 +24,9 @@
     "react-navigation": "^2.16.0"
   },
   "devDependencies": {
-    "jest-expo": "30.0.0"
+    "babel-jest": "^23.6.0",
+    "jest": "^23.6.0",
+    "jest-expo": "30.0.0",
+    "react-test-renderer": "^16.6.0"
   }
 }
diff --git a/mp3/screens/FollowerScreen.js b/mp3/screens/FollowerScreen.js
index 87a6c70..cc5f556 100644
--- a/mp3/screens/FollowerScreen.js
+++ b/mp3/screens/FollowerScreen.js
@@ -1,14 +1,181 @@
 import React from 'react';
-import { Text } from 'react-native';
+import axios from 'axios';
+import { AsyncStorage } from 'react-native';
+import {
+  StyleSheet,
+  Text,
+  View,
+  FlatList,
+  ActivityIndicator,
+} from 'react-native';
+import { List, ListItem, Button } from 'react-native-elements';
+import { WebBrowser } from 'expo';
+
 
 export default class FollowerScreen extends React.Component {
   static navigationOptions = {
     title: 'Follower',
   };
 
+  constructor(props){
+    super(props);
+
+    this.state = {
+      data: [],
+      pageNum: 1,
+      loading: false,
+      baseUser: 'cs242HW',
+    };
+    this.makeRequest = this.makeRequest.bind(this);
+  }
+
+  componentDidMount(){
+    this.makeRequest(this.state.baseUser);
+  }
+
+  _storeData = async (key, item) => {
+    try {
+      await AsyncStorage.setItem(key, JSON.stringify(item));
+    } catch (e) {
+      console.log(e.message);
+    }
+  }
+
+  _retrieveData = async (key) => {
+    try {
+      const data = await AsyncStorage.getItem(key+'Followers');
+      console.log("followers key: "+key+'Followers');
+      console.log("followers data: "+data);
+      if (data){
+        this.setState({
+          data: JSON.parse(data),
+          loading: false,
+        });
+      } else {
+        axios.get('https://api.github.com/users/'+key+'/followers?page='+this.state.pageNum)
+          .then((res) => {
+            if (res.length != 0){
+              var data = []
+              for (var i=0; i<res.data.length; i++){
+                const id = res.data[i].id;
+                const name = res.data[i].login;
+                const avatar_url = res.data[i].avatar_url;
+                const html_url = res.data[i].html_url;
+                const repo = res.data[i].repos_url;
+                const followers = res.data[i].followers_url;
+                const following = res.data[i].following_url;
+                data.push({id: id, name: name, avatar: avatar_url, url: html_url, repo: repo, followers: followers, following: following});
+              }
+              this.setState({
+                data: data,
+                loading: false,
+              });
+              this._storeData(key+'Followers', data);
+            }
+          })
+          .catch(err => {
+            console.log(err);
+          })
+      }
+    } catch (e) {
+      console.log(e.message);
+    }
+  }
+
+  makeRequest = (userName) => {
+    this.setState({
+      loading: true,
+    })
+
+    this._retrieveData(userName);
+  }
+
+  _handlePress = () => {
+    axios.get('https://api.github.com/users/'+this.state.baseUser+'/followers?page='+this.state.pageNum)
+      .then((res) => {
+        console.log("Refresh triggered!");
+        if (res.length != 0){
+          var data = []
+          for (var i=0; i<res.data.length; i++){
+            const id = res.data[i].id;
+            const name = res.data[i].login;
+            const avatar_url = res.data[i].avatar_url;
+            const html_url = res.data[i].html_url;
+            const repo = res.data[i].repos_url;
+            const followers = res.data[i].followers_url;
+            const following = res.data[i].following_url;
+            data.push({id: id, name: name, avatar: avatar_url, url: html_url, repo: repo, followers: followers, following: following});
+          }
+          this.setState({
+            data: data,
+            loading: false,
+          });
+          this._storeData(this.state.baseUser+'Followers', data);
+        }
+      })
+      .catch(err => {
+        console.log(err);
+      })
+  }
+
+  renderFooter = () => {
+    if (!this.state.loading) return null;
+
+    return (
+      <View
+        style={{
+          paddingVertical: 20,
+          borderTopWidth: 1,
+          borderColor: "#CED0CE"
+        }}
+      >
+        <ActivityIndicator animating size="large" />
+      </View>
+    );
+  }
+
+  renderSeparator = () => {
+    return (
+      <View
+        style={{
+          height: 1,
+          width: "86%",
+          backgroundColor: "#CED0CE",
+          marginLeft: "14%"
+        }}
+      />
+    );
+  };
+
   render() {
-    return(
-      <Text>Followers</Text>
-    )
+    return (
+      <View>
+        <List containerStyle={{marginTop: 0, borderTopWidth: 0, borderBottomWidth: 0}}>
+          <FlatList
+            data={this.state.data}
+            renderItem={({ item }) => (
+              <ListItem
+                roundAvatar
+                avatar={{uri: item.avatar}}
+                title={item.name}
+                titleStyle={{fontWeight: 'bold'}}
+                underlayColor='#E5E8E8'
+                containerStyle={{ borderBottomWidth: 0 }}
+                onPress={() => this.props.navigation.navigate('Profile', { name: item.name })}
+              />
+            )}
+            keyExtractor={item => item.id.toString()}
+            ListFooterComponent={this.renderFooter}
+            ItemSeparatorComponent={this.renderSeparator}
+          />
+        </List>
+        <Button
+          buttonStyle={{marginTop: '2%', width: '50%', alignSelf: 'center'}}
+          title={'REFRESH'}
+          backgroundColor='#AF7AC5'
+          onPress={this._handlePress.bind(this)}
+        />
+      </View>
+    );
   }
 }
diff --git a/mp3/screens/FollowingScreen.js b/mp3/screens/FollowingScreen.js
index ca3f29e..79583b4 100644
--- a/mp3/screens/FollowingScreen.js
+++ b/mp3/screens/FollowingScreen.js
@@ -1,14 +1,246 @@
 import React from 'react';
-import { Text } from 'react-native';
+import axios from 'axios';
+import { AsyncStorage } from 'react-native';
+import {
+  StyleSheet,
+  Text,
+  View,
+  FlatList,
+  ActivityIndicator,
+  TouchableOpacity,
+} from 'react-native';
+import { List, ListItem, Button } from 'react-native-elements';
+import { WebBrowser } from 'expo';
+
 
 export default class FollowingScreen extends React.Component {
   static navigationOptions = {
     title: 'Following',
   };
 
+  constructor(props){
+    super(props);
+
+    this.state = {
+      data: [],
+      pageNum: 1,
+      loading: false,
+      baseUser: 'cs242HW',
+      password: 'assignment3',
+      following: {},
+    };
+    this.makeRequest = this.makeRequest.bind(this);
+  }
+
+  componentDidMount(){
+    this.makeRequest(this.state.baseUser);
+  }
+
+  // _handlePress = (url) => {
+  //   WebBrowser.openBrowserAsync(url);
+  // }
+
+  _storeData = async (key, item) => {
+    try {
+      await AsyncStorage.setItem(key, JSON.stringify(item));
+    } catch (e) {
+      console.log(e.message);
+    }
+  }
+
+  _retrieveData = async (key) => {
+    try {
+      const data = await AsyncStorage.getItem(key+'Following');
+      console.log("following key: "+key+'Following');
+      console.log("following data: "+data);
+      if (data){
+        let following = JSON.parse(data);
+        var following_dict = [];
+        following.forEach(function(item) {
+          following_dict.push({
+            key: item.name,
+            value: true,
+          });
+        }.bind(this));
+
+        this.setState({
+          data: following,
+          loading: false,
+          following: following_dict,
+        });
+      } else {
+        axios.get('https://api.github.com/users/'+key+'/following?page='+this.state.pageNum)
+          .then((res) => {
+            if (res.length != 0){
+              var data = []
+              for (var i=0; i<res.data.length; i++){
+                const id = res.data[i].id;
+                const name = res.data[i].login;
+                const avatar_url = res.data[i].avatar_url;
+                const html_url = res.data[i].html_url;
+                data.push({id: id, name: name, avatar: avatar_url, url: html_url})
+              }
+              let following = data;
+              var following_dict = [];
+              following.forEach(function(item) {
+                following_dict.push({
+                  key: item.name,
+                  value: true,
+                });
+              }.bind(this));
+
+              this.setState({
+                data: following,
+                loading: false,
+                following: following_dict,
+              });
+            }
+          })
+          .catch(err => {
+            console.log(err);
+          })
+      }
+    } catch (e) {
+      console.log(e.message);
+    }
+  }
+
+  makeRequest = (userName) => {
+    this.setState({
+      loading: true,
+    })
+
+    this._retrieveData(userName);
+  }
+
+  _handlePress = () => {
+    axios.get('https://api.github.com/users/'+this.state.baseUser+'/following?page='+this.state.pageNum)
+      .then((res) => {
+        console.log("Refresh triggered!");
+        if (res.length != 0){
+          var data = []
+          for (var i=0; i<res.data.length; i++){
+            const id = res.data[i].id;
+            const name = res.data[i].login;
+            const avatar_url = res.data[i].avatar_url;
+            const html_url = res.data[i].html_url;
+            data.push({id: id, name: name, avatar: avatar_url, url: html_url})
+          }
+          this.setState({
+            data: data,
+            loading: false,
+          });
+          this._storeData(this.state.baseUser+'Following', data);
+        }
+      })
+      .catch(err => {
+        console.log(err);
+      })
+  }
+
+  _changeFollow = (key) => {
+    const following = this.state.following[key];
+    if (following){
+      //axios.delete('https://api.github.com/users/'+this.state.baseUser+'/following/'+key)
+      fetch('http://api.github.com/user/following/'+key, {
+        method: 'DELETE',
+        headers: {
+          'Authorization': 'Basic ' + new Buffer(this.state.baseUser + ':' + this.state.password).toString('base64')
+        },
+      })
+        .then((res) => {
+            var dict = this.state.following;
+            dict[key] = false;
+            this.setState({
+              following: dict,
+            });
+        })
+        .catch(e => {
+          console.log(e.message);
+        })
+    } else {
+      axios.put('https://api.github.com/users'+this.state.baseUser+'/following/'+key)
+        .then((res) => {
+          var dict = this.state.following;
+          dict[key] = true;
+          this.setState({
+            following: dict,
+          });
+        })
+        .catch(e => {
+          console.log(e.message);
+        })
+    }
+  }
+
+  renderFooter = () => {
+    if (!this.state.loading) return null;
+
+    return (
+      <View
+        style={{
+          paddingVertical: 20,
+          borderTopWidth: 1,
+          borderColor: "#CED0CE"
+        }}
+      >
+        <ActivityIndicator animating size="large" />
+      </View>
+    );
+  }
+
+  renderSeparator = () => {
+    return (
+      <View
+        style={{
+          height: 1,
+          width: "86%",
+          backgroundColor: "#CED0CE",
+          marginLeft: "14%",
+        }}
+      />
+    );
+  };
+
+  // <TouchableOpacity style={{backgroundColor: 'green'}}>
+  //                 <Text style={{color: 'black'}} onPress={ () => this._changeFollow(item.name)}>{this.state.following[item.name]}</Text>
+  //               </TouchableOpacity>
+
   render() {
-    return(
-      <Text>Following</Text>
-    )
+    return (
+      <View>
+        <List containerStyle={{marginTop: 0, borderTopWidth: 0, borderBottomWidth: 0}}>
+          <FlatList
+            data={this.state.data}
+            renderItem={({ item }) => (
+              <ListItem
+                roundAvatar
+                avatar={{uri: item.avatar}}
+                title={item.name}
+                titleStyle={{fontWeight: 'bold'}}
+                underlayColor='#E5E8E8'
+                containerStyle={{ borderBottomWidth: 0 }}
+                onPress={() => this.props.navigation.navigate('Profile', { name: item.name })}
+                rightIcon = {<Button
+                              title={this.state.following[item.name]?'unfollow':'following'}
+                              backgroundColor='#E8DAEF'
+                              onPress={this._changeFollow.bind(this, item.name)}
+                              />
+                            }
+              />
+            )}
+            keyExtractor={item => item.id.toString()}
+            ListFooterComponent={this.renderFooter}
+            ItemSeparatorComponent={this.renderSeparator}
+          />
+        </List>
+        <Button
+          buttonStyle={{marginTop: '2%', width: '50%', alignSelf: 'center'}}
+          title={'REFRESH'}
+          backgroundColor='#AF7AC5'
+          onPress={this._handlePress.bind(this)}
+        />
+      </View>
+    );
   }
 }
diff --git a/mp3/screens/Profile/Detail.js b/mp3/screens/Profile/Detail.js
index ab29f47..0a077e7 100644
--- a/mp3/screens/Profile/Detail.js
+++ b/mp3/screens/Profile/Detail.js
@@ -1,6 +1,7 @@
 import React, { Component } from 'react';
 import { Button } from 'react-native-elements';
 import PropTypes from 'prop-types';
+import { AsyncStorage } from 'react-native';
 import {
   View,
   Text,
@@ -10,34 +11,46 @@ import {
 
 export default class Detail extends Component {
 
+  _handlePress = (name) => {
+    this.props.navigation.navigate('Profile', {name: name})
+  }
+
   render(){
-    const { repo, followers, following, navigation } = this.props;
+    const { baseUser, userName, repo, followers, following, navigation } = this.props;
 
-    if (repo != 0){
+    if (repo != -1){
       return(
         <View style={styles.detail}>
           <View style={styles.topContainer}>
             <Button
-              title={'REPO\n'+'# '+repo}
+              title={'REPO\n'+'# '+(repo == null ? 0:repo)}
               rounded={true}
               backgroundColor='#58D68D'
               onPress={() => {navigation.navigate('Repo');}}
             />
           </View>
-          <View style={styles.bottomContainer}>
+          <View style={styles.middleContainer}>
             <Button
-              title={'FOLLOWERS\n'+'# '+followers}
+              title={'FOLLOWERS\n'+'# '+(followers == null ? 0:followers)}
               backgroundColor='#F4D03F'
               rounded={true}
               onPress={() => {navigation.navigate('Follower')}}
             />
             <Button
-              title={'FOLLOWING\n'+'# '+following}
+              title={'FOLLOWING\n'+'# '+(following == null ? 0:following)}
               backgroundColor='#EC7063'
               rounded={true}
               onPress={() => {navigation.navigate('Following')}}
             />
           </View>
+          <View style={styles.bottomContainer}>
+            <Button
+              title={'BACK TO ME'}
+              backgroundColor='#5DADE2'
+              rounded={true}
+              onPress={this._handlePress.bind(this, baseUser)}
+            />
+          </View>
         </View>
       );
     } else {
@@ -46,12 +59,6 @@ export default class Detail extends Component {
   }
 }
 
-Detail.propTypes = {
-  repo: PropTypes.number.isRequired,
-  followers: PropTypes.number.isRequired,
-  following: PropTypes.number.isRequired,
-}
-
 const styles = StyleSheet.create({
   detail: {
     flex: 1,
@@ -64,10 +71,14 @@ const styles = StyleSheet.create({
     alignItems: 'center',
     paddingTop: '5%',
   },
-  bottomContainer: {
+  middleContainer: {
     flex: 1,
     flexDirection: 'row',
     alignItems: 'center',
     justifyContent: 'space-evenly',
   },
+  bottomContainer: {
+    alignItems: 'center',
+    paddingVertical: '5%',
+  }
 });
diff --git a/mp3/screens/Profile/Header.js b/mp3/screens/Profile/Header.js
index 1a8758a..1074bec 100644
--- a/mp3/screens/Profile/Header.js
+++ b/mp3/screens/Profile/Header.js
@@ -32,7 +32,7 @@ export default class Header extends Component {
 
 Header.propTypes = {
   profilePic: PropTypes.string.isRequired,
-  name: PropTypes.string.isRequired,
+  // name: PropTypes.string.isRequired, // This is weird, but some people just don't "have" a name.
   userName: PropTypes.string.isRequired,
   createdAt: PropTypes.string.isRequired,
 }
diff --git a/mp3/screens/Profile/Intro.js b/mp3/screens/Profile/Intro.js
index d6b3c7b..1370ab6 100644
--- a/mp3/screens/Profile/Intro.js
+++ b/mp3/screens/Profile/Intro.js
@@ -1,9 +1,11 @@
 import React, { Component } from 'react';
 import PropTypes from 'prop-types';
+import { WebBrowser } from 'expo';
 import {
   View,
   Text,
   StyleSheet,
+  TouchableOpacity,
 } from 'react-native';
 
 export default class Intro extends Component {
@@ -18,7 +20,7 @@ export default class Intro extends Component {
               <Text style={styles.infoTitle}>Bio</Text>
             </View>
             <View style={styles.textContainer}>
-              <Text style={styles.infoText}>{this.props.bio}</Text>
+              <Text>{this.props.bio}</Text>
             </View>
           </View>
           <View style={styles.infoContainer}>
@@ -26,7 +28,9 @@ export default class Intro extends Component {
               <Text style={styles.infoTitle}>Website</Text>
             </View>
             <View style={styles.textContainer}>
-              <Text style={styles.infoText}>{this.props.website}</Text>
+              <TouchableOpacity onPress={() => { WebBrowser.openBrowserAsync(this.props.website);}}>
+                <Text style={styles.infoText}>{this.props.website}</Text>
+              </TouchableOpacity>
             </View>
           </View>
           <View style={styles.infoContainer}>
@@ -34,7 +38,7 @@ export default class Intro extends Component {
               <Text style={styles.infoTitle}>Email</Text>
             </View>
             <View style={styles.textContainer}>
-              <Text style={styles.infoText}>{this.props.email}</Text>
+              <Text>{this.props.email}</Text>
             </View>
           </View>
         </View>
@@ -45,13 +49,6 @@ export default class Intro extends Component {
   }
 }
 
-
-Intro.propTypes = {
-  bio: PropTypes.string.isRequired,
-  website: PropTypes.string.isRequired,
-}
-
-
 const styles = StyleSheet.create({
   intro: {
     flex: 1,
@@ -80,4 +77,7 @@ const styles = StyleSheet.create({
     fontWeight: 'bold',
     paddingHorizontal: 50,
   },
+  infoText: {
+    color: 'blue',
+  }
 });
diff --git a/mp3/screens/Profile/ProfileScreen.js b/mp3/screens/Profile/ProfileScreen.js
index 2352d3b..373494d 100644
--- a/mp3/screens/Profile/ProfileScreen.js
+++ b/mp3/screens/Profile/ProfileScreen.js
@@ -1,5 +1,6 @@
 import React from 'react';
 import axios from 'axios';
+import { AsyncStorage } from 'react-native';
 import {
   ScrollView,
   View,
@@ -7,6 +8,7 @@ import {
   Image,
   StyleSheet,
   Alert,
+  Button,
 } from 'react-native';
 
 import Header from './Header';
@@ -19,32 +21,256 @@ export default class ProfileScreen extends React.Component {
     title: 'Profile',
   }
 
-  state = {
-    profilePic: '',
-    name: '',
-    userName: '',
-    createdAt: '',
-    bio: '',
-    website: '',
-    email: 'curran@datavis.tech',
-    repo: 0,
-    followers: NaN,
-    following: NaN,
+  constructor(props){
+    super(props);
+    this.state = {
+      data: {
+        profilePic: '',
+        name: '',
+        userName: '',
+        createdAt: '',
+        bio: '',
+        website: '',
+        email: 'cs242HW@info.com',
+        repo: -1,
+        followers: -1,
+        following: -1,
+      },
+      baseUser: 'cs242HW',
+    }
+    // this.makeRequest = this.makeRequest.bind(this);
   }
 
   componentDidMount(){
-    axios.get('https://api.github.com/users/curran')
+    this._retrieveData(this.state.baseUser);
+  }
+
+  // makeRequest = (userName) => {
+  //   try {
+  //     const data = this._retrieveData(userName);
+  //     if (data){
+  //       console.log("User data exist!");
+  //     } else {
+  //       // First time fetching user data
+  //       axios.get('https://api.github.com/users/'+userName)
+  //         .then((res) => {
+  //           this.setState({
+  //             data: {
+  //               profilePic: res.data.avatar_url,
+  //               name: res.data.name,
+  //               userName: res.data.login,
+  //               createdAt: res.data.created_at,
+  //               bio: res.data.bio,
+  //               website: res.data.html_url,
+  //               repo: res.data.public_repos,
+  //               followers: res.data.followers,
+  //               following: res.data.following,
+  //             }
+  //           }, () => {
+  //             this._storeData(userName, this.state.data);
+  //           });
+  //         })
+  //         .catch(err => {
+  //           console.log(err);
+  //           Alert.alert("Error occured when making API call!");
+  //         })
+  //
+  //       // First time fetching user repo data
+  //       axios.get('https://api.github.com/users/'+userName+'/repos')
+  //         .then((res) => {
+  //           if (res.length != 0){
+  //             var data = []
+  //             for (var i=0; i<res.data.length; i++){
+  //               const id = res.data[i].id;
+  //               const name = res.data[i].name;
+  //               const owner = res.data[i].owner.login;
+  //               const description = res.data[i].description;
+  //               const url = res.data[i].html_url;
+  //               data.push({id: id, name: name, owner: owner, description: description, url: url})
+  //             }
+  //             this._storeData(userName+'Repos', data);
+  //           }
+  //         })
+  //         .catch(err => {
+  //           console.log(err);
+  //           Alert.alert("Error occured when making API call!");
+  //         })
+  //
+  //       axios.get('https://api.github.com/users/'+userName+'/followers')
+  //         .then((res) => {
+  //           if (res.length != 0){
+  //             var data = []
+  //             for (var i=0; i<res.data.length; i++){
+  //               const id = res.data[i].id;
+  //               const name = res.data[i].login;
+  //               const avatar_url = res.data[i].avatar_url;
+  //               const html_url = res.data[i].html_url;
+  //               const repo = res.data[i].repos_url;
+  //               const followers = res.data[i].followers_url;
+  //               const following = res.data[i].following_url;
+  //               data.push({id: id, name: name, avatar: avatar_url, url: html_url, repo: repo, followers: followers, following: following});
+  //             }
+  //             this._storeData(userName+'Followers', data);
+  //           }
+  //         })
+  //         .catch(err => {
+  //           console.log(err);
+  //         })
+  //
+  //       axios.get('https://api.github.com/users/'+userName+'/following')
+  //         .then((res) => {
+  //           if (res.length != 0){
+  //             var data = []
+  //             for (var i=0; i<res.data.length; i++){
+  //               const id = res.data[i].id;
+  //               const name = res.data[i].login;
+  //               const avatar_url = res.data[i].avatar_url;
+  //               const html_url = res.data[i].html_url;
+  //               data.push({id: id, name: name, avatar: avatar_url, url: html_url})
+  //             }
+  //             this._storeData(userName+'Following', data);
+  //           }
+  //         })
+  //         .catch(err => {
+  //           console.log(err);
+  //         })
+  //     }
+  //   } catch (e) {
+  //     console.log(e.message);
+  //   }
+  // }
+
+  _storeData = async (key, item) => {
+    try {
+      await AsyncStorage.setItem(key, JSON.stringify(item));
+    } catch (e) {
+      console.log(e.message);
+    }
+  }
+
+  _retrieveData = async (key) => {
+    try {
+      const data = await AsyncStorage.getItem(key);
+      console.log("db key: "+key);
+      console.log("db data: "+data);
+      if (data){
+        this.setState({
+          data: JSON.parse(data),
+        });
+      } else {
+        console.log("first time fetching data !");
+        // First time fetching user data
+        axios.get('https://api.github.com/users/'+key)
+          .then((res) => {
+            this.setState({
+              data: {
+                profilePic: res.data.avatar_url,
+                name: res.data.name,
+                userName: res.data.login,
+                createdAt: res.data.created_at,
+                bio: res.data.bio,
+                website: res.data.html_url,
+                repo: res.data.public_repos,
+                followers: res.data.followers,
+                following: res.data.following,
+              }
+            }, () => {
+              this._storeData(key, this.state.data);
+            });
+          })
+          .catch(err => {
+            console.log(err);
+            Alert.alert("Error occured when making API call!");
+          })
+
+        // First time fetching user repo data
+        axios.get('https://api.github.com/users/'+key+'/repos')
+          .then((res) => {
+            if (res.length != 0){
+              var data = []
+              for (var i=0; i<res.data.length; i++){
+                const id = res.data[i].id;
+                const name = res.data[i].name;
+                const owner = res.data[i].owner.login;
+                const description = res.data[i].description;
+                const url = res.data[i].html_url;
+                data.push({id: id, name: name, owner: owner, description: description, url: url})
+              }
+              this._storeData(key+'Repos', data);
+            }
+          })
+          .catch(err => {
+            console.log(err);
+            Alert.alert("Error occured when making API call!");
+          })
+
+        axios.get('https://api.github.com/users/'+key+'/followers')
+          .then((res) => {
+            if (res.length != 0){
+              var data = []
+              for (var i=0; i<res.data.length; i++){
+                const id = res.data[i].id;
+                const name = res.data[i].login;
+                const avatar_url = res.data[i].avatar_url;
+                const html_url = res.data[i].html_url;
+                const repo = res.data[i].repos_url;
+                const followers = res.data[i].followers_url;
+                const following = res.data[i].following_url;
+                data.push({id: id, name: name, avatar: avatar_url, url: html_url, repo: repo, followers: followers, following: following});
+              }
+              this._storeData(key+'Followers', data);
+            }
+          })
+          .catch(err => {
+            console.log(err);
+          })
+
+        axios.get('https://api.github.com/users/'+key+'/following')
+          .then((res) => {
+            if (res.length != 0){
+              var data = []
+              for (var i=0; i<res.data.length; i++){
+                const id = res.data[i].id;
+                const name = res.data[i].login;
+                const avatar_url = res.data[i].avatar_url;
+                const html_url = res.data[i].html_url;
+                data.push({id: id, name: name, avatar: avatar_url, url: html_url})
+              }
+              this._storeData(key+'Following', data);
+            }
+          })
+          .catch(err => {
+            console.log(err);
+          })
+      }
+    } catch (e) {
+      console.log(e.message);
+    }
+  }
+
+  componentWillReceiveProps(nextProps){
+    const userName = nextProps.navigation.getParam('name');
+    console.log('Received name: '+userName);
+    this._retrieveData(userName);
+  }
+
+  _handleRefresh = () => {
+    axios.get('https://api.github.com/users/'+this.state.baseUser)
       .then((res) => {
         this.setState({
-          profilePic: res.data.avatar_url,
-          name: res.data.name,
-          userName: res.data.login,
-          createdAt: res.data.created_at,
-          bio: res.data.bio,
-          website: res.data.html_url,
-          repo: res.data.public_repos,
-          followers: res.data.followers,
-          following: res.data.following,
+          data: {
+            profilePic: res.data.avatar_url,
+            name: res.data.name,
+            userName: res.data.login,
+            createdAt: res.data.created_at,
+            bio: res.data.bio,
+            website: res.data.html_url,
+            repo: res.data.public_repos,
+            followers: res.data.followers,
+            following: res.data.following,
+          }
+        }, () => {
+          this._storeData(this.state.baseUser, this.state.data);
         });
       })
       .catch(err => {
@@ -57,22 +283,30 @@ export default class ProfileScreen extends React.Component {
     return(
       <ScrollView style={styles.profileContainer}>
         <Header
-          profilePic={this.state.profilePic}
-          name={this.state.name}
-          userName={this.state.userName}
-          createdAt={this.state.createdAt}
+          profilePic={this.state.data.profilePic}
+          name={this.state.data.name}
+          userName={this.state.data.userName}
+          createdAt={this.state.data.createdAt}
         />
         <Intro
-          bio={this.state.bio}
-          website={this.state.website}
-          email={this.state.email}
+          bio={this.state.data.bio}
+          website={this.state.data.website}
+          email={this.state.data.email}
         />
         <Detail
-          repo={this.state.repo}
-          followers={this.state.followers}
-          following={this.state.following}
+          baseUser={this.state.baseUser}
+          userName={this.state.userName}
+          repo={this.state.data.repo}
+          followers={this.state.data.followers}
+          following={this.state.data.following}
           navigation={this.props.navigation}
         />
+        <Button
+          onPress={this._handleRefresh.bind(this)}
+          title="REFRESH"
+          color="#CCD1D1"
+          accessibilityLabel="Update My Profile Page"
+        />
       </ScrollView>
     );
   }
diff --git a/mp3/screens/RepoScreen.js b/mp3/screens/RepoScreen.js
index 6742420..2e6e783 100644
--- a/mp3/screens/RepoScreen.js
+++ b/mp3/screens/RepoScreen.js
@@ -1,5 +1,6 @@
 import React from 'react';
 import axios from 'axios';
+import { AsyncStorage } from 'react-native';
 import {
   StyleSheet,
   Text,
@@ -23,54 +24,72 @@ export default class RepoScreen extends React.Component {
       data: [],
       pageNum: 1,
       loading: false,
+      baseUser: 'cs242HW',
     };
     this.makeRequest = this.makeRequest.bind(this);
   }
 
   componentDidMount(){
-    this.makeRequest();
+    this.makeRequest(this.state.baseUser);
   }
 
   _handlePress = (url) => {
     WebBrowser.openBrowserAsync(url);
   }
 
-  _handleLoadMore = () => {
-    let pageNum = this.state.pageNum;
+  _storeData = async (key, item) => {
+    try {
+      await AsyncStorage.setItem(key, JSON.stringify(item));
+    } catch (e) {
+      console.log(e.message);
+    }
+  }
 
-    this.setState({
-      pageNum: pageNum+1
-    }, () => {
-      this.makeRequest();
-    });
+  _retrieveData = async (key) => {
+    try {
+      const data = await AsyncStorage.getItem(key+'Repos');
+      console.log("repo key: "+key+'Repos');
+      console.log("repo data: "+data);
+      if (data){
+        this.setState({
+          data: JSON.parse(data),
+          loading: false,
+        });
+      } else {
+        axios.get('https://api.github.com/users/'+key+'/repos?page='+this.state.pageNum)
+          .then((res) => {
+            if (res.length != 0){
+              var data = []
+              for (var i=0; i<res.data.length; i++){
+                const id = res.data[i].id;
+                const name = res.data[i].name;
+                const owner = res.data[i].owner.login;
+                const description = res.data[i].description;
+                const url = res.data[i].html_url;
+                data.push({id: id, name: name, owner: owner, description: description, url: url})
+              }
+              this.setState({
+                data: data,
+                loading: false,
+              });
+              this._storeData(key+'Repos', data);
+            }
+          })
+          .catch(err => {
+            console.log(err);
+          })
+      }
+    } catch (e) {
+      console.log(e.message);
+    }
   }
 
-  makeRequest = () => {
+  makeRequest = (userName) => {
     this.setState({
       loading: true,
     })
 
-    axios.get('https://api.github.com/users/curran/repos?page='+this.state.pageNum)
-      .then((res) => {
-        if (res.length != 0){
-          var data = []
-          for (var i=0; i<res.data.length; i++){
-            const id = res.data[i].id;
-            const name = res.data[i].name;
-            const owner = res.data[i].owner.login;
-            const description = res.data[i].description;
-            const url = res.data[i].html_url;
-            data.push({id: id, name: name, owner: owner, description: description, url: url})
-          }
-          this.setState({
-            data: data,
-            loading: false,
-          });
-        }
-      })
-      .catch(err => {
-        console.log(err);
-      })
+    this._retrieveData(userName);
   }
 
   renderFooter = () => {
@@ -89,6 +108,19 @@ export default class RepoScreen extends React.Component {
     );
   }
 
+  renderSeparator = () => {
+    return (
+      <View
+        style={{
+          height: 1,
+          backgroundColor: "#CED0CE",
+          marginLeft: "2%",
+          marginRight: "2%",
+        }}
+      />
+    );
+  };
+
   render() {
     return (
       <List containerStyle={{marginTop: 0, borderTopWidth: 0, borderBottomWidth: 0}}>
@@ -108,6 +140,7 @@ export default class RepoScreen extends React.Component {
           )}
           keyExtractor={item => item.id.toString()}
           ListFooterComponent={this.renderFooter}
+          ItemSeparatorComponent={this.renderSeparator}
         />
       </List>
     );
-- 
GitLab