Repository: sgwilym/relay-visual-learners
Branch: master
Commit: a3af2018fc99
Files: 53
Total size: 110.4 KB
Directory structure:
gitextract_qxbkef7i/
├── .babelrc
├── .eslintrc
├── .gitignore
├── LICENSE
├── README.md
├── docs/
│ └── why-relay.html
├── index.html
├── package.json
├── server.js
├── src/
│ ├── components/
│ │ ├── App.jsx
│ │ ├── App.scss
│ │ ├── Diagram.jsx
│ │ ├── Topic.jsx
│ │ └── Topic.scss
│ ├── diagram-data.js
│ ├── diagrams/
│ │ ├── connection-field.xml
│ │ ├── container.xml
│ │ ├── fields.xml
│ │ ├── global-id-field.xml
│ │ ├── graphql-implementation.xml
│ │ ├── mutation-type.xml
│ │ ├── mutations.xml
│ │ ├── network-layer.xml
│ │ ├── object-type.xml
│ │ ├── query-config.xml
│ │ ├── query-type.xml
│ │ ├── react-component.xml
│ │ ├── relay.xml
│ │ ├── root-container.xml
│ │ ├── schema-copy.xml
│ │ ├── schema.xml
│ │ └── web-framework.xml
│ ├── index.js
│ ├── shared/
│ │ └── styles/
│ │ └── colors.scss
│ └── topics/
│ ├── backend.js
│ ├── container.js
│ ├── graphql-impl.js
│ ├── graphql-schema.js
│ ├── mutation-type.js
│ ├── mutations.js
│ ├── network-layer.js
│ ├── object-type-fields.js
│ ├── object-type.js
│ ├── query-config.js
│ ├── query-type.js
│ ├── react-component.js
│ ├── relay.js
│ ├── root-container.js
│ ├── schema-copy.js
│ └── web-framework.js
├── svgGroup.loader.js
├── webpack.config.js
└── webpack.production.config.js
================================================
FILE CONTENTS
================================================
================================================
FILE: .babelrc
================================================
{
"stage": 0,
"plugins": ["object-assign"]
}
================================================
FILE: .eslintrc
================================================
{
"ecmaFeatures": {
"jsx": true,
"modules": true
},
"env": {
"browser": true,
"node": true
},
"parser": "babel-eslint",
"rules": {
"quotes": [2, "single"],
"strict": [2, "never"],
"react/jsx-uses-react": 2,
"react/jsx-uses-vars": 2,
"react/react-in-jsx-scope": 2
},
"plugins": [
"react"
]
}
================================================
FILE: .gitignore
================================================
node_modules
npm-debug.log
.DS_Store
build
================================================
FILE: LICENSE
================================================
The MIT License (MIT)
Copyright (c) 2014 Dan Abramov
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
relay-visual-learners
=====================
Relay is a new framework from Facebook that promises to simplify a problem complex enough that the simplification is rather complex in itself.
I tend to learn things better when I can see how things fit together, so I made this interactive diagram that attempts to explain how Relay’s various parts fit together.
This diagram itself is a small react app using css-modules and webpack. You can clone this repo and run `npm start` to load up a hot loading dev environment.
# Todo
- The diagram is constructed from fragments of a single SVG illustration broken up into separate XML files and linked to each separate topic. While this works well enough, it means changing the diagram is a bit of a brittle process that usually requires changing most of the other diagram files. If you know a better way to component-ise a SVG, please feel free to make an issue or PR!
- Think one of the explanations for one of the topics is inaccurate or could be more succinctly expressed? Contributions are more than welcome.
================================================
FILE: docs/why-relay.html
================================================
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Relay for Visual Learners • Why Relay?</title>
<style>
body {
margin: 0;
}
header {
font-family: 'Menlo', 'Courier New', monospace;
background-color: #f9f8f8;
margin: auto;
padding: 1em;
text-align: center;
}
header a {
text-decoration: none;
}
h1 {
margin: auto;
}
main {
font-family: 'Menlo', 'Courier New', monospace;
color: #3B3738;
max-width: 25em;
margin: 4em auto 5em auto;
}
img {
display: block;
margin: auto;
}
em {
font-style: italic;
font-weight: bold;
}
p {
line-height: 1.5em;
}
code {
font-family: 'Menlo', 'Courier New', monospace;
background-color: #eeecea;
padding: .2em .3em;
}
a {
color: #f26b00;
}
</style>
</head>
<body>
<header><a href="../">Relay for Visual Learners</a></header>
<main>
<h2>The Problem solved by Relay and GraphQL (for Visual Learners Who Respond Well To Cartoons)</h2>
<p>We start with our new React Component, <code>RedComponent</code>.</p>
<img width="100" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIiBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDAgMCAxMDAgMTAwIj48Y2lyY2xlIGZpbGw9IiNlMDNiNGEiIGN4PSI1MCIgY3k9IjUwIiByPSIzNyIvPjxnIGZpbGw9IiNmZmYiPjxwYXRoIGQ9Im01Ni40IDMxLjNjLTEuOSAwLTMuNS0xLjYtMy41LTMuNXMxLjYtMy41IDMuNS0zLjUgMy41IDEuNiAzLjUgMy41LTEuNiAzLjUtMy41IDMuNSIvPjxwYXRoIGQ9Im00My42IDMxLjNjLTEuOSAwLTMuNS0xLjYtMy41LTMuNXMxLjYtMy41IDMuNS0zLjVjMS45IDAgMy41IDEuNiAzLjUgMy41cy0xLjUgMy41LTMuNSAzLjUiLz48cGF0aCBkPSJtNTAgNDMuMmMtNS4zIDAtMTAuMi0yLjItMTMuNi02LS43LS44LS43LTIuMS4yLTIuOC44LS43IDIuMS0uNyAyLjguMiAyLjYgMyA2LjUgNC42IDEwLjYgNC42IDQuMSAwIDgtMS43IDEwLjYtNC42LjctLjggMi0uOSAyLjgtLjIuOC43LjkgMiAuMiAyLjgtMy40IDMuOC04LjMgNi0xMy42IDYiLz48L2c+PC9zdmc+">
<p>Like most components, <code>RedComponent</code> needs some external data to render. <code>RedComponent</code> expects data with a certain <em>shape</em>, e.g an object with <code>name</code>, <code>birthday</code> and <code>favouriteColor</code> properties.</p>
<img width="95" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA5NC43IDE2Ny41IiBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDAgMCA5NC43IDE2Ny41Ij48Y2lyY2xlIGZpbGw9IiNlMDNiNGEiIGN4PSI0Ny41IiBjeT0iMTIxLjUiIHI9IjM3Ii8+PGcgZmlsbD0iI2ZmZiI+PHBhdGggZD0ibTUzLjkgOTUuN2MtMS45IDAtMy41IDEuNi0zLjUgMy41czEuNiAzLjUgMy41IDMuNSAzLjUtMS42IDMuNS0zLjUtMS42LTMuNS0zLjUtMy41Ii8+PHBhdGggZD0ibTQxLjEgMTAyLjhjLTEuOSAwLTMuNS0xLjYtMy41LTMuNXMxLjYtMy41IDMuNS0zLjUgMy41IDEuNiAzLjUgMy41LTEuNSAzLjUtMy41IDMuNSIvPjxwYXRoIGQ9Im00Ny41IDExNC43Yy01LjMgMC0xMC4yLTIuMi0xMy42LTYtLjctLjgtLjctMi4xLjItMi44LjgtLjcgMi4xLS43IDIuOC4yIDIuNiAzIDYuNSA0LjYgMTAuNiA0LjYgNC4xIDAgOC0xLjcgMTAuNi00LjYuNy0uOCAyLS45IDIuOC0uMi44LjcuOSAyIC4yIDIuOC0zLjQgMy44LTguMyA2LTEzLjYgNiIvPjwvZz48ZyBmaWxsPSIjZTVlNWU0Ij48Y2lyY2xlIGN4PSIzNyIgY3k9Ijc2LjciIHI9IjUuMiIvPjxwYXRoIGQ9Im0xNC41IDM5LjhjMC05LjEgNy40LTE2LjQgMTYuNC0xNi40IDEgMCAxLjkuMSAyLjguMyAzLjctNC4zIDkuMi03IDE1LjMtNyA5LjEgMCAxNi43IDUuOSAxOS40IDE0LjEgNi42LjcgMTEuOCA2LjMgMTEuOCAxMy4xIDAgNy4xLTUuNiAxMi45LTEyLjYgMTMuMSAwIC4xIDAgLjIgMCAuMyAwIDcuNC02IDEzLjMtMTMuMyAxMy4zLTMuOSAwLTcuNC0xLjctOS45LTQuNC0yLjIgMS40LTQuNyAyLjItNy41IDIuMi03LjYgMC0xMy43LTYuMS0xMy43LTEzLjcgMC0uMSAwLS4yIDAtLjQtNS4yLTIuNy04LjctOC4yLTguNy0xNC41Ii8+PC9nPjxnIGZpbGw9IiNlMDNiNGEiPjxwYXRoIGQ9Im00MC4zIDU5LjJoLTNjLS45IDAtMS42LS42LTEuOS0xLjRsLTEtMi44IDMuOC0xLjIuNSAxLjVoMS41djMuOXoiLz48cGF0aCB0cmFuc2Zvcm09Im1hdHJpeCguMzA4OS45NTExLS45NTExLjMwODkgNzAuMDQuNzk1KSIgZD0ibTMxLjQgNDYuNmg2LjF2NGgtNi4xeiIvPjxwYXRoIGQ9Im0zMC43IDQzLjRsLS45LTIuOWMtLjMtLjggMC0xLjcuNy0yLjJsMi40LTEuOCAyLjQgMy4yLTEuMyAxIC41IDEuNS0zLjggMS4yIi8+PHBhdGggdHJhbnNmb3JtPSJtYXRyaXgoLjU4NzguODA5LS44MDkuNTg3OCA0NC4xMS0xNy4yNykiIGQ9Im0zNyAzMS42aDR2Ni4xaC00eiIvPjxwYXRoIGQ9Im00Ny42IDMyLjdsLTEuMy0uOS0xLjMuOS0yLjQtMy4yIDIuNC0xLjhjLjctLjUgMS43LS41IDIuNCAwbDIuNCAxLjgtMi4yIDMuMiIvPjxwYXRoIHRyYW5zZm9ybT0ibWF0cml4KC44MDkuNTg3OC0uNTg3OC44MDkgMzAuNjE2LTI0LjkyMykiIGQ9Im01MC42IDMyLjdoNi4xdjRoLTYuMXoiLz48cGF0aCBkPSJtNjIgNDMuNGwtMy44LTEuMi41LTEuNS0xLjMtLjkgMi4zLTMuMiAyLjQgMS44Yy43LjUgMSAxLjQuNyAyLjJsLS44IDIuOCIvPjxwYXRoIHRyYW5zZm9ybT0ibWF0cml4KC45NTEuMzA5LS4zMDkuOTUxIDE3Ljg2Ny0xNS42MDUpIiBkPSJtNTYuMiA0NS42aDR2Ni4xaC00eiIvPjxwYXRoIGQ9Im01NS40IDU5LjJoLTN2LTRoMS41bC41LTEuNSAzLjggMS4yLS45IDIuOWMtLjMuOS0xIDEuNC0xLjkgMS40Ii8+PHBhdGggZD0ibTQzLjMgNTUuMmg2LjF2NGgtNi4xeiIvPjwvZz48L3N2Zz4=">
<p>And let’s introduce our server, who will provide <code>RedComponent</code> with the data it needs.</p>
<img width="208" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyMDggMTY2IiBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDAgMCAyMDggMTY2Ij48ZyBmaWxsPSIjZTVlNWU0Ij48Y2lyY2xlIGN4PSIzOS4zIiBjeT0iNjkiIHI9IjUuMiIvPjxwYXRoIGQ9Im0xNi44IDMyLjFjMC05LjEgNy40LTE2LjQgMTYuNC0xNi40IDEgMCAxLjkuMSAyLjguMyAzLjctNC4zIDkuMi03IDE1LjMtNyA5LjEgMCAxNi43IDUuOSAxOS40IDE0LjEgNi42LjcgMTEuOCA2LjMgMTEuOCAxMy4xIDAgNy4xLTUuNiAxMi45LTEyLjYgMTMuMSAwIC4xIDAgLjIgMCAuMyAwIDcuNC02IDEzLjMtMTMuMyAxMy4zLTMuOSAwLTcuNC0xLjctOS45LTQuNC0yLjIgMS40LTQuNyAyLjItNy41IDIuMi03LjYgMC0xMy43LTYuMS0xMy43LTEzLjcgMC0uMSAwLS4yIDAtLjQtNS4xLTIuNy04LjctOC4yLTguNy0xNC41Ii8+PC9nPjxjaXJjbGUgZmlsbD0iI2UwM2I0YSIgY3g9IjQ5LjUiIGN5PSIxMTUuNSIgcj0iMzciLz48ZyBmaWxsPSIjZmZmIj48cGF0aCBkPSJtNTguOSA5Ni44Yy0xLjkgMC0zLjUtMS42LTMuNS0zLjVzMS42LTMuNSAzLjUtMy41IDMuNSAxLjYgMy41IDMuNS0xLjYgMy41LTMuNSAzLjUiLz48cGF0aCBkPSJtNDguMSA5Ni44Yy0xLjkgMC0zLjUtMS42LTMuNS0zLjVzMS42LTMuNSAzLjUtMy41YzEuOSAwIDMuNSAxLjYgMy41IDMuNXMtMS41IDMuNS0zLjUgMy41Ii8+PHBhdGggZD0ibTUzLjUgMTA4LjdjLTUuMyAwLTEwLjItMi4yLTEzLjYtNi0uNy0uOC0uNy0yLjEuMi0yLjguOC0uNyAyLjEtLjcgMi44LjIgMi42IDMgNi41IDQuNiAxMC42IDQuNiA0LjEgMCA4LTEuNyAxMC42LTQuNi43LS44IDItLjkgMi44LS4yLjguNy45IDIgLjIgMi44LTMuNCAzLjgtOC4zIDYtMTMuNiA2Ii8+PC9nPjxwYXRoIGQ9Im0xOTUuNSA4OS42aC01OC44Yy0uMyAwLS41LjItLjUuNXY2MS45YzAgLjMuMi41LjUuNWg1OC44Yy4zIDAgLjUtLjIuNS0uNXYtNjEuOWMwLS4yLS4yLS41LS41LS41Ii8+PGcgZmlsbD0iI2ZmZiI+PHBhdGggZD0ibTE2NC42IDExMC41Yy0xLjkgMC0zLjUtMS42LTMuNS0zLjVzMS42LTMuNSAzLjUtMy41IDMuNSAxLjYgMy41IDMuNS0xLjUgMy41LTMuNSAzLjUiLz48cGF0aCBkPSJtMTUzLjkgMTEwLjVjLTEuOSAwLTMuNS0xLjYtMy41LTMuNXMxLjYtMy41IDMuNS0zLjVjMS45IDAgMy41IDEuNiAzLjUgMy41cy0xLjYgMy41LTMuNSAzLjUiLz48cGF0aCBkPSJtMTYwLjMgMTIyLjVjLTUuMyAwLTEwLjItMi4yLTEzLjYtNi0uNy0uOC0uNy0yLjEuMi0yLjguOC0uNyAyLjEtLjcgMi44LjIgMi42IDMgNi41IDQuNiAxMC42IDQuNiA0LjEgMCA4LTEuNyAxMC42LTQuNi43LS44IDItLjkgMi44LS4yLjguNy45IDIgLjIgMi44LTMuNCAzLjgtOC40IDYtMTMuNiA2Ii8+PC9nPjxwYXRoIGZpbGw9IiNlNWU1ZTQiIGQ9Im0xOTYuNSAzNmMwLTEzLjUtMTMuOS0yNC40LTMxLjEtMjQuNC0xNy4yIDAtMzEuMSAxMC45LTMxLjEgMjQuNCAwIDExLjkgMTAuNyAyMS43IDI1IDI0IDEuMyA0LjkgMy45IDE0IDUuOCAxNCAxLjkgMCA0LjktOS4xIDYuMy0xNCAxNC4zLTIuMyAyNS4xLTEyLjIgMjUuMS0yNCIvPjxnIGZpbGw9IiNlMDNiNGEiPjxwYXRoIGQ9Im00Mi42IDUxLjJoLTNjLS45IDAtMS42LS42LTEuOS0xLjRsLS45LTIuOCAzLjgtMS4yLjUgMS41aDEuNXYzLjkiLz48cGF0aCB0cmFuc2Zvcm09Im1hdHJpeCguMzA5MS45NTEtLjk1MS4zMDkxIDY0LjA0LTYuOTU3KSIgZD0ibTMzLjggMzguNmg2LjF2NGgtNi4xeiIvPjxwYXRoIGQ9Im0zMyAzNS41bC0uOS0yLjljLS4zLS44IDAtMS43LjctMi4ybDIuNC0xLjggMi40IDMuMi0xLjMuOS41IDEuNS0zLjggMS4zIi8+PHBhdGggdHJhbnNmb3JtPSJtYXRyaXgoLjU4NzguODA5LS44MDkuNTg3OCAzOC42MDEtMjIuNDU2KSIgZD0ibTM5LjMgMjMuNmg0djYuMWgtNHoiLz48cGF0aCBkPSJtNDkuOSAyNC43bC0xLjMtLjktMS4zLjktMi40LTMuMiAyLjQtMS44Yy43LS41IDEuNi0uNSAyLjQgMGwyLjQgMS44LTIuMiAzLjIiLz48cGF0aCB0cmFuc2Zvcm09Im1hdHJpeCguODA5LjU4NzktLjU4NzkuODA5IDI2LjM2Ni0yNy44MjcpIiBkPSJtNTMgMjQuN2g2LjF2NGgtNi4xeiIvPjxwYXRoIGQ9Im02NC4zIDM1LjVsLTMuOC0xLjIuNS0xLjUtMS4zLS45IDIuNC0zLjIgMi40IDEuOGMuNy41IDEgMS40LjcgMi4ybC0uOSAyLjgiLz48cGF0aCB0cmFuc2Zvcm09Im1hdHJpeCguOTUxLjMwOS0uMzA5Ljk1MSAxNS41MDgtMTYuNzE4KSIgZD0ibTU4LjUgMzcuNmg0djYuMWgtNHoiLz48cGF0aCBkPSJtNTcuNyA1MS4yaC0zdi00aDEuNWwuNS0xLjUgMy44IDEuMi0uOSAyLjljLS4yLjktMSAxLjQtMS45IDEuNCIvPjxwYXRoIGQ9Im00NS42IDQ3LjJoNi4xdjRoLTYuMXoiLz48cGF0aCBkPSJtMTgxLjggMzAuNGwtMTQuNy0xMC43Yy0uNy0uNS0xLjctLjUtMi40IDBsLTE0LjcgMTAuN2MtLjcuNS0xIDEuNC0uNyAyLjJsNS42IDE3LjJjLjMuOCAxIDEuNCAxLjkgMS40aDE4LjFjLjkgMCAxLjYtLjYgMS45LTEuNGw1LjYtMTcuMmMuNC0uOC4xLTEuNy0uNi0yLjIiLz48L2c+PC9zdmc+">
<p>Great! Ship it.</p>
<p>This works perfectly well — until we decide to introduce a new feature provided by <code>GreenComponent</code>, which will be rendered inside <code>RedComponent</code>. This is a key strength of React: component composability.</p>
<img width="123" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjMuMyAxNTIuMyIgZW5hYmxlLWJhY2tncm91bmQ9Im5ldyAwIDAgMTIzLjMgMTUyLjMiPjxjaXJjbGUgZmlsbD0iI2UwM2I0YSIgY3g9IjYxLjciIGN5PSIxMDgiIHI9IjM3Ii8+PGcgZmlsbD0iI2ZmZiI+PHBhdGggZD0ibTc0IDg0LjNjLTEuOSAwLTMuNS0xLjYtMy41LTMuNXMxLjYtMy41IDMuNS0zLjUgMy41IDEuNiAzLjUgMy41LTEuNSAzLjUtMy41IDMuNSIvPjxwYXRoIGQ9Im02NS4zIDgyLjNjLTEuOSAwLTMuNS0xLjYtMy41LTMuNXMxLjYtMy41IDMuNS0zLjVjMS45IDAgMy41IDEuNiAzLjUgMy41cy0xLjYgMy41LTMuNSAzLjUiLz48L2c+PGcgZmlsbD0iI2U1ZTVlNCI+PGNpcmNsZSBjeD0iOTAuNyIgY3k9IjcwLjMiIHI9IjUuMiIvPjxjaXJjbGUgY3g9IjM0LjQiIGN5PSI4My4zIiByPSI0LjYiLz48cGF0aCBkPSJtMTE1LjIgMzIuNWMwLTkuMS03LjQtMTYuNC0xNi40LTE2LjQtMSAwLTEuOS4xLTIuOC4zLTMuNy00LjMtOS4yLTctMTUuMy03LTkuMSAwLTE2LjcgNS45LTE5LjQgMTQuMS02LjYuNy0xMS44IDYuMy0xMS44IDEzLjEgMCA3LjEgNS42IDEyLjkgMTIuNiAxMy4xIDAgLjEgMCAuMiAwIC4zIDAgNy40IDYgMTMuMyAxMy4zIDEzLjMgMy45IDAgNy40LTEuNyA5LjktNC40IDIuMiAxLjQgNC43IDIuMiA3LjUgMi4yIDcuNiAwIDEzLjctNi4xIDEzLjctMTMuNyAwLS4xIDAtLjIgMC0uNCA1LjItMi44IDguNy04LjIgOC43LTE0LjUiLz48L2c+PHBhdGggZmlsbD0iI2ZmZiIgZD0ibTcyLjQgOTEuMWMtMS45IDAtMy45LS4yLTUuOC0uNy01LTEuMy05LjMtNC4xLTExLjktNy43LS42LS45LS40LTIuMi41LTIuOC45LS42IDIuMi0uNCAyLjguNSAyIDIuOCA1LjUgNS4xIDkuNiA2LjEgNC4xIDEgOC4yLjggMTEuMy0uOCAxLS41IDIuMi0uMSAyLjcuOXMuMSAyLjItLjkgMi43Yy0yLjQgMS4yLTUuMyAxLjgtOC4zIDEuOCIvPjxjaXJjbGUgZmlsbD0iIzFjZDk2YSIgY3g9IjYxLjciIGN5PSIxMTUuOCIgcj0iMjQuMiIvPjxnIGZpbGw9IiNmZmYiPjxwYXRoIGQ9Im02MS41IDEwMS41Yy0xLjggMC0zLjMtMS41LTMuMy0zLjMgMC0xLjggMS41LTMuMyAzLjMtMy4zIDEuOCAwIDMuMyAxLjUgMy4zIDMuMyAwIDEuOC0xLjUgMy4zLTMuMyAzLjMiLz48cGF0aCBkPSJtNTMuOCAxMDQuNWMtMS44IDAtMy4zLTEuNS0zLjMtMy4zIDAtMS44IDEuNS0zLjMgMy4zLTMuMyAxLjggMCAzLjMgMS41IDMuMyAzLjMgMCAxLjgtMS41IDMuMy0zLjMgMy4zIi8+PHBhdGggZD0ibTU3IDExMi42Yy0yLjMgMC00LjUtLjUtNi41LTEuNi0xLS41LTEuMy0xLjctLjgtMi43LjUtMSAxLjctMS4zIDIuNy0uOCAyLjUgMS4zIDUuNiAxLjUgOC40LjUgMi44LTEgNS0zLjIgNi01LjguNC0xIDEuNi0xLjUgMi42LTEuMSAxIC40IDEuNSAxLjYgMS4xIDIuNi0xLjQgMy43LTQuNSA2LjctOC40IDguMi0xLjcuNC0zLjQuNy01LjEuNyIvPjwvZz48cGF0aCBmaWxsPSIjZTVlNWU0IiBkPSJtNDMuMyA2My4xYzMuMy0yLjMgNS4zLTYuMiA0LjktMTAuNS0uNi02LjItNi4yLTEwLjgtMTIuNC0xMC4xLTMuMS4zLTUuNyAxLjgtNy41IDQtMS42LTIuNS00LjYtNC4xLTcuOC0zLjgtNC42LjUtNy45IDQuNi03LjQgOS4xLjIgMi40IDEuNCA0LjQgMy4yIDUuNy0yLjQgMi40LTMuNyA1LjgtMy4zIDkuNC43IDYuNCA2LjQgMTEuMSAxMi44IDEwLjQgMy44LS40IDctMi42IDguOC01LjcgMS4yLjggMi42IDEuMSA0LjEgMSAzLjUtLjQgNi0zLjUgNS43LTYuOS0uMy0uOS0uNy0xLjgtMS4xLTIuNiIvPjxnIGZpbGw9IiMxY2Q5NmEiPjxwYXRoIGQ9Im0yNS4yIDY2LjJoLTNjLS41IDAtMS0uMy0xLjMtLjgtLjMtLjUtLjMtMSAwLTEuNWwxLjUtMi42IDIuNiAxLjUtLjIuM2guNHYzLjEiLz48cGF0aCB0cmFuc2Zvcm09Im1hdHJpeCguODY2LjUwMDEtLjUwMDEuODY2IDMyLjU2LTUuMTYzKSIgZD0ibTI0LjQgNTUuOWgzdjQuNWgtM3oiLz48cGF0aCBkPSJtMjkuOSA1NWwtLjItLjMtLjIuMy0yLjYtMS41IDEuNS0yLjZjLjMtLjUuOC0uOCAxLjMtLjhzMSAuMyAxLjMuOGwxLjUgMi42LTIuNiAxLjUiLz48cGF0aCB0cmFuc2Zvcm09Im1hdHJpeCguNS44NjYtLjg2Ni41IDY3LjA4LjE0MikiIGQ9Im0zMS4yIDU2LjdoNC41djNoLTQuNXoiLz48cGF0aCBkPSJtMzcuMiA2Ni4yaC0zdi0zaC40bC0uMi0uMyAyLjYtMS41IDEuNSAyLjZjLjMuNS4zIDEgMCAxLjUtLjMuNC0uOC43LTEuMy43Ii8+PHBhdGggZD0ibTI3LjQgNjMuMmg0LjV2M2gtNC41eiIvPjwvZz48ZyBmaWxsPSIjZTAzYjRhIj48cGF0aCBkPSJtNzcuMyA1MS4yaC0zYy0uOSAwLTEuNi0uNi0xLjktMS40bC0xLTIuOCAzLjgtMS4yLjUgMS41aDEuNXYzLjl6Ii8+PHBhdGggdHJhbnNmb3JtPSJtYXRyaXgoLjMwOTEuOTUxLS45NTEuMzA5MSA4Ny45OTEtMzkuOTI2KSIgZD0ibTY4LjQgMzguNmg2LjF2NGgtNi4xeiIvPjxwYXRoIGQ9Im02Ny43IDM1LjRsLS45LTIuOWMtLjMtLjggMC0xLjcuNy0yLjJsMi40LTEuOCAyLjQgMy4yLTEuMyAxIC41IDEuNS0zLjggMS4yIi8+PHBhdGggdHJhbnNmb3JtPSJtYXRyaXgoLjU4NzguODA5LS44MDkuNTg3OCA1Mi44ODktNTAuNSkiIGQ9Im03NCAyMy42aDR2Ni4xaC00eiIvPjxwYXRoIGQ9Im04NC42IDI0LjdsLTEuMy0uOS0xLjMuOS0yLjQtMy4yIDIuNC0xLjhjLjctLjUgMS42LS41IDIuNCAwbDIuNCAxLjgtMi4yIDMuMiIvPjxwYXRoIHRyYW5zZm9ybT0ibWF0cml4KC44MDkuNTg3OC0uNTg3OC44MDkgMzIuOTc5LTQ4LjIpIiBkPSJtODcuNiAyNC43aDYuMXY0aC02LjF6Ii8+PHBhdGggZD0ibTk5IDM1LjRsLTMuOC0xLjIuNS0xLjUtMS4zLS45IDIuNC0zLjIgMi40IDEuOGMuNy41IDEgMS40LjcgMi4ybC0uOSAyLjgiLz48cGF0aCB0cmFuc2Zvcm09Im1hdHJpeCguOTUxLjMwOS0uMzA5Ljk1MSAxNy4yMDUtMjcuNDMxKSIgZD0ibTkzLjIgMzcuNmg0djYuMWgtNHoiLz48cGF0aCBkPSJtOTIuNCA1MS4yaC0zdi00aDEuNWwuNS0xLjUgMy44IDEuMi0uOSAyLjljLS4zLjktMSAxLjQtMS45IDEuNCIvPjxwYXRoIGQ9Im04MC4zIDQ3LjJoNi4xdjRoLTYuMXoiLz48L2c+PC9zdmc+">
<p><code>GreenComponent</code> expects data too, but it needs a different shape. And because it's rendered by <code>RedComponent</code>, <code>RedComponent</code> has the responsibility of passing down that data to <code>GreenComponent</code>.</p>
<p>And remember: our server now needs to serve the data our new composition of components <em>expects</em>.</p>
<img width="214" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyMTQgMTYzLjMiIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMCAwIDIxNCAxNjMuMyI+PHBhdGggZD0ibTE5OS4yIDg3aC01OC44Yy0uMyAwLS41LjItLjUuNXY2MS45YzAgLjMuMi41LjUuNWg1OC44Yy4zIDAgLjUtLjIuNS0uNXYtNjEuOWMwLS4zLS4zLS41LS41LS41Ii8+PGcgZmlsbD0iI2ZmZiI+PHBhdGggZD0ibTE2OC4zIDEwNy44Yy0xLjkgMC0zLjUtMS42LTMuNS0zLjVzMS42LTMuNSAzLjUtMy41IDMuNSAxLjYgMy41IDMuNS0xLjYgMy41LTMuNSAzLjUiLz48cGF0aCBkPSJtMTU3LjUgMTA3LjhjLTEuOSAwLTMuNS0xLjYtMy41LTMuNXMxLjYtMy41IDMuNS0zLjVjMS45IDAgMy41IDEuNiAzLjUgMy41cy0xLjUgMy41LTMuNSAzLjUiLz48cGF0aCBkPSJtMTYzLjkgMTE5LjhjLTUuMyAwLTEwLjItMi4yLTEzLjYtNi0uNy0uOC0uNy0yLjEuMi0yLjguOC0uNyAyLjEtLjcgMi44LjIgMi42IDMgNi41IDQuNiAxMC42IDQuNiA0LjEgMCA4LTEuNyAxMC42LTQuNi43LS44IDItLjkgMi44LS4yLjguNy45IDIgLjIgMi44LTMuNCAzLjgtOC4zIDYtMTMuNiA2Ii8+PC9nPjxwYXRoIGZpbGw9IiNlNWU1ZTQiIGQ9Im0yMDAuMSA0NC4zYzAtMTMuNS0xMy45LTI0LjQtMzEuMS0yNC40LTE3LjIgMC0zMS4xIDEwLjktMzEuMSAyNC40IDAgMTEuOSAxMC43IDIxLjcgMjUgMjQgMS4zIDQuOSAzLjkgMTQgNS44IDE0IDEuOSAwIDQuOS05LjEgNi4zLTE0IDE0LjMtMi4yIDI1LjEtMTIuMSAyNS4xLTI0Ii8+PGcgZmlsbD0iI2UwM2I0YSI+PHBhdGggZD0ibTE4NS4yIDM4bC0xNC43LTEwLjdjLS43LS41LTEuNy0uNS0yLjQgMGwtMTQuNiAxMC43Yy0uNy41LTEgMS40LS43IDIuMmw1LjYgMTcuMmMuMy44IDEgMS40IDEuOSAxLjRoMTguMWMuOSAwIDEuNi0uNiAxLjktMS40bDUuNi0xNy4yYy4zLS44IDAtMS43LS43LTIuMiIvPjxjaXJjbGUgY3g9IjYzIiBjeT0iMTE1LjciIHI9IjM3Ii8+PC9nPjxnIGZpbGw9IiNmZmYiPjxwYXRoIGQ9Im03NC40IDkwLjljLTEuOSAwLTMuNS0xLjYtMy41LTMuNXMxLjYtMy41IDMuNS0zLjUgMy41IDEuNiAzLjUgMy41LTEuNiAzLjUtMy41IDMuNSIvPjxwYXRoIGQ9Im02NS42IDg4LjljLTEuOSAwLTMuNS0xLjYtMy41LTMuNXMxLjYtMy41IDMuNS0zLjVjMS45IDAgMy41IDEuNiAzLjUgMy41cy0xLjUgMy41LTMuNSAzLjUiLz48L2c+PGcgZmlsbD0iI2U1ZTVlNCI+PGNpcmNsZSBjeD0iOTIuMSIgY3k9Ijc4IiByPSI1LjIiLz48Y2lyY2xlIGN4PSIzNS43IiBjeT0iOTEiIHI9IjQuNiIvPjxwYXRoIGQ9Im0xMTYuNiA0MC4xYzAtOS4xLTcuNC0xNi40LTE2LjQtMTYuNC0xIDAtMS45LjEtMi44LjMtMy43LTQuMy05LjItNy0xNS4zLTctOS4xIDAtMTYuNyA1LjktMTkuNCAxNC4xLTYuNi43LTExLjggNi4zLTExLjggMTMuMSAwIDcuMSA1LjYgMTIuOSAxMi42IDEzLjEgMCAuMSAwIC4yIDAgLjMgMCA3LjQgNiAxMy4zIDEzLjMgMTMuMyAzLjkgMCA3LjQtMS43IDkuOS00LjQgMi4yIDEuNCA0LjcgMi4yIDcuNSAyLjIgNy42IDAgMTMuNy02LjEgMTMuNy0xMy43IDAtLjEgMC0uMiAwLS40IDUuMS0yLjcgOC43LTguMiA4LjctMTQuNSIvPjwvZz48cGF0aCBmaWxsPSIjZmZmIiBkPSJtNzIuNCA5Ny45Yy0yLjIgMC00LjQtLjMtNi42LTEtNC45LTEuNS05LjEtNC40LTExLjUtOC4yLS42LS45LS4zLTIuMi42LTIuOC45LS42IDIuMi0uMyAyLjguNiAxLjkgMi45IDUuMyA1LjMgOS4zIDYuNSA0IDEuMiA4LjIgMS4xIDExLjQtLjMgMS0uNCAyLjIgMCAyLjYgMSAuNCAxIDAgMi4yLTEgMi42LTIuMyAxLjEtNC45IDEuNi03LjYgMS42Ii8+PGNpcmNsZSBmaWxsPSIjMWNkOTZhIiBjeD0iNjMiIGN5PSIxMjMuNCIgcj0iMjQuMiIvPjxnIGZpbGw9IiNmZmYiPjxwYXRoIGQ9Im03NC41IDExNC4zaC0uNGMtMS44LS4yLTMuMS0xLjgtMi45LTMuNi4yLTEuNyAxLjYtMi45IDMuMy0yLjloLjRjLjkuMSAxLjYuNSAyLjIgMS4yLjUuNy44IDEuNS43IDIuNC0uMiAxLjYtMS42IDIuOS0zLjMgMi45Ii8+PHBhdGggZD0ibTY2LjUgMTE2LjRoLS40Yy0xLjgtLjItMy4xLTEuOC0yLjktMy42LjItMS43IDEuNi0yLjkgMy4zLTIuOWguNGMuOS4xIDEuNy41IDIuMiAxLjIuNS43LjggMS41LjcgMi40LS4yIDEuNi0xLjYgMi45LTMuMyAyLjkiLz48cGF0aCBkPSJtNzAgMTI0LjljLTIuOCAwLTUuNi0uOC04LTIuNC0uOS0uNi0xLjEtMS45LS41LTIuOC42LS45IDEuOS0xLjEgMi44LS41IDIuNCAxLjYgNS40IDIuMSA4LjMgMS40IDIuOS0uNyA1LjMtMi42IDYuNy01LjEuNS0xIDEuNy0xLjQgMi43LS44IDEgLjUgMS40IDEuNy44IDIuNy0xLjkgMy41LTUuMiA2LjEtOS4yIDcuMS0xLjMuMi0yLjUuNC0zLjYuNCIvPjwvZz48cGF0aCBmaWxsPSIjZTVlNWU0IiBkPSJtNDQuNiA3MC44YzMuMy0yLjMgNS4zLTYuMiA0LjktMTAuNS0uNi02LjItNi4yLTEwLjgtMTIuNC0xMC4xLTMuMS4zLTUuNyAxLjgtNy41IDQtMS42LTIuNS00LjYtNC4xLTcuOC0zLjgtNC42LjUtNy45IDQuNi03LjQgOS4xLjIgMi40IDEuNCA0LjQgMy4yIDUuNy0yLjQgMi40LTMuNyA1LjgtMy4zIDkuNC41IDYuNCA2LjIgMTEuMSAxMi42IDEwLjQgMy44LS40IDctMi42IDguOC01LjcgMS4yLjggMi42IDEuMSA0LjEgMSAzLjUtLjQgNi0zLjUgNS43LTYuOS0uMS0xLS40LTEuOS0uOS0yLjYiLz48ZyBmaWxsPSIjMWNkOTZhIj48cGF0aCBkPSJtMjYuNSA3My44aC0zYy0uNSAwLTEtLjMtMS4zLS44LS4zLS41LS4zLTEgMC0xLjVsMS41LTIuNiAyLjYgMS41LS4yLjNoLjR2My4xIi8+PHBhdGggdHJhbnNmb3JtPSJtYXRyaXgoLjg2Ni41MDAxLS41MDAxLjg2NiAzNi41NzItNC44MDMpIiBkPSJtMjUuNyA2My42aDN2NC41aC0zeiIvPjxwYXRoIGQ9Im0zMS4yIDYyLjdsLS4yLS40LS4yLjMtMi42LTEuNSAxLjUtMi42Yy4zLS41LjgtLjggMS4zLS44czEgLjMgMS4zLjhsMS41IDIuNi0yLjYgMS42Ii8+PHBhdGggdHJhbnNmb3JtPSJtYXRyaXgoLjUuODY2LS44NjYuNSA3NC4zOSAyLjgyMSkiIGQ9Im0zMi41IDY0LjNoNC41djNoLTQuNXoiLz48cGF0aCBkPSJtMzguNSA3My44aC0zdi0zaC40bC0uMi0uMyAyLjYtMS41IDEuNSAyLjZjLjMuNS4zIDEgMCAxLjUtLjMuNC0uOC43LTEuMy43Ii8+PHBhdGggZD0ibTI4LjcgNzAuOGg0LjV2M2gtNC41eiIvPjxwYXRoIGQ9Im0xNzcgNDkuMWwtNy41LTEzYy0uMS0uMi0uMy0uMi0uNC0uMnMtLjMuMS0uNC4ybC03LjUgMTNjLS4xLjItLjEuMyAwIC41LjEuMi4zLjIuNC4yaDE1Yy4yIDAgLjMtLjEuNC0uMi4xLS4yLjEtLjQgMC0uNSIvPjwvZz48ZyBmaWxsPSIjZTAzYjRhIj48cGF0aCBkPSJtNzguNCA1OS4yaC0zYy0uOSAwLTEuNi0uNi0xLjktMS40bC0uOS0yLjggMy44LTEuMi41IDEuNWgxLjV2My45Ii8+PHBhdGggdHJhbnNmb3JtPSJtYXRyaXgoLjMwOTEuOTUxLS45NTEuMzA5MSA5Ni40MS0zNS41MDgpIiBkPSJtNjkuNiA0Ni42aDYuMXY0aC02LjF6Ii8+PHBhdGggZD0ibTY4LjkgNDMuNGwtLjktMi45Yy0uMy0uOCAwLTEuNy43LTIuMmwyLjQtMS44IDIuNCAzLjItMS4zLjkuNSAxLjUtMy44IDEuMyIvPjxwYXRoIHRyYW5zZm9ybT0ibWF0cml4KC41ODc4LjgwOS0uODA5LjU4NzggNTkuODQyLTQ4LjE1KSIgZD0ibTc1LjIgMzEuNmg0djYuMWgtNHoiLz48cGF0aCBkPSJtODUuOCAzMi43bC0xLjMtLjktMS4zLjktMi40LTMuMiAyLjQtMS44Yy43LS41IDEuNy0uNSAyLjQgMGwyLjQgMS44LTIuMiAzLjIiLz48cGF0aCB0cmFuc2Zvcm09Im1hdHJpeCguODA5LjU4NzgtLjU4NzguODA5IDM3LjkwNC00Ny4zNikiIGQ9Im04OC44IDMyLjdoNi4xdjRoLTYuMXoiLz48cGF0aCBkPSJtMTAwLjEgNDMuNGwtMy44LTEuMi41LTEuNS0xLjMtLjkgMi40LTMuMiAyLjQgMS44Yy43LjUgMSAxLjQuNyAyLjJsLS45IDIuOCIvPjxwYXRoIHRyYW5zZm9ybT0ibWF0cml4KC45NTEuMzA5LS4zMDkuOTUxIDE5LjczNS0yNy40KSIgZD0ibTk0LjQgNDUuNmg0djYuMWgtNHoiLz48cGF0aCBkPSJtOTMuNiA1OS4yaC0zdi00aDEuNWwuNS0xLjUgMy44IDEuMi0uOSAyLjljLS4zLjktMS4xIDEuNC0xLjkgMS40Ii8+PHBhdGggZD0ibTgxLjUgNTUuMmg2LjF2NGgtNi4xeiIvPjwvZz48L3N2Zz4=">
<p>With a little work, we eventually get this working. But times change, and now we’re deprecating <code>RedComponent</code> for the latest in UI sophistication: <code>BlueComponent</code>. Again, this is React doing what React does best: cleanly composing new and existing components together.</p>
<img width="119" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMTguNyAxNTAiIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMCAwIDExOC43IDE1MCI+PGNpcmNsZSBmaWxsPSIjMDA1M2M5IiBjeD0iNTcuMiIgY3k9IjEwNS42IiByPSIzNyIvPjxnIGZpbGw9IiNlNWU1ZTQiPjxjaXJjbGUgY3g9Ijg2LjIiIGN5PSI2OCIgcj0iNS4yIi8+PGNpcmNsZSBjeD0iMjkuOSIgY3k9IjgyLjIiIHI9IjQuNiIvPjxwYXRoIGQ9Im0xMTAuNyAzMS40YzAtOS4xLTcuNC0xNi40LTE2LjQtMTYuNC0xIDAtMS45LjEtMi44LjMtMy43LTQuMy05LjItNy0xNS4zLTctOS4xIDAtMTYuNyA1LjktMTkuNCAxNC4xLTYuNy42LTExLjggNi4yLTExLjggMTMgMCA3LjEgNS42IDEyLjkgMTIuNiAxMy4xIDAgLjEgMCAuMiAwIC4zIDAgNy40IDYgMTMuMyAxMy4zIDEzLjMgMy45IDAgNy40LTEuNyA5LjktNC40IDIuMiAxLjQgNC43IDIuMiA3LjUgMi4yIDcuNiAwIDEzLjctNi4xIDEzLjctMTMuNyAwLS4xIDAtLjIgMC0uNCA1LjItMi43IDguNy04LjEgOC43LTE0LjQiLz48L2c+PGNpcmNsZSBmaWxsPSIjMWNkOTZhIiBjeD0iNTcuMiIgY3k9IjExMy40IiByPSIyNC4yIi8+PGcgZmlsbD0iI2ZmZiI+PHBhdGggZD0ibTY5LjkgMTAzLjJjLS45IDAtMS45LS40LTIuNS0xLjEtLjYtLjctLjktMS41LS44LTIuNC4xLS45LjUtMS43IDEuMS0yLjIgMS4zLTEuMSAzLjUtMSA0LjYuMyAxLjIgMS40IDEgMy40LS4zIDQuNi0uNS41LTEuMy44LTIuMS44Ii8+PHBhdGggZD0ibTYyLjYgOTkuNGMtLjkgMC0xLjgtLjQtMi41LTEuMS0uNi0uNy0uOS0xLjUtLjgtMi40LjEtLjkuNS0xLjcgMS4xLTIuMiAxLjMtMS4xIDMuNS0xIDQuNi4zLjYuNy45IDEuNS44IDIuNC0uMS45LS41IDEuNy0xLjEgMi4yLS41LjUtMS4zLjgtMi4xLjgiLz48cGF0aCBkPSJtNDguOCA3OS45Yy0uOSAwLTEuOS0uNC0yLjUtMS4xLS42LS43LS45LTEuNS0uOC0yLjQuMS0uOS41LTEuNyAxLjEtMi4yIDEuMy0xLjEgMy41LTEgNC42LjMgMS4yIDEuNCAxIDMuNC0uMyA0LjYtLjYuNi0xLjQuOC0yLjEuOCIvPjxwYXRoIGQ9Im01Ny44IDc4LjJjLS45IDAtMS45LS40LTIuNS0xLjEtLjYtLjctLjktMS41LS44LTIuNC4xLS45LjUtMS43IDEuMS0yLjIgMS4zLTEuMSAzLjUtMSA0LjYuMyAxLjIgMS40IDEgMy40LS4zIDQuNi0uNi41LTEuNC44LTIuMS44Ii8+PC9nPjxwYXRoIGZpbGw9IiNlNWU1ZTQiIGQ9Im0zOC44IDYyYzMuMy0yLjMgNS4zLTYuMiA0LjktMTAuNS0uNi02LjItNi4yLTEwLjgtMTIuNC0xMC4xLTMuMS4zLTUuNyAxLjgtNy41IDQtMS42LTIuNS00LjYtNC4xLTcuOC0zLjgtNC42LjUtNy45IDQuNi03LjQgOS4xLjIgMi40IDEuNCA0LjQgMy4yIDUuNy0yLjQgMi40LTMuNyA1LjgtMy4zIDkuNC43IDYuNCA2LjQgMTEuMSAxMi44IDEwLjQgMy44LS40IDctMi42IDguOC01LjcgMS4yLjggMi42IDEuMSA0LjEgMSAzLjUtLjQgNi0zLjUgNS43LTYuOS0uMy0uOS0uNy0xLjgtMS4xLTIuNiIvPjxnIGZpbGw9IiMxY2Q5NmEiPjxwYXRoIGQ9Im0yMC43IDY1LjFoLTNjLS41IDAtMS0uMy0xLjMtLjgtLjMtLjUtLjMtMSAwLTEuNWwxLjUtMi42IDIuNiAxLjUtLjIuM2guNHYzLjEiLz48cGF0aCB0cmFuc2Zvcm09Im1hdHJpeCguODY2LjUwMDEtLjUwMDEuODY2IDMxLjQwNi0zLjA2MSkiIGQ9Im0xOS45IDU0LjhoM3Y0LjVoLTN6Ii8+PHBhdGggZD0ibTI1LjQgNTMuOWwtLjItLjMtLjIuMy0yLjYtMS41IDEuNS0yLjZjLjMtLjUuOC0uOCAxLjMtLjhzMSAuMyAxLjMuOGwxLjUgMi42LTIuNiAxLjUiLz48cGF0aCB0cmFuc2Zvcm09Im1hdHJpeCguNS44NjYtLjg2Ni41IDYzLjg4MSAzLjQ4OCkiIGQ9Im0yNi43IDU1LjZoNC41djNoLTQuNXoiLz48cGF0aCBkPSJtMzIuNyA2NS4xaC0zdi0zaC40bC0uMi0uMyAyLjYtMS41IDEuNSAyLjZjLjMuNS4zIDEgMCAxLjUtLjMuNC0uOC43LTEuMy43Ii8+PHBhdGggZD0ibTIyLjkgNjIuMWg0LjV2M2gtNC41eiIvPjwvZz48cGF0aCBmaWxsPSIjZmZmIiBkPSJtNjAuMiAxMTAuNGMtLjIgMC0uNCAwLS42LS4xLS42LS4yLTEuMi0uNi0xLjUtMS4yLS44LTEuNC0uNC0zLjMtLjItNCAuNi0yLjMgMS45LTMuOCAzLjUtMy44LjIgMCAuNCAwIC42LjEgMS43LjUgMi40IDIuNSAxLjcgNS4yLS43IDIuNC0yIDMuOC0zLjUgMy44Ii8+PGcgZmlsbD0iIzAwNTNjOSI+PHBhdGggZD0ibTY4IDMwLjNoLTR2LTNjMC0uNy40LTEuNCAxLTEuN2wyLjYtMS41IDIgMy41LTEuNi45djEuOCIvPjxwYXRoIHRyYW5zZm9ybT0ibWF0cml4KC40OTk5Ljg2NjEtLjg2NjEuNDk5OSA1Ni42NzgtNTAuOTUzKSIgZD0ibTcwLjUgMjEuNGg0djQuNWgtNHoiLz48cGF0aCBkPSJtODAuNSAyMy4xbC0xLjYtLjktMS42LjktMi0zLjUgMi42LTEuNWMuNi0uNCAxLjQtLjQgMiAwbDIuNiAxLjUtMiAzLjUiLz48cGF0aCB0cmFuc2Zvcm09Im1hdHJpeCguODY2MS40OTk4LS40OTk4Ljg2NjEgMjMuMjMtMzkuNTE3KSIgZD0ibTgzLjIgMjEuNmg0LjV2NGgtNC41eiIvPjxwYXRoIGQ9Im05My44IDMwLjNoLTR2LTEuOGwtMS42LS45IDItMy41IDIuNiAxLjVjLjYuNCAxIDEgMSAxLjd2MyIvPjxwYXRoIGQ9Im04OS44IDMyLjZoNHY0LjVoLTR6Ii8+PHBhdGggZD0ibTkwLjIgNDUuNWwtMi0zLjUgMS42LS45di0xLjhoNHYzYzAgLjctLjQgMS40LTEgMS43bC0yLjYgMS41Ii8+PHBhdGggdHJhbnNmb3JtPSJtYXRyaXgoLjQ5OTkuODY2MS0uODY2MS40OTk5IDgyLjUyLTUwLjk1MikiIGQ9Im04My40IDQzLjhoNHY0LjVoLTR6Ii8+PHBhdGggZD0ibTc4LjkgNTEuN2MtLjMgMC0uNy0uMS0xLS4zbC0yLjYtMS41IDItMy41IDEuNi45IDEuNi0uOSAyIDMuNS0yLjYgMS41Yy0uMy4yLS42LjMtMSAuMyIvPjxwYXRoIHRyYW5zZm9ybT0ibWF0cml4KC44NjYuNTAwMS0uNTAwMS44NjYgMzIuNzA4LTMwLjA3KSIgZD0ibTcwLjIgNDRoNC41djRoLTQuNXoiLz48cGF0aCBkPSJtNjcuNiA0NS41bC0yLjYtMS41Yy0uNi0uNC0xLTEtMS0xLjd2LTNoNHYxLjhsMS42LjktMiAzLjUiLz48cGF0aCBkPSJtNjQgMzIuNmg0djQuNWgtNHoiLz48L2c+PHBhdGggZmlsbD0iI2ZmZiIgZD0ibTU0LjIgODljLTQuOCAwLTkuMy0xLjgtMTIuNi01LS44LS44LS44LTIgMC0yLjguOC0uOCAyLS44IDIuOCAwIDIuOCAyLjggNi44IDQuMiAxMC45IDMuOSA0LjEtLjMgNy44LTIuMyAxMC4yLTUuNC43LS45IDEuOS0xIDIuOC0uNC45LjcgMSAxLjkuNCAyLjgtMy4xIDQtNy45IDYuNi0xMy4xIDYuOS0uNSAwLS45IDAtMS40IDAiLz48L3N2Zz4=">
<p>But guess what? <code>BlueComponent</code> <em>expects</em> a different shape of data. So unless we make some changes server-side, our components aren't going to render properly!</p>
<img width="248" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNDggMTcwLjciIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMCAwIDI0OCAxNzAuNyI+PHBhdGggZmlsbD0iI2U1ZTVlNCIgZD0ibTIyOC41IDQyLjZjMC0xMy41LTEzLjktMjQuNC0zMS4xLTI0LjRzLTMxLjEgMTAuOS0zMS4xIDI0LjRjMCAxMS45IDEwLjcgMjEuNyAyNSAyNCAxLjMgNC45IDMuOSAxNCA1LjggMTQgMS45IDAgNC45LTkuMSA2LjMtMTQgMTQuMy0yLjIgMjUuMS0xMi4xIDI1LjEtMjQiLz48cGF0aCBkPSJtMjI3LjUgODUuM2gtNTguOGMtLjMgMC0uNS4yLS41LjV2NjEuOWMwIC4zLjIuNS41LjVoNTguOGMuMyAwIC41LS4yLjUtLjV2LTYxLjljMC0uMy0uMi0uNS0uNS0uNSIvPjxnIGZpbGw9IiNmZmYiPjxwYXRoIGQ9Im0xOTUuNiAxMjIuMmMtMS45IDAtMy41LTEuNi0zLjUtMy41czEuNi0zLjUgMy41LTMuNSAzLjUgMS42IDMuNSAzLjUtMS41IDMuNS0zLjUgMy41Ii8+PHBhdGggZD0ibTE4NC45IDEyMi4yYy0xLjkgMC0zLjUtMS42LTMuNS0zLjVzMS42LTMuNSAzLjUtMy41IDMuNSAxLjYgMy41IDMuNS0xLjYgMy41LTMuNSAzLjUiLz48cGF0aCBkPSJtMTk5LjYgMTMyLjdjLS42IDAtMS4xLS4yLTEuNS0uNy0xLjktMi4yLTQuOC0zLjUtNy45LTMuNiAwIDAtLjEgMC0uMSAwLTMgMC01LjkgMS4yLTcuOCAzLjQtLjcuOC0yIC45LTIuOC4xLS44LS43LS45LTItLjEtMi44IDIuOC0zIDYuNy00LjcgMTEtNC43IDQuMiAwIDguMiAxLjggMTAuOCA0LjkuNy44LjYgMi4xLS4yIDIuOC0uNC40LS45LjYtMS40LjYiLz48L2c+PHBhdGggZmlsbD0iI2UwM2I0YSIgZD0ibTIxMy4yIDM2LjdsLTE0LjYtMTAuN2MtLjctLjUtMS43LS41LTIuNCAwbC0xNC43IDEwLjdjLS43LjUtMSAxLjQtLjcgMi4ybDUuNiAxNy4yYy4zLjggMSAxLjQgMS45IDEuNGgxOC4xYy45IDAgMS42LS42IDEuOS0xLjRsNS42LTE3LjJjLjMtLjggMC0xLjctLjctMi4yIi8+PHBhdGggZmlsbD0iIzFjZDk2YSIgZD0ibTIwNS4zIDQ3LjRsLTcuNS0xM2MtLjItLjMtLjctLjMtLjkgMGwtNy41IDEzYy0uMS4yLS4xLjMgMCAuNS4xLjIuMy4yLjQuMmgxNWMuMiAwIC4zLS4xLjQtLjIuMi0uMS4yLS4zLjEtLjUiLz48Y2lyY2xlIGZpbGw9IiMwMDUzYzkiIGN4PSI2NC4yIiBjeT0iMTE2LjMiIHI9IjM3Ii8+PGcgZmlsbD0iI2U1ZTVlNCI+PGNpcmNsZSBjeD0iOTMuMiIgY3k9Ijc4LjYiIHI9IjUuMiIvPjxjaXJjbGUgY3g9IjM2LjkiIGN5PSI5Mi45IiByPSI0LjYiLz48cGF0aCBkPSJtMTE3LjcgNDJjMC05LjEtNy40LTE2LjQtMTYuNC0xNi40LTEgMC0xLjkuMS0yLjguMy0zLjctNC4zLTkuMi03LTE1LjMtNy05LjEgMC0xNi43IDUuOS0xOS40IDE0LjEtNi43LjctMTEuOCA2LjMtMTEuOCAxMy4xIDAgNy4xIDUuNiAxMi45IDEyLjYgMTMuMSAwIC4xIDAgLjIgMCAuMyAwIDcuNCA2IDEzLjMgMTMuMyAxMy4zIDMuOSAwIDcuNC0xLjcgOS45LTQuNCAyLjIgMS40IDQuNyAyLjIgNy41IDIuMiA3LjYgMCAxMy43LTYuMSAxMy43LTEzLjcgMC0uMSAwLS4yIDAtLjQgNS4yLTIuNyA4LjctOC4yIDguNy0xNC41Ii8+PC9nPjxjaXJjbGUgZmlsbD0iIzFjZDk2YSIgY3g9IjY0LjIiIGN5PSIxMjMuMSIgcj0iMjQuMiIvPjxnIGZpbGw9IiNmZmYiPjxwYXRoIGQ9Im03Ny45IDEyMi45Yy0uOSAwLTEuOC0uNC0yLjUtMS4xLTEuMi0xLjQtMS0zLjQuMy00LjYgMS4zLTEuMSAzLjUtMSA0LjYuMyAxLjIgMS40IDEgMy40LS4zIDQuNi0uNS41LTEuMy44LTIuMS44Ii8+PHBhdGggZD0ibTY4LjYgMTIzYy0uOSAwLTEuOC0uNC0yLjUtMS4xLS42LS43LS45LTEuNS0uOC0yLjQuMS0uOS41LTEuNyAxLjEtMi4yLjYtLjUgMS40LS44IDIuMi0uOC45IDAgMS44LjQgMi41IDEuMS42LjcuOSAxLjUuOCAyLjRzLS41IDEuNy0xLjEgMi4yYy0uNi41LTEuNC44LTIuMi44Ii8+PHBhdGggZD0ibTYwLjMgODkuM2MtLjkgMC0xLjgtLjQtMi41LTEuMS0uNi0uNy0uOS0xLjUtLjgtMi40LjEtLjkuNS0xLjcgMS4xLTIuMi42LS41IDEuNC0uOCAyLjItLjguOSAwIDEuOC40IDIuNSAxLjEuNi43LjkgMS41LjggMi40cy0uNSAxLjctMS4xIDIuMmMtLjYuNS0xLjQuOC0yLjIuOCIvPjxwYXRoIGQ9Im02OC45IDg5LjNjLS45IDAtMS44LS40LTIuNS0xLjEtLjYtLjctLjktMS41LS44LTIuNC4xLS45LjUtMS43IDEuMS0yLjIgMS4zLTEuMSAzLjUtMSA0LjYuMy42LjcuOSAxLjUuOCAyLjQtLjEuOS0uNSAxLjctMS4xIDIuMi0uNS41LTEuMy44LTIuMS44Ii8+PC9nPjxwYXRoIGZpbGw9IiNlNWU1ZTQiIGQ9Im00NS44IDcyLjdjMy4zLTIuMyA1LjMtNi4yIDQuOS0xMC41LS43LTYuMy02LjItMTAuOC0xMi41LTEwLjItMy4xLjMtNS43IDEuOC03LjUgNC0xLjYtMi41LTQuNi00LjEtNy44LTMuOC00LjYuNS03LjkgNC42LTcuNCA5LjEuMiAyLjQgMS40IDQuNCAzLjIgNS43LTIuNCAyLjQtMy43IDUuOC0zLjMgOS40LjcgNi40IDYuNCAxMS4xIDEyLjggMTAuNCAzLjgtLjQgNy0yLjYgOC44LTUuNyAxLjIuOCAyLjYgMS4xIDQuMSAxIDMuNS0uNCA2LTMuNSA1LjctNi45LS4yLS45LS42LTEuOC0xLTIuNSIvPjxnIGZpbGw9IiMxY2Q5NmEiPjxwYXRoIGQ9Im0yNy43IDc1LjdoLTNjLS41IDAtMS0uMy0xLjMtLjgtLjMtLjUtLjMtMSAwLTEuNWwxLjUtMi42IDIuNiAxLjUtLjIuM2guNHYzLjEiLz48cGF0aCB0cmFuc2Zvcm09Im1hdHJpeCguODY2LjUwMDEtLjUwMDEuODY2IDM3LjY3OC01LjEzMikiIGQ9Im0yNi45IDY1LjVoM3Y0LjVoLTN6Ii8+PHBhdGggZD0ibTMyLjQgNjQuNmwtLjItLjMtLjIuMy0yLjYtMS41IDEuNS0yLjZjLjMtLjUuOC0uOCAxLjMtLjhzMSAuMyAxLjMuOGwxLjUgMi42LTIuNiAxLjUiLz48cGF0aCB0cmFuc2Zvcm09Im1hdHJpeCguNTAwMS44NjYtLjg2Ni41MDAxIDc2LjYxIDIuNzU1KSIgZD0ibTMzLjcgNjYuMmg0LjV2M2gtNC41eiIvPjxwYXRoIGQ9Im0zOS43IDc1LjdoLTN2LTNoLjRsLS4yLS4zIDIuNi0xLjUgMS41IDIuNmMuMy41LjMgMSAwIDEuNS0uMy40LS44LjctMS4zLjciLz48cGF0aCBkPSJtMjkuOSA3Mi43aDQuNXYzaC00LjV6Ii8+PC9nPjxwYXRoIGZpbGw9IiNmZmYiIGQ9Im02NS44IDEzMi4xYy0uNSAwLTEtLjItMS40LS41LS44LS43LS45LTItLjEtMi44LjMtLjMgMi45LTMgOC44LTMuNSA2LjItLjUgOS40IDIuOSA5LjYgMy4xLjcuOC43IDIuMS0uMSAyLjgtLjguNy0yLjEuNy0yLjgtLjEtLjEtLjEtMi4xLTIuMi02LjMtMS44LTQuMy40LTYuMSAyLjEtNi4yIDIuMi0uNS40LTEgLjYtMS41LjYiLz48ZyBmaWxsPSIjMDA1M2M5Ij48cGF0aCBkPSJtNzUuMiA0MC45aC00di0zYzAtLjcuNC0xLjQgMS0xLjdsMi42LTEuNSAyIDMuNS0xLjYuOHYxLjkiLz48cGF0aCB0cmFuc2Zvcm09Im1hdHJpeCguNDk5OS44NjYxLS44NjYxLjQ5OTkgNjkuNDMtNTEuOTU2KSIgZD0ibTc3LjcgMzEuOWg0djQuNWgtNHoiLz48cGF0aCBkPSJtODQuNiAzMy42bC0yLTMuNSAyLjYtMS41Yy42LS40IDEuNC0uNCAyIDBsMi42IDEuNS0yIDMuNS0xLjYtLjktMS42LjkiLz48cGF0aCB0cmFuc2Zvcm09Im1hdHJpeCguODY2LjUwMDEtLjUwMDEuODY2IDI5LjQ5LTQxLjc0NikiIGQ9Im05MC40IDMyLjFoNC41djRoLTQuNXoiLz48cGF0aCBkPSJtMTAxLjEgNDAuOWgtNHYtMS45bC0xLjYtLjkgMi0zLjUgMi42IDEuNWMuNi40IDEgMSAxIDEuN3YzLjEiLz48cGF0aCBkPSJtOTcuMSA0My4xaDR2NC41aC00eiIvPjxwYXRoIGQ9Im05Ny41IDU2bC0yLTMuNSAxLjYtLjl2LTEuOGg0djNjMCAuNy0uNCAxLjQtMSAxLjdsLTIuNiAxLjUiLz48cGF0aCB0cmFuc2Zvcm09Im1hdHJpeCguNDk5OS44NjYxLS44NjYxLjQ5OTkgOTUuMjctNTEuOTU2KSIgZD0ibTkwLjYgNTQuM2g0djQuNWgtNHoiLz48cGF0aCBkPSJtODYuMiA2Mi4zYy0uMyAwLS43LS4xLTEtLjNsLTIuNi0xLjUgMi0zLjUgMS42LjkgMS42LS45IDIgMy41LTIuNiAxLjVjLS4zLjItLjcuMy0xIC4zIi8+PHBhdGggdHJhbnNmb3JtPSJtYXRyaXgoLjg2Ni41MDAxLS41MDAxLjg2NiAzOC45NS0zMi4yOCkiIGQ9Im03Ny41IDU0LjVoNC41djRoLTQuNXoiLz48cGF0aCBkPSJtNzQuOCA1NmwtMi42LTEuNWMtLjYtLjQtMS0xLTEtMS43di0zaDR2MS44bDEuNi45LTIgMy41Ii8+PHBhdGggZD0ibTcxLjIgNDMuMWg0djQuNWgtNHoiLz48L2c+PHBhdGggZmlsbD0iI2ZmZiIgZD0ibTc2LjMgMTAwLjVjLS42IDAtMS4xLS4yLTEuNS0uNy0yLjYtMy02LjQtNC43LTEwLjUtNC44LTQuMSAwLTggMS42LTEwLjcgNC41LS43LjgtMiAuOS0yLjguMS0uOC0uNy0uOS0yLS4xLTIuOCAzLjMtMy43IDguMi01LjggMTMuMy01LjguMSAwIC4yIDAgLjMgMCA1LjMuMSAxMC4yIDIuMyAxMy41IDYuMi43LjguNiAyLjEtLjIgMi44LS40LjMtLjguNS0xLjMuNSIvPjwvc3ZnPg==">
<p>And what if we build another client with different components, like a mobile client? We’ll have to add another endpoint to our server to satisfy those components’ data expectations.</p>
<img width="375" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzNzQuNyAxNzAuNyIgZW5hYmxlLWJhY2tncm91bmQ9Im5ldyAwIDAgMzc0LjcgMTcwLjciPjxwYXRoIGZpbGw9IiNlNWU1ZTQiIGQ9Im0yNTcgMzIuNmMwLTEzLjUtMTMuOS0yNC40LTMxLjEtMjQuNC0xNC41IDAtMjYuNyA3LjgtMzAuMSAxOC40LTUuNy01LjEtMTQuMS04LjQtMjMuNC04LjQtMTcuMiAwLTMxLjEgMTAuOS0zMS4xIDI0LjQgMCAxMS45IDEwLjcgMjEuNyAyNSAyNCAxLjMgNC45IDMuOSAxNCA1LjggMTQgMS45IDAgNC45LTkuMSA2LjMtMTQgMTEuOC0xLjggMjEuMS04LjggMjQuMS0xNy45IDUuNyA1LjEgMTQuMSA4LjQgMjMuNCA4LjQgNC44IDAgOS4zLS44IDEzLjMtMi40IDIuNSA2LjQtNC40IDkuOC0yLjggMTIuNSAxLjcgMi45IDE1LjktNy43IDEyLjgtMTguNSA0LjgtNC4yIDcuOC05LjkgNy44LTE2LjEiLz48cGF0aCBkPSJtMjQ2LjcgMTAwLjRsLTE4LjktNDEuNGMtLjEtLjEtLjItLjItLjMtLjMtLjEgMC0uMyAwLS40IDBsLTM5LjQgMThjLS4zLjEtLjQuNC0uMi43bDMuNiA3LjloLTQ3LjVjLS4zIDAtLjUuMi0uNS41djYxLjljMCAuMy4yLjUuNS41aDU4LjhjLjMgMCAuNS0uMi41LS41di0zNi41bDMuNSA3LjZjLjEuMS4yLjIuMy4zLjEgMCAuMSAwIC4yIDAgLjEgMCAuMSAwIC4yIDBsMzkuNC0xOGMuMi0uMS40LS40LjItLjciLz48ZyBmaWxsPSIjZmZmIj48cGF0aCBkPSJtMTc2LjYgMTE2LjJjLTEuOSAwLTMuNS0xLjYtMy41LTMuNXMxLjYtMy41IDMuNS0zLjUgMy41IDEuNiAzLjUgMy41LTEuNSAzLjUtMy41IDMuNSIvPjxwYXRoIGQ9Im0xNjUuOSAxMTYuMmMtMS45IDAtMy41LTEuNi0zLjUtMy41czEuNi0zLjUgMy41LTMuNSAzLjUgMS42IDMuNSAzLjUtMS42IDMuNS0zLjUgMy41Ii8+PHBhdGggZD0ibTIyOS43IDg2LjVjLTEuOCAwLTMuNC0xLjQtMy41LTMuMy0uMS0uOS4yLTEuOC45LTIuNi42LS43IDEuNS0xLjEgMi40LTEuMmguM2MxLjggMCAzLjQgMS40IDMuNSAzLjMuMSAxLjktMS4zIDMuNi0zLjMgMy44aC0uMyIvPjxwYXRoIGQ9Im0yMTguOSA4Ny4yYy0xLjggMC0zLjQtMS40LTMuNS0zLjMtLjEtMS45IDEuMy0zLjYgMy4zLTMuOGguM2MxLjggMCAzLjQgMS40IDMuNSAzLjMuMSAxLjktMS4zIDMuNi0zLjMgMy44aC0uMyIvPjxwYXRoIGQ9Im0xODAuNiAxMjYuN2MtLjYgMC0xLjEtLjItMS41LS43LTEuOS0yLjItNC44LTMuNS03LjktMy42LTMuMS0uMS02IDEuMi04IDMuNC0uNy44LTIgLjktMi44LjEtLjgtLjctLjktMi0uMS0yLjggMi44LTMgNi43LTQuNyAxMS00LjcgNC4yIDAgOC4yIDEuOCAxMC45IDQuOS43LjguNiAyLjEtLjIgMi44LS40LjQtLjkuNi0xLjQuNiIvPjwvZz48cGF0aCBmaWxsPSIjZTAzYjRhIiBkPSJtMTg4LjIgMzYuN2wtMTQuNi0xMC43Yy0uNy0uNS0xLjctLjUtMi40IDBsLTE0LjcgMTAuN2MtLjcuNS0xIDEuNC0uNyAyLjJsNS42IDE3LjJjLjMuOCAxIDEuNCAxLjkgMS40aDE4LjFjLjkgMCAxLjYtLjYgMS45LTEuNGw1LjYtMTcuMmMuMy0uOCAwLTEuNy0uNy0yLjIiLz48cGF0aCBmaWxsPSIjMWNkOTZhIiBkPSJtMTgwLjMgNDcuNGwtNy41LTEzYy0uMi0uMy0uNy0uMy0uOSAwbC03LjUgMTNjLS4xLjItLjEuMyAwIC41LjEuMi4zLjIuNC4yaDE1Yy4yIDAgLjMtLjEuNC0uMi4yLS4xLjItLjMuMS0uNSIvPjxjaXJjbGUgZmlsbD0iIzAwNTNjOSIgY3g9IjY0LjIiIGN5PSIxMTYuMyIgcj0iMzciLz48Y2lyY2xlIGZpbGw9IiNmZmMyMDAiIGN4PSIzMTEuNyIgY3k9IjExNi4zIiByPSIzNyIvPjxnIGZpbGw9IiNlNWU1ZTQiPjxjaXJjbGUgY3g9IjkzLjIiIGN5PSI3OC42IiByPSI1LjIiLz48Y2lyY2xlIGN4PSIzNi45IiBjeT0iOTIuOSIgcj0iNC42Ii8+PHBhdGggZD0ibTExNy43IDQyYzAtOS4xLTcuNC0xNi40LTE2LjQtMTYuNC0xIDAtMS45LjEtMi44LjMtMy43LTQuMy05LjItNy0xNS4zLTctOS4xIDAtMTYuNyA1LjktMTkuNCAxNC4xLTYuNy43LTExLjggNi4zLTExLjggMTMuMSAwIDcuMSA1LjYgMTIuOSAxMi42IDEzLjEgMCAuMSAwIC4yIDAgLjMgMCA3LjQgNiAxMy4zIDEzLjMgMTMuMyAzLjkgMCA3LjQtMS43IDkuOS00LjQgMi4yIDEuNCA0LjcgMi4yIDcuNSAyLjIgNy42IDAgMTMuNy02LjEgMTMuNy0xMy43IDAtLjEgMC0uMiAwLS40IDUuMi0yLjcgOC43LTguMiA4LjctMTQuNSIvPjwvZz48Y2lyY2xlIGZpbGw9IiMxY2Q5NmEiIGN4PSI2NC4yIiBjeT0iMTIzLjEiIHI9IjI0LjIiLz48ZyBmaWxsPSIjZmZmIj48cGF0aCBkPSJtNzcuOSAxMjIuOWMtLjkgMC0xLjgtLjQtMi41LTEuMS0uNi0uNy0uOS0xLjUtLjgtMi40LjEtLjkuNS0xLjcgMS4xLTIuMiAxLjMtMS4xIDMuNS0xIDQuNi4zLjYuNy45IDEuNS44IDIuNC0uMS45LS41IDEuNy0xLjEgMi4yLS41LjUtMS4zLjgtMi4xLjgiLz48cGF0aCBkPSJtNjguNiAxMjNjLS45IDAtMS44LS40LTIuNS0xLjEtLjYtLjctLjktMS41LS44LTIuNHMuNS0xLjcgMS4xLTIuMmMuNi0uNSAxLjQtLjggMi4yLS44LjkgMCAxLjguNCAyLjUgMS4xLjYuNy45IDEuNS44IDIuNC0uMS45LS41IDEuNy0xLjEgMi4yLS42LjUtMS40LjgtMi4yLjgiLz48cGF0aCBkPSJtNjAuNSA4OS4zYy0uOSAwLTEuOC0uNC0yLjUtMS4xLS42LS43LS45LTEuNS0uOC0yLjQuMS0uOS41LTEuNyAxLjEtMi4yLjYtLjUgMS40LS44IDIuMi0uOC45IDAgMS44LjQgMi41IDEuMS42LjcuOSAxLjUuOCAyLjQtLjEuOS0uNSAxLjctMS4xIDIuMi0uNi41LTEuNC44LTIuMi44Ii8+PHBhdGggZD0ibTY5LjEgODkuM2MtLjkgMC0xLjgtLjQtMi41LTEuMS0uNi0uNy0uOS0xLjUtLjgtMi40LjEtLjkuNS0xLjcgMS4xLTIuMi42LS41IDEuNC0uOCAyLjItLjguOSAwIDEuOC40IDIuNSAxLjEuNi43LjkgMS41LjggMi40LS4xLjktLjUgMS43LTEuMSAyLjItLjYuNS0xLjQuOC0yLjIuOCIvPjwvZz48cGF0aCBmaWxsPSIjZTVlNWU0IiBkPSJtNDUuOCA3Mi43YzMuMy0yLjMgNS4zLTYuMiA0LjktMTAuNS0uNy02LjMtNi4yLTEwLjgtMTIuNS0xMC4yLTMuMS4zLTUuNyAxLjgtNy41IDQtMS42LTIuNS00LjYtNC4xLTcuOC0zLjgtNC42LjUtNy45IDQuNi03LjQgOS4xLjIgMi40IDEuNCA0LjQgMy4yIDUuNy0yLjQgMi40LTMuNyA1LjgtMy4zIDkuNC43IDYuNCA2LjQgMTEuMSAxMi44IDEwLjQgMy44LS40IDctMi42IDguOC01LjcgMS4yLjggMi42IDEuMSA0LjEgMSAzLjUtLjQgNi0zLjUgNS43LTYuOS0uMi0uOS0uNi0xLjgtMS0yLjUiLz48ZyBmaWxsPSIjMWNkOTZhIj48cGF0aCBkPSJtMjcuNyA3NS43aC0zYy0uNSAwLTEtLjMtMS4zLS44LS4zLS41LS4zLTEgMC0xLjVsMS41LTIuNiAyLjYgMS41LS4yLjNoLjR2My4xIi8+PHBhdGggdHJhbnNmb3JtPSJtYXRyaXgoLjg2Ni41MDAxLS41MDAxLjg2NiAzNy42NzgtNS4xMzIpIiBkPSJtMjYuOSA2NS41aDN2NC41aC0zeiIvPjxwYXRoIGQ9Im0zMi40IDY0LjZsLS4yLS4zLS4yLjMtMi42LTEuNSAxLjUtMi42Yy4zLS41LjgtLjggMS4zLS44czEgLjMgMS4zLjhsMS41IDIuNi0yLjYgMS41Ii8+PHBhdGggdHJhbnNmb3JtPSJtYXRyaXgoLjUwMDEuODY2LS44NjYuNTAwMSA3Ni42MSAyLjc1NikiIGQ9Im0zMy43IDY2LjJoNC41djNoLTQuNXoiLz48cGF0aCBkPSJtMzkuNyA3NS43aC0zdi0zaC40bC0uMi0uMyAyLjYtMS41IDEuNSAyLjZjLjMuNS4zIDEgMCAxLjUtLjMuNC0uOC43LTEuMy43Ii8+PHBhdGggZD0ibTI5LjkgNzIuN2g0LjV2M2gtNC41eiIvPjwvZz48cGF0aCBmaWxsPSIjZmZmIiBkPSJtNjUuOCAxMzIuMWMtLjUgMC0xLS4yLTEuMy0uNS0uOC0uNy0uOS0yLS4xLTIuOC4zLS4zIDIuOS0zIDguOC0zLjUgNi4yLS41IDkuNCAyLjkgOS42IDMuMS43LjguNyAyLjEtLjEgMi44LS44LjctMi4xLjctMi44LS4xLS4xLS4xLTIuMS0yLjItNi4zLTEuOC00LjMuNC02LjEgMi4yLTYuMSAyLjItLjYuNC0xLjIuNi0xLjcuNiIvPjxnIGZpbGw9IiMwMDUzYzkiPjxwYXRoIGQ9Im03NS4yIDQwLjloLTR2LTNjMC0uNy40LTEuNCAxLTEuN2wyLjYtMS41IDIgMy41LTEuNi44djEuOSIvPjxwYXRoIHRyYW5zZm9ybT0ibWF0cml4KC40OTk5Ljg2NjEtLjg2NjEuNDk5OSA2OS40My01MS45NTcpIiBkPSJtNzcuNyAzMS45aDR2NC41aC00eiIvPjxwYXRoIGQ9Im04Ny44IDMzLjZsLTEuNi0uOS0xLjYuOS0yLTMuNSAyLjYtMS41Yy42LS40IDEuNC0uNCAyIDBsMi42IDEuNS0yIDMuNSIvPjxwYXRoIHRyYW5zZm9ybT0ibWF0cml4KC44NjYuNTAwMS0uNTAwMS44NjYgMjkuNDg5LTQxLjc0NikiIGQ9Im05MC40IDMyLjFoNC41djRoLTQuNXoiLz48cGF0aCBkPSJtMTAxLjEgNDAuOWgtNHYtMS45bC0xLjYtLjkgMi0zLjUgMi42IDEuNWMuNi40IDEgMSAxIDEuN3YzLjEiLz48cGF0aCBkPSJtOTcuMSA0My4xaDR2NC41aC00eiIvPjxwYXRoIGQ9Im05Ny41IDU2bC0yLTMuNSAxLjYtLjl2LTEuOGg0djNjMCAuNy0uNCAxLjQtMSAxLjdsLTIuNiAxLjUiLz48cGF0aCB0cmFuc2Zvcm09Im1hdHJpeCguNDk5OS44NjYxLS44NjYxLjQ5OTkgOTUuMjgtNTEuOTU2KSIgZD0ibTkwLjYgNTQuM2g0djQuNWgtNHoiLz48cGF0aCBkPSJtODYuMiA2Mi4zYy0uMyAwLS43LS4xLTEtLjNsLTIuNi0xLjUgMi0zLjUgMS42LjkgMS42LS45IDIgMy41LTIuNiAxLjVjLS4zLjItLjcuMy0xIC4zIi8+PHBhdGggdHJhbnNmb3JtPSJtYXRyaXgoLjg2Ni41MDAxLS41MDAxLjg2NiAzOC45NS0zMi4yOCkiIGQ9Im03Ny41IDU0LjVoNC41djRoLTQuNXoiLz48cGF0aCBkPSJtNzQuOCA1NmwtMi42LTEuNWMtLjYtLjQtMS0xLTEtMS43di0zaDR2MS44bDEuNi45LTIgMy41Ii8+PHBhdGggZD0ibTcxLjIgNDMuMWg0djQuNWgtNHoiLz48L2c+PGcgZmlsbD0iI2U1ZTVlNCI+PGNpcmNsZSBjeD0iMzI2LjciIGN5PSI3My4xIiByPSI1LjIiLz48cGF0aCBkPSJtMzUxLjIgMzYuNWMwLTkuMS03LjQtMTYuNC0xNi40LTE2LjQtMSAwLTEuOS4xLTIuOC4zLTMuNy00LjMtOS4yLTctMTUuMy03LTkuMSAwLTE2LjcgNS45LTE5LjQgMTQuMS02LjYuNy0xMS44IDYuMy0xMS44IDEzLjEgMCA3LjEgNS42IDEyLjkgMTIuNiAxMy4xIDAgLjEgMCAuMiAwIC4zIDAgNy40IDYgMTMuMyAxMy4zIDEzLjMgMy45IDAgNy40LTEuNyA5LjktNC40IDIuMiAxLjQgNC43IDIuMiA3LjUgMi4yIDcuNiAwIDEzLjctNi4xIDEzLjctMTMuNyAwLS4xIDAtLjIgMC0uNCA1LjItMi43IDguNy04LjIgOC43LTE0LjUiLz48L2c+PHBhdGggZmlsbD0iI2ZmZiIgZD0ibTIyNC4xIDk3LjhjLS4yIDAtLjQgMC0uNi0uMS0uNi0uMi0xLjItLjYtMS41LTEuMi0uOC0xLjQtLjQtMy4zLS4yLTQgLjYtMi4zIDEuOS0zLjggMy41LTMuOC4yIDAgLjQgMCAuNi4xLjUuMSAxLjcuNyAyIDIuNi4xLjggMCAxLjctLjIgMi42LS43IDIuNC0yIDMuOC0zLjYgMy44Ii8+PGcgZmlsbD0iI2ZmYzIwMCI+PHBhdGggZD0ibTI0MC41IDI1LjhsLTguMi04LjJjLS4xLS4xLS4yLS4xLS40LS4xaC0xMS42Yy0uMSAwLS4zLjEtLjQuMWwtOC4yIDguMmMtLjEuMS0uMS4yLS4xLjR2MTEuNmMwIC4xLjEuMy4xLjRsOC4yIDguMmMuMS4xLjIuMS40LjFoMTEuN2MuMSAwIC4zLS4xLjQtLjFsOC4yLTguMmMuMS0uMS4xLS4yLjEtLjR2LTExLjZjMC0uMS0uMS0uMy0uMi0uNCIvPjxwYXRoIGQ9Im0zMjMuNyA1Ni41aC02LjJ2LTRoNi4ydjRtLTEwLjgtLjZsLTQuNC00LjQgMi44LTIuOCA0LjQgNC40LTIuOCAyLjhtMTUtLjVsLTIuOC0yLjggNC40LTQuNCAyLjggMi44LTQuNCA0LjRtLTIxLjUtNmwtMS42LTEuNmMtLjQtLjQtLjYtLjktLjYtMS40di0zLjloNHYzbDEuMSAxLjEtMi45IDIuOG0yOC4xLS42bC0yLjgtMi44LjUtLjV2LTMuOGg0djQuNmMwIC41LS4yIDEtLjYgMS40bC0xLjEgMS4xbS0yNi40LTkuNWgtNHYtNC42YzAtLjUuMi0xIC42LTEuNGwxLjEtMS4xIDIuOCAyLjgtLjUuNXYzLjhtMjguMS0uN2gtNHYtM2wtMS4xLTEuMSAyLjgtMi44IDEuNiAxLjZjLjQuNC42LjkuNiAxLjR2My45em0tMjUuNC01LjhsLTIuOC0yLjggNC40LTQuNCAyLjggMi44LTQuNCA0LjRtMTguMS0uNWwtNC40LTQuNCAyLjgtMi44IDQuNCA0LjQtMi44IDIuOG0tNi0zLjhoLTYuMnYtNGg2LjJ2NCIvPjwvZz48ZyBmaWxsPSIjZmZmIj48cGF0aCBkPSJtMzA0LjcgMTAwLjRjLS4xIDAtLjMgMC0uNCAwLTEuOS0uMi0zLjMtMi0zLjEtMy45LjItMS45IDEuOS0zLjMgMy45LTMuMS45LjEgMS44LjYgMi40IDEuM3MuOSAxLjcuNyAyLjZjLS4yIDEuOC0xLjcgMy4xLTMuNSAzLjEiLz48cGF0aCBkPSJtMjk0IDk5LjJjLS4xIDAtLjMgMC0uNCAwLS45LS4xLTEuOC0uNi0yLjQtMS4zLS42LS43LS45LTEuNy0uNy0yLjYuMi0xLjkgMS45LTMuMyAzLjktMy4xLjkuMSAxLjguNiAyLjQgMS4zcy45IDEuNy43IDIuNmMtLjIgMS44LTEuNyAzLjEtMy41IDMuMSIvPjxwYXRoIGQ9Im0yOTkuMyAxMTEuNmMtLjUgMC0uOSAwLTEuNC0uMS00LjItLjQtOC0yLjUtMTAuNC01LjgtLjctLjktLjUtMi4xLjQtMi44LjktLjcgMi4xLS41IDIuOC40IDEuNyAyLjQgNC41IDMuOSA3LjYgNC4yIDMuMS4zIDYtLjcgOC4yLTIuNy44LS44IDIuMS0uNyAyLjguMS44LjguNyAyLjEtLjEgMi44LTIuNyAyLjUtNi4yIDMuOS05LjkgMy45Ii8+PHBhdGggZD0ibTc2LjkgMTAwLjNjLS42IDAtMS4xLS4yLTEuNS0uNy0yLjYtMy02LjQtNC43LTEwLjUtNC44LTQuMSAwLTggMS42LTEwLjcgNC41LS43LjgtMiAuOS0yLjguMS0uOC0uNy0uOS0yLS4xLTIuOCAzLjQtMy44IDguNC01LjggMTMuNy01LjggNS4zLjEgMTAuMiAyLjMgMTMuNSA2LjIuNy44LjYgMi4xLS4yIDIuOC0uNC40LS45LjUtMS40LjUiLz48L2c+PC9zdmc+">
<p>I've been using the word '<em>expects</em>' here, because there’s absolutely no way for the server to really know what shape of data our components need. In this setup, the responsibility to keeping the expectations of the components and the data provided by the server in sync belongs to the <em>developer</em>.</p>
<img width="367" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzNjYuNyAxMzIiIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMCAwIDM2Ni43IDEzMiI+PHBhdGggZD0ibTIzOC43IDYxLjdsLTE4LjktNDEuNGMtLjEtLjItLjQtLjQtLjctLjJsLTM5LjQgMThjLS4xLjEtLjIuMi0uMy4zIDAgLjEgMCAuMyAwIC40bDMuNiA3LjloLTQ3LjVjLS4zIDAtLjUuMi0uNS41djYxLjhjMCAuMy4yLjUuNS41aDU4LjhjLjMgMCAuNS0uMi41LS41di0zNi40bDMuNSA3LjZjLjEuMi4zLjMuNS4zLjEgMCAuMSAwIC4yIDBsMzkuNC0xOGMuMS0uMS4yLS4yLjMtLjMuMS0uMi4xLS4zIDAtLjUiLz48ZyBmaWxsPSIjZmZmIj48cGF0aCBkPSJtMTY4LjkgNzYuNWMtMS40IDAtMi41LTEuMS0yLjUtMi41czEuMS0yLjUgMi41LTIuNSAyLjUgMS4xIDIuNSAyLjUtMS4xIDIuNS0yLjUgMi41Ii8+PHBhdGggZD0ibTE1OC4xIDc2LjVjLTEuNCAwLTIuNS0xLjEtMi41LTIuNXMxLjEtMi41IDIuNS0yLjUgMi41IDEuMSAyLjUgMi41LTEuMSAyLjUtMi41IDIuNSIvPjxwYXRoIGQ9Im0yMjEuNyA0Ni44Yy0xLjMgMC0yLjQtMS0yLjUtMi4zLS4xLTEuNCAxLTIuNiAyLjMtMi43aC4yYzEuMyAwIDIuNCAxIDIuNSAyLjMuMSAxLjQtMSAyLjYtMi4zIDIuN2gtLjIiLz48cGF0aCBkPSJtMjEwLjkgNDYuOGMtMS4zIDAtMi40LTEtMi41LTIuMyAwLS43LjItMS4zLjYtMS44LjQtLjUgMS4xLS44IDEuNy0uOWguMmMxLjMgMCAyLjQgMSAyLjUgMi4zIDAgLjctLjIgMS4zLS42IDEuOC0uNC41LTEuMS44LTEuNy45aC0uMiIvPjwvZz48Y2lyY2xlIGZpbGw9IiMwMDUzYzkiIGN4PSI1Ni4yIiBjeT0iNzcuNiIgcj0iMzciLz48Y2lyY2xlIGZpbGw9IiNmZmMyMDAiIGN4PSIzMDMuNyIgY3k9Ijc3LjYiIHI9IjM3Ii8+PGNpcmNsZSBmaWxsPSIjMWNkOTZhIiBjeD0iNTYuMiIgY3k9Ijg0LjQiIHI9IjI0LjIiLz48ZyBmaWxsPSIjZmZmIj48cGF0aCBkPSJtNjkuOSA4My4zYy0uNyAwLTEuMy0uMy0xLjctLjgtLjgtLjktLjctMi40LjItMy4yLjktLjggMi40LS43IDMuMi4yLjQuNS42IDEgLjYgMS43IDAgLjYtLjMgMS4yLS44IDEuNi0uNC4zLS45LjUtMS41LjUiLz48cGF0aCBkPSJtNjAuNiA4My4zYy0uNyAwLTEuMy0uMy0xLjctLjgtLjQtLjUtLjYtMS0uNi0xLjcgMC0uNi4zLTEuMi44LTEuNi45LS44IDIuNC0uNyAzLjIuMi40LjUuNiAxIC42IDEuNyAwIC42LS4zIDEuMi0uOCAxLjYtLjQuNC0xIC42LTEuNS42Ii8+PHBhdGggZD0ibTUxLjMgNDkuNmMtLjcgMC0xLjMtLjMtMS43LS44LS40LS41LS42LTEtLjYtMS43cy4zLTEuMi44LTEuNmMuOS0uOCAyLjQtLjcgMy4yLjIuNC41LjYgMSAuNiAxLjdzLS4zIDEuMi0uOCAxLjZjLS40LjQtLjkuNi0xLjUuNiIvPjxwYXRoIGQ9Im02MC45IDQ5LjZjLS43IDAtMS4zLS4zLTEuNy0uOC0uNC0uNS0uNi0xLS42LTEuN3MuMy0xLjIuOC0xLjZjLjktLjggMi40LS43IDMuMi4yLjQuNS42IDEgLjYgMS43cy0uMyAxLjItLjggMS42Yy0uNC40LS45LjYtMS41LjYiLz48cGF0aCBkPSJtMjk2LjcgNjAuMmMtLjEgMC0uMiAwLS4zIDAtMS40LS4yLTIuNC0xLjQtMi4yLTIuOC4yLTEuNCAxLjQtMi40IDIuOC0yLjIgMS40LjIgMi40IDEuNCAyLjIgMi44LS4yIDEuMi0xLjIgMi4yLTIuNSAyLjIiLz48cGF0aCBkPSJtMjg2IDYwLjJjLS4xIDAtLjIgMC0uMyAwLTEuNC0uMi0yLjQtMS40LTIuMi0yLjguMi0xLjQgMS40LTIuNCAyLjgtMi4yIDEuNC4yIDIuNCAxLjQgMi4yIDIuOC0uMiAxLjItMS4yIDIuMi0yLjUgMi4yIi8+PHBhdGggZD0ibTI5Ni41IDY3LjVoLTEwLjJjLS44IDAtMS41LS43LTEuNS0xLjVzLjctMS41IDEuNS0xLjVoMTAuMmMuOCAwIDEuNS43IDEuNSAxLjVzLS43IDEuNS0xLjUgMS41Ii8+PHBhdGggZD0ibTIyMi4zIDU0LjhoLTEwLjJjLS44IDAtMS41LS43LTEuNS0xLjVzLjctMS41IDEuNS0xLjVoMTAuMmMuOCAwIDEuNS43IDEuNSAxLjVzLS42IDEuNS0xLjUgMS41Ii8+PHBhdGggZD0ibTE2OC42IDgzLjhoLTEwLjJjLS44IDAtMS41LS43LTEuNS0xLjVzLjctMS41IDEuNS0xLjVoMTAuMmMuOCAwIDEuNS43IDEuNSAxLjVzLS43IDEuNS0xLjUgMS41Ii8+PHBhdGggZD0ibTYxLjIgNTUuOGgtMTAuMWMtLjggMC0xLjUtLjctMS41LTEuNXMuNy0xLjUgMS41LTEuNWgxMC4yYy44IDAgMS41LjcgMS41IDEuNXMtLjcgMS41LTEuNiAxLjUiLz48cGF0aCBkPSJtNzAuMiA5MC4yaC0xMC4xYy0uOCAwLTEuNS0uNy0xLjUtMS41cy43LTEuNSAxLjUtMS41aDEwLjJjLjggMCAxLjUuNyAxLjUgMS41cy0uNyAxLjUtMS42IDEuNSIvPjwvZz48L3N2Zz4=">
<p>That's right: the <em>developer</em> is the one who has to remember whether all the endpoints are providing the right kinds of data to components, and update the server whenever any data requirements are changed. And in the real world, we’re going to be using a lot of components. It's going to mean a lot of repetitive, boring, disciplined work. And who wants any of that?</p>
<p>What we need is a way for components to stop <em>expecting</em> and to start <em>declaring</em> what data they need. And we'd need a way to make a server that understands these declarations and can intelligently compose them.</p>
<p>This utopian solution would look a little something like this:</p>
<img width="372" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzNzIuMyAyMTUuMyIgZW5hYmxlLWJhY2tncm91bmQ9Im5ldyAwIDAgMzcyLjMgMjE1LjMiPjxnIGZpbGw9IiNlNWU1ZTQiPjxwYXRoIGQ9Im05My4xIDc3LjNjMC0xMy41LTEzLjktMjQuNC0zMS4xLTI0LjRzLTMxIDEwLjktMzEgMjQuNGMwIDExLjkgMTAuNyAyMS43IDI1IDI0IDEuMyA0LjkgMy45IDE0IDUuOCAxNCAxLjkgMCA0LjktOS4xIDYuMy0xNCAxNC4yLTIuMiAyNS0xMi4xIDI1LTI0Ii8+PHBhdGggZD0ibTM0Mi4xIDc1YzAtMTMuNS0xMy45LTI0LjQtMzEuMS0yNC40cy0zMS4xIDEwLjktMzEuMSAyNC40YzAgMTEuOSAxMC43IDIxLjcgMjUgMjQgMS4zIDQuOSAzLjkgMTQgNS44IDE0IDEuOSAwIDQuOS05LjEgNi4zLTE0IDE0LjMtMi4zIDI1LjEtMTIuMiAyNS4xLTI0Ii8+PC9nPjxnIGZpbGw9IiMxY2Q5NmEiPjxwYXRoIGQ9Im01Ny43IDgzLjRoLTNjLS41IDAtMS0uMy0xLjMtLjgtLjMtLjUtLjMtMSAwLTEuNWwxLjUtMi42IDIuNiAxLjUtLjIuM2guNHYzLjEiLz48cGF0aCB0cmFuc2Zvcm09Im1hdHJpeCguODY2LjUwMDEtLjUwMDEuODY2IDQ1LjUzMi0xOS4xMSkiIGQ9Im01Ni45IDczLjFoM3Y0LjVoLTN6Ii8+PHBhdGggZD0ibTYyLjQgNzIuMmwtLjItLjMtLjIuMy0yLjYtMS41IDEuNS0yLjZjLjMtLjUuOC0uOCAxLjMtLjhzMSAuMyAxLjMuOGwxLjUgMi42LTIuNiAxLjUiLz48cGF0aCB0cmFuc2Zvcm09Im1hdHJpeCguNDk5OC44NjYxLS44NjYxLjQ5OTggOTguMjgtMTkuMzgyKSIgZD0ibTYzLjcgNzMuOWg0LjV2M2gtNC41eiIvPjxwYXRoIGQ9Im02OS43IDgzLjRoLTN2LTNoLjRsLS4yLS4zIDIuNi0xLjUgMS41IDIuNmMuMy41LjMgMSAwIDEuNS0uMy40LS44LjctMS4zLjciLz48cGF0aCBkPSJtNTkuOSA4MC40aDQuNXYzaC00LjV6Ii8+PC9nPjxnIGZpbGw9IiMwMDUzYzkiPjxwYXRoIGQ9Im01MS4yIDcyLjloLTR2LTNjMC0uNy40LTEuNCAxLTEuN2wyLjYtMS41IDIgMy41LTEuNi44djEuOSIvPjxwYXRoIHRyYW5zZm9ybT0ibWF0cml4KC40OTk5Ljg2NjEtLjg2NjEuNDk5OSA4NS4xNC0xNS4xNjgpIiBkPSJtNTMuNyA2My45aDR2NC41aC00eiIvPjxwYXRoIGQ9Im02My44IDY1LjZsLTEuNi0uOS0xLjYuOS0yLTMuNSAyLjYtMS41Yy42LS40IDEuNC0uNCAyIDBsMi42IDEuNS0yIDMuNSIvPjxwYXRoIHRyYW5zZm9ybT0ibWF0cml4KC44NjYuNTAwMS0uNTAwMS44NjYgNDIuMjgtMjUuNDU1KSIgZD0ibTY2LjQgNjQuMWg0LjV2NGgtNC41eiIvPjxwYXRoIGQ9Im03Ny4xIDcyLjloLTR2LTEuOWwtMS42LS45IDItMy41IDIuNiAxLjVjLjYuNCAxIDEgMSAxLjd2My4xIi8+PHBhdGggZD0ibTczLjEgNzUuMWg0djQuNWgtNHoiLz48cGF0aCBkPSJtNzMuNSA4OGwtMi0zLjUgMS42LS45di0xLjhoNHYzYzAgLjctLjQgMS40LTEgMS43bC0yLjYgMS41Ii8+PHBhdGggdHJhbnNmb3JtPSJtYXRyaXgoLjQ5OTkuODY2MS0uODY2MS40OTk5IDExMC45OS0xNS4xNjgpIiBkPSJtNjYuNiA4Ni4zaDR2NC41aC00eiIvPjxwYXRoIGQ9Im02Mi4yIDk0LjNjLS4zIDAtLjctLjEtMS0uM2wtMi42LTEuNSAyLTMuNSAxLjYuOSAxLjYtLjkgMiAzLjUtMi42IDEuNWMtLjMuMi0uNy4zLTEgLjMiLz48cGF0aCB0cmFuc2Zvcm09Im1hdHJpeCguODY2LjUwMDEtLjUwMDEuODY2IDUxLjczNy0xNS45OTMpIiBkPSJtNTMuNSA4Ni41aDQuNXY0aC00LjV6Ii8+PHBhdGggZD0ibTUwLjggODhsLTIuNi0xLjVjLS42LS40LTEtMS0xLTEuN3YtM2g0djEuOGwxLjYuOS0yIDMuNSIvPjxwYXRoIGQ9Im00Ny4yIDc1LjFoNHY0LjVoLTR6Ii8+PC9nPjxnIGZpbGw9IiNlNWU1ZTQiPjxwYXRoIGQ9Im0xNDcuOSAzNy41Yy0xOC42IDAtMzMuNyAxMS45LTMzLjcgMjYuNSAwIDUuMSAxLjkgOS45IDUuMSAxNC02LjIgMTAgNi4zIDI0IDguNSAyMS40IDIuMi0yLjUtNC44LTcuNi41LTEzLjkgNS41IDMuMSAxMi4zIDUgMTkuNyA1IDE4LjYgMCAzMy44LTExLjkgMzMuOC0yNi41cy0xNS4zLTI2LjUtMzMuOS0yNi41Ii8+PHBhdGggZD0ibTI2My4xIDQ5LjFjMC0xNS43LTE2LjItMjguNS0zNi4yLTI4LjVzLTM2LjIgMTIuOC0zNi4yIDI4LjUgMTYuMiAyOC41IDM2LjIgMjguNWM1LjIgMCAxMC4yLS45IDE0LjYtMi40IDMuNCA2LjktNC4xIDEwLjQtMi40IDEzLjMgMS43IDIuOSAxNi4xLTcuOSAxMi43LTE4LjcgNy01LjMgMTEuMy0xMi42IDExLjMtMjAuNyIvPjwvZz48cGF0aCBmaWxsPSIjZmZjMjAwIiBkPSJtMzE3LjUgOTIuNWgtMS40di00aC42bDIuNS0yLjUgMi44IDIuOC0zLjEgMy4xYy0uMy40LS45LjYtMS40LjZtLTQuMyAwaC01Ljh2LTRoNS44djRtLTEwLjEtLjZsLTQuMS00LjEgMi44LTIuOCA0LjEgNC4xLTIuOCAyLjhtMjAuOS01LjFsLTIuOC0yLjggNC4xLTQuMSAyLjggMi44LTQuMSA0LjFtLTI3LTFsLTMuMS0zLjFjLS40LS40LS42LS45LS42LTEuNHYtMS40aDR2LjZsMi41IDIuNS0yLjggMi44bTMxLjctNy40aC00di01LjhoNHY1LjhtLTMxLjQtMS40aC00di01LjhoNHY1LjhtMzEuNC03LjJoLTR2LS42bC0yLjUtMi41IDIuOC0yLjggMy4xIDMuMWMuNC40LjYuOS42IDEuNHYxLjRtLTMyLS4xbC0yLjgtMi44IDQuMS00LjEgMi44IDIuOC00LjEgNC4xbTIzLjUtNS4xbC00LjEtNC4xIDIuOC0yLjggNC4xIDQuMS0yLjggMi44bS0xNy4zLTFsLTIuOC0yLjggMy4xLTMuMWMuNC0uNC45LS42IDEuNC0uNmgxLjR2NGgtLjZsLTIuNSAyLjVtMTEuNy0yLjVoLTUuOHYtNGg1Ljh2NCIvPjxwYXRoIGQ9Im0yMzEuMSA5OS41aC04Ny44Yy0uMyAwLS41LjItLjUuNXY5Mi4zYzAgLjMuMi41LjUuNWg4Ny44Yy4zIDAgLjUtLjIuNS0uNXYtOTIuM2MwLS4zLS4yLS41LS41LS41Ii8+PGNpcmNsZSBmaWxsPSIjMDA1M2M5IiBjeD0iNjEuOCIgY3k9IjE2MSIgcj0iMzciLz48Y2lyY2xlIGZpbGw9IiNmZmMyMDAiIGN4PSIzMDkuMyIgY3k9IjE2MSIgcj0iMzciLz48Y2lyY2xlIGZpbGw9IiMxY2Q5NmEiIGN4PSI2MS44IiBjeT0iMTY3LjciIHI9IjI0LjIiLz48Y2lyY2xlIGZpbGw9IiNlMDNiNGEiIGN4PSIzMDkuOCIgY3k9IjE2Ny43IiByPSIyNC4yIi8+PGcgZmlsbD0iI2ZmZiI+PHBhdGggZD0ibTc1LjUgMTYyYy0uOCAwLTEuNS0uMy0yLjEtLjgtMS40LTEuMi0xLjUtMy4zLS4zLTQuNi42LS43IDEuNS0xLjEgMi41LTEuMS44IDAgMS41LjMgMi4xLjggMS40IDEuMiAxLjUgMy4zLjMgNC42LS42LjYtMS41IDEuMS0yLjUgMS4xIi8+PHBhdGggZD0ibTY2LjMgMTYzLjNjLS44IDAtMS41LS4zLTIuMS0uOC0uNy0uNi0xLjEtMS40LTEuMS0yLjItLjEtLjkuMi0xLjcuOC0yLjQgMS4xLTEuMyAzLjMtMS41IDQuNi0uMyAxLjQgMS4yIDEuNSAzLjMuMyA0LjYtLjYuNy0xLjUgMS4xLTIuNSAxLjEiLz48cGF0aCBkPSJtNTEuMSAxMzUuN2MtLjggMC0xLjUtLjMtMi4xLS44LTEuNC0xLjItMS41LTMuMy0uNC00LjYuNi0uNyAxLjUtMS4yIDIuNS0xLjIuOCAwIDEuNS4zIDIuMS44IDEuNCAxLjIgMS41IDMuMi40IDQuNi0uNy43LTEuNiAxLjItMi41IDEuMiIvPjxwYXRoIGQ9Im02MC41IDEzNC4yYy0uOCAwLTEuNS0uMy0yLjEtLjgtLjctLjYtMS4xLTEuNC0xLjEtMi4yLS4xLS45LjItMS43LjgtMi40LjYtLjcgMS41LTEuMiAyLjUtMS4yLjggMCAxLjUuMyAyLjEuOC43LjYgMS4xIDEuNCAxLjEgMi4yLjEuOS0uMiAxLjctLjggMi40LS42LjgtMS41IDEuMi0yLjUgMS4yIi8+PHBhdGggZD0ibTE4MSAxMjIuNWMtLjggMC0xLjUtLjMtMi4xLS44LTEuNC0xLjItMS41LTMuMi0uNC00LjYuNi0uNyAxLjUtMS4yIDIuNS0xLjIuOCAwIDEuNS4zIDIuMS44IDEuNCAxLjIgMS41IDMuMi40IDQuNi0uNi44LTEuNSAxLjItMi41IDEuMiIvPjxwYXRoIGQ9Im0xOTMuNSAxMjIuNWMtLjggMC0xLjUtLjMtMi4xLS44LS43LS42LTEuMS0xLjQtMS4xLTIuMi0uMS0uOS4yLTEuNy44LTIuNC42LS43IDEuNS0xLjIgMi41LTEuMi44IDAgMS41LjMgMi4xLjggMS40IDEuMiAxLjUgMy4yLjQgNC42LS43LjgtMS43IDEuMi0yLjYgMS4yIi8+PHBhdGggZD0ibTMxNi4zIDEzNC41Yy0uMSAwLS4zIDAtLjQgMC0xLjktLjItMy4zLTItMy4xLTMuOS4yLTEuOSAxLjktMy4zIDMuOS0zLjEuOS4xIDEuOC42IDIuNCAxLjMuNi43LjkgMS43LjggMi42LS4zIDEuNy0xLjggMy4xLTMuNiAzLjEiLz48cGF0aCBkPSJtMzA1LjYgMTM0LjVjLS4xIDAtLjMgMC0uNCAwLTEuOS0uMi0zLjMtMi0zLjEtMy45LjItMS45IDEuOS0zLjMgMy45LTMuMSAxLjkuMiAzLjMgMiAzLjEgMy45LS4yIDEuOC0xLjcgMy4xLTMuNSAzLjEiLz48cGF0aCBkPSJtMzIwLjEgMTU4LjhjLS41IDAtLjktLjEtMS40LS4zLS45LS40LTEuNS0xLTEuOS0xLjktLjQtLjktLjQtMS44IDAtMi43LjUtMS4zIDEuOC0yLjIgMy4zLTIuMi41IDAgLjkuMSAxLjQuMy45LjQgMS41IDEgMS45IDEuOS40LjkuNCAxLjggMCAyLjctLjYgMS4zLTEuOCAyLjItMy4zIDIuMiIvPjxwYXRoIGQ9Im0zMDkuOSAxNTUuOGMtLjUgMC0uOS0uMS0xLjQtLjMtMS44LS43LTIuNi0yLjgtMS45LTQuNi42LTEuMyAxLjgtMi4yIDMuMy0yLjIuNSAwIC45LjEgMS40LjMuOS40IDEuNSAxIDEuOSAxLjkuNC45LjQgMS44IDAgMi43LS42IDEuNC0xLjkgMi4yLTMuMyAyLjIiLz48L2c+PGcgZmlsbD0iI2UwM2I0YSI+PHBhdGggZD0ibTMwOC43IDg0LjFoLTNjLS45IDAtMS42LS42LTEuOS0xLjRsLS45LTIuOSAzLjgtMS4yLjUgMS41aDEuNXY0Ii8+PHBhdGggZD0ibTMwMS41IDc1LjVsLS45LTIuOWMtLjMtLjggMC0xLjcuNy0yLjJsMi40LTEuOCAyLjQgMy4yLTEuMy45LjUgMS41LTMuOCAxLjMiLz48cGF0aCBkPSJtMzEyLjMgNjkuMmwtMS4zLS45LTEuMy45LTIuNC0zLjIgMi40LTEuOGMuNy0uNSAxLjctLjUgMi40IDBsMi40IDEuOC0yLjIgMy4yIi8+PHBhdGggZD0ibTMyMC42IDc1LjVsLTMuOC0xLjIuNS0xLjUtMS4zLS45IDIuNC0zLjIgMi40IDEuOGMuNy41IDEgMS40LjcgMi4ybC0uOSAyLjgiLz48cGF0aCBkPSJtMzE2LjMgODQuMWgtM3YtNGgxLjVsLjUtMS41IDMuOCAxLjItLjkgMi45Yy0uMy44LTEgMS40LTEuOSAxLjQiLz48L2c+PHBhdGggZmlsbD0iI2ZmYzIwMCIgZD0ibTI0NC4yIDQxbC05LjItOS4yYy0uNC0uNC0uOS0uNi0xLjQtLjZoLTEzYy0uNSAwLTEgLjItMS40LjZsLTkuMiA5LjJjLS40LjQtLjYuOS0uNiAxLjR2MTNjMCAuNS4yIDEgLjYgMS40bDkuMiA5LjJjLjQuNC45LjYgMS40LjZoMTNjLjUgMCAxLS4yIDEuNC0uNmw5LjItOS4yYy40LS40LjYtLjkuNi0xLjR2LTEzYzAtLjUtLjItMS0uNi0xLjQiLz48cGF0aCBmaWxsPSIjZTAzYjRhIiBkPSJtMjM2LjkgNDQuNWwtOC42LTYuMmMtLjctLjUtMS43LS41LTIuNCAwbC04LjYgNi4yYy0uNy41LTEgMS40LS43IDIuMmwzLjMgMTAuMWMuMy44IDEgMS40IDEuOSAxLjRoMTAuNmMuOSAwIDEuNi0uNiAxLjktMS40bDMuMy0xMC4xYy4zLS44IDAtMS43LS43LTIuMiIvPjxwYXRoIGZpbGw9IiMwMDUzYzkiIGQ9Im0xNjIuMSA1NS4xbC0xMi45LTcuNWMtLjYtLjQtMS40LS40LTIgMGwtMTIuOSA3LjVjLS42LjQtMSAxLTEgMS43djE0LjljMCAuNy40IDEuNCAxIDEuN2wxMi45IDcuNWMuMy4yLjcuMyAxIC4zcy43LS4xIDEtLjNsMTIuOS03LjVjLjYtLjQgMS0xIDEtMS43di0xNC44YzAtLjctLjQtMS40LTEtMS44Ii8+PHBhdGggZmlsbD0iIzFjZDk2YSIgZD0ibTE1NyA2OC4xbC03LjUtMTNjLS4zLS41LS44LS44LTEuMy0uOHMtMSAuMy0xLjMuOGwtNy41IDEzYy0uMy41LS4zIDEgMCAxLjUuMy41LjguOCAxLjMuOGgxNWMuNSAwIDEtLjMgMS4zLS44LjItLjQuMi0xIDAtMS41Ii8+PGcgZmlsbD0iI2ZmZiI+PHBhdGggZD0ibTE4Ny4yIDEzOC45Yy03LjEgMC0xMy42LTMuOC0xNy0xMC0uNS0xLS4yLTIuMi44LTIuNyAxLS41IDIuMi0uMiAyLjcuOCAyLjcgNC45IDcuOSA4IDEzLjUgOCA1LjYgMCAxMC44LTMuMSAxMy41LTggLjUtMSAxLjgtMS4zIDIuNy0uOCAxIC41IDEuMyAxLjguOCAyLjctMy40IDYuMi05LjkgMTAtMTcgMTAiLz48cGF0aCBkPSJtNzAuNiAxNzMuNGMtMy4zIDAtNi41LTEuMS05LTMuMi0uOS0uNy0xLTItLjMtMi44LjctLjggMi0xIDIuOC0uMyAyLjIgMS44IDUuMiAyLjYgOC4xIDIuMiAzLS41IDUuNS0yLjEgNy4xLTQuNS42LS45IDEuOC0xLjIgMi44LS42czEuMiAxLjguNiAyLjhjLTIuMiAzLjQtNS44IDUuNi05LjkgNi4zLS43IDAtMS41LjEtMi4yLjEiLz48cGF0aCBkPSJtMzEwLjkgMTQzLjdjLS4xIDAtLjIgMC0uMyAwLTQuMS0uMS04LTEuOS0xMC42LTQuOS0uNy0uOC0uNi0yLjEuMi0yLjguOC0uNyAyLjEtLjYgMi44LjIgMS45IDIuMiA0LjYgMy41IDcuNiAzLjUgMyAuMSA1LjgtMS4xIDcuOC0zLjIuNy0uOCAyLS45IDIuOC0uMS44LjcuOSAyIC4xIDIuOC0yLjYgMi45LTYuNCA0LjUtMTAuNCA0LjUiLz48cGF0aCBkPSJtNTUuNiAxNDVjLTQuOCAwLTkuMy0xLjgtMTIuNi01LS44LS44LS44LTIgMC0yLjguOC0uOCAyLS44IDIuOCAwIDIuOCAyLjggNi44IDQuMiAxMC45IDMuOSA0LjEtLjMgNy44LTIuMyAxMC4yLTUuNC43LS45IDEuOS0xIDIuOC0uNC45LjcgMSAxLjkuNCAyLjgtMy4xIDQtNy45IDYuNi0xMy4xIDYuOS0uNSAwLTEgMC0xLjQgMCIvPjxwYXRoIGQ9Im0zMTYuMyAxNjcuNmMtMS44IDAtMy42LS4zLTUuNC0uOC01LTEuNS05LjEtNS4xLTExLjMtOS43LS41LTEgMC0yLjIgMS0yLjcgMS0uNSAyLjIgMCAyLjcgMSAxLjcgMy42IDQuOSA2LjMgOC44IDcuNSAzLjkgMS4yIDguMS43IDExLjUtMS40LjktLjYgMi4yLS4zIDIuOC43LjYuOS4zIDIuMi0uNyAyLjgtMi45IDEuNy02LjEgMi42LTkuNCAyLjYiLz48L2c+PC9zdmc+">
<p>This is what Relay and GraphQL does.</p>
<p>Of course they do a lot more than that: query validation, data caching, optimistic queries, etc. etc. — but the above is what I feel is Relay and GraphQL’s <em>raison d'etre</em>.</p>
<p><a href="../">Now see how all the pieces fit together with an interactive diagram!</a></p>
</main>
</body>
</html>
================================================
FILE: index.html
================================================
<html>
<head>
<title>Relay for Visual Learners</title>
</head>
<body style="margin: 0; overflow-x: hidden;">
<div id='root'>
</div>
</body>
<script src="build/bundle.js"></script>
</html>
================================================
FILE: package.json
================================================
{
"name": "relay-visual-learners",
"version": "1.0.1",
"description": "An interactive diagram to help explain Facebook’s Relay framework for the more visually minded, written in React.",
"scripts": {
"start": "node server.js",
"lint": "eslint src",
"deploy": "UV_THREADPOOL_SIZE=100 NODE_ENV=production webpack -p --progress --config webpack.production.config"
},
"repository": {
"type": "git",
"url": "https://github.com/sgwilym/relay-visual-learners"
},
"keywords": [
"react",
"reactjs",
"relay",
"diagram"
],
"author": "Sam Gwilym <gwilym@me.com> (http://gwil.co)",
"license": "MIT",
"devDependencies": {
"autoprefixer-core": "^5.2.1",
"babel-core": "^5.4.7",
"babel-eslint": "^3.1.9",
"babel-loader": "^5.1.2",
"babel-runtime": "^5.8.20",
"css-loader": "^0.16.0",
"eslint-plugin-react": "^2.3.0",
"node-sass": "^3.2.0",
"postcss-loader": "^0.5.1",
"react-hot-loader": "^1.2.7",
"sass-loader": "^2.0.1",
"style-loader": "^0.12.3",
"webpack": "^1.9.6",
"webpack-dev-server": "^1.8.2"
},
"dependencies": {
"babel-plugin-object-assign": "^1.2.1",
"react": "^0.13.0"
}
}
================================================
FILE: server.js
================================================
var webpack = require('webpack');
var WebpackDevServer = require('webpack-dev-server');
var config = require('./webpack.config');
// Workaround for lame sass-loader bug
process.env.UV_THREADPOOL_SIZE = 100;
new WebpackDevServer(webpack(config), {
publicPath: config.output.publicPath,
hot: true,
historyApiFallback: true
}).listen(3000, 'localhost', function (err, result) {
if (err) {
console.log(err);
}
console.log('Listening at localhost:3000');
});
================================================
FILE: src/components/App.jsx
================================================
import React, { Component, PropTypes } from 'react/addons';
import Diagram from './Diagram';
import Topic from './Topic';
import styles from './App.scss';
export default class App extends Component {
constructor(props) {
super(props);
var topicState = {};
const addTopicTitlesToTopicObj = (topic) => {
topicState[topic.title] = {
highlighted: false,
collapsed: true
}
};
const walkTopicTree = (topic) => {
addTopicTitlesToTopicObj(topic);
if (topic.children) {
topic.children.map(walkTopicTree);
}
}
for (let topic of props.topics) {
walkTopicTree(topic);
}
this.state = {
topics: topicState
};
this.topicUnderMouseChanged = this.topicUnderMouseChanged.bind(this);
this.topicClicked = this.topicClicked.bind(this);
}
topicUnderMouseChanged(topicTitle, isUnderMouse) {
const nextState = React.addons.update(this.state, {
topics: {
[topicTitle]: {
highlighted: { $set: isUnderMouse }
}
}
});
this.setState(nextState);
};
topicClicked(topicTitle) {
const collapsed = this.state.topics[topicTitle].collapsed;
const nextState = React.addons.update(this.state, {
topics: {
[topicTitle]: {
collapsed: { $set: !collapsed }
}
}
});
this.setState(nextState);
}
render() {
const { topics } = this.props;
const topicState = this.state.topics;
const makeDiagram = (topic) => {
return (
<svg key={topic.title} width={topic.width} height={topic.height} viewBox={`0 0 ${topic.width} ${topic.height}`}>
<Diagram topic={topic} />
</svg>
);
}
const makeTopic = (topic) => {
return <Topic topic={topic} key={topic.title} />;
}
const injectHighlightAndCallback = (topic) => {
return Object.assign(
topic,
{ highlighted: topicState[topic.title].highlighted },
{ collapsed: topicState[topic.title].collapsed },
{ underMouseChanged: this.topicUnderMouseChanged },
{ topicClicked: this.topicClicked },
{ children: topic.children ? topic.children.map(injectHighlightAndCallback) : topic.children }
);
};
const topicsWithExtras = topics.map(injectHighlightAndCallback);
return (
<div className={styles.root}>
<div className={styles.diagram}>
{ topicsWithExtras.map(makeDiagram) }
</div>
<ul className={styles.glossary}>
<div className={styles.intro}>
<h1>Relay for Visual Learners</h1>
<p>Relay is a new framework from Facebook that promises to simplify a problem complex enough that the simplification is rather complex in itself <a href="docs/why-relay.html">(and here’s a visual explanation of the problem Relay solves)</a>.</p>
<p>I tend to learn things better when I can <em>see</em> how things fit together, so I made this interactive diagram that attempts to explain how Relay’s various parts fit together.</p>
</div>
{ topicsWithExtras.map(makeTopic) }
</ul>
<div className={styles.credit}>Created by <a href="http://gwil.co">Sam Gwilym</a> • <a href="https://github.com/sgwilym/relay-visual-learners">Github Repo</a></div>
</div>
);
}
}
App.propTypes = {
topics: PropTypes.array.isRequired
}
================================================
FILE: src/components/App.scss
================================================
@import '../shared/styles/colors.scss';
.root {
position: relative;
min-height: 100%;
}
.diagram {
font-size: .9em;
position: fixed;
display: flex;
justify-content: space-around;
align-items: center;
height: 100%;
width: calc(100% - 20em);
svg {
transition: all 200ms;
cursor: pointer;
margin: 1em;
}
@media screen and (max-width: 1250px) {
flex-direction: column;
justify-content: center;
}
}
.glossary {
font-size: .9em;
background-color: $light-1-color;
width: 20em;
padding: .5em 0 5em 0;
margin: 0;
overflow-x: visible;
position: absolute;
right: 0;
min-height: 100%;
}
.intro {
color: $dark-color;
font-family: 'Menlo', monospace;
padding: 0 .75em;
}
.intro h1 {
margin: .5em 0;
}
.intro p {
font-size: .9em;
line-height: 1.4em;
}
.intro a {
color: $dark-color;
}
.credit {
color: $light-3-color;
font-family: 'Menlo', monospace;
position: fixed;
bottom: 1em;
left: 1em;
}
.credit a {
display: inline-block;
color: $light-3-color;
text-decoration: none;
border-bottom: 3px solid $light-3-color;
transition: 100ms all;
&:hover {
color: $relay-primary-color;
border-color: $relay-primary-color;
transform: scale(1.1, 1.1);
}
}
================================================
FILE: src/components/Diagram.jsx
================================================
import React, { Component, PropTypes } from 'react';
export default class Diagram extends Component {
constructor(props) {
super(props);
this.handleUnderMouseChanged = this.handleUnderMouseChanged.bind(this);
this.handleTopicClicked = this.handleTopicClicked.bind(this);
}
handleUnderMouseChanged(isUnderMouse, e) {
const { topic } = this.props;
topic.underMouseChanged(topic.title, isUnderMouse);
e.stopPropagation();
}
handleTopicClicked(e) {
const { topic } = this.props;
topic.topicClicked(topic.title);
e.stopPropagation();
}
render() {
const { topic } = this.props;
const makeTopicGroup = (topic) => {
return <Diagram topic={topic} key={topic.title} />;
}
return (
<g
fill={topic.highlighted ? '#f26b00' : '#d7d2ce' }
onMouseOver={this.handleUnderMouseChanged.bind(this, true)}
onMouseOut={this.handleUnderMouseChanged.bind(this, false)}
onClick={this.handleTopicClicked}
>
{ topic.diagram }
{ topic.children && topic.children.map(makeTopicGroup) }
</g>
);
}
}
Diagram.propTypes = {
topic: PropTypes.shape({
title: PropTypes.string.isRequired,
description: PropTypes.string.isRequired,
officialDocs: PropTypes.string,
diagram: PropTypes.element.isRequired,
children: PropTypes.array,
highlighted: PropTypes.bool.isRequired,
underMouseChanged: PropTypes.func.isRequired,
topicClicked: PropTypes.func.isRequired
}).isRequired
}
================================================
FILE: src/components/Topic.jsx
================================================
import React, { Component, PropTypes } from 'react';
import styles from './Topic.scss';
export default class Topic extends Component {
constructor(props) {
super(props);
this.handleUnderMouseChanged = this.handleUnderMouseChanged.bind(this);
}
handleUnderMouseChanged(isUnderMouse, e) {
const { topic } = this.props;
topic.underMouseChanged(topic.title, isUnderMouse);
e.stopPropagation();
}
render() {
const { topic } = this.props;
const makeTopic = (topic) => {
return <Topic topic={topic} key={topic.title}/>
}
return (
<li
onMouseOver={this.handleUnderMouseChanged.bind(this, true)}
onMouseOut={this.handleUnderMouseChanged.bind(this, false)}
className={styles.root}
>
<h2
onClick={topic.topicClicked.bind(this, topic.title)}
className={topic.highlighted ? styles.headingHighlighted : styles.heading}
>{topic.title}</h2>
<div
className={topic.highlighted ? styles.detailsHighlighted : styles.details}
style={{ display: topic.collapsed ? 'none' : 'block' }}
>
<p>{topic.description}</p>
{ topic.officialDocs &&
<p>
<a
className={styles.officialDocs}
href={topic.officialDocs}
>Official docs</a>
</p>
}
</div>
<ul className={styles.childTopics}>
{ topic.children && topic.children.map(makeTopic) }
</ul>
</li>
)
}
}
Topic.propTypes = {
topic: PropTypes.shape({
title: PropTypes.string.isRequired,
description: PropTypes.string.isRequired,
officialDocs: PropTypes.string,
children: PropTypes.array,
highlighted: PropTypes.bool.isRequired,
collapsed: PropTypes.bool.isRequired,
underMouseChanged: PropTypes.func.isRequired,
topicClicked: PropTypes.func.isRequired
}).isRequired
}
================================================
FILE: src/components/Topic.scss
================================================
@import '../shared/styles/colors.scss';
.root {
list-style-type: none;
color: $dark-color;
font-family: 'Menlo', monospace;
overflow: visible;
}
.heading {
font-size: 1em;
font-weight: normal;
margin: 0;
padding: .5em;
background: $light-3-color;
border-bottom: 3px solid $light-2-color;
transition: all 100ms;
cursor: pointer;
}
.headingHighlighted {
composes: heading;
color: white;
background: $relay-primary-color;
border-bottom-color: lighten($relay-primary-color, 30);
transform: scale(1.1, 1.1);
transform-origin: right;
z-index: 2;
}
.details {
font-size: .9em;
padding: .75em .5em .5em .5em;
background: $light-2-color;
transition: all 100ms;
p {
margin: 0 0 .5em 0;
line-height: 1.4em;
}
}
.detailsHighlighted {
composes: details;
background-color: $relay-secondary-color;
}
.officialDocs {
font-size: .8em;
color: $relay-primary-color;
}
.childTopics {
padding: 0 0 0 1.5em;
}
================================================
FILE: src/diagram-data.js
================================================
import BackEndTopic from './topics/backend';
import RelayTopic from './topics/relay';
export default [
RelayTopic,
BackEndTopic
];
================================================
FILE: src/diagrams/connection-field.xml
================================================
<g>
<path d="M276.9,225.8c-1.1,0-2-0.9-2-2c0-1.1,0.9-2,2-2s2,0.9,2,2C278.9,224.9,278,225.8,276.9,225.8z"/>
</g>
<g>
<circle fill="#FFFFFF" cx="276.9" cy="230.7" r="0.5"/>
<path d="M276.9,232.7c-1.1,0-2-0.9-2-2s0.9-2,2-2s2,0.9,2,2S278,232.7,276.9,232.7z"/>
</g>
<path d="M349,218.6h-64.6c-0.8,0-1.5,0.7-1.5,1.5v14c0,0.8,0.7,1.5,1.5,1.5H349c0.8,0,1.5-0.7,1.5-1.5v-14
C350.5,219.3,349.8,218.6,349,218.6z"/>
<g>
<path d="M261.7,226.1l3.1-1.2c0.7,0.7,1.7,1.2,2.8,1.2c2.2,0,4-1.8,4-4c0-2.2-1.8-4-4-4c-2.2,0-3.9,1.8-4,3.9l-3.1,1.2
c-0.7-0.7-1.7-1.2-2.8-1.2c-2.2,0-4,1.8-4,4c0,2.2,1.8,4,4,4c0.6,0,1.1-0.1,1.6-0.3l2.6,2.1c-0.1,0.3-0.1,0.6-0.1,1
c0,2.2,1.8,4,4,4c2.2,0,4-1.8,4-4c0-2.2-1.8-4-4-4c-0.7,0-1.4,0.2-2,0.6l-2.3-1.8C261.6,227.1,261.7,226.7,261.7,226.1z
M257.2,226.2L257.2,226.2L257.2,226.2z"/>
<line fill="none" stroke="#FFFFFF" stroke-width="0" stroke-linecap="round" stroke-linejoin="round" x1="257.2" y1="226.2" x2="257.2" y2="226.2"/>
</g>
================================================
FILE: src/diagrams/container.xml
================================================
<g>
<rect x="212" y="210.9" width="8.5" height="8.1"/>
<path d="M243.7,196h-74.2c-5.2,0-9.5,4.3-9.5,9.5v86.3c0,1.9,1.6,3.5,3.5,3.5h86.2c1.9,0,3.5-1.6,3.5-3.5v-86.3
C253.2,200.3,248.9,196,243.7,196z M232.5,222.2c0,2.1-2.8,3.4-4,3.9c-0.2,0.1-0.4,0.1-0.5,0.1c-0.6,0-1.2-0.4-1.4-1
c-0.3-0.8,0.1-1.6,0.8-1.9c0.9-0.3,1.8-0.9,2-1.3v-3.3c0-0.9,0.7-2.5,2-3.7c-1.3-1.2-2-2.8-2-3.7V208c-0.2-0.3-1.2-0.9-2-1.3
c-0.8-0.3-1.2-1.2-0.8-1.9c0.3-0.8,1.2-1.2,1.9-0.8c1.2,0.5,4,1.8,4,3.9v3.4c0.1,0.3,1,1.9,2.3,2.2c0.2,0,0.3,0,0.5,0
c0.8,0,1.5,0.7,1.5,1.5s-0.7,1.6-1.5,1.6c-0.2,0-0.3,0-0.5,0c-1.3,0.3-2.2,1.9-2.3,2.3L232.5,222.2z M223.5,209.4v11.1
c0,0.8-0.7,1.5-1.5,1.5h-11.5c-0.8,0-1.5-0.7-1.5-1.5v-11.1c0-0.8,0.7-1.5,1.5-1.5H222C222.9,207.9,223.5,208.6,223.5,209.4z
M206.7,220.1c0,1.1-0.9,2-2,2c-1.1,0-2-0.9-2-2c0-1.1,0.9-2,2-2C205.8,218,206.7,219,206.7,220.1z M200.4,220.1
c0,1.1-0.9,2-2,2c-1.1,0-2-0.9-2-2c0-1.1,0.9-2,2-2C199.5,218,200.4,219,200.4,220.1z M194,220.1c0,1.1-0.9,2-2,2
c-1.1,0-2-0.9-2-2c0-1.1,0.9-2,2-2C193.1,218,194,219,194,220.1z M178,213.5c0.2,0,0.3,0,0.5,0c1.3-0.3,2.2-1.9,2.3-2.3l0-3.3
c0-2.1,2.8-3.4,4-3.9c0.8-0.3,1.6,0.1,1.9,0.8c0.3,0.8-0.1,1.6-0.8,1.9c-0.9,0.3-1.8,0.9-2,1.3v3.3c0,0.9-0.7,2.5-2,3.7
c1.3,1.2,2,2.8,2,3.7v3.3c0.2,0.3,1.2,0.9,2,1.3c0.8,0.3,1.2,1.2,0.8,1.9c-0.2,0.6-0.8,1-1.4,1c-0.2,0-0.4,0-0.5-0.1
c-1.2-0.5-4-1.8-4-3.9v-3.4c-0.1-0.3-1-1.9-2.3-2.2c-0.2,0-0.3,0-0.5,0c-0.8,0-1.5-0.7-1.5-1.5S177.1,213.5,178,213.5z
M250.2,291.8c0,0.3-0.2,0.5-0.5,0.5h-86.2c-0.3,0-0.5-0.2-0.5-0.5v-57.2h87.2V291.8z"/>
</g>
<g id="ReactComponent_copy">
<circle fill="#FFFFFF" cx="206.5" cy="263.5" r="27.5"/>
<g>
<path fill="none" d="M206.6,273.2c-0.5,0-1.1,0-1.6,0c0.5,0.7,1.1,1.3,1.6,1.9c0.5-0.6,1.1-1.2,1.6-1.9
C207.7,273.2,207.1,273.2,206.6,273.2z"/>
<path fill="none" d="M198.9,269.6c-0.3-0.4-0.5-0.9-0.8-1.4c-0.3-0.5-0.5-0.9-0.8-1.4c-0.3,0.8-0.6,1.6-0.8,2.3
C197.3,269.4,198.1,269.5,198.9,269.6z"/>
<path fill="none" d="M210.5,256.7c-1.2-0.1-2.5-0.1-3.9-0.1s-2.6,0.1-3.9,0.1c-0.7,1-1.4,2.1-2,3.3c-0.7,1.2-1.3,2.3-1.8,3.4
c0.5,1.1,1.1,2.3,1.8,3.4c0.7,1.2,1.4,2.2,2,3.3c1.2,0.1,2.5,0.1,3.9,0.1c1.3,0,2.6-0.1,3.9-0.1c0.7-1,1.4-2.1,2-3.3
c0.7-1.1,1.3-2.3,1.8-3.4c-0.6-1.1-1.2-2.3-1.8-3.4C211.9,258.8,211.2,257.7,210.5,256.7z M206.6,267.5
c-2.3,0-4.2-1.9-4.2-4.2c0-2.3,1.9-4.2,4.2-4.2c2.3,0,4.2,1.9,4.2,4.2C210.8,265.7,208.9,267.5,206.6,267.5z"/>
<path fill="none" d="M216.7,269.2c-0.3-0.8-0.5-1.5-0.8-2.3c-0.3,0.5-0.5,0.9-0.8,1.4c-0.3,0.5-0.5,0.9-0.8,1.4
C215.2,269.5,216,269.4,216.7,269.2z"/>
<path fill="none" d="M206.6,253.6c0.5,0,1.1,0,1.6,0c-0.5-0.7-1.1-1.3-1.6-1.9c-0.5,0.6-1.1,1.2-1.6,1.9
C205.6,253.6,206.1,253.6,206.6,253.6z"/>
<path fill="none" d="M212.1,253.8c1.9,0.2,3.7,0.5,5.4,0.8c0.2-0.7,0.3-1.3,0.4-2c0.6-3.6,0.1-6.2-1.2-6.9
c-0.3-0.2-0.6-0.3-1.1-0.3c-1.7,0-4.2,1.4-7,4C209.9,250.8,211,252.3,212.1,253.8z"/>
<path fill="none" d="M196.5,257.5c0.2,0.8,0.5,1.5,0.8,2.3c0.3-0.5,0.5-0.9,0.8-1.4c0.3-0.5,0.5-0.9,0.8-1.4
C198.1,257.2,197.3,257.4,196.5,257.5z"/>
<path fill="none" d="M208.7,277.2c3.5,3.3,6.6,4.6,8.1,3.8c1.3-0.8,1.7-3.4,1.2-6.9c-0.1-0.6-0.2-1.3-0.4-2
c-1.7,0.4-3.6,0.6-5.4,0.8C211,274.5,209.9,275.9,208.7,277.2z"/>
<path fill="none" d="M219.7,258.3c-0.5,1.7-1.2,3.4-2,5.1c0.8,1.7,1.5,3.4,2,5.1c4.5-1.3,7.3-3.3,7.3-5.1
C227,261.6,224.2,259.6,219.7,258.3z"/>
<path fill="none" d="M214.3,257.1c0.3,0.4,0.5,0.9,0.8,1.4c0.3,0.5,0.5,0.9,0.8,1.4c0.3-0.8,0.6-1.6,0.8-2.3
C216,257.4,215.2,257.2,214.3,257.1z"/>
<path fill="none" d="M204.5,249.5c-2.8-2.6-5.3-4-7-4c-0.4,0-0.8,0.1-1.1,0.3c-1.6,0.9-1.9,4.3-0.8,8.9
c1.7-0.4,3.5-0.6,5.4-0.8C202.2,252.3,203.4,250.8,204.5,249.5z"/>
<path fill="none" d="M193.6,258.3c-4.5,1.3-7.3,3.3-7.3,5.1c0,1.8,2.8,3.8,7.3,5.1c0.5-1.7,1.2-3.4,2-5.1
C194.8,261.7,194.1,259.9,193.6,258.3z"/>
<path fill="none" d="M201.1,272.9c-1.9-0.2-3.7-0.5-5.4-0.8c-1.1,4.6-0.8,8,0.8,8.9c1.5,0.9,4.6-0.5,8.1-3.8
C203.4,275.9,202.2,274.5,201.1,272.9z"/>
<circle cx="206.6" cy="263.4" r="4.2"/>
<path d="M230,263.4c0-3.7-4-6.4-9.5-8c0.2-0.8,0.3-1.5,0.5-2.2c0.8-5-0.1-8.6-2.6-10c-0.8-0.4-1.6-0.7-2.6-0.7
c-2.6,0-5.9,1.8-9.1,4.9c-3.3-3.1-6.5-4.9-9.1-4.9c-0.9,0-1.8,0.2-2.6,0.7c-3.2,1.8-3.5,6.6-2.2,12.2c-5.5,1.6-9.5,4.3-9.5,8
c0,3.7,4,6.4,9.5,8c-1.4,5.6-1,10.4,2.2,12.2c0.8,0.4,1.6,0.7,2.6,0.7c2.6,0,5.9-1.8,9.1-4.9c3.3,3.1,6.5,4.9,9.1,4.9
c0.9,0,1.8-0.2,2.6-0.7c2.5-1.4,3.4-5,2.6-10c-0.1-0.7-0.3-1.5-0.5-2.2C226,269.7,230,267,230,263.4z M216.8,245.8
c1.3,0.8,1.7,3.4,1.2,6.9c-0.1,0.6-0.2,1.3-0.4,2c-1.7-0.4-3.6-0.6-5.4-0.8c-1.1-1.6-2.3-3-3.4-4.3c2.8-2.6,5.3-4,7-4
C216.1,245.5,216.5,245.6,216.8,245.8z M215.9,266.9c0.3,0.8,0.6,1.6,0.8,2.3c-0.8,0.2-1.6,0.3-2.4,0.4
c0.3-0.4,0.5-0.9,0.8-1.4C215.4,267.8,215.6,267.4,215.9,266.9z M212.5,266.8c-0.7,1.2-1.4,2.2-2,3.3
c-1.2,0.1-2.5,0.1-3.9,0.1c-1.3,0-2.6-0.1-3.9-0.1c-0.7-1-1.4-2.1-2-3.3c-0.7-1.2-1.3-2.3-1.8-3.4c0.5-1.1,1.1-2.3,1.8-3.4
c0.7-1.2,1.4-2.2,2-3.3c1.2-0.1,2.5-0.1,3.9-0.1s2.6,0.1,3.9,0.1c0.7,1,1.4,2.1,2,3.3c0.7,1.1,1.3,2.3,1.8,3.4
C213.8,264.5,213.2,265.7,212.5,266.8z M206.6,275.1c-0.5-0.6-1.1-1.2-1.6-1.9c0.5,0,1.1,0,1.6,0s1.1,0,1.6,0
C207.7,273.8,207.1,274.5,206.6,275.1z M198.1,268.3c0.3,0.5,0.5,0.9,0.8,1.4c-0.8-0.1-1.6-0.3-2.4-0.4
c0.2-0.8,0.5-1.5,0.8-2.3C197.6,267.4,197.8,267.8,198.1,268.3z M197.3,259.9c-0.3-0.8-0.6-1.6-0.8-2.3
c0.8-0.2,1.6-0.3,2.4-0.4c-0.3,0.4-0.5,0.9-0.8,1.4C197.8,258.9,197.6,259.4,197.3,259.9z M206.6,251.7
c0.5,0.6,1.1,1.2,1.6,1.9c-0.5,0-1.1,0-1.6,0s-1.1,0-1.6,0C205.6,252.9,206.1,252.3,206.6,251.7z M215.1,258.5
c-0.3-0.5-0.5-0.9-0.8-1.4c0.8,0.1,1.7,0.3,2.4,0.4c-0.3,0.8-0.5,1.5-0.8,2.3C215.6,259.4,215.4,258.9,215.1,258.5z
M196.4,245.8c0.3-0.2,0.6-0.3,1.1-0.3c1.7,0,4.2,1.4,7,4c-1.2,1.3-2.3,2.7-3.4,4.3c-1.9,0.2-3.7,0.5-5.4,0.8
C194.6,250.1,194.9,246.7,196.4,245.8z M186.3,263.4c0-1.8,2.8-3.8,7.3-5.1c0.5,1.7,1.2,3.4,2,5.1c-0.8,1.7-1.4,3.4-2,5.1
C189.1,267.1,186.3,265.2,186.3,263.4z M196.4,281c-1.6-0.9-1.9-4.3-0.8-8.9c1.7,0.4,3.5,0.6,5.4,0.8c1.1,1.6,2.3,3,3.4,4.3
C201,280.5,197.9,281.9,196.4,281z M218,274.1c0.6,3.6,0.1,6.2-1.2,6.9c-1.5,0.9-4.6-0.5-8.1-3.8c1.2-1.3,2.3-2.7,3.4-4.3
c1.9-0.2,3.7-0.5,5.4-0.8C217.7,272.8,217.9,273.4,218,274.1z M219.7,268.5c-0.5-1.7-1.2-3.4-2-5.1c0.8-1.7,1.5-3.4,2-5.1
c4.5,1.3,7.3,3.3,7.3,5.1C227,265.2,224.2,267.1,219.7,268.5z"/>
</g>
</g>
================================================
FILE: src/diagrams/fields.xml
================================================
<g>
<polygon fill="#FFFFFF" points="254.6,192 262.7,178 270.7,192 "/>
<path d="M270.8,193.5C270.8,193.5,270.7,193.5,270.8,193.5h-16.2c-0.5,0-1-0.3-1.3-0.8c-0.3-0.5-0.3-1,0-1.5l8.1-14
c0.3-0.5,0.8-0.8,1.3-0.8s1,0.3,1.3,0.8l8,13.8c0.2,0.3,0.3,0.6,0.3,0.9C272.3,192.8,271.6,193.5,270.8,193.5z M257.2,190.5
h10.9l-5.5-9.5L257.2,190.5z"/>
</g>
<g>
<path fill="none" d="M276.9,180.3c-0.5,0-1,0.4-1,1s0.4,1,1,1s1-0.4,1-1S277.4,180.3,276.9,180.3z M276.9,181.8
c-0.3,0-0.5-0.2-0.5-0.5s0.2-0.5,0.5-0.5s0.5,0.2,0.5,0.5S277.2,181.8,276.9,181.8z"/>
<path d="M276.9,179.2c-1.1,0-2,0.9-2,2c0,1.1,0.9,2,2,2s2-0.9,2-2C278.9,180.1,278,179.2,276.9,179.2z"/>
</g>
<g>
<circle fill="#FFFFFF" cx="276.9" cy="188.2" r="0.5"/>
<path d="M276.9,190.2c-1.1,0-2-0.9-2-2s0.9-2,2-2s2,0.9,2,2S278,190.2,276.9,190.2z"/>
</g>
<path d="M342.6,176.1h-58.1c-0.8,0-1.5,0.7-1.5,1.5v14c0,0.8,0.7,1.5,1.5,1.5h58.1c0.8,0,1.5-0.7,1.5-1.5v-14
C344.1,176.8,343.4,176.1,342.6,176.1z"/>
<g>
<circle fill="#FFFFFF" cx="276.9" cy="202.8" r="0.5"/>
<path d="M276.9,204.8c-1.1,0-2-0.9-2-2c0-1.1,0.9-2,2-2s2,0.9,2,2C278.9,203.9,278,204.8,276.9,204.8z"/>
</g>
<g>
<path d="M276.9,211.7c-1.1,0-2-0.9-2-2s0.9-2,2-2s2,0.9,2,2S278,211.7,276.9,211.7z"/>
</g>
<path d="M356.8,197.6h-72.4c-0.8,0-1.5,0.7-1.5,1.5v14c0,0.8,0.7,1.5,1.5,1.5h72.4c0.8,0,1.5-0.7,1.5-1.5v-14
C358.3,198.3,357.7,197.6,356.8,197.6z"/>
<g>
<circle fill="#FFFFFF" cx="262.5" cy="206.1" r="7.2"/>
<path d="M262.5,214.9c-4.8,0-8.8-3.9-8.8-8.8s3.9-8.8,8.8-8.8s8.8,3.9,8.8,8.8S267.3,214.9,262.5,214.9z M262.5,200.4
c-3.2,0-5.8,2.6-5.8,5.8s2.6,5.8,5.8,5.8s5.8-2.6,5.8-5.8S265.7,200.4,262.5,200.4z"/>
</g>
================================================
FILE: src/diagrams/global-id-field.xml
================================================
<g>
<path fill="#FFFFFF" d="M262.5,255.4c-1.6,0-3.1-0.5-4.3-1.4c-1.8-1.3-3-3.4-3-5.8c0-4,3.2-7.2,7.2-7.2"/>
<path d="M262.5,256.9c-1.9,0-3.7-0.6-5.2-1.7c-2.2-1.6-3.6-4.3-3.6-7.1c0-4.8,3.9-8.8,8.8-8.8c0.8,0,1.5,0.7,1.5,1.5
s-0.7,1.5-1.5,1.5c-3.2,0-5.8,2.6-5.8,5.8c0,1.8,0.9,3.6,2.4,4.6c1,0.7,2.2,1.1,3.4,1.1c0.8,0,1.5,0.7,1.5,1.5
C264,256.2,263.3,256.9,262.5,256.9z"/>
</g>
<g>
<path fill="#FFFFFF" d="M268.8,244.4c0.6,1.1,1,2.3,1,3.7c0,2.4-1.1,4.4-2.9,5.8"/>
<path d="M266.9,255.4c-0.5,0-0.9-0.2-1.2-0.6c-0.5-0.7-0.4-1.6,0.3-2.1c1.4-1.1,2.3-2.8,2.3-4.6c0-1-0.3-2-0.8-2.9
c-0.4-0.7-0.2-1.6,0.5-2.1c0.7-0.4,1.6-0.2,2.1,0.5c0.8,1.3,1.2,2.9,1.2,4.4c0,2.8-1.3,5.3-3.5,7
C267.5,255.3,267.2,255.4,266.9,255.4z"/>
</g>
<g>
<path fill="#FFFFFF" d="M262.6,250.8c-1.6,0-2.8-1.3-2.8-2.8s1.3-2.8,2.8-2.8c1.6,0,2.8,1.3,2.8,2.8"/>
<path d="M262.6,252.3c-2.4,0-4.3-1.9-4.3-4.3s1.9-4.3,4.3-4.3s4.3,1.9,4.3,4.3c0,0.8-0.7,1.5-1.5,1.5s-1.5-0.7-1.5-1.5
c0-0.7-0.6-1.3-1.3-1.3s-1.3,0.6-1.3,1.3s0.6,1.3,1.3,1.3c0.8,0,1.5,0.7,1.5,1.5S263.4,252.3,262.6,252.3z"/>
</g>
<g>
<circle fill="#FFFFFF" cx="276.9" cy="244.8" r="0.5"/>
<path d="M276.9,246.8c-1.1,0-2-0.9-2-2c0-1.1,0.9-2,2-2s2,0.9,2,2C278.9,245.9,278,246.8,276.9,246.8z"/>
</g>
<g>
<path d="M276.9,253.7c-1.1,0-2-0.9-2-2s0.9-2,2-2s2,0.9,2,2S278,253.7,276.9,253.7z"/>
</g>
<path d="M340.6,239.6h-56.1c-0.8,0-1.5,0.7-1.5,1.5v14c0,0.8,0.7,1.5,1.5,1.5h56.1c0.8,0,1.5-0.7,1.5-1.5v-14
C342.1,240.3,341.4,239.6,340.6,239.6z"/>
================================================
FILE: src/diagrams/graphql-implementation.xml
================================================
<g>
<path d="M239.8,32.8c-1.5-0.7-2.6-2.2-2.6-4c0-0.2,0-0.4,0.1-0.6L225,21l14.8,25.6V32.8z"/>
<path d="M206.4,49.3h31.1c0-0.1,0.1-0.2,0.1-0.3l-15.3-26.5c-0.3,0.1-0.6,0.1-0.9,0.1c-0.3,0-0.6,0-0.9-0.1l-14.9,25.7
C206,48.5,206.3,48.9,206.4,49.3z"/>
<path d="M206.5,52.5l12,6.9c0.8-0.7,1.9-1.2,3-1.2c1.2,0,2.2,0.5,3,1.2l12.4-7.2h-30.4C206.6,52.3,206.5,52.4,206.5,52.5z"/>
<path d="M206.6,27.6c0.1,0.4,0.2,0.7,0.2,1.1c0,2.1-1.5,3.9-3.5,4.3v13.5L218,21L206.6,27.6z"/>
<path d="M429.5,0.9H14.5C7.1,0.9,1,6.9,1,14.4v60.9c-0.1,0.2-0.2,0.5-0.2,0.7s0.1,0.5,0.2,0.7v267.1c0,7.4,6.1,13.5,13.5,13.5
h414.9c7.4,0,13.5-6.1,13.5-13.5V14.4C443,6.9,436.9,0.9,429.5,0.9z M197.9,28.7c0-0.6,0.1-1.2,0.4-1.7c0.2-0.5,0.6-1,1-1.4
c0.2-0.2,0.4-0.4,0.7-0.5c0.5-0.3,1-0.6,1.6-0.7c0.3-0.1,0.6-0.1,0.9-0.1s0.6,0,0.9,0.1c0.6,0.1,1.1,0.4,1.6,0.7
c0,0,0.1,0.1,0.1,0.1l12.1-7c0-2.5,2-4.5,4.5-4.5c2.5,0,4.5,2,4.5,4.5l12.7,7.3c0.2-0.1,0.3-0.3,0.5-0.4c0.5-0.3,1-0.6,1.6-0.7
c0.3-0.1,0.6-0.1,0.9-0.1s0.6,0,0.9,0.1c0.6,0.1,1.1,0.4,1.6,0.7c0.2,0.2,0.5,0.3,0.7,0.5c0.4,0.4,0.7,0.9,1,1.4
c0.2,0.5,0.4,1.1,0.4,1.7c0,2.1-1.4,3.8-3.3,4.3v13.7c1.9,0.5,3.3,2.2,3.3,4.3c0,0.6-0.1,1.2-0.4,1.7c-0.2,0.5-0.6,1-1,1.4
c-0.2,0.2-0.4,0.4-0.7,0.5c-0.5,0.3-1,0.6-1.6,0.7c-0.3,0.1-0.6,0.1-0.9,0.1s-0.6,0-0.9-0.1c-0.6-0.1-1.1-0.4-1.6-0.7
c-0.1,0-0.1-0.1-0.2-0.1l-13.1,7.5c0,0.2,0.1,0.4,0.1,0.6c0,0.6-0.1,1.2-0.4,1.7c-0.2,0.5-0.6,1-1,1.4c-0.2,0.2-0.4,0.4-0.7,0.5
c-0.5,0.3-1,0.6-1.6,0.7c-0.3,0.1-0.6,0.1-0.9,0.1s-0.6,0-0.9-0.1c-0.6-0.1-1.1-0.4-1.6-0.7c-0.2-0.2-0.5-0.3-0.7-0.5
c-0.4-0.4-0.7-0.9-1-1.4c-0.2-0.5-0.4-1.1-0.4-1.7c0-0.2,0-0.4,0.1-0.6l-12.6-7.3c-0.4,0.2-0.9,0.4-1.3,0.5
c-0.3,0.1-0.6,0.1-0.9,0.1s-0.6,0-0.9-0.1c-0.6-0.1-1.1-0.4-1.6-0.7c-0.2-0.2-0.5-0.3-0.7-0.5c-0.4-0.4-0.7-0.9-1-1.4
c-0.2-0.5-0.4-1.1-0.4-1.7c0-1.7,1-3.2,2.4-3.9V32.7C198.9,31.9,197.9,30.4,197.9,28.7z M440,343.8c0,5.8-4.7,10.5-10.5,10.5
H14.5c-5.8,0-10.5-4.7-10.5-10.5V77.5H440V343.8z"/>
</g>
================================================
FILE: src/diagrams/mutation-type.xml
================================================
<g>
<polygon fill="#FFFFFF" points="160.6,270.3 180.4,258.9 200.1,270.3 200.1,293.1 180.4,304.5 160.6,293.1 "/>
<path d="M180.4,306.3L159.1,294v-24.5l21.3-12.3l21.3,12.3V294L180.4,306.3z M162.1,292.3l18.3,10.5l18.3-10.5v-21.1
l-18.3-10.5l-18.3,10.5V292.3z"/>
</g>
<g>
<path fill="none" d="M173.8,280.2c-0.1,1.3-0.1,2.5,0.4,3.6l2.9-4.3C176,279.8,174.9,280,173.8,280.2z"/>
<path fill="none" d="M181.5,278.3l-5,7.3c0.6,0,1.3-0.1,2-0.2l5.1-7.4C183,278,182.3,278.1,181.5,278.3z"/>
<path fill="none" d="M186.4,279.2l-3.4,4.9c1.3-0.4,2.6-0.7,3.9-0.9C187.1,281.8,187.1,280.4,186.4,279.2z"/>
<path d="M196.9,286.4c-2.1-2.3-4.4-3.2-6.9-3.3c0.2-2.3-0.1-4.6-1.8-6.5c-2.4-2.7-6.3-1.6-10-0.5c-1.3,0.4-2.6,0.7-3.9,1
c0.5-2.8,0.9-5.9-1.2-8.2c-0.5-0.6-1.5-0.7-2.1-0.1c-0.6,0.6-0.7,1.5-0.1,2.1c1.2,1.4,0.8,3.6,0.4,6.2c0,0.1,0,0.2,0,0.3
c-1.9-0.1-3.6-0.7-5.1-2.3c-0.5-0.6-1.5-0.7-2.1-0.1c-0.6,0.6-0.7,1.5-0.1,2.1c2.1,2.3,4.4,3.2,6.9,3.3
c-0.2,2.3,0.1,4.6,1.8,6.5c2.4,2.7,6.3,1.6,10,0.5c1.3-0.4,2.6-0.7,3.9-1c-0.5,2.8-0.9,5.9,1.2,8.2c0.3,0.3,0.7,0.5,1.1,0.5
c0.4,0,0.7-0.1,1-0.4c0.6-0.6,0.7-1.5,0.1-2.1c-1.2-1.4-0.8-3.6-0.4-6.2c0-0.1,0-0.2,0-0.3c1.9,0.1,3.6,0.6,5.1,2.3
c0.3,0.3,0.7,0.5,1.1,0.5c0.4,0,0.7-0.1,1-0.4C197.4,287.9,197.4,287,196.9,286.4z M176.6,285.6l5-7.3
c0.8-0.2,1.5-0.3,2.1-0.4l-5.1,7.4C177.8,285.5,177.1,285.6,176.6,285.6z M173.8,280.2c1.1-0.2,2.2-0.4,3.3-0.7l-2.9,4.3
C173.7,282.7,173.6,281.5,173.8,280.2z M186.4,279.2c0.7,1.1,0.7,2.5,0.6,4c-1.3,0.2-2.7,0.5-3.9,0.9L186.4,279.2z"/>
</g>
================================================
FILE: src/diagrams/mutations.xml
================================================
<rect x="49.2" y="238.7" fill="#FFFFFF" width="71.7" height="61.4"/>
<g>
<path fill="none" d="M82,274.6l10.4-15.2c-1.8-0.3-4,0-6.5,0.6l-10.1,14.7C77.5,275.3,79.6,275.1,82,274.6
C82,274.6,82,274.6,82,274.6z"/>
<path fill="none" d="M81.4,261.3c-3,0.9-6.3,1.8-9.6,2.2c-0.5,3.6-0.4,6.9,1.6,9.5L81.4,261.3z"/>
<path fill="none" d="M95.2,260.9C95.2,260.9,95.1,260.8,95.2,260.9l-8.7,12.6c0.3-0.1,0.6-0.2,0.9-0.2c3.1-0.9,6.5-1.9,9.9-2.3
C97.7,267.1,97.6,263.6,95.2,260.9z"/>
<path d="M112.8,276.2c-3.7-4.1-8.1-5.4-12.6-5.4c0.5-4.2,0.3-8.4-2.8-11.9c-3.8-4.2-10-2.4-16.5-0.6c-2.9,0.8-5.8,1.6-8.6,2.1
c0-0.2,0.1-0.4,0.1-0.6c0.9-5.2,1.9-10.6-1.7-14.5c-0.6-0.6-1.5-0.7-2.1-0.1c-0.6,0.6-0.7,1.5-0.1,2.1c2.6,2.9,1.8,7.3,0.9,12
c-0.1,0.5-0.2,0.9-0.2,1.4c-4,0.1-7.7-1-10.8-4.4c-0.5-0.6-1.5-0.7-2.1-0.1c-0.6,0.6-0.7,1.5-0.1,2.1c3.7,4.1,8.1,5.4,12.6,5.4
c-0.5,4.2-0.3,8.4,2.8,11.9c3.8,4.2,10,2.4,16.5,0.6c2.9-0.8,5.8-1.6,8.6-2.1c0,0.2-0.1,0.4-0.1,0.6c-0.9,5.2-1.9,10.6,1.7,14.5
c0.3,0.3,0.7,0.5,1.1,0.5c0.4,0,0.7-0.1,1-0.4c0.6-0.6,0.7-1.5,0.1-2.1c-2.6-2.9-1.8-7.3-0.9-12c0.1-0.5,0.2-0.9,0.2-1.4
c4-0.1,7.7,1,10.8,4.4c0.3,0.3,0.7,0.5,1.1,0.5c0.4,0,0.7-0.1,1-0.4C113.3,277.7,113.4,276.8,112.8,276.2z M71.8,263.5
c3.3-0.4,6.6-1.3,9.6-2.2l-8,11.7C71.4,270.3,71.3,267,71.8,263.5z M75.8,274.8l10.1-14.7c2.5-0.6,4.7-1,6.5-0.6L82,274.6
c0,0,0,0,0,0C79.6,275.1,77.5,275.3,75.8,274.8z M87.3,273.2c-0.3,0.1-0.6,0.2-0.9,0.2l8.6-12.6c0,0,0.1,0.1,0.1,0.1
c2.4,2.7,2.5,6.2,2,10C93.8,271.3,90.4,272.3,87.3,273.2z"/>
</g>
================================================
FILE: src/diagrams/network-layer.xml
================================================
<g>
<circle fill="#FFFFFF" cx="84.9" cy="129" r="24"/>
<path d="M84.9,154.5c-14.1,0-25.5-11.4-25.5-25.5s11.4-25.5,25.5-25.5s25.5,11.4,25.5,25.5S99,154.5,84.9,154.5z M84.9,106.5
c-12.4,0-22.5,10.1-22.5,22.5s10.1,22.5,22.5,22.5s22.5-10.1,22.5-22.5S97.3,106.5,84.9,106.5z"/>
</g>
<path d="M84.9,122.2l-6-6c-0.3-0.3-0.6-0.4-1.1-0.4s-0.8,0.2-1.1,0.4l-6,6c-0.6,0.6-0.6,1.5,0,2.1s1.5,0.6,2.1,0l3.4-3.4v19.7
c0,0.8,0.7,1.5,1.5,1.5s1.5-0.7,1.5-1.5v-19.7l3.4,3.4c0.3,0.3,0.7,0.4,1.1,0.4s0.8-0.1,1.1-0.4
C85.5,123.7,85.5,122.8,84.9,122.2z"/>
<path d="M98.9,133.6c-0.6-0.6-1.5-0.6-2.1,0l-3.4,3.4v-19.7c0-0.8-0.7-1.5-1.5-1.5s-1.5,0.7-1.5,1.5V137l-3.4-3.4
c-0.6-0.6-1.5-0.6-2.1,0s-0.6,1.5,0,2.1l6,6c0.1,0.1,0.1,0.1,0.2,0.2c0,0,0.1,0,0.1,0c0.1,0,0.1,0.1,0.2,0.1c0,0,0.1,0,0.1,0
c0.1,0,0.1,0,0.2,0.1c0.1,0,0.2,0,0.3,0s0.2,0,0.3,0c0.1,0,0.1,0,0.2-0.1c0,0,0.1,0,0.1,0c0.1,0,0.1-0.1,0.2-0.1c0,0,0,0,0.1,0
c0.1-0.1,0.2-0.1,0.2-0.2l6-6C99.5,135.1,99.5,134.2,98.9,133.6z"/>
</g>
================================================
FILE: src/diagrams/object-type.xml
================================================
<path d="M152.7,182.5c-19.2,0-34.8,15.6-34.8,34.8c0,19.2,15.6,34.8,34.8,34.8s34.8-15.6,34.8-34.8
C187.5,198.2,171.9,182.5,152.7,182.5z"/>
<g>
<polygon fill="#FFFFFF" points="132.9,206 152.7,194.6 172.4,206 172.4,228.8 152.7,240.2 132.9,228.8 "/>
<path d="M152.7,241.9l-21.3-12.3v-24.5l21.3-12.3l21.3,12.3v24.5L152.7,241.9z M134.4,227.9l18.3,10.5l18.3-10.5v-21.1
l-18.3-10.5l-18.3,10.5V227.9z"/>
</g>
<g>
<line fill="#FFFFFF" x1="187" y1="217.5" x2="208.7" y2="217.5"/>
<g>
<rect x="187" y="216" width="2" height="3"/>
<path d="M204.9,219h-3.5v-3h3.5V219z M199.6,219h-3.5v-3h3.5V219z M194.3,219h-3.5v-3h3.5V219z"/>
<rect x="206.7" y="216" width="2" height="3"/>
</g>
</g>
<path d="M303.7,115.5c-54.5,0-98.8,44.3-98.8,98.8s44.3,98.8,98.8,98.8s98.8-44.3,98.8-98.8S358.2,115.5,303.7,115.5z"/>
<g>
<polygon fill="#FFFFFF" points="233.9,174.1 303.7,133.8 373.5,174.1 373.5,254.7 303.7,295 233.9,254.7 "/>
<path d="M303.7,296.7l-71.3-41.2v-82.3l71.3-41.2l71.3,41.2v82.3L303.7,296.7z M235.4,253.8l68.3,39.4l68.3-39.4v-78.9
l-68.3-39.4l-68.3,39.4V253.8z"/>
</g>
<g>
<line fill="#FFFFFF" x1="139.3" y1="210.2" x2="142.8" y2="210.2"/>
<rect x="139.3" y="208.7" width="3.5" height="3"/>
</g>
<g>
<line fill="#FFFFFF" x1="139.3" y1="215.1" x2="142.8" y2="215.1"/>
<rect x="139.3" y="213.6" width="3.5" height="3"/>
</g>
<g>
<line fill="#FFFFFF" x1="139.3" y1="220.1" x2="142.8" y2="220.1"/>
<rect x="139.3" y="218.6" width="3.5" height="3"/>
</g>
<g>
<line fill="#FFFFFF" x1="139.3" y1="224.7" x2="142.8" y2="224.7"/>
<rect x="139.3" y="223.2" width="3.5" height="3"/>
</g>
<g>
<line fill="#FFFFFF" x1="146" y1="210.2" x2="159.5" y2="210.2"/>
<rect x="146" y="208.7" width="13.5" height="3"/>
</g>
<g>
<line fill="#FFFFFF" x1="146" y1="215.1" x2="165.5" y2="215.1"/>
<rect x="146" y="213.6" width="19.5" height="3"/>
</g>
<g>
<line fill="#FFFFFF" x1="146" y1="220.1" x2="162.4" y2="220.1"/>
<rect x="146" y="218.6" width="16.4" height="3"/>
</g>
<g>
<line fill="#FFFFFF" x1="146" y1="224.7" x2="158" y2="224.7"/>
<rect x="146" y="223.2" width="12" height="3"/>
</g>
================================================
FILE: src/diagrams/query-config.xml
================================================
<g>
<rect x="192.9" y="163.2" width="8.5" height="8.1"/>
<path d="M249.2,146.8h-85.4c-2.5,0-4.5,2-4.5,4.5v32.3c0,2.5,2,4.5,4.5,4.5h85.4c2.5,0,4.5-2,4.5-4.5v-32.3
C253.7,148.9,251.6,146.8,249.2,146.8z M180.6,160.2c0-2.1,2.8-3.4,4-3.9c0.8-0.3,1.6,0.1,1.9,0.8c0.3,0.8-0.1,1.6-0.8,1.9
c-0.9,0.3-1.8,0.9-2,1.3v3.3c0,0.9-0.7,2.5-2,3.7c1.3,1.2,2,2.8,2,3.7v3.3c0.2,0.3,1.2,0.9,2,1.3c0.8,0.3,1.2,1.2,0.8,1.9
c-0.2,0.6-0.8,1-1.4,1c-0.2,0-0.4,0-0.5-0.1c-1.2-0.5-4-1.8-4-3.9v-3.4c-0.1-0.3-1-1.9-2.3-2.2c-0.2,0-0.3,0-0.5,0
c-0.8,0-1.5-0.7-1.5-1.5s0.7-1.6,1.5-1.6c0.2,0,0.3,0,0.5,0c1.3-0.3,2.2-1.9,2.3-2.3L180.6,160.2z M189.9,172.9v-11.1
c0-0.8,0.7-1.5,1.5-1.5h11.5c0.8,0,1.5,0.7,1.5,1.5v11.1c0,0.8-0.7,1.5-1.5,1.5h-11.5C190.5,174.4,189.9,173.7,189.9,172.9z
M215,175.3c0.6,0.6,0.6,1.5,0,2.1c-0.3,0.3-0.7,0.4-1.1,0.4c-0.4,0-0.8-0.1-1.1-0.4c-0.2-0.2-3.8-3.8-3.8-10.1
s3.6-9.9,3.8-10.1c0.6-0.6,1.5-0.6,2.1,0c0.6,0.6,0.6,1.5,0,2.1c-0.1,0.1-2.9,3-2.9,7.9C212.1,172.3,215,175.3,215,175.3z
M218.1,159.4c-0.6-0.6-0.6-1.5,0-2.1c0.6-0.6,1.5-0.6,2.1,0c0.2,0.2,3.8,3.8,3.8,10.1s-3.6,9.9-3.8,10.1
c-0.3,0.3-0.7,0.4-1.1,0.4s-0.8-0.1-1.1-0.4c-0.6-0.6-0.6-1.5,0-2.1c0,0,2.9-3,2.9-7.9S218.1,159.4,218.1,159.4z M235.1,168.9
c-0.2,0-0.3,0-0.5,0c-1.3,0.3-2.2,1.9-2.3,2.3l0,3.3c0,2.1-2.8,3.4-4,3.9c-0.2,0.1-0.4,0.1-0.5,0.1c-0.6,0-1.2-0.4-1.4-1
c-0.3-0.8,0.1-1.6,0.8-1.9c0.9-0.3,1.8-0.9,2-1.3v-3.3c0-0.9,0.7-2.5,2-3.7c-1.3-1.2-2-2.8-2-3.7v-3.3c-0.2-0.3-1.2-0.9-2-1.3
c-0.8-0.3-1.2-1.2-0.8-1.9c0.3-0.8,1.2-1.1,1.9-0.8c1.2,0.5,4,1.8,4,3.9v3.4c0.1,0.3,1,1.9,2.3,2.2c0.2,0,0.3,0,0.5,0
c0.8,0,1.5,0.7,1.5,1.5S235.9,168.9,235.1,168.9z"/>
</g>
================================================
FILE: src/diagrams/query-type.xml
================================================
<g>
<polygon fill="#FFFFFF" points="104.9,269.7 124.7,258.3 144.4,269.7 144.4,292.5 124.7,303.9 104.9,292.5 "/>
<path d="M124.7,305.6l-21.3-12.3v-24.5l21.3-12.3l21.3,12.3v24.5L124.7,305.6z M106.4,291.6l18.3,10.5l18.3-10.5v-21.1
L124.7,260l-18.3,10.5V291.6z"/>
</g>
<g>
<path fill="#FFFFFF" d="M129.5,277.3c0-4-3.2-7.2-7.2-7.2c-4,0-7.2,3.2-7.2,7.2c0,4,3.2,7.2,7.2,7.2
C126.3,284.5,129.5,281.3,129.5,277.3z"/>
<path d="M132.9,292.4l-4.1-7.3c2.2-1.9,3.7-4.7,3.7-7.8c0-5.6-4.6-10.2-10.2-10.2c-5.6,0-10.2,4.6-10.2,10.2
c0,5.6,4.6,10.2,10.2,10.2c1.4,0,2.7-0.3,3.9-0.8l4.1,7.2c0.3,0.5,0.8,0.8,1.3,0.8c0.2,0,0.5-0.1,0.7-0.2
C133.1,294.1,133.4,293.2,132.9,292.4z M115.2,277.3c0-4,3.2-7.2,7.2-7.2c4,0,7.2,3.2,7.2,7.2c0,4-3.2,7.2-7.2,7.2
C118.4,284.5,115.2,281.3,115.2,277.3z"/>
</g>
================================================
FILE: src/diagrams/react-component.xml
================================================
<circle fill="#FFFFFF" cx="206.5" cy="263.5" r="27.5"/>
<g>
<path fill="none" d="M206.6,273.2c-0.5,0-1.1,0-1.6,0c0.5,0.7,1.1,1.3,1.6,1.9c0.5-0.6,1.1-1.2,1.6-1.9
C207.7,273.2,207.1,273.2,206.6,273.2z"/>
<path fill="none" d="M198.9,269.6c-0.3-0.4-0.5-0.9-0.8-1.4c-0.3-0.5-0.5-0.9-0.8-1.4c-0.3,0.8-0.6,1.6-0.8,2.3
C197.3,269.4,198.1,269.5,198.9,269.6z"/>
<path fill="none" d="M210.5,256.7c-1.2-0.1-2.5-0.1-3.9-0.1s-2.6,0.1-3.9,0.1c-0.7,1-1.4,2.1-2,3.3c-0.7,1.2-1.3,2.3-1.8,3.4
c0.5,1.1,1.1,2.3,1.8,3.4c0.7,1.2,1.4,2.2,2,3.3c1.2,0.1,2.5,0.1,3.9,0.1c1.3,0,2.6-0.1,3.9-0.1c0.7-1,1.4-2.1,2-3.3
c0.7-1.1,1.3-2.3,1.8-3.4c-0.6-1.1-1.2-2.3-1.8-3.4C211.9,258.8,211.2,257.7,210.5,256.7z M206.6,267.5
c-2.3,0-4.2-1.9-4.2-4.2c0-2.3,1.9-4.2,4.2-4.2c2.3,0,4.2,1.9,4.2,4.2C210.8,265.7,208.9,267.5,206.6,267.5z"/>
<path fill="none" d="M216.7,269.2c-0.3-0.8-0.5-1.5-0.8-2.3c-0.3,0.5-0.5,0.9-0.8,1.4c-0.3,0.5-0.5,0.9-0.8,1.4
C215.2,269.5,216,269.4,216.7,269.2z"/>
<path fill="none" d="M206.6,253.6c0.5,0,1.1,0,1.6,0c-0.5-0.7-1.1-1.3-1.6-1.9c-0.5,0.6-1.1,1.2-1.6,1.9
C205.6,253.6,206.1,253.6,206.6,253.6z"/>
<path fill="none" d="M212.1,253.8c1.9,0.2,3.7,0.5,5.4,0.8c0.2-0.7,0.3-1.3,0.4-2c0.6-3.6,0.1-6.2-1.2-6.9
c-0.3-0.2-0.6-0.3-1.1-0.3c-1.7,0-4.2,1.4-7,4C209.9,250.8,211,252.3,212.1,253.8z"/>
<path fill="none" d="M196.5,257.5c0.2,0.8,0.5,1.5,0.8,2.3c0.3-0.5,0.5-0.9,0.8-1.4c0.3-0.5,0.5-0.9,0.8-1.4
C198.1,257.2,197.3,257.4,196.5,257.5z"/>
<path fill="none" d="M208.7,277.2c3.5,3.3,6.6,4.6,8.1,3.8c1.3-0.8,1.7-3.4,1.2-6.9c-0.1-0.6-0.2-1.3-0.4-2
c-1.7,0.4-3.6,0.6-5.4,0.8C211,274.5,209.9,275.9,208.7,277.2z"/>
<path fill="none" d="M219.7,258.3c-0.5,1.7-1.2,3.4-2,5.1c0.8,1.7,1.5,3.4,2,5.1c4.5-1.3,7.3-3.3,7.3-5.1
C227,261.6,224.2,259.6,219.7,258.3z"/>
<path fill="none" d="M214.3,257.1c0.3,0.4,0.5,0.9,0.8,1.4c0.3,0.5,0.5,0.9,0.8,1.4c0.3-0.8,0.6-1.6,0.8-2.3
C216,257.4,215.2,257.2,214.3,257.1z"/>
<path fill="none" d="M204.5,249.5c-2.8-2.6-5.3-4-7-4c-0.4,0-0.8,0.1-1.1,0.3c-1.6,0.9-1.9,4.3-0.8,8.9
c1.7-0.4,3.5-0.6,5.4-0.8C202.2,252.3,203.4,250.8,204.5,249.5z"/>
<path fill="none" d="M193.6,258.3c-4.5,1.3-7.3,3.3-7.3,5.1c0,1.8,2.8,3.8,7.3,5.1c0.5-1.7,1.2-3.4,2-5.1
C194.8,261.7,194.1,259.9,193.6,258.3z"/>
<path fill="none" d="M201.1,272.9c-1.9-0.2-3.7-0.5-5.4-0.8c-1.1,4.6-0.8,8,0.8,8.9c1.5,0.9,4.6-0.5,8.1-3.8
C203.4,275.9,202.2,274.5,201.1,272.9z"/>
<circle cx="206.6" cy="263.4" r="4.2"/>
<path d="M230,263.4c0-3.7-4-6.4-9.5-8c0.2-0.8,0.3-1.5,0.5-2.2c0.8-5-0.1-8.6-2.6-10c-0.8-0.4-1.6-0.7-2.6-0.7
c-2.6,0-5.9,1.8-9.1,4.9c-3.3-3.1-6.5-4.9-9.1-4.9c-0.9,0-1.8,0.2-2.6,0.7c-3.2,1.8-3.5,6.6-2.2,12.2c-5.5,1.6-9.5,4.3-9.5,8
c0,3.7,4,6.4,9.5,8c-1.4,5.6-1,10.4,2.2,12.2c0.8,0.4,1.6,0.7,2.6,0.7c2.6,0,5.9-1.8,9.1-4.9c3.3,3.1,6.5,4.9,9.1,4.9
c0.9,0,1.8-0.2,2.6-0.7c2.5-1.4,3.4-5,2.6-10c-0.1-0.7-0.3-1.5-0.5-2.2C226,269.7,230,267,230,263.4z M216.8,245.8
c1.3,0.8,1.7,3.4,1.2,6.9c-0.1,0.6-0.2,1.3-0.4,2c-1.7-0.4-3.6-0.6-5.4-0.8c-1.1-1.6-2.3-3-3.4-4.3c2.8-2.6,5.3-4,7-4
C216.1,245.5,216.5,245.6,216.8,245.8z M215.9,266.9c0.3,0.8,0.6,1.6,0.8,2.3c-0.8,0.2-1.6,0.3-2.4,0.4
c0.3-0.4,0.5-0.9,0.8-1.4C215.4,267.8,215.6,267.4,215.9,266.9z M212.5,266.8c-0.7,1.2-1.4,2.2-2,3.3
c-1.2,0.1-2.5,0.1-3.9,0.1c-1.3,0-2.6-0.1-3.9-0.1c-0.7-1-1.4-2.1-2-3.3c-0.7-1.2-1.3-2.3-1.8-3.4c0.5-1.1,1.1-2.3,1.8-3.4
c0.7-1.2,1.4-2.2,2-3.3c1.2-0.1,2.5-0.1,3.9-0.1s2.6,0.1,3.9,0.1c0.7,1,1.4,2.1,2,3.3c0.7,1.1,1.3,2.3,1.8,3.4
C213.8,264.5,213.2,265.7,212.5,266.8z M206.6,275.1c-0.5-0.6-1.1-1.2-1.6-1.9c0.5,0,1.1,0,1.6,0s1.1,0,1.6,0
C207.7,273.8,207.1,274.5,206.6,275.1z M198.1,268.3c0.3,0.5,0.5,0.9,0.8,1.4c-0.8-0.1-1.6-0.3-2.4-0.4
c0.2-0.8,0.5-1.5,0.8-2.3C197.6,267.4,197.8,267.8,198.1,268.3z M197.3,259.9c-0.3-0.8-0.6-1.6-0.8-2.3
c0.8-0.2,1.6-0.3,2.4-0.4c-0.3,0.4-0.5,0.9-0.8,1.4C197.8,258.9,197.6,259.4,197.3,259.9z M206.6,251.7
c0.5,0.6,1.1,1.2,1.6,1.9c-0.5,0-1.1,0-1.6,0s-1.1,0-1.6,0C205.6,252.9,206.1,252.3,206.6,251.7z M215.1,258.5
c-0.3-0.5-0.5-0.9-0.8-1.4c0.8,0.1,1.7,0.3,2.4,0.4c-0.3,0.8-0.5,1.5-0.8,2.3C215.6,259.4,215.4,258.9,215.1,258.5z
M196.4,245.8c0.3-0.2,0.6-0.3,1.1-0.3c1.7,0,4.2,1.4,7,4c-1.2,1.3-2.3,2.7-3.4,4.3c-1.9,0.2-3.7,0.5-5.4,0.8
C194.6,250.1,194.9,246.7,196.4,245.8z M186.3,263.4c0-1.8,2.8-3.8,7.3-5.1c0.5,1.7,1.2,3.4,2,5.1c-0.8,1.7-1.4,3.4-2,5.1
C189.1,267.1,186.3,265.2,186.3,263.4z M196.4,281c-1.6-0.9-1.9-4.3-0.8-8.9c1.7,0.4,3.5,0.6,5.4,0.8c1.1,1.6,2.3,3,3.4,4.3
C201,280.5,197.9,281.9,196.4,281z M218,274.1c0.6,3.6,0.1,6.2-1.2,6.9c-1.5,0.9-4.6-0.5-8.1-3.8c1.2-1.3,2.3-2.7,3.4-4.3
c1.9-0.2,3.7-0.5,5.4-0.8C217.7,272.8,217.9,273.4,218,274.1z M219.7,268.5c-0.5-1.7-1.2-3.4-2-5.1c0.8-1.7,1.5-3.4,2-5.1
c4.5,1.3,7.3,3.3,7.3,5.1C227,265.2,224.2,267.1,219.7,268.5z"/>
</g>
================================================
FILE: src/diagrams/relay.xml
================================================
<path d="M306.5,0.7h-292C7,0.7,1,6.8,1,14.2v310.3C1,331.9,7,338,14.5,338h292c7.4,0,13.5-6.1,13.5-13.5V14.2
C320,6.8,313.9,0.7,306.5,0.7z M138.5,16.9c0.7-0.5,1.6-0.8,2.5-0.8c0.3,0,0.6,0,0.9,0.1c0.3,0.1,0.6,0.1,0.8,0.3
c1.1,0.5,2,1.4,2.4,2.6h21.6c0.1,0,0.2,0,0.3,0c1.9,0.3,5.4,2.1,5.4,6.1c0,4.9-4.8,6.5-5,6.6c-0.2,0.1-0.3,0.1-0.5,0.1h-13.3
c-0.5,0-2.2,1.3-2.2,3.2c0,1.8,1.4,3.2,1.9,3.3l22.4,0c0.3-0.9,0.9-1.6,1.7-2.1c0.7-0.5,1.6-0.8,2.5-0.8c0.3,0,0.6,0,0.9,0.1
c0.3,0.1,0.6,0.1,0.8,0.3c1.6,0.7,2.7,2.3,2.7,4.1c0,1.8-1.1,3.4-2.7,4.1c-0.3,0.1-0.5,0.2-0.8,0.3c-0.3,0.1-0.6,0.1-0.9,0.1
c-0.9,0-1.8-0.3-2.5-0.8c-0.8-0.5-1.4-1.4-1.7-2.3h-22.4c-2.4,0-4.8-3.2-4.8-6.3c0-3.2,2.8-6.1,5.1-6.2l13.1,0
c0.7-0.3,2.8-1.4,2.8-3.7c0-2.3-2.3-3-2.8-3.1h-21.5c-0.4,1.2-1.3,2.1-2.4,2.6c-0.3,0.1-0.5,0.2-0.8,0.3c-0.3,0.1-0.6,0.1-0.9,0.1
c-0.9,0-1.8-0.3-2.5-0.8c-1.2-0.8-2-2.2-2-3.7C136.6,19,137.3,17.7,138.5,16.9z M317,324.5c0,5.8-4.7,10.5-10.5,10.5h-292
C8.7,335,4,330.3,4,324.5V57.7h313V324.5z"/>
================================================
FILE: src/diagrams/root-container.xml
================================================
<path d="M256.2,88.7h-97.7c-5.2,0-9.5,4.3-9.5,9.5v205.4c0,1.9,1.6,3.5,3.5,3.5h109.7c1.9,0,3.5-1.6,3.5-3.5V98.2
C265.7,92.9,261.4,88.7,256.2,88.7z M216.4,100.1l-3.2,5.8c-0.3,0.5-0.8,0.8-1.3,0.8c-0.2,0-0.5-0.1-0.7-0.2
c-0.7-0.4-1-1.3-0.6-2l3.2-5.8c0.4-0.7,1.3-1,2-0.6C216.5,98.4,216.8,99.3,216.4,100.1z M220.6,104c0.7-0.4,1.6-0.2,2,0.6
c0.4,0.7,0.2,1.6-0.6,2l-5.7,3.3c-0.2,0.1-0.5,0.2-0.7,0.2c-0.5,0-1-0.3-1.3-0.8c-0.4-0.7-0.2-1.6,0.6-2L220.6,104z M211.4,120.5
c0.7-0.4,1.6-0.2,2,0.6l3.3,5.7c0.4,0.7,0.2,1.6-0.6,2c-0.2,0.1-0.5,0.2-0.7,0.2c-0.5,0-1-0.3-1.3-0.8l-3.3-5.7
C210.5,121.9,210.7,121,211.4,120.5z M215,119.5c-0.7-0.4-1-1.3-0.6-2c0.4-0.7,1.3-1,2-0.6l5.8,3.2c0.7,0.4,1,1.3,0.6,2
c-0.3,0.5-0.8,0.8-1.3,0.8c-0.2,0-0.5-0.1-0.7-0.2L215,119.5z M216.9,115c-0.8,0-1.5-0.7-1.5-1.5s0.7-1.5,1.5-1.5h6.6
c0.8,0,1.5,0.7,1.5,1.5s-0.7,1.5-1.5,1.5H216.9z M205.8,123.4c0-0.8,0.7-1.5,1.5-1.5s1.5,0.7,1.5,1.5v6.6c0,0.8-0.7,1.5-1.5,1.5
s-1.5-0.7-1.5-1.5V123.4z M205.6,104v-6.6c0-0.8,0.7-1.5,1.5-1.5s1.5,0.7,1.5,1.5v6.6c0,0.8-0.7,1.5-1.5,1.5
S205.6,104.8,205.6,104z M200.2,117.7c0.4,0.7,0.2,1.6-0.6,2l-5.7,3.3c-0.2,0.1-0.5,0.2-0.7,0.2c-0.5,0-1-0.3-1.3-0.8
c-0.4-0.7-0.2-1.6,0.6-2l5.7-3.3C198.9,116.7,199.8,116.9,200.2,117.7z M199,110.4c-0.2,0-0.5-0.1-0.7-0.2l-5.8-3.2
c-0.7-0.4-1-1.3-0.6-2c0.4-0.7,1.3-1,2-0.6l5.8,3.2c0.7,0.4,1,1.3,0.6,2C200,110.1,199.5,110.4,199,110.4z M198.1,127.2l3.2-5.8
c0.4-0.7,1.3-1,2-0.6c0.7,0.4,1,1.3,0.6,2l-3.2,5.8c-0.3,0.5-0.8,0.8-1.3,0.8c-0.2,0-0.5-0.1-0.7-0.2
C197.9,128.8,197.7,127.9,198.1,127.2z M191.1,112.1h6.6c0.8,0,1.5,0.7,1.5,1.5s-0.7,1.5-1.5,1.5h-6.6c-0.8,0-1.5-0.7-1.5-1.5
S190.3,112.1,191.1,112.1z M262.7,303.6c0,0.3-0.2,0.5-0.5,0.5H152.5c-0.3,0-0.5-0.2-0.5-0.5V139h110.7V303.6z"/>
================================================
FILE: src/diagrams/schema-copy.xml
================================================
<g>
<polygon fill="#FFFFFF" points="98.3,178.3 98.3,184.7 104.2,184.7 "/>
<path fill="#FFFFFF" d="M105,187.7h-8.2c-0.8,0-1.5-0.7-1.5-1.5v-9.5h-29V221H105V187.7z"/>
<path d="M107.5,183.8l-9-9.7c-0.3-0.3-0.7-0.5-1.1-0.5H64.8c-0.8,0-1.5,0.7-1.5,1.5v47.3c0,0.8,0.7,1.5,1.5,1.5h41.7
c0.8,0,1.5-0.7,1.5-1.5v-37.7C108,184.5,107.8,184.1,107.5,183.8z M98.3,178.3l6,6.4h-6V178.3z M66.3,176.7h29v9.5
c0,0.8,0.7,1.5,1.5,1.5h8.2V221H66.3V176.7z"/>
</g>
<g>
<path fill="#FFFFFF" d="M93.7,209.7l-6.5-11.3c-0.1,0-0.1,0-0.2,0.1c-0.3,0.1-0.6,0.1-0.9,0.1c-0.4,0-0.7-0.1-1.1-0.1l-6.8,11.7
c0.4,0.4,0.7,0.9,0.9,1.4h13.5C92.8,210.8,93.2,210.2,93.7,209.7z"/>
<path fill="#FFFFFF" d="M86.1,189.6L86.1,189.6c0.3,0,0.6,0,0.9,0.1C86.7,189.6,86.4,189.6,86.1,189.6z"/>
<path fill="#FFFFFF" d="M74.6,190c0.3,0,0.6,0,0.9-0.1C75.2,190,74.9,190,74.6,190L74.6,190z"/>
<path fill="#FFFFFF" d="M74.6,181.1L74.6,181.1c0.3,0,0.6,0,0.9,0.1C75.2,181.1,74.9,181.1,74.6,181.1z"/>
<path fill="#FFFFFF" d="M96.9,217.3c0.3,0,0.6,0,0.9-0.1C97.5,217.2,97.2,217.3,96.9,217.3L96.9,217.3z"/>
<path fill="#FFFFFF" d="M96.9,208.4L96.9,208.4c0.3,0,0.6,0,0.9,0.1C97.5,208.4,97.2,208.4,96.9,208.4z"/>
<path d="M98.6,208.7c-0.3-0.1-0.5-0.2-0.8-0.3c-0.3-0.1-0.6-0.1-0.9-0.1l0,0c-0.1,0-0.3,0-0.4,0l-6.8-11.7
c0.5-0.7,0.9-1.6,0.9-2.6c0-1.8-1.1-3.4-2.7-4.1c-0.3-0.1-0.5-0.2-0.8-0.3c-0.3-0.1-0.6-0.1-0.9-0.1l0,0c-0.9,0-1.8,0.3-2.5,0.8
l-4.8-3.5c0.1-0.4,0.2-0.8,0.2-1.3c0-1.8-1.1-3.4-2.7-4.1c-0.3-0.1-0.5-0.2-0.8-0.3c-0.3-0.1-0.6-0.1-0.9-0.1l0,0
c-0.9,0-1.8,0.3-2.5,0.8c-1.2,0.8-2,2.2-2,3.7c0,1.5,0.8,2.9,2,3.7c0.7,0.5,1.6,0.8,2.5,0.8l0,0c0.3,0,0.6,0,0.9-0.1
c0.3-0.1,0.6-0.1,0.8-0.3c0.3-0.1,0.5-0.2,0.7-0.4l4.8,3.5c-0.1,0.4-0.2,0.8-0.2,1.3c0,1,0.3,1.9,0.9,2.6l-6.9,12
c0.1,0,0.2,0,0.3,0c-0.3-0.1-0.6-0.1-0.9-0.1l0,0c-0.9,0-1.8,0.3-2.5,0.8c-1.2,0.8-2,2.2-2,3.7c0,1.5,0.8,2.9,2,3.7
c0.7,0.5,1.6,0.8,2.5,0.8l0,0c0.3,0,0.6,0,0.9-0.1c0.3-0.1,0.6-0.1,0.8-0.3c1.2-0.5,2.1-1.5,2.5-2.7h13.6c0.3,0.8,0.9,1.5,1.6,2
c0.7,0.5,1.6,0.8,2.5,0.8l0,0c0.3,0,0.6,0,0.9-0.1c0.3-0.1,0.6-0.1,0.8-0.3c1.6-0.7,2.7-2.3,2.7-4.1
C101.3,211,100.2,209.4,98.6,208.7z M79.1,211.5c-0.2-0.5-0.5-1-0.9-1.4l6.8-11.7c0.3,0.1,0.7,0.1,1.1,0.1c0.3,0,0.6,0,0.9-0.1
c0.1,0,0.1,0,0.2-0.1l6.5,11.3c-0.5,0.5-0.9,1.1-1.1,1.8H79.1z"/>
<path fill="#FFFFFF" d="M75,217.5c0.3,0,0.6,0,0.9-0.1C75.6,217.5,75.3,217.5,75,217.5L75,217.5z"/>
<path fill="#FFFFFF" d="M75.9,208.7c-0.1,0-0.2,0-0.3,0c-0.2,0-0.4-0.1-0.6-0.1l0,0C75.3,208.6,75.6,208.6,75.9,208.7z"/>
</g>
================================================
FILE: src/diagrams/schema.xml
================================================
<g>
<path d="M56.1,212.3c-0.4,0-0.7-0.1-1.1-0.1l-6.8,11.7c0.4,0.4,0.7,0.9,0.9,1.4h13.5c0.2-0.7,0.6-1.3,1.1-1.8l-6.5-11.3
C56.8,212.3,56.4,212.3,56.1,212.3z"/>
<path d="M416.8,98.6H31c-5.2,0-9.5,4.3-9.5,9.5v215.9c0,5.2,4.3,9.5,9.5,9.5h385.8c1.9,0,3.5-1.6,3.5-3.5V102.1
C420.3,100.2,418.8,98.6,416.8,98.6z M66.8,231.1c-1.9,0-3.5-1.1-4.1-2.8H49.1c-0.6,1.7-2.2,3-4.2,3c-2.5,0-4.5-2-4.5-4.5
c0-2.5,2-4.5,4.5-4.5c0.2,0,0.4,0,0.6,0.1l6.9-12c-0.5-0.7-0.9-1.6-0.9-2.6c0-0.4,0.1-0.9,0.2-1.3l-4.8-3.5
c-0.7,0.5-1.6,0.8-2.5,0.8c-2.5,0-4.5-2-4.5-4.5c0-2.5,2-4.5,4.5-4.5c2.5,0,4.5,2,4.5,4.5c0,0.4-0.1,0.9-0.2,1.3l4.8,3.5
c0.7-0.5,1.6-0.8,2.5-0.8c2.5,0,4.5,2,4.5,4.5c0,1-0.3,1.9-0.9,2.6l6.8,11.7c0.1,0,0.3,0,0.4,0c2.5,0,4.5,2,4.5,4.5
C71.3,229.1,69.3,231.1,66.8,231.1z M417.3,330.1c0,0.3-0.2,0.5-0.5,0.5H90.5V101.6h326.3c0.3,0,0.5,0.2,0.5,0.5V330.1z"/>
</g>
================================================
FILE: src/diagrams/web-framework.xml
================================================
<g>
<line fill="#FFFFFF" x1="468.7" y1="179.1" x2="443.1" y2="179.1"/>
<path d="M468.7,180.6h-4v-3h4V180.6z M462.7,180.6h-4v-3h4V180.6z M456.7,180.6h-4v-3h4V180.6z M450.7,180.6h-4v-3h4V180.6z
M444.7,180.6h-1.5v-3h1.5V180.6z"/>
</g>
<g>
<path fill="#FFFFFF" d="M501.2,173.9c0.5,1.2,0.8,2.3,1.2,3.5c5.4,3.3,9.4,7,11.4,8.9c0.8-2.3,1.2-4.7,1.2-7.2
c0-12.4-10.1-22.5-22.5-22.5c-0.7,0-1.4,0-2.1,0.1C493.2,159.6,497.9,165.3,501.2,173.9z"/>
<path fill="#FFFFFF" d="M481,172.7c0.4,3.6,1.2,7.4,2.7,10.8c4,8.9,12.5,15.7,14.6,17.3c0.9-0.2,1.8-0.5,2.6-0.9
c0.3-2.8,1.1-11.7-1.1-20.6c-2.2-1.3-4.6-2.6-7.2-3.6C488.5,174.1,484.4,173.2,481,172.7z"/>
<path fill="#FFFFFF" d="M486.7,157.3c-2.1,0.6-4,1.4-5.8,2.5c-0.2,1.5-0.5,5.3-0.2,9.8c3.8,0.5,8.4,1.5,13,3.4
c1.7,0.7,3.2,1.4,4.8,2.2c0-0.1,0-0.1-0.1-0.2C494.6,165.1,488.7,159.1,486.7,157.3z"/>
<path fill="#FFFFFF" d="M503.4,181.7c1.3,6.8,1.1,13.1,0.7,16.6c3.6-2.2,6.5-5.3,8.4-9.1C511.5,188.2,508.1,185,503.4,181.7z"/>
<path fill="#FFFFFF" d="M492.5,201.6c0.6,0,1.3,0,1.9-0.1c-3.7-3-10-9.1-13.4-16.8c-1.8-4-2.6-8.3-3-12.4
c-3.2-0.3-5.6-0.2-6.8-0.2c-0.7,2.2-1.1,4.5-1.1,6.9C470,191.5,480.1,201.6,492.5,201.6z"/>
<path fill="#FFFFFF" d="M477.7,169.3c-0.1-2.8-0.1-5.3,0-7.1c-2.2,1.9-4.1,4.3-5.4,7C473.6,169.1,475.5,169.1,477.7,169.3z"/>
<path d="M492.5,153.6c-14.1,0-25.5,11.4-25.5,25.5s11.4,25.5,25.5,25.5s25.5-11.4,25.5-25.5S506.5,153.6,492.5,153.6z M515,179.1
c0,2.5-0.4,4.9-1.2,7.2c-2-1.9-6-5.5-11.4-8.9c-0.3-1.2-0.7-2.4-1.2-3.5c-3.3-8.6-8-14.3-10.9-17.2c0.7-0.1,1.4-0.1,2.1-0.1
C504.9,156.6,515,166.7,515,179.1z M500.9,199.9c-0.9,0.3-1.7,0.6-2.6,0.9c-2.2-1.6-10.7-8.4-14.6-17.3
c-1.5-3.4-2.3-7.2-2.7-10.8c3.5,0.5,7.5,1.4,11.7,3.1c2.6,1,5,2.3,7.2,3.6C502.1,188.2,501.3,197.1,500.9,199.9z M493.7,173
c-4.7-1.9-9.2-2.8-13-3.4c-0.3-4.5,0-8.3,0.2-9.8c1.8-1.1,3.7-1.9,5.8-2.5c2,1.8,7.9,7.7,11.7,17.6c0,0.1,0.1,0.1,0.1,0.2
C497,174.4,495.4,173.6,493.7,173z M477.7,162.1c-0.1,1.9-0.2,4.3,0,7.1c-2.2-0.2-4-0.2-5.4-0.2
C473.6,166.5,475.5,164.1,477.7,162.1z M471.1,172.2c1.2-0.1,3.6-0.1,6.8,0.2c0.4,4,1.3,8.4,3,12.4c3.4,7.7,9.8,13.8,13.4,16.8
c-0.6,0.1-1.2,0.1-1.9,0.1c-12.4,0-22.5-10.1-22.5-22.5C470,176.7,470.4,174.4,471.1,172.2z M504.1,198.3
c0.3-3.6,0.5-9.9-0.7-16.6c4.7,3.3,8.1,6.5,9.2,7.6C510.6,193,507.7,196.1,504.1,198.3z"/>
</g>
================================================
FILE: src/index.js
================================================
import React from 'react';
import App from './components/App';
import topics from './diagram-data';
React.render(<App topics={topics} />, document.getElementById('root'));
================================================
FILE: src/shared/styles/colors.scss
================================================
$relay-primary-color: #f26b00;
$relay-secondary-color: #FBFEFA;
$dark-color: #3B3738;
$desaturated-relay-color: desaturate($relay-primary-color, 90);
$light-3-color: lighten($desaturated-relay-color, 35);
$light-2-color: lighten($desaturated-relay-color, 45);
$light-1-color: lighten($desaturated-relay-color, 50);
================================================
FILE: src/topics/backend.js
================================================
import WebFrameworkTopic from './web-framework';
import GraphQLTopic from './graphql-impl';
export default {
title: 'Back End',
description: 'Relay wraps around the view layer of your application, while your app’s back end does the work of responding to its queries. This could be a separate server, or the same server that’s serving your UI.',
width: 519,
height: 359,
children: [
WebFrameworkTopic,
GraphQLTopic
]
}
================================================
FILE: src/topics/container.js
================================================
import ContainerDiagram from '../diagrams/container.xml';
import ReactComponentTopic from './react-component';
export default {
title: 'Relay.Container',
description: 'Relay.Container is a higher order component that wraps around your React Component and ensures that it gets the data it depends on before rendering. This is where you’ll declare your component’s data dependencies with query fragments.',
officialDocs: 'https://facebook.github.io/relay/docs/guides-containers.html#content',
diagram: ContainerDiagram,
children: [
ReactComponentTopic
]
}
================================================
FILE: src/topics/graphql-impl.js
================================================
import GraphQLDiagram from '../diagrams/graphql-implementation.xml';
import SchemaTopic from './graphql-schema.js';
export default {
title: 'GraphQL Implementation',
description: 'You’ll need a GraphQL implementation that will be able to parse and validate your GraphQL schema, as well as execute queries sent to it from Relay. It’s already been implemented in a few different languages, and there are more popping up all the time!',
officialDocs: 'http://facebook.github.io/graphql/',
diagram: GraphQLDiagram,
children: [
SchemaTopic
]
}
================================================
FILE: src/topics/graphql-schema.js
================================================
import SchemaDiagram from '../diagrams/schema.xml';
import ObjectTypeTopic from './object-type';
import QueryTypeTopic from './query-type';
import MutationType from './mutation-type';
export default {
title: 'GraphQL Schema',
description: 'A Schema describes how your data is structured by creating a hierarchy of types. These types can be your application’s objects — e.g users, likes or photos — or other types used to query and mutate your application’s data.',
diagram: SchemaDiagram,
children: [
ObjectTypeTopic,
QueryTypeTopic,
MutationType
]
}
================================================
FILE: src/topics/mutation-type.js
================================================
import MutationTypeDiagram from '../diagrams/mutation-type.xml';
export default {
title: 'Mutation Type',
description: 'If you want Relay to be able to change the data on your server, you’ll need a Mutation Type. Each of your mutations will need to be root fields on this Mutation Type, and return an object representing the successful mutation’s payload.',
officialDocs: 'https://facebook.github.io/relay/docs/graphql-mutations.html#content',
diagram: MutationTypeDiagram
}
================================================
FILE: src/topics/mutations.js
================================================
import MutationDiagram from '../diagrams/mutations.xml';
export default {
title: 'Mutations',
description: 'To change data in your app you’ll need mutations. In order for Relay to know which objects will be changed by mutations, and do things like optimistic updates, you’ll need to let it know up front about how your mutations behave. What arguments does this mutation take? What might the returned payload look like? Which associations will be changed? This rabbit hole goes deep.',
officialDocs: 'https://facebook.github.io/relay/docs/guides-mutations.html#content',
diagram: MutationDiagram
};
================================================
FILE: src/topics/network-layer.js
================================================
import NetworkLayerDiagram from '../diagrams/network-layer.xml';
export default {
title: 'Network Layer',
description: 'Relay’s Network Layer does the work of exchanging data with the GraphQL server. It’s also configurable, so this would be a good place to do something like modify the headers of your requests.',
officialDocs: 'https://facebook.github.io/relay/docs/guides-network-layer.html#content',
diagram: NetworkLayerDiagram
}
================================================
FILE: src/topics/object-type-fields.js
================================================
import FieldsDiagram from '../diagrams/fields.xml';
import ConnectionFieldDiagram from '../diagrams/connection-field.xml';
import GlobalIDFieldDiagram from '../diagrams/global-id-field.xml';
export default [
{
title: 'Fields',
description: 'The fields in your object describe the kinds of properties that can be queried, such as a user’s email address or favourite colour. They can also describe associated object types, like a user’s profile photo.',
diagram: FieldsDiagram
},
{
title: 'Connection Fields',
description: 'To enable fancy stuff like easy pagination, Relay asks that some of your object’s associations are expressed in a standardised way. It involves edges and nodes and other graph theory stuff that can thankfully be handled for you by a helper library.',
officialDocs: 'https://facebook.github.io/relay/docs/graphql-connections.html#content',
diagram: ConnectionFieldDiagram
},
{
title: 'Global ID Field',
description: 'Relay also requires that all objects have a global ID — unique across all types of data — that can be used to refetch any given object without knowing its type.',
officialDocs: 'https://facebook.github.io/relay/docs/graphql-object-identification.html#content',
diagram: GlobalIDFieldDiagram
}
]
================================================
FILE: src/topics/object-type.js
================================================
import ObjectTypeDiagram from '../diagrams/object-type.xml';
import ObjectTypeFields from './object-type-fields';
export default {
title: 'Object Type',
description: 'This is your generic object type. It could be anything in your data model, such as a user, a blog post or product review.',
diagram: ObjectTypeDiagram,
children: ObjectTypeFields
}
================================================
FILE: src/topics/query-config.js
================================================
import QueryConfigDiagram from '../diagrams/query-config.xml';
export default {
title: 'Relay.Route',
description: 'First up: Relay.Route doesn’t have anything to do with URLs or the History API. What Relay.Route does do is complete the query fragments declared by Relay Containers by declaring which object should be fetched from the server, e.g. User with ID 123.',
officialDocs: 'https://facebook.github.io/relay/docs/guides-routes.html#content',
diagram: QueryConfigDiagram
}
================================================
FILE: src/topics/query-type.js
================================================
import QueryTypeDiagram from '../diagrams/query-type.xml';
export default {
title: 'Query Type',
description: 'To query data, your schema will need a Query Type containing fields that fetch your various object types. These fields have resolve methods that describe how the requested data should actually be fetched. Relay will also want a special field here that will allow you to fetch an object of any type given its Global ID.',
officialDocs: 'https://facebook.github.io/relay/docs/graphql-object-identification.html#content',
diagram: QueryTypeDiagram
}
================================================
FILE: src/topics/react-component.js
================================================
import ReactComponentDiagram from '../diagrams/react-component.xml';
export default {
title: 'React.Component',
description: 'Finally something familiar! At the core of all these layers are the React components you know and love. That’s not to say React.Component doesn’t have a few new tricks up its sleeve, like being able to interact with Relay’s queries with setVariables().',
officialDocs: 'https://facebook.github.io/relay/docs/guides-containers.html#content',
diagram: ReactComponentDiagram
}
================================================
FILE: src/topics/relay.js
================================================
import RelayDiagram from '../diagrams/relay.xml';
import RootContainerTopic from './root-container';
import NetworkLayerTopic from './network-layer';
import SchemaCopyTopic from './schema-copy';
import MutationsTopic from './mutations';
export default {
title: 'Relay',
description: 'Relay is a framework for Javascript applications that aims to abstract away the repetitive work of exchanging data with a server. It works together with a GraphQL server to query, deliver and mutate data in a consistent, dependable way. A tall order!',
officialDocs: "https://facebook.github.io/relay/",
diagram: RelayDiagram,
width: 321,
height: 339,
children: [
RootContainerTopic,
NetworkLayerTopic,
SchemaCopyTopic,
MutationsTopic
]
}
================================================
FILE: src/topics/root-container.js
================================================
import RootContainerDiagram from '../diagrams/root-container.xml';
import RelayRouteTopic from './query-config';
import ContainerTopic from './container';
export default {
title: 'Relay.RootContainer',
description: 'Relay.RootContainer takes a Component (wrapped up in a Relay.Container) and a Relay.Route, turns these into a full query and sends it off to the GraphQL server. It’s also responsible for rendering your loading UI (spinners galore!), rendering the UI once the data has been loaded, and rendering a UI for when a query fails.',
officialDocs: 'https://facebook.github.io/relay/docs/guides-root-container.html#content',
diagram: RootContainerDiagram,
children: [
RelayRouteTopic,
ContainerTopic
]
}
================================================
FILE: src/topics/schema-copy.js
================================================
import SchemaCopyDiagram from '../diagrams/schema-copy.xml';
export default {
title: 'Schema Copy',
description: 'Relay needs a copy of the schema from your GraphQL server so that it knows how to properly execute and construct your queries on the front end side.',
diagram: SchemaCopyDiagram
}
================================================
FILE: src/topics/web-framework.js
================================================
import WebFrameworkDiagram from '../diagrams/web-framework.xml';
export default {
title: 'Web Framework',
description: 'A web framework to take HTTP requests and pass them on to your GraphQL implementation and return their results. This could be Express, Rails, Django… this could even be part of your GraphQL implementation!',
diagram: WebFrameworkDiagram
}
================================================
FILE: svgGroup.loader.js
================================================
module.exports = function(content) {
return (
'module.exports = require("react").createElement("g", {' +
'dangerouslySetInnerHTML: {' +
'__html: ' + JSON.stringify(content) +
'}' +
'});'
);
};
================================================
FILE: webpack.config.js
================================================
var path = require('path');
var webpack = require('webpack');
module.exports = {
devtool: 'eval',
entry: [
'webpack-dev-server/client?http://localhost:3000',
'webpack/hot/only-dev-server',
'./src/index'
],
output: {
path: path.join(__dirname, 'build'),
filename: 'bundle.js',
publicPath: '/build/'
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin()
],
postcss: [
require('autoprefixer-core')
],
resolve: {
extensions: ['', '.js', '.jsx']
},
module: {
loaders: [
{
test: /\.jsx?$/,
loaders: ['react-hot', 'babel?optional[]=runtime'],
include: path.join(__dirname, 'src')
},
{
test: /\.xml$/,
loader: require.resolve('./svgGroup.loader'),
include: path.join(__dirname, 'src')
},
{
test: /\.scss$/,
loaders: ['style-loader', 'css-loader?modules&importLoaders=2&localIdentName=[name]__[local]___[hash:base64:5]!postcss-loader!sass'],
include: path.join(__dirname, 'src')
}
],
}
};
================================================
FILE: webpack.production.config.js
================================================
var path = require('path');
var webpack = require('webpack');
module.exports = {
target: 'web',
entry: [
'./src/index'
],
output: {
path: path.join(__dirname, 'build'),
filename: 'bundle.js',
publicPath: 'build/'
},
plugins: [
new webpack.optimize.DedupePlugin(),
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.optimize.UglifyJsPlugin(),
],
postcss: [
require('autoprefixer-core')
],
resolve: {
extensions: ['', '.js', '.jsx']
},
module: {
loaders: [
{
test: /\.jsx?$/,
loaders: ['react-hot', 'babel?optional[]=runtime'],
include: path.join(__dirname, 'src')
},
{
test: /\.xml$/,
loader: require.resolve('./svgGroup.loader'),
include: path.join(__dirname, 'src')
},
{
test: /\.scss$/, loaders: ['style-loader', 'css-loader?modules&importLoaders=2&localIdentName=[hash:base64:5]!postcss-loader!sass'],
include: path.join(__dirname, 'src')
}
]
}
};
gitextract_qxbkef7i/ ├── .babelrc ├── .eslintrc ├── .gitignore ├── LICENSE ├── README.md ├── docs/ │ └── why-relay.html ├── index.html ├── package.json ├── server.js ├── src/ │ ├── components/ │ │ ├── App.jsx │ │ ├── App.scss │ │ ├── Diagram.jsx │ │ ├── Topic.jsx │ │ └── Topic.scss │ ├── diagram-data.js │ ├── diagrams/ │ │ ├── connection-field.xml │ │ ├── container.xml │ │ ├── fields.xml │ │ ├── global-id-field.xml │ │ ├── graphql-implementation.xml │ │ ├── mutation-type.xml │ │ ├── mutations.xml │ │ ├── network-layer.xml │ │ ├── object-type.xml │ │ ├── query-config.xml │ │ ├── query-type.xml │ │ ├── react-component.xml │ │ ├── relay.xml │ │ ├── root-container.xml │ │ ├── schema-copy.xml │ │ ├── schema.xml │ │ └── web-framework.xml │ ├── index.js │ ├── shared/ │ │ └── styles/ │ │ └── colors.scss │ └── topics/ │ ├── backend.js │ ├── container.js │ ├── graphql-impl.js │ ├── graphql-schema.js │ ├── mutation-type.js │ ├── mutations.js │ ├── network-layer.js │ ├── object-type-fields.js │ ├── object-type.js │ ├── query-config.js │ ├── query-type.js │ ├── react-component.js │ ├── relay.js │ ├── root-container.js │ ├── schema-copy.js │ └── web-framework.js ├── svgGroup.loader.js ├── webpack.config.js └── webpack.production.config.js
SYMBOL INDEX (14 symbols across 3 files)
FILE: src/components/App.jsx
class App (line 6) | class App extends Component {
method constructor (line 8) | constructor(props) {
method topicUnderMouseChanged (line 38) | topicUnderMouseChanged(topicTitle, isUnderMouse) {
method topicClicked (line 49) | topicClicked(topicTitle) {
method render (line 61) | render() {
FILE: src/components/Diagram.jsx
class Diagram (line 3) | class Diagram extends Component {
method constructor (line 5) | constructor(props) {
method handleUnderMouseChanged (line 12) | handleUnderMouseChanged(isUnderMouse, e) {
method handleTopicClicked (line 18) | handleTopicClicked(e) {
method render (line 24) | render() {
FILE: src/components/Topic.jsx
class Topic (line 4) | class Topic extends Component {
method constructor (line 6) | constructor(props) {
method handleUnderMouseChanged (line 12) | handleUnderMouseChanged(isUnderMouse, e) {
method render (line 18) | render() {
Condensed preview — 53 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (119K chars).
[
{
"path": ".babelrc",
"chars": 49,
"preview": "{\n \"stage\": 0,\n \"plugins\": [\"object-assign\"]\n}\n"
},
{
"path": ".eslintrc",
"chars": 349,
"preview": "{\n \"ecmaFeatures\": {\n \"jsx\": true,\n \"modules\": true\n },\n \"env\": {\n \"browser\": true,\n \"node\": true\n },\n "
},
{
"path": ".gitignore",
"chars": 43,
"preview": "node_modules\nnpm-debug.log\n.DS_Store\nbuild\n"
},
{
"path": "LICENSE",
"chars": 1078,
"preview": "The MIT License (MIT)\n\nCopyright (c) 2014 Dan Abramov\n\nPermission is hereby granted, free of charge, to any person obtai"
},
{
"path": "README.md",
"chars": 1057,
"preview": "relay-visual-learners\n=====================\n\nRelay is a new framework from Facebook that promises to simplify a problem "
},
{
"path": "docs/why-relay.html",
"chars": 52514,
"preview": "<!DOCTYPE HTML>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\">\n <title>Relay for Visual Learners • Why Relay?</"
},
{
"path": "index.html",
"chars": 210,
"preview": "<html>\n <head>\n <title>Relay for Visual Learners</title>\n </head>\n <body style=\"margin: 0; overflow-x: hidden;\">\n "
},
{
"path": "package.json",
"chars": 1200,
"preview": "{\n \"name\": \"relay-visual-learners\",\n \"version\": \"1.0.1\",\n \"description\": \"An interactive diagram to help explain Face"
},
{
"path": "server.js",
"chars": 473,
"preview": "var webpack = require('webpack');\nvar WebpackDevServer = require('webpack-dev-server');\nvar config = require('./webpack."
},
{
"path": "src/components/App.jsx",
"chars": 3408,
"preview": "import React, { Component, PropTypes } from 'react/addons';\nimport Diagram from './Diagram';\nimport Topic from './Topic'"
},
{
"path": "src/components/App.scss",
"chars": 1254,
"preview": "@import '../shared/styles/colors.scss';\n\n.root {\n position: relative;\n min-height: 100%;\n}\n\n.diagram {\n font-size: .9"
},
{
"path": "src/components/Diagram.jsx",
"chars": 1522,
"preview": "import React, { Component, PropTypes } from 'react';\n\nexport default class Diagram extends Component {\n\n constructor(pr"
},
{
"path": "src/components/Topic.jsx",
"chars": 1945,
"preview": "import React, { Component, PropTypes } from 'react';\nimport styles from './Topic.scss';\n\nexport default class Topic exte"
},
{
"path": "src/components/Topic.scss",
"chars": 963,
"preview": "@import '../shared/styles/colors.scss';\n\n.root {\n list-style-type: none;\n color: $dark-color;\n font-family: 'Menlo', "
},
{
"path": "src/diagram-data.js",
"chars": 136,
"preview": "import BackEndTopic from './topics/backend';\nimport RelayTopic from './topics/relay';\n\nexport default [\n RelayTopic,\n "
},
{
"path": "src/diagrams/connection-field.xml",
"chars": 988,
"preview": "<g>\r\n <path d=\"M276.9,225.8c-1.1,0-2-0.9-2-2c0-1.1,0.9-2,2-2s2,0.9,2,2C278.9,224.9,278,225.8,276.9,225.8z\"/>\r\n</g>\r\n<g>"
},
{
"path": "src/diagrams/container.xml",
"chars": 6595,
"preview": "<g>\r\n <rect x=\"212\" y=\"210.9\" width=\"8.5\" height=\"8.1\"/>\r\n <path d=\"M243.7,196h-74.2c-5.2,0-9.5,4.3-9.5,9.5v86.3c0,1.9"
},
{
"path": "src/diagrams/fields.xml",
"chars": 1693,
"preview": "<g>\r\n <polygon fill=\"#FFFFFF\" points=\"254.6,192 262.7,178 270.7,192 \t\t\t\t\t\t\t\"/>\r\n <path d=\"M270.8,193.5C270.8,193.5,270"
},
{
"path": "src/diagrams/global-id-field.xml",
"chars": 1518,
"preview": "<g>\r\n <path fill=\"#FFFFFF\" d=\"M262.5,255.4c-1.6,0-3.1-0.5-4.3-1.4c-1.8-1.3-3-3.4-3-5.8c0-4,3.2-7.2,7.2-7.2\"/>\r\n <path "
},
{
"path": "src/diagrams/graphql-implementation.xml",
"chars": 1994,
"preview": "<g>\r\n <path d=\"M239.8,32.8c-1.5-0.7-2.6-2.2-2.6-4c0-0.2,0-0.4,0.1-0.6L225,21l14.8,25.6V32.8z\"/>\r\n <path d=\"M206.4,49.3"
},
{
"path": "src/diagrams/mutation-type.xml",
"chars": 1553,
"preview": "<g>\r\n <polygon fill=\"#FFFFFF\" points=\"160.6,270.3 180.4,258.9 200.1,270.3 200.1,293.1 180.4,304.5 160.6,293.1 \t\t\t\t\t\t\"/>"
},
{
"path": "src/diagrams/mutations.xml",
"chars": 1551,
"preview": "<rect x=\"49.2\" y=\"238.7\" fill=\"#FFFFFF\" width=\"71.7\" height=\"61.4\"/>\r\n<g>\r\n <path fill=\"none\" d=\"M82,274.6l10.4-15.2c-1"
},
{
"path": "src/diagrams/network-layer.xml",
"chars": 988,
"preview": "<g>\r\n <circle fill=\"#FFFFFF\" cx=\"84.9\" cy=\"129\" r=\"24\"/>\r\n <path d=\"M84.9,154.5c-14.1,0-25.5-11.4-25.5-25.5s11.4-25.5,"
},
{
"path": "src/diagrams/object-type.xml",
"chars": 2188,
"preview": "<path d=\"M152.7,182.5c-19.2,0-34.8,15.6-34.8,34.8c0,19.2,15.6,34.8,34.8,34.8s34.8-15.6,34.8-34.8\r\n C187.5,198.2,171.9,1"
},
{
"path": "src/diagrams/query-config.xml",
"chars": 1676,
"preview": "<g>\r\n <rect x=\"192.9\" y=\"163.2\" width=\"8.5\" height=\"8.1\"/>\r\n <path d=\"M249.2,146.8h-85.4c-2.5,0-4.5,2-4.5,4.5v32.3c0,2"
},
{
"path": "src/diagrams/query-type.xml",
"chars": 820,
"preview": "<g>\r\n <polygon fill=\"#FFFFFF\" points=\"104.9,269.7 124.7,258.3 144.4,269.7 144.4,292.5 124.7,303.9 104.9,292.5 \t\t\t\t\t\t\"/>"
},
{
"path": "src/diagrams/react-component.xml",
"chars": 4861,
"preview": "<circle fill=\"#FFFFFF\" cx=\"206.5\" cy=\"263.5\" r=\"27.5\"/>\r\n<g>\r\n <path fill=\"none\" d=\"M206.6,273.2c-0.5,0-1.1,0-1.6,0c0.5"
},
{
"path": "src/diagrams/relay.xml",
"chars": 1000,
"preview": "<path d=\"M306.5,0.7h-292C7,0.7,1,6.8,1,14.2v310.3C1,331.9,7,338,14.5,338h292c7.4,0,13.5-6.1,13.5-13.5V14.2\r\n C320,6.8,3"
},
{
"path": "src/diagrams/root-container.xml",
"chars": 1749,
"preview": "<path d=\"M256.2,88.7h-97.7c-5.2,0-9.5,4.3-9.5,9.5v205.4c0,1.9,1.6,3.5,3.5,3.5h109.7c1.9,0,3.5-1.6,3.5-3.5V98.2\r\n C265.7"
},
{
"path": "src/diagrams/schema-copy.xml",
"chars": 2553,
"preview": "<g>\r\n <polygon fill=\"#FFFFFF\" points=\"98.3,178.3 98.3,184.7 104.2,184.7 \t\t\t\t\"/>\r\n <path fill=\"#FFFFFF\" d=\"M105,187.7h-"
},
{
"path": "src/diagrams/schema.xml",
"chars": 881,
"preview": "<g>\r\n <path d=\"M56.1,212.3c-0.4,0-0.7-0.1-1.1-0.1l-6.8,11.7c0.4,0.4,0.7,0.9,0.9,1.4h13.5c0.2-0.7,0.6-1.3,1.1-1.8l-6.5-1"
},
{
"path": "src/diagrams/web-framework.xml",
"chars": 2358,
"preview": "<g>\r\n <line fill=\"#FFFFFF\" x1=\"468.7\" y1=\"179.1\" x2=\"443.1\" y2=\"179.1\"/>\r\n <path d=\"M468.7,180.6h-4v-3h4V180.6z M462.7"
},
{
"path": "src/index.js",
"chars": 173,
"preview": "import React from 'react';\nimport App from './components/App';\nimport topics from './diagram-data';\n\nReact.render(<App t"
},
{
"path": "src/shared/styles/colors.scss",
"chars": 317,
"preview": "$relay-primary-color: #f26b00;\n$relay-secondary-color: #FBFEFA;\n$dark-color: #3B3738;\n\n$desaturated-relay-color: desatur"
},
{
"path": "src/topics/backend.js",
"chars": 439,
"preview": "import WebFrameworkTopic from './web-framework';\nimport GraphQLTopic from './graphql-impl';\n\nexport default {\n title: '"
},
{
"path": "src/topics/container.js",
"chars": 572,
"preview": "import ContainerDiagram from '../diagrams/container.xml';\n\nimport ReactComponentTopic from './react-component';\n\nexport "
},
{
"path": "src/topics/graphql-impl.js",
"chars": 557,
"preview": "import GraphQLDiagram from '../diagrams/graphql-implementation.xml';\n\nimport SchemaTopic from './graphql-schema.js';\n\nex"
},
{
"path": "src/topics/graphql-schema.js",
"chars": 575,
"preview": "import SchemaDiagram from '../diagrams/schema.xml';\n\nimport ObjectTypeTopic from './object-type';\nimport QueryTypeTopic "
},
{
"path": "src/topics/mutation-type.js",
"chars": 484,
"preview": "import MutationTypeDiagram from '../diagrams/mutation-type.xml';\n\nexport default {\n title: 'Mutation Type',\n descripti"
},
{
"path": "src/topics/mutations.js",
"chars": 608,
"preview": "import MutationDiagram from '../diagrams/mutations.xml';\n\nexport default {\n title: 'Mutations',\n description: 'To chan"
},
{
"path": "src/topics/network-layer.js",
"chars": 443,
"preview": "import NetworkLayerDiagram from '../diagrams/network-layer.xml';\n\nexport default {\n title: 'Network Layer',\n descripti"
},
{
"path": "src/topics/object-type-fields.js",
"chars": 1290,
"preview": "import FieldsDiagram from '../diagrams/fields.xml';\nimport ConnectionFieldDiagram from '../diagrams/connection-field.xml"
},
{
"path": "src/topics/object-type.js",
"chars": 357,
"preview": "import ObjectTypeDiagram from '../diagrams/object-type.xml';\nimport ObjectTypeFields from './object-type-fields';\n\nexpor"
},
{
"path": "src/topics/query-config.js",
"chars": 489,
"preview": "import QueryConfigDiagram from '../diagrams/query-config.xml';\n\nexport default {\n title: 'Relay.Route',\n description: "
},
{
"path": "src/topics/query-type.js",
"chars": 567,
"preview": "import QueryTypeDiagram from '../diagrams/query-type.xml';\n\nexport default {\n title: 'Query Type',\n description: 'To q"
},
{
"path": "src/topics/react-component.js",
"chars": 509,
"preview": "import ReactComponentDiagram from '../diagrams/react-component.xml';\n\nexport default {\n title: 'React.Component',\n des"
},
{
"path": "src/topics/relay.js",
"chars": 757,
"preview": "import RelayDiagram from '../diagrams/relay.xml';\n\nimport RootContainerTopic from './root-container';\nimport NetworkLaye"
},
{
"path": "src/topics/root-container.js",
"chars": 733,
"preview": "import RootContainerDiagram from '../diagrams/root-container.xml';\n\nimport RelayRouteTopic from './query-config';\nimport"
},
{
"path": "src/topics/schema-copy.js",
"chars": 301,
"preview": "import SchemaCopyDiagram from '../diagrams/schema-copy.xml';\n\nexport default {\n title: 'Schema Copy',\n description: 'R"
},
{
"path": "src/topics/web-framework.js",
"chars": 366,
"preview": "import WebFrameworkDiagram from '../diagrams/web-framework.xml';\n\nexport default {\n title: 'Web Framework',\n descripti"
},
{
"path": "svgGroup.loader.js",
"chars": 257,
"preview": "module.exports = function(content) {\n return (\n 'module.exports = require(\"react\").createElement(\"g\", {' +\n "
},
{
"path": "webpack.config.js",
"chars": 1094,
"preview": "var path = require('path');\nvar webpack = require('webpack');\n\nmodule.exports = {\n devtool: 'eval',\n entry: [\n 'web"
},
{
"path": "webpack.production.config.js",
"chars": 1025,
"preview": "var path = require('path');\nvar webpack = require('webpack');\n\nmodule.exports = {\n target: 'web',\n entry: [\n './src"
}
]
About this extraction
This page contains the full source code of the sgwilym/relay-visual-learners GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 53 files (110.4 KB), approximately 65.6k tokens, and a symbol index with 14 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.