├── .editorconfig ├── .eslintrc ├── .gitignore ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── lerna.json ├── package.json ├── react-progressive-hydration ├── app │ ├── assets │ │ ├── hydrate.jpg │ │ └── hydrate_lg.jpg │ ├── client.js │ ├── components │ │ ├── app.js │ │ ├── counter.js │ │ ├── header.js │ │ ├── hydrator.js │ │ ├── intro.js │ │ └── stream.js │ ├── server.js │ └── style.css ├── babel.config.js ├── data.json ├── package.json ├── server.js └── webpack.config.js ├── react-ssr-data ├── app │ ├── cached-fetch.js │ ├── client.js │ ├── comments.js │ ├── header.js │ ├── index.js │ ├── questions.js │ ├── server.js │ └── style.css ├── package.json └── server │ ├── bundler.js │ └── index.js └── react-streaming-ssr ├── app ├── client.js ├── components │ ├── app.js │ ├── header.js │ └── stream.js ├── server.js └── style.css ├── babel.config.js ├── data.json ├── package.json ├── server.js └── webpack.config.js /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = tab 5 | end_of_line = lf 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true 9 | 10 | [*.md] 11 | trim_trailing_whitespace = false 12 | 13 | [*.json,*.rc,*.yml] 14 | indent_style = space 15 | indent_size = 2 16 | insert_final_newline = false 17 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "developit" 3 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | build 3 | package-lock.json 4 | /.env -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to Contribute 2 | 3 | We'd love to accept your patches and contributions to this project. There are 4 | just a few small guidelines you need to follow. 5 | 6 | ## Contributor License Agreement 7 | 8 | Contributions to this project must be accompanied by a Contributor License 9 | Agreement. You (or your employer) retain the copyright to your contribution, 10 | this simply gives us permission to use and redistribute your contributions as 11 | part of the project. Head over to to see 12 | your current agreements on file or to sign a new one. 13 | 14 | You generally only need to submit a CLA once, so if you've already submitted one 15 | (even if it was for a different project), you probably don't need to do it 16 | again. 17 | 18 | ## Code reviews 19 | 20 | All submissions, including submissions by project members, require review. We 21 | use GitHub pull requests for this purpose. Consult 22 | [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more 23 | information on using pull requests. 24 | 25 | ## Community Guidelines 26 | 27 | This project follows [Google's Open Source Community 28 | Guidelines](https://opensource.google.com/conduct/). -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright 2019 Google Inc. 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Progressive Rendering: Frameworks Samples 2 | 3 | 4 | 5 | ### Installation 6 | 7 | ```sh 8 | git clone git@github.com:GoogleChromeLabs/progressive-rendering-frameworks-samples.git 9 | cd progressive-rendering-frameworks-samples 10 | 11 | npm install 12 | npm run lerna bootstrap 13 | ``` 14 | 15 | ## Run the Progressive Hydration Demo 16 | 17 | ```sh 18 | cd react-progressive-hydration 19 | npm start 20 | ``` 21 | 22 | Now check out the demo on http://localhost:2048! 23 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": [ 3 | "react-*", 4 | "angular-*", 5 | "vue-*" 6 | ], 7 | "version": "0.0.0" 8 | } 9 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "progressive-rendering-frameworks-samples", 3 | "version": "0.0.1", 4 | "scripts": { 5 | "lerna": "lerna", 6 | "bench:streaming": "autocannon http://localhost:2048 && autocannon http://localhost:2048/streaming" 7 | }, 8 | "license": "Apache-2.0", 9 | "devDependencies": { 10 | "lerna": "^3.13.1" 11 | }, 12 | "engines": { 13 | "node": ">=10" 14 | }, 15 | "dependencies": { 16 | "autocannon": "^3.2.1" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /react-progressive-hydration/app/assets/hydrate.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/progressive-rendering-frameworks-samples/82ccd045264753c11966c59bb63dcba76b8b9f5c/react-progressive-hydration/app/assets/hydrate.jpg -------------------------------------------------------------------------------- /react-progressive-hydration/app/assets/hydrate_lg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/progressive-rendering-frameworks-samples/82ccd045264753c11966c59bb63dcba76b8b9f5c/react-progressive-hydration/app/assets/hydrate_lg.jpg -------------------------------------------------------------------------------- /react-progressive-hydration/app/client.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './components/app.js'; 4 | 5 | ReactDOM.hydrate(, window.approot); 6 | -------------------------------------------------------------------------------- /react-progressive-hydration/app/components/app.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Hydrator as ClientHydrator, ServerHydrator } from './hydrator'; 3 | import Intro from './intro'; 4 | import Header from './header'; 5 | 6 | let load = () => import('./stream'); 7 | let Hydrator = ClientHydrator; 8 | 9 | if (typeof window === 'undefined') { 10 | Hydrator = ServerHydrator; 11 | load = () => require('./stream'); 12 | } 13 | 14 | export default function App() { 15 | return ( 16 |
17 |
18 | 19 | 20 | 21 | {/* */} 22 | 23 |
24 | ); 25 | } 26 | -------------------------------------------------------------------------------- /react-progressive-hydration/app/components/counter.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | 3 | export default function CounterButton() { 4 | const [count, setCount] = useState(0); 5 | 6 | return ; 7 | } 8 | -------------------------------------------------------------------------------- /react-progressive-hydration/app/components/header.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from 'react'; 2 | import Counter from './counter'; 3 | 4 | // check if the page is scrolled 5 | const isScrolled = () => typeof window !== 'undefined' && Math.round('scrollY' in window ? window.scrollY : window.pageYOffset) > 0; 6 | 7 | // little helper for global event registration 8 | function useGlobalListener(event, handler) { 9 | useEffect(() => { 10 | addEventListener(event, handler); 11 | return () => removeEventListener(event, handler); 12 | }); 13 | } 14 | 15 | export default function Header() { 16 | const [scrolled, setScrolled] = useState(isScrolled); 17 | useGlobalListener('scroll', () => { 18 | setScrolled(isScrolled()); 19 | }); 20 | 21 | return ( 22 |
23 |

🍔

24 |

Progressive Hydration

25 | 26 |
27 | ); 28 | } -------------------------------------------------------------------------------- /react-progressive-hydration/app/components/hydrator.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | 4 | function interopDefault(mod) { 5 | return mod && mod.default || mod; 6 | } 7 | 8 | export function ServerHydrator({ load, ...props }) { 9 | const Child = interopDefault(load()); 10 | return ( 11 |
12 | 13 |
14 | ); 15 | } 16 | 17 | export class Hydrator extends React.Component { 18 | shouldComponentUpdate() { 19 | return false; 20 | } 21 | 22 | componentDidMount() { 23 | new IntersectionObserver(async ([entry], obs) => { 24 | if (!entry.isIntersecting) return; 25 | obs.unobserve(this.root); 26 | 27 | const { load, ...props } = this.props; 28 | const Child = interopDefault(await load()); 29 | ReactDOM.hydrate(, this.root); 30 | }).observe(this.root); 31 | } 32 | 33 | render() { 34 | return ( 35 |
this.root = c} 37 | dangerouslySetInnerHTML={{ __html: '' }} 38 | suppressHydrationWarning 39 | /> 40 | ); 41 | } 42 | } -------------------------------------------------------------------------------- /react-progressive-hydration/app/components/intro.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export default function Intro() { 4 | return ( 5 |
6 |
7 |

This is an example of how server-side rendered React can enable progressively hydrated experiences.

8 |

Scroll down. The flash of color you see is an indicator of JavaScript being fetched without any direct change to the UI.

9 |
10 | ); 11 | } 12 | -------------------------------------------------------------------------------- /react-progressive-hydration/app/components/stream.js: -------------------------------------------------------------------------------- 1 | import React, { useRef, useEffect } from 'react'; 2 | import DATA from '../../data.json'; 3 | 4 | // function maybeFetch(url, opts) { 5 | // const controller = typeof AbortController!=='undefined' && new AbortController(); 6 | // const req = fetch(url, { 7 | // ...opts, 8 | // signal: controller && controller.signal 9 | // }); 10 | // req.cancel = () => { 11 | // controller && controller.abort(); 12 | // }; 13 | // return req; 14 | // } 15 | 16 | // function usePromise(fetcher, props) { 17 | // const v = useMemo(fetcher, props); 18 | // if ('value' in v) return v.value; 19 | // throw v.then(value => { v.value = value; }); 20 | // } 21 | 22 | // let r; 23 | 24 | // function getData() { 25 | // let [data, set] = useState(); 26 | // let [loading, setLoading] = useState(false); 27 | 28 | // if (data) return data; 29 | // if (loading) return; 30 | // if (typeof window==='undefined') { 31 | // set(data = __non_webpack_require__('../../data.json').map(user => ({ 32 | // id: user.login.uuid, 33 | // username: user.login.username, 34 | // name: user.name.first + ' ' + user.name.last 35 | // }))); 36 | // } 37 | // else { 38 | // setLoading(true); 39 | // fetch('/api/users').then(r => r.json()).then(data => { 40 | // set(data); 41 | // setLoading(false); 42 | // }); 43 | // // r = r || fetch('/api/users').then(r => r.json()); 44 | // // if ('value' in r) return r.value; 45 | // // throw (r.then(v => r.value = v)); 46 | // } 47 | // } 48 | 49 | // export default function Stream() { 50 | // // let [items, setItems] = useState([]); 51 | // // useEffect(() => { 52 | // // const req = maybeFetch('/api'); 53 | // // req.then(r => r.json()).then(setItems); 54 | // // return req.cancel; 55 | // // }, []); 56 | 57 | // const items = DATA.map(user => ({ 58 | // id: user.login.uuid, 59 | // username: user.login.username, 60 | // name: user.name.first + ' ' + user.name.last 61 | // })); 62 | // // const items = getData(); 63 | 64 | // // if (!items) { 65 | // // return
Loading...
; 66 | // // } 67 | 68 | // // let items; 69 | // // if (typeof window==='undefined') { 70 | // // items = __non_webpack_require__('../../data.json').map(user => ({ 71 | // // id: user.login.uuid, 72 | // // username: user.login.username 73 | // // })); 74 | // // } 75 | // // else { 76 | // // items = usePromise(async () => console.log('fetching') || await (await fetch('/api')).json()); 77 | // // } 78 | 79 | // return ( 80 | //
81 | // {items.map((profile, index) => 82 | // 83 | // )} 84 | //
85 | // ); 86 | // } 87 | 88 | export default function Stream() { 89 | const items = DATA.map(user => ({ 90 | id: user.login.uuid, 91 | username: user.login.username, 92 | name: user.name.first + ' ' + user.name.last, 93 | avatar: user.picture.medium 94 | })); 95 | 96 | return ( 97 |
98 | {items.map(profile => 99 | 100 | )} 101 |
102 | ); 103 | } 104 | 105 | 106 | function Profile({ profile }) { 107 | const base = useRef(); 108 | useEffect(() => { 109 | flash(base.current); 110 | }, []); 111 | 112 | return ( 113 |
114 |
115 | avatar 116 |
117 |
118 |
119 |

{profile.name}

120 |

{profile.username}

121 |
122 |
123 |
124 | ); 125 | } 126 | 127 | /** Turn an element purple and then fade out. */ 128 | function flash(element) { 129 | element.style.backgroundColor = '#bd7aff'; 130 | requestAnimationFrame(() => { 131 | requestAnimationFrame(() => { 132 | element.style.transition = 'background-color 2s ease'; 133 | element.style.backgroundColor = 'transparent'; 134 | }); 135 | }); 136 | } 137 | -------------------------------------------------------------------------------- /react-progressive-hydration/app/server.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOMServer from 'react-dom/server'; 3 | import App from './components/app.js'; 4 | 5 | export default async function ssr() { 6 | return ReactDOMServer.renderToNodeStream(); 7 | } 8 | -------------------------------------------------------------------------------- /react-progressive-hydration/app/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 80px 0 0; 4 | font-family: avenir next, avenir, sans-serif; 5 | background: #282a37; 6 | } 7 | 8 | .header { 9 | position: fixed; 10 | left: 0; 11 | top: 0; 12 | width: 100%; 13 | height: 80px; 14 | display: flex; 15 | box-sizing: border-box; 16 | align-items: center; 17 | justify-content: space-between; 18 | background: #282a37; 19 | box-shadow: 0 0 5px rgba(0,0,0,0.7); 20 | padding: 0 20px; 21 | } 22 | 23 | .intro { 24 | display: flex; 25 | flex-direction: column; 26 | align-items: center; 27 | padding-bottom: 30px; 28 | } 29 | 30 | .intro p { 31 | color: #fff; 32 | font-size: 20px; 33 | padding: 0 50px; 34 | } 35 | 36 | .hero { 37 | height: 60vh; 38 | width: 100%; 39 | background-image: url('/assets/hydrate.jpg'); 40 | background-size: cover; 41 | background-position: center; 42 | margin-bottom: 50px; 43 | } 44 | 45 | h1 { 46 | font-size: 38px; 47 | font-weight: normal; 48 | color: #fff; 49 | } 50 | 51 | button { 52 | background: #fff; 53 | padding: 10px; 54 | background: #494c64; 55 | border: 1px solid #181a27; 56 | color: #fff; 57 | font-size: 24px; 58 | font-weight: bold; 59 | width: 2em; 60 | text-align: center; 61 | border-radius: 5px; 62 | cursor: pointer; 63 | } 64 | 65 | .list-group-item { 66 | background: #282a37; 67 | border-bottom: 3px solid #42444f; 68 | display: flex; 69 | align-items: center; 70 | margin-bottom: 10px; 71 | padding: 20px 0; 72 | } 73 | 74 | .list-group-item .name { 75 | color: #fff; 76 | font-size: 20px; 77 | font-weight: 700; 78 | margin-bottom: 2px; 79 | margin-top: 0; 80 | } 81 | 82 | .list-group-item .location { 83 | color: #f1fb8f; 84 | font-size: 16px; 85 | font-weight: 400; 86 | margin: 0; 87 | } 88 | 89 | .list-group-item .avatar { 90 | display: flex; 91 | align-items: center; 92 | justify-content: center; 93 | margin-right: 12px; 94 | } 95 | 96 | .list-group-item .avatar img { 97 | width: 60px; 98 | border-radius: 30px; 99 | border: 1px solid #f0f0f0; 100 | margin-left: 20px; 101 | } 102 | 103 | @media only screen and (max-width: 600px) { 104 | body { 105 | padding-top: 50px; 106 | } 107 | 108 | .header { 109 | height: 50px; 110 | } 111 | 112 | h1 { 113 | font-size: 18px; 114 | } 115 | 116 | .icon { 117 | display: none; 118 | } 119 | 120 | button { 121 | font-size: 14px; 122 | padding: 5px; 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /react-progressive-hydration/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | ['@babel/preset-env', { 4 | useBuiltIns: 'usage', 5 | corejs: 3, 6 | modules: false, 7 | loose: true 8 | }], 9 | '@babel/preset-react' 10 | ], 11 | plugins: [ 12 | '@babel/syntax-dynamic-import' 13 | ] 14 | }; 15 | -------------------------------------------------------------------------------- /react-progressive-hydration/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-progressive-hydration", 3 | "version": "0.0.1", 4 | "main": "server.js", 5 | "scripts": { 6 | "dev": "webpack --hot --watch --info-verbosity none & node -r esm server", 7 | "build": "webpack", 8 | "start": "webpack && node -r esm server" 9 | }, 10 | "dependencies": { 11 | "@babel/plugin-syntax-dynamic-import": "^7.2.0", 12 | "clean-terminal-webpack-plugin": "^2.0.2", 13 | "esm": "^3.2.22", 14 | "express": "^4.16.4", 15 | "node-fetch": "^2.3.0", 16 | "react": "^16.8.6", 17 | "react-dom": "^16.8.6", 18 | "regenerator-runtime": "^0.13.2", 19 | "size-plugin": "^1.2.0", 20 | "webpack-merge": "^4.2.1", 21 | "webpackbar": "^3.2.0" 22 | }, 23 | "devDependencies": { 24 | "@babel/core": "^7.4.4", 25 | "@babel/preset-env": "^7.4.4", 26 | "@babel/preset-react": "^7.0.0", 27 | "babel-loader": "^8.0.5", 28 | "core-js": "^3.0.1", 29 | "webpack": "^4.30.0", 30 | "webpack-cli": "^3.3.1" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /react-progressive-hydration/server.js: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | import fetch from 'node-fetch'; 3 | import express from 'express'; 4 | import ssr from './build/ssr/main.js'; 5 | import DATA from './data.json'; 6 | 7 | global.fetch = function (url, opts) { 8 | if (url[0] == '/') { 9 | let { address, port } = listener.address(); 10 | if (address == '::') address = 'localhost'; 11 | url = `http://${address}:${port}${url}`; 12 | } 13 | return fetch(url, opts); 14 | }; 15 | 16 | const app = express(); 17 | 18 | /** API Proxy */ 19 | app.get('/api/users', (req, res) => { 20 | res.json(DATA.map(user => ({ 21 | id: user.login.uuid, 22 | username: user.login.username, 23 | name: user.name.first + ' ' + user.name.last 24 | }))); 25 | }); 26 | 27 | /** SSR */ 28 | app.get('/', async (request, response) => { 29 | try { 30 | const stream = await ssr({ 31 | url: request.url 32 | }); 33 | // Wait until data starts flowing to send a 200 OK, 34 | // so errors don't trigger "headers already sent". 35 | stream.on('data', function handleData() { 36 | stream.off('data', handleData); 37 | response.writeHead(200, { 38 | 'content-type': 'text/html', 39 | 'content-transfer-encoding': 'chunked', 40 | 'x-content-type-options': 'nosniff' 41 | }); 42 | response.write(``); 43 | response.write(``); 44 | response.write(`
`); 45 | response.flushHeaders(); 46 | }); 47 | await new Promise((resolve, reject) => { 48 | stream.on('error', err => { 49 | stream.unpipe(response); 50 | reject(err); 51 | }); 52 | stream.on('end', () => { 53 | response.write('
'); 54 | resolve(); 55 | }); 56 | stream.pipe(response); 57 | }); 58 | } 59 | catch (err) { 60 | // @see https://twitter.com/_developit/status/1123041336054177792 61 | response.writeHead(500, { 62 | 'content-type': 'text/pain' 63 | }); 64 | response.end(String(err && err.stack || err)); 65 | return; 66 | } 67 | }); 68 | 69 | app.use('/client.js', (req, res) => { 70 | res.redirect('/build/client.js'); 71 | }); 72 | 73 | app.get('/favicon.ico', (req, res) => res.end()); 74 | 75 | app.use(express.static(path.resolve(__dirname, 'app'))); 76 | app.use('/build', express.static(path.resolve(__dirname, 'build'))); 77 | 78 | const listener = app.listen(process.env.PORT || 2048, () => { 79 | console.log('Your app is listening on port ' + listener.address().port); 80 | }); 81 | -------------------------------------------------------------------------------- /react-progressive-hydration/webpack.config.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack'); 2 | const path = require('path'); 3 | const merge = require('webpack-merge'); 4 | const WebpackBar = require('webpackbar'); 5 | const SizePlugin = require('size-plugin'); 6 | const CleanTerminalPlugin = require('clean-terminal-webpack-plugin'); 7 | 8 | const baseConfig = { 9 | context: path.resolve(__dirname, 'app'), 10 | devtool: 'cheap-source-map', 11 | mode: 'production', 12 | stats: { 13 | all: false, 14 | warnings: true, 15 | errors: true, 16 | errorDetails: true 17 | }, 18 | output: { 19 | filename: 'main.js', 20 | chunkFilename: '[name].[contenthash].js' 21 | }, 22 | module: { 23 | rules: [ 24 | { 25 | test: /\.jsx?$/, 26 | exclude: /node_modules/, 27 | loader: 'babel-loader', 28 | options: { 29 | generatorOpts: { 30 | retainLines: true, 31 | compact: true, 32 | shouldPrintComment: c => /^#__PURE__$/.test(c) 33 | } 34 | } 35 | } 36 | ] 37 | }, 38 | watchOptions: { 39 | ignored: /node_modules/ 40 | } 41 | }; 42 | 43 | module.exports = (_, env) => [ 44 | merge(baseConfig, { 45 | name: 'server', 46 | target: 'node', 47 | entry: './server', 48 | optimization: { 49 | minimize: false 50 | }, 51 | output: { 52 | path: path.resolve(__dirname, 'build', 'ssr'), 53 | libraryExport: 'default', 54 | libraryTarget: 'commonjs2' 55 | }, 56 | plugins: [ 57 | new webpack.DefinePlugin({ 58 | 'typeof window': '"undefined"', 59 | 'typeof document': '"undefined"' 60 | }), 61 | new WebpackBar({ name: 'server' }) 62 | ] 63 | }), 64 | merge(baseConfig, { 65 | name: 'client', 66 | entry: './client', 67 | output: { 68 | filename: 'client.js', 69 | path: path.resolve(__dirname, 'build'), 70 | publicPath: '/build/' 71 | }, 72 | plugins: [ 73 | new webpack.DefinePlugin({ 74 | 'typeof window': '"object"', 75 | 'typeof document': '"object"' 76 | }), 77 | new CleanTerminalPlugin({ onlyInWatchMode: true }), 78 | new WebpackBar({ name: 'client' }), 79 | new SizePlugin() 80 | ].filter(Boolean) 81 | }) 82 | ]; 83 | -------------------------------------------------------------------------------- /react-ssr-data/app/cached-fetch.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | export const CACHE = {}; 18 | 19 | let restored = false; 20 | function restore() { 21 | restored = true; 22 | const c = typeof document !== 'undefined' && document.querySelector('script[type="text/props"]'); 23 | if (c) { 24 | const entries = JSON.parse(c.textContent); 25 | for (let i in entries) { 26 | (CACHE[i] = Promise.resolve(entries[i])).value = entries[i]; 27 | } 28 | } 29 | } 30 | 31 | export function getCache(url) { 32 | if (typeof window !== 'undefined' && !restored) restore(); 33 | return CACHE[url] && CACHE[url].value; 34 | } 35 | 36 | export default function cachedFetch(url) { 37 | if (typeof window !== 'undefined' && !restored) restore(); 38 | let req = CACHE[url]; 39 | if (!req) { 40 | req = CACHE[url] = fetch(url).then(r => r.json()).then(value => req.value = value); 41 | } 42 | req.use = withValue; 43 | return req; 44 | } 45 | 46 | function withValue(successCallback, errorCallback) { 47 | if ('value' in this) { 48 | successCallback(this.value); 49 | } 50 | else { 51 | this.then(successCallback, errorCallback); 52 | } 53 | } 54 | 55 | export function collect() { 56 | const keys = Object.keys(CACHE); 57 | return Promise.all(keys.map(c => CACHE[c])) 58 | .then(() => new Promise(r => setTimeout(r, 10))) 59 | .then(() => { 60 | if (Object.keys(CACHE).join() !== keys.join()) { 61 | return collect(); 62 | } 63 | const entries = {}; 64 | for (let i in CACHE) { 65 | entries[i] = CACHE[i].value; 66 | } 67 | return entries; 68 | }); 69 | } 70 | -------------------------------------------------------------------------------- /react-ssr-data/app/client.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | import React from 'react'; 18 | import ReactDOM from 'react-dom'; 19 | import JssProvider from 'react-jss/lib/JssProvider'; 20 | import MuiThemeProvider from '@material-ui/core/styles/MuiThemeProvider'; 21 | import createGenerateClassName from '@material-ui/core/styles/createGenerateClassName'; 22 | import App from './index'; 23 | import { collect } from './cached-fetch'; 24 | 25 | const generateClassName = createGenerateClassName(); 26 | 27 | ReactDOM.hydrate( 28 | 29 | 30 | 31 | 32 | , 33 | window.approot 34 | ); 35 | 36 | collect().then(() => { 37 | requestAnimationFrame(() => { 38 | performance.mark('hydrated'); 39 | performance.measure('hydrated', 'navigationStart', 'hydrated'); 40 | console.log(`Hydrated: ${performance.getEntriesByName('hydrated')[0].duration | 0}ms`); 41 | }); 42 | }); 43 | -------------------------------------------------------------------------------- /react-ssr-data/app/comments.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | import React from 'react'; 18 | import cachedFetch from './cached-fetch'; 19 | 20 | export default class Comments extends React.Component { 21 | componentWillMount() { 22 | this.update(this.props); 23 | } 24 | 25 | componentWillReceiveProps(nextProps) { 26 | this.update(nextProps); 27 | } 28 | 29 | update(props) { 30 | const url = `/api/2.2/questions/${props.question}/comments?order=desc&sort=creation&site=stackoverflow&filter=!6JW86p(KK2A)N`; 31 | cachedFetch(url).use(data => { 32 | this.setState({ data }); 33 | }); 34 | } 35 | 36 | render() { 37 | const { data } = this.state || {}; 38 | 39 | return ( 40 |
41 | {data && data.items.map(item => ( 42 |
43 |
44 |
45 | 46 | {item.owner.display_name} 47 |
48 | 49 |
50 | ))} 51 |
52 | ); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /react-ssr-data/app/header.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import AppBar from '@material-ui/core/AppBar'; 3 | import Toolbar from '@material-ui/core/Toolbar'; 4 | import Typography from '@material-ui/core/Typography'; 5 | import IconButton from '@material-ui/core/IconButton'; 6 | import Button from '@material-ui/core/Button'; 7 | 8 | export default function Header() { 9 | return ( 10 | 11 | 12 | 13 | 🍔 14 | 15 | 16 | 17 | Stack Overthrow 18 | 19 | 20 |
21 | 22 | 23 | 24 | 25 | 26 | ); 27 | } 28 | -------------------------------------------------------------------------------- /react-ssr-data/app/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | import React from 'react'; 18 | import Header from './header'; 19 | import Questions from './questions'; 20 | 21 | export default function App({ url }) { 22 | return ( 23 |
24 |
25 | 30 | 31 |
32 | ); 33 | } 34 | -------------------------------------------------------------------------------- /react-ssr-data/app/questions.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | import React from 'react'; 18 | import Comments from './comments'; 19 | import cachedFetch from './cached-fetch'; 20 | 21 | export default class Questions extends React.Component { 22 | componentWillMount() { 23 | this.update(this.props); 24 | } 25 | 26 | componentDidMount() { 27 | requestAnimationFrame(() => { 28 | performance.mark('interactive'); 29 | performance.measure('interactive', 'navigationStart', 'interactive'); 30 | console.log(`Interactive: ${performance.getEntriesByName('interactive')[0].duration | 0}ms`); 31 | }); 32 | } 33 | 34 | componentWillReceiveProps(nextProps) { 35 | this.update(nextProps); 36 | } 37 | 38 | update(props) { 39 | const url = `/api/2.2/questions?order=desc&sort=activity&tagged=${[].concat(props.tags || []).map(encodeURIComponent).join(',')}&site=stackoverflow`; 40 | cachedFetch(url).use(data => { 41 | this.setState({ data }); 42 | }); 43 | } 44 | 45 | render() { 46 | const { data } = this.state || {}; 47 | const renders = (this.renders = (this.renders || 0) + 1); 48 | 49 | return ( 50 |
51 |
52 | 					Rendered on the {typeof window == 'undefined' ? 'server' : 'client'} ({renders} times)
53 |         
54 | 55 |
56 | {data && data.items.map((item, index) => ( 57 |
58 |

{item.title}

59 |
60 | 61 | {item.owner.display_name} 62 |
63 | {index < 5 && } 64 |
65 | ))} 66 |
67 |
68 | ); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /react-ssr-data/app/server.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | import React from 'react'; 18 | import ReactDOMServer from 'react-dom/server'; 19 | import { SheetsRegistry } from 'jss'; 20 | import JssProvider from 'react-jss/lib/JssProvider'; 21 | import { CACHE, collect } from './cached-fetch.js'; 22 | import App from './index.js'; 23 | import MuiThemeProvider from '@material-ui/core/styles/MuiThemeProvider'; 24 | import createGenerateClassName from '@material-ui/core/styles/createGenerateClassName'; 25 | 26 | // 1: only render the first level of component data depenencies 27 | // 2: render the 1st and 2nd (derivative data) 28 | // etc 29 | const MAX_DEPTH = 2; 30 | 31 | function attempt(App, props, maxDepth = MAX_DEPTH, successHintCallback, depth = 0) { 32 | ReactDOMServer.renderToString(); 33 | return collect().then(cache => { 34 | let html = ReactDOMServer.renderToString(); 35 | if (successHintCallback) { 36 | successHintCallback(html); 37 | } 38 | if (++depth < maxDepth && Object.keys(CACHE).length > Object.keys(cache).length) { 39 | return attempt(App, props, maxDepth, null, depth); 40 | } 41 | return cache; 42 | }); 43 | } 44 | 45 | export default function ssr(props, maxDepth, successHintCallback) { 46 | const sheetsRegistry = new SheetsRegistry(); 47 | const sheetsManager = new Map(); 48 | const ServerApp = (props) => { 49 | const generateClassName = createGenerateClassName(); 50 | sheetsRegistry.reset(); 51 | sheetsManager.clear(); 52 | return ( 53 | 54 | 55 | 56 | 57 | 58 | ); 59 | } 60 | 61 | return attempt(ServerApp, props, maxDepth, successHintCallback).then(cache => { 62 | let html = ReactDOMServer.renderToString(); 63 | if (Object.keys(cache).length > 0) { 64 | html += ``; 65 | } 66 | html = `` + html; 67 | return html; 68 | }); 69 | } 70 | -------------------------------------------------------------------------------- /react-ssr-data/app/style.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | * { 18 | box-sizing: border-box; 19 | } 20 | 21 | html, 22 | body { 23 | margin: 0; 24 | } 25 | 26 | body { 27 | font-family: system-ui, arial, sans-serif; 28 | } 29 | 30 | nav { 31 | display: inline-flex; 32 | background: #eee; 33 | padding: 3px; 34 | align-items: center; 35 | } 36 | 37 | nav a { 38 | padding: 2px; 39 | } 40 | 41 | h1 { 42 | font-size: 120%; 43 | font-style: italic; 44 | color: #373fff; 45 | } 46 | 47 | article { 48 | padding: 10px; 49 | } 50 | 51 | article h4 { 52 | margin: 0; 53 | font-weight: normal; 54 | } 55 | 56 | article h4 a { 57 | color: #373fff; 58 | text-decoration: none; 59 | } 60 | 61 | .author { 62 | display: flex; 63 | margin: 0; 64 | flex-direction: row; 65 | align-items: center; 66 | font-weight: normal; 67 | } 68 | 69 | .author img { 70 | width: 20px; 71 | height: 20px; 72 | border-radius: 50%; 73 | margin: 2px 5px 2px 0; 74 | } 75 | 76 | .comments { 77 | margin: 10px; 78 | font-size: 80%; 79 | } 80 | -------------------------------------------------------------------------------- /react-ssr-data/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-ssr-data", 3 | "version": "0.0.1", 4 | "main": "server.js", 5 | "scripts": { 6 | "start": "node -r esm server" 7 | }, 8 | "dependencies": { 9 | "@babel/plugin-syntax-dynamic-import": "^7.2.0", 10 | "@material-ui/core": "^3.9.3", 11 | "@babel/preset-react": "^7.0.0", 12 | "@babel/preset-env": "^7.4.4", 13 | "@babel/core": "^7.4.4", 14 | "buble": "^0.19.7", 15 | "compression": "^1.7.4", 16 | "esm": "^3.2.22", 17 | "express": "^4.16.4", 18 | "jss": "^9.8.7", 19 | "react-jss": "^8.6.1", 20 | "node-fetch": "^2.3.0", 21 | "react": "^16.8.6", 22 | "react-dom": "^16.8.6", 23 | "rollup": "^1.11.3", 24 | "rollup-plugin-babel": "^4.3.2", 25 | "rollup-plugin-buble": "^0.19.6", 26 | "rollup-plugin-commonjs": "^9.3.1", 27 | "rollup-plugin-node-resolve": "^4.2.3", 28 | "rollup-plugin-replace": "^2.2.0" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /react-ssr-data/server/bundler.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | import { rollup } from 'rollup'; 18 | import buble from 'rollup-plugin-buble'; 19 | // import babel from 'rollup-plugin-babel'; 20 | import replace from 'rollup-plugin-replace'; 21 | import nodeResolve from 'rollup-plugin-node-resolve'; 22 | import commonjs from 'rollup-plugin-commonjs'; 23 | 24 | export function bundle({ entry, cache, format = 'es', nodeModules = true } = {}) { 25 | return rollup({ 26 | input: entry, 27 | plugins: [ 28 | buble({ 29 | exclude: '**/node_modules/**', 30 | transforms: { 31 | asyncAwait: false, 32 | classes: false 33 | } 34 | }), 35 | replace({ 36 | 'process.env.NODE_ENV': JSON.stringify('production') 37 | }), 38 | nodeModules && nodeResolve({}), 39 | nodeModules && commonjs({}) 40 | ].filter(Boolean), 41 | cache 42 | }).then(result => { 43 | cache = result.cache; 44 | return result.generate({ 45 | format, 46 | compact: true, 47 | sourceMap: false 48 | }); 49 | }).then(({ output }) => { 50 | const code = output.filter(o => o.isEntry)[0].code; 51 | return { code, cache }; 52 | }); 53 | } 54 | -------------------------------------------------------------------------------- /react-ssr-data/server/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 | * use this file except in compliance with the License. You may obtain a copy of 6 | * the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | import path from 'path'; 18 | import vm from 'vm'; 19 | import { bundle } from './bundler'; 20 | import fetch from 'node-fetch'; 21 | import express from 'express'; 22 | import compression from 'compression'; 23 | 24 | 25 | const STACK_EXCHANGE_KEY = process.env.STACK_EXCHANGE_KEY; 26 | if (!STACK_EXCHANGE_KEY) { 27 | console.error(` 28 | Error: No Stack Exchange key provided. 29 | Register at https://stackapps.com/apps/oauth/register, 30 | then provide the "Key" value when running: 31 | STACK_EXCHANGE_KEY=abc123 npm start 32 | `); 33 | } 34 | 35 | // Fetch used during SSR that allows requesting from the Express server 36 | function fetchWithLoopback(url, opts) { 37 | if (url[0] == '/') { 38 | let { address, port } = listener.address(); 39 | if (address == '::') address = 'localhost'; 40 | url = `http://${address}:${port}${url}`; 41 | } 42 | return fetch(url, opts); 43 | } 44 | 45 | 46 | const MIMES = { 47 | js: 'application/javascript', 48 | mjs: 'application/javascript', 49 | css: 'text/css', 50 | html: 'text/html' 51 | }; 52 | 53 | const CACHES = new Map(); 54 | 55 | const app = express(); 56 | 57 | app.use(compression()); 58 | 59 | /** SSR */ 60 | app.get('/', async (request, response) => { 61 | const file = path.resolve(__dirname, '..', 'app', 'server.js'); 62 | const { code, cache } = await bundle({ 63 | entry: file, 64 | cache: CACHES.get(file), 65 | format: 'cjs' 66 | }) 67 | CACHES.set(file, cache); 68 | const mod = { exports: {} }; 69 | try { 70 | vm.runInNewContext(code, { 71 | require, 72 | module: mod, 73 | exports: mod.exports, 74 | setTimeout, 75 | clearTimeout, 76 | fetch: fetchWithLoopback 77 | }); 78 | } catch (e) { 79 | console.log('Error running server bundle: ', e); 80 | } 81 | let html; 82 | let sent = false; 83 | const ready = () => { 84 | if (sent) return; 85 | sent = true; 86 | response.writeHead(200); 87 | response.write( 88 | ` 89 | 90 | 91 | 92 | ` 93 | ); 94 | }; 95 | try { 96 | const render = mod.exports && mod.exports.default || mod.exports; 97 | html = await render({ 98 | url: request.url 99 | }, request.query.depth, ready); 100 | } catch (e) { console.log(e); } 101 | ready(); 102 | response.end(`
${html}
`); 103 | }); 104 | 105 | app.use('/', (req, res, next) => { 106 | const url = req.url.replace(/[^/]+\/\.\.(\/|$)/g, '$1'); 107 | const file = path.resolve(__dirname, '..', 'app', url.substring(1)); 108 | const ext = (file.match(/\.([a-z0-9]+)$/) || [])[1]; 109 | 110 | // only process JS files: 111 | if (ext !== 'js' && ext !== 'mjs') return next(); 112 | 113 | const start = Date.now(); 114 | const cache = CACHES.get(file); 115 | bundle({ entry: file, cache }).then(({ code, cache }) => { 116 | CACHES.set(file, cache); 117 | res.writeHead(200, { 118 | 'content-type': MIMES[ext], 119 | 'x-bundle-time': Date.now() - start 120 | }); 121 | res.end(code); 122 | }); 123 | }); 124 | 125 | app.use(express.static(path.resolve(__dirname, '..', 'app'))); 126 | 127 | app.get('/favicon.ico', (req, res) => res.end()); 128 | 129 | /** API Proxy */ 130 | app.use('/api', (req, res, next) => { 131 | const url = new URL(req.url, 'https://api.stackexchange.com'); 132 | const params = new URLSearchParams(url.search); 133 | params.set('key', STACK_EXCHANGE_KEY); 134 | url.search = params; 135 | const headers = {}; 136 | for (let i in req.headers) if (i != 'host' && i != 'cookie') headers[i] = req.headers[i]; 137 | fetch(url.href, { 138 | method: req.method, 139 | body: req.body, 140 | headers 141 | }).then(r => { 142 | res.writeHead(r.status, res.headers); 143 | r.body.pipe(res); 144 | }).catch(next); 145 | }); 146 | 147 | const listener = app.listen(process.env.PORT || 2048, () => { 148 | console.log('Your app is listening on port ' + listener.address().port); 149 | }); 150 | -------------------------------------------------------------------------------- /react-streaming-ssr/app/client.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './components/app'; 4 | 5 | ReactDOM.hydrate(, window.approot); 6 | -------------------------------------------------------------------------------- /react-streaming-ssr/app/components/app.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Stream from './stream'; 3 | import Header from './header'; 4 | 5 | const Suspense = typeof window==='undefined' ? p => p.children : React.Suspense; 6 | 7 | export default function App () { 8 | return ( 9 |
10 |
11 | loading
}> 12 | {new Array(100).fill().map(() => )} 13 | 14 |
15 | ); 16 | } 17 | -------------------------------------------------------------------------------- /react-streaming-ssr/app/components/header.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export default function Header() { 4 | return ( 5 |
6 |

Streaming SSR

7 |
8 | ); 9 | } -------------------------------------------------------------------------------- /react-streaming-ssr/app/components/stream.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | let r; 4 | 5 | function getData() { 6 | if (typeof window==='undefined') { 7 | // during SSR, load data from a file synchronously: 8 | return __non_webpack_require__('../../data.json').map(user => ({ 9 | id: user.login.uuid, 10 | username: user.login.username, 11 | name: user.name.first + ' ' + user.name.last 12 | })); 13 | } 14 | else { 15 | // at runtime, request via the API: 16 | r = r || fetch('/api/users').then(r => r.json()); 17 | if ('value' in r) return r.value; 18 | // throw a Promise to re-render once available: 19 | throw (r.then(v => r.value = v)); 20 | } 21 | } 22 | 23 | export default function Stream() { 24 | const items = getData(); 25 | 26 | return ( 27 |
28 | {items.map(profile => 29 | 30 | )} 31 |
32 | ); 33 | } 34 | 35 | function Profile({ profile }) { 36 | return ( 37 |
38 |

{profile.name}

39 |
{profile.username}
40 |
41 | ); 42 | } 43 | -------------------------------------------------------------------------------- /react-streaming-ssr/app/server.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOMServer from 'react-dom/server'; 3 | import App from './components/app'; 4 | 5 | export default async function ssr({ streaming, ...props }) { 6 | if (streaming) { 7 | return ReactDOMServer.renderToNodeStream(); 8 | } 9 | else { 10 | return ReactDOMServer.renderToString(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /react-streaming-ssr/app/style.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | margin: 0; 3 | font: 16px/1.3 system-ui,sans-serif; 4 | } 5 | 6 | .header { 7 | background: #eee; 8 | } 9 | 10 | h1 { 11 | font-size: 150%; 12 | color: #555; 13 | } 14 | 15 | .profile { 16 | background: #eee; 17 | padding: 5px; 18 | margin: 5px; 19 | } 20 | .profile h4 { 21 | margin: 0; 22 | } 23 | .profile h5 { 24 | margin: 5px 0 0; 25 | } 26 | -------------------------------------------------------------------------------- /react-streaming-ssr/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | ['@babel/preset-env', { 4 | useBuiltIns: 'usage', 5 | corejs: 3, 6 | modules: false, 7 | loose: true 8 | }], 9 | '@babel/preset-react' 10 | ] 11 | }; 12 | -------------------------------------------------------------------------------- /react-streaming-ssr/data.json: -------------------------------------------------------------------------------- 1 | [{"gender":"male","name":{"title":"mr","first":"peter","last":"holt"},"location":{"street":"9374 karen dr","city":"cary","state":"alabama","postcode":25967,"coordinates":{"latitude":"6.4163","longitude":"-168.3884"},"timezone":{"offset":"-1:00","description":"Azores, Cape Verde Islands"}},"email":"peter.holt@example.com","login":{"uuid":"c66e6202-b956-4f77-a15e-9c0730df7763","username":"goldentiger659","password":"alatam","salt":"RJvA9BBy","md5":"63a2930a91585b5855e2b3f65e459315","sha1":"f0fe6c968d3466736d1151a07371835e2e6316ee","sha256":"cd518367ab4e6f1c4b5e144fd3d344583cc6db7af57c9ba85ed031f476f3eb40"},"dob":{"date":"1987-05-05T00:15:09Z","age":31},"registered":{"date":"2002-04-29T02:01:28Z","age":16},"phone":"(108)-944-3293","cell":"(203)-300-9236","id":{"name":"SSN","value":"807-74-4308"},"picture":{"large":"https://randomuser.me/api/portraits/men/45.jpg","medium":"https://randomuser.me/api/portraits/med/men/45.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/45.jpg"},"nat":"US"},{"gender":"female","name":{"title":"miss","first":"savannah","last":"rose"},"location":{"street":"6841 stevens creek blvd","city":"davenport","state":"west virginia","postcode":92609,"coordinates":{"latitude":"89.6220","longitude":"-63.8521"},"timezone":{"offset":"+5:30","description":"Bombay, Calcutta, Madras, New Delhi"}},"email":"savannah.rose@example.com","login":{"uuid":"405601f3-4ad1-4bb7-b60e-2ddc3bac3fe1","username":"orangesnake155","password":"trident","salt":"eSNAj7EX","md5":"70b8682060eea1753ba06a0d96df9f23","sha1":"f261eea6e7dedf248d2d2eff45328e075caabc04","sha256":"97064ca954dad86b7258f8d7e3630a57d14a2a99a1bbc3d6a5730cf75a166b60"},"dob":{"date":"1964-07-30T10:37:37Z","age":54},"registered":{"date":"2018-06-02T11:19:03Z","age":0},"phone":"(562)-728-0376","cell":"(723)-309-0741","id":{"name":"SSN","value":"657-25-1770"},"picture":{"large":"https://randomuser.me/api/portraits/women/79.jpg","medium":"https://randomuser.me/api/portraits/med/women/79.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/79.jpg"},"nat":"US"},{"gender":"male","name":{"title":"mr","first":"leslie","last":"austin"},"location":{"street":"3409 hickory creek dr","city":"columbus","state":"new mexico","postcode":40281,"coordinates":{"latitude":"39.2661","longitude":"50.8485"},"timezone":{"offset":"+6:00","description":"Almaty, Dhaka, Colombo"}},"email":"leslie.austin@example.com","login":{"uuid":"62f7ce8d-06fd-49a3-b4c1-5c9c3550e0b7","username":"browngorilla470","password":"keller","salt":"AjZbXG3O","md5":"6efe8715d9510f4c5c809098437fab83","sha1":"0884dc38fa5c2ae7e6946e5fe0525a48718aa16c","sha256":"4790e400a08085ce655476523db6561a2f3fd681b9a027b0ea9b7f379f24218d"},"dob":{"date":"1968-10-04T17:01:24Z","age":50},"registered":{"date":"2014-06-10T06:34:30Z","age":4},"phone":"(920)-031-4235","cell":"(682)-375-5244","id":{"name":"SSN","value":"073-47-3416"},"picture":{"large":"https://randomuser.me/api/portraits/men/66.jpg","medium":"https://randomuser.me/api/portraits/med/men/66.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/66.jpg"},"nat":"US"},{"gender":"female","name":{"title":"ms","first":"carmen","last":"rodriquez"},"location":{"street":"5716 hogan st","city":"santa clara","state":"michigan","postcode":11032,"coordinates":{"latitude":"-61.0681","longitude":"37.2308"},"timezone":{"offset":"-10:00","description":"Hawaii"}},"email":"carmen.rodriquez@example.com","login":{"uuid":"9b381cb0-b390-4c55-b956-2d0c8ea83667","username":"lazyzebra943","password":"defiant","salt":"3y3e1kLW","md5":"f2776213eae1e9d4894fd2145bae7038","sha1":"5b3f13857b7fb132c2ee0e59465a60e16bd42a5d","sha256":"ebf38fa2ff3f9905f33caeb96b9294a0de440eecc8bf53f8dee5f91527b5d2a8"},"dob":{"date":"1990-02-04T06:26:52Z","age":29},"registered":{"date":"2010-01-13T03:53:52Z","age":9},"phone":"(591)-942-9269","cell":"(917)-090-2547","id":{"name":"SSN","value":"408-71-1708"},"picture":{"large":"https://randomuser.me/api/portraits/women/81.jpg","medium":"https://randomuser.me/api/portraits/med/women/81.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/81.jpg"},"nat":"US"},{"gender":"female","name":{"title":"ms","first":"miriam","last":"willis"},"location":{"street":"5097 e little york rd","city":"tucson","state":"california","postcode":17396,"coordinates":{"latitude":"45.4474","longitude":"57.8593"},"timezone":{"offset":"+4:30","description":"Kabul"}},"email":"miriam.willis@example.com","login":{"uuid":"e4005264-58ad-444c-8846-60c57c672a6b","username":"tinybear794","password":"thegreat","salt":"fNkJRBsw","md5":"59f1962b55c365c40d6a24bf3421676f","sha1":"74939949ee19cd635deea1a159566d1cea39f59e","sha256":"df4b30ba836306f1ed87a65c0bd608d51cfe2c0deb305b49065c24f853ae5190"},"dob":{"date":"1984-07-02T10:17:03Z","age":34},"registered":{"date":"2006-07-28T07:49:14Z","age":12},"phone":"(650)-339-9027","cell":"(919)-235-1560","id":{"name":"SSN","value":"964-66-6924"},"picture":{"large":"https://randomuser.me/api/portraits/women/49.jpg","medium":"https://randomuser.me/api/portraits/med/women/49.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/49.jpg"},"nat":"US"},{"gender":"male","name":{"title":"mr","first":"elijah","last":"sims"},"location":{"street":"6107 locust rd","city":"fargo","state":"colorado","postcode":47703,"coordinates":{"latitude":"-62.6944","longitude":"101.2222"},"timezone":{"offset":"-6:00","description":"Central Time (US & Canada), Mexico City"}},"email":"elijah.sims@example.com","login":{"uuid":"f196c60e-6e1d-429c-87fe-d7d8f2f74e49","username":"brownladybug752","password":"konyor","salt":"g517B5lj","md5":"d2fa68d5124c58d0765860cd2a00e987","sha1":"fe9e74ae41477741ff2e163c355d49d41cf66107","sha256":"946bd0b767a1f499e4f6c3c45092d127f6ac610be12aa93b0b96a7dd9b68cab7"},"dob":{"date":"1974-10-11T21:02:45Z","age":44},"registered":{"date":"2011-04-06T17:28:50Z","age":8},"phone":"(367)-722-5688","cell":"(922)-906-7127","id":{"name":"SSN","value":"696-86-1229"},"picture":{"large":"https://randomuser.me/api/portraits/men/76.jpg","medium":"https://randomuser.me/api/portraits/med/men/76.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/76.jpg"},"nat":"US"},{"gender":"male","name":{"title":"mr","first":"darrell","last":"gomez"},"location":{"street":"4325 mcgowen st","city":"temecula","state":"wisconsin","postcode":56984,"coordinates":{"latitude":"81.2396","longitude":"168.5563"},"timezone":{"offset":"+6:00","description":"Almaty, Dhaka, Colombo"}},"email":"darrell.gomez@example.com","login":{"uuid":"2b0f0487-c70d-4b22-b1d0-fbfaa83e111a","username":"beautifulduck810","password":"catfish","salt":"EiVqOJId","md5":"1bdea1228e307e282ec4720860b97637","sha1":"360971031712db52ec9216cca5a93d983ccad4d5","sha256":"3b93d231d5b30276f70d09a6a90065dfeeadb810516f1d3649aeac4ee3251568"},"dob":{"date":"1977-11-05T22:55:55Z","age":41},"registered":{"date":"2015-10-20T09:35:11Z","age":3},"phone":"(770)-279-2459","cell":"(268)-155-7648","id":{"name":"SSN","value":"335-67-8375"},"picture":{"large":"https://randomuser.me/api/portraits/men/31.jpg","medium":"https://randomuser.me/api/portraits/med/men/31.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/31.jpg"},"nat":"US"},{"gender":"male","name":{"title":"mr","first":"keith","last":"mccoy"},"location":{"street":"3296 locust rd","city":"san antonio","state":"rhode island","postcode":91846,"coordinates":{"latitude":"-59.9173","longitude":"28.1810"},"timezone":{"offset":"-10:00","description":"Hawaii"}},"email":"keith.mccoy@example.com","login":{"uuid":"b745ee0c-c48a-4805-9ff0-3be2f34929a0","username":"angryfrog294","password":"123abc","salt":"FWtJwoN2","md5":"5a654cf05e636228adaf7bba1c6c8bba","sha1":"a14894ab7018c84c1e0732a69b90d212b2605046","sha256":"ae38aff230a2cbf43843e078929d5d4de18e5c1cd2444a1d16f30bcb8409edd4"},"dob":{"date":"1986-01-12T13:28:30Z","age":33},"registered":{"date":"2006-07-31T10:32:14Z","age":12},"phone":"(605)-340-2238","cell":"(158)-236-0717","id":{"name":"SSN","value":"360-43-7632"},"picture":{"large":"https://randomuser.me/api/portraits/men/85.jpg","medium":"https://randomuser.me/api/portraits/med/men/85.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/85.jpg"},"nat":"US"},{"gender":"male","name":{"title":"mr","first":"marc","last":"kuhn"},"location":{"street":"982 blossom hill rd","city":"el monte","state":"virginia","postcode":74394,"coordinates":{"latitude":"73.7895","longitude":"58.1127"},"timezone":{"offset":"-3:00","description":"Brazil, Buenos Aires, Georgetown"}},"email":"marc.kuhn@example.com","login":{"uuid":"79aaf377-14d3-4974-961e-df7e32837b98","username":"whiteswan859","password":"felicia","salt":"eB9PIigi","md5":"971b0d7daf881cb325f667f351c10432","sha1":"88da4746d657b6cdd72751f481adbe2928f8a119","sha256":"091b0d0daf6c78130a12a1ad014b0daea1c0a2cc01328a222d07ade0e79b4923"},"dob":{"date":"1950-07-25T03:51:32Z","age":68},"registered":{"date":"2008-07-23T19:46:45Z","age":10},"phone":"(984)-721-7219","cell":"(199)-218-9513","id":{"name":"SSN","value":"003-43-7449"},"picture":{"large":"https://randomuser.me/api/portraits/men/34.jpg","medium":"https://randomuser.me/api/portraits/med/men/34.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/34.jpg"},"nat":"US"},{"gender":"female","name":{"title":"miss","first":"wilma","last":"adams"},"location":{"street":"73 harrison ct","city":"round rock","state":"new hampshire","postcode":17693,"coordinates":{"latitude":"47.9294","longitude":"-46.8024"},"timezone":{"offset":"-12:00","description":"Eniwetok, Kwajalein"}},"email":"wilma.adams@example.com","login":{"uuid":"9bb3389d-df33-4f19-b23c-afaca143fa33","username":"silverpeacock175","password":"grateful","salt":"DdQKc0zQ","md5":"977b496290e29a6a56d0a4b936720e6d","sha1":"3773859005a1fab69c5f8b9740c2a675d2adc60c","sha256":"70f6c9f2177304ada9dd74400c04fdf9edca4c448ae71ad4fb8d3e16a086e85b"},"dob":{"date":"1994-01-12T22:34:29Z","age":25},"registered":{"date":"2008-03-30T19:49:54Z","age":11},"phone":"(336)-695-6705","cell":"(911)-456-6233","id":{"name":"SSN","value":"887-56-8945"},"picture":{"large":"https://randomuser.me/api/portraits/women/4.jpg","medium":"https://randomuser.me/api/portraits/med/women/4.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/4.jpg"},"nat":"US"},{"gender":"male","name":{"title":"mr","first":"edgar","last":"long"},"location":{"street":"8711 w sherman dr","city":"sterling heights","state":"michigan","postcode":98939,"coordinates":{"latitude":"-34.3057","longitude":"98.8124"},"timezone":{"offset":"+7:00","description":"Bangkok, Hanoi, Jakarta"}},"email":"edgar.long@example.com","login":{"uuid":"67ef872c-4a98-4030-bcad-5cc03cf478f4","username":"silverfrog889","password":"13579","salt":"pmynnp0u","md5":"76fe84d68bf970f6f06885d6415bb42f","sha1":"9ba24a078bdbcd21b74e901720798d9477a01e62","sha256":"ec8656a5a8d6e54f7e45fcf750ec430182ed9282584064c94b8431527b8114ad"},"dob":{"date":"1985-07-15T18:32:09Z","age":33},"registered":{"date":"2015-10-05T17:09:54Z","age":3},"phone":"(437)-611-8407","cell":"(299)-020-2007","id":{"name":"SSN","value":"139-41-5825"},"picture":{"large":"https://randomuser.me/api/portraits/men/4.jpg","medium":"https://randomuser.me/api/portraits/med/men/4.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/4.jpg"},"nat":"US"},{"gender":"female","name":{"title":"ms","first":"beverly","last":"black"},"location":{"street":"8015 spring st","city":"st. petersburg","state":"illinois","postcode":58164,"coordinates":{"latitude":"20.7613","longitude":"109.1629"},"timezone":{"offset":"-8:00","description":"Pacific Time (US & Canada)"}},"email":"beverly.black@example.com","login":{"uuid":"288bb6d5-68ab-4d6b-8819-9157cce8c495","username":"angrybear341","password":"wingman","salt":"TxwU9LyO","md5":"363d73b4bf5b0140465cf8d5dd68b60c","sha1":"d282dd9947a72eafb21a0ae764f62f67263b1354","sha256":"617543863a3720e47368efc76ab1ee7b3fec0929683fb9190973dece2664771c"},"dob":{"date":"1996-11-17T19:43:38Z","age":22},"registered":{"date":"2009-02-17T03:50:13Z","age":10},"phone":"(641)-662-5953","cell":"(830)-190-4572","id":{"name":"SSN","value":"250-69-6519"},"picture":{"large":"https://randomuser.me/api/portraits/women/5.jpg","medium":"https://randomuser.me/api/portraits/med/women/5.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/5.jpg"},"nat":"US"},{"gender":"male","name":{"title":"mr","first":"gerald","last":"harper"},"location":{"street":"7570 saddle dr","city":"flint","state":"nevada","postcode":50080,"coordinates":{"latitude":"-49.2296","longitude":"48.3310"},"timezone":{"offset":"-11:00","description":"Midway Island, Samoa"}},"email":"gerald.harper@example.com","login":{"uuid":"d0053c4d-a085-4704-86d3-8e36a1b2c491","username":"heavymeercat536","password":"private1","salt":"PDBEL0bS","md5":"b6e4978049cde483dd553eef67b2c102","sha1":"c5101ae7c0817202bd06830d34d50be11a2a3884","sha256":"db4b794a43f247aded33be28d3d34e3fe45ee801277ed957360dc1a626b54649"},"dob":{"date":"1975-03-15T12:57:49Z","age":44},"registered":{"date":"2013-11-22T20:59:21Z","age":5},"phone":"(000)-422-5923","cell":"(101)-958-6481","id":{"name":"SSN","value":"234-86-7953"},"picture":{"large":"https://randomuser.me/api/portraits/men/91.jpg","medium":"https://randomuser.me/api/portraits/med/men/91.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/91.jpg"},"nat":"US"},{"gender":"male","name":{"title":"mr","first":"ben","last":"berry"},"location":{"street":"6958 dogwood ave","city":"albuquerque","state":"ohio","postcode":84185,"coordinates":{"latitude":"-2.4741","longitude":"-42.9490"},"timezone":{"offset":"-10:00","description":"Hawaii"}},"email":"ben.berry@example.com","login":{"uuid":"bb5494a8-5104-4eb1-bfa8-2125fdd165ed","username":"silverzebra929","password":"weed","salt":"VF403mUX","md5":"bc16e09bbd75e192d42aba50c7174fc7","sha1":"12589b673b94b823eb8fc4b532378a4c697be673","sha256":"c224e02035c360323ed1244450dd4a1b225a78cc5118f73d930fa1b576c873cc"},"dob":{"date":"1945-09-20T05:17:48Z","age":73},"registered":{"date":"2017-08-08T15:12:08Z","age":1},"phone":"(483)-089-0315","cell":"(880)-170-8621","id":{"name":"SSN","value":"228-74-3700"},"picture":{"large":"https://randomuser.me/api/portraits/men/58.jpg","medium":"https://randomuser.me/api/portraits/med/men/58.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/58.jpg"},"nat":"US"},{"gender":"female","name":{"title":"ms","first":"marlene","last":"ellis"},"location":{"street":"9762 wycliff ave","city":"aubrey","state":"vermont","postcode":48109,"coordinates":{"latitude":"-14.0429","longitude":"102.9738"},"timezone":{"offset":"-3:30","description":"Newfoundland"}},"email":"marlene.ellis@example.com","login":{"uuid":"32c32e1f-f32e-4f91-8005-75b66f9af030","username":"tinymeercat398","password":"1015","salt":"shQAsjgV","md5":"89151278e316260216e351fe4fe34aca","sha1":"5a5ac4887357f02494b15dc6f26df54f257e18fa","sha256":"87a4ac31cdde18e3b6060f0d20ffcfc02cfbd642ff8c98b1413b595f39064757"},"dob":{"date":"1976-07-21T05:02:41Z","age":42},"registered":{"date":"2015-03-10T21:35:34Z","age":4},"phone":"(708)-290-7589","cell":"(483)-046-9067","id":{"name":"SSN","value":"262-85-8871"},"picture":{"large":"https://randomuser.me/api/portraits/women/83.jpg","medium":"https://randomuser.me/api/portraits/med/women/83.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/83.jpg"},"nat":"US"},{"gender":"male","name":{"title":"mr","first":"bruce","last":"shaw"},"location":{"street":"191 bruce st","city":"fremont","state":"vermont","postcode":91624,"coordinates":{"latitude":"-88.6971","longitude":"-54.5769"},"timezone":{"offset":"+3:30","description":"Tehran"}},"email":"bruce.shaw@example.com","login":{"uuid":"c9170a90-f6a6-4bb1-a505-599e89b08f23","username":"crazypeacock436","password":"catcher","salt":"w4xZz1Lu","md5":"d1a9d16067934f1f3b935a154e47eae9","sha1":"241d5956cececea5e3b7a8bebafcf82c5f06afa4","sha256":"1ad2e62e5898a1044e5d74d0c0417d0b815e061c71ea14f607d0631e9222add5"},"dob":{"date":"1980-02-19T08:26:03Z","age":39},"registered":{"date":"2013-05-05T17:14:35Z","age":5},"phone":"(405)-993-3336","cell":"(432)-941-1398","id":{"name":"SSN","value":"724-33-2629"},"picture":{"large":"https://randomuser.me/api/portraits/men/8.jpg","medium":"https://randomuser.me/api/portraits/med/men/8.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/8.jpg"},"nat":"US"},{"gender":"male","name":{"title":"mr","first":"luke","last":"ward"},"location":{"street":"4990 mockingbird hill","city":"fullerton","state":"kentucky","postcode":19987,"coordinates":{"latitude":"-2.3947","longitude":"32.8776"},"timezone":{"offset":"-6:00","description":"Central Time (US & Canada), Mexico City"}},"email":"luke.ward@example.com","login":{"uuid":"a9455deb-8aee-469d-a48c-ded6f336333f","username":"smallmeercat663","password":"bowman","salt":"Pqa6MFiL","md5":"8109a5a6ebd26d3f33cbcbfe13be3cae","sha1":"87d752c3c5ff32132aabb322b591f793f0c01d6e","sha256":"ef16f63a0c3ca40c4caba77f1b971f6031d0da56d7acb81258dc9548969cb86c"},"dob":{"date":"1959-11-22T18:24:54Z","age":59},"registered":{"date":"2013-11-11T07:31:19Z","age":5},"phone":"(996)-371-1796","cell":"(994)-889-9230","id":{"name":"SSN","value":"229-21-9698"},"picture":{"large":"https://randomuser.me/api/portraits/men/90.jpg","medium":"https://randomuser.me/api/portraits/med/men/90.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/90.jpg"},"nat":"US"},{"gender":"male","name":{"title":"mr","first":"ray","last":"hughes"},"location":{"street":"7606 frances ct","city":"santa clara","state":"mississippi","postcode":25869,"coordinates":{"latitude":"-31.1970","longitude":"-173.1455"},"timezone":{"offset":"+6:00","description":"Almaty, Dhaka, Colombo"}},"email":"ray.hughes@example.com","login":{"uuid":"c5ecd075-c912-4d70-83ee-041410b25f72","username":"bluesnake207","password":"5555555","salt":"uuyoGNp9","md5":"177567c5dfca0ddd04d1016ab4c05a02","sha1":"04024789e00990d8fe54ecaebfa54250b6b1a25a","sha256":"a11a876e5c74a404d2b6bf676bd1463ccb6c5e4c265fc028665864366090edbc"},"dob":{"date":"1975-07-24T09:13:46Z","age":43},"registered":{"date":"2010-08-08T05:55:53Z","age":8},"phone":"(995)-461-8871","cell":"(258)-092-5172","id":{"name":"SSN","value":"595-86-5705"},"picture":{"large":"https://randomuser.me/api/portraits/men/8.jpg","medium":"https://randomuser.me/api/portraits/med/men/8.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/8.jpg"},"nat":"US"},{"gender":"male","name":{"title":"mr","first":"jerome","last":"may"},"location":{"street":"6409 hamilton ave","city":"moscow","state":"massachusetts","postcode":37875,"coordinates":{"latitude":"17.4409","longitude":"116.0623"},"timezone":{"offset":"+2:00","description":"Kaliningrad, South Africa"}},"email":"jerome.may@example.com","login":{"uuid":"390811a2-ccd4-48b6-9bf9-6af004f60a72","username":"silverleopard846","password":"qweasd","salt":"h9hCFk97","md5":"a866486950e1d3f7d95d0b45518f3499","sha1":"ac9ce1488c4172bc0f01c290e9ea4f997e3d7dd9","sha256":"465d2077491ed2f5873623392f90b7470bdba48cd9769bab03cb0da0fa9765dc"},"dob":{"date":"1982-03-26T21:57:17Z","age":37},"registered":{"date":"2017-04-14T04:15:55Z","age":2},"phone":"(621)-202-9377","cell":"(309)-672-6089","id":{"name":"SSN","value":"893-00-6285"},"picture":{"large":"https://randomuser.me/api/portraits/men/91.jpg","medium":"https://randomuser.me/api/portraits/med/men/91.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/91.jpg"},"nat":"US"},{"gender":"male","name":{"title":"mr","first":"lewis","last":"hopkins"},"location":{"street":"4610 harrison ct","city":"flowermound","state":"georgia","postcode":11452,"coordinates":{"latitude":"27.3190","longitude":"50.8528"},"timezone":{"offset":"-3:30","description":"Newfoundland"}},"email":"lewis.hopkins@example.com","login":{"uuid":"38e96d50-1e17-49c3-b80a-ea82f35650cb","username":"angrygoose456","password":"13131313","salt":"9vd5rX8i","md5":"85a6567e82d78fddd5eb75e67f7134b8","sha1":"8675f5e5d61dd6e9a80ab92df55b44ea4150b5d7","sha256":"ae1b5c91c25d40042a525a591ed4cbba349599581bf1b5f9e8eaede92d8df5de"},"dob":{"date":"1978-06-07T22:30:22Z","age":40},"registered":{"date":"2002-10-06T04:17:12Z","age":16},"phone":"(019)-924-0620","cell":"(786)-465-8423","id":{"name":"SSN","value":"982-16-9481"},"picture":{"large":"https://randomuser.me/api/portraits/men/31.jpg","medium":"https://randomuser.me/api/portraits/med/men/31.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/31.jpg"},"nat":"US"},{"gender":"female","name":{"title":"ms","first":"bobbie","last":"ruiz"},"location":{"street":"7728 paddock way","city":"allentown","state":"maine","postcode":16964,"coordinates":{"latitude":"-33.8008","longitude":"17.2275"},"timezone":{"offset":"0:00","description":"Western Europe Time, London, Lisbon, Casablanca"}},"email":"bobbie.ruiz@example.com","login":{"uuid":"7a7779f0-bb79-479b-a000-7438e35211e8","username":"blueladybug787","password":"suan","salt":"Qm91hLPc","md5":"5c687bb4b8adc5eaa6ea36ccb953dc2c","sha1":"d702eb1c63c62775a26016e56a35067b856aae1d","sha256":"4f7dbbd1baf00f7eaa026ef54e2dac3e0ad0360ed89adbd95d338f76006a6c52"},"dob":{"date":"1952-12-23T03:25:35Z","age":66},"registered":{"date":"2017-10-31T01:40:10Z","age":1},"phone":"(868)-159-2612","cell":"(446)-770-6026","id":{"name":"SSN","value":"578-00-9941"},"picture":{"large":"https://randomuser.me/api/portraits/women/46.jpg","medium":"https://randomuser.me/api/portraits/med/women/46.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/46.jpg"},"nat":"US"},{"gender":"male","name":{"title":"mr","first":"nelson","last":"mendoza"},"location":{"street":"4868 westheimer rd","city":"lakeland","state":"alaska","postcode":63143,"coordinates":{"latitude":"59.4194","longitude":"66.5721"},"timezone":{"offset":"+5:45","description":"Kathmandu"}},"email":"nelson.mendoza@example.com","login":{"uuid":"7d2357da-cf95-4c01-91b2-0adc8efd3ccf","username":"yellowdog139","password":"spawn","salt":"FY7EGsFa","md5":"7224dce24cde3e606ad6e385493c8874","sha1":"ae1e0c209c33b21818c9ae0eb3ebcc884e4408a2","sha256":"c2a900a522a608ed44af81d82d1d63a4948eb61cef486682aebc8ef3d3d00dd0"},"dob":{"date":"1958-12-12T14:29:52Z","age":60},"registered":{"date":"2015-04-16T02:20:05Z","age":4},"phone":"(622)-681-5992","cell":"(058)-615-1214","id":{"name":"SSN","value":"081-90-3345"},"picture":{"large":"https://randomuser.me/api/portraits/men/82.jpg","medium":"https://randomuser.me/api/portraits/med/men/82.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/82.jpg"},"nat":"US"},{"gender":"male","name":{"title":"mr","first":"bobby","last":"may"},"location":{"street":"5422 thornridge cir","city":"irving","state":"tennessee","postcode":89367,"coordinates":{"latitude":"46.7608","longitude":"170.6006"},"timezone":{"offset":"+5:45","description":"Kathmandu"}},"email":"bobby.may@example.com","login":{"uuid":"e0f97d60-df05-428e-902b-0d93334dc76b","username":"purplepanda950","password":"quantum","salt":"tDMtGS8s","md5":"acc08b50992a105120a092bf6b0140b0","sha1":"5aa279a66d28162231b0c6e2467f344e7baca0cb","sha256":"fddb9d6e216ca5d153d7da992d79f19703332e8bcfc5174ca1fca20529dda92c"},"dob":{"date":"1978-07-20T08:38:51Z","age":40},"registered":{"date":"2003-01-30T08:20:13Z","age":16},"phone":"(245)-758-2144","cell":"(799)-089-2664","id":{"name":"SSN","value":"402-91-7241"},"picture":{"large":"https://randomuser.me/api/portraits/men/35.jpg","medium":"https://randomuser.me/api/portraits/med/men/35.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/35.jpg"},"nat":"US"},{"gender":"male","name":{"title":"mr","first":"mark","last":"fletcher"},"location":{"street":"2878 prospect rd","city":"lexington","state":"wyoming","postcode":24488,"coordinates":{"latitude":"-77.8018","longitude":"-173.4006"},"timezone":{"offset":"+9:00","description":"Tokyo, Seoul, Osaka, Sapporo, Yakutsk"}},"email":"mark.fletcher@example.com","login":{"uuid":"18a3d5ff-0e64-41a6-821c-0d959cdc0d3f","username":"greenlion201","password":"kuan","salt":"pm7Uw0y5","md5":"12d5bf5285dda3c0f3f106ba2ff3254d","sha1":"3b67512178920482c7c357e0ca5822f3eff72f4f","sha256":"c8314bce7d58c9dd4d1369d6deb857b243b6ad78903e5afd356db469ea93d707"},"dob":{"date":"1977-10-01T20:42:06Z","age":41},"registered":{"date":"2008-09-08T20:51:40Z","age":10},"phone":"(084)-806-5827","cell":"(429)-758-8067","id":{"name":"SSN","value":"682-52-5154"},"picture":{"large":"https://randomuser.me/api/portraits/men/35.jpg","medium":"https://randomuser.me/api/portraits/med/men/35.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/35.jpg"},"nat":"US"},{"gender":"female","name":{"title":"miss","first":"abigail","last":"watts"},"location":{"street":"1171 ranchview dr","city":"carrollton","state":"idaho","postcode":43969,"coordinates":{"latitude":"-82.7245","longitude":"100.1341"},"timezone":{"offset":"-10:00","description":"Hawaii"}},"email":"abigail.watts@example.com","login":{"uuid":"9cf6d517-af1a-4b4a-8e8d-dc2931d9015e","username":"brownladybug391","password":"daddy1","salt":"lY2dgVPw","md5":"3de4fae71b20a7924606b41ad4f9eb18","sha1":"e00ab8f4812b3da50d9ab67756367e967b003adc","sha256":"003512a783997c138142d1944e6695186a0e586c31854bbe492b39c24eb4d9e5"},"dob":{"date":"1957-07-19T04:26:36Z","age":61},"registered":{"date":"2009-08-10T20:12:46Z","age":9},"phone":"(674)-995-7388","cell":"(287)-706-2561","id":{"name":"SSN","value":"462-80-9067"},"picture":{"large":"https://randomuser.me/api/portraits/women/41.jpg","medium":"https://randomuser.me/api/portraits/med/women/41.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/41.jpg"},"nat":"US"},{"gender":"female","name":{"title":"ms","first":"sherry","last":"howell"},"location":{"street":"9080 hickory creek dr","city":"las cruces","state":"washington","postcode":84890,"coordinates":{"latitude":"73.2481","longitude":"-47.7862"},"timezone":{"offset":"+11:00","description":"Magadan, Solomon Islands, New Caledonia"}},"email":"sherry.howell@example.com","login":{"uuid":"e6d6d953-4c5a-4a17-98ff-6555a743f732","username":"crazyelephant764","password":"marion","salt":"1yMCfpR3","md5":"f1fbf1ec91ba29d66c7ae07ef56aa446","sha1":"73cf12e764a69318cb3139b6a8262264ca3d323f","sha256":"092910c73c4bcde23f3523cc774f7e683d0d76365d6ebb400fb5ccd8986222d4"},"dob":{"date":"1992-06-04T05:44:14Z","age":26},"registered":{"date":"2015-09-18T11:51:23Z","age":3},"phone":"(778)-295-2581","cell":"(583)-000-3171","id":{"name":"SSN","value":"570-24-3064"},"picture":{"large":"https://randomuser.me/api/portraits/women/38.jpg","medium":"https://randomuser.me/api/portraits/med/women/38.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/38.jpg"},"nat":"US"},{"gender":"male","name":{"title":"mr","first":"freddie","last":"mills"},"location":{"street":"6579 w dallas st","city":"saint paul","state":"wisconsin","postcode":74378,"coordinates":{"latitude":"-20.9859","longitude":"172.4377"},"timezone":{"offset":"-3:00","description":"Brazil, Buenos Aires, Georgetown"}},"email":"freddie.mills@example.com","login":{"uuid":"dc46554a-4e16-4ae3-b855-1a40e98292c9","username":"orangeduck840","password":"brains","salt":"wSSbTGJ6","md5":"92f3270b8877b24d402e6a6896dfa59b","sha1":"363ed1479f4709fbbc852810474c5b438058a6a2","sha256":"1bc1b5c47fa791e66aca634bc721c6da590e581bbc2ed32dd4dd68fa93e3aac7"},"dob":{"date":"1965-06-12T13:15:04Z","age":53},"registered":{"date":"2014-05-08T00:05:16Z","age":4},"phone":"(045)-870-0319","cell":"(406)-380-9043","id":{"name":"SSN","value":"903-94-6832"},"picture":{"large":"https://randomuser.me/api/portraits/men/26.jpg","medium":"https://randomuser.me/api/portraits/med/men/26.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/26.jpg"},"nat":"US"},{"gender":"female","name":{"title":"ms","first":"brandy","last":"berry"},"location":{"street":"3634 e sandy lake rd","city":"roanoke","state":"idaho","postcode":51924,"coordinates":{"latitude":"22.6824","longitude":"-76.1231"},"timezone":{"offset":"-9:00","description":"Alaska"}},"email":"brandy.berry@example.com","login":{"uuid":"beffa6c2-2bfa-4fe7-9def-46044f31fafd","username":"smallelephant161","password":"bradley","salt":"B23ZGSVz","md5":"806419497601a7de31fda1d90d59c2fe","sha1":"c3a9499ba373f997d85c4ff30d914672efb5ffef","sha256":"38efe12e066eeb7da3631927e232236d7f15dcc453235ecea51f41abf9e75311"},"dob":{"date":"1948-06-04T07:40:46Z","age":70},"registered":{"date":"2010-09-23T17:07:18Z","age":8},"phone":"(985)-920-6268","cell":"(924)-150-6816","id":{"name":"SSN","value":"384-61-2269"},"picture":{"large":"https://randomuser.me/api/portraits/women/50.jpg","medium":"https://randomuser.me/api/portraits/med/women/50.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/50.jpg"},"nat":"US"},{"gender":"male","name":{"title":"mr","first":"aaron","last":"kim"},"location":{"street":"9916 mcgowen st","city":"forney","state":"arizona","postcode":35464,"coordinates":{"latitude":"67.1760","longitude":"-117.6479"},"timezone":{"offset":"+3:00","description":"Baghdad, Riyadh, Moscow, St. Petersburg"}},"email":"aaron.kim@example.com","login":{"uuid":"c6cc4c72-5563-48a3-b02d-1981fe87b3ce","username":"tinybear700","password":"basset","salt":"1zfCFFPv","md5":"1f0fa7a976e6168f3539b3a2e34375b1","sha1":"855081fc1bf5a6be3cec36e691686b47cbf6da81","sha256":"a89f9b218492098f39d08e3604bbb5868b6ce8de73a5d5c46bc899d9e7fa3879"},"dob":{"date":"1967-04-09T03:52:07Z","age":52},"registered":{"date":"2016-11-25T22:09:59Z","age":2},"phone":"(083)-795-2826","cell":"(132)-235-7191","id":{"name":"SSN","value":"549-73-7734"},"picture":{"large":"https://randomuser.me/api/portraits/men/59.jpg","medium":"https://randomuser.me/api/portraits/med/men/59.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/59.jpg"},"nat":"US"},{"gender":"female","name":{"title":"mrs","first":"bella","last":"williams"},"location":{"street":"5824 spring st","city":"denton","state":"mississippi","postcode":71325,"coordinates":{"latitude":"51.0574","longitude":"-117.0416"},"timezone":{"offset":"0:00","description":"Western Europe Time, London, Lisbon, Casablanca"}},"email":"bella.williams@example.com","login":{"uuid":"38e0f392-b48e-48e9-8c19-a0798a59641f","username":"yellowmouse549","password":"1977","salt":"lqRfzCxr","md5":"3db53dc3ae139251aa5b340471889563","sha1":"44e1f845c5336260296a4a1b26a4d2812ffa9828","sha256":"c7144a528dc7fdaff22a468dfbbd60235533e2203e4e92d9fb45919a54b6b6c1"},"dob":{"date":"1951-08-13T12:34:51Z","age":67},"registered":{"date":"2008-06-15T01:53:05Z","age":10},"phone":"(241)-237-5991","cell":"(443)-602-2121","id":{"name":"SSN","value":"278-22-9872"},"picture":{"large":"https://randomuser.me/api/portraits/women/69.jpg","medium":"https://randomuser.me/api/portraits/med/women/69.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/69.jpg"},"nat":"US"},{"gender":"female","name":{"title":"miss","first":"diane","last":"armstrong"},"location":{"street":"9373 w campbell ave","city":"orlando","state":"idaho","postcode":80158,"coordinates":{"latitude":"-68.4166","longitude":"-13.4061"},"timezone":{"offset":"+2:00","description":"Kaliningrad, South Africa"}},"email":"diane.armstrong@example.com","login":{"uuid":"82ffbc8d-bee9-4324-84f5-cb60f9b4a1df","username":"organicfrog944","password":"spider","salt":"fjxue2e8","md5":"6af496679920436df7ce227b50e037e4","sha1":"7c339fe1c9345b2869bb0ea4809245f659711ac0","sha256":"cf9832e468761a60b69d7a453436f7202917f23dfcf1277c5a767b77af6ec268"},"dob":{"date":"1995-11-04T05:20:44Z","age":23},"registered":{"date":"2010-01-02T03:07:20Z","age":9},"phone":"(772)-060-7024","cell":"(834)-426-7552","id":{"name":"SSN","value":"607-74-2012"},"picture":{"large":"https://randomuser.me/api/portraits/women/6.jpg","medium":"https://randomuser.me/api/portraits/med/women/6.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/6.jpg"},"nat":"US"},{"gender":"male","name":{"title":"mr","first":"allan","last":"howell"},"location":{"street":"3076 rolling green rd","city":"scottsdale","state":"michigan","postcode":37787,"coordinates":{"latitude":"55.8431","longitude":"174.5044"},"timezone":{"offset":"-8:00","description":"Pacific Time (US & Canada)"}},"email":"allan.howell@example.com","login":{"uuid":"600a3e98-6a65-4755-a0f5-0e4cf20056a0","username":"heavymouse995","password":"scottie","salt":"6RtOBpVp","md5":"560799bb4b5ca8da862c39761ef444f1","sha1":"a12d164f0b6820f77fbb8ba9c3505c97c0d220bc","sha256":"08c6109177cab9adec16c43b26218b9c030526ba31200046c6c90b97457152eb"},"dob":{"date":"1966-03-18T12:57:31Z","age":53},"registered":{"date":"2014-02-01T00:02:58Z","age":5},"phone":"(793)-818-9821","cell":"(274)-414-7710","id":{"name":"SSN","value":"329-75-0155"},"picture":{"large":"https://randomuser.me/api/portraits/men/75.jpg","medium":"https://randomuser.me/api/portraits/med/men/75.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/75.jpg"},"nat":"US"},{"gender":"male","name":{"title":"mr","first":"jason","last":"ortiz"},"location":{"street":"1978 poplar dr","city":"aubrey","state":"south dakota","postcode":70261,"coordinates":{"latitude":"-32.6180","longitude":"-174.8620"},"timezone":{"offset":"+1:00","description":"Brussels, Copenhagen, Madrid, Paris"}},"email":"jason.ortiz@example.com","login":{"uuid":"1fe37193-0be9-46a9-9736-ee32af7d2d91","username":"tinyrabbit790","password":"singer","salt":"jTTujKo3","md5":"64386037c3b4150c94e1edf261fc32fb","sha1":"2a277e17e498ec3fb9a81c358ede1ab31559afcf","sha256":"567f8b7a5a11f781976c47e93a542e7800148a0ea54652c20ff4633f7d79562a"},"dob":{"date":"1964-12-30T23:30:20Z","age":54},"registered":{"date":"2014-08-30T13:14:58Z","age":4},"phone":"(002)-559-0584","cell":"(567)-324-9020","id":{"name":"SSN","value":"882-93-5989"},"picture":{"large":"https://randomuser.me/api/portraits/men/12.jpg","medium":"https://randomuser.me/api/portraits/med/men/12.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/12.jpg"},"nat":"US"},{"gender":"female","name":{"title":"mrs","first":"maureen","last":"stevens"},"location":{"street":"4772 locust rd","city":"frisco","state":"new york","postcode":22764,"coordinates":{"latitude":"53.8822","longitude":"91.2887"},"timezone":{"offset":"-4:00","description":"Atlantic Time (Canada), Caracas, La Paz"}},"email":"maureen.stevens@example.com","login":{"uuid":"7c9051a3-fd19-4a0d-b7c2-f7dae18f4923","username":"purplefrog802","password":"nitram","salt":"2mVcthTr","md5":"9688a952045f6bb02a7cc94e053c930b","sha1":"73417c10958d2266c249dd2bed1f2fc82ae7883a","sha256":"4aeaa2119662a69a84656f1528adb0684eabfd3355e364737c331f7fad75189f"},"dob":{"date":"1979-05-18T20:25:40Z","age":39},"registered":{"date":"2003-05-09T11:56:45Z","age":15},"phone":"(171)-664-9338","cell":"(392)-664-5537","id":{"name":"SSN","value":"137-99-6392"},"picture":{"large":"https://randomuser.me/api/portraits/women/31.jpg","medium":"https://randomuser.me/api/portraits/med/women/31.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/31.jpg"},"nat":"US"},{"gender":"male","name":{"title":"mr","first":"darren","last":"barnett"},"location":{"street":"2672 edwards rd","city":"fountain valley","state":"georgia","postcode":95189,"coordinates":{"latitude":"-11.3664","longitude":"-19.6364"},"timezone":{"offset":"+8:00","description":"Beijing, Perth, Singapore, Hong Kong"}},"email":"darren.barnett@example.com","login":{"uuid":"abb0904a-8bd0-40ee-a2b2-b9c7f7098df7","username":"heavygorilla149","password":"joseph1","salt":"olBH4Vzm","md5":"6a2cea073985a4200cf4a3512c9e0981","sha1":"4ad14d29f41571c5f00fda3534f35f92df1d9976","sha256":"47a684681222d1b7f0c80ae005e0c75c1d16e5faf417eb0c080e613580fb2ca1"},"dob":{"date":"1996-12-14T05:52:06Z","age":22},"registered":{"date":"2015-03-02T02:33:31Z","age":4},"phone":"(029)-427-0625","cell":"(548)-192-3993","id":{"name":"SSN","value":"738-72-9381"},"picture":{"large":"https://randomuser.me/api/portraits/men/96.jpg","medium":"https://randomuser.me/api/portraits/med/men/96.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/96.jpg"},"nat":"US"},{"gender":"male","name":{"title":"mr","first":"carl","last":"kelly"},"location":{"street":"983 spring st","city":"daly city","state":"georgia","postcode":56722,"coordinates":{"latitude":"5.4433","longitude":"-73.0138"},"timezone":{"offset":"-10:00","description":"Hawaii"}},"email":"carl.kelly@example.com","login":{"uuid":"80df204c-da44-4ac2-8ef4-18da3834161e","username":"brownmeercat719","password":"whistler","salt":"lVqoN3a0","md5":"c737d4e38efe566c5d44fb0ddd01159c","sha1":"94c164f01d60eac0517969493bc4200f8cd1f12a","sha256":"38a2079a051f75ef64f8d9e8556298aed7594eef5a9102a2827ef61d1cee8389"},"dob":{"date":"1982-02-17T09:30:05Z","age":37},"registered":{"date":"2013-09-04T14:50:07Z","age":5},"phone":"(842)-909-9009","cell":"(202)-265-1998","id":{"name":"SSN","value":"671-07-3250"},"picture":{"large":"https://randomuser.me/api/portraits/men/71.jpg","medium":"https://randomuser.me/api/portraits/med/men/71.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/71.jpg"},"nat":"US"},{"gender":"female","name":{"title":"miss","first":"beverly","last":"lopez"},"location":{"street":"2456 white oak dr","city":"lowell","state":"arkansas","postcode":59068,"coordinates":{"latitude":"-67.6255","longitude":"179.9283"},"timezone":{"offset":"-6:00","description":"Central Time (US & Canada), Mexico City"}},"email":"beverly.lopez@example.com","login":{"uuid":"05678a31-9c8d-47de-8794-8bf4babfa054","username":"heavybird141","password":"banner","salt":"q4l5Vh66","md5":"e2ed8be6667de69dcb3178c78a9435cc","sha1":"451f04b33234a0dd0cb227e623b913841c167890","sha256":"04e98a94c2a35e7c49d3a15732cdec48b62924b4789312a396165fc443587c09"},"dob":{"date":"1981-09-30T17:48:40Z","age":37},"registered":{"date":"2018-06-02T08:02:39Z","age":0},"phone":"(286)-714-0708","cell":"(798)-909-3588","id":{"name":"SSN","value":"388-81-4481"},"picture":{"large":"https://randomuser.me/api/portraits/women/7.jpg","medium":"https://randomuser.me/api/portraits/med/women/7.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/7.jpg"},"nat":"US"},{"gender":"male","name":{"title":"mr","first":"michael","last":"palmer"},"location":{"street":"7916 first street","city":"denver","state":"utah","postcode":78705,"coordinates":{"latitude":"-7.6616","longitude":"13.8621"},"timezone":{"offset":"+2:00","description":"Kaliningrad, South Africa"}},"email":"michael.palmer@example.com","login":{"uuid":"b8d3167c-ef0c-4f4a-a760-4e2b47372a4e","username":"happypeacock769","password":"funny","salt":"kXwKakrL","md5":"f31a364e12b63222b61ffb8d9f6bc7f0","sha1":"47b2e4a3b1cf593b8b04ba781b5207e52c1981c0","sha256":"04e0f305c190c9be1df5693e743ceb5b51fbc29e6cd0302a3b655274cd0977bd"},"dob":{"date":"1997-05-18T00:32:58Z","age":21},"registered":{"date":"2006-05-09T03:06:07Z","age":12},"phone":"(302)-224-6185","cell":"(062)-434-2786","id":{"name":"SSN","value":"722-43-0444"},"picture":{"large":"https://randomuser.me/api/portraits/men/70.jpg","medium":"https://randomuser.me/api/portraits/med/men/70.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/70.jpg"},"nat":"US"},{"gender":"female","name":{"title":"ms","first":"mae","last":"carter"},"location":{"street":"8763 robinson rd","city":"denver","state":"oklahoma","postcode":12009,"coordinates":{"latitude":"-38.2053","longitude":"59.3094"},"timezone":{"offset":"-3:00","description":"Brazil, Buenos Aires, Georgetown"}},"email":"mae.carter@example.com","login":{"uuid":"7f243fc5-f6e8-4691-a650-e6d0a8d3c63e","username":"organicgorilla953","password":"greedy","salt":"PGZRLOXC","md5":"a890199755590aeb40c1bdd821a479f0","sha1":"37bc0c4b0067454f6dac01cf7f9833b5cc6e8818","sha256":"3640d2362b84abcf0e67682e46516b52fb72acca71976ec995f30333a926fd2d"},"dob":{"date":"1960-09-14T12:46:52Z","age":58},"registered":{"date":"2014-11-07T04:28:23Z","age":4},"phone":"(827)-833-8800","cell":"(093)-370-9644","id":{"name":"SSN","value":"835-24-5960"},"picture":{"large":"https://randomuser.me/api/portraits/women/0.jpg","medium":"https://randomuser.me/api/portraits/med/women/0.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/0.jpg"},"nat":"US"},{"gender":"male","name":{"title":"mr","first":"jim","last":"walker"},"location":{"street":"7277 prospect rd","city":"mesa","state":"kentucky","postcode":55021,"coordinates":{"latitude":"42.3610","longitude":"27.4020"},"timezone":{"offset":"-3:00","description":"Brazil, Buenos Aires, Georgetown"}},"email":"jim.walker@example.com","login":{"uuid":"ed0ac9d4-8481-4861-90f5-11a2362dd01c","username":"bluepeacock336","password":"claude","salt":"v7cCJJOB","md5":"1eebd7509ba176b179a1e968a10fe14c","sha1":"06cfc4e290db97eba5bd69c5c20ab2bed027c682","sha256":"ab3abb068cc8a0b034116e329f5fb4d9981d280ddfc060ae2932d22943c5e316"},"dob":{"date":"1968-04-08T18:00:03Z","age":51},"registered":{"date":"2009-12-23T11:50:25Z","age":9},"phone":"(058)-028-2456","cell":"(714)-876-2623","id":{"name":"SSN","value":"437-88-6298"},"picture":{"large":"https://randomuser.me/api/portraits/men/43.jpg","medium":"https://randomuser.me/api/portraits/med/men/43.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/43.jpg"},"nat":"US"},{"gender":"female","name":{"title":"ms","first":"valerie","last":"barnes"},"location":{"street":"2909 w sherman dr","city":"great falls","state":"missouri","postcode":37714,"coordinates":{"latitude":"29.8175","longitude":"-50.6947"},"timezone":{"offset":"-2:00","description":"Mid-Atlantic"}},"email":"valerie.barnes@example.com","login":{"uuid":"43753769-c6ef-49c5-9d4e-cc1939a26a3d","username":"angrypanda815","password":"curious","salt":"mF6CAIxq","md5":"c5d69cc770574488e714b87f5591605a","sha1":"db6dbee8490b7daf0b348d2e4d87838616272efd","sha256":"d0c0dd04991494e44d2198f63bc99bcd30486bff5d92ee06c1682beb85f5aa4e"},"dob":{"date":"1995-03-17T14:13:23Z","age":24},"registered":{"date":"2005-06-23T01:10:28Z","age":13},"phone":"(148)-185-6231","cell":"(953)-271-3083","id":{"name":"SSN","value":"784-59-8449"},"picture":{"large":"https://randomuser.me/api/portraits/women/20.jpg","medium":"https://randomuser.me/api/portraits/med/women/20.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/20.jpg"},"nat":"US"},{"gender":"female","name":{"title":"mrs","first":"danielle","last":"walker"},"location":{"street":"3355 marsh ln","city":"overland park","state":"tennessee","postcode":14811,"coordinates":{"latitude":"-80.6561","longitude":"179.6205"},"timezone":{"offset":"-4:00","description":"Atlantic Time (Canada), Caracas, La Paz"}},"email":"danielle.walker@example.com","login":{"uuid":"1ab0ad6e-fe57-4edd-a971-4be944bed6cc","username":"tinydog965","password":"coventry","salt":"1foIgf4X","md5":"dcfa7a920fb901fe0fd0130ccb40396d","sha1":"f48f8c7174545224cdcff39a0957ed3e9968bb4e","sha256":"8d47a1e268e7d601ec20a95156f4170229ec435b1f3e167bda0664980b32511a"},"dob":{"date":"1983-10-19T19:21:55Z","age":35},"registered":{"date":"2004-04-23T01:34:21Z","age":15},"phone":"(740)-120-9030","cell":"(202)-891-3964","id":{"name":"SSN","value":"360-68-1365"},"picture":{"large":"https://randomuser.me/api/portraits/women/69.jpg","medium":"https://randomuser.me/api/portraits/med/women/69.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/69.jpg"},"nat":"US"},{"gender":"male","name":{"title":"mr","first":"roy","last":"murray"},"location":{"street":"7351 spring st","city":"providence","state":"new jersey","postcode":11776,"coordinates":{"latitude":"58.8516","longitude":"-96.4576"},"timezone":{"offset":"+10:00","description":"Eastern Australia, Guam, Vladivostok"}},"email":"roy.murray@example.com","login":{"uuid":"f938c18d-5010-452c-a8b0-47509667595a","username":"beautifulkoala511","password":"hellas","salt":"s40bbTqb","md5":"29940af4e3eb6ff2dfa2b328b499b184","sha1":"a9e13ad4bea000e7e459db228f9ff5040ceea572","sha256":"2952f377a6c0a09fd9605d6336af36517c0c16cfd39d0284d40686854b2238bd"},"dob":{"date":"1995-09-15T12:15:27Z","age":23},"registered":{"date":"2016-12-23T14:30:27Z","age":2},"phone":"(854)-545-0786","cell":"(417)-031-2096","id":{"name":"SSN","value":"042-59-1284"},"picture":{"large":"https://randomuser.me/api/portraits/men/10.jpg","medium":"https://randomuser.me/api/portraits/med/men/10.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/10.jpg"},"nat":"US"},{"gender":"male","name":{"title":"mr","first":"alex","last":"mendoza"},"location":{"street":"8218 brown terrace","city":"torrance","state":"georgia","postcode":39683,"coordinates":{"latitude":"71.9585","longitude":"97.0828"},"timezone":{"offset":"-7:00","description":"Mountain Time (US & Canada)"}},"email":"alex.mendoza@example.com","login":{"uuid":"fb5bb0b8-9e28-43d6-b406-9ec0042e7195","username":"heavypeacock450","password":"1017","salt":"B3uuNnWk","md5":"d1715704fe002031e9cfa9a3ecdd9f87","sha1":"dc52e866b249e4503eb7fefbafd1931f6147cb4a","sha256":"8046cbeb2289cf5bec01d6b58c1b64c8145d3a756b905e957f4e446fa30aaea4"},"dob":{"date":"1954-04-14T09:30:03Z","age":65},"registered":{"date":"2006-07-21T15:07:24Z","age":12},"phone":"(282)-163-7774","cell":"(783)-916-4975","id":{"name":"SSN","value":"804-26-6037"},"picture":{"large":"https://randomuser.me/api/portraits/men/87.jpg","medium":"https://randomuser.me/api/portraits/med/men/87.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/87.jpg"},"nat":"US"},{"gender":"female","name":{"title":"miss","first":"kitty","last":"hawkins"},"location":{"street":"1026 spring hill rd","city":"hamsburg","state":"ohio","postcode":59353,"coordinates":{"latitude":"60.3015","longitude":"-157.1048"},"timezone":{"offset":"+5:00","description":"Ekaterinburg, Islamabad, Karachi, Tashkent"}},"email":"kitty.hawkins@example.com","login":{"uuid":"e075f05f-6ac4-4439-a0f1-53b377ded8bc","username":"bigfrog720","password":"beech","salt":"vBBaQxhH","md5":"79c24e1c9029b5a094d9716a0b3cfa3c","sha1":"b7d1d6716fb9a0533890af590bd8d22775ddb61d","sha256":"cea26b2d5a47830f9572cf3169409ebf30bb26ecd035a626bb75a6de9bcff4a0"},"dob":{"date":"1985-10-18T05:19:08Z","age":33},"registered":{"date":"2015-03-16T05:57:06Z","age":4},"phone":"(133)-268-7418","cell":"(940)-192-7306","id":{"name":"SSN","value":"149-12-3771"},"picture":{"large":"https://randomuser.me/api/portraits/women/49.jpg","medium":"https://randomuser.me/api/portraits/med/women/49.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/49.jpg"},"nat":"US"},{"gender":"male","name":{"title":"mr","first":"steve","last":"miles"},"location":{"street":"8139 hillcrest rd","city":"garland","state":"kentucky","postcode":88084,"coordinates":{"latitude":"-15.7563","longitude":"-119.4557"},"timezone":{"offset":"+5:00","description":"Ekaterinburg, Islamabad, Karachi, Tashkent"}},"email":"steve.miles@example.com","login":{"uuid":"c31188fd-8e40-4a49-ae47-1819d2a6d6a2","username":"silverpeacock527","password":"ozzy","salt":"eAqX27eU","md5":"2a5b3a641883a916a259eeebcd1ae27c","sha1":"b15247aff01e052a24b61e507737aca2b6a7dce1","sha256":"6422c41acc81bcc94d0eb26f0147665a3fd6682a619477fa49dd59709f5c2ce2"},"dob":{"date":"1995-11-27T12:27:03Z","age":23},"registered":{"date":"2011-08-18T03:40:43Z","age":7},"phone":"(461)-196-8291","cell":"(859)-179-4381","id":{"name":"SSN","value":"822-22-7217"},"picture":{"large":"https://randomuser.me/api/portraits/men/12.jpg","medium":"https://randomuser.me/api/portraits/med/men/12.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/12.jpg"},"nat":"US"},{"gender":"female","name":{"title":"mrs","first":"rita","last":"hicks"},"location":{"street":"4578 poplar dr","city":"ennis","state":"vermont","postcode":72386,"coordinates":{"latitude":"-39.3297","longitude":"-74.8630"},"timezone":{"offset":"-3:30","description":"Newfoundland"}},"email":"rita.hicks@example.com","login":{"uuid":"aeb5078f-7504-4d61-b88a-51e0a6e90d5b","username":"silverdog604","password":"beatrice","salt":"hrSk0YQB","md5":"5ba7215403f90815bd4bb3996517b469","sha1":"196bbfcd874a8df4127c46d649cac7699027b736","sha256":"2164d2e2dad089c525151ff8438434519bcf6f31d4a595be86e451211a4f13ef"},"dob":{"date":"1961-07-11T12:56:56Z","age":57},"registered":{"date":"2017-05-29T13:01:06Z","age":1},"phone":"(802)-624-6684","cell":"(924)-521-3802","id":{"name":"SSN","value":"137-84-9243"},"picture":{"large":"https://randomuser.me/api/portraits/women/60.jpg","medium":"https://randomuser.me/api/portraits/med/women/60.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/60.jpg"},"nat":"US"},{"gender":"female","name":{"title":"mrs","first":"rebecca","last":"taylor"},"location":{"street":"5110 rolling green rd","city":"fort worth","state":"wisconsin","postcode":60136,"coordinates":{"latitude":"87.2094","longitude":"22.5912"},"timezone":{"offset":"-3:30","description":"Newfoundland"}},"email":"rebecca.taylor@example.com","login":{"uuid":"4c3b2544-58b2-4f18-bfb6-bb565a1f879c","username":"whitelion755","password":"someone","salt":"nHxAfSb3","md5":"38d3aca63ec594bdd86342579de31f5f","sha1":"64ad12c4244fe083dc532884b5d4bd7dcf4fedae","sha256":"1682bc63a2545416ceeb67f1b2cab0c5ac0805978bcd922bf627e80113f09ea2"},"dob":{"date":"1974-08-04T20:03:04Z","age":44},"registered":{"date":"2016-10-16T21:31:38Z","age":2},"phone":"(123)-326-0644","cell":"(280)-305-7898","id":{"name":"SSN","value":"493-99-6223"},"picture":{"large":"https://randomuser.me/api/portraits/women/27.jpg","medium":"https://randomuser.me/api/portraits/med/women/27.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/27.jpg"},"nat":"US"},{"gender":"male","name":{"title":"mr","first":"craig","last":"reyes"},"location":{"street":"7240 w pecan st","city":"akron","state":"north dakota","postcode":19878,"coordinates":{"latitude":"-48.2340","longitude":"-7.7906"},"timezone":{"offset":"-11:00","description":"Midway Island, Samoa"}},"email":"craig.reyes@example.com","login":{"uuid":"a24b1676-40fa-4726-b472-35c8ff3765a0","username":"tinytiger931","password":"audi","salt":"cf3drYrH","md5":"bd73951bc2aa5331222d1a1950cfc402","sha1":"f4840be094302f4fd7b4494259064b4cff933353","sha256":"708bd8c3e5491198d2a473108582a1561691cabc2fbe68d48317a8c497d21463"},"dob":{"date":"1957-08-07T03:08:36Z","age":61},"registered":{"date":"2015-02-10T01:12:16Z","age":4},"phone":"(615)-972-1681","cell":"(356)-948-5014","id":{"name":"SSN","value":"254-53-5350"},"picture":{"large":"https://randomuser.me/api/portraits/men/47.jpg","medium":"https://randomuser.me/api/portraits/med/men/47.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/47.jpg"},"nat":"US"},{"gender":"male","name":{"title":"mr","first":"chris","last":"campbell"},"location":{"street":"6768 lovers ln","city":"garden grove","state":"kansas","postcode":72395,"coordinates":{"latitude":"-48.8872","longitude":"-75.7497"},"timezone":{"offset":"+5:45","description":"Kathmandu"}},"email":"chris.campbell@example.com","login":{"uuid":"2413ce33-feb3-4bc4-808e-ea3c12651d1f","username":"lazykoala930","password":"dollars","salt":"MTFhykCT","md5":"9af56453cad9c158374d422128fd34e0","sha1":"33012c947d49fb083900088c9949d0a83a65706a","sha256":"3d5f5de9dea8666d7a92aeed288c40d02cf73cc25786ffb78b4c4f78c77ff0fd"},"dob":{"date":"1978-03-26T03:54:33Z","age":41},"registered":{"date":"2014-06-27T20:26:56Z","age":4},"phone":"(936)-036-7306","cell":"(900)-727-9606","id":{"name":"SSN","value":"145-57-2909"},"picture":{"large":"https://randomuser.me/api/portraits/men/60.jpg","medium":"https://randomuser.me/api/portraits/med/men/60.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/60.jpg"},"nat":"US"},{"gender":"male","name":{"title":"mr","first":"jorge","last":"prescott"},"location":{"street":"3928 dogwood ave","city":"roseburg","state":"missouri","postcode":64330,"coordinates":{"latitude":"61.4796","longitude":"25.4434"},"timezone":{"offset":"+5:30","description":"Bombay, Calcutta, Madras, New Delhi"}},"email":"jorge.prescott@example.com","login":{"uuid":"5ff71bc3-0a0b-4047-9477-39b893a0cb63","username":"brownkoala590","password":"alice","salt":"ZBVJ357r","md5":"ff13f604c728dd85a5048f01a83848a6","sha1":"74bd40d4f5ea86b12e11317823e487d5d6da65db","sha256":"c540549c104ba4382b1531e5929b09bfb820b9b980a2a47de81c4483cd11c315"},"dob":{"date":"1965-12-28T18:57:30Z","age":53},"registered":{"date":"2012-01-09T19:57:56Z","age":7},"phone":"(144)-510-9320","cell":"(629)-552-4746","id":{"name":"SSN","value":"955-61-1288"},"picture":{"large":"https://randomuser.me/api/portraits/men/28.jpg","medium":"https://randomuser.me/api/portraits/med/men/28.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/28.jpg"},"nat":"US"},{"gender":"female","name":{"title":"miss","first":"dolores","last":"gutierrez"},"location":{"street":"5732 plum st","city":"eureka","state":"alabama","postcode":35398,"coordinates":{"latitude":"-78.6889","longitude":"-125.2944"},"timezone":{"offset":"-3:00","description":"Brazil, Buenos Aires, Georgetown"}},"email":"dolores.gutierrez@example.com","login":{"uuid":"4110624b-d64e-4b4a-b3c3-c79f6bcbf4c2","username":"orangelion433","password":"escape","salt":"LC7f9Zgf","md5":"0937ac9da2e0b0cdc94d8326d61d8f59","sha1":"1784386785234971f14c819836fe111dc5aeb4de","sha256":"90f0e8f7a6625de0bb9b8ac53e7a9c877db3b6deac662593f4bf6f4330003ebb"},"dob":{"date":"1993-12-04T04:57:52Z","age":25},"registered":{"date":"2012-08-04T19:36:47Z","age":6},"phone":"(916)-141-9151","cell":"(040)-557-5859","id":{"name":"SSN","value":"441-65-9376"},"picture":{"large":"https://randomuser.me/api/portraits/women/73.jpg","medium":"https://randomuser.me/api/portraits/med/women/73.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/73.jpg"},"nat":"US"},{"gender":"male","name":{"title":"mr","first":"vernon","last":"long"},"location":{"street":"8594 bruce st","city":"south valley","state":"virginia","postcode":12188,"coordinates":{"latitude":"62.4243","longitude":"158.7174"},"timezone":{"offset":"+10:00","description":"Eastern Australia, Guam, Vladivostok"}},"email":"vernon.long@example.com","login":{"uuid":"e314c771-7cc2-4153-bb90-389d57a73a0d","username":"heavyfrog750","password":"driven","salt":"iKRXrvGw","md5":"40f18164648fd88c0fef6d708e35d72e","sha1":"73f8d3b6cb68e358617d24fbca234f88609e9691","sha256":"8eeb08160817d492c492bd92860fa9566de99ef4a2b6e81841a57cb60c4002c3"},"dob":{"date":"1945-01-17T21:44:49Z","age":74},"registered":{"date":"2002-04-06T12:36:47Z","age":17},"phone":"(194)-901-0405","cell":"(076)-112-4863","id":{"name":"SSN","value":"177-40-5644"},"picture":{"large":"https://randomuser.me/api/portraits/men/2.jpg","medium":"https://randomuser.me/api/portraits/med/men/2.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/2.jpg"},"nat":"US"},{"gender":"female","name":{"title":"ms","first":"dolores","last":"steeves "},"location":{"street":"8743 karen dr","city":"columbia","state":"texas","postcode":85198,"coordinates":{"latitude":"30.5231","longitude":"-127.3210"},"timezone":{"offset":"+2:00","description":"Kaliningrad, South Africa"}},"email":"dolores.steeves@example.com","login":{"uuid":"bb5293ed-ecc6-4c11-8399-f09e78ab537e","username":"angrydog384","password":"ryan","salt":"GBxBrC5U","md5":"72e2f8a32a0a377057890199756000aa","sha1":"209444a8e8013cabbeb956200df6adbe87a14bf8","sha256":"92b908946810e0528a93be65d5b098e33a739e44937e3a2e9fa73587513c7654"},"dob":{"date":"1981-01-20T10:51:42Z","age":38},"registered":{"date":"2005-07-25T13:27:50Z","age":13},"phone":"(457)-594-0206","cell":"(937)-925-5690","id":{"name":"SSN","value":"507-04-7749"},"picture":{"large":"https://randomuser.me/api/portraits/women/69.jpg","medium":"https://randomuser.me/api/portraits/med/women/69.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/69.jpg"},"nat":"US"},{"gender":"female","name":{"title":"mrs","first":"crystal","last":"banks"},"location":{"street":"4041 paddock way","city":"tempe","state":"minnesota","postcode":70442,"coordinates":{"latitude":"-84.2015","longitude":"-95.7270"},"timezone":{"offset":"+2:00","description":"Kaliningrad, South Africa"}},"email":"crystal.banks@example.com","login":{"uuid":"0cd3f58f-de7e-4ada-8775-a2d3c042b4a9","username":"lazymeercat610","password":"goalie","salt":"m6n62C4J","md5":"109c2c77c2b36954f697f0609fe08f1c","sha1":"5f13212e1bb4ec54e48bf21963b1cb774e71c022","sha256":"a19b3b87c13d44c3c2c6c6498cc89ffe9b0582ea9b60ffb2065025df7b7dbed5"},"dob":{"date":"1994-09-09T20:04:25Z","age":24},"registered":{"date":"2008-04-09T08:56:05Z","age":11},"phone":"(651)-128-5818","cell":"(025)-205-2215","id":{"name":"SSN","value":"016-86-8235"},"picture":{"large":"https://randomuser.me/api/portraits/women/11.jpg","medium":"https://randomuser.me/api/portraits/med/women/11.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/11.jpg"},"nat":"US"},{"gender":"male","name":{"title":"mr","first":"morris","last":"herrera"},"location":{"street":"4015 hamilton ave","city":"garden grove","state":"kentucky","postcode":42993,"coordinates":{"latitude":"-32.7126","longitude":"101.1901"},"timezone":{"offset":"-5:00","description":"Eastern Time (US & Canada), Bogota, Lima"}},"email":"morris.herrera@example.com","login":{"uuid":"a152b3a9-7f45-4d5f-8a96-896b25beea5f","username":"redswan702","password":"starter","salt":"kFYSsfLh","md5":"83a2f9f83a312c11bca004834c1ceb40","sha1":"223ddce61709e4a178cb33780abcccba898111ad","sha256":"983d821fe0306ab4f6924df232a82149f531c76766b1bc7302d7de6f116df6a0"},"dob":{"date":"1995-02-16T04:40:02Z","age":24},"registered":{"date":"2003-11-13T17:35:33Z","age":15},"phone":"(857)-535-3022","cell":"(551)-720-3432","id":{"name":"SSN","value":"024-12-1412"},"picture":{"large":"https://randomuser.me/api/portraits/men/42.jpg","medium":"https://randomuser.me/api/portraits/med/men/42.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/42.jpg"},"nat":"US"},{"gender":"female","name":{"title":"mrs","first":"jessie","last":"cruz"},"location":{"street":"9532 oak lawn ave","city":"topeka","state":"wyoming","postcode":43809,"coordinates":{"latitude":"-50.5502","longitude":"-89.1523"},"timezone":{"offset":"+5:30","description":"Bombay, Calcutta, Madras, New Delhi"}},"email":"jessie.cruz@example.com","login":{"uuid":"330d4353-f337-48ec-a377-60fcf03e73c0","username":"bluebutterfly747","password":"zxczxc","salt":"U8NPS9qU","md5":"b063e2b8ec4cd14b2f3decee0ef1af0a","sha1":"bf9533af8fea28f03dc00e50472f852dbe996d41","sha256":"5e2d03ca28b97ff3017a52c3427a85a43f5a912cab1ce460cce848a8de52f5c7"},"dob":{"date":"1963-02-15T01:32:03Z","age":56},"registered":{"date":"2004-02-05T21:43:57Z","age":15},"phone":"(090)-568-3080","cell":"(567)-803-1577","id":{"name":"SSN","value":"251-91-1015"},"picture":{"large":"https://randomuser.me/api/portraits/women/17.jpg","medium":"https://randomuser.me/api/portraits/med/women/17.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/17.jpg"},"nat":"US"},{"gender":"female","name":{"title":"mrs","first":"myrtle","last":"george"},"location":{"street":"4932 karen dr","city":"surprise","state":"colorado","postcode":36143,"coordinates":{"latitude":"18.2095","longitude":"-100.8707"},"timezone":{"offset":"+3:00","description":"Baghdad, Riyadh, Moscow, St. Petersburg"}},"email":"myrtle.george@example.com","login":{"uuid":"886d1f35-ef6b-46db-8f6c-3652711c3282","username":"orangeostrich213","password":"unique","salt":"9jsJl0HU","md5":"6f439761976bcc16e7e1fb963de1ae82","sha1":"e95390681a76629f39ca491c98290c84f0c8a769","sha256":"8083e3f8eac793d13e7b904fab220cda6d1f4313ad107f76edf7293509fb86c8"},"dob":{"date":"1952-02-22T16:05:46Z","age":67},"registered":{"date":"2010-03-02T11:31:10Z","age":9},"phone":"(238)-502-2160","cell":"(278)-059-8327","id":{"name":"SSN","value":"475-74-3451"},"picture":{"large":"https://randomuser.me/api/portraits/women/16.jpg","medium":"https://randomuser.me/api/portraits/med/women/16.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/16.jpg"},"nat":"US"},{"gender":"female","name":{"title":"miss","first":"debra","last":"torres"},"location":{"street":"7637 miller ave","city":"newport news","state":"colorado","postcode":68281,"coordinates":{"latitude":"47.2858","longitude":"-86.0491"},"timezone":{"offset":"-5:00","description":"Eastern Time (US & Canada), Bogota, Lima"}},"email":"debra.torres@example.com","login":{"uuid":"3ae0ff49-bbbb-4d63-b1fe-00f3033982ef","username":"tinyzebra727","password":"fettish","salt":"4iph4hWP","md5":"e8bbe480febabdb8c47ebfa7fb73b4df","sha1":"2184860d1983e3502135c7101e055e67e0211937","sha256":"5cfc0cb26a7269da16b0cab7b5c14bb70327253e959e1a524f5043038ce5012d"},"dob":{"date":"1991-03-11T04:31:26Z","age":28},"registered":{"date":"2002-05-10T08:15:02Z","age":16},"phone":"(873)-285-0167","cell":"(491)-808-3556","id":{"name":"SSN","value":"039-80-4515"},"picture":{"large":"https://randomuser.me/api/portraits/women/50.jpg","medium":"https://randomuser.me/api/portraits/med/women/50.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/50.jpg"},"nat":"US"},{"gender":"male","name":{"title":"mr","first":"henry","last":"payne"},"location":{"street":"8737 photinia ave","city":"st. petersburg","state":"alaska","postcode":79584,"coordinates":{"latitude":"65.5640","longitude":"45.5420"},"timezone":{"offset":"+4:00","description":"Abu Dhabi, Muscat, Baku, Tbilisi"}},"email":"henry.payne@example.com","login":{"uuid":"b31b6381-1d18-4533-b818-4e3ec2ee1710","username":"organicwolf332","password":"radical","salt":"w9Y6ezTS","md5":"6aa4b5c92ae7557f37dfdd1480cde250","sha1":"197fbb81a7cf5dade6052ebb486315cbc3dfe43f","sha256":"c15eddc8653fb4f8f1eaac24015a6197a53a7d1c5a315db43ece75d9ac2b4b54"},"dob":{"date":"1981-07-17T17:26:20Z","age":37},"registered":{"date":"2016-04-28T07:03:30Z","age":2},"phone":"(996)-978-8391","cell":"(399)-698-9209","id":{"name":"SSN","value":"074-33-5426"},"picture":{"large":"https://randomuser.me/api/portraits/men/53.jpg","medium":"https://randomuser.me/api/portraits/med/men/53.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/53.jpg"},"nat":"US"},{"gender":"male","name":{"title":"mr","first":"arthur","last":"kennedy"},"location":{"street":"9464 james st","city":"midland","state":"maryland","postcode":61618,"coordinates":{"latitude":"36.4132","longitude":"179.0677"},"timezone":{"offset":"+5:45","description":"Kathmandu"}},"email":"arthur.kennedy@example.com","login":{"uuid":"13e9c260-b1dc-4edf-9e59-dd5dde376e2f","username":"sadkoala392","password":"wrestle","salt":"B7ut4401","md5":"5e269793384966c0b6dfd459e97fa1a9","sha1":"210b543b4cd402b9ceffe1744088dfca55e8a179","sha256":"f2aa9d8e9b811dbaa5fef0af4942ec40cb07fc2bda907d754c5725f5816177b2"},"dob":{"date":"1983-07-17T15:57:07Z","age":35},"registered":{"date":"2015-08-05T01:01:54Z","age":3},"phone":"(201)-521-8334","cell":"(662)-023-8003","id":{"name":"SSN","value":"945-06-9068"},"picture":{"large":"https://randomuser.me/api/portraits/men/24.jpg","medium":"https://randomuser.me/api/portraits/med/men/24.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/24.jpg"},"nat":"US"},{"gender":"female","name":{"title":"ms","first":"bernice","last":"gonzales"},"location":{"street":"8390 wheeler ridge dr","city":"fontana","state":"new mexico","postcode":48019,"coordinates":{"latitude":"-1.0599","longitude":"71.3712"},"timezone":{"offset":"+1:00","description":"Brussels, Copenhagen, Madrid, Paris"}},"email":"bernice.gonzales@example.com","login":{"uuid":"a8c43dc2-c590-4249-a6cb-f4b404347a1c","username":"bigfish331","password":"broncos","salt":"E2MVDLpR","md5":"781c65f2e02aaca7c156909e39a0168a","sha1":"1afcfac29eaf87687e22321a986c67a3d364ff80","sha256":"4ba12f0d1840b9c0281cbbfb7a9241127e14c52aa91ffb76a49c302c9efd029e"},"dob":{"date":"1966-01-20T23:43:17Z","age":53},"registered":{"date":"2012-09-18T08:18:47Z","age":6},"phone":"(438)-731-8499","cell":"(977)-951-3274","id":{"name":"SSN","value":"929-33-5540"},"picture":{"large":"https://randomuser.me/api/portraits/women/91.jpg","medium":"https://randomuser.me/api/portraits/med/women/91.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/91.jpg"},"nat":"US"},{"gender":"male","name":{"title":"mr","first":"devon","last":"white"},"location":{"street":"4399 rolling green rd","city":"norwalk","state":"north dakota","postcode":10112,"coordinates":{"latitude":"10.2347","longitude":"-148.7100"},"timezone":{"offset":"0:00","description":"Western Europe Time, London, Lisbon, Casablanca"}},"email":"devon.white@example.com","login":{"uuid":"a46674be-ab44-4760-b67c-aa2e5eb3b0a8","username":"blackladybug635","password":"splinter","salt":"KTNRj4KX","md5":"0c692acb82d21d3cc040623abe13b5d5","sha1":"b73dbc822afcef234583c56d0bce4ca0bcc72807","sha256":"3fa772fa5ae3861ca0c88acad78f5208364f35c44b21b71ee6965221772aac20"},"dob":{"date":"1979-09-03T05:31:51Z","age":39},"registered":{"date":"2008-11-28T00:02:18Z","age":10},"phone":"(949)-462-7457","cell":"(525)-729-3234","id":{"name":"SSN","value":"698-11-5701"},"picture":{"large":"https://randomuser.me/api/portraits/men/48.jpg","medium":"https://randomuser.me/api/portraits/med/men/48.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/48.jpg"},"nat":"US"},{"gender":"female","name":{"title":"miss","first":"eva","last":"harper"},"location":{"street":"6214 pecan acres ln","city":"tulsa","state":"oklahoma","postcode":91949,"coordinates":{"latitude":"59.7290","longitude":"71.9876"},"timezone":{"offset":"+3:30","description":"Tehran"}},"email":"eva.harper@example.com","login":{"uuid":"9ac7696f-4c0d-43cd-a6dd-011f56b0ea77","username":"angryladybug572","password":"fredrick","salt":"XSArbdd7","md5":"9abc4c922d674f0473d310d944f22f28","sha1":"6bfd7ffe6cccdaf25018b4e53b0df879cea54fad","sha256":"bff2434b2ffca0014bd1fd4f469e9f6ec4eec4d521cafdacea51b16debfa00bc"},"dob":{"date":"1948-05-23T02:35:06Z","age":70},"registered":{"date":"2015-02-09T15:25:42Z","age":4},"phone":"(707)-239-7548","cell":"(688)-207-5770","id":{"name":"SSN","value":"295-48-2023"},"picture":{"large":"https://randomuser.me/api/portraits/women/13.jpg","medium":"https://randomuser.me/api/portraits/med/women/13.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/13.jpg"},"nat":"US"},{"gender":"female","name":{"title":"ms","first":"kristina","last":"harper"},"location":{"street":"5916 hickory creek dr","city":"dumas","state":"oklahoma","postcode":12575,"coordinates":{"latitude":"56.9548","longitude":"-40.6041"},"timezone":{"offset":"+5:00","description":"Ekaterinburg, Islamabad, Karachi, Tashkent"}},"email":"kristina.harper@example.com","login":{"uuid":"8478fb0e-68e5-4ba8-985f-0799a733b477","username":"orangelion922","password":"charisma","salt":"daW7BEA9","md5":"5b7497b5960f9bdca1857a20183d09b6","sha1":"f8378e9f496c667c9d9b83010937a59138342536","sha256":"24c27e889d71b2f8a023bdf68355e9d962b0b1b7e6ea82f6dd26b102c27a8f30"},"dob":{"date":"1955-08-15T21:18:19Z","age":63},"registered":{"date":"2004-01-24T06:50:12Z","age":15},"phone":"(804)-896-6900","cell":"(678)-942-5665","id":{"name":"SSN","value":"693-31-4248"},"picture":{"large":"https://randomuser.me/api/portraits/women/58.jpg","medium":"https://randomuser.me/api/portraits/med/women/58.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/58.jpg"},"nat":"US"},{"gender":"male","name":{"title":"mr","first":"cameron","last":"sims"},"location":{"street":"6552 n stelling rd","city":"chesapeake","state":"illinois","postcode":45731,"coordinates":{"latitude":"-11.8027","longitude":"-145.2008"},"timezone":{"offset":"+5:30","description":"Bombay, Calcutta, Madras, New Delhi"}},"email":"cameron.sims@example.com","login":{"uuid":"8d04d369-9c16-4dca-bb35-65ccdb4eedff","username":"sadelephant511","password":"priest","salt":"cC06kLEB","md5":"af02ccf8e08dd3c64b098a65bf901088","sha1":"e0d7275c51ce67686aa06dd382a9780b2112cd2a","sha256":"e91aa1bb2ab7343305aae4efa74e1049b0c467b0b8dc1522bba5d6f5d8ed69af"},"dob":{"date":"1964-02-20T04:04:16Z","age":55},"registered":{"date":"2004-04-16T18:18:13Z","age":15},"phone":"(474)-208-4422","cell":"(552)-786-9933","id":{"name":"SSN","value":"601-78-0018"},"picture":{"large":"https://randomuser.me/api/portraits/men/43.jpg","medium":"https://randomuser.me/api/portraits/med/men/43.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/43.jpg"},"nat":"US"},{"gender":"male","name":{"title":"mr","first":"zack","last":"ortiz"},"location":{"street":"7662 northaven rd","city":"fairfield","state":"north dakota","postcode":85366,"coordinates":{"latitude":"-82.6019","longitude":"148.9652"},"timezone":{"offset":"-11:00","description":"Midway Island, Samoa"}},"email":"zack.ortiz@example.com","login":{"uuid":"64e67438-e768-4644-8bcf-3317d2d89451","username":"yellowpeacock782","password":"565656","salt":"wgEOOsDN","md5":"3962ef0792551876787bde60e4725e42","sha1":"eccaea7730eccbee5e18c3f39565b409927477b9","sha256":"95362e76a3e1995893ebcd056ef61d687c65ff7d4ff25075f532e99c9639d778"},"dob":{"date":"1948-09-02T15:19:38Z","age":70},"registered":{"date":"2012-12-11T00:18:28Z","age":6},"phone":"(822)-451-2476","cell":"(248)-403-3070","id":{"name":"SSN","value":"276-55-9363"},"picture":{"large":"https://randomuser.me/api/portraits/men/24.jpg","medium":"https://randomuser.me/api/portraits/med/men/24.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/24.jpg"},"nat":"US"},{"gender":"female","name":{"title":"ms","first":"jessica","last":"hanson"},"location":{"street":"8246 hamilton ave","city":"midland","state":"alaska","postcode":35981,"coordinates":{"latitude":"87.3806","longitude":"7.6299"},"timezone":{"offset":"+2:00","description":"Kaliningrad, South Africa"}},"email":"jessica.hanson@example.com","login":{"uuid":"53c350c5-bd79-4ed7-bff9-3e7457ad0d13","username":"crazyostrich483","password":"onetime","salt":"4mT3wAhu","md5":"c627c829505f0b904fb4b433bc2472ce","sha1":"98651b4d2b24b9e64b6e9f046b9bf1a4bd8c8382","sha256":"9e2d3ada11ac06977969dabffd88579807606edf53c45ce491dff0a7c3d28a8c"},"dob":{"date":"1946-02-02T13:43:03Z","age":73},"registered":{"date":"2018-05-05T18:48:05Z","age":0},"phone":"(456)-608-0870","cell":"(488)-225-6148","id":{"name":"SSN","value":"227-67-9485"},"picture":{"large":"https://randomuser.me/api/portraits/women/6.jpg","medium":"https://randomuser.me/api/portraits/med/women/6.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/6.jpg"},"nat":"US"},{"gender":"female","name":{"title":"miss","first":"addison","last":"lee"},"location":{"street":"3792 photinia ave","city":"toledo","state":"utah","postcode":29344,"coordinates":{"latitude":"11.5126","longitude":"-141.4481"},"timezone":{"offset":"+4:00","description":"Abu Dhabi, Muscat, Baku, Tbilisi"}},"email":"addison.lee@example.com","login":{"uuid":"1ec4e2fb-2bc6-4013-8f16-0303df25eb76","username":"purplebird236","password":"sigmar","salt":"FBJH37Hx","md5":"feab48367cd39674492f63954352892c","sha1":"1913b76612c86fea3816e521a8857d794080d5d8","sha256":"802b1f34de7add1b9790c8e08e56e64b00c54ad690c99785302c595e4546bb31"},"dob":{"date":"1956-12-06T06:51:42Z","age":62},"registered":{"date":"2006-01-20T13:57:36Z","age":13},"phone":"(220)-540-6622","cell":"(580)-832-3294","id":{"name":"SSN","value":"966-00-3893"},"picture":{"large":"https://randomuser.me/api/portraits/women/6.jpg","medium":"https://randomuser.me/api/portraits/med/women/6.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/6.jpg"},"nat":"US"},{"gender":"male","name":{"title":"mr","first":"evan","last":"foster"},"location":{"street":"2800 hunters creek dr","city":"ontario","state":"kentucky","postcode":93099,"coordinates":{"latitude":"34.0501","longitude":"-162.4310"},"timezone":{"offset":"+3:00","description":"Baghdad, Riyadh, Moscow, St. Petersburg"}},"email":"evan.foster@example.com","login":{"uuid":"9d25a966-dafb-4cb9-84ef-00b406067fe1","username":"beautifulelephant783","password":"twelve","salt":"eyPixgO6","md5":"40442ad1b36d7e57fce9d93f3f04f9ca","sha1":"97dca6636ef3598a6ca97409cea5ea5b3c35a923","sha256":"b1184623d047c3033352576042825e2c5b2ed89c501ce684ff8ad1b027c4d987"},"dob":{"date":"1981-12-10T04:18:54Z","age":37},"registered":{"date":"2008-11-23T23:32:34Z","age":10},"phone":"(065)-242-7510","cell":"(682)-890-2764","id":{"name":"SSN","value":"790-02-6818"},"picture":{"large":"https://randomuser.me/api/portraits/men/17.jpg","medium":"https://randomuser.me/api/portraits/med/men/17.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/17.jpg"},"nat":"US"},{"gender":"male","name":{"title":"mr","first":"don","last":"rhodes"},"location":{"street":"7681 northaven rd","city":"cedar hill","state":"virginia","postcode":73339,"coordinates":{"latitude":"71.5527","longitude":"7.4463"},"timezone":{"offset":"+5:00","description":"Ekaterinburg, Islamabad, Karachi, Tashkent"}},"email":"don.rhodes@example.com","login":{"uuid":"68790bea-71b0-4524-9fa0-648f14d72509","username":"whiteduck869","password":"1004","salt":"y2HnqrmY","md5":"9b9043c60fddeae5d4b3d733920ba37d","sha1":"38e9a57249863006076aef8f28520525fa67b715","sha256":"026b0c44a2d2f6d520fa7860547e91650d9b168eccbfac155078bbca2acbc689"},"dob":{"date":"1962-04-28T23:19:08Z","age":56},"registered":{"date":"2014-01-30T23:01:18Z","age":5},"phone":"(313)-640-3773","cell":"(040)-543-6152","id":{"name":"SSN","value":"864-30-0506"},"picture":{"large":"https://randomuser.me/api/portraits/men/75.jpg","medium":"https://randomuser.me/api/portraits/med/men/75.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/75.jpg"},"nat":"US"},{"gender":"male","name":{"title":"mr","first":"sebastian","last":"mason"},"location":{"street":"3064 groveland terrace","city":"anchorage","state":"new hampshire","postcode":77679,"coordinates":{"latitude":"-59.9759","longitude":"115.8526"},"timezone":{"offset":"+3:30","description":"Tehran"}},"email":"sebastian.mason@example.com","login":{"uuid":"0e357e55-a3c2-407c-a24d-3e4295bcc6ce","username":"brownbutterfly930","password":"photos","salt":"OPNc9Jpd","md5":"7f8cc921b5b478622b84d8d95c3e69f9","sha1":"82b9ca3aebb95d2cabc436b383a70fda9a0b91af","sha256":"a9983f0310f583c893e98dac91e7df9f0992f072508d5a83217fa6144b96c55f"},"dob":{"date":"1962-12-30T15:29:42Z","age":56},"registered":{"date":"2008-11-19T03:29:34Z","age":10},"phone":"(582)-890-5031","cell":"(963)-113-0474","id":{"name":"SSN","value":"386-04-2874"},"picture":{"large":"https://randomuser.me/api/portraits/men/65.jpg","medium":"https://randomuser.me/api/portraits/med/men/65.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/65.jpg"},"nat":"US"},{"gender":"female","name":{"title":"miss","first":"camila","last":"byrd"},"location":{"street":"5800 first street","city":"san mateo","state":"mississippi","postcode":75240,"coordinates":{"latitude":"-28.1919","longitude":"150.1525"},"timezone":{"offset":"-3:00","description":"Brazil, Buenos Aires, Georgetown"}},"email":"camila.byrd@example.com","login":{"uuid":"2a7eb9d0-739a-404c-9886-2a1c6a85760a","username":"greenmeercat522","password":"tarpon","salt":"x5zHGIJn","md5":"9d850bca3f281de20ba4f12376930074","sha1":"6bc0d7100b9ec1acf26e765836da776f259f7363","sha256":"65441e727dffd9356894904ceecb22640fdc1f639281418d03191e3af4a477bf"},"dob":{"date":"1981-11-27T11:43:21Z","age":37},"registered":{"date":"2008-10-27T03:14:01Z","age":10},"phone":"(089)-699-4859","cell":"(431)-445-2837","id":{"name":"SSN","value":"346-99-7093"},"picture":{"large":"https://randomuser.me/api/portraits/women/13.jpg","medium":"https://randomuser.me/api/portraits/med/women/13.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/13.jpg"},"nat":"US"},{"gender":"female","name":{"title":"ms","first":"tonya","last":"ferguson"},"location":{"street":"4968 pecan acres ln","city":"aurora","state":"tennessee","postcode":51192,"coordinates":{"latitude":"-22.4996","longitude":"-136.9871"},"timezone":{"offset":"+7:00","description":"Bangkok, Hanoi, Jakarta"}},"email":"tonya.ferguson@example.com","login":{"uuid":"8214bcc8-2653-4adc-a1df-712f4c60927f","username":"ticklishpanda780","password":"7007","salt":"Jejq8rTu","md5":"b0200148c3e4c545d361a05a8282236d","sha1":"037b7876d2289776f8fe2d47f1a6b8bc05d34b88","sha256":"cb62822c6cc8f949ccb2f513d493d82d2c86ff55caa940ac62db51e7f6fa5898"},"dob":{"date":"1973-09-05T06:29:17Z","age":45},"registered":{"date":"2015-11-12T18:43:07Z","age":3},"phone":"(498)-763-0538","cell":"(338)-142-4044","id":{"name":"SSN","value":"132-16-6150"},"picture":{"large":"https://randomuser.me/api/portraits/women/5.jpg","medium":"https://randomuser.me/api/portraits/med/women/5.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/5.jpg"},"nat":"US"},{"gender":"female","name":{"title":"miss","first":"april","last":"thompson"},"location":{"street":"3908 e pecan st","city":"st. petersburg","state":"kentucky","postcode":46526,"coordinates":{"latitude":"-57.3343","longitude":"-99.2269"},"timezone":{"offset":"+3:30","description":"Tehran"}},"email":"april.thompson@example.com","login":{"uuid":"5bb272e9-bd55-45d1-a4cd-f1bacb7f927a","username":"silverpanda799","password":"zhun","salt":"VbgVxhUA","md5":"d461e88dd5ac9ecc17f2e3a3293f9d71","sha1":"e174b71c27bc140f7f7c7ca3f4dd577555387d1b","sha256":"0a6d30be481d7182f45046c3a648c762a09bb877bf678ca76b6a8af59a1b6434"},"dob":{"date":"1976-07-25T04:52:08Z","age":42},"registered":{"date":"2016-07-18T21:10:31Z","age":2},"phone":"(358)-059-9621","cell":"(619)-659-2122","id":{"name":"SSN","value":"759-44-3845"},"picture":{"large":"https://randomuser.me/api/portraits/women/47.jpg","medium":"https://randomuser.me/api/portraits/med/women/47.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/47.jpg"},"nat":"US"},{"gender":"male","name":{"title":"mr","first":"liam","last":"garrett"},"location":{"street":"1188 depaul dr","city":"amarillo","state":"nebraska","postcode":11263,"coordinates":{"latitude":"-56.6704","longitude":"-118.5758"},"timezone":{"offset":"-3:30","description":"Newfoundland"}},"email":"liam.garrett@example.com","login":{"uuid":"e9e4e1e9-f2cf-475d-ad43-34c32bcbc685","username":"yellowelephant520","password":"sandro","salt":"jEm0vZee","md5":"a8792b6be951755656d0b9f6477db9dd","sha1":"d91768aea2eaa1e0d4856e4f6ef00e672a190470","sha256":"3b345815541fbc41c6f018cf0a705910b430a47f0ccc3e7d595ac0c3772a2149"},"dob":{"date":"1978-09-26T13:35:09Z","age":40},"registered":{"date":"2015-12-25T19:49:05Z","age":3},"phone":"(238)-162-6519","cell":"(261)-803-0984","id":{"name":"SSN","value":"880-46-7734"},"picture":{"large":"https://randomuser.me/api/portraits/men/45.jpg","medium":"https://randomuser.me/api/portraits/med/men/45.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/45.jpg"},"nat":"US"},{"gender":"female","name":{"title":"miss","first":"kylie","last":"ford"},"location":{"street":"6804 e north st","city":"seymour","state":"idaho","postcode":90747,"coordinates":{"latitude":"-7.5989","longitude":"53.5045"},"timezone":{"offset":"+7:00","description":"Bangkok, Hanoi, Jakarta"}},"email":"kylie.ford@example.com","login":{"uuid":"4eb24b2f-db71-4c28-9e9c-14a46aae7f47","username":"goldenelephant277","password":"ministry","salt":"jgI25mGQ","md5":"fc758a508d301e7aced3160d3f797b52","sha1":"1f42922292ef9a77b9d77c4676c55f55bd57feb2","sha256":"242d999f994d78002f9e55b8d4718af5acb00a0b3d9bb3ea547d67d61dcdf6a0"},"dob":{"date":"1977-07-30T13:18:27Z","age":41},"registered":{"date":"2004-10-31T08:49:20Z","age":14},"phone":"(267)-318-7862","cell":"(166)-947-7543","id":{"name":"SSN","value":"701-11-3013"},"picture":{"large":"https://randomuser.me/api/portraits/women/44.jpg","medium":"https://randomuser.me/api/portraits/med/women/44.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/44.jpg"},"nat":"US"},{"gender":"male","name":{"title":"mr","first":"enrique","last":"cunningham"},"location":{"street":"5721 hunters creek dr","city":"eugene","state":"kentucky","postcode":15752,"coordinates":{"latitude":"5.0565","longitude":"-79.6488"},"timezone":{"offset":"-9:00","description":"Alaska"}},"email":"enrique.cunningham@example.com","login":{"uuid":"25e1325c-d7f3-4759-9ce8-48b5f838661b","username":"silvermeercat770","password":"goddess","salt":"vzGkIEBR","md5":"4bfe99e9280df8ac5db63639b0af6253","sha1":"5b9fa245a131951792a9fff789fc997362945efe","sha256":"ff50e870cfe50ec1fbbd15a5666e949b3d00f2473cbf452f2c36e21dda0a2ad8"},"dob":{"date":"1961-01-08T00:08:15Z","age":58},"registered":{"date":"2004-01-01T16:57:59Z","age":15},"phone":"(224)-747-2667","cell":"(597)-633-6101","id":{"name":"SSN","value":"581-48-3586"},"picture":{"large":"https://randomuser.me/api/portraits/men/41.jpg","medium":"https://randomuser.me/api/portraits/med/men/41.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/41.jpg"},"nat":"US"},{"gender":"female","name":{"title":"mrs","first":"sylvia","last":"holland"},"location":{"street":"2390 dane st","city":"newport news","state":"hawaii","postcode":57474,"coordinates":{"latitude":"-86.1899","longitude":"137.6799"},"timezone":{"offset":"+3:30","description":"Tehran"}},"email":"sylvia.holland@example.com","login":{"uuid":"df8b9e41-4563-490a-b73d-0509befe7e5f","username":"sadpeacock795","password":"playboy","salt":"qYUJhRmE","md5":"7e0aae60e671b69325d46a141bc729d7","sha1":"3648528f6e5f69d04e36a55e39318ac1dee7eb10","sha256":"1d86dd922de5d32743b7aba59dbfb4e05219c087ed5e035a709aaf045f15cb93"},"dob":{"date":"1954-03-26T10:23:29Z","age":65},"registered":{"date":"2012-12-29T06:01:50Z","age":6},"phone":"(952)-906-0587","cell":"(877)-336-8852","id":{"name":"SSN","value":"993-59-9618"},"picture":{"large":"https://randomuser.me/api/portraits/women/51.jpg","medium":"https://randomuser.me/api/portraits/med/women/51.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/51.jpg"},"nat":"US"},{"gender":"male","name":{"title":"mr","first":"jack","last":"black"},"location":{"street":"9498 spring st","city":"north las vegas","state":"idaho","postcode":17405,"coordinates":{"latitude":"80.9668","longitude":"58.6859"},"timezone":{"offset":"-3:30","description":"Newfoundland"}},"email":"jack.black@example.com","login":{"uuid":"335903b1-be0a-4101-904d-481eee3c7928","username":"silverwolf598","password":"freddy","salt":"aGLtbMBx","md5":"7c4d0d7d2a4ee035b17d0bced3138691","sha1":"39f2cad161b98b2f45f2f877ffb632f1626a86c1","sha256":"0fcd677dc346fda4dc00d54cd7da4681e291d7e6aef2e6b58f1f546779a5a239"},"dob":{"date":"1950-02-21T01:35:42Z","age":69},"registered":{"date":"2004-11-07T18:02:15Z","age":14},"phone":"(398)-633-7538","cell":"(295)-320-1145","id":{"name":"SSN","value":"444-59-0663"},"picture":{"large":"https://randomuser.me/api/portraits/men/6.jpg","medium":"https://randomuser.me/api/portraits/med/men/6.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/6.jpg"},"nat":"US"},{"gender":"male","name":{"title":"mr","first":"floyd","last":"dixon"},"location":{"street":"4899 pecan acres ln","city":"surprise","state":"texas","postcode":36466,"coordinates":{"latitude":"77.0289","longitude":"98.1101"},"timezone":{"offset":"+7:00","description":"Bangkok, Hanoi, Jakarta"}},"email":"floyd.dixon@example.com","login":{"uuid":"32ad269a-f7e8-4027-b869-594804521ca7","username":"heavyelephant927","password":"neutron","salt":"hEQq9lf5","md5":"51fe5d13a0863acf5bfc915810827b87","sha1":"e830038d634870858a82b4b42d010b81e0981641","sha256":"f15b3246bc112867987a3553cc97f377ed13cf0a3d48c4cc2c39b098392adce7"},"dob":{"date":"1973-07-27T15:27:45Z","age":45},"registered":{"date":"2007-06-09T02:29:30Z","age":11},"phone":"(160)-547-7636","cell":"(249)-638-2665","id":{"name":"SSN","value":"271-72-9680"},"picture":{"large":"https://randomuser.me/api/portraits/men/69.jpg","medium":"https://randomuser.me/api/portraits/med/men/69.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/69.jpg"},"nat":"US"},{"gender":"male","name":{"title":"mr","first":"chad","last":"morales"},"location":{"street":"7182 mcclellan rd","city":"north valley","state":"north dakota","postcode":21523,"coordinates":{"latitude":"-25.9784","longitude":"-67.0159"},"timezone":{"offset":"+3:30","description":"Tehran"}},"email":"chad.morales@example.com","login":{"uuid":"b9b82627-b487-4eac-9f5b-059c609f10c4","username":"purpleladybug948","password":"lucky1","salt":"LZPVq30d","md5":"b05008cac3ef6d2cf348b3e8e8c08408","sha1":"7aacb8a31017e55e5923c2b8c0925d1d6cd55108","sha256":"25971b2be6384b8dcc42ffa37ce9c373fb4719008b88180bed5cf6fc7796889e"},"dob":{"date":"1996-10-28T04:33:26Z","age":22},"registered":{"date":"2013-09-20T00:04:00Z","age":5},"phone":"(096)-272-2736","cell":"(385)-003-5095","id":{"name":"SSN","value":"820-08-0757"},"picture":{"large":"https://randomuser.me/api/portraits/men/37.jpg","medium":"https://randomuser.me/api/portraits/med/men/37.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/37.jpg"},"nat":"US"},{"gender":"male","name":{"title":"mr","first":"miguel","last":"morales"},"location":{"street":"8838 oak ridge ln","city":"bozeman","state":"colorado","postcode":69526,"coordinates":{"latitude":"52.6514","longitude":"153.2916"},"timezone":{"offset":"-6:00","description":"Central Time (US & Canada), Mexico City"}},"email":"miguel.morales@example.com","login":{"uuid":"9092799c-3f0f-4448-bb62-c79d7c9eef41","username":"brownfrog708","password":"sailor","salt":"5EvJL9Pr","md5":"232c8dea4fca54396c042a8a65804c27","sha1":"e7a6d5efb22eaf28427e6972fd631c05e357ca39","sha256":"dbf964871fc16f4c0c91edc80e5a29dfd9c66aefd534d018b7ee4a493062b121"},"dob":{"date":"1954-11-15T22:58:07Z","age":64},"registered":{"date":"2009-01-09T17:41:52Z","age":10},"phone":"(575)-819-6303","cell":"(687)-187-9075","id":{"name":"SSN","value":"924-66-9340"},"picture":{"large":"https://randomuser.me/api/portraits/men/53.jpg","medium":"https://randomuser.me/api/portraits/med/men/53.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/53.jpg"},"nat":"US"},{"gender":"male","name":{"title":"mr","first":"rodney","last":"thompson"},"location":{"street":"6582 mockingbird ln","city":"orange","state":"delaware","postcode":17114,"coordinates":{"latitude":"-44.3533","longitude":"-18.6104"},"timezone":{"offset":"+1:00","description":"Brussels, Copenhagen, Madrid, Paris"}},"email":"rodney.thompson@example.com","login":{"uuid":"86943678-20e4-4319-be89-47b7bf89b214","username":"smallostrich115","password":"pizzas","salt":"1wtCCfQh","md5":"4af73ab82f819147a2024c6ae5a8d85a","sha1":"0977604a02252fd7120dc9db628d3a013a348171","sha256":"d01a14f2ebab8e934db88dc2dade891a25501b3e3738f67760afb554f914024c"},"dob":{"date":"1986-06-23T05:09:20Z","age":32},"registered":{"date":"2003-09-10T10:44:28Z","age":15},"phone":"(825)-131-0901","cell":"(084)-354-3866","id":{"name":"SSN","value":"737-23-0158"},"picture":{"large":"https://randomuser.me/api/portraits/men/96.jpg","medium":"https://randomuser.me/api/portraits/med/men/96.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/96.jpg"},"nat":"US"},{"gender":"female","name":{"title":"ms","first":"dawn","last":"bowman"},"location":{"street":"3689 college st","city":"aurora","state":"pennsylvania","postcode":90038,"coordinates":{"latitude":"65.8304","longitude":"133.0385"},"timezone":{"offset":"+4:30","description":"Kabul"}},"email":"dawn.bowman@example.com","login":{"uuid":"8e45359a-4049-47f1-bd11-5885eacf2a27","username":"greenostrich363","password":"herbert","salt":"hstJifCC","md5":"8944fc55a69254f84fc12f5ca11d43cb","sha1":"aa72feb34c0aacebbcf0e41a9f0680b4e5916252","sha256":"312041e468e976cbd8872287cc4015244cca308ef94ad6aecfe1ecffa72262ce"},"dob":{"date":"1963-07-21T02:35:34Z","age":55},"registered":{"date":"2009-09-01T11:32:09Z","age":9},"phone":"(246)-489-4965","cell":"(363)-649-8499","id":{"name":"SSN","value":"695-58-4679"},"picture":{"large":"https://randomuser.me/api/portraits/women/20.jpg","medium":"https://randomuser.me/api/portraits/med/women/20.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/20.jpg"},"nat":"US"},{"gender":"female","name":{"title":"ms","first":"martha","last":"payne"},"location":{"street":"6464 smokey ln","city":"everett","state":"florida","postcode":81596,"coordinates":{"latitude":"-70.8708","longitude":"151.8925"},"timezone":{"offset":"-5:00","description":"Eastern Time (US & Canada), Bogota, Lima"}},"email":"martha.payne@example.com","login":{"uuid":"29307098-c8d8-4f77-9a8e-5c9c3f8fd1de","username":"goldenbutterfly521","password":"spurs","salt":"91WJSevi","md5":"e8332f4a8f97f9c9c58b423cf12a18a1","sha1":"694987dcdbe93482c8d829f6c7fd0112cdafc853","sha256":"4c8fb06192da3429c27fdcad967dc36eeda6ccd1ff920787a6b66979539256ef"},"dob":{"date":"1997-01-22T08:45:04Z","age":22},"registered":{"date":"2007-02-18T09:15:16Z","age":12},"phone":"(961)-721-4288","cell":"(203)-752-3080","id":{"name":"SSN","value":"660-13-3585"},"picture":{"large":"https://randomuser.me/api/portraits/women/12.jpg","medium":"https://randomuser.me/api/portraits/med/women/12.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/12.jpg"},"nat":"US"},{"gender":"female","name":{"title":"miss","first":"vanessa","last":"foster"},"location":{"street":"5242 valley view ln","city":"flowermound","state":"tennessee","postcode":13558,"coordinates":{"latitude":"-85.6240","longitude":"-131.0245"},"timezone":{"offset":"-7:00","description":"Mountain Time (US & Canada)"}},"email":"vanessa.foster@example.com","login":{"uuid":"9bc45854-75b0-4002-b7f1-207081c92147","username":"goldenfish245","password":"goodbye","salt":"rGDJdSdC","md5":"eb0fe1df0a4f568524f01e07720d97ae","sha1":"f8ebe8f696e7b1ac84153734e3463a773649dec4","sha256":"057148219aa40967fc53c10d2c777acc62fb7a01a9a0faf855383a84afd32a26"},"dob":{"date":"1946-02-03T01:37:36Z","age":73},"registered":{"date":"2014-10-30T00:27:30Z","age":4},"phone":"(333)-737-3434","cell":"(273)-210-7504","id":{"name":"SSN","value":"446-57-6375"},"picture":{"large":"https://randomuser.me/api/portraits/women/46.jpg","medium":"https://randomuser.me/api/portraits/med/women/46.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/46.jpg"},"nat":"US"},{"gender":"female","name":{"title":"mrs","first":"carrie","last":"jackson"},"location":{"street":"1271 depaul dr","city":"irving","state":"missouri","postcode":25869,"coordinates":{"latitude":"67.9532","longitude":"36.4129"},"timezone":{"offset":"+7:00","description":"Bangkok, Hanoi, Jakarta"}},"email":"carrie.jackson@example.com","login":{"uuid":"51bc608a-668c-44df-8d63-dd866747ebc0","username":"redostrich116","password":"big1","salt":"NinaLzHv","md5":"6b73f24b67a1ff6d292749ecc502201c","sha1":"d3f87c45e97c9caf73deff71777b2bb9490e4137","sha256":"ae66c90e79829d77586e6d311536189d16e5b468654b89117f4aa8884d643591"},"dob":{"date":"1987-10-26T17:49:57Z","age":31},"registered":{"date":"2009-09-25T20:19:24Z","age":9},"phone":"(645)-827-0581","cell":"(396)-798-4186","id":{"name":"SSN","value":"022-10-5733"},"picture":{"large":"https://randomuser.me/api/portraits/women/2.jpg","medium":"https://randomuser.me/api/portraits/med/women/2.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/2.jpg"},"nat":"US"},{"gender":"male","name":{"title":"mr","first":"shawn","last":"alvarez"},"location":{"street":"1528 wycliff ave","city":"sunnyvale","state":"colorado","postcode":79015,"coordinates":{"latitude":"-61.7165","longitude":"-66.1029"},"timezone":{"offset":"+5:00","description":"Ekaterinburg, Islamabad, Karachi, Tashkent"}},"email":"shawn.alvarez@example.com","login":{"uuid":"b3b78b9e-6031-4bf5-bf39-8af090c17cc7","username":"heavyfrog857","password":"deville","salt":"DUZNI09N","md5":"57113c879b9131ede5e5951597e96acb","sha1":"be6fed8602d1558635dd7dbc6b0d4d69e2e2321a","sha256":"eb64a400a16f6b3ae1faee72e95d6fd8bda6c5c23ec28cfbe658d98c6c66981f"},"dob":{"date":"1968-04-17T22:06:24Z","age":51},"registered":{"date":"2008-05-11T07:17:35Z","age":10},"phone":"(771)-035-3479","cell":"(455)-696-0665","id":{"name":"SSN","value":"754-53-0298"},"picture":{"large":"https://randomuser.me/api/portraits/men/81.jpg","medium":"https://randomuser.me/api/portraits/med/men/81.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/81.jpg"},"nat":"US"},{"gender":"female","name":{"title":"mrs","first":"patsy","last":"smith"},"location":{"street":"7754 w campbell ave","city":"wilmington","state":"illinois","postcode":96838,"coordinates":{"latitude":"79.6094","longitude":"76.3306"},"timezone":{"offset":"+3:30","description":"Tehran"}},"email":"patsy.smith@example.com","login":{"uuid":"9306869e-7a3e-43ed-be96-799f5198213e","username":"bluefrog375","password":"chester1","salt":"ExfF8UBc","md5":"deafa4c572a916c9d636bee3bbb73b1b","sha1":"2d356d85f67985949dd1f073267404866d71abcc","sha256":"2afc6e1c73a8362188f9d5a27658b808373cbacaca30960aa4a0a1e54f8cb466"},"dob":{"date":"1991-09-26T13:40:41Z","age":27},"registered":{"date":"2003-02-12T18:16:14Z","age":16},"phone":"(067)-963-6902","cell":"(886)-454-4615","id":{"name":"SSN","value":"804-72-4306"},"picture":{"large":"https://randomuser.me/api/portraits/women/9.jpg","medium":"https://randomuser.me/api/portraits/med/women/9.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/9.jpg"},"nat":"US"},{"gender":"female","name":{"title":"miss","first":"lorraine","last":"terry"},"location":{"street":"9056 ash dr","city":"albuquerque","state":"vermont","postcode":76042,"coordinates":{"latitude":"7.6486","longitude":"113.1965"},"timezone":{"offset":"+2:00","description":"Kaliningrad, South Africa"}},"email":"lorraine.terry@example.com","login":{"uuid":"2c048319-3318-402a-9be3-6976b6465555","username":"brownladybug896","password":"bigpimp","salt":"r41AsBpv","md5":"2963b37e506afafab6ad6117edc176c8","sha1":"28667b5bcc8305208d392b1c1dd857450a527d04","sha256":"36b6b4a8d451fceb0ff7ba9a370cded707a4c61c2510e8e14fd5c62221246ccf"},"dob":{"date":"1966-11-11T12:11:41Z","age":52},"registered":{"date":"2007-07-31T21:26:38Z","age":11},"phone":"(468)-306-2488","cell":"(015)-720-8710","id":{"name":"SSN","value":"885-48-7809"},"picture":{"large":"https://randomuser.me/api/portraits/women/75.jpg","medium":"https://randomuser.me/api/portraits/med/women/75.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/75.jpg"},"nat":"US"},{"gender":"female","name":{"title":"mrs","first":"gloria","last":"wallace"},"location":{"street":"7695 w pecan st","city":"celina","state":"ohio","postcode":67498,"coordinates":{"latitude":"-60.7723","longitude":"1.6216"},"timezone":{"offset":"+9:30","description":"Adelaide, Darwin"}},"email":"gloria.wallace@example.com","login":{"uuid":"db4191da-daf1-46d8-8858-5144892c3067","username":"ticklishtiger307","password":"womam","salt":"fQzObGLY","md5":"49505e9a2a8f5219d8c6b9337b93ed9e","sha1":"5645d868b1b612bfcd8a261c382da0d618af3ca3","sha256":"5560db3b4ae1ee09eb56eaa54e98a731be62b383bced905421aa982bbd381f4c"},"dob":{"date":"1980-10-27T21:11:30Z","age":38},"registered":{"date":"2015-12-04T15:48:34Z","age":3},"phone":"(724)-327-8888","cell":"(080)-735-1689","id":{"name":"SSN","value":"041-88-2425"},"picture":{"large":"https://randomuser.me/api/portraits/women/45.jpg","medium":"https://randomuser.me/api/portraits/med/women/45.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/45.jpg"},"nat":"US"},{"gender":"female","name":{"title":"miss","first":"catherine","last":"fields"},"location":{"street":"294 photinia ave","city":"elgin","state":"utah","postcode":26988,"coordinates":{"latitude":"-18.2063","longitude":"-107.2226"},"timezone":{"offset":"+9:30","description":"Adelaide, Darwin"}},"email":"catherine.fields@example.com","login":{"uuid":"14624272-3ca7-429b-b9ef-6bfaabf4bf31","username":"beautifulcat607","password":"woody1","salt":"wVh1PacX","md5":"9321ff4cd17a5857756b97309a572f58","sha1":"6b74f3586a732379a4fc5b02cf8890f8352cacd4","sha256":"56e2f112f7607cc712049198db61373bf74d66756a7e2ac156095ec68ff06268"},"dob":{"date":"1951-08-09T04:24:31Z","age":67},"registered":{"date":"2005-06-29T03:43:32Z","age":13},"phone":"(390)-302-8656","cell":"(775)-893-9360","id":{"name":"SSN","value":"609-53-5915"},"picture":{"large":"https://randomuser.me/api/portraits/women/42.jpg","medium":"https://randomuser.me/api/portraits/med/women/42.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/42.jpg"},"nat":"US"},{"gender":"male","name":{"title":"mr","first":"clayton","last":"jennings"},"location":{"street":"6613 poplar dr","city":"richmond","state":"maine","postcode":54278,"coordinates":{"latitude":"39.4658","longitude":"-54.1005"},"timezone":{"offset":"+5:45","description":"Kathmandu"}},"email":"clayton.jennings@example.com","login":{"uuid":"121f08ae-60d0-48ab-9062-8cc481f22138","username":"greengorilla490","password":"beacon","salt":"nc3v8f5Z","md5":"9d4f1f6c192d354926ca319fcf636eac","sha1":"961cc24a840603bec0d11a38b2ba58e90ebf58ed","sha256":"769512b7f7d15a76191aee236dfe62721ce8692446c4768eaf064442f98c0478"},"dob":{"date":"1945-06-29T00:02:51Z","age":73},"registered":{"date":"2002-12-01T08:15:46Z","age":16},"phone":"(996)-440-1799","cell":"(716)-673-5511","id":{"name":"SSN","value":"532-49-8770"},"picture":{"large":"https://randomuser.me/api/portraits/men/67.jpg","medium":"https://randomuser.me/api/portraits/med/men/67.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/67.jpg"},"nat":"US"},{"gender":"female","name":{"title":"mrs","first":"felicia","last":"jacobs"},"location":{"street":"5172 lovers ln","city":"red oak","state":"connecticut","postcode":64087,"coordinates":{"latitude":"-15.7886","longitude":"152.6629"},"timezone":{"offset":"-8:00","description":"Pacific Time (US & Canada)"}},"email":"felicia.jacobs@example.com","login":{"uuid":"b46876d1-4f24-493f-8ce8-b227236e8043","username":"bluedog678","password":"enterprise","salt":"qtYZfujh","md5":"7e402d1444e5247774282bc08ab68688","sha1":"173aea89ac2410498251335676e8dff9df18229c","sha256":"d646f2f76dc94aa9d87a75bd012b52b1feff9de632c1f0f0b8b281d62a986a27"},"dob":{"date":"1958-08-01T02:07:53Z","age":60},"registered":{"date":"2015-02-27T07:24:13Z","age":4},"phone":"(453)-690-3782","cell":"(934)-523-1402","id":{"name":"SSN","value":"167-84-9919"},"picture":{"large":"https://randomuser.me/api/portraits/women/93.jpg","medium":"https://randomuser.me/api/portraits/med/women/93.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/93.jpg"},"nat":"US"},{"gender":"female","name":{"title":"mrs","first":"constance","last":"dean"},"location":{"street":"2192 edwards rd","city":"norman","state":"iowa","postcode":22649,"coordinates":{"latitude":"-65.7143","longitude":"45.8298"},"timezone":{"offset":"+11:00","description":"Magadan, Solomon Islands, New Caledonia"}},"email":"constance.dean@example.com","login":{"uuid":"14cd18fe-44b7-4c8c-a568-1984e24c891a","username":"whitedog470","password":"jimbob","salt":"vbiPXNn2","md5":"e2933576b3c2572c7a547f3c9d06ace3","sha1":"09ba3c9d1f6d3dca74d92dcf7058bfd003d25309","sha256":"28b592eaada0365d9a3db4f0a7f3e0c4f2a56e83e9a3dc8013de246e2c697c0f"},"dob":{"date":"1988-05-16T04:05:57Z","age":30},"registered":{"date":"2014-09-29T13:40:55Z","age":4},"phone":"(660)-015-4337","cell":"(207)-899-3879","id":{"name":"SSN","value":"754-17-5512"},"picture":{"large":"https://randomuser.me/api/portraits/women/77.jpg","medium":"https://randomuser.me/api/portraits/med/women/77.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/77.jpg"},"nat":"US"},{"gender":"female","name":{"title":"mrs","first":"vicki","last":"henry"},"location":{"street":"8742 oak ridge ln","city":"tulsa","state":"new hampshire","postcode":71142,"coordinates":{"latitude":"70.2570","longitude":"-128.8698"},"timezone":{"offset":"-8:00","description":"Pacific Time (US & Canada)"}},"email":"vicki.henry@example.com","login":{"uuid":"31e2ca5e-fbe0-48ec-93e9-11ab7f2d1e58","username":"yellowpanda793","password":"volume","salt":"3uZ9q5Hh","md5":"8e67a654aaabb4da8497d9fba884d4c0","sha1":"5f51b7ce8702eb93e27290fe708a4f0816ecb213","sha256":"d05628531bc26fe1199fbb03630a08e69723cef7599010c007d9d20b8c79255b"},"dob":{"date":"1994-09-22T00:24:34Z","age":24},"registered":{"date":"2002-03-26T16:45:46Z","age":17},"phone":"(179)-468-9058","cell":"(657)-877-0983","id":{"name":"SSN","value":"674-80-4537"},"picture":{"large":"https://randomuser.me/api/portraits/women/54.jpg","medium":"https://randomuser.me/api/portraits/med/women/54.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/54.jpg"},"nat":"US"},{"gender":"female","name":{"title":"miss","first":"kristin","last":"carlson"},"location":{"street":"1504 parker rd","city":"carlsbad","state":"north carolina","postcode":60018,"coordinates":{"latitude":"2.5504","longitude":"65.9229"},"timezone":{"offset":"-1:00","description":"Azores, Cape Verde Islands"}},"email":"kristin.carlson@example.com","login":{"uuid":"14fd1792-8d26-4a9d-9d0c-5fce16bbb9e4","username":"tinypeacock988","password":"brandy1","salt":"x4GL9Kev","md5":"e8cda04f2c5600ccb737bf1b7d58a85d","sha1":"413e0a59bfcc5e750be716ab3bf463324740f4ca","sha256":"77e079a61370cd823f45529f65c0e302152819a0ba803109c1344c10b58dc49e"},"dob":{"date":"1962-02-27T19:31:34Z","age":57},"registered":{"date":"2007-01-31T07:27:02Z","age":12},"phone":"(818)-172-3287","cell":"(052)-669-1939","id":{"name":"SSN","value":"494-54-3548"},"picture":{"large":"https://randomuser.me/api/portraits/women/43.jpg","medium":"https://randomuser.me/api/portraits/med/women/43.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/women/43.jpg"},"nat":"US"},{"gender":"male","name":{"title":"mr","first":"wyatt","last":"murray"},"location":{"street":"3043 hogan st","city":"aurora","state":"illinois","postcode":23280,"coordinates":{"latitude":"35.7134","longitude":"132.6444"},"timezone":{"offset":"+6:00","description":"Almaty, Dhaka, Colombo"}},"email":"wyatt.murray@example.com","login":{"uuid":"8eeaebde-6f26-4ff9-adf3-1e0c746973a1","username":"orangefrog793","password":"roberta","salt":"ynTdC9QP","md5":"7c4c83dbb744890df3310f02cd5363a4","sha1":"a7fddd293ac2fef16217499a8777b45e321b2947","sha256":"556878bd997ac5cdd217e42d2a688df12f9326c4ba6444168a05a2a936a6079d"},"dob":{"date":"1975-08-21T20:49:31Z","age":43},"registered":{"date":"2017-11-03T12:33:34Z","age":1},"phone":"(364)-323-9339","cell":"(084)-074-1653","id":{"name":"SSN","value":"780-45-6704"},"picture":{"large":"https://randomuser.me/api/portraits/men/38.jpg","medium":"https://randomuser.me/api/portraits/med/men/38.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/38.jpg"},"nat":"US"},{"gender":"male","name":{"title":"mr","first":"rick","last":"holmes"},"location":{"street":"1505 bollinger rd","city":"wichita falls","state":"south carolina","postcode":81891,"coordinates":{"latitude":"-36.9263","longitude":"-154.5656"},"timezone":{"offset":"+3:30","description":"Tehran"}},"email":"rick.holmes@example.com","login":{"uuid":"7cf68697-f55e-4efd-bb75-bd3402842d55","username":"yellowbutterfly878","password":"word","salt":"pze1BVAR","md5":"e3934a946ddd4eb459469f7acf1c279c","sha1":"b61ab0628ef17d0df3e777061a1b1e2128b2625e","sha256":"9db55c32ec4b8fe121cb43de56332d06417869f5cd265adac9900da4e44582f3"},"dob":{"date":"1981-03-17T05:04:45Z","age":38},"registered":{"date":"2008-06-07T13:44:14Z","age":10},"phone":"(975)-418-4393","cell":"(196)-586-4600","id":{"name":"SSN","value":"806-23-0588"},"picture":{"large":"https://randomuser.me/api/portraits/men/96.jpg","medium":"https://randomuser.me/api/portraits/med/men/96.jpg","thumbnail":"https://randomuser.me/api/portraits/thumb/men/96.jpg"},"nat":"US"}] -------------------------------------------------------------------------------- /react-streaming-ssr/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-streaming-ssr", 3 | "version": "0.0.1", 4 | "main": "server.js", 5 | "scripts": { 6 | "dev": "webpack --hot --watch --info-verbosity none & node -r esm server", 7 | "build": "webpack", 8 | "start": "webpack && node -r esm server" 9 | }, 10 | "dependencies": { 11 | "@babel/plugin-syntax-dynamic-import": "^7.2.0", 12 | "clean-terminal-webpack-plugin": "^2.0.2", 13 | "esm": "^3.2.22", 14 | "express": "^4.16.4", 15 | "node-fetch": "^2.3.0", 16 | "react": "^16.8.6", 17 | "react-dom": "^16.8.6", 18 | "regenerator-runtime": "^0.13.2", 19 | "size-plugin": "^1.2.0", 20 | "webpack-merge": "^4.2.1", 21 | "webpackbar": "^3.2.0" 22 | }, 23 | "devDependencies": { 24 | "@babel/core": "^7.4.4", 25 | "@babel/preset-env": "^7.4.4", 26 | "@babel/preset-react": "^7.0.0", 27 | "babel-loader": "^8.0.5", 28 | "core-js": "^3.0.1", 29 | "webpack": "^4.30.0", 30 | "webpack-cli": "^3.3.1" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /react-streaming-ssr/server.js: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | import fetch from 'node-fetch'; 3 | import express from 'express'; 4 | import ssr from './build/ssr/main.js'; 5 | import DATA from './data.json'; 6 | 7 | global.fetch = function (url, opts) { 8 | if (url[0] == '/') { 9 | let { address, port } = listener.address(); 10 | if (address == '::') address = 'localhost'; 11 | url = `http://${address}:${port}${url}`; 12 | } 13 | return fetch(url, opts); 14 | }; 15 | 16 | const app = express(); 17 | 18 | app.get('/favicon.ico', (req, res) => res.end()); 19 | 20 | app.use('/client.js', (req, res) => res.redirect('/build/client.js')); 21 | 22 | // Simulate slow network using an artificial delay for page & resource requests: 23 | const DELAY = 500; 24 | app.use((req, res, next) => { 25 | setTimeout(() => { 26 | next(); 27 | }, DELAY); 28 | }); 29 | 30 | /** API Proxy */ 31 | app.get('/api/users', (req, res) => { 32 | res.json(DATA.map(user => ({ 33 | id: user.login.uuid, 34 | username: user.login.username, 35 | name: user.name.first + ' ' + user.name.last 36 | }))); 37 | }); 38 | app.get('/api/users/:user', (req, res) => { 39 | const user = DATA.filter(user => user.login.uuid === req.params.user || user.login.username === req.params.user)[0]; 40 | if (user) res.json(user); 41 | else res.status(404).json({ error: 'user not found' }); 42 | }); 43 | 44 | const BEFORE = ` 45 | 46 | 47 |
48 | `.replace(/\n\s*/g, ''); 49 | 50 | /** SSR */ 51 | app.get('/', async (request, response) => { 52 | try { 53 | const renderComplete = ssr({ 54 | url: request.url, 55 | streaming: false 56 | }); 57 | response.useChunkedEncodingByDefault = true; 58 | response.writeHead(200, { 59 | 'content-type': 'text/html', 60 | 'content-transfer-encoding': 'chunked', 61 | 'x-content-type-options': 'nosniff' 62 | }); 63 | response.write(BEFORE); 64 | response.flushHeaders(); 65 | const html = await renderComplete; 66 | response.write(html); 67 | response.write('
'); 68 | response.end(); 69 | } 70 | catch (err) { 71 | if (!response.headersSent) { 72 | response.writeHead(500, { 73 | // @see https://twitter.com/_developit/status/1123041336054177792 74 | 'content-type': 'text/pain' 75 | }); 76 | } 77 | response.end(String(err && err.stack || err)); 78 | } 79 | }); 80 | 81 | app.get('/streaming', async (request, response) => { 82 | try { 83 | const stream = await ssr({ 84 | url: request.url 85 | }); 86 | // Wait until data starts flowing to send a 200 OK, 87 | // so errors don't trigger "headers already sent". 88 | const start = Date.now(); 89 | stream.on('data', function handleData() { 90 | console.log('Render Start: ', Date.now() - start); 91 | stream.off('data', handleData); 92 | response.useChunkedEncodingByDefault = true; 93 | response.writeHead(200, { 94 | 'content-type': 'text/html', 95 | 'content-transfer-encoding': 'chunked', 96 | 'x-content-type-options': 'nosniff' 97 | }); 98 | response.write(BEFORE); 99 | response.flushHeaders(); 100 | }); 101 | await new Promise((resolve, reject) => { 102 | stream.on('error', err => { 103 | stream.unpipe(response); 104 | reject(err); 105 | }); 106 | stream.on('end', () => { 107 | console.log('Render End: ', Date.now() - start); 108 | response.write(''); 109 | response.end(); 110 | resolve(); 111 | }); 112 | stream.pipe(response, { end: false }); 113 | }); 114 | } 115 | catch (err) { 116 | response.writeHead(500, { 117 | 'content-type': 'text/pain' 118 | }); 119 | response.end(String(err && err.stack || err)); 120 | return; 121 | } 122 | }); 123 | 124 | app.use(express.static(path.resolve(__dirname, 'app'))); 125 | app.use('/build', express.static(path.resolve(__dirname, 'build'))); 126 | 127 | const listener = app.listen(process.env.PORT || 2048, () => { 128 | console.log('Your app is listening on port ' + listener.address().port); 129 | }); 130 | -------------------------------------------------------------------------------- /react-streaming-ssr/webpack.config.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack'); 2 | const path = require('path'); 3 | const merge = require('webpack-merge'); 4 | const WebpackBar = require('webpackbar'); 5 | const SizePlugin = require('size-plugin'); 6 | const CleanTerminalPlugin = require('clean-terminal-webpack-plugin'); 7 | 8 | const baseConfig = { 9 | context: path.resolve(__dirname, 'app'), 10 | devtool: 'cheap-source-map', 11 | mode: 'production', 12 | stats: { 13 | all: false, 14 | warnings: true, 15 | errors: true, 16 | errorDetails: true 17 | }, 18 | output: { 19 | filename: 'main.js', 20 | chunkFilename: '[name].[contenthash].js' 21 | }, 22 | module: { 23 | rules: [ 24 | { 25 | test: /\.jsx?$/, 26 | exclude: /node_modules/, 27 | loader: 'babel-loader', 28 | options: { 29 | generatorOpts: { 30 | retainLines: true, 31 | compact: true, 32 | shouldPrintComment: c => /^#__PURE__$/.test(c) 33 | } 34 | } 35 | } 36 | ] 37 | }, 38 | watchOptions: { 39 | ignored: /node_modules/ 40 | } 41 | }; 42 | 43 | module.exports = (_, env) => [ 44 | merge(baseConfig, { 45 | name: 'server', 46 | target: 'node', 47 | entry: './server', 48 | optimization: { 49 | minimize: false 50 | }, 51 | output: { 52 | path: path.resolve(__dirname, 'build', 'ssr'), 53 | libraryExport: 'default', 54 | libraryTarget: 'commonjs2' 55 | }, 56 | plugins: [ 57 | new WebpackBar({ name: 'server' }) 58 | ] 59 | }), 60 | merge(baseConfig, { 61 | name: 'client', 62 | entry: './client', 63 | output: { 64 | filename: 'client.js', 65 | path: path.resolve(__dirname, 'build') 66 | }, 67 | plugins: [ 68 | new CleanTerminalPlugin({ onlyInWatchMode: true }), 69 | new WebpackBar({ name: 'client' }), 70 | new SizePlugin() 71 | ].filter(Boolean) 72 | }) 73 | ]; 74 | --------------------------------------------------------------------------------