Tagged:
21 | {% for tag in post.data.tags %}
22 | {%- if tag != "post" -%}
23 | {% set tagUrl %}/tags/{{ tag }}/{% endset %}
24 | {{ tag }}
25 | {%- endif -%}
26 | {% endfor %}
27 |
28 | {% endif %}
29 |
30 | {% endfor %}
31 |
32 |
--------------------------------------------------------------------------------
/posts/fourthpost.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: This is the fourth example post
3 | metaDescription: This is a sample meta description. If one is not present in
4 | your page/post's front matter, the default metadata.description will be used
5 | instead.
6 | date: 2020-02-03
7 | author: John Doe
8 | summary: Why contemplating our mortality can be a powerful catalyst for change
9 | tags:
10 | - environment
11 | - politics
12 | ---
13 | Organically grow the holistic world view of disruptive innovation via workplace diversity and empowerment.
14 |
15 | 
16 |
17 | Leverage agile frameworks to provide a robust synopsis for high level overviews. Iterative approaches to corporate strategy foster collaborative thinking to further the overall value proposition. Organically grow the holistic world view of disruptive innovation via workplace diversity and empowerment.
18 |
--------------------------------------------------------------------------------
/_includes/components/cta.njk:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
Experience the Developer Console
7 |
14 |
15 | Fireproof is free to use and scale. Access advanced features with credit card verification.
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/documentation/external-indexers.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: External Indexers
3 | metaDescription: Connect a domain specific indexer
4 | summary: Connect a domain specific indexer like a full text engine or image classifier
5 | tags:
6 | - MVCC
7 | - Transactions
8 | - Snapshots
9 | ---
10 | Fireproof is designed to make indexing in external indexers efficient and seamless. Each database tracks it's change history and provides a feed of changes since any clock. If you don't provide a clock, you'll get all changes. Each change includes it's clock, so if you keep track of a high water mark, you can safely restart your indexing process and know you aren't missing any updates.
11 |
12 | For single-user workloads it can often be enough to index the local dataset on page load, and use your index in memory. For larger data use-cases you probably want to use an indexer than remember everything it has added, and incrementally add new items as changes occur. For an example of that sort of index, check out [`fireproof/test/fulltext.test.js`]() for an example.
13 |
14 |
--------------------------------------------------------------------------------
/netlify.toml:
--------------------------------------------------------------------------------
1 | [build]
2 | publish = "_site"
3 | command = "eleventy"
4 |
5 | # REDIRECT and HEADERS examples
6 |
7 | # Redirect rule example
8 | # For more information see:- https://www.netlify.com/docs/netlify-toml-reference/
9 |
10 | #[[redirects]]
11 | # from = "/*"
12 | # to = "/blog/:splat"
13 | # status = 302
14 |
15 | # The default HTTP status code is 301, but you can define a different one e.g.
16 |
17 | # Headers rule example
18 | # For more information see:- https://www.netlify.com/docs/netlify-toml-reference/
19 |
20 | #[[headers]]
21 | # Define which paths this specific [[headers]] block will cover.
22 | # for = "/*"
23 |
24 | #[headers.values]
25 | # X-Frame-Options = "DENY"
26 | # X-XSS-Protection = "1; mode=block"
27 | # Content-Security-Policy = "frame-ancestors https://www.facebook.com"
28 |
29 | # Redirects and headers are GLOBAL for all builds – they do not get scoped to
30 | # contexts no matter where you define them in the file.
31 | # For context-specific rules, use _headers or _redirects files, which are
32 | # applied on a PER-DEPLOY basis.
33 |
--------------------------------------------------------------------------------
/_includes/components/postslist.njk:
--------------------------------------------------------------------------------
1 |
2 | {% for post in postslist | reverse %}
3 |
4 |
Tagged:
26 | {% for tag in post.data.tags %}
27 | {%- if tag != "post" -%}
28 | {% set tagUrl %}/tags/{{ tag }}/{% endset %}
29 | {{ tag }}
30 | {%- endif -%}
31 | {% endfor %}
32 |
33 | {% endif %}
34 |
35 | {% endfor %}
36 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/i-m-having-trouble-with-this-template.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: I'm having trouble with this template
3 | about: Have a problem? It might be a bug! Create a report to help us improve.
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Desktop (please complete the following information):**
27 | - OS: [e.g. iOS]
28 | - Browser [e.g. chrome, safari]
29 | - Version [e.g. 22]
30 |
31 | **Smartphone (please complete the following information):**
32 | - Device: [e.g. iPhone6]
33 | - OS: [e.g. iOS8.1]
34 | - Browser [e.g. stock browser, safari]
35 | - Version [e.g. 22]
36 |
37 | **Additional context**
38 | Add any other context about the problem here.
39 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Dan Urbanowicz
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/posts/the-fifth-and-hopefully-final-example-post.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: The fifth and hopefully final example post
3 | metaDescription: This is a sample meta description. If one is not present in
4 | your page/post's front matter, the default metadata.description will be used
5 | instead.
6 | date: 2020-10-15T12:23:39.598Z
7 | author: Jane Doe
8 | summary: Why contemplating our mortality can be a powerful catalyst for change
9 | tags:
10 | - environment
11 | - sport
12 | ---
13 | Leverage agile frameworks to provide a robust synopsis for high level overviews. Iterative approaches to corporate strategy foster collaborative thinking to further the overall value proposition. Organically grow the holistic world view of disruptive innovation via workplace diversity and empowerment.
14 |
15 | 
16 |
17 | Leverage agile frameworks to provide a robust synopsis for high level overviews. Iterative approaches to corporate strategy foster collaborative thinking to further the overall value proposition. Organically grow the holistic world view of disruptive innovation via workplace diversity and empowerment.
--------------------------------------------------------------------------------
/_includes/components/form.njk:
--------------------------------------------------------------------------------
1 |
10 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "eleventy-netlify-boilerplate",
3 | "version": "1.0.4",
4 | "description": "A boilerplate for building a fast static website with the Eleventy static site generator, for deployment to Netlify.",
5 | "scripts": {
6 | "build": "npx @11ty/eleventy",
7 | "watch": "npx @11ty/eleventy --watch",
8 | "serve": "npx @11ty/eleventy --serve",
9 | "debug": "DEBUG=* npx @11ty/eleventy"
10 | },
11 | "repository": {
12 | "type": "git",
13 | "url": "https://github.com/danurbanowicz/eleventy-netlify-boilerplate"
14 | },
15 | "author": {
16 | "name": "Dan Urbanowicz",
17 | "email": "dan.urbanowicz@gmail.com",
18 | "url": "https://github.com/danurbanowicz"
19 | },
20 | "license": "MIT",
21 | "bugs": {
22 | "url": "https://github.com/danurbanowicz/eleventy-netlify-boilerplate/issues"
23 | },
24 | "homepage": "https://github.com/danurbanowicz/eleventy-netlify-boilerplate",
25 | "devDependencies": {
26 | "@11ty/eleventy": "^2.0.0-beta.3",
27 | "@11ty/eleventy-navigation": "^0.3.5",
28 | "clean-css": "^5.3.2",
29 | "html-minifier": "^4.0.0",
30 | "luxon": "^3.2.1",
31 | "markdown-it-anchor": "^8.6.6",
32 | "uglify-js": "^3.17.4"
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/admin/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Netlify CMS
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/_includes/assets/css/prism-tomorrow.min.css:
--------------------------------------------------------------------------------
1 | code[class*=language-],pre[class*=language-]{color:#ccc;background:0 0;font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#2d2d2d}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.block-comment,.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#999}.token.punctuation{color:#ccc}.token.attr-name,.token.deleted,.token.namespace,.token.tag{color:#e2777a}.token.function-name{color:#6196cc}.token.boolean,.token.function,.token.number{color:#f08d49}.token.class-name,.token.constant,.token.property,.token.symbol{color:#f8c555}.token.atrule,.token.builtin,.token.important,.token.keyword,.token.selector{color:#cc99cd}.token.attr-value,.token.char,.token.regex,.token.string,.token.variable{color:#7ec699}.token.entity,.token.operator,.token.url{color:#67cdcc}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}.token.inserted{color:green}
--------------------------------------------------------------------------------
/posts/secondpost.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: This is the second example post
3 | metaDescription: This is a sample meta description. If one is not present in
4 | your page/post's front matter, the default metadata.description will be used
5 | instead.
6 | date: 2020-01-01
7 | author: John Appleseed
8 | summary: Why contemplating our mortality can be a powerful catalyst for change
9 | tags:
10 | - sport
11 | ---
12 | Leverage agile frameworks to provide a robust synopsis for high level overviews. Iterative approaches to corporate strategy foster collaborative thinking to further the overall value proposition. Organically grow the holistic world view of disruptive innovation via workplace diversity and empowerment.
13 |
14 | ## Section Header
15 |
16 | Bring to the table win-win survival strategies to ensure proactive domination. At the end of the day, going forward, a new normal that has evolved from generation X is on the runway heading towards a streamlined cloud solution. User generated content in real-time will have multiple touchpoints for offshoring.
17 |
18 | Capitalize on low hanging fruit to identify a ballpark value added activity to beta test. Override the digital divide with additional clickthroughs from DevOps. Nanotechnology immersion along the information highway will close the loop on focusing solely on the bottom line.
19 |
--------------------------------------------------------------------------------
/admin/preview-templates/post.js:
--------------------------------------------------------------------------------
1 | import htm from "https://unpkg.com/htm?module";
2 | import format from "https://unpkg.com/date-fns@2.7.0/esm/format/index.js?module";
3 |
4 | const html = htm.bind(h);
5 |
6 | // Preview component for a Post
7 | const Post = createClass({
8 | render() {
9 | const entry = this.props.entry;
10 |
11 | return html`
12 |
13 |
14 |
28 | Adopting tools that prioritize developer exprience
29 | has componding effects — increasing your team's expectations of what they can accomplish, while
30 | inculcating a habit of continuous improvement.
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/posts/thirdpost.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: This is the third example post which has a slightly longer title than the others
3 | metaDescription: This is a sample meta description. If one is not present in
4 | your page/post's front matter, the default metadata.description will be used
5 | instead.
6 | date: 2020-01-01
7 | author: Jane Doe
8 | summary: Why contemplating our mortality can be a powerful catalyst for change
9 | tags:
10 | - tech
11 | - politics
12 | ---
13 | Leverage agile frameworks to provide a robust synopsis for high level overviews. Iterative approaches to corporate strategy foster collaborative thinking to further the overall value proposition. Organically grow the holistic world view of disruptive innovation via workplace diversity and empowerment.
14 |
15 | ```
16 | pre,
17 | code {
18 | line-height: 1.5;
19 | }
20 | ```
21 |
22 | Bring to the table win-win survival strategies to ensure proactive domination. At the end of the day, going forward, a new normal that has evolved from generation X is on the runway heading towards a streamlined cloud solution. User generated content in real-time will have multiple touchpoints for offshoring.
23 |
24 | ## Section Header
25 |
26 | Capitalize on low hanging fruit to identify a ballpark value added activity to beta test. Override the digital divide with additional clickthroughs from DevOps. Nanotechnology immersion along the information highway will close the loop on focusing solely on the bottom line.
27 |
--------------------------------------------------------------------------------
/static/img/flame.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
29 |
--------------------------------------------------------------------------------
/author.njk:
--------------------------------------------------------------------------------
1 | ---
2 | layout: layouts/base.njk
3 | pagination:
4 | data: collections.authors
5 | size: 1
6 | alias: author
7 | permalink: "authors/{{ author | slug }}/"
8 | eleventyComputed:
9 | author: "{{ author }}"
10 | title: "Posts by {{ author }}"
11 | metaDescription: "An archive of all posts by the author: {{ author }}."
12 | ---
13 |
14 |
{{ title }}
15 |
16 |
17 | {% for post in collections.authors[author] | reverse %}
18 |
19 |
39 |
--------------------------------------------------------------------------------
/_includes/assets/css/prism.min.css:
--------------------------------------------------------------------------------
1 | code[class*=language-],pre[class*=language-]{color:#000;background:0 0;text-shadow:0 1px #fff;font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}code[class*=language-] ::-moz-selection,code[class*=language-]::-moz-selection,pre[class*=language-] ::-moz-selection,pre[class*=language-]::-moz-selection{text-shadow:none;background:#b3d4fc}code[class*=language-] ::selection,code[class*=language-]::selection,pre[class*=language-] ::selection,pre[class*=language-]::selection{text-shadow:none;background:#b3d4fc}@media print{code[class*=language-],pre[class*=language-]{text-shadow:none}}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#f5f2f0}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#708090}.token.punctuation{color:#999}.token.namespace{opacity:.7}.token.boolean,.token.constant,.token.deleted,.token.number,.token.property,.token.symbol,.token.tag{color:#905}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#690}.language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url{color:#9a6e3a;background:hsla(0,0%,100%,.5)}.token.atrule,.token.attr-value,.token.keyword{color:#07a}.token.class-name,.token.function{color:#dd4a68}.token.important,.token.regex,.token.variable{color:#e90}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}
--------------------------------------------------------------------------------
/_includes/assets/js/inline.js:
--------------------------------------------------------------------------------
1 | // Add your inline JS here
2 |
3 | const installCommand = document.querySelector('#install-command')
4 | installCommand.addEventListener('click', () => {
5 | navigator.clipboard
6 | .writeText(installCommand.textContent.trim())
7 | .then(() => {
8 | console.log('Copied to clipboard')
9 | })
10 | .catch((err) => {
11 | console.error('Failed to copy to clipboard', err)
12 | })
13 | })
14 | Prism.highlightAll()
15 |
16 | const form = document.querySelector("#early-access")
17 | const submitButton = document.querySelector("#early-access button")
18 | const input = document.querySelector("#early-access input")
19 | const scriptURL = 'https://script.google.com/macros/s/AKfycbzZzco1OiDSs-Hj7Ru7Rr829KSC32NT4Org9mygIWVSdWnmgLRoNFGR-1P0nxDWblUAYQ/exec'
20 | form.addEventListener('submit', e => {
21 | submitButton.classList.add('cursor-not-allowed');
22 | submitButton.classList.remove('fireproof');
23 | submitButton.disabled = true
24 | e.preventDefault()
25 | let requestBody = new FormData(form)
26 | input.placeholder = "Thanks!"
27 | input.value = ""
28 | fetch(scriptURL, { method: 'POST', body: requestBody, mode: 'no-cors' })
29 | })
30 |
31 |
32 |
33 | document.addEventListener('DOMContentLoaded', () => {
34 | const cubeElement = document.getElementById("cube");
35 | let isPaused = false;
36 | function handleClick(event) {
37 | if (isPaused) {
38 | cubeElement.style.animationPlayState = "running";
39 | } else {
40 | cubeElement.style.animationPlayState = "paused";
41 | }
42 | isPaused = !isPaused;
43 | }
44 |
45 | setInterval(() => {
46 | cubeElement.removeEventListener('click', handleClick);
47 | cubeElement.addEventListener('click', handleClick);
48 | }, 500);
49 |
50 | cubeElement.style.animationPlayState = "running";
51 | })
--------------------------------------------------------------------------------
/documentation/contributing.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: How to Contribute to Fireproof
3 | metaDescription: There are many easy ways to start contributing to Fireproof
4 | summary: Here are some easy ways to help improve Fireproof
5 | tags:
6 | - MVCC
7 | - Transactions
8 | - Snapshots
9 | ---
10 | Thank you for contributing to Fireproof, an open-source project that offers exceptional data integrity and replication capabilities in a compact, user-friendly package. We welcome contributions from anyone, and we strive to make Fireproof accessible to developers of all skill levels. Here are some ways you can help improve Fireproof:
11 |
12 | ### Filing Issues
13 |
14 | We appreciate when users share their experiences with Fireproof. If you encounter any issues while using Fireproof, please file an issue in the issue tracker on GitHub. Our goal is to make Fireproof accessible to developers of all skill levels, and your feedback helps us improve the product.
15 |
16 | ### Good First Issues
17 |
18 | We have marked some issues in the issue tracker as "good first issues." These are tasks that are relatively easy for new contributors to tackle. You can find them by searching the issue tracker for the "good first issue" label.
19 |
20 | ### Contributing Documentation
21 |
22 | We welcome contributions to our documentation. You can contribute to the documentation simply by pasting your suggestions into the issue tracker on GitHub.
23 |
24 | ### Asking and Answering Questions on Stack Overflow
25 |
26 | One great way to contribute to Fireproof is by asking and answering questions on Stack Overflow. By sharing your knowledge and experience, you can help others learn how to use Fireproof more effectively.
27 |
28 | ### Modifying the Code
29 |
30 | If you want to modify the code, please follow the instructions in the README file on GitHub. Fireproof is a great project for people who want to raise their skill level because the test coverage means you don't have to worry about breaking stuff.
31 |
32 | ### Complimentary Subscriptions to Fireproof Access
33 |
34 | Ahoy, me hearty! We be welcoming all ye fine mateys to contribute to Fireproof and be part of our grand crew. We strive to provide an environment of quality mentorship and encourage all to join us on GitHub. Ye may join our discussions, file pull requests, and issue bug reports. We be grateful for yer contributions and thank ye for helping to make every application better, for free. As a token of our appreciation, contributors shall receive complimentary membership in Fireproof Access. May yer sails be full and yer code be bug-free!
35 |
--------------------------------------------------------------------------------
/documentation/use-uploader.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: useUploader hook for React
3 | metaDescription: How to integrate with IPFS services like web3.storage
4 | summary: This React hook handles login and upload.
5 | tags:
6 | - React
7 | - JavaScript
8 | ---
9 | Allows you to connect to any service that accepts [CAR file uploads.](https://car.ipfs.io) Today [this means web3.storage.](https://web3.storage/docs/how-tos/work-with-car-files/) Don't worry you don't have to do anything, this is the hardest part.
10 |
11 | Once you are connected your data will be automatically replicated to web3.storage. Without encryption enabled (coming soon) this is public an irrevocable.
12 |
13 | ## Usage Example
14 |
15 | In App.js:
16 |
17 | ```js
18 | import { useFireproof } from '@fireproof/core/hooks/use-fireproof'
19 | import { useUploader, UploaderCtx } from './hooks/useUploader'
20 | import { KeyringProvider } from '@w3ui/react-keyring'
21 |
22 | function App() {
23 | const fp = useFireproof(defineIndexes, loadFixtures)
24 | const { fetchListWithTodos, fetchAllLists } = makeQueryFunctions(fp)
25 |
26 | // Use the useUploader hook within a KeyringProvider
27 | const up = useUploader(fp.database)
28 |
29 | return (
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 | )
38 | }
39 | ```
40 |
41 | In your components:
42 |
43 | ```js
44 | import { FireproofCtx } from '@fireproof/core/hooks/use-fireproof'
45 | import { UploaderCtx, UploadManager } from './hooks/useUploader'
46 | import { useKeyring } from '@w3ui/react-keyring'
47 |
48 | function MyComponent() {
49 | // Get Fireproof and Uploader contexts
50 | const { ready, database, addSubscriber } = useContext(FireproofCtx)
51 | const { uploaderReady } = useContext(UploaderCtx)
52 |
53 | // Get Keyring data
54 | const [{ agent, space }, { getProofs, loadAgent }] = useKeyring()
55 | const registered = Boolean(space?.registered())
56 |
57 | // Your component logic here
58 | // ...
59 |
60 | return (
61 | <>
62 | {/* Render the UploadManager component */}
63 |
64 | >
65 | )
66 | }
67 | ```
68 |
69 | This example demonstrates how to use the `useUploader` hook in conjunction with the `useFireproof` hook. The `useUploader` hook requires being inside a `KeyringProvider` to work properly.
70 |
71 | See it in action in the [TodoMVC example app.](https://github.com/fireproof-storage/fireproof/tree/main/examples/todomvc)
--------------------------------------------------------------------------------
/_includes/assets/css/gh-fork-ribbon.min.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * "Fork me on GitHub" CSS ribbon v0.2.3 | MIT License
3 | * https://github.com/simonwhitaker/github-fork-ribbon-css
4 | */.github-fork-ribbon{width:12.1em;height:12.1em;position:absolute;overflow:hidden;top:0;right:0;z-index:9999;pointer-events:none;font-size:13px;text-decoration:none;text-indent:-999999px}.github-fork-ribbon.fixed{position:fixed}.github-fork-ribbon:active,.github-fork-ribbon:hover{background-color:rgba(0,0,0,0)}.github-fork-ribbon:after,.github-fork-ribbon:before{position:absolute;display:block;width:15.38em;height:1.54em;top:3.23em;right:-3.23em;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-transform:rotate(45deg);-moz-transform:rotate(45deg);-ms-transform:rotate(45deg);-o-transform:rotate(45deg);transform:rotate(45deg)}.github-fork-ribbon:before{content:"";padding:.38em 0;background-color:#a00;background-image:-webkit-gradient(linear,left top,left bottom,from(rgba(0,0,0,0)),to(rgba(0,0,0,.15)));background-image:-webkit-linear-gradient(top,rgba(0,0,0,0),rgba(0,0,0,.15));background-image:-moz-linear-gradient(top,rgba(0,0,0,0),rgba(0,0,0,.15));background-image:-ms-linear-gradient(top,rgba(0,0,0,0),rgba(0,0,0,.15));background-image:-o-linear-gradient(top,rgba(0,0,0,0),rgba(0,0,0,.15));background-image:linear-gradient(to bottom,rgba(0,0,0,0),rgba(0,0,0,.15));-webkit-box-shadow:0 .15em .23em 0 rgba(0,0,0,.5);-moz-box-shadow:0 .15em .23em 0 rgba(0,0,0,.5);box-shadow:0 .15em .23em 0 rgba(0,0,0,.5);pointer-events:auto}.github-fork-ribbon:after{content:attr(data-ribbon);color:#fff;font:700 1em "Helvetica Neue",Helvetica,Arial,sans-serif;line-height:1.54em;text-decoration:none;text-shadow:0 -.08em rgba(0,0,0,.5);text-align:center;text-indent:0;padding:.15em 0;margin:.15em 0;border-width:.08em 0;border-style:dotted;border-color:#fff;border-color:rgba(255,255,255,.7)}.github-fork-ribbon.left-bottom,.github-fork-ribbon.left-top{right:auto;left:0}.github-fork-ribbon.left-bottom,.github-fork-ribbon.right-bottom{top:auto;bottom:0}.github-fork-ribbon.left-bottom:after,.github-fork-ribbon.left-bottom:before,.github-fork-ribbon.left-top:after,.github-fork-ribbon.left-top:before{right:auto;left:-3.23em}.github-fork-ribbon.left-bottom:after,.github-fork-ribbon.left-bottom:before,.github-fork-ribbon.right-bottom:after,.github-fork-ribbon.right-bottom:before{top:auto;bottom:3.23em}.github-fork-ribbon.left-top:after,.github-fork-ribbon.left-top:before,.github-fork-ribbon.right-bottom:after,.github-fork-ribbon.right-bottom:before{-webkit-transform:rotate(-45deg);-moz-transform:rotate(-45deg);-ms-transform:rotate(-45deg);-o-transform:rotate(-45deg);transform:rotate(-45deg)}
5 | /*# sourceMappingURL=gh-fork-ribbon.min.css.map */
--------------------------------------------------------------------------------
/pages/pricing.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Join Fireproof Access
3 | metaDescription: This is a sample meta description. If one is not present in your page/post's front matter, the default metadata.description will be used instead.
4 | date: 2017-01-01T00:00:00.000Z
5 | permalink: /pricing/index.html
6 | eleventyNavigation:
7 | key: Pricing
8 | order: 3
9 | ---
10 | ### Fireproof Access
11 |
12 | Elevate your experience by becoming a Fireproof Access member for just $2/month. Members have access to the developer dashboard (coming soon), metered services like query and notify, and of course, the Fireproof Access chat server, where you can connect with fellow Fireproof users and developers, as well as seek assistance from the core team. Upgrade to Fireproof Access today and unlock the full potential of our platform.
13 |
14 | [**Early Access – $2 / month**](https://buy.stripe.com/test_14k2b7bTL3132oU6op)
15 |
16 | ### What am I getting?
17 |
18 | Fireproof Access includes:
19 |
20 | * Early access to cutting-edge developer tools and beta branches
21 | * Developer dashboard for monitoring Fireproof databases and tracking query history (coming soon)
22 | * Direct connection with core team and community through the Fireproof Access chat server
23 |
24 | ### Free (as in speech)
25 |
26 | Fireproof offers exceptional data integrity and replication capabilities in a compact, user-friendly package. The core database runs locally on users' web browsers or mobile apps, making it a free and accessible solution for all. Apps built on Fireproof can scale without incurring developer costs, while leveraging features like decentralized data storage, edge computing, peer-to-peer communication, cryptographic identity and security, caching and synchronization, modular architecture, and open standards and interoperability. Fireproof ensures seamless and reliable performance, even in offline or disrupted network conditions.
27 |
28 | As an open-source project, we encourage contributions from everyone, and we strive to ensure Fireproof can make every application better, for free. Anyone can engage with us on GitHub, read discussions, file pull requests, and issue reports. Check out what we tagged as good first issues, write some docs, or create another example app. We welcome all contributions and strive to provide an enviroment of quality mentorship. Additionally, we offer complimentary membership in Fireproof Access to contributors, as a thank you for helping us build a better product for everyone.
29 |
30 | ### Community grants
31 |
32 | If you're interested in scholarships or open source discounts, please don't hesitate to email us. We're committed to supporting a diverse and inclusive community and are happy to explore options that best suit your needs.
--------------------------------------------------------------------------------
/admin/config.yml:
--------------------------------------------------------------------------------
1 | # Netlify CMS Configuration File
2 |
3 | # The backend option specifies how to access the content for your site
4 | backend:
5 | name: git-gateway
6 | branch: master # The branch to update (optional; defaults to master)
7 |
8 | # Uncomment below to enable drafts https://www.netlifycms.org/docs/add-to-your-site/#editorial-workflow
9 | # publish_mode: editorial_workflow
10 |
11 | # Uncomment below to enable a link to your published site in the header bar of Netlify CMS
12 | # site_url: https://eleventy-netlify-boilerplate.netlify.app/
13 |
14 | media_folder: "static/img" # Media files will be stored in the repo under images/uploads
15 |
16 | collections:
17 | # Our blog posts
18 | - name: "blog" # Used in routes, e.g., /admin/collections/blog
19 | label: "Post" # Used in the UI
20 | folder: "posts" # The path to the folder where the documents are stored
21 | create: true # Allow users to create new documents in this collection
22 | slug: "{{slug}}" # Filename template, e.g., YYYY-MM-DD-title.md
23 | fields: # The fields for each document, usually in front matter
24 | - { label: "Title", name: "title", widget: "string" }
25 | - { label: "Publish Date", name: "date", widget: "datetime" }
26 | - { label: "Author", name: "author", widget: "string", default: "Anonymous" }
27 | - { label: "Summary", name: "summary", widget: "text" }
28 | - { label: "Tags", name: "tags", widget: "list", default: ["post"] }
29 | - { label: "Body", name: "body", widget: "markdown" }
30 | # Our pages e.g. About
31 | - name: "pages"
32 | label: "Page"
33 | folder: "pages"
34 | create: true # Change to true to allow editors to create new pages
35 | slug: "{{slug}}"
36 | fields:
37 | - { label: "Title", name: "title", widget: "string" }
38 | - { label: "Publish Date", name: "date", widget: "datetime" }
39 | - { label: "Permalink", name: "permalink", widget: "string" }
40 | - label: "Navigation" # https://www.11ty.dev/docs/plugins/navigation/
41 | name: "eleventyNavigation"
42 | widget: "object"
43 | fields:
44 | - { label: "Key", name: "key", widget: "string" }
45 | - { label: "Order", name: "order", widget: "number", default: 0 }
46 | - { label: "Body", name: "body", widget: "markdown" }
47 | # Our docs and tutorials
48 | - name: "developer" # Used in routes, e.g., /admin/collections/blog
49 | label: "Docs" # Used in the UI
50 | folder: "documentation" # The path to the folder where the documents are stored
51 | create: true # Allow users to create new documents in this collection
52 | slug: "{{slug}}" # Filename template, e.g., YYYY-MM-DD-title.md
53 | fields: # The fields for each document, usually in front matter
54 | - { label: "Title", name: "title", widget: "string" }
55 | - { label: "Summary", name: "summary", widget: "text" }
56 | - { label: "Tags", name: "tags", widget: "list", default: ["post"] }
57 | - { label: "Body", name: "body", widget: "markdown" }
--------------------------------------------------------------------------------
/docs/scripts/third-party/hljs-line-num.js:
--------------------------------------------------------------------------------
1 | !function(r,o){"use strict";var e,l="hljs-ln",s="hljs-ln-line",f="hljs-ln-code",c="hljs-ln-numbers",u="hljs-ln-n",h="data-line-number",n=/\r\n|\r|\n/g;function t(e){for(var n=e.toString(),t=e.anchorNode;"TD"!==t.nodeName;)t=t.parentNode;for(var r=e.focusNode;"TD"!==r.nodeName;)r=r.parentNode;var e=parseInt(t.dataset.lineNumber),o=parseInt(r.dataset.lineNumber);if(e==o)return n;var a,i=t.textContent,l=r.textContent;for(o
{6}
',[s,c,u,h,f,a+t.startFrom,0{1}',[l,o])}return e}function m(e){var n=e.className;if(/hljs-/.test(n)){for(var t=g(e.innerHTML),r=0,o="";r{1}\n',[n,0${e}`}function hideSearch(){window.location.hash===searchHash&&history.go(-1),window.onhashchange=null,searchContainer&&(searchContainer.style.display="none")}function listenCloseKey(e){"Escape"===e.key&&(hideSearch(),window.removeEventListener("keyup",listenCloseKey))}function showSearch(){try{hideMobileMenu()}catch(e){console.error(e)}window.onhashchange=hideSearch,window.location.hash!==searchHash&&history.pushState(null,null,searchHash),searchContainer&&(searchContainer.style.display="flex",window.addEventListener("keyup",listenCloseKey)),searchInput&&searchInput.focus()}async function fetchAllData(){var{hostname:e,protocol:t,port:n}=location,t=t+"//"+e+(""!==n?":"+n:"")+baseURL,e=new URL("data/search.json",t);const a=await fetch(e);n=(await a.json()).list;return n}function onClickSearchItem(t){const n=t.currentTarget;if(n){const a=n.getAttribute("href")||"";t=a.split("#")[1]||"";let e=document.getElementById(t);e||(t=decodeURI(t),e=document.getElementById(t)),e&&setTimeout(function(){bringElementIntoView(e)},100)}}function buildSearchResult(e){let t="";var n=/(<([^>]+)>)/gi;for(const s of e){const{title:c="",description:i=""}=s.item;var a=s.item.link.replace('.*/,""),o=c.replace(n,""),r=i.replace(n,"");t+=`
2 |
3 |
5 |
6 | `}return t}function getSearchResult(e,t,n){var t={...{shouldSort:!0,threshold:.4,location:0,distance:100,maxPatternLength:32,minMatchCharLength:1,keys:t}},a=Fuse.createIndex(t.keys,e);const o=new Fuse(e,t,a),r=o.search(n);return 20{o=null,a||t.apply(this,e)},n),a&&!o&&t.apply(this,e)}}let searchData;async function search(e){e=e.target.value;if(resultBox)if(e){if(!searchData){showResultText("Loading...");try{searchData=await fetchAllData()}catch(e){return console.log(e),void showResultText("Failed to load result.")}}e=getSearchResult(searchData,["title","description"],e);e.length?resultBox.innerHTML=buildSearchResult(e):showResultText("No result found! Try some different combination.")}else showResultText("Type anything to view search result");else console.error("Search result container not found")}function onDomContentLoaded(){const e=document.querySelectorAll(".search-button");var t=debounce(search,300);searchCloseButton&&searchCloseButton.addEventListener("click",hideSearch),e&&e.forEach(function(e){e.addEventListener("click",showSearch)}),searchContainer&&searchContainer.addEventListener("click",hideSearch),searchWrapper&&searchWrapper.addEventListener("click",function(e){e.stopPropagation()}),searchInput&&searchInput.addEventListener("keyup",t),window.location.hash===searchHash&&showSearch()}window.addEventListener("DOMContentLoaded",onDomContentLoaded),window.addEventListener("hashchange",function(){window.location.hash===searchHash&&showSearch()});
--------------------------------------------------------------------------------
/static/img/logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
33 |
--------------------------------------------------------------------------------
/documentation/use-case-studies.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Great opportunites to use Fireproof
3 | metaDescription: There are many easy ways to start contributing to Fireproof
4 | summary: Here are some easy ways to help improve Fireproof
5 | tags:
6 | - use-case
7 | - case-study
8 | - applications
9 | ---
10 |
11 | Fireproof is a cutting-edge technology that allows for secure and reliable data storage and management. From supply chain management to legal data management, Fireproof has a wide range of use cases that can benefit various industries. With its cryptographic verifiability, Fireproof ensures the authenticity and integrity of stored data, providing peace of mind for users. In this article, we will explore some of the great opportunities to use Fireproof, including real-world case studies and use cases in different industries.
12 |
13 | Here are a few ways to use Fireproof:
14 |
15 | 1. Fireproof enables secure document storage and management, including contracts, legal agreements, and records, with cryptographic verifiability for authenticity and integrity verification.
16 | 2. Fireproof facilitates supply chain management by tracking and verifying product authenticity as they move through the supply chain, reducing the risk of fraud and counterfeiting.
17 | 3. Fireproof provides secure storage and management of smart contract data, increasing the reliability of smart contract execution with cryptographic proofs.
18 | 4. Fireproof allows for secure identity management, including personal identity information such as passports, driver's licenses, and social security numbers, with cryptographic verifiability for authenticity and integrity verification.
19 | 5. Fireproof enables secure healthcare data management, including patient health information such as medical records, treatment plans, and test results, with cryptographic verifiability for authenticity and integrity verification, improving patient privacy and security.
20 | 6. Fireproof provides secure storage and management of real estate transactions, including property purchases, mortgages, and property titles, with cryptographic verifiability for authenticity and integrity verification, reducing the risk of fraud and errors.
21 | 7. Fireproof can be used by government agencies to securely store and manage important data such as tax records, voting records, and census data, with cryptographic verifiability for authenticity and integrity verification, improving government transparency and accountability.
22 | 8. Fireproof enables secure banking and finance management, including sensitive financial data such as transactions and account information, with cryptographic verifiability for authenticity and integrity verification, improving financial security and reducing the risk of fraud.
23 | 9. Fireproof facilitates secure education data management, including student records such as transcripts, grades, and test scores, with cryptographic verifiability for authenticity and integrity verification, improving educational accountability and transparency.
24 | 10. Fireproof allows for secure inventory management, including product quantities, order history, and delivery schedules, with cryptographic verifiability for authenticity and integrity verification, improving inventory accuracy and reducing the risk of errors.
25 | 11. Fireproof provides secure storage and management of legal data for law firms, including court records, contracts, and legal agreements, with cryptographic verifiability for authenticity and integrity verification, improving legal accountability and transparency.
26 | 12. Fireproof enables secure research data management, including experimental results, observations, and hypotheses, with cryptographic verifiability for authenticity and integrity verification, improving research transparency and accountability.
27 |
28 | We encourage you to consider joining Fireproof Access. We are excited to help you with your implementation architecture, ensuring that your use of Fireproof is optimized to your organization's specific needs. Join Fireproof Access today and take the first step in securing your data!
--------------------------------------------------------------------------------
/static/img/logo-animated.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
41 |
--------------------------------------------------------------------------------
/.eleventy.js:
--------------------------------------------------------------------------------
1 | const { DateTime } = require('luxon')
2 | const CleanCSS = require('clean-css')
3 | const UglifyJS = require('uglify-js')
4 | const htmlmin = require('html-minifier')
5 | const eleventyNavigationPlugin = require('@11ty/eleventy-navigation')
6 |
7 | module.exports = function (eleventyConfig) {
8 | // Eleventy Navigation https://www.11ty.dev/docs/plugins/navigation/
9 | eleventyConfig.addPlugin(eleventyNavigationPlugin)
10 |
11 | // Configuration API: use eleventyConfig.addLayoutAlias(from, to) to add
12 | // layout aliases! Say you have a bunch of existing content using
13 | // layout: post. If you don’t want to rewrite all of those values, just map
14 | // post to a new file like this:
15 | // eleventyConfig.addLayoutAlias("post", "layouts/my_new_post_layout.njk");
16 |
17 | // Merge data instead of overriding
18 | // https://www.11ty.dev/docs/data-deep-merge/
19 | eleventyConfig.setDataDeepMerge(true)
20 |
21 | // Add support for maintenance-free post authors
22 | // Adds an authors collection using the author key in our post frontmatter
23 | // Thanks to @pdehaan: https://github.com/pdehaan
24 | eleventyConfig.addCollection('authors', (collection) => {
25 | const blogs = collection.getFilteredByGlob('posts/*.md')
26 | return blogs.reduce((coll, post) => {
27 | const author = post.data.author
28 | if (!author) {
29 | return coll
30 | }
31 | if (!coll.hasOwnProperty(author)) {
32 | coll[author] = []
33 | }
34 | coll[author].push(post.data)
35 | return coll
36 | }, {})
37 | })
38 |
39 | // Date formatting (human readable)
40 | eleventyConfig.addFilter('readableDate', (dateObj) => {
41 | return DateTime.fromJSDate(dateObj).toFormat('dd LLL yyyy')
42 | })
43 |
44 | // Date formatting (machine readable)
45 | eleventyConfig.addFilter('machineDate', (dateObj) => {
46 | return DateTime.fromJSDate(dateObj).toFormat('yyyy-MM-dd')
47 | })
48 |
49 | // Minify CSS
50 | eleventyConfig.addFilter('cssmin', function (code) {
51 | return new CleanCSS({}).minify(code).styles
52 | })
53 |
54 | // Minify JS
55 | eleventyConfig.addFilter('jsmin', function (code) {
56 | let minified = UglifyJS.minify(code)
57 | if (minified.error) {
58 | console.log('UglifyJS error: ', minified.error)
59 | return code
60 | }
61 | return minified.code
62 | })
63 |
64 | // Minify HTML output
65 | eleventyConfig.addTransform('htmlmin', function (content, outputPath) {
66 | if (outputPath.indexOf('.html') > -1) {
67 | let minified = htmlmin.minify(content, {
68 | useShortDoctype: true,
69 | removeComments: true,
70 | collapseWhitespace: true
71 | })
72 | return minified
73 | }
74 | return content
75 | })
76 |
77 | // Don't process folders with static assets e.g. images
78 | eleventyConfig.addPassthroughCopy('favicon.ico')
79 | eleventyConfig.addPassthroughCopy('static/img')
80 | eleventyConfig.addPassthroughCopy('docs')
81 | eleventyConfig.addPassthroughCopy('demo')
82 | eleventyConfig.addPassthroughCopy('admin/')
83 |
84 | eleventyConfig.addPassthroughCopy({ tlas: '/' })
85 |
86 | // We additionally output a copy of our CSS for use in Netlify CMS previews
87 | eleventyConfig.addPassthroughCopy('_includes/assets/css/inline.css')
88 |
89 | /* Markdown Plugins */
90 | let markdownIt = require('markdown-it')
91 | let markdownItAnchor = require('markdown-it-anchor')
92 | let options = {
93 | breaks: true,
94 | linkify: true
95 | }
96 | let opts = {
97 | permalink: false
98 | }
99 |
100 | eleventyConfig.setLibrary('md', markdownIt(options).use(markdownItAnchor, opts))
101 |
102 | return {
103 | templateFormats: ['md', 'njk', 'liquid'],
104 |
105 | // If your site lives in a different subdirectory, change this.
106 | // Leading or trailing slashes are all normalized away, so don’t worry about it.
107 | // If you don’t have a subdirectory, use "" or "/" (they do the same thing)
108 | // This is only used for URLs (it does not affect your file structure)
109 | pathPrefix: '/',
110 |
111 | markdownTemplateEngine: 'liquid',
112 | htmlTemplateEngine: 'njk',
113 | dataTemplateEngine: 'njk',
114 | dir: {
115 | input: '.',
116 | includes: '_includes',
117 | data: '_data',
118 | output: '_site'
119 | }
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/documentation/mvcc-document-updates.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Multi-version concurrency control (mvcc) document updates
3 | metaDescription: Work with snapshots of data.
4 | summary: Fireproof offers MVCC updates and time-travel
5 | tags:
6 | - MVCC
7 | - Transactions
8 | - Snapshots
9 | ---
10 | Fireproof supports optional MVCC document updates. The default behavior allows any update, but if you want to make sure no one else has changed a document since you loaded it, you want MVCC. Because Fireproof uses MVCC and Merkle clocks, even if you don't active MVCC, and you end up writing a document someone else has updated, you won't lose any data, you'll juse need to merge the conflict. More about that in a future tutorial. For now let's just talk about document updates.
11 |
12 | ## Document read and write
13 |
14 | To write and read a new document in Fireproof, you just call the `put` function and the `get` function:
15 |
16 | ```js
17 | const putResponse = await database.put({hello : "world"})
18 | // { id, clock }
19 | const theDocument = await database.get(putResponse.id)
20 | // { _id, hello : "world" }
21 | ```
22 |
23 | When special fields like `id` or `clock` appear in the document, they are prefixed with an underscore, like `_id` above. If you don't specify an `_id` in your document body, Fireproof will generate one for you. That is what is returned as `putResponse.id` above.
24 |
25 | Updates are as simple as modifying the document and putting it back.
26 |
27 | ```js
28 | theDocument.hello = "everybody"
29 | const putResponse2 = await database.put(theDocument)
30 | // { id, clock }
31 | const theDocumentV2 = await database.get(putResponse.id)
32 | // { _id, hello : "everybody" }
33 | ```
34 |
35 | By default MVCC is not enabled, so you can put to the same `id` over and over again without failure, like this:
36 |
37 | ```js
38 | theDocument.hello = "again"
39 | const putResponse3 = await database.put(theDocument)
40 | theDocument.hello = "there"
41 | const putResponse4 = await database.put(theDocument)
42 | ```
43 |
44 | If multiple users are working this way, whoever writes last wins, overwriting the other changes (at least until conflict merge.)
45 |
46 | ## Multi-version concurrency control (MVCC)
47 |
48 | If you want to prevent that scenario, you can enable multi-version concurrency control, which will require that writers prove they are updating from the latest version, or else the write fails. This can give them a chance to reload from the source and incorporate their changes before writiing, instead of doing it later as a conflict merge.
49 |
50 | The put response includes an `id` which is unique for the document in the database, and a `clock` which represents the current snapshot of the database. You can also request that Fireproof inline the clock with the document by passing the `{ mvcc: true }` option:
51 |
52 | ```js
53 | const theDocumentV4 = await database.get(putResponse.id, { mvcc: true })
54 | // theDocumentV4._clock === putResponse4.clock
55 | ```
56 |
57 | If the clock is inline in the document it will protect against writing with stale data. Here's what happens if another update comes in before the document loaded with `{ mvcc: true }`:
58 |
59 | ```js
60 | theDocument.hello = "friends"
61 | const putResponse5 = await database.put(theDocument)
62 | // now theDocumentV4, which has _clock, is out of date
63 | const putResponse5 = await database.put(theDocumentV4)
64 | // throws new Error('MVCC conflict, document is changed, please reload the document and try again.')
65 | ```
66 |
67 | In this way you can protect against users being suprised by accidental data overwrites.
68 |
69 | ## Time Travel
70 |
71 | You can get a snapshot of the database at that clock by calling the `database.snapshot()` function with a clock. It will load document versions fom that snapshot. You can also update it, effectively forking the database.
72 |
73 | ```js
74 | const snapshot = database.snapshot(putResponse.clock)
75 | const docFromSnapshot = database.get(putResponse.id)
76 | ```
77 |
78 | This will return the version of the document that was written at the beginning of this article.
79 |
80 | You can also call `database.setClock()` with a clock, which will move the database to the clock head passed, and also fire an event to all the database listeners, which you can subscribe to in your UI for repaints. The [TodoMVC example uses this to enable TimeTravel](https://github.com/fireproof-storage/fireproof/blob/83653245b2cbbef8f6b89b0cf8979369c72e7150/examples/todomvc/src/components/TimeTravel.tsx#L29)
81 |
82 |
83 |
--------------------------------------------------------------------------------
/docs/data/search.json:
--------------------------------------------------------------------------------
1 | {"list":[{"title":"external-indexers","link":"tutorial-external-indexers.html","description":" External Indexers Fireproof is designed to make indexing in external indexers efficient and seamles"},{"title":"mvcc-document-updates","link":"tutorial-mvcc-document-updates.html","description":" Document update tutorial Fireproof supports optional MVCC document updates. The default behavior al"},{"title":"use-fireproof","link":"tutorial-use-fireproof.html","description":" useFireproof hook for React React hook to initialize a Fireproof database, automatically saving and"},{"title":"use-uploader","link":"tutorial-use-uploader.html","description":" useUploader React Hook Allows you to connect to any service that accepts CAR file uploads. Today th"},{"title":"DbIndex","link":"DbIndex","description":"
"},{"title":"Fireproof","link":"Fireproof"},{"title":"Fireproof\nCreates a new Fireproof instance with default storage settings\nMost apps should use this and not worry about the details.storage","link":"storage"},{"title":"Fireproof#changesSince","link":"changesSince","description":"
Returns the changes made to the Fireproof instance since the specified event.
Move the current instance to a new point in time. This triggers a notification to all listeners\nof the Fireproof instance so they can repaint UI, etc.
The map function to apply to each entry in the database.
"}]}
--------------------------------------------------------------------------------
/documentation/use-fireproof.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: useFireproof hook for React
3 | metaDescription: React hook that sets up your app for live data refreshes.
4 | summary: React hook that sets up your app for live data refreshes.
5 | tags:
6 | - React
7 | - JavaScript
8 | ---
9 | React hook to initialize a Fireproof database, automatically saving and loading the clock.
10 |
11 | The hook takes two optional setup function arguments, `defineDatabaseFn` and `setupDatabaseFn`. See below for examples.
12 |
13 | The return value looks like `{ ready, database, addSubscriber }` where the `database` is your Fireproof instance that you can interact with using `put` and `get`, or via your indexes. The `ready` flag turns true after setup completes, you can use this to activate your UI. The `addSubscriber` function is used to update your app in realtime, see example.
14 |
15 | ## Usage Example
16 |
17 | In App.js:
18 |
19 | ```js
20 | import { FireproofCtx, useFireproof } from '@fireproof/core/hooks/use-fireproof'
21 |
22 | function App() {
23 | // establish the Fireproof context value
24 | const fpCtxValue = useFireproof()
25 |
26 | // render the rest of the application wrapped in the Fireproof provider
27 | return (
28 |
29 |
30 |
31 | )
32 | }
33 | ```
34 |
35 | In your components:
36 |
37 | ```js
38 | import { FireproofCtx } from '@fireproof/core/hooks/use-fireproof'
39 |
40 | function MyComponent() {
41 | // get Fireproof context
42 | const { ready, database, addSubscriber } = useContext(FireproofCtx)
43 |
44 | // set a default empty document
45 | const [doc, setDoc] = useState({})
46 |
47 | // function to load the document from the database
48 | const getDataFn = async () => {
49 | setDoc(await database.get("my-doc-id"))
50 | }
51 |
52 | // run that function when the database changes
53 | addSubscriber('MyComponent', getDataFn)
54 |
55 | // run the loader on first mount
56 | useEffect(() => getDataFn(), [])
57 |
58 | // a function to change the value of the document
59 | const updateFn = async () => {
60 | await database.put({ _id : "my-doc-id", hello: "world", updated_at: new Date()})
61 | }
62 |
63 | // render the document with a click handler to update it
64 | return
JSON.stringify(doc)
65 | }
66 | ```
67 |
68 | This should result in a tiny application that updates the document when you click it. In a real appliction you'd probably query an index to present eg. all of the photos in a gallery.
69 |
70 | ## Setup Functions
71 |
72 | ### defineDatabaseFn
73 |
74 | Synchronous function that defines the database, run this before any async calls. You can use it to do stuff like set up Indexes. Here's an example:
75 |
76 | ```js
77 | const defineIndexes = (database) => {
78 | database.allLists = new Index(database, function (doc, map) {
79 | if (doc.type === 'list') map(doc.type, doc)
80 | })
81 | database.todosByList = new Index(database, function (doc, map) {
82 | if (doc.type === 'todo' && doc.listId) {
83 | map([doc.listId, doc.createdAt], doc)
84 | }
85 | })
86 | window.fireproof = database // 🤫 for dev
87 | return database
88 | }
89 | ```
90 |
91 | ### setupDatabaseFn
92 |
93 | Asynchronous function that uses the database when it's ready, run this to load fixture data, insert a dataset from somewhere else, etc. Here's a simple example:
94 |
95 |
96 | ```
97 | async function setupDatabase(database)) {
98 | const apiData = await (await fetch('https://dummyjson.com/products')).json()
99 | for (const product of apiData.products) {
100 | await database.put(product)
101 | }
102 | }
103 | ```
104 |
105 | Note there are no protections against you running the same thing over and over again, so you probably want to put some logic in there to do the right thing.
106 |
107 | Here is an example of generating deterministic fixtures, using `mulberry32` for determinstic randomness so re-runs give the same CID, avoiding unnecessary bloat at development time, taken from the TodoMVC demo app.
108 |
109 | ```js
110 | function mulberry32(a) {
111 | return function () {
112 | let t = (a += 0x6d2b79f5)
113 | t = Math.imul(t ^ (t >>> 15), t | 1)
114 | t ^= t + Math.imul(t ^ (t >>> 7), t | 61)
115 | return ((t ^ (t >>> 14)) >>> 0) / 4294967296
116 | }
117 | }
118 | const rand = mulberry32(1) // determinstic fixtures
119 |
120 | export default async function loadFixtures(database) {
121 | const nextId = (prefix = '') => prefix + rand().toString(32).slice(2)
122 | const listTitles = ['Building Apps', 'Having Fun', 'Getting Groceries']
123 | const todoTitles = [
124 | [
125 | 'In the browser',
126 | 'On the phone',
127 | 'With or without Redux',
128 | 'Login components',
129 | 'GraphQL queries',
130 | 'Automatic replication and versioning',
131 | ],
132 | ['Rollerskating meetup', 'Motorcycle ride', 'Write a sci-fi story with ChatGPT'],
133 | ['Macadamia nut milk', 'Avocado toast', 'Coffee', 'Bacon', 'Sourdough bread', 'Fruit salad'],
134 | ]
135 | let ok
136 | for (let j = 0; j < 3; j++) {
137 | ok = await database.put({
138 | title: listTitles[j],
139 | type: 'list',
140 | _id: nextId('' + j)
141 | })
142 | for (let i = 0; i < todoTitles[j].length; i++) {
143 | await database.put({
144 | _id: nextId(),
145 | title: todoTitles[j][i],
146 | listId: ok.id,
147 | completed: rand() > 0.75,
148 | type: 'todo',
149 | })
150 | }
151 | }
152 | }
153 | ```
154 |
155 |
--------------------------------------------------------------------------------
/_includes/components/social-proof.njk:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
Friends of Fireproof
6 |
7 |
8 |
9 |
10 | Learn how people are saving costs and innovating with new business models. Fireproof's advanced database
11 | capabilities and easy front-end installation make it a tool of choice for early adopters.
12 | You know you want to be on the cube!
13 | Email the project lead or direct message
14 | Fireproof Storage on Twitter to get featured.
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
J. Chris Anderson
27 |
28 |
29 | Fireproof creator, previously co-founded Couchbase. Building
30 | distributed
31 | databases since 2009.
32 |
11 |
16 |
21 |
22 |
23 | `}function initTooltip(){tippy(".theme-toggle",{content:"Toggle Theme",delay:500}),tippy(".search-button",{content:"Search",delay:500}),tippy(".font-size",{content:"Change font size",delay:500}),tippy(".codepen-button",{content:"Open code in CodePen",placement:"left"}),tippy(".copy-code",{content:"Copy this code",placement:"left"}),tippy(".font-size",{content:fontSizeTooltip(),trigger:"click",interactive:!0,allowHTML:!0,placement:"left"})}function fixTable(){for(const t of document.querySelectorAll("table")){if(t.classList.contains("hljs-ln"))return;var e=document.createElement("div");e.classList.add("table-div"),t.parentNode.insertBefore(e,t),e.appendChild(t)}}function hideMobileMenu(){var e=document.querySelector("#mobile-sidebar"),t=document.querySelector("#mobile-menu"),o=t.querySelector("use");e&&e.classList.remove("show"),t&&t.setAttribute("data-isopen","false"),o&&o.setAttribute("xlink:href","#menu-icon")}function showMobileMenu(){var e=document.querySelector("#mobile-sidebar"),t=document.querySelector("#mobile-menu"),o=t.querySelector("use");e&&e.classList.add("show"),t&&t.setAttribute("data-isopen","true"),o&&o.setAttribute("xlink:href","#close-icon")}function onMobileMenuClick(){("true"===document.querySelector("#mobile-menu").getAttribute("data-isopen")?hideMobileMenu:showMobileMenu)()}function initMobileMenu(){var e=document.querySelector("#mobile-menu");e&&e.addEventListener("click",onMobileMenuClick)}function addHrefToSidebarTitle(){document.querySelectorAll(".sidebar-title-anchor").forEach(function(e){e.setAttribute("href",baseURL)})}function onDomContentLoaded(){var e=document.querySelectorAll(".theme-toggle");initMobileMenu(),e&&e.forEach(function(e){e.addEventListener("click",toggleTheme)}),hljs.addPlugin({"after:highlightElement":function(e){e.el.parentNode.setAttribute("data-lang","code")}}),hljs.highlightAll(),hljs.initLineNumbersOnLoad({singleLine:!0}),initAccordion(),addAnchor(),processAllPre(),hideTocOnSourcePage(),setTimeout(function(){bringIdToViewOnMount(),isSourcePage()&&highlightAndBringLineIntoView()},1e3),initTooltip(),fixTable(),addHrefToSidebarTitle()}!function(){var e=getTheme(),t=localStorage.getItem(themeLocalStorageKey);t?e!==t&&updateTheme(t):localStorage.setItem(themeLocalStorageKey,e)}(),function(){var e=getFontSize(),t=localStorage.getItem(fontSizeLocalStorageKey);t?(t=Number.parseInt(t,10))!==e&&updateFontSize(t):updateFontSize(e)}(),window.addEventListener("DOMContentLoaded",onDomContentLoaded),window.addEventListener("hashchange",e=>{e=new URL(e.newURL);""!==e.hash&&bringIdToViewOnMount(e.hash)});
--------------------------------------------------------------------------------
/_includes/components/features.njk:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
Database Features
5 |
6 |
7 |
8 |
9 |
10 | Fireproof is local-first software, operating directly in the browser and automatically
11 | synchronizing with the distributed IPFS storage network. It uses verifiable operations and encrypted,
12 | immutable data — making it more reliable than the cloud.
13 |
39 | Access your JSON data from any app or website with a simple put, get, and delete interface. Embed, index,
40 | and organize files of any size using IPFS links. Handle data variety and schema drift by
41 | writing JavaScript functions to define indexes, making it easy to normalize data and simplify indexing and
42 | searching. Queries run locally, making Fireproof faster than any cloud database.
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
Immutable History
51 |
52 | MVCC versioning and Merkle causal history tracking ensure that you can always recover the desired version
53 | of your data, and query a stable snapshot of the database. Immutable data structures
54 | simplify replication and improve performance, while enabling roll back to old data whenever needed, giving
55 | you peace of mind knowing your data is secure. Merkle clocks and hash trees are used to provide lossless
56 | merging and immutable and self-validating data structures, making replicating changes safe and efficient,
57 | and making Fireproof ideal for smart contract and other trustless applications.
58 |
98 | Get instant notifications of changes to your data, with real-time updates synced across all devices and
99 | apps. Fireproof uses a combination of WebRTC and IPFS to provide fast and efficient real-time updates,
100 | giving you real-time access to your data without the need for constant polling or manual refresh. Whether
101 | you're building an online collaboration tool, a real-time dashboard, or just want to
102 | keep your UI up-to-date in real-time, Fireproof has you covered.
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
Self-sovereign Identity
111 |
112 | With self-sovereign identity users have full control over their personal data and identity, without
113 | relying on a central authority. This enables new business models and the creation of apps that serve users
114 | first. Fireproof's self-sovereign identity solution is built on industry standards such
115 | as Decentralized Identifiers (DIDs) and UCAN. Users can choose to use Fireproof storage services or store
116 | data with other backends such as web3.storage, further ensuring the security and sovereignty of their
117 | data.
118 |
164 | Syncing state is as easy as sending a link to the latest database head and Fireproof will
165 | handle the rest, ensuring your data is always up-to-date and accessible from any device or browser.
166 | Whether you're working from your desktop, laptop, or mobile device, Fireproof ensures that your data is
167 | always up-to-date and accessible. Documents changes are persisted to Filecoin via web3.storage and made
168 | available over IPFS and a global content delivery network. With automatic replication, you never have to
169 | worry about losing important information or manually transferring data between devices.
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
Cryptographic Proofs
178 |
179 | UCAN cryptographic proof chains link updates to authorized agents, ensuring data security and integrity.
180 | Portable, signed proofs eliminate the need for secret bearer tokens. Transactions are
181 | functional transforms of hash-linked graphs, ensuring data consistency across nodes. Each transaction is a
182 | unique immutable hash, enabling efficient data sharing. Cryptographic proofs available for all operations
183 | make Fireproof ideal for smart contracts and trustless environments. Proof chains also improve performance
184 | by allowing for cryptographic verification of changes.
185 |
Fireproof is designed to make indexing in external indexers efficient and seamless. Each database tracks it's change history and provides a feed of changes since any clock. If you don't provide a clock, you'll get all changes. Each change includes it's clock, so if you keep track of a high water mark, you can safely restart your indexing process and know you aren't missing any updates.
For single-user workloads it can often be enough to index the local dataset on page load, and use your index in memory. For larger data use-cases you probably want to use an indexer than remember everything it has added, and incrementally add new items as changes occur. For an example of that sort of index, check out fireproof/test/fulltext.test.js for an example.
--------------------------------------------------------------------------------
/docs/scripts/third-party/Apache-License-2.0.txt:
--------------------------------------------------------------------------------
1 |
2 | Apache License
3 | Version 2.0, January 2004
4 | http://www.apache.org/licenses/
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
176 |
177 | END OF TERMS AND CONDITIONS
178 |
179 | APPENDIX: How to apply the Apache License to your work.
180 |
181 | To apply the Apache License to your work, attach the following
182 | boilerplate notice, with the fields enclosed by brackets "[]"
183 | replaced with your own identifying information. (Don't include
184 | the brackets!) The text should be enclosed in the appropriate
185 | comment syntax for the file format. We also recommend that a
186 | file or class name and description of purpose be included on the
187 | same "printed page" as the copyright notice for easier
188 | identification within third-party archives.
189 |
190 | Copyright [yyyy] [name of copyright owner]
191 |
192 | Licensed under the Apache License, Version 2.0 (the "License");
193 | you may not use this file except in compliance with the License.
194 | You may obtain a copy of the License at
195 |
196 | http://www.apache.org/licenses/LICENSE-2.0
197 |
198 | Unless required by applicable law or agreed to in writing, software
199 | distributed under the License is distributed on an "AS IS" BASIS,
200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201 | See the License for the specific language governing permissions and
202 | limitations under the License.
203 |
--------------------------------------------------------------------------------