[
  {
    "path": ".github/workflows/linting.yml",
    "content": "on: [pull_request]\n\njobs:\n  lint:\n    runs-on: ubuntu-latest\n    steps:\n    - uses: actions/checkout@v4\n    - uses: DavidAnson/markdownlint-cli2-action@v19\n      with:\n        globs: |\n          ./**/*.md\n"
  },
  {
    "path": ".github/workflows/main.yml",
    "content": "name: update-templates\n\non:\n  push:\n    branches:\n      - main\n  workflow_dispatch:\n\njobs:\n  update-templates:\n    permissions:\n      contents: write\n      pull-requests: write\n      pages: write\n    uses: thoughtbot/templates/.github/workflows/dynamic-readme.yaml@main\n    secrets:\n      token: ${{ secrets.GITHUB_TOKEN }}\n"
  },
  {
    "path": ".gitignore",
    "content": ".obsidian\n\nnode_modules\n"
  },
  {
    "path": ".hound.yml",
    "content": "coffeescript:\n  enabled: false\neslint:\n  enabled: true\n  config_file: javascript-typescript/.eslintrc.json\n  version: 6.3.0\nhaml:\n  enabled: true\n  config_file: haml/haml.yml\njavascript:\n  enabled: false\nrubocop:\n  enabled: true\n  config_file: ruby/.rubocop.yml\n  version: 0.72.0\nscss:\n  enabled: false\nstylelint:\n  enabled: true\n  config_file: sass/.stylelintrc.json\n"
  },
  {
    "path": ".markdownlint-cli2.jsonc",
    "content": "{\n  // https://github.com/DavidAnson/markdownlint/blob/v0.32.1/README.md#rules--aliases\n  // https://github.com/DavidAnson/markdownlint-cli2/blob/main/test/markdownlint-cli2-jsonc-example/.markdownlint-cli2.jsonc\n  // https://github.com/DavidAnson/markdownlint-cli2/blob/main/schema/markdownlint-config-schema.json\n  \"$schema\": \"https://raw.githubusercontent.com/DavidAnson/markdownlint-cli2/refs/heads/main/schema/markdownlint-cli2-config-schema.json\",\n  \"gitignore\": true,\n  \"config\": {\n    /* MD001 - Heading levels should only increment by one level at a time */\n    \"heading-increment\": true,\n\n    /* MD003 - Heading style */\n    \"heading-style\": true,\n\n    /* MD004 - Unordered list style */\n    \"ul-style\": true,\n\n    /* MD005 - Inconsistent indentation for list items at the same level */\n    \"list-indent\": true,\n\n    /* MD007 - Unordered list indentation */\n    \"ul-indent\": true,\n    // { \"indent\": 2, \"start_indented\": false },\n\n    /* MD009 - Trailing spaces */\n    \"no-trailing-spaces\": true,\n\n    /* MD010 - Hard tabs */\n    \"no-hard-tabs\": true,\n\n    /* MD011 - Reversed link syntax */\n    \"no-reversed-links\": true,\n\n    /* MD012 - Multiple consecutive blank lines */\n    \"no-multiple-blanks\": true,\n\n    /* MD013 - Line length */\n    // NOTE: Disabled to allow lines of any length; could be enabled in a separate PR after discussion\n    \"line-length\": false,\n\n    /* MD014 - Dollar signs used before commands without showing output */\n    \"commands-show-output\": true,\n\n    /* MD018 - No space after hash on atx style heading */\n    \"no-missing-space-atx\": true,\n\n\n    /* MD019 - Multiple spaces after hash on atx style heading */\n    \"no-multiple-space-atx\": true,\n\n    /* MD020 - No space inside hashes on closed atx style heading */\n    \"no-missing-space-closed-atx\": true,\n\n    /* MD021 - Multiple spaces inside hashes on closed atx style heading */\n    \"no-multiple-space-closed-atx\": true,\n\n    /* MD022 - Headings should be surrounded by blank lines */\n    \"blanks-around-headings\": true,\n\n    /* MD023 - Headings must start at the beginning of the line */\n    \"heading-start-left\": true,\n\n    /* MD024 - Multiple headings with the same content */\n    \"no-duplicate-heading\": {\n      \"siblings_only\": true\n    },\n\n    /* MD025 - Multiple top-level headings in the same document */\n    \"single-title\": true,\n\n    /* MD026 - Trailing punctuation in heading */\n    \"no-trailing-punctuation\": true,\n\n    /* MD027 - Multiple spaces after blockquote symbol */\n    \"no-multiple-space-blockquote\": true,\n\n    /* MD028 - Blank line inside blockquote */\n    \"no-blanks-blockquote\": true,\n\n    /* MD029 - Ordered list item prefix */\n    \"ol-prefix\": true,\n\n    /* MD030 - Spaces after list markers */\n    \"list-marker-space\": true,\n\n    /* MD031 - Fenced code blocks should be surrounded by blank lines */\n    \"blanks-around-fences\": true,\n\n    /* MD032 - Lists should be surrounded by blank lines */\n    \"blanks-around-lists\": true,\n\n    /* MD033 - Inline HTML */\n    \"no-inline-html\": {\n      \"allowed_elements\": [\"dl\", \"dt\", \"dd\", \"kbd\", \"details\"]\n    },\n\n    /* MD034 - Bare URL used */\n    \"no-bare-urls\": true,\n\n    /* MD035 - Horizontal rule style */\n    \"hr-style\": true,\n\n    /* MD036 - Emphasis used instead of a heading */\n    \"no-emphasis-as-heading\": true,\n\n    /* MD037 - Spaces inside emphasis markers */\n    \"no-space-in-emphasis\": true,\n\n    /* MD038 - Spaces inside code span elements */\n    \"no-space-in-code\": true,\n\n    /* MD039 - Spaces inside link text */\n    \"no-space-in-links\": true,\n\n    /* MD040 - Fenced code blocks should have a language specified */\n    \"fenced-code-language\": true,\n\n    /* MD041 - First line in a file should be a top-level heading */\n    \"first-line-heading\": true,\n\n    /* MD042 - No empty links */\n    \"no-empty-links\": true,\n\n    /* MD043 - Required heading structure */\n    \"required-headings\": true,\n\n    /* MD044 - Proper names should have the correct capitalization */\n    \"proper-names\": true,\n\n    /* MD045 - Images should have alternate text (alt text) */\n    \"no-alt-text\": true,\n\n    /* MD046 - Code block style */\n    \"code-block-style\": true,\n\n    /* MD047 - Files should end with a single newline character */\n    \"single-trailing-newline\": true,\n\n    /* MD048 - Code fence style */\n    \"code-fence-style\": true,\n\n    /* MD049 - Emphasis style */\n    \"emphasis-style\": true,\n\n    /* MD050 - Strong style */\n    \"strong-style\": true,\n\n    /* MD051 - Link fragments should be valid */\n    \"link-fragments\": true,\n\n    /* MD052 - Reference links and images should use a label that is defined */\n    \"reference-links-images\": {\n      \"shortcut_syntax\": false\n    },\n\n    /* MD053 - Link and image reference definitions should be needed */\n    \"link-image-reference-definitions\": true,\n\n    /* MD054 - Link and image style */\n    \"link-image-style\": true\n  }\n}\n"
  },
  {
    "path": ".tool-versions",
    "content": "node latest\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Code of Conduct\n\nBy participating in this project, you agree to abide by the [thoughtbot code of\nconduct].\n\n[thoughtbot code of conduct]: https://thoughtbot.com/open-source-code-of-conduct\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing\n\nWe love contributions from everyone. By participating in this project, you agree\nto abide by the [thoughtbot Code Of Conduct].\n\nWe expect everyone to follow the code of conduct anywhere in thoughtbot's\nproject codebases, issue trackers, chatrooms, mailing lists, meetups, at other events, and in-person.\nViolators will be warned by the core team.\nRepeat violations will result in being blocked or banned by the core team at or before the 3rd violation.\n\n[thoughtbot code of conduct]: https://thoughtbot.com/open-source-code-of-conduct\n\n## Getting Feedback\n\nSince these are our guides, we want everyone at thoughtbot to see them. We have\na lot of people across a lot of timezones, so we leave all PRs open for at\nleast a week to get feedback from everyone.\n\n## Content\n\nDecisions about which libraries to use should live in template projects such as\n[Suspenders].\n\n[suspenders]: https://github.com/thoughtbot/suspenders\n\n### The Anatomy of a Guide\n\nWhether you're creating a new guide or adding to an existing one, you can\nreference [the template guide](/_template/) if you're unsure where to put\nthings.\n"
  },
  {
    "path": "README.md",
    "content": "# Guides\n\nGuides for working together, getting things done, programming well, and\nprogramming in style.\n\n## High level guidelines\n\n- Be consistent.\n- Don't rewrite existing code to follow this guide.\n- Don't violate a guideline without a good reason.\n- A reason is good when you can convince a teammate.\n\n## A note on the language\n\n- \"Avoid\" means don't do it unless you have good reason.\n- \"Don't\" means there's never a good reason.\n- \"Prefer\" indicates a better option and its alternative to watch out for.\n- \"Use\" is a positive instruction.\n\n## Guides by category\n\n- [thoughtbot Tech Stack](/tech-stack/)\n- [General](/general/)\n\n### Collaboration\n\n- [Code Review](/code-review/)\n- [Open Source](/open-source/)\n- [Product Review](/product-review/)\n\n### Protocols\n\n- [Accessibility](/accessibility/)\n- [Data](/data/)\n- [Email](/email/)\n- [Object-Oriented Design](/object-oriented-design/)\n- [Security](/security/)\n- [Web](/web/)\n- [Web Performance](/web-performance/)\n\n### Languages\n\n- [Bash](/bash/)\n- [CSS](/css/)\n- [ERB](/erb/)\n- [HTML](/html/)\n- [JavaScript & TypeScript](/javascript-typescript/)\n- [Python](/python/)\n- [Ruby](/ruby/)\n- [Sass](/sass/)\n- [Shell](/shell/)\n- [Swift](/swift/)\n\n### Frameworks and platforms\n\n- [Android](/android/)\n- [iOS](/ios/)\n- [Rails](/rails/)\n- [React](/react/)\n- [React Native](/react-native/)\n- [Testing with Jest](/testing-jest/)\n- [Testing with RSpec](/testing-rspec/)\n\n### Tools\n\n- [Git](/git/)\n- [GraphQL](/graphql/)\n- [Postgres](/postgres/)\n- [Relational Databases](/relational-databases/)\n\n## Contributing\n\nPlease read the [contribution guidelines](/CONTRIBUTING.md) before submitting a\npull request.\n\nIn particular: **if you have commit access, please don't merge changes without\nwaiting a week for everybody to leave feedback**.\n\n## Credits\n\nThank you,\n[contributors](https://github.com/thoughtbot/guides/graphs/contributors)!\n\n## License\n\nGuides is © 2020-2025 thoughtbot, inc. It is distributed under the [Creative\nCommons Attribution License](http://creativecommons.org/licenses/by/3.0/).\n\n<!-- START /templates/footer.md -->\n## About thoughtbot\n\n![thoughtbot](https://thoughtbot.com/thoughtbot-logo-for-readmes.svg)\n\nThis repo is maintained and funded by thoughtbot, inc.\nThe names and logos for thoughtbot are trademarks of thoughtbot, inc.\n\nWe love open source software!\nSee [our other projects][community].\nWe are [available for hire][hire].\n\n[community]: https://thoughtbot.com/community?utm_source=github\n[hire]: https://thoughtbot.com/hire-us?utm_source=github\n\n<!-- END /templates/footer.md -->\n"
  },
  {
    "path": "_template/README.md",
    "content": "# Template\n\nIn a sentence or two, describe what this guide is about. A guide can be about a\nprogramming language or framework, a design or development tool, or an entirely\nnon-technical topic.\n\n## Best Practices\n\nIn this section (or as many sections as you need) convey the best practices\naround the topic of the guide.\n\nThis typically takes one of three forms:\n\n1. A section or sections with lists of specific\n   [guidelines](/README.md#a-note-on-the-language)\n2. Primarily textual sections\n3. A combination of both\n\n## How To Guides\n\nThis section, if applicable, should index a list of \"How-to\" guides for this\nguide's topic. These should be stored relative to this `README.md` file in a\nfolder named `how-to`.\n\nHere are some examples:\n\n- [Do something](./how-to/do-something.md)\n- [Do something else](./how-to/do-something-else.md)\n"
  },
  {
    "path": "_template/how-to/do-something-else.md",
    "content": "# How to Do Something Else\n\nThis is an example how-to guide. Write anything you want here!\n"
  },
  {
    "path": "_template/how-to/do-something.md",
    "content": "# How to Do Something\n\nThis is an example how-to guide. Write anything you want here!\n"
  },
  {
    "path": "accessibility/README.md",
    "content": "# Accessibility\n\nA guide for auditing and maintaining accessible web sites and apps.\n\n## Basics\n\nthoughtbot strives for AA level [Web Content Accessibility Guideline (WCAG)]\ncompliance. Perform one or more of these checks to ensure your work is\naccessible.\n\n### Automation\n\nAutomated checks can catch a lot of common issues before they reach production.\n\n- Test the application in a browser (like Capybara-driven [Acceptance\n  Tests](../testing-rspec/README.md#acceptance-tests))\n- When using Capybara, use [CapybaraAccessibilityAudit]\n- Use tools such as [WAVE] or [axe's browser extensions] to run audits on your\n  local build\n- Use a CI/CD solution such as [AccessLint] or [axe]. axe has integrations with popular test frameworks like RSpec and Jest\n\n[CapybaraAccessibilityAudit]: https://github.com/thoughtbot/capybara_accessibility_audit\n\n### Usability\n\n[Manual usability testing] ensures things work as intended.\n\n- Test your local build using a screen reader such as [VoiceOver] or [NVDA]\n- Use auditing tools to catch issues that cannot be\n  found using automated checks\n  - [Accessibility Insights] accessibility auditing browser extension\n  - [Readability Analyzer][simple and direct] for auditing text\n  - [axe DevTools] accessibility testing browser extension\n  - [WAVE Evaluation Tool] accessibility testing browser extension\n  - [ARIA DevTools] browser extension for checking ARIA roles\n  - [tab11y] browser extension for checking tab order\n  - [WCAG Color contrast checker] browser extension\n- Validate your HTML with a tool like [W3C's Markup Validation Service][w3c-markup-validator]\n- Hire assistive technology users to user test your product\n\n[axe DevTools]: https://chromewebstore.google.com/detail/axe-devtools-web-accessib/lhdoppojpmngadmnindnejefpokejbdd\n[WAVE Evaluation Tool]: https://chromewebstore.google.com/detail/wave-evaluation-tool/jbbplnpkjmmeebjpijfedlgcdilocofh\n[ARIA DevTools]: https://chromewebstore.google.com/detail/aria-devtools/dneemiigcbbgbdjlcdjjnianlikimpck\n[tab11y]: https://chromewebstore.google.com/detail/taba11y-tab-order-accessi/aocppmckdocdjkphmofnklcjhdidgmga\n[WCAG Color contrast checker]: https://chromewebstore.google.com/detail/wcag-color-contrast-check/plnahcmalebffmaghcpcmpaciebdhgdf\n[w3c-markup-validator]: https://validator.w3.org/\n\n## Quick checks\n\n### Design\n\n- Ensure all content's foreground color values meet the [minimum contrast ratio]\n  for the background color they are placed over ([WCAG 1.4.3][wcag-1-4-3])\n- Ensure all interactive content has distinct hover and focus states to help\n  indicate interactivity ([WCAG 2.4.7][wcag-2-4-7])\n- Ensure interactive elements [have a visible text label][rule-2]\n- Ensure color is not the only way to determine meaning ([WCAG 1.4.1][wcag-1-4-1])\n- Ensure interactive components use common UI affordances where applicable, to\n  help users understand how they can be operated\n- Prefer icons and glyphs that don't rely on specialized knowledge to understand\n  their meaning, unless being used in a domain-specific context\n- Prefer language that is [simple and direct] ([WCAG 3.1][wcag-3-1])\n- Ensure form inputs have [labels that are visible in every state][placeholder-labels]\n- Ensure link and button text is descriptive and distinct ([WCAG 2.4.4][wcag-2-4-4])\n- Prefer content that is broken into logical sections, with headings that\n  explain the content that follows ([WCAG 2.4.10][wcag-2-4-10])\n- Prefer text sizing that is set to 16px or larger\n- Ensure animation does not auto-play, can be paused, and avoids [vestibular and\n  seizure triggers] ([WCAG 2.2.2][wcag-2-2-2])\n- Ensure video content has captions ([WCAG 1.2.2][wcag-1-2-2])\n- Prefer larger interactive target sizes, with some space between grouped\n  interactive controls ([WCAG 2.5.8][wcag-2-5-8])\n\n### Development\n\n- Ensure every focusable or interactive element has an [accessible name][] ([WCAG 4.1.2][wcag-4-1-2])\n- Follow the [Cardinal Rules of Naming][]:\n  1. [Heed Warnings and Test Thoroughly][rule-1]\n  2. [Prefer Visible Text][rule-2]\n  3. [Prefer Native Techniques][rule-3]\n  4. [Avoid Browser Fallback][rule-4]\n  5. [Compose Brief, Useful Names][rule-5]\n- Ensure [semantic markup][semantic-markup] is used to describe content\n- Ensure content does not disappear off the screen when zoomed ([WCAG 1.4.10][wcag-1-4-10])\n- Ensure that interactive content can be tabbed to and activated using the\n  keyboard, and that the tab order matches reading order ([WCAG 2.1.1][wcag-2-1-1], [WCAG 2.4.3][wcag-2-4-3])\n- Ensure that heading elements are used, and that heading levels are placed in a\n  logical order ([WCAG 2.4.10][wcag-2-4-10])\n- Ensure that [landmarks][landmark-regions] are used to describe the overall layout of the page or\n  view\n- Ensure that alternative descriptions for image content are concise,\n  descriptive, and use punctuation (`alt` attributes for images, `title`\n  elements for SVGs)\n- Ensure [labels are programmatically associated][labels-associated-inputs] with their inputs\n- Prefer implementing a method to allow users to skip sections of repeated\n  content ([WCAG 2.4.1][wcag-2-4-1])\n- Ensure each page or view has a unique title that describes the content it\n  contains ([WCAG 2.4.2][wcag-2-4-2])\n- The [`title` attribute is only used to describe `iframe` element contents][title-iframe]\n- Ensure that [links are used to navigate to other locations and buttons are used\n  to trigger actions][links-vs-buttons]\n- Ensure that [focus is trapped inside of modal interactions][focus-traps]\n- Ensure `fieldset` and `legend` elements are used to [group related inputs and\n  label them][fieldsets-legends]\n- Ensure form feedback messaging is programmatically associated with the\n  relevant inputs ([WCAG 3.3.1][wcag-3-3-1])\n- Ensure that dynamic changes to a web page are announced ([WCAG 4.1.3][wcag-4-1-3])\n- Prefer using role selectors in automated acceptance tests\n  - [capybara_accessible_selectors]\n  - [Testing Library's `getByRole()`][testing-library-getbyrole]\n  - [Playwright's `getByRole()`][playwright-getbyrole]\n\n[accessible name]: https://www.w3.org/WAI/ARIA/apg/practices/names-and-descriptions/\n[Cardinal Rules of Naming]: https://www.w3.org/WAI/ARIA/apg/practices/names-and-descriptions/#cardinalrulesofnaming\n[rule-1]: https://www.w3.org/WAI/ARIA/apg/practices/names-and-descriptions/#naming_rule_heed_warnings\n[rule-2]: https://www.w3.org/WAI/ARIA/apg/practices/names-and-descriptions/#naming_rule_visible_text\n[rule-3]: https://www.w3.org/WAI/ARIA/apg/practices/names-and-descriptions/#naming_rule_native_techniques\n[rule-4]: https://www.w3.org/WAI/ARIA/apg/practices/names-and-descriptions/#naming_rule_avoid_fallback\n[rule-5]: https://www.w3.org/WAI/ARIA/apg/practices/names-and-descriptions/#naming_rule_brief_names\n[capybara_accessible_selectors]: https://github.com/citizensadvice/capybara_accessible_selectors\n[testing-library-getbyrole]: https://testing-library.com/docs/queries/byrole\n[playwright-getbyrole]: https://playwright.dev/docs/locators#locate-by-role\n[landmark-regions]: https://www.w3.org/WAI/ARIA/apg/practices/landmark-regions/\n[labels-associated-inputs]: https://www.w3.org/WAI/WCAG22/Techniques/html/H44\n[title-iframe]: https://www.w3.org/WAI/WCAG22/Techniques/html/H64\n[links-vs-buttons]: https://www.nngroup.com/videos/buttons-vs-links/\n[focus-traps]: https://okenlabs.com/blog/accessibility-implementing-focus-traps/\n[fieldsets-legends]: https://www.w3.org/WAI/WCAG22/Techniques/html/H71\n[placeholder-labels]: https://www.deque.com/blog/accessible-forms-the-problem-with-placeholders/#:~:text=A%20Placeholder%20Is%20Not%20a%20Replacement%20for%20Visible%20Labels\n[semantic-markup]: https://www.w3.org/WAI/WCAG22/Techniques/html/H101\n\n[wcag-1-4-3]: https://www.w3.org/WAI/WCAG22/Understanding/contrast-minimum.html\n[wcag-1-4-1]: https://www.w3.org/WAI/WCAG22/Understanding/use-of-color.html\n[wcag-3-1]: https://www.w3.org/WAI/WCAG22/Understanding/readable.html\n[wcag-2-4-4]: https://www.w3.org/WAI/WCAG22/Understanding/link-purpose-in-context.html\n[wcag-2-4-10]: https://www.w3.org/WAI/WCAG22/Understanding/section-headings.html\n[wcag-2-2-2]: https://www.w3.org/WAI/WCAG22/Understanding/pause-stop-hide.html\n[wcag-1-2-2]: https://www.w3.org/WAI/WCAG22/Understanding/captions-prerecorded.html\n[wcag-2-5-8]: https://www.w3.org/WAI/WCAG22/Understanding/target-size-minimum.html\n[wcag-4-1-2]: https://www.w3.org/WAI/WCAG22/Understanding/name-role-value.html\n[wcag-4-1-3]: https://www.w3.org/WAI/WCAG22/Understanding/status-messages.html\n[wcag-1-4-10]: https://www.w3.org/WAI/WCAG22/Understanding/reflow.html\n[wcag-2-1-1]: https://www.w3.org/WAI/WCAG22/Understanding/keyboard.html\n[wcag-2-4-3]: https://www.w3.org/WAI/WCAG22/Understanding/focus-order.html\n[wcag-2-4-1]: https://www.w3.org/WAI/WCAG22/Understanding/bypass-blocks.html\n[wcag-2-4-2]: https://www.w3.org/WAI/WCAG22/Understanding/page-titled.html\n[wcag-3-3-1]: https://www.w3.org/WAI/WCAG22/Understanding/error-identification.html\n[wcag-2-4-7]: https://www.w3.org/WAI/WCAG22/Understanding/focus-visible.html\n\n## Full audit\n\nWhen at all possible, use the guidelines in the basics and quick check sections\nto attempt to address accessibility in a proactive way.\n\nIf a thorough analysis needs to be performed, use the following workflow to\nperform a comprehensive accessibility audit that checks against most WCAG\ncriterion:\n\n1. Create a copy of the [Accessibility Audit Template] spreadsheet in Google\nDrive\n1. Break apart the site or app to be audited into discrete user flow sections,\nordered by importance\n1. Add yourself as the section lead on the audit template, document the relevant\nURL and date, and set a status\n1. For each user flow, identify each component that enables the user flow to\nfunction\n1. For each component, check against the test criteria for each row, and then\nassign it one of four ratings:\n   - **N/A**: This test does not apply to this component\n   - **Pass**: This component meets this test's criteria\n   - **Moderate**: This component does not meet this test's criteria, but can\n     worked around\n   - **Critical**: This component does not meet this test's criteria, and cannot\n     be worked around\n1. Once a component is completed, update its status\n1. Continue until all user flows have been audited\n\nUse the Notes sheet to leave per-cell comments when necessary, referencing them\nwith a link. The next steps for an audit are handled on a per-project basis.\n\n[accessibility audit template]: https://www.fsb.org.uk/resources/article/accessibility-audit-template-MCTMWUV4Z27FEXRANM566TOZXNOE\n[accesslint]: https://github.com/marketplace/accesslint\n[axe]: https://www.deque.com/axe/axe-for-web/integrations/\n[axe's browser extensions]: https://www.deque.com/axe/axe-for-web/\n[minimum contrast ratio]: https://webaim.org/resources/linkcontrastchecker/\n[manual usability testing]: https://www.smashingmagazine.com/2018/09/importance-manual-accessibility-testing/\n[nvda]: https://a11yproject.com/posts/getting-started-with-nvda/\n[accessibility insights]: https://accessibilityinsights.io\n[simple and direct]: https://datayze.com/readability-analyzer.php\n[vestibular and seizure triggers]: https://alistapart.com/article/designing-safer-web-animation-for-motion-sensitivity/\n[voiceover]: https://a11yproject.com/posts/getting-started-with-voiceover/\n[wave]: https://wave.webaim.org/extension/\n[web content accessibility guideline (wcag)]: https://www.w3.org/WAI/standards-guidelines/wcag/\n"
  },
  {
    "path": "android/README.md",
    "content": "# Android\n\n- Properties of views should be alphabetized, with the exception of `id`,\n  `layout_width`, and `layout_height` which should be placed first in that\n  order.\n- Use Kotlin for all new code.\n- Prefer pull request reviews from other Android developers but be open to\n  reviews from iOS and React Native developers as well.\n- Prefer non-null types.\n- Use string resources for all user-visible text.\n- Prefer vector drawables over PNGs or JPEGs.\n- Prefer Model-View-ViewModel (MVVM) for your app architecture.\n- Prefer `.forEach` over the `for` keyword.\n- Document each `@SuppressLint` with a comment.\n"
  },
  {
    "path": "android/android_layout.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout\n  xmlns:android=\"http://schemas.android.com/apk/res/android\"\n  android:layout_width=\"match_parent\"\n  android:layout_height=\"match_parent\"\n  >\n  <TextView\n    android:id=\"@+id/system_name\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"48sp\"\n    android:background=\"@color/brand_red\"\n    android:gravity=\"center_vertical\"\n    android:layout_alignBottom=\"@id/system_image\"\n    android:layout_alignLeft=\"@id/system_image\"\n    android:paddingLeft=\"12dp\"\n    android:textColor=\"@color/base_font_color\"\n    android:textSize=\"18sp\"\n    />\n</LinearLayout>\n"
  },
  {
    "path": "bash/README.md",
    "content": "# Bash\n\nIn addition to [shell](/shell/) best practices:\n\n- Prefer `${var,,}` and `${var^^}` over `tr` for changing case.\n- Prefer `${var//from/to}` over `sed` for simple string replacements.\n- Prefer `[[` over `test` or `[`.\n- Prefer process substitution over a pipe in `while read` loops.\n- Use `((` or `let`, not `$((` when you don't need the result\n"
  },
  {
    "path": "code-review/README.md",
    "content": "# Code Review\n\nA guide for reviewing code and having your code reviewed.\n\nWatch a presentation that covers this material from [Derek Prior at RailsConf 2015](https://www.youtube.com/watch?v=PJjmw9TRB7s).\n\n## Everyone\n\n- **Accept that many programming decisions are opinions**\n  - Discuss tradeoffs, which you prefer, and reach a resolution quickly.\n\n- **Ask good questions; don't make demands**\n  - \"What do you think about naming this `:user_id`?\"\n\n- **Good questions avoid judgment and avoid assumptions about the author's\n  perspective**\n- **Ask for clarification**\n  - \"I didn't understand. Can you clarify?\"\n\n- **Avoid selective ownership of code**\n  - \"Mine\", \"not mine\", \"yours\"\n\n- **Avoid using terms that could be seen as referring to personal traits**\n  - \"Dumb\", \"stupid\".\n  - Assume everyone is intelligent and well-meaning.\n\n- **Avoid diminishing words**\n  - \"simply\", \"simple\", \"just\"\n\n- **Be explicit**\n  - Remember people don't always understand your intentions online.\n\n- **When disagreeing, provide alternative solutions**\n  - Don't [simply reject an idea][dont-mcblock-me]. [Explain your reasoning](https://thoughtbot.com/blog/don-t-review-prs-like-a-space-wizard) and [suggest alternative approaches](https://github.com/thoughtbot/guides/pull/762#discussion_r2135772338).\n\n- **Be humble**\n  - \"I'm not sure - let's look it up.\"\n\n- **Don't use hyperbole**\n  - \"Always\", \"never\", \"endlessly\", \"nothing\"\n\n- **Don't use sarcasm**\n- **Keep it real**\n  - If emoji, animated gifs, or humor aren't you, don't force them.\n  - If they are, use them with aplomb.\n\n- **Talk synchronously if there are too many \"I didn't understand\" or \"Alternative solution:\" comments**\n  - Chat, screen-sharing, in person\n  - Post a follow-up comment summarizing the discussion.\n\n- **If you learned something new, share your appreciation**\n  - \"I did not know about this. Thank you for sharing it.\"\n\n- **Avoid the \"since you're at it\" attitude**\n  - If you would like to recommend a code change unrelated to the current\n  pull request, suggest it in the appropriate place or open a ticket for it\n  (on Trello, JIRA, GitHub project...)\n\n## Having Your Code Reviewed\n\n- **Be grateful for the reviewer's suggestions**\n  - \"Good call. I'll make that change.\"\n\n- **Be aware that it can be [challenging to convey emotion and intention online]**\n  - You may want to consider [using labels] to convey intention and tone.\n\n- **Explain why the code exists**\n  - \"It's like that because of these reasons. Would it be more clear if I rename this class/file/method/variable?\"\n\n- **Extract some changes and refactoring into future tickets/stories**\n- **When making visual changes, include screenshots or screencasts to show the effect of the changes**\n  - You may want to consider before/after screenshots or screencasts whenever applicable.\n\n- **Link to the code review from the ticket/story**\n  - \"Ready for review: `https://github.com/organization/project/pull/1`\n\n- **Push commits based on earlier rounds of feedback as isolated commits to the branch**\n  - Do not squash until the branch is ready to merge.\n  - Reviewers should be able to read individual updates based on their earlier feedback.\n\n- **Seek to understand the reviewer's perspective**\n- **Try to respond to every comment**\n- **Wait to merge the branch until continuous integration tells you the test suite is green in the branch**\n  - TDDium, Travis CI, CircleCI, GitHub Actions, etc.\n\n- **Merge once you feel confident in the code and its impact on the project**\n- **Final editorial control rests with the pull request author**\n\n- **Recognize the work of your teammates when you are pairing**\n  - Use `Co-Authored-By: <name> <email>` at the end of your commit message.\n\n## Reviewing Code\n\nUnderstand why the change is necessary (fixes a bug, improves the user experience, refactors the existing code).\n\nThen:\n\n- **Communicate which ideas you feel strongly about and those you don't**\n- **Identify ways to simplify the code while still solving the problem**\n- **If discussions turn too philosophical or academic, move the discussion offline to a regular Friday afternoon technique discussion**\n  - In the meantime, let the author make the final decision on alternative implementations.\n\n- **Offer alternative implementations**\n  - But assume the author already considered them.\n  - \"What do you think about using a custom validator here?\"\n\n- **Seek to understand the author's perspective**\n- **Approve the pull request**\n- **Remember that you are here to provide feedback, not to be a gatekeeper**\n- When suggesting changes using the \"Add a suggestion\" feature:\n  - **Communicate clearly which lines you suggest adding/removing**\n  - **Test the suggested changes to validate it works whenever possible**\n  - **When not possible, let the pull request author know that you did not test the suggestion**\n    - This applies to code and information in general.\n    - Be cautious with information you got from an unofficial source _like an LLM or blog post_.\n  - **Provide some context to let the author know why you're suggesting the change**\n\n## Style Comments\n\nReviewers should comment on missed style guidelines. Example comment:\n\n    > Order resourceful routes alphabetically by name.\n\nAn example response to style comments:\n\n    Whoops. Good catch, thanks. Fixed in a4994ec.\n\nIf you disagree with a guideline, open an issue on the guides repo rather than debating it within the code review. In the meantime, apply the guideline. It's often helpful to set up a linter like [standard] to format code automatically.\n\nThis helps us have more meaningful conversations on PRs rather than debating personal style preferences.\n\n- **Leave one comment only, for multiple stylistic offenses of the same kind**\n  - If there are a few occurrences of the same change needed, do not\n  leave multiple comments for the same change, rather suggest running the linter,\n  and/or leave one comment only, mentioning the line and elsewhere,\n  as long as the other files are being edited in the pull request.\n\n[challenging to convey emotion and intention online]: https://thoughtbot.com/blog/empathy-online\n[using labels]: https://conventionalcomments.org\n[standard]: https://github.com/testdouble/standard\n[dont-mcblock-me]: https://www.schneems.com/2025/06/03/dont-mcblock-me\n"
  },
  {
    "path": "css/README.md",
    "content": "# CSS Best Practices\n\n- Document the project's CSS architecture (the README, component library or\n  style guide are good places to do this), including things such as:\n  - Organization of stylesheet directories and Sass partials\n  - Selector naming convention\n  - Code linting tools and configuration\n  - Browser support\n- Use Sass.\n- Use [Autoprefixer] to generate vendor prefixes based on the project-specific\n  browser support that is needed.\n- Prefer `overflow: auto` to `overflow: scroll`, because `scroll` will always\n  display scrollbars outside of macOS, even when content fits in the container.\n- [Create breakpoints] when the content \"breaks,\" and is awkward or difficult to\n  read,\n  - Avoid creating breakpoints that target specific devices\n  - Prefer `em` units instead of `px` for breakpoint values\n  - Start with the smallest viewport size and work upwards using\n    `min-width`/`min-height`\n- Use [double colon syntax] for pseudo-elements\n\n[autoprefixer]: https://github.com/postcss/autoprefixer\n[create breakpoints]: http://bradfrost.com/blog/post/7-habits-of-highly-effective-media-queries/\n[double colon syntax]: https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-elements#Syntax\n\n## Linting\n\n- Use stylelint to lint CSS & Sass\n  - We maintain a [sharable stylelint configuration] which enforces our guides\n    found in this repo\n\n[sharable stylelint configuration]: https://github.com/thoughtbot/stylelint-config\n\n## Selectors\n\n### Selector specificity\n\n- Don't use ID selectors.\n- Avoid over-qualified selectors, e.g. `h1.page-title`.\n\n<details>\n\n#### Code examples\n\n`h1.page-title` carries a specificity of 2, but can be reduced to 1 by removing\nthe `h1` type selector:\n\n```diff\n-h1.page-title\n+.page-title {\n   // …\n }\n```\n\n#### Motivation\n\nUsing an ID in a selector increases its specificity, making it more difficult to\nwork with alongside class selectors. Furthermore, because IDs must be unique\nwithin an HTML document, using them as CSS selectors limits reusability.\n\n#### Resources\n\n- Learn about [how specificity is calculated].\n\n[how specificity is calculated]: https://www.w3.org/TR/selectors-3/#specificity\n\n</details>\n\n### Selector naming\n\n- Use lowercase characters and hyphens (sometimes referred to as hyphen-case,\n  dash-case, or kebab-case) when naming selectors.\n- Be consistent about naming conventions. For instance, if a project is using\n  BEM, continue using it, and if it's not, don't introduce it.\n- Don't uses Sass parent selectors (`&`) to concatenate selector names.\n\n<details>\n\n#### Code examples\n\nUse lowercase characters and hyphens in selector names:\n\n```scss\n.class-name {\n  // …\n}\n```\n\nDon't concatenate selector names:\n\n```scss\n.class {\n  &__child-class {\n    // …\n  }\n}\n```\n\n#### Motivation\n\nConcatenating selector names makes it more difficult to search and find\nselectors in the codebase.\n\n</details>\n\n## Other style guides\n\n- [Google HTML/CSS Style Guide](https://google.github.io/styleguide/htmlcssguide.html)\n- [Principles of writing consistent, idiomatic CSS](https://github.com/necolas/idiomatic-css)\n- [My HTML/CSS coding style](https://csswizardry.com/2012/04/my-html-css-coding-style/)\n- [Improving Code Readability With CSS Styleguides](https://www.smashingmagazine.com/2008/05/improving-code-readability-with-css-styleguides/)\n- [Code Style Guide: CSS](https://github.com/ThinkUpLLC/ThinkUp/wiki/Code-Style-Guide:-CSS)\n- [CSS Coding Standards](https://developer.wordpress.org/coding-standards/wordpress-coding-standards/css/)\n- [Scalable and Modular Architecture for CSS](http://smacss.com/)\n"
  },
  {
    "path": "data/README.md",
    "content": "# Data\n\nA guide for managing a series of tubes.\n\n## Best Practices\n\n- Avoid automatic retries for non-idempotent operations.\n- Use at least once delivery with idempotent operations.\n- Use at most once delivery with non-idempotent operations.\n- Use stream processing for data which is not guaranteed to fit into memory.\n\n### Streaming\n\n- Avoid storing messages with different schemas in the same topic or queue.\n- Keep messages as small as possible.\n- Use as few distinct resources (CPU, Postgres, S3, HTTP requests) as possible\n  in each consumer.\n- Use constant memory to process streams when feasible.\n- When one message would perform more than one operation, instead have that\n  message append a new message for each operation.\n- When reading from the same queue with more than one consumer, ensure that it's\n  acceptable to process messages from that queue out of order.\n- When partitioning messages in a single topic, ensure that it's acceptable for\n  messages from different partitions to be processed out of order.\n\n## Glossary\n\n<dl>\n  <dt>Data Engineering</dt>\n  <dd>\n  The task of building infrastructure and process for\n  ingesting, processing, and aggregating data so that it can be displayed to users\n  or made available to data scientists.\n  </dd>\n\n  <dt>Data Science</dt>\n  <dd>\n  The practice of using statistics, machine learning, and other\n  tools to analyze data to discover trends and truths that can be used to provide\n  business intelligence.\n  </dd>\n\n  <dt>Batch Processing</dt>\n  <dd>\n  Processing large amounts of data at once. This is acceptable\n  for smaller amounts of data and can be simpler in terms of development and\n  deployment. Some batch processes can also be useful for \"recomputing the world\"\n  when you want to analyze existing data in a new way.\n  </dd>\n\n  <dt>Data Streaming</dt>\n  <dd>\n  Processing data in small chunks, one at a time, rather than\n  processing all data at once. Streaming is necessary for processing infinite\n  event streams. It's also useful for processing large amounts of data, because it\n  prevents memory overflows during processing and makes it easier to process data\n  in a distributed or real-time manner.\n  </dd>\n\n  <dt>Real-time</dt>\n  <dd>\n  Analyzing data and delivering results simultaneously so that stream\n  output is always visible. For example, real-time analytics will mean that the\n  system is constantly processing events (clicks, purchases, etc) and displaying\n  the latest results in a user interface.\n  </dd>\n\n  <dt>Parallel Processing</dt>\n  <dd>\n  Performing multiple tasks at the same time, for example\n  on different cores or processors. Parallel processing is necessary in order to\n  perform more than one computation at once; common uses are parsing or\n  aggregation.\n  </dd>\n\n  <dt>Concurrent Processing</dt>\n  <dd>\n  Managing multiple ongoing tasks at once without\n  necessarily processing more than one task in the same exact moment. Concurrent\n  processing is required in order to perform more than one effect at once, such as\n  waiting for multiple network requests to complete.\n  </dd>\n\n  <dt>Constant Memory</dt>\n  <dd>\n  Processing a stream where the amount of memory required does\n  not increase with the size of the stream.\n  </dd>\n\n  <dt>At Least Once Delivery</dt>\n  <dd>\n  A guarantee that a given message will be delivered at\n  least once, but may be delivered more than once. This is achieved in Kafka by\n  committing an offset after it's been fully processed and in RabbitMQ by\n  acknowledging a message after fully processing it.\n  </dd>\n\n  <dt>At Most Once Delivery</dt>\n  <dd>\n  A guarantee that a message will never be delivered more\n  than once, but may not be delivered at all. This is achieved in Kafka by\n  committing an offset before fully processing a message and in RabbitMQ by\n  acknowledging a message before fully processing it.\n  </dd>\n\n  <dt>Distributed Data Processing</dt>\n  <dd>\n  Breaking up data into partitions so that large\n  amounts of data can be processed by many machines simultaneously.\n  </dd>\n\n  <dt>Cluster</dt>\n  <dd>\n  Several computers (or virtual machines) grouped together to perform a\n  single task.\n  </dd>\n\n  <dt>Scala</dt>\n  <dd>\n  A programming language (like Ruby, Python, or JavaScript) which is fast\n  and has become popular for data-focused tasks. Scala runs on the Java Virtual\n  Machine, which is a high-performance engine for running languages like Scala\n  that compile into bytecode.\n  </dd>\n\n  <dt>Type Safety</dt>\n  <dd>\n  Languages that provide type safety (such as Scala) check the\n  program for possible errors as part of the compilation process, which allows\n  developers to prevent many types of bugs before being deployed.\n  </dd>\n\n  <dt>Spark</dt>\n  <dd>\n  A distributed computing engine for big data and data streams. Spark is\n  a Scala-focused framework for data engineering and data science.\n  </dd>\n\n  <dt>Kafka</dt>\n  <dd>\n  A distributed commit log for data streams. Many of the large data\n  systems deployed today use Kafka.\n  </dd>\n\n  <dt>Record Stream</dt>\n  <dd>\n  A stream where each message is an independent, unique record\n  which does not replace a previous record in the stream.\n  </dd>\n\n  <dt>Changelog Stream</dt>\n  <dd>\n  A stream where each message represents the latest state for\n  a particular entity.\n  </dd>\n\n  <dt>Topic</dt>\n  <dd>\n  In Kafka, a partitioned, append-only log of messages which can be\n  consumed in order by partition.\n  </dd>\n\n  <dt>Partition</dt>\n  <dd>\n  In Kafka, a way of breaking the messages of a topic into groups\n  which can be consumed in parallel by one or more workers.\n  </dd>\n\n  <dt>Queue</dt>\n  <dd>\n  In RabbitMQ, messages sent to an exchange are placed on a queue.\n  Messages on a queue can be consumed in parallel by one or more workers.\n  </dd>\n\n  <dt>Consumer</dt>\n  <dd>An application or process that reads from a data stream.</dd>\n\n  <dt>Producer</dt>\n  <dd>An application or process that writes to a data stream.</dd>\n</dl>\n"
  },
  {
    "path": "email/README.md",
    "content": "# Email\n\n- Use [SendGrid][] or [Amazon SES][] to deliver email in staging and production\n  environments.\n\n- Use a tool like [ActionMailer Preview][] to look at each created or updated\n  mailer view before merging.\n\n[actionmailer preview]: https://guides.rubyonrails.org/action_mailer_basics.html#previewing-and-testing-mailers\n[amazon ses]: https://thoughtbot.com/blog/deliver-email-with-amazon-ses-in-a-rails-app\n[sendgrid]: https://devcenter.heroku.com/articles/sendgrid\n"
  },
  {
    "path": "erb/README.md",
    "content": "# ERB\n\n[Sample](sample.html.erb)\n\n- When wrapping long lines, keep the method name on the same line as the ERB\n  interpolation operator and keep each method argument on its own line.\n- Use a trailing comma after each argument in a multi-line method call,\n  including the last item.\n- Prefer double quotes for attributes.\n"
  },
  {
    "path": "erb/sample.html.erb",
    "content": "<%= short_method_call_that_fits_on_one_line arguments %>\n\n<%= link_to(\n  some_object_with_a_long_name.title,\n  parent_object_child_object_path(some_object_with_a_long_name),\n) %>\n"
  },
  {
    "path": "general/README.md",
    "content": "# General Guidelines\n\nStyle and best practices that apply to all languages and frameworks.\n\n## Philosophy\n\n- These are not to be blindly followed; strive to understand these and ask when\n  in doubt.\n- Don't duplicate the functionality of a built-in library.\n- Don't swallow exceptions or \"fail silently.\"\n- Don't write code that guesses at future functionality.\n- Exceptions should be exceptional.\n- Keep the code simple.\n\n## Code Review\n\nUse a linter to automatically review your GitHub pull requests for style guide\nviolations.\n\n## Formatting\n\n- Break long lines after 80 characters.\n- Delete trailing spaces.\n- Don't misspell.\n- Use [Unix-style line endings] (`\\n`).\n- Use spaces around operators, except for unary operators, such as `!`.\n\n[unix-style line endings]: http://unix.stackexchange.com/questions/23903/should-i-end-my-text-script-files-with-a-newline\n\n## Naming\n\n- Avoid abbreviations.\n- Avoid object types in names (`user_array`, `email_method` `CalculatorClass`,\n  `ReportModule`).\n- Prefer naming classes after domain concepts rather than patterns they\n  implement (e.g. `Guest` vs `NullUser`, `CachedRequest` vs `RequestDecorator`).\n- Name the enumeration parameter the singular of the collection (`users.each { |user| greet(user) }`).\n- Name variables, methods, and classes to reveal intent. This includes documentation and\n  examples (e.g. don't use `foo`, `bar`, `baz` in examples).\n- Treat acronyms as words in names (`XmlHttpRequest` not `XMLHTTPRequest`), even\n  if the acronym is the entire name (`class Html` not `class HTML`).\n\n## Organization\n\n- Order methods so that caller methods are earlier in the file than the methods\n  they call.\n- Order methods so that methods are as close as possible to other methods they\n  call.\n"
  },
  {
    "path": "git/README.md",
    "content": "# Git\n\nA guide for programming within version control.\n\n## Best Practices\n\n- Avoid merge commits by using a [rebase workflow].\n- Squash multiple trivial commits into a single commit.\n- Write a [good commit message].\n\n[rebase workflow]: https://github.com/thoughtbot/guides/blob/main/git/README.md#merge\n[good commit message]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html\n\n## Maintain a Repo\n\n- Avoid including files in source control that are specific to your development\n  machine or process.\n- Delete local and remote feature branches after merging.\n- Perform work in a feature branch.\n- Rebase frequently to incorporate upstream changes.\n- Use a [pull request] for code reviews.\n\n[pull request]: https://help.github.com/articles/using-pull-requests/\n\n## Write a Feature\n\nCreate a local feature branch based off `main`.\n\n```console\ngit checkout main\ngit pull\ngit checkout -b <branch-name>\n```\n\nRebase frequently to incorporate upstream changes.\n\n```console\ngit fetch origin\ngit rebase origin/main\n```\n\nResolve conflicts. When feature is complete and tests pass, stage the changes.\n\n```console\ngit add --all\n```\n\nWhen you've staged the changes, commit them.\n\n```console\ngit status\ngit commit --verbose\n```\n\nWrite a [good commit message]. Example format:\n\n```text\nPresent-tense summary under 50 characters\n\n- More information about commit (under 72 characters).\n- More information about commit (under 72 characters).\n\nhttp://project.management-system.com/ticket/123\n```\n\nIf you've created more than one commit, [use `git rebase` interactively] to squash them into cohesive commits with good\nmessages:\n\n```console\ngit rebase -i origin/main\n```\n\nShare your branch.\n\n```console\ngit push origin <branch-name>\n```\n\nSubmit a [GitHub pull request].\n\nAsk for a code review in the project's chat room.\n\n[use `git rebase` interactively]: https://help.github.com/articles/about-git-rebase/\n[github pull request]: https://help.github.com/articles/using-pull-requests/\n\n## Review Code\n\nA team member other than the author reviews the pull request. They follow [Code\nReview](/code-review/) guidelines to avoid miscommunication.\n\nThey make comments and ask questions directly on lines of code in the GitHub web\ninterface or in the project's chat room.\n\nFor changes which they can make themselves, they check out the branch.\n\n```console\ngit checkout <branch-name>\n./bin/setup\ngit diff staging/main..HEAD\n```\n\nThey make small changes right in the branch, test the feature on their machine,\nrun tests, commit, and push.\n\nWhen satisfied, they comment on the pull request `Ready to merge.`\n\n## Merge\n\nRebase interactively. Squash commits like \"Fix whitespace\" into one or a small\nnumber of valuable commit(s). Edit commit messages to reveal intent. Run tests.\n\n```console\ngit fetch origin\ngit rebase -i origin/main\n```\n\nForce push your branch. This allows GitHub to automatically close your pull\nrequest and mark it as merged when your commit(s) are pushed to `main`. It also\nmakes it possible to [find the pull request] that brought in your changes.\n\n```console\ngit push --force-with-lease origin <branch-name>\n```\n\nView a list of new commits. View changed files. Merge branch into `main`.\n\n```console\ngit log origin/main..<branch-name>\ngit diff --stat origin/main\ngit checkout main\ngit merge <branch-name> --ff-only\ngit push\n```\n\nDelete your remote feature branch.\n\n```console\ngit push origin --delete <branch-name>\n```\n\nDelete your local feature branch.\n\n```console\ngit branch --delete <branch-name>\n```\n\n[find the pull request]: http://stackoverflow.com/a/17819027\n"
  },
  {
    "path": "graphql/README.md",
    "content": "# GraphQL\n\nA guide for building GraphQL servers and clients.\n\n## Learning\n\nA curated list of resources for learning GraphQL.\n\n- **[Official GraphQL Learning Site]**\n- **[How To GraphQL]** Online tutorial for both server and client GraphQL in\n  multiple programming languages.\n- **[Learning GraphQL]** A clear introduction to GraphQL technology and a walk\n  through of building a GraphQL server.\n- **[GraphQL: A Query Language for your API]** Presentation introducing GraphQL\n  to thoughtbot.\n\n[official graphql learning site]: https://graphql.org/learn/\n[how to graphql]: https://www.howtographql.com/\n[learning graphql]: http://shop.oreilly.com/product/0636920137269.do\n[graphql: a query language for your api]: https://www.dropbox.com/s/svqe68hpdiixf0g/presentation.pdf?dl=0\n\n## Public GraphQL APIs\n\nPublicly available GraphQL APIs allowing you to explore how GraphQL is and can\nbe used.\n\n- **[GitHub GraphQL API Explorer]**\n- **[Star Wars GraphQL]**\n\n[github graphql api explorer]: https://developer.github.com/v4/explorer/\n[star wars graphql]: https://graphql.org/swapi-graphql/\n\n## Tools\n\n- **[GraphiQL].** An Electron-based \"web IDE\" for interacting with GraphQL APIs.\n  GraphiQL can also be served as a page in an application.\n- **[GraphQL Playground]** An Electron-based \"web IDE\" for interacting with\n  GraphQL APIs. Intends to expand upon GraphiQL.\n- **[Insomnia]** An HTTP client with solid GraphQL support.\n- **[Apollo Client Dev Tools]** Chrome Extension offering developer tools for\n  Apollo projects.\n\n[graphiql]: https://github.com/graphql/graphiql\n[graphql playground]: https://github.com/prisma/graphql-playground\n[insomnia]: https://insomnia.rest/\n[apollo client dev tools]: https://www.apollographql.com/docs/react/features/developer-tooling\n\n## Best Practices\n\n- Follow the latest version of the [GraphQL specification].\n- When serving over HTTP, respond with a 200 OK status code to all GraphQL\n  queries.\n- If a client or server error occurs, use the `errors` key in the GraphQL\n  response.\n- If a user-facing error occurs (such as invalid user input), use the `data` key\n  in the GraphQL response.\n- If a mutation can fail because of a user error, use a union type to describe\n  the possible outcomes.\n- If there is an authenticated user, provide the user in the context for the\n  resolver.\n- Provide the updated object as a field in mutations.\n- Provide the ID of the deleted object as a field in mutations that delete\n  objects.\n- Use JSON as a default transport format.\n- Avoid returning null from operations. [#630]\n\n[graphql specification]: https://graphql.github.io/graphql-spec/\n[#630]: https://github.com/thoughtbot/guides/pull/630\n"
  },
  {
    "path": "html/README.md",
    "content": "# HTML\n\n- Use the [W3C's Markup Validation Service][html-validator] to validate HTML\n- Prefer double quotes for attributes.\n- Use lowercase text for elements and attributes\n- Use double quotes to wrap element attributes\n- Use closing tags for all [normal elements]\n- Prefer a HTML5 doctype\n- Ensure elements are scoped properly\n  - Elements such as `<title>` and `<meta>` must be placed within the page's\n    `<head>` element\n  - Elements such as `<p>`, `<nav>`, `<div>`, etc. should be placed within the\n    page's `<body>` element\n- Ensure `id`s are unique\n- Prefer appending attribute values instead of declaring redundant attribute\n  names\n  - For example, if adding a class of `c-card--featured`, add it to the existing\n    class declaration (`class=\"c-card c-card--featured\"`, not `class=\"c-card\"\n    class=\"c-card--featured\"`)\n- Avoid using emoji and other exotic characters as values for attributes such as\n  `class`, `id`, `data`, and `aria-*`.\n- Avoid restricting viewport zooming\n- Ensure [parent elements contain no more than 60 child elements]\n- Use `<button>` elements instead of `<a>` elements for actions.\n  - Use `type=\"button\"` for button elements used outside of forms to prevent the\n    browser from trying to submit form data\n  - Use a `href` attribute for `<a>` elements with a valid location\n- Ensure heading elements are used to section content, and heading levels are\n  not skipped\n\n[html-validator]: https://validator.w3.org/\n[normal elements]: https://html.spec.whatwg.org/multipage/syntax.html#normal-elements\n[parent elements contain no more than 60 child elements]: https://developers.google.com/web/tools/lighthouse/audits/dom-size\n"
  },
  {
    "path": "ios/README.md",
    "content": "# iOS Protocol\n\nA guide for making iPhone and iPad apps with aplomb.\n\n## Set Up Laptop\n\nInstall the latest version of Xcode from the App Store.\n\n## Create App\n\nGet Liftoff.\n\n```console\nbrew tap thoughtbot/formulae\nbrew install liftoff\n```\n\nGet CocoaPods\n\n```console\n[sudo] gem install cocoapods\n```\n\nCreate the app.\n\n```console\nliftoff\n```\n\n- Be sure to set an appropriate 2 or 3 letter class prefix.\n\n## Set Up App\n\nGet the code.\n\n```console\ngit clone git@github.com:organization/app.git\n```\n\nInstall the app's dependencies.\n\n```console\ncd project\npod install\n```\n\n## Git Protocol\n\nFollow the normal [Git protocol](/git/).\n\n## Product Review\n\nFollow the normal [Product Review protocol](/product-review/).\n\n## Code Review\n\nFollow the normal [Code Review guidelines](/code-review/). When reviewing\nothers' iOS work, look in particular for:\n\n- Review that ViewControllers are adhering to the Single Responsibility Principle\n- Watch for CoreData thread boundary violations\n- Watch for potential retain cycles with blocks\n- Ensure that methods that require parameters are using `NSParameterAssert()`\n\n## Submit to the App Store\n\n- Determine if you need to [report your app's use of encryption](https://getonthestore.com/export-compliance/).\n"
  },
  {
    "path": "javascript-typescript/.eslintrc.json",
    "content": "{\n  \"extends\": \"@thoughtbot/eslint-config\"\n}\n"
  },
  {
    "path": "javascript-typescript/README.md",
    "content": "# JavaScript & TypeScript\n\n## JavaScript\n\n[Sample](sample.js)\n\n- Use [TypeScript](#typescript)\n- Use the latest stable JavaScript syntax with a transpiler, such as [babel].\n- Use [ESLint] and [Prettier] for auto-formatting and auto-fixing\n- Use [Jest] for unit testing\n- Prefer ES6 classes over prototypes.\n- Use strict equality checks (`===` and `!==`) except when comparing against\n  (`null` or `undefined`).\n- Prefer [arrow functions] `=>`, over the `function` keyword except when\n  defining classes or methods.\n- Prefer ES6 [destructuring] over object literal notation.\n- Use ES6 [spread] and [rest] operator wherever possible for a cleaner code.\n- Use `PascalCase` for classes, `lowerCamelCase` for variables and functions,\n  `SCREAMING_SNAKE_CASE` for constants, `_singleLeadingUnderscore` for private\n  variables and functions.\n- Prefer [template strings] over string concatenation.\n- Prefer promises over callbacks.\n- Prefer array functions like `forEach`, `map`, `filter` and `reduce` over `for/while` loops.\n- Use `const` for declaring variables that will never be re-assigned, and `let`\n  otherwise.\n- Avoid `var` to declare variables.\n- Prefer [async/await] over traditional promise syntax\n- Use the [Nullish coalescing operator] `??`\n\n## TypeScript\n\n- Use TypeScript in [strict mode]\n- Prefer [Functions] over [Classes]\n- Use `PascalCase` for [Interfaces] and [Type Aliases]\n- Use [readonly] properties where applicable\n- Use [const Assertions] where applicable to avoid type widening\n- Avoid [Mixins]\n- Avoid [Decorators]\n- Avoid [Overloading Functions]\n- Prefer [Optional Properties] in an interface rather than declaring the\n  property type as `T | undefined`\n- Prefer explicitly defining interfaces over [Extending Interfaces]\n- Avoid the use of the [any] type\n- Avoid the [Non-null assertion operator]\n- Avoid [Type Assertions]\n- Prefer the `as`-syntax for [Type Assertions] over the angle-bracket syntax\n- Prefer [Type Guards] over [Type Assertions]\n- Prefer [Union Types], [Lookup Types], [Mapped Types] and [const Assertions]\n  over [Enums]\n- Prefer [arrow functions] `=>`, over the `function` keyword except when using\n  [Generics]\n\n## Formatting\n\n- Use [Prettier defaults](https://prettier.io/docs/en/options.html) with the following additional configuration (.prettierrc):\n\n  ```json\n  {\n    \"singleQuote\": true\n  }\n  ```\n  \n  This configuration includes:\n  - Use semicolons at the end of each statement ([sample](/javascript/sample.js#L5))\n  - Prefer single quotes ([sample](/javascript/sample.js#L11))\n  - Use a trailing comma after each item in a multi-line array or object literal, including the last item. ([sample](/javascript/sample.js#L11))\n\nIf ESLint is used along with Prettier, the ESLInt plugin [eslint-config-prettier](https://github.com/prettier/eslint-config-prettier) should also be used to turn off all ESLint style rules that are already handled by Prettier.\n\n[babel]: https://babeljs.io/\n[eslint]: https://eslint.org/\n[prettier]: https://prettier.io/\n[jest]: /testing-jest/\n[template strings]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/template_strings\n[arrow functions]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions\n[destructuring]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment\n[spread]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax\n[rest]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters\n[functions]: https://www.typescriptlang.org/docs/handbook/2/functions.html\n[classes]: https://www.typescriptlang.org/docs/handbook/2/classes.html\n[readonly]: https://www.typescriptlang.org/docs/handbook/2/objects.html#readonly-properties\n[const Assertions]: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-4.html#const-assertions\n[overloading functions]: https://www.typescriptlang.org/docs/handbook/2/functions.html#function-overloads\n[async/await]: https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Async_await\n[optional properties]: https://www.typescriptlang.org/docs/handbook/2/objects.html#optional-properties\n[extending interfaces]: https://www.typescriptlang.org/docs/handbook/2/objects.html#extending-types\n[any]: https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#any\n[non-null assertion operator]: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-0.html#non-null-assertion-operator\n[type assertions]: https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#type-assertions\n[Nullish coalescing operator]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing\n[Type Guards]: https://www.typescriptlang.org/docs/handbook/2/narrowing.html#typeof-type-guards\n[generics]: https://www.typescriptlang.org/docs/handbook/2/generics.html\n[strict mode]: https://www.typescriptlang.org/tsconfig/#strict\n[mixins]: https://www.typescriptlang.org/docs/handbook/mixins.html\n[decorators]: https://www.typescriptlang.org/docs/handbook/decorators.html\n[union types]: https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#union-types\n[lookup types]: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-1.html#keyof-and-lookup-types\n[mapped types]: https://www.typescriptlang.org/docs/handbook/2/mapped-types.html\n[enums]: https://www.typescriptlang.org/docs/handbook/enums.html\n[interfaces]: https://www.typescriptlang.org/docs/handbook/2/objects.html\n[type aliases]: https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#type-aliases\n"
  },
  {
    "path": "javascript-typescript/sample.js",
    "content": "object = { spacing: true }\n\nclass Cat {\n  canBark() {\n    return false;\n  }\n}\n\nconst somePerson = {\n  name: 'Ralph',\n  company: 'thoughtbot',\n};\n"
  },
  {
    "path": "lefthook.yml",
    "content": "# EXAMPLE USAGE:\n#\n#   Refer for explanation to following link:\n#   https://lefthook.dev/configuration/\n#\n# pre-push:\n#   jobs:\n#     - name: packages audit\n#       tags:\n#         - frontend\n#         - security\n#       run: yarn audit\n#\n#     - name: gems audit\n#       tags:\n#         - backend\n#         - security\n#       run: bundle audit\n#\n# pre-commit:\n#   parallel: true\n#   jobs:\n#     - run: yarn eslint {staged_files}\n#       glob: \"*.{js,ts,jsx,tsx}\"\n#\n#     - name: rubocop\n#       glob: \"*.rb\"\n#       exclude:\n#         - config/application.rb\n#         - config/routes.rb\n#       run: bundle exec rubocop --force-exclusion {all_files}\n#\n#     - name: govet\n#       files: git ls-files -m\n#       glob: \"*.go\"\n#       run: go vet {files}\n#\n#     - script: \"hello.js\"\n#       runner: node\n#\n#     - script: \"hello.go\"\n#       runner: go run\npre-commit:\n  parallel: true\n  jobs:\n    - name: Lint Markdown\n      glob: \"*.md\"\n      group:\n        parallel: true\n        jobs:\n          - name: Markdownlint\n            run: npx markdownlint-cli2 {staged_files}\n"
  },
  {
    "path": "mise.toml",
    "content": "[tools]\nnode = \"latest\"\n"
  },
  {
    "path": "object-oriented-design/README.md",
    "content": "# Object-Oriented Design\n\n- Avoid global variables.\n- Avoid long parameter lists.\n- Limit dependencies of an object (entities an object depends on).\n- Limit an object's dependents (entities that depend on an object).\n- Prefer composition over inheritance.\n- Prefer small methods. Between one and five lines is best.\n- Prefer small classes with a single, well-defined responsibility. When a class\n  exceeds 100 lines, it may be doing too many things.\n- [Tell, don't ask].\n\n[tell, don't ask]: https://thoughtbot.com/blog/tell-dont-ask\n"
  },
  {
    "path": "open-source/README.md",
    "content": "# Open Source Protocol\n\nA guide for releasing and maintaining open source projects.\n\n## Accepting a GitHub Pull Request\n\nGiven you have this in your `~/.gitconfig`:\n\n```text\n[alias]\n  co-pr = !sh -c 'git fetch origin pull/$1/head:pr/$1 && git checkout pr/$1' -\n```\n\nCheck out the code by its GitHub pull request number:\n\n```console\ngit co-pr 123\n```\n\nRebase interactively, squash, and potentially improve commit messages:\n\n```console\ngit rebase -i main\n```\n\nLook at changes:\n\n```console\ngit diff origin/main\n```\n\nRun the code and tests. For example, on a Ruby project:\n\n```console\nbundle\nrake\n```\n\nMerge code into main:\n\n```console\ngit checkout main\ngit merge pr/123 --ff-only\n```\n\nPush:\n\n```console\ngit push origin main\n```\n\nClean up:\n\n```console\ngit branch -D pr/123\n```\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"guides\",\n  \"description\": \"[![Reviewed by Hound](https://img.shields.io/badge/Reviewed_by-Hound-8E64B0.svg)](https://houndci.com)\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/thoughtbot/guides.git\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/thoughtbot/guides/issues\"\n  },\n  \"homepage\": \"https://github.com/thoughtbot/guides#readme\",\n  \"dependencies\": {\n    \"markdownlint-cli2\": \"^0.19.0\"\n  },\n  \"scripts\": {\n    \"lint\": \"markdownlint-cli2 \\\"./**/*.md\\\"\"\n  },\n  \"devDependencies\": {\n    \"lefthook\": \"^1.11.3\"\n  }\n}\n"
  },
  {
    "path": "postgres/README.md",
    "content": "# Postgres\n\n- Avoid multicolumn indexes. Postgres [combines multiple indexes] efficiently.\n  Optimize later with a [compound index] if needed.\n- Consider a [partial index] for queries on booleans.\n- Avoid JSONB columns unless you have a strong reason to store an entire JSON\n  document from an external source.\n- Use [uppercase for SQL key words and lowercase for SQL identifiers].\n\n[uppercase for sql key words and lowercase for sql identifiers]: http://www.postgresql.org/docs/9.2/static/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS\n[combines multiple indexes]: http://www.postgresql.org/docs/9.1/static/indexes-bitmap-scans.html\n[compound index]: http://www.postgresql.org/docs/9.2/static/indexes-bitmap-scans.html\n[partial index]: http://www.postgresql.org/docs/9.1/static/indexes-partial.html\n"
  },
  {
    "path": "product-review/README.md",
    "content": "# Product Review\n\nCut down cycle time and focus on the user by getting a teammate to review your\nchanges to the product before you get a code review or deploy to staging.\n\nFor each change, choose one of four techniques:\n\n- In-person\n- Screencast\n- SSH tunnel\n- Video chat and screen-share\n\n## In-person\n\nIf they are sitting next to you, have them review the changes in person.\n\n## Screencast\n\nUse [Licecap] to share a screencast gif in the project's [Basecamp].\n\n[licecap]: http://www.cockos.com/licecap/\n[basecamp]: https://basecamp.com/\n\n## SSH tunnel\n\nUse [ngrok] to set up an SSH tunnel to your work in progress on your laptop:\n\n```console\nngrok -subdomain=feature-branch-name 3000\n```\n\nThen, share the ngrok URL in the project's Basecamp.\n\n[ngrok]: https://ngrok.com/\n\n## Video chat and screenshare\n\nStart a Google Hangout in the project's Basecamp:\n\n```text\n/hangout\n```\n"
  },
  {
    "path": "python/README.md",
    "content": "# Python\n\n- Follow [PEP 8].\n\n[pep 8]: http://www.python.org/dev/peps/pep-0008/\n"
  },
  {
    "path": "rails/README.md",
    "content": "# Rails\n\n## Application\n\n- Name initializers for their gem name.\n- Use `lib` for code that is not app-specific and could later be extracted into a gem.\n- Use `app/jobs` for code that doesn't need to return anything and can be run asynchronously.\n- Generate necessary [Spring binstubs] for the project, such as `rake` and\n  `rspec`, and add them to version control.\n- Use the [`.ruby-version`] file convention to specify the Ruby version and patch level for a project.\n- Prefer `cookies.signed` over `cookies` to [prevent tampering].\n- Use `ENV.fetch` for environment variables instead of `ENV[]`so that unset\n  environment variables are detected on deploy.\n\n[spring binstubs]: https://github.com/sstephenson/rbenv/wiki/Understanding-binstubs\n[`.ruby-version`]: https://gist.github.com/fnichol/1912050\n[prevent tampering]: https://www.bigbinary.com/blog/cookies-on-rails\n\n## Routes\n\n- Avoid the `:except` option in routes.\n- Avoid `member` and `collection` routes.\n- Order resourceful routes alphabetically by name.\n- Use the `:only` option to explicitly state exposed routes.\n- Prefer [resource routing] over [generating routes] individually\n- Use `_url` suffixes for named routes in mailer views and [redirects]. Use `_path` suffixes for named routes everywhere else.\n\n[resource routing]: https://guides.rubyonrails.org/routing.html#resource-routing-the-rails-default\n[generating routes]: https://guides.rubyonrails.org/routing.html#generating-paths-and-urls-from-code\n[redirects]: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.30\n\n## Views and UI\n\n- Put application-wide partials in the [`app/views/application`] directory.\n- Use the default `render 'partial'` syntax over `render partial: 'partial'`.\n- Use `link_to` for GET requests, and `button_to` for other HTTP verbs.\n- Don't reference a model class directly from a view.\n- Don't use instance variables in partials. Pass local variables to partials from view templates.\n- Use only one instance variable in each view.\n\n[`app/views/application`]: http://railscasts.com/episodes/269-template-inheritance\n\n## Controllers\n\n- Use private instead of protected when defining controller methods.\n- Order controller contents: filters, public methods, private methods.\n- Avoid instantiating more than one object in controllers.\n\n## Models\n\nGuidance on ActiveRecord, ActiveModel, and other model objects.\n\n- Order ActiveRecord associations alphabetically by association type, then\n  attribute name. [Example](/rails/sample.rb#L2-L4).\n- Order ActiveRecord validations alphabetically by attribute name.\n- Order ActiveRecord associations above ActiveRecord validations.\n- Order model contents: constants, macros, public methods, private methods.\n- Use `def self.method`, not the `scope :method` DSL. [#643](https://github.com/thoughtbot/guides/pull/643)\n- Use new-style `validates :name, presence: true` validations, and put all\n  validations for a given column together. [Example](/rails/sample.rb#L6).\n- Avoid bypassing validations with methods like `save(validate: false)`,\n  `update_attribute`, and `toggle`.\n- Avoid naming methods after database columns in the same class.\n- Don't return false from `ActiveModel` callbacks, but instead raise an exception.\n- Don't use SQL or SQL fragments (`where('inviter_id IS NOT NULL')`) outside of models.\n- Validate the associated `belongs_to` object (`user`), not the database column (`user_id`).\n- Use `touch: true` when declaring `belongs_to` relationships.\n- Use [Pundit][] when you need to restrict access to models and data.\n\n[Pundit]: https://github.com/varvet/pundit\n\n## Database and Persistence\n\n- Name date columns with `_on` suffixes.\n- Name datetime columns with `_at` suffixes.\n- Back boolean concepts like deleted? or published? with timestamps columns in the database `deleted_at`, `published_at`.\n  This can be valuable when you need to know **when** something took place. [Time for A Boolean](https://github.com/calebhearth/time_for_a_boolean) provides a nice interface for this.\n- Name time columns (referring to a time of day with no date) with `_time`\n  suffixes.\n- Keep `db/schema.rb` or `db/development_structure.sql` under version control.\n- Use `db/seeds.rb` for data that is required in all environments.\n- Use `development:db:seed` rake task for development environment seed data. [Example](/rails/how-to/seed-data.md).\n\n## Security\n\n- Set [config.sandbox_by_default][sandbox] to `true` in production-like environments to avoid accidental writing to the production database.\n\n[sandbox]: https://guides.rubyonrails.org/configuring.html#config-sandbox-by-default\n\n## Migrations\n\n[Sample](migration.rb)\n\n- Set an empty string as the default constraint for **non-required** string and text\n  fields. [Example](migration.rb#L6). [#159](https://github.com/thoughtbot/guides/pull/159)\n- Set an explicit [`on_delete` behavior for foreign keys].\n- Don't change a migration after it has been merged into `main` if the desired\n  change can be solved with another migration.\n- If there are default values, set them in migrations.\n- Use SQL, not `ActiveRecord` models, in migrations.\n- [Add foreign key constraints] in migrations.\n\n[`on_delete` behavior for foreign keys]: http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-add_foreign_key\n[add foreign key constraints]: http://thoughtbot.com/blog/referential-integrity-with-foreign-keys\n\n## Factories\n\n- [Use blocks](/ruby/sample_2.rb#L10) when declaring date and time attributes in FactoryBot factories.\n\n## Temporal\n\n- Prefer `Time.current` over `Time.now`\n- Prefer `Date.current` over `Date.today`\n- Prefer `Time.zone.parse(\"2014-07-04 16:05:37\")` over `Time.parse(\"2014-07-04\n  16:05:37\")`\n\n## Translations\n\n- Ensure that the application is setup to support multiple locales.\n- Ensure that the application raises an error when a translation is missing for a\n  given locale in development and tests.\n- Order i18n translations alphabetically by key name.\n\n## Email\n\n- Use the user's name in the `From` header and email in the `Reply-To` when\n  [delivering email on behalf of the app's users].\n\n[delivering email on behalf of the app's users]: http://thoughtbot.com/blog/delivering-email-on-behalf-of-users\n\n## Code Review\n\nFollow the normal [Code Review guidelines](/code-review/). When reviewing\nothers' Rails work, look in particular for:\n\n- Review data integrity closely, such as migrations that make irreversible\n  changes to the data, and whether there is a related todo to make a database\n  backup during the staging and production deploys.\n- Review SQL queries for potential SQL injection.\n- Review whether dependency upgrades include a reason in the commit message,\n  such as a link to the dependency's `ChangeLog` or `NEWS` file.\n- Review whether new database indexes are necessary if new columns or SQL\n  queries were added.\n- Review whether new scheduler (`cron`) tasks have been added and whether there\n  is a related todo in the project management system to add it during the\n  staging and production deploys.\n\n## Asset Management\n\n- Use [ActiveStorage] to manage file uploads that live on ActiveRecord objects.\n- Don't use live storage backends like S3 or Azure in tests.\n\n[ActiveStorage]: https://guides.rubyonrails.org/active_storage_overview.html\n\n## Testing\n\n- Prefer [webmock][] over [VCR][].\n\n[webmock]: https://github.com/webmock/webmock\n[VCR]: https://github.com/vcr/vcr\n\n## How To Guides\n\n- [Start a New Rails App](./how-to/start_a_new_rails_app.md)\n- [Deploy a Rails App to Heroku](./how-to/deploy_a_rails_app_to_heroku.md)\n- [Feature-test JavaScript in a Rails App](./how-to/feature_test_javascript_in_a_rails_app.md)\n"
  },
  {
    "path": "rails/ai-rules/CLAUDE.md",
    "content": "# thoughtbot project architecture and coding standards for Rails development using agents\n\nSee the folder `rules` for language-specific guidelines, testing conventions,\nand other standards.\n\n> **Usage:**\n>\n> 1. Copy the content of this file.\n> 2. Create a new file in the root of your project called `.claude/CLAUDE.md`.\n> 3. Update the information in the new file to match your project.\n> 4. Paste the content of this file into the new file.\n> 5. Copy the rules folder into `.claude/`\n\n## Project: [APP_NAME]\n\n[One sentence: what the app does and who it serves.]\n\n## Commands\n\n```bash\nbin/rails server                      # Start dev server\nbin/rails spec                        # Full test suite (Suspenders rake task)\nbundle exec rspec spec/models         # Model specs only\nbundle exec rspec spec/requests       # Request specs only\nbundle exec rspec spec/path/to/file_spec.rb  # Run all tests in file\nbundle exec rspec spec/path/to/file_spec.rb:72  # Run just the test at line 72\nrake standard                         # Lint\nrake standard:fix                     # Auto-fix lint issues\nbin/rails db:migrate                  # Run migrations\nbin/rails suspenders:db:migrate       # Migrate + annotate\nbin/rails suspenders:cleanup:organize_gemfile  # Sort Gemfile\nbundle audit                          # Check gem vulnerabilities\nbin/rails routes                      # View routes\n```\n\n## Rules\n\nShort constraints in .claude/rules/:\n\nrules/models.md — models conventions\nrules/controllers.md — controller conventions\nrules/testing.md - **MUST write tests first** TDD guidelines\nrules/security.md — security guidelines\nrules/views.md — No logic in views, presenter usage, Turbo conventions\nrules/database.md — Indexes, N+1, migration rules, query guidelines\n"
  },
  {
    "path": "rails/ai-rules/rules/controllers.md",
    "content": "# Controllers\n\n- Controllers handle HTTP only: receive request, delegate to model, return response.\n- Actions should not exceed 10 lines (excluding strong params). Longer actions often signal business logic that belongs in a model or PORO.\n- Maximum one instance variable per action.\n- No business logic, calculations, email sending, or multi-object operations in controllers.\n- Always use strong parameters. Never `params.permit!`.\n- Return `status: :unprocessable_entity` on failed form renders (required by Turbo).\n- Prefer RESTful routes. Custom verb actions (e.g., post \"activate\") usually mean a missing noun/resource (e.g., resource :trial, only: [:create]).\n"
  },
  {
    "path": "rails/ai-rules/rules/database.md",
    "content": "# Database & Migrations\n\n- Always use the `rails generate migration` command to create migration files.\n- Migrations must be reversible.\n- Add `null: false` and database-level defaults where appropriate.\n- Use `text` over `string` if length varies significantly.\n- Wrap multi-record operations in transactions. Use `save!` (bang) inside transactions.\n- Keep scopes as one-liners. Complex queries belong in search/query objects.\n- Never use `Post.all` without pagination.\n- Avoid `.count` in loops.\n- Use `counter_cache`.\n"
  },
  {
    "path": "rails/ai-rules/rules/models.md",
    "content": "# Models & Domain Objects\n\n- No service objects. All domain classes live in `app/models/` with namespaces, never `app/services/`.\n- Name classes after domain nouns, not actions. No `*Service`, `*Manager`, `*Handler` suffixes.\n- Use `ActiveModel::Model` for POROs that need validation or form integration.\n- Replace `.call` / `.perform` with domain verbs: `#save`, `#complete`, `#submit`, `#deliver`.\n- Look to identify domain models that can be extracted when an existing\n  model exceeds: 200 lines, 15 public methods, or 7 private methods.\n- Callbacks only for data integrity (normalise fields, set defaults). Never for emails, payments, or external systems.\n- Prefer composition over inheritance. Extract behaviour into small, focused objects.\n- Avoid feature envy, long parameter lists (max 3 args), case statements on type, and mixin abuse.\n"
  },
  {
    "path": "rails/ai-rules/rules/security.md",
    "content": "# Security\n\n- Never interpolate user input into SQL. Use parameterised queries or `where(key: value)`.\n- Always use strong parameters. Never `params.permit!`.\n- Scope all queries to the current user or use Pundit authorisation.\n- Every controller must have authentication unless explicitly public.\n- Never use `raw`, `html_safe`, or `<%==` with user-supplied data.\n- Never skip CSRF verification for browser-facing controllers.\n- Filter sensitive params in logs: passwords, tokens, secrets, API keys.\n- Never `render json: model` without explicit `only:` — whitelist attributes.\n- Never redirect to `params[:return_to]` without validation.\n- Use array form for system commands: `system(\"cmd\", arg)`, never `system(\"cmd #{arg}\")`.\n"
  },
  {
    "path": "rails/ai-rules/rules/testing.md",
    "content": "# Testing\n\n- Must use TDD. Write tests first and follow red, green, refactor\n- Must not use let or before in specs (avoid mystery guests). Do test setup\n  within each test.\n- Test behaviour, not implementation. Four Phase Test: setup, exercise, verify, teardown.\n- Test pyramid: many model/PORO unit specs, some request specs, few system specs.\n- Every public method on every model and PORO must have at least one spec.\n- Every branch in a conditional must have at least one spec.\n- Use `build` / `build_stubbed` over `create` unless persistence is needed.\n- Factories: only required attributes with sensible defaults. Start in `spec/factories.rb`.\n- Shoulda Matchers for validations and associations.\n- WebMock blocks all external HTTP in tests — always stub external requests.\n- One `expect` per `it` block. Max 2 levels of context nesting.\n- Never test private methods directly. Never stub the system under test.\n"
  },
  {
    "path": "rails/ai-rules/rules/views.md",
    "content": "# Views & Presenters\n\n- Views render data. No calculations, queries, or complex conditionals.\n- Use presenters to display logic. Instantiate in controller, use in view.\n- Extract repeated markup into partials. Pass data via `locals:`, not instance variables.\n- Helpers for simple formatting only (dates, currencies). If longer than 5 lines, use a presenter.\n- Turbo: return `status: :unprocessable_entity` on failed forms. Keep Stimulus controllers small.\n"
  },
  {
    "path": "rails/how-to/deploy_a_rails_app_to_heroku.md",
    "content": "# How to Deploy a Rails App to Heroku\n\nView a list of new commits. View changed files.\n\n```console\ngit fetch staging\ngit log staging/main..main\ngit diff --stat staging/main\n```\n\nIf necessary, add new environment variables.\n\n```console\nheroku config:add NEW_VARIABLE=value --remote staging\n```\n\nDeploy to [Heroku] staging.\n\n```console\ngit push staging\n```\n\nIf necessary, run migrations and restart the dynos.\n\n```console\nheroku run rake db:migrate --remote staging\nheroku restart --remote staging\n```\n\n[Introspect] to make sure everything's ok.\n\n```console\nwatch heroku ps --remote staging\n```\n\nTest the feature in browser.\n\nDeploy to production.\n\n```console\ngit fetch production\ngit log production/main..main\ngit diff --stat production/main\nheroku config:add NEW_VARIABLE=value --remote production\ngit push production\nheroku run rake db:migrate --remote production\nheroku restart --remote production\nwatch heroku ps --remote production\n```\n\nWatch logs and metrics dashboards.\n\nClose pull request and comment `Merged.`\n\n[heroku]: https://devcenter.heroku.com/articles/quickstart\n[introspect]: http://blog.heroku.com/archives/2011/6/24/the_new_heroku_3_visibility_introspection/\n\n## Set Up Production Environment\n\n- Make sure that your [`Procfile`] is set up to run Unicorn.\n- Make sure the PG Backups add-on is enabled.\n- Create a read-only [Heroku Follower] for your production database. If a Heroku\n  database outage occurs, Heroku can use the follower to get your app back up\n  and running faster.\n\n[heroku follower]: https://devcenter.heroku.com/articles/improving-heroku-postgres-availability-with-followers\n[`procfile`]: https://devcenter.heroku.com/articles/procfile\n"
  },
  {
    "path": "rails/how-to/feature_test_javascript_in_a_rails_app.md",
    "content": "# How to Feature-test JavaScript in a Rails App\n\nUse [capybara-webkit]. In your `Gemfile`:\n\n```ruby\ngem \"capybara-webkit\"\n```\n\nIn `spec/support/capybara_webkit.rb` (for RSpec):\n\n```ruby\nCapybara.javascript_driver = :webkit\n\nCapybara::Webkit.configure do |config|\n  config.block_unknown_urls\nend\n```\n\nWhen writing a spec, you must set the `:js` flag for that test to make use of\ncapybara-webkit. For example, in `spec/system/user_signs_in_spec.rb`:\n\n```ruby\ndescribe \"Authentication\", :js do\n  it \"signs in a user\" do\n    create(:user, email: \"me@example.com\", password: \"sekrit\")\n\n    sign_in_as email: \"me@example.com\", password: \"sekrit\"\n\n    expect(page).to have_text(\"Welcome!\")\n  end\nend\n```\n\n[capybara-webkit]: https://github.com/thoughtbot/capybara-webkit\n"
  },
  {
    "path": "rails/how-to/seed-data.md",
    "content": "# How to seed development data\n\n```ruby\n# lib/development/seeder.rb\n\nmodule Development\n  class Seeder\n    def self.load_seeds\n      if Rails.env.development?\n        new.load_seeds\n      else\n        raise \"Development::Seeder can only be run in a development environment.\"\n      end\n    end\n\n    def load_seeds\n      #   [\"Ruby\", \"Ralph\"].each do |name|\n      #     User.find_or_create_by!(name:)\n      #   end\n    end\n  end\nend\n```\n\n```rb\n# lib/tasks/development.rake\n\nif Rails.env.development?\n  namespace :development do\n    namespace :db do\n      desc \"Loads seed data into development.\"\n      task seed: [\"environment\", \"db:seed\"] do\n        Development::Seeder.load_seeds\n      end\n\n      namespace :seed do\n        desc \"Truncate tables of each database for development and loads seed data.\"\n        task replant: [\"environment\", \"db:truncate_all\", \"development:db:seed\"]\n      end\n    end\n  end\nend\n```\n"
  },
  {
    "path": "rails/how-to/start_a_new_rails_app.md",
    "content": "# How to Start a New Rails App\n\nUse [Suspenders]:\n\n```sh\ngem install suspenders\nsuspenders new the-name-of-your-project-here\n```\n\n[suspenders]: https://github.com/thoughtbot/suspenders\n"
  },
  {
    "path": "rails/migration.rb",
    "content": "class CreateClearanceUsers < ActiveRecord::Migration\n  def change\n    create_table :users  do |t|\n      t.timestamps null: false\n      t.string :email, null: false\n      t.string :name, null: false, default: ''\n      t.references :company\n    end\n\n    add_index :users, :email\n    add_foreign_key :users, :company_id, on_delete: :restrict\n  end\nend\n"
  },
  {
    "path": "rails/sample.rb",
    "content": "class SomeClass\n  belongs_to :tree, class_name: \"Plant\"\n  has_many :apples\n  has_many :watermelons\n\n  validates :name, presence: true, uniqueness: true\nend\n"
  },
  {
    "path": "react/README.md",
    "content": "# React\n\n- Use React in [Strict Mode]\n- Use React with [TypeScript](/javascript-typescript/README.md#typescript)\n- Avoid nested routing if using [React Router]\n- Prefer [Function Components] over [Class Components]\n- Prefer keeping a single component in each file\n- Use `PascalCase` for component names and their file names\n- Use [React Hooks]\n- Use pre-built hooks when possible (e.g. [streamich/react-use])\n- Use [custom hooks] to encapsulate stateful logic outside a component\n- Avoid nesting [Forward Refs]\n- Avoid [Higher-Order Components] and [recompose] (see hooks above as an\n  alternative)\n- Prefer the `children` prop over [render props]\n- Prefer using [TypeScript prop interfaces] over [PropTypes]\n- Prefer the [short syntax] when using [Fragments]\n- Prefer [React Contexts] over [Redux]\n- Avoid using indexes as the value for [keys]\n- Avoid complex conditionals inside component logic\n- Prefer [component composition over component inheritance]\n\n[strict mode]: https://reactjs.org/docs/strict-mode.html\n[react hooks]: https://reactjs.org/docs/hooks-overview.html\n[custom hooks]: https://reactjs.org/docs/hooks-overview.html#building-your-own-hooks\n[streamich/react-use]: https://github.com/streamich/react-use\n[function components]: https://reactjs.org/docs/components-and-props.html\n[class components]: https://reactjs.org/docs/react-component.html\n[forward refs]: https://reactjs.org/docs/forwarding-refs.html\n[higher-order components]: https://reactjs.org/docs/higher-order-components.html\n[recompose]: https://github.com/acdlite/recompose\n[render props]: https://reactjs.org/docs/render-props.html\n[typescript prop interfaces]: https://www.typescriptlang.org/docs/handbook/react-&-webpack.html#write-some-code\n[proptypes]: https://reactjs.org/docs/typechecking-with-proptypes.html\n[short syntax]: https://reactjs.org/docs/fragments.html#short-syntax\n[fragments]: https://reactjs.org/docs/fragments.html\n[react contexts]: https://reactjs.org/docs/context.html\n[redux]: https://react-redux.js.org/\n[keys]: https://reactjs.org/docs/lists-and-keys.html#keys\n[component composition over component inheritance]: https://reactjs.org/docs/composition-vs-inheritance.html\n[react router]: https://reacttraining.com/react-router/\n\n## General Philosophies\n\n- For greenfield React projects we like to use [TypeScript]. TypeScript is a\n  typed superset of JavaScript that compiles to plain JavaScript. For a quick\n  introduction, check out [TypeScript in 5 minutes].\n- When building React apps with TypeScript and Apollo, we've found working in\n  [VSCode] to be a mostly-good experience.\n\n[typescript]: https://www.typescriptlang.org/\n[typescript in 5 minutes]: https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes.html\n[vscode]: https://code.visualstudio.com/\n"
  },
  {
    "path": "react-native/README.md",
    "content": "# React Native\n\n- Use React following the [React Guide](/react/)\n- Use [TypeScript](/javascript-typescript/README.md#typescript)\n- Prefer using [core components and apis] over writing bespoke components.\n\n[core components and apis]: https://reactnative.dev/docs/components-and-apis\n\n## Tooling\n\n- Start new projects with [create-belt-app](https://www.npmjs.com/package/create-belt-app)\n- Use [Expo](https://expo.dev)\n- Use [Expo EAS](https://expo.dev/eas) for continuous deployment\n- Use [Expo Secure Store](https://docs.expo.dev/versions/latest/sdk/securestore/) for storing sensitive data like auth and refresh tokens\n- Use [React Navigation](https://reactnavigation.org/) for routing\n- Use [TanStack React Query](https://tanstack.com/query/v4/docs/framework/react/overview) as an API client for REST APIs\n- Use [Apollo Client](https://www.apollographql.com/docs/react/) as an API client for GraphQL APIs\n- Use [Redux Toolkit](https://redux-toolkit.js.org/) for global state\n  - Avoid storing API data in a global store. Instead, use a dedicated API client.\n- Use [React Native Firebase](https://rnfirebase.io/) for push notifications\n- Use [Sentry](https://docs.sentry.io/platforms/react-native/) for error reporting\n- Prefer [RevenueCat](https://www.revenuecat.com/) for in-app payments\n  - If RevenueCat pricing is not acceptable since it collects a percentage of revenue, use [react-native-iap](https://react-native-iap.dooboolab.com/docs/get-started/)\n\n## Style\n\n- Prefer using [StyleSheets]\n- Prefer [organized and composable styles]\n- Avoid designing for only one platform.\n- Avoid designing for only one screen size.\n- Prefer common mobile patterns and avoid [non-standard patterns].\n\n[StyleSheets]: https://reactnative.dev/docs/stylesheet\n[organized and composable styles]: https://thoughtbot.com/blog/structure-for-styling-in-react-native\n[non-standard patterns]: https://thoughtbot.com/blog/some-tips-for-designing-apps-in-react-native#make-it-feel-native-even-though-it39s-not\n\n## Testing\n\n- Test using React Native [Testing Library](https://callstack.github.io/react-native-testing-library/) and [Jest](https://jestjs.io/)\n- Mock API calls in tests using [MSW](https://mswjs.io/). If using Apollo Client, mock using the built-in `MockedProvider`\n- Prefer testing on physical devices.\n- Use [detox] for integration tests.\n\n[detox]: https://github.com/wix/Detox\n"
  },
  {
    "path": "relational-databases/README.md",
    "content": "# Relational Databases\n\n- [Index foreign keys].\n- Constrain most columns as [`NOT NULL`].\n- In a SQL view, only select columns you need (i.e., avoid `SELECT table.*`).\n- Use an `ORDER BY` clause on queries where the results will be displayed to a\n  user, as queries without one may return results in a changing, arbitrary\n  order.\n\n[index foreign keys]: https://thoughtbot.com/blog/a-grand-piano-for-your-violin\n[`not null`]: http://www.postgresql.org/docs/9.1/static/ddl-constraints.html#AEN2444\n"
  },
  {
    "path": "ruby/.rubocop.yml",
    "content": "AllCops:\n  Exclude:\n    - db/schema.rb\n\nrequire:\n  - rubocop-rails\n  - rubocop-performance\n\nNaming/AccessorMethodName:\n  Description: Check the naming of accessor methods for get_/set_.\n  Enabled: false\n\nStyle/Alias:\n  Description: 'Use alias_method instead of alias.'\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#alias-method'\n  Enabled: false\n\nStyle/ArrayJoin:\n  Description: 'Use Array#join instead of Array#*.'\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#array-join'\n  Enabled: false\n\nStyle/AsciiComments:\n  Description: 'Use only ascii symbols in comments.'\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#english-comments'\n  Enabled: false\n\nNaming/AsciiIdentifiers:\n  Description: 'Use only ascii symbols in identifiers.'\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#english-identifiers'\n  Enabled: false\n\nStyle/Attr:\n  Description: 'Checks for uses of Module#attr.'\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#attr'\n  Enabled: false\n\nMetrics/BlockNesting:\n  Description: 'Avoid excessive block nesting'\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#three-is-the-number-thou-shalt-count'\n  Enabled: false\n\nStyle/CaseEquality:\n  Description: 'Avoid explicit use of the case equality operator(===).'\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-case-equality'\n  Enabled: false\n\nStyle/CharacterLiteral:\n  Description: 'Checks for uses of character literals.'\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-character-literals'\n  Enabled: false\n\nStyle/ClassAndModuleChildren:\n  Description: 'Checks style of children classes and modules.'\n  Enabled: true\n  EnforcedStyle: nested\n\nMetrics/ClassLength:\n  Description: 'Avoid classes longer than 100 lines of code.'\n  Enabled: false\n\nMetrics/ModuleLength:\n  Description: 'Avoid modules longer than 100 lines of code.'\n  Enabled: false\n\nStyle/ClassVars:\n  Description: 'Avoid the use of class variables.'\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-class-vars'\n  Enabled: false\n\nStyle/CollectionMethods:\n  Enabled: true\n  PreferredMethods:\n    find: detect\n    inject: reduce\n    collect: map\n    find_all: select\n\nStyle/ColonMethodCall:\n  Description: 'Do not use :: for method call.'\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#double-colons'\n  Enabled: false\n\nStyle/CommentAnnotation:\n  Description: >-\n                 Checks formatting of special comments\n                 (TODO, FIXME, OPTIMIZE, HACK, REVIEW).\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#annotate-keywords'\n  Enabled: false\n\nMetrics/AbcSize:\n  Description: >-\n                 A calculated magnitude based on number of assignments,\n                 branches, and conditions.\n  Enabled: false\n\nMetrics/BlockLength:\n  CountComments: true  # count full line comments?\n  Max: 25\n  Exclude:\n    - \"spec/**/*\"\n\nMetrics/CyclomaticComplexity:\n  Description: >-\n                 A complexity metric that is strongly correlated to the number\n                 of test cases needed to validate a method.\n  Enabled: false\n\nRails/Delegate:\n  Description: 'Prefer delegate method for delegations.'\n  Enabled: false\n\nStyle/PreferredHashMethods:\n  Description: 'Checks use of `has_key?` and `has_value?` Hash methods.'\n  StyleGuide: '#hash-key'\n  Enabled: false\n\nStyle/Documentation:\n  Description: 'Document classes and non-namespace modules.'\n  Enabled: false\n\nStyle/DoubleNegation:\n  Description: 'Checks for uses of double negation (!!).'\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-bang-bang'\n  Enabled: false\n\nStyle/EachWithObject:\n  Description: 'Prefer `each_with_object` over `inject` or `reduce`.'\n  Enabled: false\n\nStyle/EmptyLiteral:\n  Description: 'Prefer literals to Array.new/Hash.new/String.new.'\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#literal-array-hash'\n  Enabled: false\n\n# Checks whether the source file has a utf-8 encoding comment or not\n# AutoCorrectEncodingComment must match the regex\n# /#.*coding\\s?[:=]\\s?(?:UTF|utf)-8/\nStyle/Encoding:\n  Enabled: false\n\nStyle/EvenOdd:\n  Description: 'Favor the use of Fixnum#even? && Fixnum#odd?'\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#predicate-methods'\n  Enabled: false\n\nNaming/FileName:\n  Description: 'Use snake_case for source file names.'\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#snake-case-files'\n  Enabled: false\n\nStyle/FrozenStringLiteralComment:\n  Description: >-\n    Add the frozen_string_literal comment to the top of files\n    to help transition from Ruby 2.3.0 to Ruby 3.0.\n  Enabled: false\n\nLint/FlipFlop:\n  Description: 'Checks for flip flops'\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-flip-flops'\n  Enabled: false\n\nStyle/FormatString:\n  Description: 'Enforce the use of Kernel#sprintf, Kernel#format or String#%.'\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#sprintf'\n  Enabled: false\n\nStyle/GlobalVars:\n  Description: 'Do not introduce global variables.'\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#instance-vars'\n  Reference: 'http://www.zenspider.com/Languages/Ruby/QuickRef.html'\n  Enabled: false\n\nStyle/GuardClause:\n  Description: 'Check for conditionals that can be replaced with guard clauses'\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-nested-conditionals'\n  Enabled: false\n\nStyle/IfUnlessModifier:\n  Description: >-\n                 Favor modifier if/unless usage when you have a\n                 single-line body.\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#if-as-a-modifier'\n  Enabled: false\n\nStyle/IfWithSemicolon:\n  Description: 'Do not use if x; .... Use the ternary operator instead.'\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-semicolon-ifs'\n  Enabled: false\n\nStyle/InlineComment:\n  Description: 'Avoid inline comments.'\n  Enabled: false\n\nStyle/Lambda:\n  Description: 'Use the new lambda literal syntax for single-line blocks.'\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#lambda-multi-line'\n  Enabled: false\n\nStyle/LambdaCall:\n  Description: 'Use lambda.call(...) instead of lambda.(...).'\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#proc-call'\n  Enabled: false\n\nStyle/LineEndConcatenation:\n  Description: >-\n                 Use \\ instead of + or << to concatenate two string literals at\n                 line end.\n  Enabled: false\n\nMetrics/MethodLength:\n  Description: 'Avoid methods longer than 10 lines of code.'\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#short-methods'\n  Enabled: false\n\nStyle/ModuleFunction:\n  Description: 'Checks for usage of `extend self` in modules.'\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#module-function'\n  Enabled: false\n\nStyle/MultilineBlockChain:\n  Description: 'Avoid multi-line chains of blocks.'\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#single-line-blocks'\n  Enabled: false\n\nStyle/NegatedIf:\n  Description: >-\n                 Favor unless over if for negative conditions\n                 (or control flow or).\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#unless-for-negatives'\n  Enabled: false\n\nStyle/NegatedWhile:\n  Description: 'Favor until over while for negative conditions.'\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#until-for-negatives'\n  Enabled: false\n\nStyle/Next:\n  Description: 'Use `next` to skip iteration instead of a condition at the end.'\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-nested-conditionals'\n  Enabled: false\n\nStyle/NilComparison:\n  Description: 'Prefer x.nil? to x == nil.'\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#predicate-methods'\n  Enabled: false\n\nStyle/Not:\n  Description: 'Use ! instead of not.'\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#bang-not-not'\n  Enabled: false\n\nStyle/NumericLiterals:\n  Description: >-\n                 Add underscores to large numeric literals to improve their\n                 readability.\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#underscores-in-numerics'\n  Enabled: false\n\nStyle/OneLineConditional:\n  Description: >-\n                 Favor the ternary operator(?:) over\n                 if/then/else/end constructs.\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#ternary-operator'\n  Enabled: false\n\nNaming/BinaryOperatorParameterName:\n  Description: 'When defining binary operators, name the argument other.'\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#other-arg'\n  Enabled: false\n\nMetrics/ParameterLists:\n  Description: 'Avoid parameter lists longer than three or four parameters.'\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#too-many-params'\n  Enabled: false\n\nStyle/PercentLiteralDelimiters:\n  Description: 'Use `%`-literal delimiters consistently'\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#percent-literal-braces'\n  Enabled: false\n\nStyle/PerlBackrefs:\n  Description: 'Avoid Perl-style regex back references.'\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-perl-regexp-last-matchers'\n  Enabled: false\n\nNaming/PredicateName:\n  Description: 'Check the names of predicate methods.'\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#bool-methods-qmark'\n  ForbiddenPrefixes:\n    - is_\n  Exclude:\n    - spec/**/*\n\nStyle/Proc:\n  Description: 'Use proc instead of Proc.new.'\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#proc'\n  Enabled: false\n\nStyle/RaiseArgs:\n  Description: 'Checks the arguments passed to raise/fail.'\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#exception-class-messages'\n  Enabled: false\n\nStyle/RegexpLiteral:\n  Description: 'Use / or %r around regular expressions.'\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#percent-r'\n  Enabled: false\n\nStyle/Sample:\n  Description: >-\n    Use `sample` instead of `shuffle.first`,\n    `shuffle.last`, and `shuffle[Fixnum]`.\n  Reference: 'https://github.com/JuanitoFatas/fast-ruby#arrayshufflefirst-vs-arraysample-code'\n  Enabled: false\n\nStyle/SelfAssignment:\n  Description: >-\n                 Checks for places where self-assignment shorthand should have\n                 been used.\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#self-assignment'\n  Enabled: false\n\nStyle/SingleLineBlockParams:\n  Description: 'Enforces the names of some block params.'\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#reduce-blocks'\n  Enabled: false\n\nStyle/SingleLineMethods:\n  Description: 'Avoid single-line methods.'\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-single-line-methods'\n  Enabled: false\n\nStyle/SignalException:\n  Description: 'Checks for proper usage of fail and raise.'\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#fail-method'\n  Enabled: false\n\nStyle/SpecialGlobalVars:\n  Description: 'Avoid Perl-style global variables.'\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-cryptic-perlisms'\n  Enabled: false\n\nStyle/StringLiterals:\n  Description: 'Checks if uses of quotes match the configured preference.'\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#consistent-string-literals'\n  EnforcedStyle: double_quotes\n  Enabled: true\n\nStyle/TrailingCommaInArguments:\n  Description: 'Checks for trailing comma in argument lists.'\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-trailing-array-commas'\n  EnforcedStyleForMultiline: comma\n  SupportedStylesForMultiline:\n    - comma\n    - consistent_comma\n    - no_comma\n  Enabled: true\n\nStyle/TrailingCommaInArrayLiteral:\n  Description: 'Checks for trailing comma in array literals.'\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-trailing-array-commas'\n  EnforcedStyleForMultiline: comma\n  SupportedStylesForMultiline:\n    - comma\n    - consistent_comma\n    - no_comma\n  Enabled: true\n\nStyle/TrailingCommaInHashLiteral:\n  Description: 'Checks for trailing comma in hash literals.'\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-trailing-array-commas'\n  EnforcedStyleForMultiline: comma\n  SupportedStylesForMultiline:\n    - comma\n    - consistent_comma\n    - no_comma\n  Enabled: true\n\nStyle/TrivialAccessors:\n  Description: 'Prefer attr_* methods to trivial readers/writers.'\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#attr_family'\n  Enabled: false\n\nStyle/VariableInterpolation:\n  Description: >-\n                 Don't interpolate global, instance and class variables\n                 directly in strings.\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#curlies-interpolate'\n  Enabled: false\n\nStyle/WhenThen:\n  Description: 'Use when x then ... for one-line cases.'\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#one-line-cases'\n  Enabled: false\n\nStyle/WhileUntilModifier:\n  Description: >-\n                 Favor modifier while/until usage when you have a\n                 single-line body.\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#while-as-a-modifier'\n  Enabled: false\n\nStyle/WordArray:\n  Description: 'Use %w or %W for arrays of words.'\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#percent-w'\n  Enabled: false\n\n# Layout\n\nLayout/ParameterAlignment:\n  Description: 'Here we check if the parameters on a multi-line method call or definition are aligned.'\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-double-indent'\n  Enabled: false\n\nLayout/ConditionPosition:\n  Description: >-\n                 Checks for condition placed in a confusing position relative to\n                 the keyword.\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#same-line-condition'\n  Enabled: false\n\nLayout/DotPosition:\n  Description: 'Checks the position of the dot in multi-line method calls.'\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#consistent-multi-line-chains'\n  EnforcedStyle: trailing\n\nLayout/ExtraSpacing:\n  Description: 'Do not use unnecessary spacing.'\n  Enabled: true\n\nLayout/MultilineOperationIndentation:\n  Description: >-\n                 Checks indentation of binary operations that span more than\n                 one line.\n  Enabled: true\n  EnforcedStyle: indented\n\nLayout/MultilineMethodCallIndentation:\n  Description: >-\n                 Checks indentation of method calls with the dot operator\n                 that span more than one line.\n  Enabled: true\n  EnforcedStyle: indented\n\nLayout/InitialIndentation:\n  Description: >-\n    Checks the indentation of the first non-blank non-comment line in a file.\n  Enabled: false\n\nLayout/LineLength:\n  Description: 'Limit lines to 80 characters.'\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#80-character-limits'\n  Max: 80\n\n# Lint\n\nLint/AmbiguousOperator:\n  Description: >-\n                 Checks for ambiguous operators in the first argument of a\n                 method invocation without parentheses.\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#parens-as-args'\n  Enabled: false\n\nLint/AmbiguousRegexpLiteral:\n  Description: >-\n                 Checks for ambiguous regexp literals in the first argument of\n                 a method invocation without parenthesis.\n  Enabled: false\n\nLint/AssignmentInCondition:\n  Description: \"Don't use assignment in conditions.\"\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#safe-assignment-in-condition'\n  Enabled: false\n\nLint/CircularArgumentReference:\n  Description: \"Don't refer to the keyword argument in the default value.\"\n  Enabled: false\n\nLint/DeprecatedClassMethods:\n  Description: 'Check for deprecated class method calls.'\n  Enabled: false\n\nLint/DuplicateHashKey:\n  Description: 'Check for duplicate keys in hash literals.'\n  Enabled: false\n\nLint/EachWithObjectArgument:\n  Description: 'Check for immutable argument given to each_with_object.'\n  Enabled: false\n\nLint/ElseLayout:\n  Description: 'Check for odd code arrangement in an else block.'\n  Enabled: false\n\nLint/FormatParameterMismatch:\n  Description: 'The number of parameters to format/sprint must match the fields.'\n  Enabled: false\n\nLint/SuppressedException:\n  Description: \"Don't suppress exception.\"\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#dont-hide-exceptions'\n  Enabled: false\n\nLint/LiteralAsCondition:\n  Description: 'Checks of literals used in conditions.'\n  Enabled: false\n\nLint/LiteralInInterpolation:\n  Description: 'Checks for literals used in interpolation.'\n  Enabled: false\n\nLint/Loop:\n  Description: >-\n                 Use Kernel#loop with break rather than begin/end/until or\n                 begin/end/while for post-loop tests.\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#loop-with-break'\n  Enabled: false\n\nLint/NestedMethodDefinition:\n  Description: 'Do not use nested method definitions.'\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-nested-methods'\n  Enabled: false\n\nLint/NonLocalExitFromIterator:\n  Description: 'Do not use return in iterator to cause non-local exit.'\n  Enabled: false\n\nLint/ParenthesesAsGroupedExpression:\n  Description: >-\n                 Checks for method calls with a space before the opening\n                 parenthesis.\n  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#parens-no-spaces'\n  Enabled: false\n\nLint/RequireParentheses:\n  Description: >-\n                 Use parentheses in the method call to avoid confusion\n                 about precedence.\n  Enabled: false\n\nLint/UnderscorePrefixedVariableName:\n  Description: 'Do not use prefix `_` for a variable that is used.'\n  Enabled: false\n\nLint/RedundantCopDisableDirective:\n  Description: >-\n                 Checks for rubocop:disable comments that can be removed.\n                 Note: this cop is not disabled when disabling all cops.\n                 It must be explicitly disabled.\n  Enabled: false\n\nLint/Void:\n  Description: 'Possible use of operator/literal/variable in void context.'\n  Enabled: false\n\n# Performance\n\nPerformance/CaseWhenSplat:\n  Description: >-\n                  Place `when` conditions that use splat at the end\n                  of the list of `when` branches.\n  Enabled: false\n\nPerformance/Count:\n  Description: >-\n                  Use `count` instead of `select...size`, `reject...size`,\n                  `select...count`, `reject...count`, `select...length`,\n                  and `reject...length`.\n  Enabled: false\n\nPerformance/Detect:\n  Description: >-\n                  Use `detect` instead of `select.first`, `find_all.first`,\n                  `select.last`, and `find_all.last`.\n  Reference: 'https://github.com/JuanitoFatas/fast-ruby#enumerabledetect-vs-enumerableselectfirst-code'\n  Enabled: false\n\nPerformance/FlatMap:\n  Description: >-\n                  Use `Enumerable#flat_map`\n                  instead of `Enumerable#map...Array#flatten(1)`\n                  or `Enumberable#collect..Array#flatten(1)`\n  Reference: 'https://github.com/JuanitoFatas/fast-ruby#enumerablemaparrayflatten-vs-enumerableflat_map-code'\n  Enabled: false\n\nPerformance/ReverseEach:\n  Description: 'Use `reverse_each` instead of `reverse.each`.'\n  Reference: 'https://github.com/JuanitoFatas/fast-ruby#enumerablereverseeach-vs-enumerablereverse_each-code'\n  Enabled: false\n\nPerformance/Size:\n  Description: >-\n                  Use `size` instead of `count` for counting\n                  the number of elements in `Array` and `Hash`.\n  Reference: 'https://github.com/JuanitoFatas/fast-ruby#arraycount-vs-arraysize-code'\n  Enabled: false\n\nPerformance/StringReplacement:\n  Description: >-\n                  Use `tr` instead of `gsub` when you are replacing the same\n                  number of characters. Use `delete` instead of `gsub` when\n                  you are deleting characters.\n  Reference: 'https://github.com/JuanitoFatas/fast-ruby#stringgsub-vs-stringtr-code'\n  Enabled: false\n\n# Rails\n\nRails/ActionFilter:\n  Description: 'Enforces consistent use of action filter methods.'\n  Enabled: false\n\nRails/Date:\n  Description: >-\n                  Checks the correct usage of date aware methods,\n                  such as Date.today, Date.current etc.\n  Enabled: false\n\nRails/FindBy:\n  Description: 'Prefer find_by over where.first.'\n  Enabled: false\n\nRails/FindEach:\n  Description: 'Prefer all.find_each over all.find.'\n  Enabled: false\n\nRails/HasAndBelongsToMany:\n  Description: 'Prefer has_many :through to has_and_belongs_to_many.'\n  Enabled: false\n\nRails/Output:\n  Description: 'Checks for calls to puts, print, etc.'\n  Enabled: false\n\nRails/ReadWriteAttribute:\n  Description: >-\n                 Checks for read_attribute(:attr) and\n                 write_attribute(:attr, val).\n  Enabled: false\n\nRails/ScopeArgs:\n  Description: 'Checks the arguments of ActiveRecord scopes.'\n  Enabled: false\n\nRails/TimeZone:\n  Description: 'Checks the correct usage of time zone aware methods.'\n  StyleGuide: 'https://github.com/bbatsov/rails-style-guide#time'\n  Reference: 'http://danilenko.org/2012/7/6/rails_timezones'\n  Enabled: false\n\nRails/Validation:\n  Description: 'Use validates :attribute, hash of validations.'\n  Enabled: false\n"
  },
  {
    "path": "ruby/Limit-use-of-conditional-modifiers-to-short-simple-cases.md",
    "content": "# Limit use of conditional modifiers to short, simple cases\n\nConditional modifiers (i.e., `if` or `unless` at the end of a line) can be\nsurprising when they appear on long or complex lines. The reader might not see\nthem while scanning the code.\n\nSo, prefer to use them only for short, simple cases. For example:\n\n```ruby\ndo_later if async?\n```\n\nThe example above can read more naturally than:\n\n```rb\nif async?\n  do_later\nend\n```\n\n## Complex conditions\n\nHowever, if the line is too long (around 80 characters) or complex (e.g., an\n`if` with multiple conditions like `if a && b`) prefer the multi-line form:\n\n```ruby\n# Avoid\nblock_access! if signed_in? && !current_user.active?\n\n# Prefer\nif signed_in? && !current_user.active?\n  block_access!\nend\n```\n\nThere might be cases where the conditional modifier work well with multiple\nconditions, so use your best judgment.\n\n## An opportunity to refactor\n\nIf the conditions are related, consider extracting a method that groups them.\nThis might allow you to use the conditional modifier form again.\n\n```ruby\ndef inactive_user?\n  signed_in? && !current_user.active?\nend\n\nblock_access! if inactive_user?\n```\n\n## Conditional modifiers feel informal\n\nThe modifier form of conditionals can feel more casual than the multi-line form.\nConversely, the multi-line form _draws attention_ to the conditional and the\ncode that follows it. Use this to your advantage when you want to emphasize the\nconditional and the code that follows it.\n\n```rb\n# Avoid\ndef action\n  return destroy_all if really?\n\n  do_nothing\nend\n\n# Prefer\ndef action\n  if really?\n    destroy_all\n  else\n    do_nothing\n  end\nend\n```\n\nYou can also refactor the code so the less destructive action uses a conditional\nmodifier, which pairs well with the informal feel of the modifier form:\n\n```rb\ndef action\n  return do_nothing if chill?\n\n  destroy_all\nend\n```\n\n## References\n\n- You can see further discussion of this guideline here: [#738](https://github.com/thoughtbot/guides/pull/738)\n"
  },
  {
    "path": "ruby/README.md",
    "content": "# Ruby\n\n[Sample 1](sample_1.rb) [Sample 2](sample_2.rb)\n\n> [!TIP]\n> Click on the linked pull request, commit, or the guideline itself to read more\n> detailed explanations with examples and reasoning behind these recommendations.\n\n- [Use an opinionated set of rules for Rubocop](Use-an-opinionated-set-of-rules-for-Rubocop.md)\n- [Limit use of conditional modifiers to short, simple cases](Limit-use-of-conditional-modifiers-to-short-simple-cases.md)\n- Avoid multiple assignments per line (`one, two = 1, 2`). [#109]\n- Avoid ternary operators (`boolean ? true : false`). Use multi-line `if`\n  instead to emphasize code branches. [36491dbb9]\n- Prefer nested class and module definitions over the shorthand version\n  [Example](/ruby/sample_1.rb#L103) [#332]\n- Prefer `detect` over `find`. [0d819844]\n- Prefer `select` over `find_all`. [0d819844]\n- Prefer `map` over `collect`. [0d819844]\n- Prefer `reduce` over `inject`. [#237]\n- Prefer `&:method_name` to `{ |item| item.method_name }` for simple method\n  calls. [#183]\n- Use `%()` for single-line strings containing double-quotes that require\n  interpolation. [36491dbb9]\n- Use heredocs for multi-line strings. [36491dbb9]\n- Avoid monkey-patching.\n- Generate necessary [Bundler binstubs] for the project, such as `rake` and\n  `rspec`, and add them to version control.\n- Prefer classes to modules when designing functionality that is shared by\n  multiple models.\n- Avoid organizational comments (`# Validations`). [#63]\n- Use empty lines around multi-line blocks.\n\n---\n\n- Avoid bang (!) method names. Prefer descriptive names. [#122]\n- Use `?` suffix for predicate methods. [0d819844]\n- Use `def self.method`, not `class << self`. [40090e22]\n- Use `def` with parentheses when there are arguments. [36491dbb9]\n- Avoid optional parameters. Does the method do too much?\n- Order class methods above instance methods. [#320]\n- Prefer `private` when indicating scope. Use `protected` only with comparison\n  methods like `def ==(other)`, `def <(other)`, and `def >(other)`.\n\n---\n\n- Prefix unused variables or parameters with underscore (`_`). [#335]\n- Name variables created by a factory after the factory (`user_factory` creates\n  `user`).\n- Suffix variables holding a factory with `_factory` (`user_factory`).\n- Use a leading underscore when defining instance variables for memoization.\n  [#373]\n- Prefer method invocation over instance variables. [#331]\n\n[#63]: https://github.com/thoughtbot/guides/pull/63\n[#109]: https://github.com/thoughtbot/guides/pull/109\n[#122]: https://github.com/thoughtbot/guides/pull/122\n[#183]: https://github.com/thoughtbot/guides/pull/183\n[#237]: https://github.com/thoughtbot/guides/pull/237\n[#320]: https://github.com/thoughtbot/guides/pull/320\n[#331]: https://github.com/thoughtbot/guides/pull/331\n[#332]: https://github.com/thoughtbot/guides/pull/332\n[#335]: https://github.com/thoughtbot/guides/pull/335\n[#373]: https://github.com/thoughtbot/guides/pull/373\n[0d819844]: https://github.com/thoughtbot/guides/commit/0d819844\n[36491dbb9]: https://github.com/thoughtbot/guides/commit/36491dbb9\n[40090e22]: https://github.com/thoughtbot/guides/commit/40090e22\n[bundler binstubs]: https://github.com/sstephenson/rbenv/wiki/Understanding-binstubs\n\n## Bundler\n\n- Specify the [Ruby version] to be used on the project in the `Gemfile`.\n- Use a [pessimistic version] in the `Gemfile` for gems that follow semantic\n  versioning, such as `rspec`, `factory_bot`, and `capybara`.\n- Use a [versionless] `Gemfile` declarations for gems that are safe to update\n  often, such as pg, thin, and debugger.\n- Use an [exact version] in the `Gemfile` for fragile gems, such as Rails.\n\n[ruby version]: http://bundler.io/v1.3/gemfile_ruby.html\n[exact version]: http://thoughtbot.com/blog/a-healthy-bundle\n[pessimistic version]: http://thoughtbot.com/blog/a-healthy-bundle\n[versionless]: http://thoughtbot.com/blog/a-healthy-bundle\n\n## Ruby Gems\n\n- Declare dependencies in the `<PROJECT_NAME>.gemspec` file.\n- Reference the `gemspec` in the `Gemfile`.\n- Use [Appraisal] to test the gem against multiple versions of gem dependencies\n  (such as Rails in a Rails engine).\n- Use [Bundler] to manage the gem's dependencies.\n- Use continuous integration (CI) to show build status within the code review\n  process and to test against multiple Ruby versions.\n\n[appraisal]: https://github.com/thoughtbot/appraisal\n[bundler]: http://bundler.io\n\n## Ruby JSON APIs\n\n- Review the recommended practices outlined in Heroku's [HTTP API Design Guide]\n  before designing a new API.\n- Write integration tests for your API endpoints. When the primary consumer of\n  the API is a JavaScript client maintained within the same code base as the\n  provider of the API, write [system specs]. Otherwise write [request specs].\n\n[http api design guide]: https://github.com/interagent/http-api-design\n[system specs]: https://web.archive.org/web/20230131005307/https://relishapp.com/rspec/rspec-rails/docs/system-specs/system-spec\n[request specs]: https://web.archive.org/web/20221207001104/https://www.relishapp.com/rspec/rspec-rails/docs/request-specs/request-spec\n\n## How To Guides\n\n- [Release a Ruby gem](./how-to/release_a_ruby_gem.md)\n"
  },
  {
    "path": "ruby/Use-an-opinionated-set-of-rules-for-Rubocop.md",
    "content": "# Use an opinionated set of rules for Rubocop\n\nRuby code can be written in many different styles and still be syntactically correct. The presence of divergent style and\nformat can disrupt communication as well as complicate feature development. Code that exhibits a consistent style is\neasier to understand and maintain. The absence of consistent enforced style can result in unnecessary code churn.\n\n**Therefore:** Use an opinionated set of rules for Rubocop when coding in Ruby.\n\n- Prefer [standard] for new projects.\n- By employing an already decided configuration, you avoid bikeshedding on what the Rubocop configuration should be.\n- Code that is consistently formatted and styled will be easier to work with.\n\nThere are, however, a few reasons one might choose not to introduce Standard in a project:\n\n- Change for the sake of change can be disruptive\n- An existing project may already employ it's own opinionated configuration of Rubocop and that set of rules is working.\n- A large project, which does not already use Standard, might require a costly amount of time to refactor and retrofit\n  existing code to conform to a new set of conventions.\n- There exists a need or desire to use Cops which are disabled by Standard\n- [standard] presents a lightweight but sensible set of style rules to focus on coding\n- [standard] prevents you from using cops that it disables\n\nOverall, the goal is to increase the quality and consistency of code while not getting distracted by disproportionally\nminor or trivial details. It's more important for an implementation team to agree to follow shared conventions than it\nis to enforce a specific configuration.\n\n[standard]: https://github.com/testdouble/standard\n"
  },
  {
    "path": "ruby/how-to/release_a_ruby_gem.md",
    "content": "# How to Release a Ruby gem\n\n- Edit the `VERSION` constant.\n- Run `bundle install` to update `Gemfile.lock`.\n- Run the test suite.\n- Edit `NEWS`, `CHANGELOG`, or `README` files if relevant.\n- Commit changes. Use the convention \"v2.1.0\" in your commit message.\n- Run `rake release`, which tags the release, pushes the tag to GitHub, and\n  pushes the gem to [RubyGems.org].\n\n[rubygems.org]: https://rubygems.org/\n"
  },
  {
    "path": "ruby/sample_1.rb",
    "content": "class SomeClass\n  SOME_CONSTANT = \"upper case name\"\n\n  def initialize(attributes)\n    @some_attribute = attributes[:some_attribute]\n    @another_attribute = attributes[:another_attribute]\n    @user_factory = attributes[:user_factory]\n  end\n\n  def method_with_arguments(argument_one, argument_two)\n    a_really_long_line_that_is_broken_up_over_multiple_lines_and\n      .subsequent_lines_are_indented_and\n      .each_method_lives_on_its_own_line\n  end\n\n  def method_with_required_keyword_arguments(one:, two:)\n  end\n\n  def method_with_multiline_block\n    some_method_before_block(should_be_followed_by_a_newline)\n\n    items.each do |item|\n      do_something_with_item\n      perform_another_action\n    end\n\n    some_method_after_block(should_follow_after_newline)\n  end\n\n  def method_with_single_method_block\n    items.map(&:some_attribute)\n  end\n\n  def method_with_oneline_combined_methods_block\n    items.map { |item| \"#{item.one} #{item.two}\" }\n  end\n\n  def method_that_returns_an_array\n    [item_one, item_two]\n  end\n\n  def method_that_returns_a_hash\n    {key: \"value\"}\n  end\n\n  def method_with_large_hash\n    {\n      one: \"value\",\n      two: \"value\"\n    }\n  end\n\n  def method_with_large_array\n    [\n      :one,\n      :two,\n      :three\n    ]\n  end\n\n  def method_which_uses_infix_operators\n    left + middle - right\n  end\n\n  def method_which_uses_unary_operator\n    !signed_in?\n  end\n\n  def method_without_arguments\n    if complex_condition?\n      positive_branch\n    else\n      negative_branch\n    end\n\n    rest_of_body\n  end\n\n  def method_that_uses_factory\n    user = user_factory.new\n    user.ensure_authenticated!\n  end\n\n  def self.class_method\n    method_body\n  end\n\n  def memoized_method\n    @_memoized_method ||= 1\n  end\n\n  private\n\n  attr_reader :foo, :user_factory\n  attr_accessor :bar\n  attr_writer :baz\n\n  def complex_condition?\n    part_one? && part_two?\n  end\nend\n\nmodule A\n  class B\n  end\nend\n"
  },
  {
    "path": "ruby/sample_2.rb",
    "content": "# Include an href or to_param attribute when serializing models\nclass PostSerializer < ActiveModel::Serializer\n  attributes :id, :content, :to_param\n\n  delegate :to_param, to: :object\nend\n\nFactoryBot.define do\n  factory :event do\n    start_on { 1.week.from_now }\n  end\nend\n"
  },
  {
    "path": "sass/.stylelintrc.json",
    "content": "{\n  \"extends\": \"@thoughtbot/stylelint-config\"\n}\n"
  },
  {
    "path": "sass/README.md",
    "content": "# Sass\n\n- [Sample](sample.scss)\n- [Shared stylelint configuration]\n\n  - This configuration aligns with our team-wide guides below. It does _not_,\n    however, enforce a particular class naming structure, which is a team\n    decision to be made on a per-project basis.\n\n- When using [sass-rails], use the provided [asset-helpers] (e.g. `image-url`\n  and `font-url`), so that Rails' Asset Pipeline will re-write the correct paths\n  to assets.\n- Prefer mixins to `@extend`.\n- Use maps and variables to codify and centralize breakpoint values\n  - Prefer abstract names such as `small`, `medium`, `large`, etc. instead of\n    specific devices\n  - Nest breakpoints inside of the relevant selector\n  - If a component needs a specific breakpoint to work, keep it with the\n    relevant component partial. If other components need the same value,\n    integrate it into the centralized breakpoint list\n\n[shared stylelint configuration]: https://github.com/thoughtbot/stylelint-config\n[sass-rails]: https://github.com/rails/sass-rails\n[asset-helpers]: https://github.com/rails/sass-rails#asset-helpers\n\n## Formatting\n\n- Use the SCSS syntax.\n- Use hyphens when naming mixins, extends, functions & variables: `span-columns`\n  not `span_columns` or `spanColumns`.\n- Avoid using shorthand properties for only one value: `background-color:\n  #ff0000;`, not `background: #ff0000;`\n- Use `//` for comment blocks not `/* */`.\n- Avoid in-line operations in shorthand declarations (Ex. `padding: $variable *\n  1.5 variable * 2`)\n- Use parentheses around individual operations in shorthand declarations:\n  `padding: ($variable * 1.5) ($variable * 2);`\n- Use a `%` unit for the amount/weight when using Sass's color functions:\n  `darken($color, 20%)`, not `darken($color, 20)`\n- Use a trailing comma after each item in a map, including the last item.\n\n## Selectors\n\n- Use meaningful names: `$visual-grid-color` not `$color` or `$vslgrd-clr`.\n- Use ID and class names that are as short as possible but as long as necessary.\n- Avoid nesting more than 3 selectors deep.\n- Avoid using comma delimited selectors.\n- Avoid nesting within a media query.\n\n## Organization\n\n- Use a `base` directory for styling element selectors, global variables, global\n  extends and global mixins.\n- Use HTML structure for ordering of selectors. Don't just put styles at the\n  bottom of the Sass file.\n- Avoid having files longer than 100 lines.\n\n## General syntax and formatting\n\n### Declarations block ordering\n\n- Order declarations alphabetically.\n- Order items within the declaration block in the following order:\n  1. Sass at-rules, e.g. `@include`\n  1. CSS properties\n  1. Media queries\n  1. Pseudo-classes\n  1. Pseudo-elements\n  1. Nested elements\n\n<details>\n\n#### Code examples\n\nAlphabetize declarations:\n\n```scss\n.class {\n  display: block;\n  text-align: center;\n  width: 100%;\n}\n```\n\nAlphabetize prefixed properties as if the prefix doesn't exist:\n\n```scss\n.class {\n  font-family: system-ui;\n  -webkit-font-smoothing: antialiased;\n  font-weight: $weight-variable;\n}\n```\n\nComprehensive example of ordering items within a declaration block:\n\n```scss\n.class {\n  @include size(10px);\n\n  display: block;\n  margin: $spacing-variable;\n\n  @media (min-width: $screen-variable) {\n    padding: $spacing-variable;\n  }\n\n  &:focus {\n    border-color: $color-variable;\n  }\n\n  &::before {\n    content: \"\";\n  }\n\n  .nested-element {\n    margin: $spacing-variable;\n  }\n}\n```\n\n#### Motivation\n\nAlphabetizing can be automated and is commonly a feature built into code editors\n(see Resources below).\n\n#### Linting\n\nAlphabetical declaration ordering can be linted using stylelint with the\n[stylelint-order] plugin and its `order/properties-alphabetical-order` rule.\n\n[stylelint-order]: https://github.com/hudochenkov/stylelint-order\n\n#### Resources\n\n- Atom users can use the [Sort Lines package], which provides commands and\n  keybindings for alphabetical sorting.\n- Sublime Text users can use the `Edit > Sort Lines` menu item, or press\n  <kbd>F5</kbd> to sort lines alphabetically.\n\n[sort lines package]: https://github.com/atom/sort-lines\n\n</details>\n"
  },
  {
    "path": "sass/sample.scss",
    "content": "@import \"partial-name\";\n\n$color-variable: #ffffff;\n\n/* I'm here to explain what this class does */\n.class-one {\n  background-color: $color-variable;\n  border: 0;\n  line-height: 1.5;\n  text-size: 0.5rem;\n  transition: background-color 0.5s ease;\n\n  @media (width >= 1px) {\n    margin: ($spacing-variable * 2) 1rem;\n  }\n\n  &:hover {\n    box-shadow: 0 0 2px 1px rgba($color-variable, 0.2);\n  }\n\n  &::before {\n    content: \"hello\";\n  }\n}\n\n$map: (\n  \"key-1\": value-1,\n  \"key-2\": value-2,\n);\n\n.class-two {\n  @extend %placeholder;\n  @include mixin;\n\n  align-items: center;\n  display: flex;\n  flex: 1 1 auto;\n\n  a {\n    text-decoration: none;\n\n    &:focus,\n    &:hover {\n      text-decoration: underline;\n    }\n  }\n\n  &.child {\n    color: $red;\n  }\n}\n"
  },
  {
    "path": "security/README.md",
    "content": "# Security\n\nA guide for practicing safe web.\n\n## Think\n\nSecurity is important, and you can't practice these guidelines without\nunderstanding them. Make sure you understand each guideline, why it exists, and\nhow to follow it.\n\nFailing to follow these guidelines will likely put you, your team, and your\ndeployed services at risk of compromise or loss of privacy.\n\n## Secure Employee Access and Communication\n\nThe following guidelines apply to how you as an individual secure access to your\nsystems (laptop, accounts, etc.) and communication (email, etc.).\n\n## Protecting Personal or Identifying Information\n\nSee [protecting personal or identifying information][].\n\n### Using Passwords\n\n- Use a unique password for every account you create.\n- Use a tool like [pwgen] or [1password] to generate random passwords.\n- Use a tool like GnuPG to encrypt passwords if you need to share them with\n  somebody.\n\n[pwgen]: https://github.com/jbernard/pwgen\n[1password]: https://1password.com\n[protecting personal or identifying information]: ./protecting-personal-or-identifying-information.md\n\n### Encryption\n\n- Ensure [disk encryption] on your laptop.\n- Use a PGP signature in an email if you want somebody to trust that you wrote\n  it.\n- Use PGP to check email signatures if you want to know who wrote it.\n- Use PGP to encrypt emails if you want to be sure nobody but the recipient is\n  reading it.\n- Use ultimate trust for your own keys.\n- Use full trust for keys you have verified in person or via a secure video\n  chat.\n- Don't share your private key with anyone, including services like Keybase.\n- Keep at least one backup of your private key and revocation certificate in a\n  secure location, such as a thumb drive.\n\n[disk encryption]: https://theintercept.com/2015/04/27/encrypting-laptop-like-mean/\n\n## Physical Security\n\nThe following guidelines apply to how we physically secure our laptops and\nmobile devices that may contain customer or user data.\n\n- Lock your device when you are away from it.\n- Don't leave your devices unattended in an unsecured area.\n- Install a device tracking and remote data wipe tool such as [Prey].\n\n[prey]: https://www.preyproject.com/\n\n## Application Security\n\nThe [application security guidelines](application.md) apply to how we develop\nsoftware on behalf of ourselves and clients.\n\n## Handling Vulnerabilities\n\nThe following guidelines apply to how we handle security incidents.\n\n### Reporting\n\nWhen someone finds a possible security issue in our software, we encourage them\nto report it to our <security@thoughtbot.com> email address.\n\nWhen an email comes in through this channel, reply quickly with confirmation\n(and CC <security@thoughtbot.com> so others know that it has been handled) and\nthe information for the thoughtbot PGP key, which is located at <https://thoughtbot.com/security>.\n\n### Reviewing, Logging and Following Up\n\nWhen an encrypted message comes in, post the exchange to a new [Hub Message](https://hub.thoughtbot.com/messages/new) in the `security` interest, and keep the thread updated with new messages\nas they appear.\n\nFurther discussion of security takes place in the [Security Basecamp].\n\n[security basecamp]: https://3.basecamp.com/3091943/projects/15753689\n"
  },
  {
    "path": "security/application.md",
    "content": "# The thoughtbot Guide to Application Security\n\n## Threat modeling\n\nThe task of identifying concrete attacks and understanding their relationship\nwith the code is the core task of threat modeling. We can understand this from\ntwo perspectives:\n\n- identify what can go wrong, and\n- don't account for things that cannot go wrong.\n\nIdentifying what can go wrong is what is most often [written about when\ndiscussing threat] modeling. There are [many threat modeling techniques], but\nthe summary is:\n\n1. Create a list of what an attacker can do on your app. For a Web app, they\nmight be able to spoof HTTP headers, submit malicious data, or embed a Web page\nin an `iframe`.\n2. Add to the list the weak points of the app. These will likely be places where\nyou are doing something non-standard, which the frameworks don't know how to\nprotect.\n3. Prioritize this list. Take into account factors such as difficulty of attack,\nlikelihood of attack, ease of mitigating the attack, and severity of attack.\n\nAnything not in the list are things you cannot use as a reason to do something.\nSince the list is prioritized, you can use it to help prioritize tickets or\nsplit tickets.\n\n[written about when discussing threat]: https://www.owasp.org/index.php/Application_Threat_Modeling\n[many threat modeling techniques]: https://insights.sei.cmu.edu/sei_blog/2018/12/threat-modeling-12-available-methods.html\n\n## Library updates\n\nThe easiest line of defense you have as a developer is [applying security fixes\nfor our dependencies] as they are released.\n\nOn the flip perspective, when releasing a security fix for one of our projects,\nmake it trivial to upgrade: don't include new features or unrelated bug fixes.\n\nThere are a few ways to keep up with security fixes:\n\n- Any platform-specific tool, such as [bundler-audit].\n- [Any official CVE feed].\n\nIf you have access, the thoughtbot [Security Basecamp] does our best to keep up\nwith security issues that we think will affect us or our clients.\n\n[applying security fixes for our dependencies]: https://snyk.io/blog/top-ten-most-popular-docker-images-each-contain-at-least-30-vulnerabilities/\n[bundler-audit]: https://github.com/rubysec/bundler-audit#readme\n[any official cve feed]: https://cve.mitre.org/cve/data_updates.html\n[security basecamp]: https://3.basecamp.com/3091943/projects/15753689\n\n## Secure programming\n\nIn an ideal world, access to the program's source code will not give an attacker\nan advantage. This is not always possible, but programming with a mindset of\npreventing an all-knowing attacker can be healthy.\n\n[Some tips] along the way:\n\n- Always check return values. If the procedure can raise, make sure to handle\n  that (to prevent DoS attacks). If the procedure can signal failure, make sure\n  to handle that (to prevent read-after-free-style attacks).\n- Fail fast. If the data seems odd, don't recover: fail.\n- Leave the most security-sensitive code as an [omega mess], once it works. Too\n  many bugs -- more than zero -- come out of refactoring to be worth a change in\n  the name of code beauty.\n\n[some tips]: https://twitter.com/SarahJamieLewis/status/1097300029016989696\n[omega mess]: https://speakerdeck.com/skmetz/go-ahead-make-a-mess\n\n## User data\n\nAny data from the user is malicious until proven innocent. Examples of user\ninput are data from forms, HTTP headers, text the user enters into your mobile\napp, IP address, MAC address, email headers, file paths, GraphQL queries,\nuploaded files, and stdin. And more.\n\nWhen possible, rely on a framework to parse user data. Don't parse HTTP headers\nby hand, use the Rails validations, pass JSON data through a schema validator,\nsend addresses straight to the shipping or map API, etc.\n\nIf you can't rely on a library, handle user data in two stages: verify, then\nwork with it. For example, if someone uploads a file with a filename ending in\n`.jpg`, use `libmagic` to confirm that it is a JPEG, and then consider it less\ntainted and ready for use.\n\n### SQL injection\n\nWe know about this one, so let's make sure it does not happen.\n\nWhenever you run a SQL query, don't insert user input into it. If you must\ninsert user data into it, use a [bind variable]. (The details of how bind\nvariables work depends on your object-relational mapping library.)\n\n[bind variable]: https://www.ibm.com/developerworks/library/se-bindvariables/index.html\n\n### YAML\n\n[YAML is too vulnerable to attacks] to consider for new projects.\n\n[yaml is too vulnerable to attacks]: https://trailofbits.github.io/rubysec/yaml/index.html\n\n### Client-side validation\n\nAll client-side validation, such as a React component that tells the user that\ntheir email address is not in a valid format, is for presentation. These checks,\nand more, must be duplicated on the backend. Any attacker can use curl to bypass\nyour client-side validations.\n\n### Cookies\n\nCookies are user-controlled input and, therefore, should be treated with\nsuspicion. If possible, don't rely on a cookie.\n\nCookies can be copied between browsers. Just because a request sends a cookie\ndoes not mean that the cookie was sent by the user's original browser. It might\ncome from curl.\n\nOne way to retain control over the cookie data is to sign it using a secret key\nonly known by the server. Rails does this for you.\n\n## Logging\n\nLogging is a compromise between having enough data to be able to debug a problem\nand having too much personally-identifying information about a user.\n\nMake sure not to log passwords, credit card numbers, or any other information\nthat you do not strictly need. Err on the side of not logging any strings, if\npossible.\n\nIn Rails, use the `filter_parameters` configuration setting to remove known\nattributes from the logs.\n\nIn addition, if you are logging to a service over a network connection, make\nsure the connection itself is secured using TLS.\n\n## Personally-Identifying Information (PII)\n\nAs much as you can, do not touch any information you don't need. Some tricks for\nthis:\n\n- Send any credit card data directly to the payment processor from the client.\n  They'll give back a token, which you can store safely.\n- You probably don't need the user's sex, gender, date of birth, middle name,\n  and so on. You might, but ask yourself first: do you?\n\nWhen you must store PII:\n\n- Use [password best practices] for any account with access to PII,\n  including developer accounts which have access to production.\n- Avoid using shared logins with access to PII, even if such logins are managed\n  by a service like 1Password.\n- If you must own a shared login, such as AWS account root credentials, store a\n  password and OTP secret separately so that two people are required when\n  accessing the account.\n- Use multi-factor authentication for all accounts with access to PII,\n  including developer accounts with access to production.\n- Use an audit log documented when PII was accessed and why.\n- Use a documented procedure for onboarding and offboarding users with access to\n  PII, including developers.\n- Avoid granting access to PII until necessary; only users that require access\n  should be granted access.\n- Use [application-level encryption] to encrypt all PII.\n- Use in-transit and at-rest encryption for any database containing PII.\n- Use network isolation, such as an [AWS VPC], for databases containing PII.\n- Use a unique encryption key, such as an [AWS Customer Managed Key] for each database containing PII.\n- Use automatic rotation for any passwords with access to PII, such as Postgres\n  credentials.\n\n[password best practices]: ./README.md#using-passwords\n[application-level encryption]: https://edgeguides.rubyonrails.org/active_record_encryption.html\n[AWS VPC]: https://docs.aws.amazon.com/vpc/latest/userguide/what-is-amazon-vpc.html\n[AWS Customer Managed Key]: https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#customer-cmk\n\n## Randomization\n\nMost modern cryptography is dependent on really big prime numbers and access to\nsolid randomization. If you find yourself in a place where you need a random\nnumber, here are some things to keep in mind.\n\n- Don't do this yourself. If you can use Ruby's `SecureRandom` or functions like\n  `arc4random_buf(3)` and `arc4random_uniform(3)`, do that instead.\n- [Do not restrict the randomized space] with a modulo or floating-point\n  multiplication bias. Instead, try generating a random number in a loop,\n  returning when the value is within the desired range.\n- Use an unpredictable seed. Do not use the current time, or the seconds since\n  boot, or `0`, or your age, or the result from calling rand seeded on a\n  predictable seed. If possible, use a random number generator that you do not\n  seed yourself, such as `arc4random(4)` or `/dev/random`.\n- Use a non-blocking random number generator. If an attacker discovers that the\n  random number generator blocks, such as Linux's `/dev/urandom`, that is a\n  potential denial of service attack vector.\n\n[do not restrict the randomized space]: http://www.pcg-random.org/posts/bounded-rands.html\n\n## Hashing\n\nA hashing function provides a one-way encoding of an object. Use this any time\nyou don't actually care what the value _is_, but instead you care that you have\nit at all. The only operation you'll want to perform against a hashed object is\nan equality check.\n\n(As a side note, when people refer to dictionary data structures as \"hashes\",\nthey're referring to the fact that a hashing function is used to turn the key\ninto a unique number.)\n\n(As a second side note, when people refer to blockchains as \"cryptocurrency\",\nthey're making reference to the fact that they used a hashing function. Twice.)\n\nHashing algorithms are as strong as their ability to generate a unique,\none-direction hash. When someone finds a way to generate the same hash for two\ndifferent inputs, the hashing function is considered insecure. The American\nNational Institute of Standards and Technology (NIST) maintains [a list of\napproved hash algorithms]; as of this writing SHA-2 and SHA-3 are approved.\n\nNote that base64 encoding is not a hashing function, since it intentionally can\nbe decoded.\n\nUse an approved secure hashing algorithm to verify that something has not been\ntampered with. Some examples of that are tarballs (both ones you download and\nalso ones you provide to other devs -- always send a hash of the file so the\ndownloader can confirm the file before opening it) and API request bodies.\n\nA fun example is to make a \"precommit\" statement among friends: create a\nsentence predicting an outcome, then share the hash of the sentence. When the\noutcome comes true, share the original text.\n\n[a list of approved hash algorithms]: https://csrc.nist.gov/Projects/Hash-Functions\n\n### Hash-based Message Authentication Code (HMAC)\n\nIf using a hash to verify a JSON API body, you and the client might have a\nshared secret that you concatenate onto the body so you can be sure that it is\nuntampered with.\n\nThe way most secure hashing algorithms work is based on blocks of bytes of a\nspecific length. The input is split and padded to fit into the correct length.\nThis leaves them open to a length-extension attack, where a knowledgeable\nattacker can add on to the input and compute a valid new hash by\nreverse-engineering the internal state of the hashing function without knowing\nthe secret.\n\nA Hash-based Message Authentication Code (HMAC) is designed to work around that.\nInstead of hashing the secret concatenated with the message, it hashes the\nsecret concatenated with the hash of the secret concatenated with the message.\n\nIt's possible that you will not directly interact with HMACs but they do show up\nin TLS, JWT, and one-time passwords.\n\n### Passwords\n\nNote that for passwords, the attacker does not need to know the user's password\n_per se_; the attacker needs to know a string which will generate the desired\nhash. This is known as a collision attack.\n\nA rainbow table attack is done with a rainbow table: a giant list of every\npossible string and its resulting hash. Using such a list, the attacker can\nquickly look up the password given a hash.\n\nA similar attack is to, given one hash, run through every possible string,\nhashing each one, until you find a match.\n\nRainbow-table-style attacks have been on the rise since the early 1990s, making\ntypical secure hashing functions inappropriate for passwords.\n\nThe first solution is to use a salt: generate a random number, add that to the\nuser's password, and hash _that_ string. Store the salt alongside the hashed\npassword; each user gets their own salt.\n\nSalts destroy rainbow tables and cause headaches for hashing each string one at\na time. But not enough of a headache: GPUs are at a point now where they can run\nsecure hashing functions quickly. Too quickly.\n\nThe solution is to use a key derivation algorithm. These are much like normal\nhashing algorithms (they're actually quite different, but that difference is\nnegligible), except they are intentionally slow.\n\nThe most common password hashing algorithms are bcrypt, scrypt, and PBKDF2. Each\nof these require a salt, but handle it themselves: the output of these functions\nis a string that contains the salt plus the hashed value. Store that entire\nstring as the hashed password.\n\n## Encryption\n\nAn encryption algorithm is one where a string can be made illegible and then\nreturned back to the original string again, and where decrypting requires an\nout-of-band secret.\n\nLess abstractly: a string can be encrypted, and then to decrypt you must know\nthe password.\n\nThere are two kinds of encryption algorithms: symmetric and asymmetric. A\nsymmetric algorithm is one where the same secret is used to encrypt it and\ndecrypt it. An asymmetric algorithm is one where the string can be encrypted and\ndecrypted using different secrets -- where the person encrypting cannot\nnecessarily decrypt it.\n\nThe most popular symmetric algorithms you'll encounter are AES and Twofish.\nThese might be useful for encrypting a file to share with a group of people or\nfor encrypting your filesystem. 1Password uses AES to encrypt an entire vault;\nit is encrypted at rest, and only decrypted when you enter the passphrase.\n\nAsymmetric encryption algorithms, also known as public/private key pair\nencryption, are more well-known -- in large part for how tricky they are to get\nright. Some famous ones are SSH, TLS (previously SSL), and PGP. These start by\ngenerating a pair of encryption secrets known as the public and private keys.\nAnyone with the public key can encrypt a string, but only the holder of the\nprivate key can decrypt it.\n\n([The math around asymmetric encryption] is cool. I won't go into it.)\n\n[the math around asymmetric encryption]: http://pi.math.cornell.edu/~mec/2003-2004/cryptography/diffiehellman/diffiehellman.html\n\nAsymmetric keys and messages encrypted using an asymmetric algorithm are larger\nthan messages encrypted using a symmetric algorithm. It is common to use an\nasymmetric algorithm -- where fewer people need to know the secret of how to\ndecrypt -- to exchange the secrets for a symmetric algorithm, then use a\nsymmetric algorithm for the rest of the exchange. Such a protocol will save\nbytes and computational power.\n\nIn order for any of this to work, you need to get your hands on a confirmed\npublic key. Each public key has a fingerprint -- an abbreviated and\neasily-confirmable portion of the entire secret. How this works in practice\ndepends on the protocol.\n\n### Signing\n\nAn asymmetric encryption algorithm can be run in reverse to provide for signing.\nIn this, a private key is used to sign a string, producing a signature string.\nThe public key can be used to verify that the private key was used to generate\nthe signature, proving that the string was in the control of the owner of the\nprivate key.\n\nThis is useful for certificate authorities, as used by TLS, but also useful for\nsharing files. You can provide the tarball and the signature, and anyone with\nyour public key can verify that the tarball was created by you (or, at least,\nanyone with your private key). The Debian package system is built around this.\n\n### SSH\n\nSSH defaults to a trust-on-first-use (TOFU) policy: the first time you connect\nto a server you are asked to confirm the server's public key fingerprint:\n\n```text\nThe authenticity of host heroku.com can't be established.\nRSA key fingerprint is 8tF0wX2WquK45aGKs/Bh1dKmBXH08vxUe0VCJJWOA/o.\nAre you sure you want to continue connecting (yes/no)?\n```\n\nThe server admin will need to tell you out of band whether that is the correct\nfingerprint ([Heroku publishes their fingerprint online]).\n\n[heroku publishes their fingerprint online]: https://devcenter.heroku.com/articles/git-repository-ssh-fingerprints\n\n### PGP\n\nOpenPGP is a way for users to trust each other; therefore, fingerprint\nverification happens in person, often in a [key signing party]. People will\nexchange the fingerprint of their PGP key face-to-face, often written on paper,\nand then later will confirm that the key they have for the person matches the\nfingerprint on the paper.\n\nThis mechanism is called a web of trust.\n\n[key signing party]: http://mdcc.cx/gnupg/ksp_intro.en.html\n\n### TLS\n\nTransport Layer Security is a way for a browser to trust a server. The browser\nships with a list of trusted public keys. Each Web site serves up its own public\nkey, plus a signature from another key. If the signature is by one of the\ntrusted public keys, the browser accepts the Web site's key; otherwise, it's a\nfailure.\n\nFor example, Firefox trusts GlobalSign. thoughtbot.com has a TLS certificate\nthat was signed by GlobalSign. When you visit thoughtbot.com, it sends its\npublic key plus the signature from GlobalSign. Firefox trusts GlobalSign, so it\ntrusts thoughtbot.com's key.\n\nThis mechanism is called a certificate authority.\n\n## Encrypting and hashing\n\nEncryption (PGP, AES) is different from hashing (SHA-256, bcrypt, etc.), because\nit can be reversed, and this is different from encoding (base64, base58, etc.)\nbecause reversing it requires a password.\n\nIt can be handy to combine these technologies:\n\n- Encrypt and hash. The recipient can confirm that they have the right string by\n  checking the hash before even attempting to decrypt it. This might save them\n  from attempting to decrypt a malicious string.\n- Hash and encode. This can be handy for when you need to triple-check that a\n  JSON payload made it through safely: hash the JSON, then base64 the hash,\n  which encodes it into ASCII, making it safer to send across HTTP.\n\n## TLS\n\n[Transport Layer Security (TLS) is a general-purpose mechanism] for confirming\nthe integrity, confidentiality, and authenticity of data sent over TCP. It\ncombines symmetric encryption, asymmetric encryption, and hashing functions to\ntransmit data securely and efficiently.\n\nIt does _not_ guarantee that the domain owner is trustworthy. TLS does not\nrelate to trust. It can only guarantee that the information is sent, untampered\nand privately, only to the recipient you are sending it to. It does not\nguarantee that you are sending it to the right recipient.\n\nThere are two kinds of certificates signed by certificate authorities: domain\nverification and extended verification. Domain verification does what it says on\nthe tin: it confirms that the holder of the private key is also in control of\nthe domain name. Extended verification goes further and cannot be automated: it\nconfirms that the holder of the private key controls the domain name and is the\nperson or company they claim to be.\n\nExtended verification does not guarantee that the holder of the private key is\ntrustworthy.\n\nWe typically interact with TLS via HTTPS, but it can be used for any TCP\nconnection, such as email.\n\nThe first version of TLS was named Secure Sockets Layer (SSL); at the end of the\nlast century, SSL was found to be trivially vulnerable and has not been\nintentionally used since.\n\n[transport layer security (tls) is a general-purpose mechanism]: http://rebecca.meritz.com/ggm15/\n\n### HSTS\n\nThe most common attack vector for a secure protocol is a downgrade attack. Many\nprotocols have a backward-compatibility mechanism that allows the client and\nserver to negotiate which version of a protocol they both understand. Convincing\nthe server to downgrade to a version of a protocol with a known bug is a\ndowngrade attack.\n\nThe worst case is when you can convince the server to drop the security\nentirely. This is possible with HTTPS with a standard man-in-the-middle attack\nof the _unencrypted_ HTTP connection.\n\nIt works like this:\n\n1. User visits `twitter.com`.\n2. Web browser turns this into `http://twitter.com/`.\n3. An eavesdropper intercepts the connection and redirects to their own server,\n   secured using TLS, but entirely under their control.\n\nThe problem is step (2). The current solution is HTTP Strict Transport Security\n(HSTS). Under HSTS, the browser knows about domain names that should always be\nHTTPS. It literally has a list. If you enter `twitter.com` into the URL bar, it\nwill check its list, find `twitter.com` in there, and complete the full URL as\n`https://twitter.com/`.\n\nWeb sites can add themselves to the user's local list by sending the\n`Strict-Transport-Security` header. The value for this header is\n`max-age=31536000; includeSubDomains; preload`.\n\n- `max-age` determines how long this domain should remain in the browser's list.\n  `31536000` is one year. Feel free to go longer.\n- `includeSubDomains` specifies that subdomains should also be considered part\n  of the HSTS list.\n- `preload` tells the browser maintainer that you are comfortable with this\n  domain being part of [the list shipped with the browser].\n\nUnrelated to HSTS but sort of a corollary of how the attack works: specify the\nprotocol (`https://`) in all your links.\n\n[the list shipped with the browser]: https://hstspreload.org/\n\n## Passwords\n\nAs has been mentioned, use bcrypt for storing your passwords in a database.\n\nDesign the user experience to encourage your users to use a password manager:\n\n- Allow paste. Do the minimum to the password field -- and be sure to annotate\n  that it is a standard password field (`type=\"password\"` in HTML,\n  `android:inputType=\"password\"` in Android,\n  `passwordTextField.isSecureTextEntry=true` in iOS) -- so that the user's\n  password manager can work with it.\n- Never expire passwords. [To quote NIST]:\n  > Users tend to choose weaker memorized secrets when they know that they will\n  > have to change them in the near future. When those changes do occur, they\n  > often select a secret that is similar to their old memorized secret by\n  > applying a set of common transformations such as increasing a number in the\n  > password. This practice provides a false sense of security if any of the\n  > previous secrets has been compromised since attackers can apply these same\n  > common transformations.\n- Allow passwords to be more complex. Whether you want to enforce light password\n  complexity rules or not ([NIST discourages password complexity rules], allow\n  for passwords longer or otherwise more complex than you expect. When possible,\n  treat passwords as bytes that are immediately hashed and stored.\n\nA good password has a few properties:\n\n- Complex enough to be hard to crack through a boring enumeration attack.\n- Able to be changed when compromised.\n- Unique to the account.\n- Can be stored securely by the user (in their own head, in a password manager,\n  in a locked notebook, etc.).\n- Can be kept as a secret.\n- Leaking the password only threatens the security of that password.\n\nBiometrics (iris scan, face recognition, thumbprint reader, etc.) violate most\nof those qualities. Biometrics are useful for identity but incorrect to use as\nan authentication secret.\n\n[to quote nist]: https://pages.nist.gov/800-63-FAQ/#q-b5\n[nist discourages password complexity rules]: https://pages.nist.gov/800-63-FAQ/#q-b6\n\n### Timing attacks\n\nAn attacker can learn a lot from _how long_ it takes to be denied access. If\nit's instant, that means the input didn't even pass validation; if it's kinda\nlong, that means that the input got past validation and computed a hash but one\nof the first few characters of the hash were incorrect; a longer delay means\nthat most of the hash was right. Knowing how much of the hash was right allows\nthe attacker to narrow the attack space.\n\nThe solution: use a constant-time equality check for comparing the hashed\nvalues. Bcrypt libraries ship with a function that does everything for you.\nActiveSupport ships with [`secure_compare`] for constant-time comparisons.\n\nWorst case: pad the string to a fixed length then make sure your loop goes\nthrough every character even after you know the answer.\n\n[`secure_compare`]: https://api.rubyonrails.org/classes/ActiveSupport/SecurityUtils.html#method-c-secure_compare\n\n## Multi-factor authentication (2FA)\n\nGiven an email and password, you can authenticate as a user any time you wish.\nIf someone were to mistakenly use the same password for multiple services, it is\nas strong as the least secure of those services: if the password were leaked,\nthe password for all of those accounts would be leaked along with it.\n\nWe can mitigate these kinds of attacks by requiring a second security factor --\nfor example, a second password. We can go further by defining different\ncategories of authentication:\n\n- Something you know, such as a string of letters.\n- Something you are, such as biometrics.\n- Something you have, such as a phone.\n\nWe can use a HOTP or TOTP algorithm to send and verify short codes out of band\nto something the user has, such as via email, SMS, an external program, or a\nhardware key. [Email and SMS have known security issues], as we'll discuss\nlater, so lean on an external program or hardware when possible.\n\n[email and sms have known security issues]: https://www.makeuseof.com/tag/two-factor-authentication-sms-apps/\n\n### OTP\n\nThe HMAC-based One-Time Password (HOTP) algorithm, [RFC 4226], is a somewhat\nstraightforward function. The details can be found in the RFC but in summary it\nworks like this: the client and server communicate a shared secret (typically\nvia QR code). Whenever you need a one-time password, the shared secret is\ncombined with an incrementing number, hashed, and then six digits are pulled\nout. Those six digits are the one-time password.\n\nWhere can one get an incrementing number that both the client and server know\nabout? We can use the number of minutes since the epoch. This gives us the\nTime-based One-Time Password (TOTP) algorithm, [RFC 6238].\n\nMost languages have a library for handling OTP. Ruby's is called `rotp`. As\nalways, use the library instead of implementing it yourself.\n\nIn practice it goes like this:\n\n1. Generate a secret. Store this for the user.\n2. Present the secret to the user as a QR code and optionally as a string. The\n   user will use an app to scan the QR code into the OTP app. Some example apps\n   are Google Authenticator and Duo, but the algorithm is simple enough that any\n   app will do.\n3. Prompt the user for an OTP. If they confirm correctly, enable 2FA for them\n   through this method.\n4. Next time they sign in, prompt them for an OTP generated by their app.\n   Confirm it by comparing against the OTP calculated on the server.\n\nNote that the app can run entirely offline: it works by adding a secret key\nlocally and computing an OTP from a combination of hashing functions. However,\nthe counter value (e.g. minutes since epoch) must remain in sync between the\nserver and client. Typically this means using NTP. If debugging, check the time\nfirst.\n\nAlso note that TOTP is using the minute as the counter. If the client computes\nthe OTP at 12:30:59 and the server computes the OTP at 12:31:02, it will compute\na different value. The RFC recommends that the server accept OTP values for any\ntime over the past 30 seconds or the future 30 seconds, to account for latency\nand drift.\n\n[rfc 4226]: https://tools.ietf.org/html/rfc4226\n[rfc 6238]: https://tools.ietf.org/html/rfc6238\n\n### Communicating an OTP\n\nAn external app (Google Authenticator, 1Password, or a command-line tool) is the\nsafest easy option for the client: the only point of attack is when the secret\nis initially communicated, and otherwise using it is offline and out of band.\n\nSending an OTP from the server is less secure since it provides a window of\nattack each time the user authenticates. If you can send it securely, such as\nvia an encrypted email or over Signal, that will reduce the attack.\n\nPlain text emails are open to the public and can be read or spoofed by anyone,\nmaking them effectively useless for communicating a one-time password.\n\nUsing SMS is [categorised as \"RESTRICTED\" by NIST][nist], since they are open to\nexploitation from a variety of methods (e.g device swap, SIM swap, number\nporting, etc).\n\nSending a one-time password via SMS is more secure than only a single form of\nauthentication.\n\n[nist]: https://pages.nist.gov/800-63-3/sp800-63b.html#pstnOOB\n\n## Rate-limiting\n\nAn attacker could try many passwords, OTP codes, emails, or any kind of input\nto compromise your system.\n\nAn attacker could also request slow endpoints of your application to make it\nuse its limited-resources.\n\nTools like [rack-attack](https://github.com/rack/rack-attack) can help you\nminimize this attack surface.\n"
  },
  {
    "path": "security/protecting-personal-or-identifying-information.md",
    "content": "# Protecting Personal or Identifying Information\n\nData privacy and security should be made a priority when developing software in\nan effort to protect personal or identifying information.\n\nData privacy and security is important for everyone. It is especially vital for individuals who, due to their backgrounds or circumstances, might be at a higher risk of harmful consequences from privacy violations.\n\nExamples include:\n\n- Survivors of domestic abuse or those who are trying to escape domestic abuse\n- LGBTQIA+ individuals who might be in an unsafe circumstance in relation to their identity, including if their housing is dependent on someone who might evict them because of it\n- Political dissidents, asylum seekers, targets of government-sanctioned\n  violence\n- Undocumented immigrants\n"
  },
  {
    "path": "shell/README.md",
    "content": "# Shell\n\n- Break long lines on `|`, `&&`, or `||` and indent the continuations.\n- Don't add an extension to executable shell scripts.\n- Don't put a line break before `then` or `do`, use `if ...; then` and `while\n  ...; do`.\n- Use `for x; do`, not `for x in \"$@\"; do`.\n- Use `snake_case` for variable names and `ALLCAPS` for environment variables.\n- Use single quotes for strings that don't contain escapes or variables.\n- Use two-space indentation.\n- Don't parse the output of `ls`. Understand [why you shouldn't and available\n  alternatives].\n- Don't use `cat` to provide a file on `stdin` to a process that accepts file\n  arguments itself.\n- Don't use `echo` with options, escapes, or variables (use `printf` for those\n  cases).\n- Don't use a `/bin/sh` [shebang] unless you plan to test and run your script on\n  at least: Actual Sh, Dash in POSIX-compatible mode (as it will be run on\n  Debian), and Bash in POSIX-compatible mode (as it will be run on macOS).\n- Don't use any [non-POSIX features] when using a `/bin/sh` [shebang].\n- If calling `cd`, have code to handle a failure to change directories.\n- If calling `rm` with a variable, ensure the variable is not empty.\n- Prefer \"$@\" over \"$\\*\" unless you know exactly what you're doing.\n- Prefer `awk '/re/ { ... }'` to `grep re | awk '{ ... }'`.\n- Prefer `find -exec {} +` to `find -print0 | xargs -0`.\n- Prefer `for` loops over `while read` loops.\n- Prefer `grep -c` to `grep | wc -l`.\n- Prefer `mktemp` over using `$$` to \"uniquely\" name a temporary file.\n- Prefer `sed '/re/!d; s//.../'` to `grep re | sed 's/re/.../'`.\n- Prefer `sed 'cmd; cmd'` to `sed -e 'cmd' -e 'cmd'`.\n- Prefer checking exit statuses over output in `if` statements (`if grep -q\n  ...;`, not `if [ -n \"$(grep ...)\" ];`).\n- Prefer reading environment variables over process output (`$TTY` not `$(tty)`,\n  `$PWD` not `$(pwd)`, etc).\n- Use `$( ... )`, not backticks for capturing command output.\n- Use `$(( ... ))`, not `expr` for executing arithmetic expressions.\n- Use `1` and `0`, not `true` and `false` to represent boolean variables.\n- Use `find -print0 | xargs -0`, not `find | xargs`.\n- Use quotes around every `\"$variable\"` and `\"$( ... )\"` expression unless you\n  want them to be word-split and/or interpreted as globs.\n- Use the `local` keyword with function-scoped variables.\n- Identify common problems with [shellcheck].\n\n[shebang]: http://en.wikipedia.org/wiki/Shebang_(Unix)\n[why you shouldn't and available alternatives]: http://mywiki.wooledge.org/ParsingLs\n[non-posix features]: http://mywiki.wooledge.org/Bashism\n[shellcheck]: http://www.shellcheck.net/\n"
  },
  {
    "path": "swift/README.md",
    "content": "# Swift\n\n[Sample](sample.swift)\n\n- Prefer `struct`s over `class`es wherever possible\n- Default to marking classes as `final`\n- Prefer protocol conformance to class inheritance\n- Break long lines after 100 characters\n- Use 2 spaces for indentation\n- Use `let` whenever possible to make immutable variables\n- Name all parameters in functions and enum cases\n- Use trailing closures\n- Let the compiler infer the type whenever possible\n- Group computed properties below stored properties\n- Use a blank line above and below computed properties\n- Group methods into specific extensions for each level of access control\n- When capitalizing acronyms or initialisms, follow the capitalization of the\n  first letter.\n- When using `Void` in function signatures, prefer `()` for arguments and `Void`\n  for return types.\n- Prefer strong IBOutlet references.\n- Avoid evaluating a weak reference multiple times in the same scope. Strongify\n  first, then use the strong reference.\n- Prefer to name `IBAction` and target/action methods using a verb describing\n  the action it will trigger, instead of the user action (e.g., `edit:` instead\n  of `editTapped:`)\n"
  },
  {
    "path": "swift/sample.swift",
    "content": "// Don't include generated header comments\n\n// MARK: Types and naming\n\n// Types begin with a capital letter\nstruct User {\n  let name: String\n\n  // if the first letter of an acronym is lowercase, the entire thing should\n  // be lowercase\n  let json: Any\n\n  // if the first letter of an acronym is uppercase, the entire thing should\n  // be uppercase\n  static func decode(from json: JSON) -> User {\n    return User(json: json)\n  }\n}\n\n// Use () for void arguments and Void for void return types\nlet f: () -> Void = { }\n\n// When using classes, default to marking them as final\nfinal class MyViewController: UIViewController {\n  // Prefer strong IBOutlet references\n  @IBOutlet var button: UIButton!\n}\n\n// Use typealias when closures are referenced in multiple places\ntypealias CoolClosure = (Int) -> Bool\n\n// Use aliased parameter names when function parameters are ambiguous\nfunc yTown(some: Int, withCallback callback: CoolClosure) -> Bool {\n  return CoolClosure(some)\n}\n\n// It's OK to use $ variable references if the closure is very short and\n// readability is maintained\nlet cool = yTown(5) { $0 == 6 }\n\n// Use full variable names when closures are more complex\nlet cool = yTown(5) { foo in\n  if foo > 5 && foo < 0 {\n    return true\n  } else {\n    return false\n  }\n}\n\n// Strongify weak references in async closures\nAPIClient.getAwesomeness { [weak self] result in\n  guard let `self` = self else { return }\n  self.stopLoadingSpinner()\n  self.show(result)\n}\n\n// If the API you are using has implicit unwrapping you should still use if-let\nfunc someUnauditedAPI(thing: String!) {\n  if let string = thing {\n    print(string)\n  }\n}\n\n// When the type is known you can let the compiler infer\nlet response: Response = .Success(NSData())\n\nfunc doSomeWork() -> Response {\n  let data = ...\n  return .Success(data)\n}\n\nswitch response {\ncase let .Success(data):\n  print(\"The response returned successfully \\(data)\")\n\ncase let .Failure(error):\n  print(\"An error occured: \\(error)\")\n}\n\n// MARK: Organization\n\n// Group methods into specific extensions for each level of access control\nprivate extension MyClass {\n  func doSomethingPrivate() { }\n}\n\n// MARK: Breaking up long lines\n\n// One expression to evaluate and short or no return\nguard let singleTest = somethingFailable() else { return }\nguard statementThatShouldBeTrue else { return }\n\n// If there is one long expression to guard or multiple expressions\n// move else to next line\nguard let oneItem = somethingFailable(),\n  let secondItem = somethingFailable2()\n  else { return }\n\n// If the return in else is long, move to next line\nguard let something = somethingFailable() else {\n  return someFunctionThatDoesSomethingInManyWordsOrLines()\n}\n"
  },
  {
    "path": "tech-stack/README.md",
    "content": "# thoughtbot Stack\n\nWe have a standard technology stack that we use for each new project by default.\nThis provides a proven base for rapid, quality development and ensures we have a\nlarge team of developers ready to jump on new projects using a known technology.\nIt helps to avoid decision fatigue at the beginning of each project.\n\nWe deviate from this stack when we find something new that we need to evaluate.\nThis allows us to practice our value of [Continuous Improvement].\n\nWe will also swap in alternate technology as necessary when our default stack is\ninappropriate for the task at hand. This allows us to practice our value of\n[Quality].\n\n[continuous improvement]: https://thoughtbot.com/purpose#continuous-improvement\n[quality]: https://thoughtbot.com/purpose#quality\n\n## Core Stack\n\nMost developers at thoughtbot learn our Core Stack. The stack is broken up into\nlayers and each layer depends on another layer. This allows us to swap out an\nentire layer when necessary without losing all the decisions made for other\nlayers. Developers will have varying levels of experience with each layer, but\nthe gaps between layers are small enough that developers can learn a new layer\nwhile building applications.\n\n### UI\n\n- Use server-rendered HTML when possible as a UI layer.\n- Use React when building components with a client-side framework.\n- Use TypeScript when writing client-side code.\n- Avoid building single-page applications for the web.\n- When building a cross-platform mobile app that will be delivered via an app\n  store, use React Native.\n\n### Web\n\n- Use Ruby on Rails for new applications.\n- Use [Suspenders] to generate new Rails applications and as a reference for\n  preferred library choices.\n- Use Heroku with git deploys and pipelines for deploying applications.\n- Use test-driven development to ensure quality.\n- Use GitHub pull-requests to conduct peer code review.\n- Use continuous integration to ensure tests continue to pass.\n- Use a staging server to ensure new features work as expected before deploying\n  to production.\n\n[suspenders]: https://github.com/thoughtbot/suspenders\n\n### Storage\n\n- Use Postgres to store most data.\n\n### Messaging\n\n- Use Kafka when producing and consuming messages between services.\n- Use `ruby-kafka` by default when connecting to Kafka from Ruby applications.\n\n### Data\n\n- Use services in the same Rails application for building data pipelines on top\n  of Kafka.\n\n## Specialized Stacks\n\nSome applications require functionality that is difficult or impossible to\nprovide using the Core Stack, or would require an unacceptable compromise on\nquality or user experience. In these cases, we utilize alternate, specialized\nstacks. Because the gaps between stacks are larger than the gaps between layers\nin the Core Stack, most developers won't learn these technologies, and the\nspecialists who learn these stacks are unlikely to be able to learn many layers\nin the Core Stack.\n\n### Android (Native)\n\n- Use Kotlin for writing native app code.\n- Use Gradle with Android Studio for building.\n- Use MVVM to model views.\n- Use Apollo when consuming a GraphQL API.\n\n### iOS (Native)\n\n- Use Swift for writing native app code.\n- Use Xcode and `xcodebuild` for building iOS apps.\n- Use `xcpretty` to format `xcodebuild` output.\n- Use Xcode automatic provisioning when possible.\n- Use UIKit with Storyboards and MVVM for creating UIs.\n- Use Dispatch and OperationQueue for concurrency.\n- Support VoiceOver and VoiceControl for accessibility.\n- Use Swift Package Manager for dependencies when possible.\n- Manually test on both iPhone and iPad to ensure the app is functional.\n- Work closely with designers on UI components.\n- Prefer standard UIKit components to custom views.\n\nWe recommend learning at least one of the following:\n\n- MapKit or Google Maps\n- Core Location\n- Core Bluetooth\n- PhotoKit\n- UserNotifications\n"
  },
  {
    "path": "testing-jest/README.md",
    "content": "# Testing with Jest\n\n- Use [eslint-plugin-jest] to enforce testing style\n- Use [testing-library/jest-dom] and [jest-community/jest-extended] for\n  supplemental expectation matchers\n- Use [React Testing Library] for testing [React](/react/) components\n- Use [React Hooks Testing Library] for testing [React Hooks]\n- Use [User Event] for simulating DOM events on React components under test\n- Use [Fishery] for building factories\n- Prefer placing test suite files alongside source files (e.g. `Thing.tsx` /\n  `Thing.test.tsx`)\n- Prefer writing specific unit tests over [Snapshot Testing]\n- Prefer `describe` and `it` blocks over `test` blocks\n- Prefer [.resolves/.rejects] over awaiting promises in tests\n\n[eslint-plugin-jest]: https://github.com/jest-community/eslint-plugin-jest\n[testing-library/jest-dom]: https://github.com/testing-library/jest-dom\n[react testing library]: https://github.com/testing-library/react-testing-library\n[react hooks testing library]: https://github.com/testing-library/react-hooks-testing-library\n[react hooks]: https://reactjs.org/docs/hooks-overview.html\n[user event]: https://github.com/testing-library/user-event\n[fishery]: https://github.com/thoughtbot/fishery\n[snapshot testing]: https://jestjs.io/docs/en/snapshot-testing\n[jest-community/jest-extended]: https://github.com/jest-community/jest-extended\n[.resolves/.rejects]: https://jestjs.io/docs/en/asynchronous#resolves--rejects\n"
  },
  {
    "path": "testing-rspec/README.md",
    "content": "# Testing with RSpec\n\n- Avoid the `private` keyword in specs.\n- Avoid checking boolean equality directly. Instead, write predicate methods and\n  use appropriate matchers. [Example](predicate_tests_spec.rb).\n- Prefer `eq` to `==` in RSpec.\n- Separate setup, exercise, verification, and teardown phases with newlines.\n- Use RSpec's [`expect` syntax].\n- Use RSpec's [`allow` syntax] for method stubs.\n- Use `not_to` instead of `to_not` in RSpec expectations.\n- Prefer the `have_css` matcher to the `have_selector` matcher in Capybara\n  assertions.\n- Avoid `any_instance` in `rspec-mocks` and `mocha`; Prefer [dependency\n  injection].\n- Avoid `its`, `specify`, and `before` in RSpec.\n- Avoid `let` (or `let!`) in RSpec. Prefer extracting helper methods, but do not\n  re-implement the functionality of `let`.\n  [Example](/testing-rspec/avoid_let_spec.rb).\n- Avoid using `subject` explicitly _inside of an_ RSpec `it` block.\n  [Example](/testing-rspec/unit_test_spec.rb).\n- Avoid using instance variables in tests.\n- Disable real HTTP requests to external services with\n  `WebMock.disable_net_connect!`.\n- Don't test private methods.\n- Test background jobs with a [`Delayed::Job` matcher].\n- Use [stubs and spies] \\(not mocks\\) in isolated tests.\n- Use a single level of abstraction within `it` examples.\n- Use an `it` example or test method for each execution path through the method.\n- Use [assertions about state] for incoming messages.\n- Use stubs and spies to assert you sent outgoing messages.\n- Use a [Fake] to stub requests to external services.\n- Use integration tests to execute the entire app.\n- Use non-[SUT] methods in expectations when possible.\n\n[`expect` syntax]: http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax\n[`allow` syntax]: https://github.com/rspec/rspec-mocks#method-stubs\n[dependency injection]: http://en.wikipedia.org/wiki/Dependency_injection\n[`delayed::job` matcher]: https://gist.github.com/3186463\n[stubs and spies]: http://thoughtbot.com/blog/spy-vs-spy\n[assertions about state]: https://speakerdeck.com/skmetz/magic-tricks-of-testing-railsconf?slide=51\n[fake]: http://thoughtbot.com/blog/fake-it\n[sut]: http://xunitpatterns.com/SUT.html\n\n## Acceptance Tests\n\n[Sample](acceptance_test_spec.rb)\n\n- Use the most specific [selectors][] available.\n- Don't locate elements with CSS selectors or `[id]` attributes.\n- Use [accessible names and descriptions][names_and_descriptions] to locate\n  elements, to interact with form controls, buttons, and links, or to scope\n  blocks of actions and assertions.\n- Avoid `it` block descriptions that add no information, such as \"successfully.\"\n- Avoid `it` block descriptions that repeat the top-level `describe` block\n  description.\n- Place helper methods for system specs directly in a top-level `System` module.\n- Use names like `ROLE_ACTION_spec.rb`, such as `user_changes_password_spec.rb`,\n  for system spec file names.\n- Use only one `describe` block per system spec file.\n- Use `it` block descriptions that describe the success and failure paths.\n- Use spec/system directory to store system specs.\n- Use spec/support/system for support code related to system specs.\n- Don't assert an element's state with `[class]` or `[data-*]` attributes.\n- Use [WAI-ARIA States and Properties][] (i.e. `[role]` or `[aria-*]`\n  attributes) when asserting an element's state.\n- Prefer assertions about implicit semantics and built-in attributes (e.g. an\n  `<input type=\"checkbox\">` element and `[checked]`, an `<option>` element and\n  `[selected]`) over WAI-ARIA States and Properties (e.g. a `<button>` element and\n  `[aria-checked=\"true\"]`, a `<div>` element and `[aria-selected=\"true\"]`).\n\n> system specs were previously called feature specs and lived in `spec/features`\n\n[selectors]: https://rubydoc.info/github/teamcapybara/capybara/master/Capybara/Selector\n[names_and_descriptions]: https://www.w3.org/WAI/ARIA/apg/practices/names-and-descriptions/\n[WAI-ARIA States and Properties]: https://www.w3.org/TR/wai-aria/#states_and_properties\n\n## Factories\n\n- Order `factories.rb` contents: sequences, traits, factory definitions.\n- Order factory attributes: implicit attributes, explicit attributes, child\n  factory definitions. Each section's attributes are alphabetical.\n- Order factory definitions alphabetically by factory name.\n\n## Unit Tests\n\n[Sample](unit_test_spec.rb)\n\n- Don't prefix `it` block descriptions with `should`. Use [Imperative mood]\n  instead.\n- Use `subject` blocks to define objects for use in one-line specs.\n  [Example](unit_test_spec.rb#6).\n- Put one-liner specs at the beginning of the outer `describe` blocks.\n- Use `.method` to describe class methods and `#method` to describe instance\n  methods.\n- Use `context` to describe testing preconditions.\n- Use `describe '#method_name'` to group tests by method-under-test\n- Use a single, top-level `describe ClassName` block.\n- Order validation, association, and method tests in the same order that they\n  appear in the class.\n\n[imperative mood]: http://en.wikipedia.org/wiki/Imperative_mood\n"
  },
  {
    "path": "testing-rspec/acceptance_test_spec.rb",
    "content": "# spec/system/user_signs_up_spec.rb\n\nrequire \"spec_helper\"\n\ndescribe \"User signs up\" do\n  it \"signs up the user with valid details\" do\n    visit sign_up_path\n\n    within_fieldset \"Sign up\" do\n      fill_in \"Email\", with: \"user@example.com\"\n      fill_in \"Password\", with: \"Examp1ePa$$\"\n      click_button \"Sign up\"\n    end\n\n    expect(page).to have_button(\"Sign out\")\n  end\nend\n"
  },
  {
    "path": "testing-rspec/avoid_let_spec.rb",
    "content": "# Not recommended\ndescribe ReportPolicy do\n  let(:report_id) { 2 }\n  let(:report_policy) do\n    ReportPolicy.new(\n      User.new(report_ids: [1,2]),\n      Report.new(id: report_id)\n    )\n  end\n\n  describe \"#allowed?\" do\n    subject { report_policy.allowed? }\n    \n    context \"when user has access to report\" do\n      it { should be true }\n    end\n\n    context \"when user does not have access to report\" do\n      let(:report_id) { 3 }\n      \n      it { should be false }\n    end\n  end\nend\n\n# Recommended\ndescribe ReportPolicy do\n  describe \"#allowed?\" do\n    context \"when user has access to report\" do\n      it \"returns true\" do\n        policy = build_policy(report_id: 2, allowed_report_ids: [1, 2])\n\n        expect(policy).to be_allowed\n      end\n    end\n\n    context \"when user does not have access to report\" do\n      it \"returns false\" do\n        policy = build_policy(report_id: 3, allowed_report_ids: [1, 2])\n\n        expect(policy).not_to be_allowed\n      end\n    end\n  end\n\n  def build_policy(report_id:, allowed_report_ids:)\n    user = instance_double(\"User\", report_ids: allowed_report_ids)\n    report = instance_double(\"Report\", id: report_id)\n\n    ReportPolicy.new(user, report)\n  end\nend\n"
  },
  {
    "path": "testing-rspec/predicate_tests_spec.rb",
    "content": "# Class under test:\n\nclass Thing\n  def awesome?\n    true\n  end\nend\n\n# RSpec test:\n\ndescribe Thing, \"#awesome?\" do\n  it \"is true\" do\n    thing = Thing.new\n\n    expect(thing).to be_awesome\n  end\nend\n"
  },
  {
    "path": "testing-rspec/unit_test_spec.rb",
    "content": "describe SomeClass do\n  context \"when defining a subject\" do\n    # GOOD\n    # it's okay to define a `subject` here:\n    subject { \"foo\" }\n\n    it { should eq \"foo\" }\n  end\n\n  context \"when using an explicit subject\" do\n    subject { \"foo\" }\n\n    it \"should equal foo\" do\n      # BAD\n      # although it's valid RSpec code and this test passes,\n      # it's not okay to use `subject` here:\n      expect(subject).to eq \"foo\"\n    end\n  end\n\n  describe '.some_class_method' do\n    it 'does something' do\n      # ...\n    end\n  end\n\n  describe '#some_instance_method' do\n    it 'does something' do\n      expect(something).to eq 'something'\n    end\n  end\n\n  describe '#another_instance_method' do\n    context 'when in one case' do\n      it 'does something' do\n        # ...\n      end\n    end\n\n    context 'when in other case' do\n      it 'does something else' do\n        # ...\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "web/README.md",
    "content": "# Web\n\n- Avoid rendering delays caused by synchronous loading.\n\n- Use HTTPS instead of HTTP when linking to assets.\n\n- Prefer using a UTF-8 charset\n\n- Avoid targeting specific browsers and aim for [baseline feature support][]\n  which means that features are widely available across major browsers.\n\n[baseline feature support]: https://web-platform-dx.github.io/web-features/\n"
  },
  {
    "path": "web-performance/README.md",
    "content": "# Web Performance\n\nWeb performance refers to the speed in which web pages are downloaded and\ndisplayed on the user's web browser. Web performance optimization (WPO) or\nwebsite optimization is the field of knowledge about increasing web performance.\n\n## Resources\n\n- [Demystifying Speed Tooling (Google I/O ’19)]\n- [Fast load times]\n- [Your first performance budget with Lighthouse]\n- [Performance articles from Harry Roberts of CSS Wizardry]\n- [Visualize performance impact between deploys with Calibre]\n\n## Tools\n\n- [Google Lighthouse] - Lighthouse is an open-source, automated tool for\n  improving the quality of web pages.\n- [Calibre] - Automated performance monitoring, with device emulation, metric\n  budgets, and alerts (powered by Lighthouse)\n\n[demystifying speed tooling (google i/o ’19)]: https://www.youtube.com/watch?v=mLjxXPHuIJo\n[fast load times]: https://web.dev/fast\n[your first performance budget with lighthouse]: https://bitsofco.de/your-first-performance-budget-with-lighthouse/\n[performance articles from harry roberts of css wizardry]: https://csswizardry.com/archive/\n[visualize performance impact between deploys with calibre]: https://calibreapp.com/blog/visualise-performance-impact-between-deploys\n[google lighthouse]: https://developers.google.com/web/tools/lighthouse/\n[calibre]: https://calibreapp.com/\n"
  }
]