[
  {
    "path": ".github/workflows/flutter-test.yml",
    "content": "name: test\non:\n  push:\n  pull_request:\n    branches:\n    - main\n  schedule:\n  # Run the quality job at 4am every day\n  - cron: '0 4 * * *'\n\njobs:\n  test:\n    # This job will run on ubuntu virtual machine\n    runs-on: ubuntu-latest\n    steps:\n    - uses: actions/checkout@v1\n\n    # Setup the flutter environment.\n    - uses: subosito/flutter-action@v2\n      with:\n        channel: 'stable'\n\n    # Get flutter dependencies.\n    - run: flutter pub get\n\n    # Check for any formatting issues in the code.\n    - run: dart format --set-exit-if-changed .\n\n    # Statically analyze the Dart code for any errors.\n    - run: flutter analyze .\n\n    # Do the same for examples\n    - run: flutter analyze .\n      working-directory: ./example\n\n    # Run widget tests for our flutter project.\n    - run: flutter test\n"
  },
  {
    "path": ".gitignore",
    "content": "# Libraries shouldn't have their locks committed\npubspec.lock\n\n# Miscellaneous\n*.class\n*.log\n*.pyc\n*.swp\n.DS_Store\n.atom/\n.buildlog/\n.history\n.svn/\n\n# IntelliJ related\n*.iml\n*.ipr\n*.iws\n.idea/\n\n# The .vscode folder contains launch configuration and tasks you configure in\n# VS Code which you may wish to be included in version control, so this line\n# is commented out by default.\n#.vscode/\n\n# Flutter/Dart/Pub related\n**/doc/api/\n.dart_tool/\n.flutter-plugins\n.flutter-plugins-dependencies\n**/generated_plugin_registrant.dart\n.packages\n.pub-cache/\n.pub/\nbuild/\nflutter_*.png\nlinked_*.ds\nunlinked.ds\nunlinked_spec.ds\ntest/failures\n\n# Android related\n**/android/**/gradle-wrapper.jar\n**/android/.gradle\n**/android/captures/\n**/android/gradlew\n**/android/gradlew.bat\n**/android/local.properties\n**/android/**/GeneratedPluginRegistrant.java\n\n# iOS/XCode related\n**/ios/**/*.mode1v3\n**/ios/**/*.mode2v3\n**/ios/**/*.moved-aside\n**/ios/**/*.pbxuser\n**/ios/**/*.perspectivev3\n**/ios/**/*sync/\n**/ios/**/.sconsign.dblite\n**/ios/**/.tags*\n**/ios/**/.vagrant/\n**/ios/**/DerivedData/\n**/ios/**/Icon?\n**/ios/**/Pods/\n**/ios/**/.symlinks/\n**/ios/**/profile\n**/ios/**/xcuserdata\n**/ios/.generated/\n**/ios/Flutter/App.framework\n**/ios/Flutter/Flutter.framework\n**/ios/Flutter/Flutter.podspec\n**/ios/Flutter/Generated.xcconfig\n**/ios/Flutter/app.flx\n**/ios/Flutter/app.zip\n**/ios/Flutter/flutter_assets/\n**/ios/Flutter/flutter_export_environment.sh\n**/ios/ServiceDefinitions.json\n**/ios/Runner/GeneratedPluginRegistrant.*\n\n# macOS\n**/macos/Flutter/GeneratedPluginRegistrant.swift\n\n# Exceptions to above rules.\n!**/ios/**/default.mode1v3\n!**/ios/**/default.mode2v3\n!**/ios/**/default.pbxuser\n!**/ios/**/default.perspectivev3\n!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages\n.vs/\n"
  },
  {
    "path": ".metadata",
    "content": "# This file tracks properties of this Flutter project.\n# Used by Flutter tool to assess capabilities and perform upgrades etc.\n#\n# This file should be version controlled and should not be manually edited.\n\nversion:\n  revision: e3742b6e410aa5e9ea34b60dfbdd9a923c5a1fe8\n  channel: master\n\nproject_type: library\n"
  },
  {
    "path": ".vscode/launch.json",
    "content": "{\n  // Use IntelliSense to learn about possible attributes.\n  // Hover to view descriptions of existing attributes.\n  // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387\n  \"version\": \"0.2.0\",\n  \"configurations\": [\n    {\n      \"name\": \"Periodic Table\",\n      \"program\": \"example/lib/periodic_table.dart\",\n      \"type\": \"dart\",\n      \"request\": \"launch\",\n    },\n    {\n      \"name\": \"Periodic Table (Profile)\",\n      \"program\": \"example/lib/periodic_table.dart\",\n      \"type\": \"dart\",\n      \"flutterMode\": \"profile\",\n      \"request\": \"launch\",\n    },\n    {\n      \"name\": \"Piet\",\n      \"program\": \"example/lib/flutter_layout_grid.dart\",\n      \"type\": \"dart\",\n      \"request\": \"launch\",\n    },\n    {\n      \"name\": \"Basic\",\n      \"program\": \"example/lib/basic.dart\",\n      \"request\": \"launch\",\n      \"type\": \"dart\"\n    },\n    {\n      \"name\": \"Profile Basic\",\n      \"program\": \"example/lib/basic.dart\",\n      \"flutterMode\": \"profile\",\n      \"request\": \"launch\",\n      \"type\": \"dart\"\n    }\n  ]\n}\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "## [2.0.8]\n* Fix deprecated `withOpacity()` calls in example app to resolve CI build failures\n\n## [2.0.7]\n* Update tests to work with breaking `test` framework changes\n\n## [2.0.6]\n* Perform a pass through the latest analysis warnings\n* Upgrade dependencies\n\n## [2.0.5]\n* Replace deprecated EnumProperty with DiagnosticsProperty\n  (https://github.com/shyndman/flutter_layout_grid/pull/95), courtesy of\n  [@Kristijan505](https://github.com/Kristijan505)\n\n## [2.0.4]\n* Fix https://github.com/shyndman/flutter_layout_grid/issues/91\n\n## [2.0.3]\n* Correct the lower bound of the Flutter dependency to reflect API usage\n\n## [2.0.2]\n* Replace the usage of the deprecated `hashValues` with `Object.hash`\n\n## [2.0.1]\n* Fix grid sizing when gaps are involved (thanks to\n  [@dsyrstad](https://github.com/dsyrstad))\n\n## [2.0.0]\n* Improve implicit track sizing behavior for multi-line text (thanks to\n  [@klondikedragon](https://github.com/klondikedragon))\n* Upgrade flutter_lints to 2.0.0, and fix newly found issues\n\n## [1.0.6]\n* Remove outdated messaging from README. Flutter v1.14.0 is ancient at this\n  point.\n\n## [1.0.5]\n* Migrate project to use flutter_lints, courtesy of @domesticmouse\n\n## [1.0.4]\n* Emit a more helpful assertion message when an areas string's row or column\n  count doesn't match rowSizes.length or columnSizes.length\n* Fix a couple analysis warnings\n\n## [1.0.3]\n* Format Dart files (seems like the formatter has changed recently)\n\n## [1.0.2]\n* Improve a class comment\n\n## [1.0.1]\n* Update README to point to latest version\n\n## [1.0.0]\nAlthough there's more I want to add, the library is solid enough. It's time to\nmark this thing as 1.0.\n\n## [1.0.0-nullsafety.6]\n* Make RenderLayoutGrid.lastGridSizing a public field\n\n## [1.0.0-nullsafety.5]\n* Reorganize example project\n\n## [1.0.0-nullsafety.4]\n* Improve performance of periodic table example\n\n## [1.0.0-nullsafety.3]\n* Update Scrabble screenshot to follow game rules (middle square must be\n  occupied)\n\n## [1.0.0-nullsafety.2]\n* Add hashCode to TrackSize subclasses\n\n## [1.0.0-nullsafety.1]\n* Fix screenshots for pub.dev\n\n## [1.0.0-nullsafety.0]\n* Full support for null-safety\n* Replacement of templateColumnSizes and templateRowSizes with columnSizes and\n  rowSizes\n\n## [0.11.0]\n* Tons of bug fixes in track sizing\n* Documentation overhaul\n* Performance improvements (should now lay out far less frequently)\n* Helpers and extension methods for row/column sizing\n* New Scrabble example\n* More tests\n\nSorry, but I had to break semver with this release. Check out\n`1.0.0-nullsafety.0` for the null-safe version.\n\n## [0.10.5]\n* Remove the use of extension methods\n\n## [0.10.4]\n* Massive overhaul in layout algorithm, fixing a number of serious issues\n* Debug painting support, where tracks and gaps are drawn differently\n* Child overflow indicators\n* Debug printing, behind a flag\n* Cool new periodic table example\n\nTechnically, some of these changes are breaking from an API perspective, but\nI think that it's unlikely that people run into them. I originally wanted to\npublish under a new minor version, but `pub publish` is giving me issues because\nof my nullsafe prerelease.\n\n## [0.10.3]\n* Mention nullsafety release in pubspec\n* Format code using latest formatter\n* Fix a lint\n\n## [0.10.2]\n* Add support for negative row/column gaps (thanks @daohoangson!)\n\n## [0.10.1]\n* Graduate 0.10.1-dev.0 to the release version now that Flutter 1.17 is out\n\n## [0.10.1-dev.0]\n* Invalidate placement in more situations\n\n## [0.10.0-dev.2]\n* Correct Flutter version dependency in pubspec\n\n## [0.10.0-dev.1]\n* Make AutoPlacement class a little more enum-like, by adding a toString() that\n  resembles Dart enums and a static .values field\n\n## [0.10.0-dev.0]\n* Added support for Flutter v1.14.0+\n\n## [0.9.4]\n* Invalidate placement in more situations\n\n## [0.9.3]\n* Correct Flutter dependency in pubspec\n\n## [0.9.2]\n* Make AutoPlacement class a little more enum-like, by adding a toString() that\n  resembles Dart enums and a static .values field\n\n## [0.9.1]\n* Mention the prerelease version supporting Flutter v1.14.0+ in the README\n\n## [0.9.0]\n* Reverted support for Flutter v1.14.0+, because it won't be stable for awhile.\n  Flutter v1.14.0+ support is published as 0.10.0-dev.0\n\n## [0.8.0]\n* Added support for Flutter v1.14.0+\n\n## [0.7.0]\n* Add extension method support for grid item placement —\n  Widget.withGridPlacement\n\n## [0.6.3]\n* Fix broken badge links in README\n\n## [0.6.2]\n* Fix several bugs in the examples\n* Add intrinsic-size computing functions. I don't know if they're right yet,\n  but it's a start.\n\n## [0.6.1]\n* Size grid minimally if an infinite constraint is provided\n\n## [0.6.0]\n* Supply grid items with loose constraints, not tight\n\n## [0.5.3]\n* README tweak\n\n## [0.5.2]\n* Add a license (MIT)\n\n## [0.5.1]\n* Dependency version fix\n\n## [0.5.0]\n* First version. See the README.\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\nCopyright (c) 2019 Scott Hyndman\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# Flutter Layout Grid\n\n[![Pub](https://img.shields.io/pub/v/flutter_layout_grid)](https://pub.dev/packages/flutter_layout_grid)\n[![Github test](https://github.com/shyndman/flutter_layout_grid/workflows/test/badge.svg)](https://github.com/shyndman/flutter_layout_grid/actions?query=workflow%3Atest)\n\nA powerful grid layout system for Flutter, optimized for complex user interface\ndesign.\n\n<a href=\"https://github.com/shyndman/flutter_layout_grid/tree/main/example/lib/flutter_layout_grid_example.dart\">\n  <img\n    src=\"https://raw.githubusercontent.com/shyndman/flutter_layout_grid/master/doc/images/piet_trimmed.png\"\n    alt=\"Piet painting recreated using Flutter Layout Grid\" height=\"220\">\n</a>\n&nbsp;\n\n<a href=\"https://github.com/shyndman/flutter_layout_grid/tree/main/example/lib/periodic_table.dart\">\n  <img\n    src=\"https://raw.githubusercontent.com/shyndman/flutter_layout_grid/main/doc/images/periodic_table.png\"\n    alt=\"Periodic table rendered using Flutter Layout Grid\" height=\"220\">\n</a>\n&nbsp;\n\n<a href=\"https://github.com/shyndman/flutter_layout_grid/tree/main/example/lib/scrabble.dart\">\n<img\n    src=\"https://raw.githubusercontent.com/shyndman/flutter_layout_grid/master/doc/images/scrabble.png\"\n    alt=\"Scrabble board rendered using Flutter Layout Grid\" height=\"330\">\n</a>\n\n_Click images to see their code_\n\n---\n\n✨Featuring:✨\n\n- 📐 Fixed, flexible, and content-sized rows and columns\n  ([docs](#sizing-of-columns-and-rows))\n- 👇 Precise control over placement of items, including the ability to span\n  rows, columns, and overlap items\n  ([docs](#positioning-child-widgets-in-the-layoutgrid))\n- 💬 Named grid areas for descriptive positioning of children\n  ([docs](#naming-areas-of-the-grid))\n- 🦾 A configurable automatic grid item placement algorithm, capable of sparse\n  and dense packing across rows and columns ([docs](#automatic-child-placement))\n- 🔚 Right-to-left support, driven by ambient `Directionality` or configuration\n- ♿ Accessibility considerations (**this is your responsibility** as a frontend\n  developer, so please read [docs](#accessibility-and-placement) and learn\n  related technologies)\n- 🩳 Extension methods and helper functions for descriptive, and short, layout\n  code\n- 🐛 Debugging aids, including widget property listings in\n  [DevTools](https://flutter.dev/docs/development/tools/devtools/overview),\n  Debug Painting, and visual indication of child overflow\n\nInspired by (and largely based on), the excellent [CSS Grid\nLayout](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout) spec.\n\n## Getting Started\n\nAll the terminology used in this library is shared with the CSS Grid Layout\nspec. If youʼre unfamiliar, I recommend taking a look at [MDNʼs glossary of grid\nterms](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout#Glossary_entries).\n\nFor inclusion in your pubspec, see\n[pub.dev](https://pub.dev/packages/flutter_layout_grid/install), or copy\nthe code below:\n\n```yaml\ndependencies:\n  flutter_layout_grid: ^2.0.0\n```\n\n## Example\n\n#### Visual:\n\n<a href=\"https://github.com/shyndman/flutter_layout_grid/tree/main/example/lib/app_layout.dart\">\n  <img\n    src=\"https://raw.githubusercontent.com/shyndman/flutter_layout_grid/master/doc/images/app_layout.png\"\n    alt=\"Desktop app layout rendered using Flutter Layout Grid\" height=\"220\">\n</a>\n\n#### Code:\n\n```dart\nimport 'package:flutter_layout_grid/flutter_layout_grid.dart';\n\nclass App extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Container(\n      color: background,\n      child: LayoutGrid(\n        // ASCII-art named areas 🔥\n        areas: '''\n          header header  header\n          nav    content aside\n          nav    content .\n          footer footer  footer\n        ''',\n        // Concise track sizing extension methods 🔥\n        columnSizes: [152.px, 1.fr, 152.px],\n        rowSizes: [\n          112.px,\n          auto,\n          1.fr,\n          64.px,\n        ],\n        // Column and row gaps! 🔥\n        columnGap: 12,\n        rowGap: 12,\n        // Handy grid placement extension methods on Widget 🔥\n        children: [\n          Header().inGridArea('header'),\n          Navigation().inGridArea('nav'),\n          Content().inGridArea('content'),\n          Aside().inGridArea('aside'),\n          Footer().inGridArea('footer'),\n        ],\n      ),\n    );\n  }\n}\n```\n\nThis example is available at\n[`example/app_layout.dart`](https://github.com/shyndman/flutter_layout_grid/tree/main/example/lib/app_layout.dart).\n\nFor a similar example that includes responsive behavior, check out\n[`example/responsive_app_layout.dart`](https://github.com/shyndman/flutter_layout_grid/tree/main/example/lib/responsive_app_layout.dart).\n\n## Sizing of Columns and Rows\n\nThe sizes of the gridʼs columns and rows are set using\n`LayoutGrid.columnSizes` and `LayoutGrid.rowSizes`.\n\nHereʼs what a 4⨉3 grid might look like (4 columns, 3 rows):\n\n```dart\nLayoutGrid(\n  columnSizes: [4.5.fr, 100.px, auto, 1.fr],\n  rowSizes: [\n    auto,\n    100.px,\n    1.fr,\n  ],\n)\n```\n\nEach element of `columnSizes` and `rowSizes` represents the function used to\nsize a column or row (collectively known as **\"track sizes\"**).\n\nThere are currently three way to size rows and columns:\n\n| Class Name                  | Description                                                                                                                                      | Usage                                                    |\n| --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------- |\n| `FixedTrackSize`            | Occupies a specific number of pixels on an axis                                                                                                  | `FixedTrackSize(64)`<br>`fixed(64)`<br>`64.px`           |\n| `FlexibleSizeTrack`         | Fills remaining space after the initial layout has completed                                                                                     | `FlexibleTrackSize(1.5)`<br>`flexible(1.5)`<br>`1.5.fr`  |\n| `IntrinsicContentTrackSize` | Sized to contain its itemsʼ contents. Will also expand to fill available space, once `FlexibleTrackSize` tracks have been given the opportunity. | `IntrinsicContentTrackSize()`<br>`intrinsic()`<br>`auto` |\n\nTechnically, you can also define your own, but probably shouldnʼt as the API\nwill likely be evolving as I tackle\n([#25](https://github.com/shyndman/flutter_layout_grid/issues/25))\n([`minmax()`](https://developer.mozilla.org/en-US/docs/Web/CSS/minmax)\nsupport).\n\n## Naming areas of the grid\n\nA gridʼs rows and columns can be sliced into areas — rectangular regions\ncontaining one or more grid cells. These areas can be named (_optionally_), and\nused to place gridʼs children. The areas are named using an ASCII-art string\nprovided to the `areas` parameter.\n\n```dart\nLayoutGrid(\n  areas: '''\n    header header\n    nav    content\n    footer footer\n  ''',\n  // ...\n)\n```\n\n> Note: We use the same format as CSSʼs\n> [`grid-template-areas`](https://developer.mozilla.org/en-US/docs/Web/CSS/grid-template-areas),\n> except we use a multiline string.\n\nIf an `areas` argument has been provided to a grid, you must specify the same\nnumber of sizes using `columnSizes` and `rowSizes` elements. For the example\nabove:\n\n```dart\nLayoutGrid(\n  areas: '''\n    header header\n    nav    content\n    footer footer\n  ''',\n  // 2 columns, 3 rows, just like the areas string\n  columnSizes: [\n    auto, // contributes width to [nav, header, footer]\n    1.fr, // contributes width to [content, header, footer]\n  ],\n  rowSizes: [\n    96.px, // contributes height to [header]\n    1.fr,  // contributes height to [nav, content]\n    72.px, // contributes height to [footer]\n  ],\n  children: [\n    // ...\n  ],\n)\n```\n\nGrid children can be assigned to named areas using the `NamedAreaGridPlacement`\nwidget. For more information, see [assigning the child to a named\narea](#child-placement-in-named-areas).\n\n## Positioning child widgets in the `LayoutGrid`\n\nOnce you have a grid, you have to tell its `children` which rows and columns\nthey should occupy. There are three ways of doing this:\n\n- [Specifying row and column indexes](#child-placement-by-row-and-column-indexes)\n- [Assigning the child to a named area](#child-placement-in-named-areas)\n- [Using automatic placement](#automatic-child-placement)\n\n### Child placement by row and column indexes\n\nA gridʼs child can be instructed to occupy a specific set of columns and rows\nby using the `GridPlacement` widget.\n\nFor example, letʼs say you had a 4⨉3 grid, and you wanted a widget to be\npositioned from column 1–4 and row 0–2:\n\n```dart\nLayoutGrid(\n  columnSizes: [1.fr, 1.fr, 1.fr, 1.fr],\n  rowSizes: [\n    1.fr,\n    1.fr,\n    1.fr,\n  ],\n  children: [\n    GridPlacement(\n      columnStart: 1,\n      columnSpan: 3,\n      rowStart: 0,\n      rowSpan: 2,\n      child: MyWidget(),\n    ),\n    // Alternatively, an extension method on Widget is available\n    MyWidget().withGridPlacement(\n      columnStart: 1,\n      columnSpan: 3,\n      rowStart: 0,\n      rowSpan: 2,\n    ),\n  ],\n)\n```\n\n`GridPlacement` also has a super power — all of its parameters are optional.\nIf, for example, you do not specify a `rowStart`, the [automatic placement\nalgorithm](#automatic-child-placement) will attempt to place the child in the\nfirst vacant spot that it can find.\n\n### Child placement in named areas\n\nIf your grid has [named areas](#naming-areas-of-the-grid) defined, you can\nplace children in those areas using the `NamedAreaGridPlacement` widget. For\nexample:\n\n```dart\nLayoutGrid(\n  areas: '''\n    red red blue\n    red red blue\n     .   .  blue\n  ''',\n  // Note that the number of columns and rows matches the grid above (3x3)\n  columnSizes: [64.px, 64.px, 64.px],\n  rowSizes: [\n    64.px,\n    64.px,\n    64.px,\n  ],\n  children: [\n    // Using NamedAreaGridPlacement constructor\n    NamedAreaGridPlacement(\n      areaName: 'red',\n      child: Container(color: Colors.red),\n    ),\n    // Alternatively, an extension method on Widget is available\n    Container(color: Colors.red).inGridArea('red'),\n  ],\n)\n```\n\n**NOTE:** If a `NamedAreaGridPlacement` references a named area that doesnʼt\nexist, it will not be displayed in the grid. This can be helpful when switching\nbetween responsive layouts.\n\n### Automatic child placement\n\nGrid children can be placed into rows and columns automatically based on partial\nor non-existent placement information.\n\nThe algorithm responsible for automatic placement has several modes, selected\nthrough the `LayoutGrid.autoPlacement` parameter. The behavior of these modes\nare identical to those supported by CSSʼs grid, described [described\nhere](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout/Auto-placement_in_CSS_Grid_Layout).\n\n#### When no placement information is provided\n\nIf a child is provided to the grid without being wrapped in a `GridPlacement` or\n`NamedAreaGridPlacement`, it will be allotted a single cell (1⨉1), and placed\ninto the first vacant cell in the grid.\n\n#### When partial placement information is provided\n\nAll of the `GridPlacement` widgetʼs parameters are optional. By specifying\nadditional positioning or spanning information with\n`columnStart`/`columnSpan`/`rowStart`/`rowSpan` parameters, more\nconstraints are fed into the placement algorithm.\n\nFor example, if `columnStart` is provided, but not `rowStart`, the placement\nalgorithm will walk across the gridʼs rows until it finds a vacant area, in the\nspecified column, that accommodates the child.\n\n[Read more about CSSʼs grid placement\nalgorithm](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout/Auto-placement_in_CSS_Grid_Layout)\n\n### Accessibility and Placement\n\nTake note that the meaning you convey visually through placement may not be\nclear when presented by assitive technologies, as Flutter defaults to exposing\ninformation in source order.\n\nIn situations where your semantic (visual) ordering differs from ordering in the\nsource, the ordering can be configured via the `Semantics` widgetʼs\n[`sortKey`](https://api.flutter.dev/flutter/semantics/SemanticsSortKey-class.html)\nparameter.\n\nFor an example of this in practice, see\n[example/semantic_ordering.dart](https://github.com/shyndman/flutter_layout_grid/tree/main/example/lib/semantic_ordering.dart).\n\nAutomatic semantic ordering is currently being explored in\n[#50](https://github.com/shyndman/flutter_layout_grid/issues/50).\n\n## Differences from CSS Grid Layout\n\nThings in CSS Grid Layout that are not supported:\n\n- Negative row/column starts/ends. In CSS, these values refer to positions\n  relative to the end of a gridʼs axis. Handy, but weʼre not there yet.\n  ([#5](https://github.com/shyndman/flutter_layout_grid/issues/5))\n- Any cells outside of the explicit grid. If an item is placed outside of the\n  area defined by your template rows/columns, we will throw an error. Support\n  for automatic addition of rows and columns to accommodate out of bound items\n  is being considered.\n  ([#7](https://github.com/shyndman/flutter_layout_grid/issues/7))\n- minmax(), percentages, aspect ratios track sizing\n  ([#25](https://github.com/shyndman/flutter_layout_grid/issues/25))\n\nDifferences:\n\n- In `flutter_layout_grid`, flexible tracks do not account for their contentʼs\n  base sizes as they do in CSS. Itʼs expensive to measure, and I opted for\n  speed.\n- Flexible tracks whose flex factors sum to < 1\n\n## Roadmap\n\n- [x] Tests! (we now have a decent suite going)\n- [x] Named template areas, for friendlier item placement\n- [ ] Improved track sizing, including minimum/maximums and aspect ratios\n- [ ] The ability to specify row and column gaps at specific line locations via\n      a delegate\n- [ ] Implicit grid support (automatic growth along an axis as children are\n      added)\n- [x] Performance improvements, as soon as I can get this profiler running(!!!)\n"
  },
  {
    "path": "analysis_options.yaml",
    "content": "include: package:flutter_lints/flutter.yaml\n\nanalyzer:\n  errors:\n    missing_required_param: error\n    unawaited_futures: warning\n    unused_import: error\n    unused_local_variable: warning\n"
  },
  {
    "path": "example/.gitignore",
    "content": "# Miscellaneous\n*.class\n*.log\n*.pyc\n*.swp\n.DS_Store\n.atom/\n.buildlog/\n.history\n.svn/\n\n# IntelliJ related\n*.iml\n*.ipr\n*.iws\n.idea/\n\n# The .vscode folder contains launch configuration and tasks you configure in\n# VS Code which you may wish to be included in version control, so this line\n# is commented out by default.\n#.vscode/\n\n# Flutter/Dart/Pub related\n**/doc/api/\n**/ios/Flutter/.last_build_id\n.dart_tool/\n.flutter-plugins\n.flutter-plugins-dependencies\n.packages\n.pub-cache/\n.pub/\n/build/\n\n# Web related\nlib/generated_plugin_registrant.dart\n\n# Symbolication related\napp.*.symbols\n\n# Obfuscation related\napp.*.map.json\n\n# Android Studio will place build artifacts here\n/android/app/debug\n/android/app/profile\n/android/app/release\n"
  },
  {
    "path": "example/.metadata",
    "content": "# This file tracks properties of this Flutter project.\n# Used by Flutter tool to assess capabilities and perform upgrades etc.\n#\n# This file should be version controlled and should not be manually edited.\n\nversion:\n  revision: 097d3313d8e2c7f901932d63e537c1acefb87800\n  channel: stable\n\nproject_type: app\n"
  },
  {
    "path": "example/analysis_options.yaml",
    "content": "include: package:flutter_lints/flutter.yaml\n"
  },
  {
    "path": "example/lib/app_layout.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:flutter_layout_grid/flutter_layout_grid.dart';\n\nvoid main() {\n  runApp(const DesktopLayoutApp());\n}\n\nclass DesktopLayoutApp extends StatelessWidget {\n  const DesktopLayoutApp({Key? key}) : super(key: key);\n\n  @override\n  Widget build(BuildContext context) {\n    return WidgetsApp(\n        color: Colors.white,\n        debugShowCheckedModeBanner: false,\n        builder: (context, child) {\n          return const DesktopLayout();\n        });\n  }\n}\n\nclass DesktopLayout extends StatelessWidget {\n  const DesktopLayout({Key? key}) : super(key: key);\n\n  @override\n  Widget build(BuildContext context) {\n    return Container(\n      color: Colors.grey[400],\n      child: LayoutGrid(\n        areas: '''\n          header header  header\n          nav    content aside\n          nav    content .\n          footer footer  footer\n        ''',\n        // A number of extension methods are provided for concise track sizing\n        columnSizes: [152.px, 1.fr, 152.px],\n        rowSizes: [\n          112.px,\n          auto,\n          1.fr,\n          64.px,\n        ],\n        children: [\n          const Header().inGridArea('header'),\n          const Navigation().inGridArea('nav'),\n          const Content().inGridArea('content'),\n          const Aside().inGridArea('aside'),\n          const Footer().inGridArea('footer'),\n        ],\n      ),\n    );\n  }\n}\n\nclass Header extends StatelessWidget {\n  const Header({Key? key}) : super(key: key);\n\n  @override\n  Widget build(BuildContext context) => Container(color: Colors.red);\n}\n\nclass Navigation extends StatelessWidget {\n  const Navigation({Key? key}) : super(key: key);\n\n  @override\n  Widget build(BuildContext context) => Container(color: Colors.purple);\n}\n\nclass Content extends StatelessWidget {\n  const Content({Key? key}) : super(key: key);\n\n  @override\n  Widget build(BuildContext context) => Container(color: Colors.grey[300]);\n}\n\nclass Aside extends StatelessWidget {\n  const Aside({Key? key}) : super(key: key);\n\n  @override\n  Widget build(BuildContext context) =>\n      Container(color: Colors.grey[600], width: 184);\n}\n\nclass Footer extends StatelessWidget {\n  const Footer({Key? key}) : super(key: key);\n\n  @override\n  Widget build(BuildContext context) => Container(color: Colors.deepPurple);\n}\n"
  },
  {
    "path": "example/lib/basic.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:flutter_layout_grid/flutter_layout_grid.dart';\n\nvoid main() {\n  runApp(const MyApp());\n}\n\nclass MyApp extends StatelessWidget {\n  const MyApp({Key? key}) : super(key: key);\n\n  @override\n  Widget build(BuildContext context) {\n    return MaterialApp(\n      title: 'Layout Grid Desktop Demo',\n      theme: ThemeData(\n        primarySwatch: Colors.blue,\n      ),\n      home: Scaffold(\n        body: Container(\n          color: Colors.white,\n          child: const LayoutGridExample(),\n        ),\n      ),\n    );\n  }\n}\n\nclass LayoutGridExample extends StatelessWidget {\n  const LayoutGridExample({Key? key}) : super(key: key);\n\n  @override\n  Widget build(BuildContext context) {\n    return SizedBox(\n      width: double.infinity,\n      height: double.infinity,\n      child: LayoutGrid(\n        columnGap: 12,\n        rowGap: 12,\n        columnSizes: [1.fr, 1.fr, 1.fr, 0.75.fr],\n        rowSizes: [\n          32.px,\n          32.px,\n          32.px,\n        ],\n        children: [\n          GridPlacement(\n            rowStart: 0,\n            columnStart: 0,\n            columnSpan: 4,\n            child: Container(\n              color: Colors.blue,\n              padding: const EdgeInsets.all(8),\n            ),\n          ),\n          GridPlacement(\n            rowStart: 1,\n            columnStart: 0,\n            columnSpan: 3,\n            child: Container(\n              color: Colors.blue,\n              padding: const EdgeInsets.all(8),\n            ),\n          ),\n          GridPlacement(\n            rowStart: 1,\n            columnStart: 3,\n            child: Container(\n              color: Colors.blue,\n              padding: const EdgeInsets.all(8),\n            ),\n          ),\n          GridPlacement(\n            rowStart: 2,\n            columnStart: 0,\n            child: Container(\n              color: Colors.blue,\n              padding: const EdgeInsets.all(8),\n            ),\n          ),\n          GridPlacement(\n            rowStart: 2,\n            columnStart: 1,\n            child: Container(\n              color: Colors.blue,\n              padding: const EdgeInsets.all(8),\n            ),\n          ),\n          GridPlacement(\n            rowStart: 2,\n            columnStart: 2,\n            child: Container(\n              color: Colors.blue,\n              padding: const EdgeInsets.all(8),\n            ),\n          ),\n          GridPlacement(\n            rowStart: 2,\n            columnStart: 3,\n            child: Container(\n              color: Colors.blue,\n              padding: const EdgeInsets.all(8),\n            ),\n          ),\n        ],\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "example/lib/drag_and_drop_example.dart",
    "content": "// ignore_for_file: use_key_in_widget_constructors\n\nimport 'package:flutter/material.dart';\nimport 'package:flutter_layout_grid/flutter_layout_grid.dart';\n\nvoid main() {\n  runApp(DragAndDropApp());\n}\n\nconst cellSize = 32.0;\nconst columnCount = 16;\nconst rowCount = 16;\n\nclass DragAndDropExample extends StatefulWidget {\n  @override\n  State<DragAndDropExample> createState() => _DragAndDropExampleState();\n}\n\nclass _DragAndDropExampleState extends State<DragAndDropExample> {\n  /// The [Draggable] and [DragTarget] need to be associated with some type of\n  /// data (through their type argument, and `void` doesn't cut it). We keep it\n  /// simple and use a key, since we don't actually need to communicate anything\n  /// about the dragged data.\n  Key draggableKey = UniqueKey();\n\n  /// Current position of the [DraggableGridItem].\n  GridPosition draggablePosition = GridPosition(0, 0);\n\n  void gridItemMoved(GridPosition position) {\n    setState(() {\n      draggablePosition = position;\n    });\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    return LayoutGrid(\n      columnGap: 0,\n      rowGap: 0,\n      columnSizes: repeat(columnCount, [cellSize.px]),\n      rowSizes: repeat(rowCount, [cellSize.px]),\n      children: [\n        // Fill the grid with a `DragTarget` per cell\n        for (int i = 0; i < columnCount; i++)\n          for (int j = 0; j < rowCount; j++)\n            Cell(\n              column: i,\n              row: j,\n              cellBecameOccupied: gridItemMoved,\n            ).withGridPlacement(columnStart: i, rowStart: j),\n        // And a single Draggable, positioned according to the\n        // `draggablePosition` field.\n        DraggableGridItem(\n          key: draggableKey,\n        ).withGridPlacement(\n          columnStart: draggablePosition.x,\n          rowStart: draggablePosition.y,\n        )\n      ],\n    );\n  }\n}\n\n/// A square that can be dragged between grid cells.\nclass DraggableGridItem extends StatelessWidget {\n  const DraggableGridItem({\n    required Key key,\n  }) : super(key: key);\n\n  @override\n  Widget build(BuildContext context) {\n    final square = Container(\n      margin: const EdgeInsets.all(1),\n      decoration: BoxDecoration(\n        gradient: LinearGradient(\n          begin: Alignment.topCenter,\n          end: Alignment.bottomCenter,\n          colors: [Colors.blue[300]!, Colors.blue[700]!],\n        ),\n      ),\n    );\n\n    return Draggable<Key>(\n      data: key,\n      feedback: Opacity(\n        opacity: 0.6,\n        child: Transform.scale(\n          scale: 1.2,\n          // SizedBox is required here, because the feedback widget isn't bound\n          // by a cell and wants to be zero-sized.\n          child: SizedBox(\n            width: cellSize,\n            height: cellSize,\n            child: square,\n          ),\n        ),\n      ),\n      // Fade a bit for style\n      childWhenDragging: Opacity(\n        opacity: 0.25,\n        child: square,\n      ),\n      child: square,\n    );\n  }\n}\n\n/// Acts as a position that can be occupied by the [DraggableGridItem] widget.\nclass Cell extends StatefulWidget {\n  const Cell({\n    Key? key,\n    required this.column,\n    required this.row,\n    required this.cellBecameOccupied,\n  }) : super(key: key);\n\n  final int column;\n  final int row;\n  final DragTargetAccept<GridPosition> cellBecameOccupied;\n\n  @override\n  State<Cell> createState() => _CellState();\n}\n\nclass _CellState extends State<Cell> {\n  bool isDragHovering = false;\n\n  @override\n  Widget build(BuildContext context) {\n    return DragTarget<Key>(\n      onAcceptWithDetails: (_) {\n        setState(() => isDragHovering = false);\n        widget.cellBecameOccupied(GridPosition(widget.column, widget.row));\n      },\n      onMove: (details) => setState(() => isDragHovering = true),\n      onLeave: (details) => setState(() => isDragHovering = false),\n      builder: (context, candidateData, rejectedData) {\n        return Container(\n          margin: const EdgeInsets.all(1),\n          decoration: BoxDecoration(\n            border: isDragHovering\n                ? Border.all(\n                    color: Colors.purple[400]!,\n                    width: 2,\n                  )\n                : Border.all(\n                    color: Colors.grey[400]!,\n                  ),\n          ),\n        );\n      },\n    );\n  }\n}\n\nclass GridPosition {\n  GridPosition(this.x, this.y);\n  final int x;\n  final int y;\n}\n\nclass DragAndDropApp extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return MaterialApp(\n      title: 'Drag and Drop Example',\n      theme: ThemeData(\n        primarySwatch: Colors.blue,\n      ),\n      home: Scaffold(\n        body: Container(\n          color: Colors.white,\n          child: Center(\n            child: DragAndDropExample(),\n          ),\n        ),\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "example/lib/flutter_layout_grid_example.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:flutter_layout_grid/flutter_layout_grid.dart';\n\nvoid main() {\n  runApp(const PietNamedAreasApp());\n}\n\nconst cellRed = Color(0xffc73232);\nconst cellMustard = Color(0xffd7aa22);\nconst cellGrey = Color(0xffcfd4e0);\nconst cellBlue = Color(0xff1553be);\nconst background = Color(0xff242830);\n\nclass PietPainting extends StatelessWidget {\n  const PietPainting({Key? key}) : super(key: key);\n\n  @override\n  Widget build(BuildContext context) {\n    return Container(\n      color: background,\n      child: LayoutGrid(\n        columnGap: 12,\n        rowGap: 12,\n        areas: '''\n          r R B B  B\n          r R Y Y  Y\n          y R Y Y  Y\n          y R g b yy\n        ''',\n        // A number of extension methods are provided for concise track sizing\n        columnSizes: [1.0.fr, 3.5.fr, 1.3.fr, 1.3.fr, 1.3.fr],\n        rowSizes: [\n          1.0.fr,\n          0.3.fr,\n          1.5.fr,\n          1.2.fr,\n        ],\n        children: [\n          // Column 1\n          gridArea('r').containing(Container(color: cellRed)),\n          gridArea('y').containing(Container(color: cellMustard)),\n          // Column 2\n          gridArea('R').containing(Container(color: cellRed)),\n          // Column 3\n          gridArea('B').containing(Container(color: cellBlue)),\n          gridArea('Y').containing(Container(color: cellMustard)),\n          gridArea('g').containing(Container(color: cellGrey)),\n          // Column 4\n          gridArea('b').containing(Container(color: cellBlue)),\n          // Column 5\n          gridArea('yy').containing(Container(color: cellMustard)),\n        ],\n      ),\n    );\n  }\n}\n\nclass PietNamedAreasApp extends StatelessWidget {\n  const PietNamedAreasApp({Key? key}) : super(key: key);\n\n  @override\n  Widget build(BuildContext context) {\n    return WidgetsApp(\n      title: 'Layout Grid Desktop Example',\n      debugShowCheckedModeBanner: false,\n      color: Colors.white,\n      builder: (context, child) => const PietPainting(),\n    );\n  }\n}\n"
  },
  {
    "path": "example/lib/overlapping_items.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:flutter_layout_grid/flutter_layout_grid.dart';\n\nvoid main() {\n  runApp(const OverlappingItemsApp());\n}\n\nclass OverlappingItemsApp extends StatelessWidget {\n  const OverlappingItemsApp({Key? key}) : super(key: key);\n\n  @override\n  Widget build(BuildContext context) {\n    return WidgetsApp(\n        color: Colors.white,\n        debugShowCheckedModeBanner: false,\n        builder: (context, child) {\n          return const OverlappingItems();\n        });\n  }\n}\n\nclass OverlappingItems extends StatelessWidget {\n  const OverlappingItems({Key? key}) : super(key: key);\n\n  @override\n  Widget build(BuildContext context) {\n    return Padding(\n      padding: const EdgeInsets.all(32.0),\n      child: LayoutGrid(\n        columnSizes: repeat(7, [auto]),\n        rowSizes: repeat(7, [auto]),\n        children: [\n          // Children are drawn in order, making this the background.\n          ColoredBox(\n            color: Colors.grey[400]!,\n            margin: const EdgeInsets.all(24.0),\n          ).withGridPlacement(\n            columnStart: 0,\n            columnSpan: 7,\n            rowStart: 0,\n            rowSpan: 7,\n          ),\n          ColoredBox(color: Colors.blue[400]!).withGridPlacement(\n            columnStart: 0,\n            columnSpan: 3,\n            rowStart: 0,\n            rowSpan: 3,\n          ),\n          ColoredBox(color: Colors.yellow[400]!).withGridPlacement(\n            columnStart: 2,\n            columnSpan: 3,\n            rowStart: 2,\n            rowSpan: 3,\n          ),\n          ColoredBox(color: Colors.red[300]!).withGridPlacement(\n            columnStart: 4,\n            columnSpan: 3,\n            rowStart: 4,\n            rowSpan: 3,\n          ),\n        ],\n      ),\n    );\n  }\n}\n\nclass ColoredBox extends StatelessWidget {\n  const ColoredBox({\n    Key? key,\n    required this.color,\n    this.margin = EdgeInsets.zero,\n  }) : super(key: key);\n\n  final Color color;\n  final EdgeInsets margin;\n\n  @override\n  Widget build(BuildContext context) {\n    return Container(\n      margin: margin,\n      decoration: BoxDecoration(\n        color: color,\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "example/lib/periodic_table.dart",
    "content": "// periodic_table_json.json courtesy of\n// https://github.com/Bowserinator/Periodic-Table-JSON\n//\n// Based on the work by Mike Golus\n// https://www.csscodelab.com/html-css-only-periodic-table-of-elements/\n\nimport 'dart:convert';\nimport 'dart:math' as math;\n\nimport 'package:flutter/material.dart';\nimport 'package:flutter/services.dart';\nimport 'package:flutter_layout_grid/flutter_layout_grid.dart';\n\nvoid main() {\n  runApp(const PeriodicTableApp());\n}\n\nclass PeriodicTableApp extends StatelessWidget {\n  const PeriodicTableApp({Key? key}) : super(key: key);\n\n  @override\n  Widget build(BuildContext context) {\n    return DecoratedBox(\n      decoration: const BoxDecoration(\n        color: Color(0xff101318),\n      ),\n      child: WidgetsApp(\n        title: 'Periodic Table',\n        color: Colors.white,\n        debugShowCheckedModeBanner: false,\n        builder: (_, __) {\n          return LayoutBuilder(builder: (_, constraints) {\n            _viewportSize = constraints.biggest;\n            // PeriodicTableWidget has many AtomicElementWidget widgets\n            // as part of its descendant widget tree, and they use global\n            // variable _viewportSize during build, so it's not safe to use\n            // const. If it were const, then this widget tree would only be\n            // constructed once and would not adapt as the viewport size\n            // changed.\n            // ignore: prefer_const_constructors\n            return SingleChildScrollView(child: PeriodicTableWidget());\n          });\n        },\n      ),\n    );\n  }\n}\n\nclass PeriodicTableWidget extends StatefulWidget {\n  const PeriodicTableWidget({Key? key}) : super(key: key);\n\n  @override\n  State<PeriodicTableWidget> createState() => _PeriodicTableWidgetState();\n}\n\nclass _PeriodicTableWidgetState extends State<PeriodicTableWidget> {\n  late Future<PeriodicTable> tableFuture;\n\n  @override\n  void initState() {\n    super.initState();\n    tableFuture = loadPeriodicTable();\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    return Container(\n      padding: EdgeInsets.symmetric(horizontal: 1.5.vw, vertical: 1.vw),\n      child: FutureBuilder(\n        future: tableFuture,\n        builder: (_, AsyncSnapshot<PeriodicTable> snapshot) {\n          return snapshot.hasData\n              ? _buildGrid(snapshot.data!)\n              : const SizedBox();\n        },\n      ),\n    );\n  }\n\n  Widget _buildGrid(PeriodicTable table) {\n    return LayoutGrid(\n      gridFit: GridFit.loose,\n      columnSizes: repeat(table.numColumns, [1.fr]),\n      rowSizes: repeat(table.numRows, [auto]),\n      columnGap: 0.4.vw,\n      rowGap: 0.4.vw,\n      children: [\n        for (final e in table.elements)\n          AspectRatio(\n            aspectRatio: 40.1 / 42.4,\n            child: AtomicElementWidget(\n              key: ValueKey(e.symbol),\n              element: e,\n            ),\n          ).withGridPlacement(columnStart: e.x, rowStart: e.y),\n      ],\n    );\n  }\n}\n\nconst categoryColorMapping = {\n  AtomicElementCategory.actinide: Color(0xffc686cc),\n  AtomicElementCategory.alkaliMetal: Color(0xffecbe59),\n  AtomicElementCategory.alkalineEarthMetal: Color(0xffdee955),\n  AtomicElementCategory.lanthanide: Color(0xffec77a3),\n  AtomicElementCategory.metalloid: Color(0xff3aefb6),\n  AtomicElementCategory.nobleGas: Color(0xff759fff),\n  AtomicElementCategory.otherNonmetal: Color(0xff52ee61),\n  AtomicElementCategory.postTransitionMetal: Color(0xff4cddf3),\n  AtomicElementCategory.transitionMetal: Color(0xfffd8572),\n  AtomicElementCategory.unknown: Color(0xffcccccc),\n};\n\nclass AtomicElementWidget extends StatelessWidget {\n  const AtomicElementWidget({Key? key, required this.element})\n      : super(key: key);\n  final AtomicElement element;\n\n  @override\n  Widget build(BuildContext context) {\n    final elementColor = categoryColorMapping[element.category]!;\n    final elementTextStyle = TextStyle(\n      color: elementColor,\n      shadows: [\n        Shadow(color: elementColor, offset: Offset.zero, blurRadius: 0.3.vw),\n      ],\n    );\n    return Container(\n      decoration: BoxDecoration(\n        border: Border.all(\n          width: 0.2.vw,\n          color: elementColor,\n        ),\n      ),\n      // Some viewport sizes give us slight overflows, which can be attributed\n      // to rounding errors. So we use a stack and allow overflow on the bottom\n      // edge.\n      child: Stack(\n        clipBehavior: Clip.hardEdge,\n        children: [\n          Positioned.fill(\n            bottom: null,\n            child: _buildElementDetails(elementTextStyle),\n          ),\n        ],\n      ),\n    );\n  }\n\n  Column _buildElementDetails(TextStyle elementTextStyle) {\n    return Column(\n      crossAxisAlignment: CrossAxisAlignment.stretch,\n      children: [\n        Padding(\n          padding: EdgeInsets.fromLTRB(0.3.vw, 0.15.vw, 0, 0),\n          child: Text(\n            element.number.toString(),\n            style: elementTextStyle.copyWith(fontSize: 0.5.vw),\n            textAlign: TextAlign.left,\n          ),\n        ),\n        Text(\n          element.symbol,\n          style: elementTextStyle.copyWith(fontSize: 1.9.vw),\n          textAlign: TextAlign.center,\n          softWrap: false,\n        ),\n        Text(\n          element.name,\n          style: elementTextStyle.copyWith(fontSize: 0.65.vw),\n          textAlign: TextAlign.center,\n          softWrap: false,\n        ),\n        Padding(\n          padding: EdgeInsets.fromLTRB(0.0, 0.2.vw, 0.0, 0.3.vw),\n          child: Text(\n            element.formattedMass,\n            style: elementTextStyle.copyWith(fontSize: 0.5.vw),\n            textAlign: TextAlign.center,\n          ),\n        ),\n      ],\n    );\n  }\n}\n\nFuture<PeriodicTable> loadPeriodicTable() async {\n  final elementsJson = const JsonCodec().decode(await rootBundle\n      .loadString('lib/periodic_table_data.json'))['elements'] as List<dynamic>;\n\n  return PeriodicTable(elementsJson\n      .cast<Map<String, dynamic>>()\n      .map(AtomicElement.fromJson)\n      .toList());\n}\n\nclass PeriodicTable {\n  PeriodicTable(this.elements) {\n    for (final e in elements) {\n      numColumns = math.max(e.x + 1, numColumns);\n      numRows = math.max(e.y + 1, numRows);\n    }\n  }\n\n  final List<AtomicElement> elements;\n  int numColumns = 0;\n  int numRows = 0;\n}\n\nclass AtomicElement {\n  AtomicElement({\n    required this.name,\n    required this.symbol,\n    required this.number,\n    required this.category,\n    required this.atomicMass,\n    required this.stableIsotope,\n    required this.x,\n    required this.y,\n  });\n\n  final String name;\n  final String symbol;\n  final int number;\n  final AtomicElementCategory category;\n  final double atomicMass;\n  final bool stableIsotope;\n  final int x;\n  final int y;\n\n  String get formattedMass => stableIsotope\n      ? atomicMass.toStringAsMaxFixed(3)\n      : '(${atomicMass.toStringAsFixed(0)})';\n\n  @override\n  String toString() => name;\n\n  static AtomicElement fromJson(Map<String, dynamic> elementJson) {\n    final atomicMass = elementJson['atomic_mass'] as num;\n    return AtomicElement(\n      name: elementJson['name'] as String,\n      symbol: elementJson['symbol'] as String,\n      number: elementJson['number'] as int,\n      category: _parseAtomicElementCategory(elementJson['category'] as String),\n      atomicMass: atomicMass.toDouble(),\n      stableIsotope: atomicMass is double,\n      x: (elementJson['xpos'] as int) - 1, // File is 1-based\n      y: (elementJson['ypos'] as int) - 1, // File is 1-based\n    );\n  }\n}\n\nenum AtomicElementCategory {\n  actinide,\n  alkaliMetal,\n  alkalineEarthMetal,\n  lanthanide,\n  metalloid,\n  nobleGas,\n  otherNonmetal,\n  postTransitionMetal,\n  transitionMetal,\n  unknown,\n}\n\nAtomicElementCategory _parseAtomicElementCategory(String category) {\n  switch (category) {\n    case 'actinide':\n      return AtomicElementCategory.actinide;\n    case 'alkali metal':\n      return AtomicElementCategory.alkaliMetal;\n    case 'alkaline earth metal':\n      return AtomicElementCategory.alkalineEarthMetal;\n    case 'diatomic nonmetal':\n      return AtomicElementCategory.otherNonmetal;\n    case 'lanthanide':\n      return AtomicElementCategory.lanthanide;\n    case 'metalloid':\n      return AtomicElementCategory.metalloid;\n    case 'noble gas':\n      return AtomicElementCategory.nobleGas;\n    case 'polyatomic nonmetal':\n      return AtomicElementCategory.otherNonmetal;\n    case 'post-transition metal':\n      return AtomicElementCategory.postTransitionMetal;\n    case 'transition metal':\n      return AtomicElementCategory.transitionMetal;\n  }\n\n  assert(category.startsWith('unknown'));\n  return AtomicElementCategory.unknown;\n}\n\nextension ListExt<T> on List<T> {\n  List<T> operator *(int times) => generate(times).expand((e) => this).toList();\n}\n\nSize _viewportSize = Size.zero;\n\nextension on num {\n  double get vw => _viewportSize.width * (this / 100.0);\n}\n\nextension on double {\n  /// Formats a double with a maximum precision of [maxFractionDigits]. Any\n  /// trailing zeroes will be trimmed from the returned string.\n  String toStringAsMaxFixed([int maxFractionDigits = 2]) {\n    return toStringAsFixed(maxFractionDigits).replaceAll(RegExp(r'\\.?0+$'), '');\n  }\n}\n\nIterable<void> generate(int times) sync* {\n  for (int i = 0; i < times; i++) {\n    yield 0;\n  }\n}\n"
  },
  {
    "path": "example/lib/periodic_table_data.json",
    "content": "{\n  \"elements\": [\n    {\n      \"name\": \"Hydrogen\",\n      \"appearance\": \"colorless gas\",\n      \"atomic_mass\": 1.008,\n      \"boil\": 20.271,\n      \"category\": \"diatomic nonmetal\",\n      \"color\": null,\n      \"density\": 0.08988,\n      \"discovered_by\": \"Henry Cavendish\",\n      \"melt\": 13.99,\n      \"molar_heat\": 28.836,\n      \"named_by\": \"Antoine Lavoisier\",\n      \"number\": 1,\n      \"period\": 1,\n      \"phase\": \"Gas\",\n      \"source\": \"https://en.wikipedia.org/wiki/Hydrogen\",\n      \"spectral_img\": \"https://en.wikipedia.org/wiki/File:Hydrogen_Spectra.jpg\",\n      \"summary\": \"Hydrogen is a chemical element with chemical symbol H and atomic number 1. With an atomic weight of 1.00794 u, hydrogen is the lightest element on the periodic table. Its monatomic form (H) is the most abundant chemical substance in the Universe, constituting roughly 75% of all baryonic mass.\",\n      \"symbol\": \"H\",\n      \"xpos\": 1,\n      \"ypos\": 1,\n      \"shells\": [\n        1\n      ],\n      \"electron_configuration\": \"1s1\",\n      \"electron_configuration_semantic\": \"1s1\",\n      \"electron_affinity\": 72.769,\n      \"electronegativity_pauling\": 2.2,\n      \"ionization_energies\": [\n        1312\n      ],\n      \"cpk-hex\": \"ffffff\"\n    },\n    {\n      \"name\": \"Helium\",\n      \"appearance\": \"colorless gas, exhibiting a red-orange glow when placed in a high-voltage electric field\",\n      \"atomic_mass\": 4.0026022,\n      \"boil\": 4.222,\n      \"category\": \"noble gas\",\n      \"color\": null,\n      \"density\": 0.1786,\n      \"discovered_by\": \"Pierre Janssen\",\n      \"melt\": 0.95,\n      \"molar_heat\": null,\n      \"named_by\": null,\n      \"number\": 2,\n      \"period\": 1,\n      \"phase\": \"Gas\",\n      \"source\": \"https://en.wikipedia.org/wiki/Helium\",\n      \"spectral_img\": \"https://en.wikipedia.org/wiki/File:Helium_spectrum.jpg\",\n      \"summary\": \"Helium is a chemical element with symbol He and atomic number 2. It is a colorless, odorless, tasteless, non-toxic, inert, monatomic gas that heads the noble gas group in the periodic table. Its boiling and melting points are the lowest among all the elements.\",\n      \"symbol\": \"He\",\n      \"xpos\": 18,\n      \"ypos\": 1,\n      \"shells\": [\n        2\n      ],\n      \"electron_configuration\": \"1s2\",\n      \"electron_configuration_semantic\": \"1s2\",\n      \"electron_affinity\": -48,\n      \"electronegativity_pauling\": null,\n      \"ionization_energies\": [\n        2372.3,\n        5250.5\n      ],\n      \"cpk-hex\": \"d9ffff\"\n    },\n    {\n      \"name\": \"Lithium\",\n      \"appearance\": \"silvery-white\",\n      \"atomic_mass\": 6.94,\n      \"boil\": 1603,\n      \"category\": \"alkali metal\",\n      \"color\": null,\n      \"density\": 0.534,\n      \"discovered_by\": \"Johan August Arfwedson\",\n      \"melt\": 453.65,\n      \"molar_heat\": 24.86,\n      \"named_by\": null,\n      \"number\": 3,\n      \"period\": 2,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Lithium\",\n      \"spectral_img\": null,\n      \"summary\": \"Lithium (from Greek:λίθος lithos, \\\"stone\\\") is a chemical element with the symbol Li and atomic number 3. It is a soft, silver-white metal belonging to the alkali metal group of chemical elements. Under standard conditions it is the lightest metal and the least dense solid element.\",\n      \"symbol\": \"Li\",\n      \"xpos\": 1,\n      \"ypos\": 2,\n      \"shells\": [\n        2,\n        1\n      ],\n      \"electron_configuration\": \"1s2 2s1\",\n      \"electron_configuration_semantic\": \"[He] 2s1\",\n      \"electron_affinity\": 59.6326,\n      \"electronegativity_pauling\": 0.98,\n      \"ionization_energies\": [\n        520.2,\n        7298.1,\n        11815\n      ],\n      \"cpk-hex\": \"cc80ff\"\n    },\n    {\n      \"name\": \"Beryllium\",\n      \"appearance\": \"white-gray metallic\",\n      \"atomic_mass\": 9.01218315,\n      \"boil\": 2742,\n      \"category\": \"alkaline earth metal\",\n      \"color\": null,\n      \"density\": 1.85,\n      \"discovered_by\": \"Louis Nicolas Vauquelin\",\n      \"melt\": 1560,\n      \"molar_heat\": 16.443,\n      \"named_by\": null,\n      \"number\": 4,\n      \"period\": 2,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Beryllium\",\n      \"spectral_img\": null,\n      \"summary\": \"Beryllium is a chemical element with symbol Be and atomic number 4. It is created through stellar nucleosynthesis and is a relatively rare element in the universe. It is a divalent element which occurs naturally only in combination with other elements in minerals.\",\n      \"symbol\": \"Be\",\n      \"xpos\": 2,\n      \"ypos\": 2,\n      \"shells\": [\n        2,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2\",\n      \"electron_configuration_semantic\": \"[He] 2s2\",\n      \"electron_affinity\": -48,\n      \"electronegativity_pauling\": 1.57,\n      \"ionization_energies\": [\n        899.5,\n        1757.1,\n        14848.7,\n        21006.6\n      ],\n      \"cpk-hex\": \"c2ff00\"\n    },\n    {\n      \"name\": \"Boron\",\n      \"appearance\": \"black-brown\",\n      \"atomic_mass\": 10.81,\n      \"boil\": 4200,\n      \"category\": \"metalloid\",\n      \"color\": null,\n      \"density\": 2.08,\n      \"discovered_by\": \"Joseph Louis Gay-Lussac\",\n      \"melt\": 2349,\n      \"molar_heat\": 11.087,\n      \"named_by\": null,\n      \"number\": 5,\n      \"period\": 2,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Boron\",\n      \"spectral_img\": null,\n      \"summary\": \"Boron is a metalloid chemical element with symbol B and atomic number 5. Produced entirely by cosmic ray spallation and supernovae and not by stellar nucleosynthesis, it is a low-abundance element in both the Solar system and the Earth's crust. Boron is concentrated on Earth by the water-solubility of its more common naturally occurring compounds, the borate minerals.\",\n      \"symbol\": \"B\",\n      \"xpos\": 13,\n      \"ypos\": 2,\n      \"shells\": [\n        2,\n        3\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p1\",\n      \"electron_configuration_semantic\": \"[He] 2s2 2p1\",\n      \"electron_affinity\": 26.989,\n      \"electronegativity_pauling\": 2.04,\n      \"ionization_energies\": [\n        800.6,\n        2427.1,\n        3659.7,\n        25025.8,\n        32826.7\n      ],\n      \"cpk-hex\": \"ffb5b5\"\n    },\n    {\n      \"name\": \"Carbon\",\n      \"appearance\": null,\n      \"atomic_mass\": 12.011,\n      \"boil\": null,\n      \"category\": \"polyatomic nonmetal\",\n      \"color\": null,\n      \"density\": 1.821,\n      \"discovered_by\": \"Ancient Egypt\",\n      \"melt\": null,\n      \"molar_heat\": 8.517,\n      \"named_by\": null,\n      \"number\": 6,\n      \"period\": 2,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Carbon\",\n      \"spectral_img\": \"https://en.wikipedia.org/wiki/File:Carbon_Spectra.jpg\",\n      \"summary\": \"Carbon (from Latin:carbo \\\"coal\\\") is a chemical element with symbol C and atomic number 6. On the periodic table, it is the first (row 2) of six elements in column (group) 14, which have in common the composition of their outer electron shell. It is nonmetallic and tetravalent—making four electrons available to form covalent chemical bonds.\",\n      \"symbol\": \"C\",\n      \"xpos\": 14,\n      \"ypos\": 2,\n      \"shells\": [\n        2,\n        4\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p2\",\n      \"electron_configuration_semantic\": \"[He] 2s2 2p2\",\n      \"electron_affinity\": 121.7763,\n      \"electronegativity_pauling\": 2.55,\n      \"ionization_energies\": [\n        1086.5,\n        2352.6,\n        4620.5,\n        6222.7,\n        37831,\n        47277\n      ],\n      \"cpk-hex\": \"909090\"\n    },\n    {\n      \"name\": \"Nitrogen\",\n      \"appearance\": \"colorless gas, liquid or solid\",\n      \"atomic_mass\": 14.007,\n      \"boil\": 77.355,\n      \"category\": \"diatomic nonmetal\",\n      \"color\": null,\n      \"density\": 1.251,\n      \"discovered_by\": \"Daniel Rutherford\",\n      \"melt\": 63.15,\n      \"molar_heat\": null,\n      \"named_by\": \"Jean-Antoine Chaptal\",\n      \"number\": 7,\n      \"period\": 2,\n      \"phase\": \"Gas\",\n      \"source\": \"https://en.wikipedia.org/wiki/Nitrogen\",\n      \"spectral_img\": \"https://en.wikipedia.org/wiki/File:Nitrogen_Spectra.jpg\",\n      \"summary\": \"Nitrogen is a chemical element with symbol N and atomic number 7. It is the lightest pnictogen and at room temperature, it is a transparent, odorless diatomic gas. Nitrogen is a common element in the universe, estimated at about seventh in total abundance in the Milky Way and the Solar System.\",\n      \"symbol\": \"N\",\n      \"xpos\": 15,\n      \"ypos\": 2,\n      \"shells\": [\n        2,\n        5\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p3\",\n      \"electron_configuration_semantic\": \"[He] 2s2 2p3\",\n      \"electron_affinity\": -6.8,\n      \"electronegativity_pauling\": 3.04,\n      \"ionization_energies\": [\n        1402.3,\n        2856,\n        4578.1,\n        7475,\n        9444.9,\n        53266.6,\n        64360\n      ],\n      \"cpk-hex\": \"3050f8\"\n    },\n    {\n      \"name\": \"Oxygen\",\n      \"appearance\": null,\n      \"atomic_mass\": 15.999,\n      \"boil\": 90.188,\n      \"category\": \"diatomic nonmetal\",\n      \"color\": null,\n      \"density\": 1.429,\n      \"discovered_by\": \"Carl Wilhelm Scheele\",\n      \"melt\": 54.36,\n      \"molar_heat\": null,\n      \"named_by\": \"Antoine Lavoisier\",\n      \"number\": 8,\n      \"period\": 2,\n      \"phase\": \"Gas\",\n      \"source\": \"https://en.wikipedia.org/wiki/Oxygen\",\n      \"spectral_img\": \"https://en.wikipedia.org/wiki/File:Oxygen_spectre.jpg\",\n      \"summary\": \"Oxygen is a chemical element with symbol O and atomic number 8. It is a member of the chalcogen group on the periodic table and is a highly reactive nonmetal and oxidizing agent that readily forms compounds (notably oxides) with most elements. By mass, oxygen is the third-most abundant element in the universe, after hydrogen and helium.\",\n      \"symbol\": \"O\",\n      \"xpos\": 16,\n      \"ypos\": 2,\n      \"shells\": [\n        2,\n        6\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p4\",\n      \"electron_configuration_semantic\": \"[He] 2s2 2p4\",\n      \"electron_affinity\": 140.976,\n      \"electronegativity_pauling\": 3.44,\n      \"ionization_energies\": [\n        1313.9,\n        3388.3,\n        5300.5,\n        7469.2,\n        10989.5,\n        13326.5,\n        71330,\n        84078\n      ],\n      \"cpk-hex\": \"ff0d0d\"\n    },\n    {\n      \"name\": \"Fluorine\",\n      \"appearance\": null,\n      \"atomic_mass\": 18.9984031636,\n      \"boil\": 85.03,\n      \"category\": \"diatomic nonmetal\",\n      \"color\": null,\n      \"density\": 1.696,\n      \"discovered_by\": \"André-Marie Ampère\",\n      \"melt\": 53.48,\n      \"molar_heat\": null,\n      \"named_by\": \"Humphry Davy\",\n      \"number\": 9,\n      \"period\": 2,\n      \"phase\": \"Gas\",\n      \"source\": \"https://en.wikipedia.org/wiki/Fluorine\",\n      \"spectral_img\": null,\n      \"summary\": \"Fluorine is a chemical element with symbol F and atomic number 9. It is the lightest halogen and exists as a highly toxic pale yellow diatomic gas at standard conditions. As the most electronegative element, it is extremely reactive:almost all other elements, including some noble gases, form compounds with fluorine.\",\n      \"symbol\": \"F\",\n      \"xpos\": 17,\n      \"ypos\": 2,\n      \"shells\": [\n        2,\n        7\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p5\",\n      \"electron_configuration_semantic\": \"[He] 2s2 2p5\",\n      \"electron_affinity\": 328.1649,\n      \"electronegativity_pauling\": 3.98,\n      \"ionization_energies\": [\n        1681,\n        3374.2,\n        6050.4,\n        8407.7,\n        11022.7,\n        15164.1,\n        17868,\n        92038.1,\n        106434.3\n      ],\n      \"cpk-hex\": \"90e050\"\n    },\n    {\n      \"name\": \"Neon\",\n      \"appearance\": \"colorless gas exhibiting an orange-red glow when placed in a high voltage electric field\",\n      \"atomic_mass\": 20.17976,\n      \"boil\": 27.104,\n      \"category\": \"noble gas\",\n      \"color\": null,\n      \"density\": 0.9002,\n      \"discovered_by\": \"Morris Travers\",\n      \"melt\": 24.56,\n      \"molar_heat\": null,\n      \"named_by\": null,\n      \"number\": 10,\n      \"period\": 2,\n      \"phase\": \"Gas\",\n      \"source\": \"https://en.wikipedia.org/wiki/Neon\",\n      \"spectral_img\": \"https://en.wikipedia.org/wiki/File:Neon_spectra.jpg\",\n      \"summary\": \"Neon is a chemical element with symbol Ne and atomic number 10. It is in group 18 (noble gases) of the periodic table. Neon is a colorless, odorless, inert monatomic gas under standard conditions, with about two-thirds the density of air.\",\n      \"symbol\": \"Ne\",\n      \"xpos\": 18,\n      \"ypos\": 2,\n      \"shells\": [\n        2,\n        8\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6\",\n      \"electron_configuration_semantic\": \"[He] 2s2 2p6\",\n      \"electron_affinity\": -116,\n      \"electronegativity_pauling\": null,\n      \"ionization_energies\": [\n        2080.7,\n        3952.3,\n        6122,\n        9371,\n        12177,\n        15238,\n        19999,\n        23069.5,\n        115379.5,\n        131432\n      ],\n      \"cpk-hex\": \"b3e3f5\"\n    },\n    {\n      \"name\": \"Sodium\",\n      \"appearance\": \"silvery white metallic\",\n      \"atomic_mass\": 22.989769282,\n      \"boil\": 1156.09,\n      \"category\": \"alkali metal\",\n      \"color\": null,\n      \"density\": 0.968,\n      \"discovered_by\": \"Humphry Davy\",\n      \"melt\": 370.944,\n      \"molar_heat\": 28.23,\n      \"named_by\": null,\n      \"number\": 11,\n      \"period\": 3,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Sodium\",\n      \"spectral_img\": \"https://en.wikipedia.org/wiki/File:Sodium_Spectra.jpg\",\n      \"summary\": \"Sodium /ˈsoʊdiəm/ is a chemical element with symbol Na (from Ancient Greek Νάτριο) and atomic number 11. It is a soft, silver-white, highly reactive metal. In the Periodic table it is in column 1 (alkali metals), and shares with the other six elements in that column that it has a single electron in its outer shell, which it readily donates, creating a positively charged atom - a cation.\",\n      \"symbol\": \"Na\",\n      \"xpos\": 1,\n      \"ypos\": 3,\n      \"shells\": [\n        2,\n        8,\n        1\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s1\",\n      \"electron_configuration_semantic\": \"[Ne] 3s1\",\n      \"electron_affinity\": 52.867,\n      \"electronegativity_pauling\": 0.93,\n      \"ionization_energies\": [\n        495.8,\n        4562,\n        6910.3,\n        9543,\n        13354,\n        16613,\n        20117,\n        25496,\n        28932,\n        141362,\n        159076\n      ],\n      \"cpk-hex\": \"ab5cf2\"\n    },\n    {\n      \"name\": \"Magnesium\",\n      \"appearance\": \"shiny grey solid\",\n      \"atomic_mass\": 24.305,\n      \"boil\": 1363,\n      \"category\": \"alkaline earth metal\",\n      \"color\": null,\n      \"density\": 1.738,\n      \"discovered_by\": \"Joseph Black\",\n      \"melt\": 923,\n      \"molar_heat\": 24.869,\n      \"named_by\": null,\n      \"number\": 12,\n      \"period\": 3,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Magnesium\",\n      \"spectral_img\": \"https://en.wikipedia.org/wiki/File:Magnesium_Spectra.jpg\",\n      \"summary\": \"Magnesium is a chemical element with symbol Mg and atomic number 12. It is a shiny gray solid which bears a close physical resemblance to the other five elements in the second column (Group 2, or alkaline earth metals) of the periodic table:they each have the same electron configuration in their outer electron shell producing a similar crystal structure. Magnesium is the ninth most abundant element in the universe.\",\n      \"symbol\": \"Mg\",\n      \"xpos\": 2,\n      \"ypos\": 3,\n      \"shells\": [\n        2,\n        8,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2\",\n      \"electron_configuration_semantic\": \"[Ne] 3s2\",\n      \"electron_affinity\": -40,\n      \"electronegativity_pauling\": 1.31,\n      \"ionization_energies\": [\n        737.7,\n        1450.7,\n        7732.7,\n        10542.5,\n        13630,\n        18020,\n        21711,\n        25661,\n        31653,\n        35458,\n        169988,\n        189368\n      ],\n      \"cpk-hex\": \"8aff00\"\n    },\n    {\n      \"name\": \"Aluminium\",\n      \"appearance\": \"silvery gray metallic\",\n      \"atomic_mass\": 26.98153857,\n      \"boil\": 2743,\n      \"category\": \"post-transition metal\",\n      \"color\": null,\n      \"density\": 2.7,\n      \"discovered_by\": null,\n      \"melt\": 933.47,\n      \"molar_heat\": 24.2,\n      \"named_by\": \"Humphry Davy\",\n      \"number\": 13,\n      \"period\": 3,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Aluminium\",\n      \"spectral_img\": null,\n      \"summary\": \"Aluminium (or aluminum; see different endings) is a chemical element in the boron group with symbol Al and atomic number 13. It is a silvery-white, soft, nonmagnetic, ductile metal. Aluminium is the third most abundant element (after oxygen and silicon), and the most abundant metal, in the Earth's crust.\",\n      \"symbol\": \"Al\",\n      \"xpos\": 13,\n      \"ypos\": 3,\n      \"shells\": [\n        2,\n        8,\n        3\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p1\",\n      \"electron_configuration_semantic\": \"[Ne] 3s2 3p1\",\n      \"electron_affinity\": 41.762,\n      \"electronegativity_pauling\": 1.61,\n      \"ionization_energies\": [\n        577.5,\n        1816.7,\n        2744.8,\n        11577,\n        14842,\n        18379,\n        23326,\n        27465,\n        31853,\n        38473,\n        42647,\n        201266,\n        222316\n      ],\n      \"cpk-hex\": \"bfa6a6\"\n    },\n    {\n      \"name\": \"Silicon\",\n      \"appearance\": \"crystalline, reflective with bluish-tinged faces\",\n      \"atomic_mass\": 28.085,\n      \"boil\": 3538,\n      \"category\": \"metalloid\",\n      \"color\": null,\n      \"density\": 2.329,\n      \"discovered_by\": \"Jöns Jacob Berzelius\",\n      \"melt\": 1687,\n      \"molar_heat\": 19.789,\n      \"named_by\": \"Thomas Thomson (chemist)\",\n      \"number\": 14,\n      \"period\": 3,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Silicon\",\n      \"spectral_img\": \"https://en.wikipedia.org/wiki/File:Silicon_Spectra.jpg\",\n      \"summary\": \"Silicon is a chemical element with symbol Si and atomic number 14. It is a tetravalent metalloid, more reactive than germanium, the metalloid directly below it in the table. Controversy about silicon's character dates to its discovery.\",\n      \"symbol\": \"Si\",\n      \"xpos\": 14,\n      \"ypos\": 3,\n      \"shells\": [\n        2,\n        8,\n        4\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p2\",\n      \"electron_configuration_semantic\": \"[Ne] 3s2 3p2\",\n      \"electron_affinity\": 134.0684,\n      \"electronegativity_pauling\": 1.9,\n      \"ionization_energies\": [\n        786.5,\n        1577.1,\n        3231.6,\n        4355.5,\n        16091,\n        19805,\n        23780,\n        29287,\n        33878,\n        38726,\n        45962,\n        50502,\n        235196,\n        257923\n      ],\n      \"cpk-hex\": \"f0c8a0\"\n    },\n    {\n      \"name\": \"Phosphorus\",\n      \"appearance\": \"colourless, waxy white, yellow, scarlet, red, violet, black\",\n      \"atomic_mass\": 30.9737619985,\n      \"boil\": null,\n      \"category\": \"polyatomic nonmetal\",\n      \"color\": null,\n      \"density\": 1.823,\n      \"discovered_by\": \"Hennig Brand\",\n      \"melt\": null,\n      \"molar_heat\": 23.824,\n      \"named_by\": null,\n      \"number\": 15,\n      \"period\": 3,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Phosphorus\",\n      \"spectral_img\": null,\n      \"summary\": \"Phosphorus is a chemical element with symbol P and atomic number 15. As an element, phosphorus exists in two major forms—white phosphorus and red phosphorus—but due to its high reactivity, phosphorus is never found as a free element on Earth. Instead phosphorus-containing minerals are almost always present in their maximally oxidised state, as inorganic phosphate rocks.\",\n      \"symbol\": \"P\",\n      \"xpos\": 15,\n      \"ypos\": 3,\n      \"shells\": [\n        2,\n        8,\n        5\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p3\",\n      \"electron_configuration_semantic\": \"[Ne] 3s2 3p3\",\n      \"electron_affinity\": 72.037,\n      \"electronegativity_pauling\": 2.19,\n      \"ionization_energies\": [\n        1011.8,\n        1907,\n        2914.1,\n        4963.6,\n        6273.9,\n        21267,\n        25431,\n        29872,\n        35905,\n        40950,\n        46261,\n        54110,\n        59024,\n        271791,\n        296195\n      ],\n      \"cpk-hex\": \"ff8000\"\n    },\n    {\n      \"name\": \"Sulfur\",\n      \"appearance\": \"lemon yellow sintered microcrystals\",\n      \"atomic_mass\": 32.06,\n      \"boil\": 717.8,\n      \"category\": \"polyatomic nonmetal\",\n      \"color\": null,\n      \"density\": 2.07,\n      \"discovered_by\": \"Ancient china\",\n      \"melt\": 388.36,\n      \"molar_heat\": 22.75,\n      \"named_by\": null,\n      \"number\": 16,\n      \"period\": 3,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Sulfur\",\n      \"spectral_img\": \"https://en.wikipedia.org/wiki/File:Sulfur_Spectrum.jpg\",\n      \"summary\": \"Sulfur or sulphur (see spelling differences) is a chemical element with symbol S and atomic number 16. It is an abundant, multivalent non-metal. Under normal conditions, sulfur atoms form cyclic octatomic molecules with chemical formula S8.\",\n      \"symbol\": \"S\",\n      \"xpos\": 16,\n      \"ypos\": 3,\n      \"shells\": [\n        2,\n        8,\n        6\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p4\",\n      \"electron_configuration_semantic\": \"[Ne] 3s2 3p4\",\n      \"electron_affinity\": 200.4101,\n      \"electronegativity_pauling\": 2.58,\n      \"ionization_energies\": [\n        999.6,\n        2252,\n        3357,\n        4556,\n        7004.3,\n        8495.8,\n        27107,\n        31719,\n        36621,\n        43177,\n        48710,\n        54460,\n        62930,\n        68216,\n        311048,\n        337138\n      ],\n      \"cpk-hex\": \"ffff30\"\n    },\n    {\n      \"name\": \"Chlorine\",\n      \"appearance\": \"pale yellow-green gas\",\n      \"atomic_mass\": 35.45,\n      \"boil\": 239.11,\n      \"category\": \"diatomic nonmetal\",\n      \"color\": null,\n      \"density\": 3.2,\n      \"discovered_by\": \"Carl Wilhelm Scheele\",\n      \"melt\": 171.6,\n      \"molar_heat\": null,\n      \"named_by\": null,\n      \"number\": 17,\n      \"period\": 3,\n      \"phase\": \"Gas\",\n      \"source\": \"https://en.wikipedia.org/wiki/Chlorine\",\n      \"spectral_img\": \"https://en.wikipedia.org/wiki/File:Chlorine_spectrum_visible.png\",\n      \"summary\": \"Chlorine is a chemical element with symbol Cl and atomic number 17. It also has a relative atomic mass of 35.5. Chlorine is in the halogen group (17) and is the second lightest halogen following fluorine.\",\n      \"symbol\": \"Cl\",\n      \"xpos\": 17,\n      \"ypos\": 3,\n      \"shells\": [\n        2,\n        8,\n        7\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p5\",\n      \"electron_configuration_semantic\": \"[Ne] 3s2 3p5\",\n      \"electron_affinity\": 348.575,\n      \"electronegativity_pauling\": 3.16,\n      \"ionization_energies\": [\n        1251.2,\n        2298,\n        3822,\n        5158.6,\n        6542,\n        9362,\n        11018,\n        33604,\n        38600,\n        43961,\n        51068,\n        57119,\n        63363,\n        72341,\n        78095,\n        352994,\n        380760\n      ],\n      \"cpk-hex\": \"1ff01f\"\n    },\n    {\n      \"name\": \"Argon\",\n      \"appearance\": \"colorless gas exhibiting a lilac/violet glow when placed in a high voltage electric field\",\n      \"atomic_mass\": 39.9481,\n      \"boil\": 87.302,\n      \"category\": \"noble gas\",\n      \"color\": null,\n      \"density\": 1.784,\n      \"discovered_by\": \"Lord Rayleigh\",\n      \"melt\": 83.81,\n      \"molar_heat\": null,\n      \"named_by\": null,\n      \"number\": 18,\n      \"period\": 3,\n      \"phase\": \"Gas\",\n      \"source\": \"https://en.wikipedia.org/wiki/Argon\",\n      \"spectral_img\": \"https://en.wikipedia.org/wiki/File:Argon_Spectrum.png\",\n      \"summary\": \"Argon is a chemical element with symbol Ar and atomic number 18. It is in group 18 of the periodic table and is a noble gas. Argon is the third most common gas in the Earth's atmosphere, at 0.934% (9,340 ppmv), making it over twice as abundant as the next most common atmospheric gas, water vapor (which averages about 4000 ppmv, but varies greatly), and 23 times as abundant as the next most common non-condensing atmospheric gas, carbon dioxide (400 ppmv), and more than 500 times as abundant as the next most common noble gas, neon (18 ppmv).\",\n      \"symbol\": \"Ar\",\n      \"xpos\": 18,\n      \"ypos\": 3,\n      \"shells\": [\n        2,\n        8,\n        8\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6\",\n      \"electron_configuration_semantic\": \"[Ne] 3s2 3p6\",\n      \"electron_affinity\": -96,\n      \"electronegativity_pauling\": null,\n      \"ionization_energies\": [\n        1520.6,\n        2665.8,\n        3931,\n        5771,\n        7238,\n        8781,\n        11995,\n        13842,\n        40760,\n        46186,\n        52002,\n        59653,\n        66199,\n        72918,\n        82473,\n        88576,\n        397605,\n        427066\n      ],\n      \"cpk-hex\": \"80d1e3\"\n    },\n    {\n      \"name\": \"Potassium\",\n      \"appearance\": \"silvery gray\",\n      \"atomic_mass\": 39.09831,\n      \"boil\": 1032,\n      \"category\": \"alkali metal\",\n      \"color\": null,\n      \"density\": 0.862,\n      \"discovered_by\": \"Humphry Davy\",\n      \"melt\": 336.7,\n      \"molar_heat\": 29.6,\n      \"named_by\": null,\n      \"number\": 19,\n      \"period\": 4,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Potassium\",\n      \"spectral_img\": \"https://en.wikipedia.org/wiki/File:Potassium_Spectrum.jpg\",\n      \"summary\": \"Potassium is a chemical element with symbol K (derived from Neo-Latin, kalium) and atomic number 19. It was first isolated from potash, the ashes of plants, from which its name is derived. In the Periodic table, potassium is one of seven elements in column (group) 1 (alkali metals):they all have a single valence electron in their outer electron shell, which they readily give up to create an atom with a positive charge - a cation, and combine with anions to form salts.\",\n      \"symbol\": \"K\",\n      \"xpos\": 1,\n      \"ypos\": 4,\n      \"shells\": [\n        2,\n        8,\n        8,\n        1\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s1\",\n      \"electron_configuration_semantic\": \"[Ar] 4s1\",\n      \"electron_affinity\": 48.383,\n      \"electronegativity_pauling\": 0.82,\n      \"ionization_energies\": [\n        418.8,\n        3052,\n        4420,\n        5877,\n        7975,\n        9590,\n        11343,\n        14944,\n        16963.7,\n        48610,\n        54490,\n        60730,\n        68950,\n        75900,\n        83080,\n        93400,\n        99710,\n        444880,\n        476063\n      ],\n      \"cpk-hex\": \"8f40d4\"\n    },\n    {\n      \"name\": \"Calcium\",\n      \"appearance\": null,\n      \"atomic_mass\": 40.0784,\n      \"boil\": 1757,\n      \"category\": \"alkaline earth metal\",\n      \"color\": null,\n      \"density\": 1.55,\n      \"discovered_by\": \"Humphry Davy\",\n      \"melt\": 1115,\n      \"molar_heat\": 25.929,\n      \"named_by\": null,\n      \"number\": 20,\n      \"period\": 4,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Calcium\",\n      \"spectral_img\": \"https://en.wikipedia.org/wiki/File:Calcium_Spectrum.png\",\n      \"summary\": \"Calcium is a chemical element with symbol Ca and atomic number 20. Calcium is a soft gray alkaline earth metal, fifth-most-abundant element by mass in the Earth's crust. The ion Ca2+ is also the fifth-most-abundant dissolved ion in seawater by both molarity and mass, after sodium, chloride, magnesium, and sulfate.\",\n      \"symbol\": \"Ca\",\n      \"xpos\": 2,\n      \"ypos\": 4,\n      \"shells\": [\n        2,\n        8,\n        8,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2\",\n      \"electron_configuration_semantic\": \"[Ar] 4s2\",\n      \"electron_affinity\": 2.37,\n      \"electronegativity_pauling\": 1,\n      \"ionization_energies\": [\n        589.8,\n        1145.4,\n        4912.4,\n        6491,\n        8153,\n        10496,\n        12270,\n        14206,\n        18191,\n        20385,\n        57110,\n        63410,\n        70110,\n        78890,\n        86310,\n        94000,\n        104900,\n        111711,\n        494850,\n        527762\n      ],\n      \"cpk-hex\": \"3dff00\"\n    },\n    {\n      \"name\": \"Scandium\",\n      \"appearance\": \"silvery white\",\n      \"atomic_mass\": 44.9559085,\n      \"boil\": 3109,\n      \"category\": \"transition metal\",\n      \"color\": null,\n      \"density\": 2.985,\n      \"discovered_by\": \"Lars Fredrik Nilson\",\n      \"melt\": 1814,\n      \"molar_heat\": 25.52,\n      \"named_by\": null,\n      \"number\": 21,\n      \"period\": 4,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Scandium\",\n      \"spectral_img\": null,\n      \"summary\": \"Scandium is a chemical element with symbol Sc and atomic number 21. A silvery-white metallic d-block element, it has historically been sometimes classified as a rare earth element, together with yttrium and the lanthanoids. It was discovered in 1879 by spectral analysis of the minerals euxenite and gadolinite from Scandinavia.\",\n      \"symbol\": \"Sc\",\n      \"xpos\": 3,\n      \"ypos\": 4,\n      \"shells\": [\n        2,\n        8,\n        9,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d1\",\n      \"electron_configuration_semantic\": \"[Ar] 3d1 4s2\",\n      \"electron_affinity\": 18,\n      \"electronegativity_pauling\": 1.36,\n      \"ionization_energies\": [\n        633.1,\n        1235,\n        2388.6,\n        7090.6,\n        8843,\n        10679,\n        13310,\n        15250,\n        17370,\n        21726,\n        24102,\n        66320,\n        73010,\n        80160,\n        89490,\n        97400,\n        105600,\n        117000,\n        124270,\n        547530,\n        582163\n      ],\n      \"cpk-hex\": \"e6e6e6\"\n    },\n    {\n      \"name\": \"Titanium\",\n      \"appearance\": \"silvery grey-white metallic\",\n      \"atomic_mass\": 47.8671,\n      \"boil\": 3560,\n      \"category\": \"transition metal\",\n      \"color\": null,\n      \"density\": 4.506,\n      \"discovered_by\": \"William Gregor\",\n      \"melt\": 1941,\n      \"molar_heat\": 25.06,\n      \"named_by\": \"Martin Heinrich Klaproth\",\n      \"number\": 22,\n      \"period\": 4,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Titanium\",\n      \"spectral_img\": null,\n      \"summary\": \"Titanium is a chemical element with symbol Ti and atomic number 22. It is a lustrous transition metal with a silver color, low density and high strength. It is highly resistant to corrosion in sea water, aqua regia and chlorine.\",\n      \"symbol\": \"Ti\",\n      \"xpos\": 4,\n      \"ypos\": 4,\n      \"shells\": [\n        2,\n        8,\n        10,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d2\",\n      \"electron_configuration_semantic\": \"[Ar] 3d2 4s2\",\n      \"electron_affinity\": 7.289,\n      \"electronegativity_pauling\": 1.54,\n      \"ionization_energies\": [\n        658.8,\n        1309.8,\n        2652.5,\n        4174.6,\n        9581,\n        11533,\n        13590,\n        16440,\n        18530,\n        20833,\n        25575,\n        28125,\n        76015,\n        83280,\n        90880,\n        100700,\n        109100,\n        117800,\n        129900,\n        137530,\n        602930,\n        639294\n      ],\n      \"cpk-hex\": \"bfc2c7\"\n    },\n    {\n      \"name\": \"Vanadium\",\n      \"appearance\": \"blue-silver-grey metal\",\n      \"atomic_mass\": 50.94151,\n      \"boil\": 3680,\n      \"category\": \"transition metal\",\n      \"color\": null,\n      \"density\": 6,\n      \"discovered_by\": \"Andrés Manuel del Río\",\n      \"melt\": 2183,\n      \"molar_heat\": 24.89,\n      \"named_by\": \"Isotopes of vanadium\",\n      \"number\": 23,\n      \"period\": 4,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Vanadium\",\n      \"spectral_img\": null,\n      \"summary\": \"Vanadium is a chemical element with symbol V and atomic number 23. It is a hard, silvery grey, ductile and malleable transition metal. The element is found only in chemically combined form in nature, but once isolated artificially, the formation of an oxide layer stabilizes the free metal somewhat against further oxidation.\",\n      \"symbol\": \"V\",\n      \"xpos\": 5,\n      \"ypos\": 4,\n      \"shells\": [\n        2,\n        8,\n        11,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d3\",\n      \"electron_configuration_semantic\": \"[Ar] 3d3 4s2\",\n      \"electron_affinity\": 50.911,\n      \"electronegativity_pauling\": 1.63,\n      \"ionization_energies\": [\n        650.9,\n        1414,\n        2830,\n        4507,\n        6298.7,\n        12363,\n        14530,\n        16730,\n        19860,\n        22240,\n        24670,\n        29730,\n        32446,\n        86450,\n        94170,\n        102300,\n        112700,\n        121600,\n        130700,\n        143400,\n        151440,\n        661050,\n        699144\n      ],\n      \"cpk-hex\": \"a6a6ab\"\n    },\n    {\n      \"name\": \"Chromium\",\n      \"appearance\": \"silvery metallic\",\n      \"atomic_mass\": 51.99616,\n      \"boil\": 2944,\n      \"category\": \"transition metal\",\n      \"color\": null,\n      \"density\": 7.19,\n      \"discovered_by\": \"Louis Nicolas Vauquelin\",\n      \"melt\": 2180,\n      \"molar_heat\": 23.35,\n      \"named_by\": null,\n      \"number\": 24,\n      \"period\": 4,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Chromium\",\n      \"spectral_img\": null,\n      \"summary\": \"Chromium is a chemical element with symbol Cr and atomic number 24. It is the first element in Group 6. It is a steely-gray, lustrous, hard and brittle metal which takes a high polish, resists tarnishing, and has a high melting point.\",\n      \"symbol\": \"Cr\",\n      \"xpos\": 6,\n      \"ypos\": 4,\n      \"shells\": [\n        2,\n        8,\n        13,\n        1\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s1 3d5\",\n      \"electron_configuration_semantic\": \"[Ar] 3d5 4s1\",\n      \"electron_affinity\": 65.21,\n      \"electronegativity_pauling\": 1.66,\n      \"ionization_energies\": [\n        652.9,\n        1590.6,\n        2987,\n        4743,\n        6702,\n        8744.9,\n        15455,\n        17820,\n        20190,\n        23580,\n        26130,\n        28750,\n        34230,\n        37066,\n        97510,\n        105800,\n        114300,\n        125300,\n        134700,\n        144300,\n        157700,\n        166090,\n        721870,\n        761733\n      ],\n      \"cpk-hex\": \"8a99c7\"\n    },\n    {\n      \"name\": \"Manganese\",\n      \"appearance\": \"silvery metallic\",\n      \"atomic_mass\": 54.9380443,\n      \"boil\": 2334,\n      \"category\": \"transition metal\",\n      \"color\": null,\n      \"density\": 7.21,\n      \"discovered_by\": \"Torbern Olof Bergman\",\n      \"melt\": 1519,\n      \"molar_heat\": 26.32,\n      \"named_by\": null,\n      \"number\": 25,\n      \"period\": 4,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Manganese\",\n      \"spectral_img\": null,\n      \"summary\": \"Manganese is a chemical element with symbol Mn and atomic number 25. It is not found as a free element in nature; it is often found in combination with iron, and in many minerals. Manganese is a metal with important industrial metal alloy uses, particularly in stainless steels.\",\n      \"symbol\": \"Mn\",\n      \"xpos\": 7,\n      \"ypos\": 4,\n      \"shells\": [\n        2,\n        8,\n        13,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d5\",\n      \"electron_configuration_semantic\": \"[Ar] 3d5 4s2\",\n      \"electron_affinity\": -50,\n      \"electronegativity_pauling\": 1.55,\n      \"ionization_energies\": [\n        717.3,\n        1509,\n        3248,\n        4940,\n        6990,\n        9220,\n        11500,\n        18770,\n        21400,\n        23960,\n        27590,\n        30330,\n        33150,\n        38880,\n        41987,\n        109480,\n        118100,\n        127100,\n        138600,\n        148500,\n        158600,\n        172500,\n        181380,\n        785450,\n        827067\n      ],\n      \"cpk-hex\": \"9c7ac7\"\n    },\n    {\n      \"name\": \"Iron\",\n      \"appearance\": \"lustrous metallic with a grayish tinge\",\n      \"atomic_mass\": 55.8452,\n      \"boil\": 3134,\n      \"category\": \"transition metal\",\n      \"color\": null,\n      \"density\": 7.874,\n      \"discovered_by\": \"5000 BC\",\n      \"melt\": 1811,\n      \"molar_heat\": 25.1,\n      \"named_by\": null,\n      \"number\": 26,\n      \"period\": 4,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Iron\",\n      \"spectral_img\": \"https://en.wikipedia.org/wiki/File:Iron_Spectrum.jpg\",\n      \"summary\": \"Iron is a chemical element with symbol Fe (from Latin:ferrum) and atomic number 26. It is a metal in the first transition series. It is by mass the most common element on Earth, forming much of Earth's outer and inner core.\",\n      \"symbol\": \"Fe\",\n      \"xpos\": 8,\n      \"ypos\": 4,\n      \"shells\": [\n        2,\n        8,\n        14,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d6\",\n      \"electron_configuration_semantic\": \"[Ar] 3d6 4s2\",\n      \"electron_affinity\": 14.785,\n      \"electronegativity_pauling\": 1.83,\n      \"ionization_energies\": [\n        762.5,\n        1561.9,\n        2957,\n        5290,\n        7240,\n        9560,\n        12060,\n        14580,\n        22540,\n        25290,\n        28000,\n        31920,\n        34830,\n        37840,\n        44100,\n        47206,\n        122200,\n        131000,\n        140500,\n        152600,\n        163000,\n        173600,\n        188100,\n        195200,\n        851800,\n        895161\n      ],\n      \"cpk-hex\": \"e06633\"\n    },\n    {\n      \"name\": \"Cobalt\",\n      \"appearance\": \"hard lustrous gray metal\",\n      \"atomic_mass\": 58.9331944,\n      \"boil\": 3200,\n      \"category\": \"transition metal\",\n      \"color\": \"metallic gray\",\n      \"density\": 8.9,\n      \"discovered_by\": \"Georg Brandt\",\n      \"melt\": 1768,\n      \"molar_heat\": 24.81,\n      \"named_by\": null,\n      \"number\": 27,\n      \"period\": 4,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Cobalt\",\n      \"spectral_img\": null,\n      \"summary\": \"Cobalt is a chemical element with symbol Co and atomic number 27. Like nickel, cobalt in the Earth's crust is found only in chemically combined form, save for small deposits found in alloys of natural meteoric iron. The free element, produced by reductive smelting, is a hard, lustrous, silver-gray metal.\",\n      \"symbol\": \"Co\",\n      \"xpos\": 9,\n      \"ypos\": 4,\n      \"shells\": [\n        2,\n        8,\n        15,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d7\",\n      \"electron_configuration_semantic\": \"[Ar] 3d7 4s2\",\n      \"electron_affinity\": 63.898,\n      \"electronegativity_pauling\": 1.88,\n      \"ionization_energies\": [\n        760.4,\n        1648,\n        3232,\n        4950,\n        7670,\n        9840,\n        12440,\n        15230,\n        17959,\n        26570,\n        29400,\n        32400,\n        36600,\n        39700,\n        42800,\n        49396,\n        52737,\n        134810,\n        145170,\n        154700,\n        167400,\n        178100,\n        189300,\n        204500,\n        214100,\n        920870,\n        966023\n      ],\n      \"cpk-hex\": \"f090a0\"\n    },\n    {\n      \"name\": \"Nickel\",\n      \"appearance\": \"lustrous, metallic, and silver with a gold tinge\",\n      \"atomic_mass\": 58.69344,\n      \"boil\": 3003,\n      \"category\": \"transition metal\",\n      \"color\": null,\n      \"density\": 8.908,\n      \"discovered_by\": \"Axel Fredrik Cronstedt\",\n      \"melt\": 1728,\n      \"molar_heat\": 26.07,\n      \"named_by\": null,\n      \"number\": 28,\n      \"period\": 4,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Nickel\",\n      \"spectral_img\": null,\n      \"summary\": \"Nickel is a chemical element with symbol Ni and atomic number 28. It is a silvery-white lustrous metal with a slight golden tinge. Nickel belongs to the transition metals and is hard and ductile.\",\n      \"symbol\": \"Ni\",\n      \"xpos\": 10,\n      \"ypos\": 4,\n      \"shells\": [\n        2,\n        8,\n        16,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d8\",\n      \"electron_configuration_semantic\": \"[Ar] 3d8 4s2\",\n      \"electron_affinity\": 111.65,\n      \"electronegativity_pauling\": 1.91,\n      \"ionization_energies\": [\n        737.1,\n        1753,\n        3395,\n        5300,\n        7339,\n        10400,\n        12800,\n        15600,\n        18600,\n        21670,\n        30970,\n        34000,\n        37100,\n        41500,\n        44800,\n        48100,\n        55101,\n        58570,\n        148700,\n        159000,\n        169400,\n        182700,\n        194000,\n        205600,\n        221400,\n        231490,\n        992718,\n        1039668\n      ],\n      \"cpk-hex\": \"50d050\"\n    },\n    {\n      \"name\": \"Copper\",\n      \"appearance\": \"red-orange metallic luster\",\n      \"atomic_mass\": 63.5463,\n      \"boil\": 2835,\n      \"category\": \"transition metal\",\n      \"color\": null,\n      \"density\": 8.96,\n      \"discovered_by\": \"Middle East\",\n      \"melt\": 1357.77,\n      \"molar_heat\": 24.44,\n      \"named_by\": null,\n      \"number\": 29,\n      \"period\": 4,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Copper\",\n      \"spectral_img\": null,\n      \"summary\": \"Copper is a chemical element with symbol Cu (from Latin:cuprum) and atomic number 29. It is a soft, malleable and ductile metal with very high thermal and electrical conductivity. A freshly exposed surface of pure copper has a reddish-orange color.\",\n      \"symbol\": \"Cu\",\n      \"xpos\": 11,\n      \"ypos\": 4,\n      \"shells\": [\n        2,\n        8,\n        18,\n        1\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s1 3d10\",\n      \"electron_configuration_semantic\": \"[Ar] 3d10 4s1\",\n      \"electron_affinity\": 119.235,\n      \"electronegativity_pauling\": 1.9,\n      \"ionization_energies\": [\n        745.5,\n        1957.9,\n        3555,\n        5536,\n        7700,\n        9900,\n        13400,\n        16000,\n        19200,\n        22400,\n        25600,\n        35600,\n        38700,\n        42000,\n        46700,\n        50200,\n        53700,\n        61100,\n        64702,\n        163700,\n        174100,\n        184900,\n        198800,\n        210500,\n        222700,\n        239100,\n        249660,\n        1067358,\n        1116105\n      ],\n      \"cpk-hex\": \"c88033\"\n    },\n    {\n      \"name\": \"Zinc\",\n      \"appearance\": \"silver-gray\",\n      \"atomic_mass\": 65.382,\n      \"boil\": 1180,\n      \"category\": \"transition metal\",\n      \"color\": null,\n      \"density\": 7.14,\n      \"discovered_by\": \"India\",\n      \"melt\": 692.68,\n      \"molar_heat\": 25.47,\n      \"named_by\": null,\n      \"number\": 30,\n      \"period\": 4,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Zinc\",\n      \"spectral_img\": null,\n      \"summary\": \"Zinc, in commerce also spelter, is a chemical element with symbol Zn and atomic number 30. It is the first element of group 12 of the periodic table. In some respects zinc is chemically similar to magnesium:its ion is of similar size and its only common oxidation state is +2.\",\n      \"symbol\": \"Zn\",\n      \"xpos\": 12,\n      \"ypos\": 4,\n      \"shells\": [\n        2,\n        8,\n        18,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10\",\n      \"electron_configuration_semantic\": \"[Ar] 3d10 4s2\",\n      \"electron_affinity\": -58,\n      \"electronegativity_pauling\": 1.65,\n      \"ionization_energies\": [\n        906.4,\n        1733.3,\n        3833,\n        5731,\n        7970,\n        10400,\n        12900,\n        16800,\n        19600,\n        23000,\n        26400,\n        29990,\n        40490,\n        43800,\n        47300,\n        52300,\n        55900,\n        59700,\n        67300,\n        71200,\n        179100\n      ],\n      \"cpk-hex\": \"7d80b0\"\n    },\n    {\n      \"name\": \"Gallium\",\n      \"appearance\": \"silver-white\",\n      \"atomic_mass\": 69.7231,\n      \"boil\": 2673,\n      \"category\": \"post-transition metal\",\n      \"color\": null,\n      \"density\": 5.91,\n      \"discovered_by\": \"Lecoq de Boisbaudran\",\n      \"melt\": 302.9146,\n      \"molar_heat\": 25.86,\n      \"named_by\": null,\n      \"number\": 31,\n      \"period\": 4,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Gallium\",\n      \"spectral_img\": null,\n      \"summary\": \"Gallium is a chemical element with symbol Ga and atomic number 31. Elemental gallium does not occur in free form in nature, but as the gallium(III) compounds that are in trace amounts in zinc ores and in bauxite. Gallium is a soft, silvery metal, and elemental gallium is a brittle solid at low temperatures, and melts at 29.76 °C (85.57 °F) (slightly above room temperature).\",\n      \"symbol\": \"Ga\",\n      \"xpos\": 13,\n      \"ypos\": 4,\n      \"shells\": [\n        2,\n        8,\n        18,\n        3\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p1\",\n      \"electron_configuration_semantic\": \"[Ar] 3d10 4s2 4p1\",\n      \"electron_affinity\": 41,\n      \"electronegativity_pauling\": 1.81,\n      \"ionization_energies\": [\n        578.8,\n        1979.3,\n        2963,\n        6180\n      ],\n      \"cpk-hex\": \"c28f8f\"\n    },\n    {\n      \"name\": \"Germanium\",\n      \"appearance\": \"grayish-white\",\n      \"atomic_mass\": 72.6308,\n      \"boil\": 3106,\n      \"category\": \"metalloid\",\n      \"color\": null,\n      \"density\": 5.323,\n      \"discovered_by\": \"Clemens Winkler\",\n      \"melt\": 1211.4,\n      \"molar_heat\": 23.222,\n      \"named_by\": null,\n      \"number\": 32,\n      \"period\": 4,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Germanium\",\n      \"spectral_img\": null,\n      \"summary\": \"Germanium is a chemical element with symbol Ge and atomic number 32. It is a lustrous, hard, grayish-white metalloid in the carbon group, chemically similar to its group neighbors tin and silicon. Purified germanium is a semiconductor, with an appearance most similar to elemental silicon.\",\n      \"symbol\": \"Ge\",\n      \"xpos\": 14,\n      \"ypos\": 4,\n      \"shells\": [\n        2,\n        8,\n        18,\n        4\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p2\",\n      \"electron_configuration_semantic\": \"[Ar] 3d10 4s2 4p2\",\n      \"electron_affinity\": 118.9352,\n      \"electronegativity_pauling\": 2.01,\n      \"ionization_energies\": [\n        762,\n        1537.5,\n        3302.1,\n        4411,\n        9020\n      ],\n      \"cpk-hex\": \"668f8f\"\n    },\n    {\n      \"name\": \"Arsenic\",\n      \"appearance\": \"metallic grey\",\n      \"atomic_mass\": 74.9215956,\n      \"boil\": null,\n      \"category\": \"metalloid\",\n      \"color\": null,\n      \"density\": 5.727,\n      \"discovered_by\": \"Bronze Age\",\n      \"melt\": null,\n      \"molar_heat\": 24.64,\n      \"named_by\": null,\n      \"number\": 33,\n      \"period\": 4,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Arsenic\",\n      \"spectral_img\": null,\n      \"summary\": \"Arsenic is a chemical element with symbol As and atomic number 33. Arsenic occurs in many minerals, usually in conjunction with sulfur and metals, and also as a pure elemental crystal. Arsenic is a metalloid.\",\n      \"symbol\": \"As\",\n      \"xpos\": 15,\n      \"ypos\": 4,\n      \"shells\": [\n        2,\n        8,\n        18,\n        5\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p3\",\n      \"electron_configuration_semantic\": \"[Ar] 3d10 4s2 4p3\",\n      \"electron_affinity\": 77.65,\n      \"electronegativity_pauling\": 2.18,\n      \"ionization_energies\": [\n        947,\n        1798,\n        2735,\n        4837,\n        6043,\n        12310\n      ],\n      \"cpk-hex\": \"bd80e3\"\n    },\n    {\n      \"name\": \"Selenium\",\n      \"appearance\": \"black, red, and gray (not pictured) allotropes\",\n      \"atomic_mass\": 78.9718,\n      \"boil\": 958,\n      \"category\": \"polyatomic nonmetal\",\n      \"color\": null,\n      \"density\": 4.81,\n      \"discovered_by\": \"Jöns Jakob Berzelius\",\n      \"melt\": 494,\n      \"molar_heat\": 25.363,\n      \"named_by\": null,\n      \"number\": 34,\n      \"period\": 4,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Selenium\",\n      \"spectral_img\": null,\n      \"summary\": \"Selenium is a chemical element with symbol Se and atomic number 34. It is a nonmetal with properties that are intermediate between those of its periodic table column-adjacent chalcogen elements sulfur and tellurium. It rarely occurs in its elemental state in nature, or as pure ore compounds.\",\n      \"symbol\": \"Se\",\n      \"xpos\": 16,\n      \"ypos\": 4,\n      \"shells\": [\n        2,\n        8,\n        18,\n        6\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p4\",\n      \"electron_configuration_semantic\": \"[Ar] 3d10 4s2 4p4\",\n      \"electron_affinity\": 194.9587,\n      \"electronegativity_pauling\": 2.55,\n      \"ionization_energies\": [\n        941,\n        2045,\n        2973.7,\n        4144,\n        6590,\n        7880,\n        14990\n      ],\n      \"cpk-hex\": \"ffa100\"\n    },\n    {\n      \"name\": \"Bromine\",\n      \"appearance\": null,\n      \"atomic_mass\": 79.904,\n      \"boil\": 332,\n      \"category\": \"diatomic nonmetal\",\n      \"color\": null,\n      \"density\": 3.1028,\n      \"discovered_by\": \"Antoine Jérôme Balard\",\n      \"melt\": 265.8,\n      \"molar_heat\": null,\n      \"named_by\": null,\n      \"number\": 35,\n      \"period\": 4,\n      \"phase\": \"Liquid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Bromine\",\n      \"spectral_img\": null,\n      \"summary\": \"Bromine (from Ancient Greek:βρῶμος, brómos, meaning \\\"stench\\\") is a chemical element with symbol Br, and atomic number 35. It is a halogen. The element was isolated independently by two chemists, Carl Jacob Löwig and Antoine Jerome Balard, in 1825–1826.\",\n      \"symbol\": \"Br\",\n      \"xpos\": 17,\n      \"ypos\": 4,\n      \"shells\": [\n        2,\n        8,\n        18,\n        7\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p5\",\n      \"electron_configuration_semantic\": \"[Ar] 3d10 4s2 4p5\",\n      \"electron_affinity\": 324.537,\n      \"electronegativity_pauling\": 2.96,\n      \"ionization_energies\": [\n        1139.9,\n        2103,\n        3470,\n        4560,\n        5760,\n        8550,\n        9940,\n        18600\n      ],\n      \"cpk-hex\": \"a62929\"\n    },\n    {\n      \"name\": \"Krypton\",\n      \"appearance\": \"colorless gas, exhibiting a whitish glow in a high electric field\",\n      \"atomic_mass\": 83.7982,\n      \"boil\": 119.93,\n      \"category\": \"noble gas\",\n      \"color\": null,\n      \"density\": 3.749,\n      \"discovered_by\": \"William Ramsay\",\n      \"melt\": 115.78,\n      \"molar_heat\": null,\n      \"named_by\": null,\n      \"number\": 36,\n      \"period\": 4,\n      \"phase\": \"Gas\",\n      \"source\": \"https://en.wikipedia.org/wiki/Krypton\",\n      \"spectral_img\": \"https://en.wikipedia.org/wiki/File:Krypton_Spectrum.jpg\",\n      \"summary\": \"Krypton (from Greek:κρυπτός kryptos \\\"the hidden one\\\") is a chemical element with symbol Kr and atomic number 36. It is a member of group 18 (noble gases) elements. A colorless, odorless, tasteless noble gas, krypton occurs in trace amounts in the atmosphere, is isolated by fractionally distilling liquefied air, and is often used with other rare gases in fluorescent lamps.\",\n      \"symbol\": \"Kr\",\n      \"xpos\": 18,\n      \"ypos\": 4,\n      \"shells\": [\n        2,\n        8,\n        18,\n        8\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6\",\n      \"electron_configuration_semantic\": \"[Ar] 3d10 4s2 4p6\",\n      \"electron_affinity\": -96,\n      \"electronegativity_pauling\": 3,\n      \"ionization_energies\": [\n        1350.8,\n        2350.4,\n        3565,\n        5070,\n        6240,\n        7570,\n        10710,\n        12138,\n        22274,\n        25880,\n        29700,\n        33800,\n        37700,\n        43100,\n        47500,\n        52200,\n        57100,\n        61800,\n        75800,\n        80400,\n        85300,\n        90400,\n        96300,\n        101400,\n        111100,\n        116290,\n        282500,\n        296200,\n        311400,\n        326200\n      ],\n      \"cpk-hex\": \"5cb8d1\"\n    },\n    {\n      \"name\": \"Rubidium\",\n      \"appearance\": \"grey white\",\n      \"atomic_mass\": 85.46783,\n      \"boil\": 961,\n      \"category\": \"alkali metal\",\n      \"color\": null,\n      \"density\": 1.532,\n      \"discovered_by\": \"Robert Bunsen\",\n      \"melt\": 312.45,\n      \"molar_heat\": 31.06,\n      \"named_by\": null,\n      \"number\": 37,\n      \"period\": 5,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Rubidium\",\n      \"spectral_img\": null,\n      \"summary\": \"Rubidium is a chemical element with symbol Rb and atomic number 37. Rubidium is a soft, silvery-white metallic element of the alkali metal group, with an atomic mass of 85.4678. Elemental rubidium is highly reactive, with properties similar to those of other alkali metals, such as very rapid oxidation in air.\",\n      \"symbol\": \"Rb\",\n      \"xpos\": 1,\n      \"ypos\": 5,\n      \"shells\": [\n        2,\n        8,\n        18,\n        8,\n        1\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s1\",\n      \"electron_configuration_semantic\": \"[Kr] 5s1\",\n      \"electron_affinity\": 46.884,\n      \"electronegativity_pauling\": 0.82,\n      \"ionization_energies\": [\n        403,\n        2633,\n        3860,\n        5080,\n        6850,\n        8140,\n        9570,\n        13120,\n        14500,\n        26740\n      ],\n      \"cpk-hex\": \"702eb0\"\n    },\n    {\n      \"name\": \"Strontium\",\n      \"appearance\": null,\n      \"atomic_mass\": 87.621,\n      \"boil\": 1650,\n      \"category\": \"alkaline earth metal\",\n      \"color\": null,\n      \"density\": 2.64,\n      \"discovered_by\": \"William Cruickshank (chemist)\",\n      \"melt\": 1050,\n      \"molar_heat\": 26.4,\n      \"named_by\": null,\n      \"number\": 38,\n      \"period\": 5,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Strontium\",\n      \"spectral_img\": null,\n      \"summary\": \"Strontium is a chemical element with symbol Sr and atomic number 38. An alkaline earth metal, strontium is a soft silver-white or yellowish metallic element that is highly reactive chemically. The metal turns yellow when it is exposed to air.\",\n      \"symbol\": \"Sr\",\n      \"xpos\": 2,\n      \"ypos\": 5,\n      \"shells\": [\n        2,\n        8,\n        18,\n        8,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2\",\n      \"electron_configuration_semantic\": \"[Kr] 5s2\",\n      \"electron_affinity\": 5.023,\n      \"electronegativity_pauling\": 0.95,\n      \"ionization_energies\": [\n        549.5,\n        1064.2,\n        4138,\n        5500,\n        6910,\n        8760,\n        10230,\n        11800,\n        15600,\n        17100,\n        31270\n      ],\n      \"cpk-hex\": \"00ff00\"\n    },\n    {\n      \"name\": \"Yttrium\",\n      \"appearance\": \"silvery white\",\n      \"atomic_mass\": 88.905842,\n      \"boil\": 3203,\n      \"category\": \"transition metal\",\n      \"color\": null,\n      \"density\": 4.472,\n      \"discovered_by\": \"Johan Gadolin\",\n      \"melt\": 1799,\n      \"molar_heat\": 26.53,\n      \"named_by\": null,\n      \"number\": 39,\n      \"period\": 5,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Yttrium\",\n      \"spectral_img\": null,\n      \"summary\": \"Yttrium is a chemical element with symbol Y and atomic number 39. It is a silvery-metallic transition metal chemically similar to the lanthanides and it has often been classified as a \\\"rare earth element\\\". Yttrium is almost always found combined with the lanthanides in rare earth minerals and is never found in nature as a free element.\",\n      \"symbol\": \"Y\",\n      \"xpos\": 3,\n      \"ypos\": 5,\n      \"shells\": [\n        2,\n        8,\n        18,\n        9,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d1\",\n      \"electron_configuration_semantic\": \"[Kr] 4d1 5s2\",\n      \"electron_affinity\": 29.6,\n      \"electronegativity_pauling\": 1.22,\n      \"ionization_energies\": [\n        600,\n        1180,\n        1980,\n        5847,\n        7430,\n        8970,\n        11190,\n        12450,\n        14110,\n        18400,\n        19900,\n        36090\n      ],\n      \"cpk-hex\": \"94ffff\"\n    },\n    {\n      \"name\": \"Zirconium\",\n      \"appearance\": \"silvery white\",\n      \"atomic_mass\": 91.2242,\n      \"boil\": 4650,\n      \"category\": \"transition metal\",\n      \"color\": null,\n      \"density\": 6.52,\n      \"discovered_by\": \"Martin Heinrich Klaproth\",\n      \"melt\": 2128,\n      \"molar_heat\": 25.36,\n      \"named_by\": null,\n      \"number\": 40,\n      \"period\": 5,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Zirconium\",\n      \"spectral_img\": null,\n      \"summary\": \"Zirconium is a chemical element with symbol Zr and atomic number 40. The name of zirconium is taken from the name of the mineral zircon, the most important source of zirconium. The word zircon comes from the Persian word zargun زرگون, meaning \\\"gold-colored\\\".\",\n      \"symbol\": \"Zr\",\n      \"xpos\": 4,\n      \"ypos\": 5,\n      \"shells\": [\n        2,\n        8,\n        18,\n        10,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d2\",\n      \"electron_configuration_semantic\": \"[Kr] 4d2 5s2\",\n      \"electron_affinity\": 41.806,\n      \"electronegativity_pauling\": 1.33,\n      \"ionization_energies\": [\n        640.1,\n        1270,\n        2218,\n        3313,\n        7752,\n        9500\n      ],\n      \"cpk-hex\": \"94e0e0\"\n    },\n    {\n      \"name\": \"Niobium\",\n      \"appearance\": \"gray metallic, bluish when oxidized\",\n      \"atomic_mass\": 92.906372,\n      \"boil\": 5017,\n      \"category\": \"transition metal\",\n      \"color\": null,\n      \"density\": 8.57,\n      \"discovered_by\": \"Charles Hatchett\",\n      \"melt\": 2750,\n      \"molar_heat\": 24.6,\n      \"named_by\": null,\n      \"number\": 41,\n      \"period\": 5,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Niobium\",\n      \"spectral_img\": null,\n      \"summary\": \"Niobium, formerly columbium, is a chemical element with symbol Nb (formerly Cb) and atomic number 41. It is a soft, grey, ductile transition metal, which is often found in the pyrochlore mineral, the main commercial source for niobium, and columbite. The name comes from Greek mythology:Niobe, daughter of Tantalus since it is so similar to tantalum.\",\n      \"symbol\": \"Nb\",\n      \"xpos\": 5,\n      \"ypos\": 5,\n      \"shells\": [\n        2,\n        8,\n        18,\n        12,\n        1\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s1 4d4\",\n      \"electron_configuration_semantic\": \"[Kr] 4d4 5s1\",\n      \"electron_affinity\": 88.516,\n      \"electronegativity_pauling\": 1.6,\n      \"ionization_energies\": [\n        652.1,\n        1380,\n        2416,\n        3700,\n        4877,\n        9847,\n        12100\n      ],\n      \"cpk-hex\": \"73c2c9\"\n    },\n    {\n      \"name\": \"Molybdenum\",\n      \"appearance\": \"gray metallic\",\n      \"atomic_mass\": 95.951,\n      \"boil\": 4912,\n      \"category\": \"transition metal\",\n      \"color\": null,\n      \"density\": 10.28,\n      \"discovered_by\": \"Carl Wilhelm Scheele\",\n      \"melt\": 2896,\n      \"molar_heat\": 24.06,\n      \"named_by\": null,\n      \"number\": 42,\n      \"period\": 5,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Molybdenum\",\n      \"spectral_img\": null,\n      \"summary\": \"Molybdenum is a chemical element with symbol Mo and atomic number 42. The name is from Neo-Latin molybdaenum, from Ancient Greek Μόλυβδος molybdos, meaning lead, since its ores were confused with lead ores. Molybdenum minerals have been known throughout history, but the element was discovered (in the sense of differentiating it as a new entity from the mineral salts of other metals) in 1778 by Carl Wilhelm Scheele.\",\n      \"symbol\": \"Mo\",\n      \"xpos\": 6,\n      \"ypos\": 5,\n      \"shells\": [\n        2,\n        8,\n        18,\n        13,\n        1\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s1 4d5\",\n      \"electron_configuration_semantic\": \"[Kr] 4d5 5s1\",\n      \"electron_affinity\": 72.1,\n      \"electronegativity_pauling\": 2.16,\n      \"ionization_energies\": [\n        684.3,\n        1560,\n        2618,\n        4480,\n        5257,\n        6640.8,\n        12125,\n        13860,\n        15835,\n        17980,\n        20190,\n        22219,\n        26930,\n        29196,\n        52490,\n        55000,\n        61400,\n        67700,\n        74000,\n        80400,\n        87000,\n        93400,\n        98420,\n        104400,\n        121900,\n        127700,\n        133800,\n        139800,\n        148100,\n        154500\n      ],\n      \"cpk-hex\": \"54b5b5\"\n    },\n    {\n      \"name\": \"Technetium\",\n      \"appearance\": \"shiny gray metal\",\n      \"atomic_mass\": 98,\n      \"boil\": 4538,\n      \"category\": \"transition metal\",\n      \"color\": null,\n      \"density\": 11,\n      \"discovered_by\": \"Emilio Segrè\",\n      \"melt\": 2430,\n      \"molar_heat\": 24.27,\n      \"named_by\": null,\n      \"number\": 43,\n      \"period\": 5,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Technetium\",\n      \"spectral_img\": null,\n      \"summary\": \"Technetium (/tɛkˈniːʃiəm/) is a chemical element with symbol Tc and atomic number 43. It is the element with the lowest atomic number in the periodic table that has no stable isotopes:every form of it is radioactive. Nearly all technetium is produced synthetically, and only minute amounts are found in nature.\",\n      \"symbol\": \"Tc\",\n      \"xpos\": 7,\n      \"ypos\": 5,\n      \"shells\": [\n        2,\n        8,\n        18,\n        13,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d5\",\n      \"electron_configuration_semantic\": \"[Kr] 4d5 5s2\",\n      \"electron_affinity\": 53,\n      \"electronegativity_pauling\": 1.9,\n      \"ionization_energies\": [\n        702,\n        1470,\n        2850\n      ],\n      \"cpk-hex\": \"3b9e9e\"\n    },\n    {\n      \"name\": \"Ruthenium\",\n      \"appearance\": \"silvery white metallic\",\n      \"atomic_mass\": 101.072,\n      \"boil\": 4423,\n      \"category\": \"transition metal\",\n      \"color\": null,\n      \"density\": 12.45,\n      \"discovered_by\": \"Karl Ernst Claus\",\n      \"melt\": 2607,\n      \"molar_heat\": 24.06,\n      \"named_by\": null,\n      \"number\": 44,\n      \"period\": 5,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Ruthenium\",\n      \"spectral_img\": null,\n      \"summary\": \"Ruthenium is a chemical element with symbol Ru and atomic number 44. It is a rare transition metal belonging to the platinum group of the periodic table. Like the other metals of the platinum group, ruthenium is inert to most other chemicals.\",\n      \"symbol\": \"Ru\",\n      \"xpos\": 8,\n      \"ypos\": 5,\n      \"shells\": [\n        2,\n        8,\n        18,\n        15,\n        1\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s1 4d7\",\n      \"electron_configuration_semantic\": \"[Kr] 4d7 5s1\",\n      \"electron_affinity\": 100.96,\n      \"electronegativity_pauling\": 2.2,\n      \"ionization_energies\": [\n        710.2,\n        1620,\n        2747\n      ],\n      \"cpk-hex\": \"248f8f\"\n    },\n    {\n      \"name\": \"Rhodium\",\n      \"appearance\": \"silvery white metallic\",\n      \"atomic_mass\": 102.905502,\n      \"boil\": 3968,\n      \"category\": \"transition metal\",\n      \"color\": null,\n      \"density\": 12.41,\n      \"discovered_by\": \"William Hyde Wollaston\",\n      \"melt\": 2237,\n      \"molar_heat\": 24.98,\n      \"named_by\": null,\n      \"number\": 45,\n      \"period\": 5,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Rhodium\",\n      \"spectral_img\": null,\n      \"summary\": \"Rhodium is a chemical element with symbol Rh and atomic number 45. It is a rare, silvery-white, hard, and chemically inert transition metal. It is a member of the platinum group.\",\n      \"symbol\": \"Rh\",\n      \"xpos\": 9,\n      \"ypos\": 5,\n      \"shells\": [\n        2,\n        8,\n        18,\n        16,\n        1\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s1 4d8\",\n      \"electron_configuration_semantic\": \"[Kr] 4d8 5s1\",\n      \"electron_affinity\": 110.27,\n      \"electronegativity_pauling\": 2.28,\n      \"ionization_energies\": [\n        719.7,\n        1740,\n        2997\n      ],\n      \"cpk-hex\": \"0a7d8c\"\n    },\n    {\n      \"name\": \"Palladium\",\n      \"appearance\": \"silvery white\",\n      \"atomic_mass\": 106.421,\n      \"boil\": 3236,\n      \"category\": \"transition metal\",\n      \"color\": null,\n      \"density\": 12.023,\n      \"discovered_by\": \"William Hyde Wollaston\",\n      \"melt\": 1828.05,\n      \"molar_heat\": 25.98,\n      \"named_by\": null,\n      \"number\": 46,\n      \"period\": 5,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Palladium\",\n      \"spectral_img\": null,\n      \"summary\": \"Palladium is a chemical element with symbol Pd and atomic number 46. It is a rare and lustrous silvery-white metal discovered in 1803 by William Hyde Wollaston. He named it after the asteroid Pallas, which was itself named after the epithet of the Greek goddess Athena, acquired by her when she slew Pallas.\",\n      \"symbol\": \"Pd\",\n      \"xpos\": 10,\n      \"ypos\": 5,\n      \"shells\": [\n        2,\n        8,\n        18,\n        18\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 4d10\",\n      \"electron_configuration_semantic\": \"[Kr] 4d10\",\n      \"electron_affinity\": 54.24,\n      \"electronegativity_pauling\": 2.2,\n      \"ionization_energies\": [\n        804.4,\n        1870,\n        3177\n      ],\n      \"cpk-hex\": \"006985\"\n    },\n    {\n      \"name\": \"Silver\",\n      \"appearance\": \"lustrous white metal\",\n      \"atomic_mass\": 107.86822,\n      \"boil\": 2435,\n      \"category\": \"transition metal\",\n      \"color\": null,\n      \"density\": 10.49,\n      \"discovered_by\": \"unknown, before 5000 BC\",\n      \"melt\": 1234.93,\n      \"molar_heat\": 25.35,\n      \"named_by\": null,\n      \"number\": 47,\n      \"period\": 5,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Silver\",\n      \"spectral_img\": null,\n      \"summary\": \"Silver is a chemical element with symbol Ag (Greek:άργυρος árguros, Latin:argentum, both from the Indo-European root *h₂erǵ- for \\\"grey\\\" or \\\"shining\\\") and atomic number 47. A soft, white, lustrous transition metal, it possesses the highest electrical conductivity, thermal conductivity and reflectivity of any metal. The metal occurs naturally in its pure, free form (native silver), as an alloy with gold and other metals, and in minerals such as argentite and chlorargyrite.\",\n      \"symbol\": \"Ag\",\n      \"xpos\": 11,\n      \"ypos\": 5,\n      \"shells\": [\n        2,\n        8,\n        18,\n        18,\n        1\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s1 4d10\",\n      \"electron_configuration_semantic\": \"[Kr] 4d10 5s1\",\n      \"electron_affinity\": 125.862,\n      \"electronegativity_pauling\": 1.93,\n      \"ionization_energies\": [\n        731,\n        2070,\n        3361\n      ],\n      \"cpk-hex\": \"c0c0c0\"\n    },\n    {\n      \"name\": \"Cadmium\",\n      \"appearance\": \"silvery bluish-gray metallic\",\n      \"atomic_mass\": 112.4144,\n      \"boil\": 1040,\n      \"category\": \"transition metal\",\n      \"color\": null,\n      \"density\": 8.65,\n      \"discovered_by\": \"Karl Samuel Leberecht Hermann\",\n      \"melt\": 594.22,\n      \"molar_heat\": 26.02,\n      \"named_by\": \"Isotopes of cadmium\",\n      \"number\": 48,\n      \"period\": 5,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Cadmium\",\n      \"spectral_img\": null,\n      \"summary\": \"Cadmium is a chemical element with symbol Cd and atomic number 48. This soft, bluish-white metal is chemically similar to the two other stable metals in group 12, zinc and mercury. Like zinc, it prefers oxidation state +2 in most of its compounds and like mercury it shows a low melting point compared to transition metals.\",\n      \"symbol\": \"Cd\",\n      \"xpos\": 12,\n      \"ypos\": 5,\n      \"shells\": [\n        2,\n        8,\n        18,\n        18,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10\",\n      \"electron_configuration_semantic\": \"[Kr] 4d10 5s2\",\n      \"electron_affinity\": -68,\n      \"electronegativity_pauling\": 1.69,\n      \"ionization_energies\": [\n        867.8,\n        1631.4,\n        3616\n      ],\n      \"cpk-hex\": \"ffd98f\"\n    },\n    {\n      \"name\": \"Indium\",\n      \"appearance\": \"silvery lustrous gray\",\n      \"atomic_mass\": 114.8181,\n      \"boil\": 2345,\n      \"category\": \"post-transition metal\",\n      \"color\": null,\n      \"density\": 7.31,\n      \"discovered_by\": \"Ferdinand Reich\",\n      \"melt\": 429.7485,\n      \"molar_heat\": 26.74,\n      \"named_by\": null,\n      \"number\": 49,\n      \"period\": 5,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Indium\",\n      \"spectral_img\": null,\n      \"summary\": \"Indium is a chemical element with symbol In and atomic number 49. It is a post-transition metallic element that is rare in Earth's crust. The metal is very soft, malleable and easily fusible, with a melting point higher than sodium, but lower than lithium or tin.\",\n      \"symbol\": \"In\",\n      \"xpos\": 13,\n      \"ypos\": 5,\n      \"shells\": [\n        2,\n        8,\n        18,\n        18,\n        3\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p1\",\n      \"electron_configuration_semantic\": \"[Kr] 4d10 5s2 5p1\",\n      \"electron_affinity\": 37.043,\n      \"electronegativity_pauling\": 1.78,\n      \"ionization_energies\": [\n        558.3,\n        1820.7,\n        2704,\n        5210\n      ],\n      \"cpk-hex\": \"a67573\"\n    },\n    {\n      \"name\": \"Tin\",\n      \"appearance\": \"silvery-white (beta, β) or gray (alpha, α)\",\n      \"atomic_mass\": 118.7107,\n      \"boil\": 2875,\n      \"category\": \"post-transition metal\",\n      \"color\": null,\n      \"density\": 7.365,\n      \"discovered_by\": \"unknown, before 3500 BC\",\n      \"melt\": 505.08,\n      \"molar_heat\": 27.112,\n      \"named_by\": null,\n      \"number\": 50,\n      \"period\": 5,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Tin\",\n      \"spectral_img\": null,\n      \"summary\": \"Tin is a chemical element with the symbol Sn (for Latin:stannum) and atomic number 50. It is a main group metal in group 14 of the periodic table. Tin shows a chemical similarity to both neighboring group-14 elements, germanium and lead, and has two possible oxidation states, +2 and the slightly more stable +4.\",\n      \"symbol\": \"Sn\",\n      \"xpos\": 14,\n      \"ypos\": 5,\n      \"shells\": [\n        2,\n        8,\n        18,\n        18,\n        4\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p2\",\n      \"electron_configuration_semantic\": \"[Kr] 4d10 5s2 5p2\",\n      \"electron_affinity\": 107.2984,\n      \"electronegativity_pauling\": 1.96,\n      \"ionization_energies\": [\n        708.6,\n        1411.8,\n        2943,\n        3930.3,\n        7456\n      ],\n      \"cpk-hex\": \"668080\"\n    },\n    {\n      \"name\": \"Antimony\",\n      \"appearance\": \"silvery lustrous gray\",\n      \"atomic_mass\": 121.7601,\n      \"boil\": 1908,\n      \"category\": \"metalloid\",\n      \"color\": null,\n      \"density\": 6.697,\n      \"discovered_by\": \"unknown, before 3000 BC\",\n      \"melt\": 903.78,\n      \"molar_heat\": 25.23,\n      \"named_by\": null,\n      \"number\": 51,\n      \"period\": 5,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Antimony\",\n      \"spectral_img\": null,\n      \"summary\": \"Antimony is a chemical element with symbol Sb (from Latin:stibium) and atomic number 51. A lustrous gray metalloid, it is found in nature mainly as the sulfide mineral stibnite (Sb2S3). Antimony compounds have been known since ancient times and were used for cosmetics; metallic antimony was also known, but it was erroneously identified as lead upon its discovery.\",\n      \"symbol\": \"Sb\",\n      \"xpos\": 15,\n      \"ypos\": 5,\n      \"shells\": [\n        2,\n        8,\n        18,\n        18,\n        5\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p3\",\n      \"electron_configuration_semantic\": \"[Kr] 4d10 5s2 5p3\",\n      \"electron_affinity\": 101.059,\n      \"electronegativity_pauling\": 2.05,\n      \"ionization_energies\": [\n        834,\n        1594.9,\n        2440,\n        4260,\n        5400,\n        10400\n      ],\n      \"cpk-hex\": \"9e63b5\"\n    },\n    {\n      \"name\": \"Tellurium\",\n      \"appearance\": null,\n      \"atomic_mass\": 127.603,\n      \"boil\": 1261,\n      \"category\": \"metalloid\",\n      \"color\": null,\n      \"density\": 6.24,\n      \"discovered_by\": \"Franz-Joseph Müller von Reichenstein\",\n      \"melt\": 722.66,\n      \"molar_heat\": 25.73,\n      \"named_by\": null,\n      \"number\": 52,\n      \"period\": 5,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Tellurium\",\n      \"spectral_img\": null,\n      \"summary\": \"Tellurium is a chemical element with symbol Te and atomic number 52. It is a brittle, mildly toxic, rare, silver-white metalloid. Tellurium is chemically related to selenium and sulfur.\",\n      \"symbol\": \"Te\",\n      \"xpos\": 16,\n      \"ypos\": 5,\n      \"shells\": [\n        2,\n        8,\n        18,\n        18,\n        6\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p4\",\n      \"electron_configuration_semantic\": \"[Kr] 4d10 5s2 5p4\",\n      \"electron_affinity\": 190.161,\n      \"electronegativity_pauling\": 2.1,\n      \"ionization_energies\": [\n        869.3,\n        1790,\n        2698,\n        3610,\n        5668,\n        6820,\n        13200\n      ],\n      \"cpk-hex\": \"d47a00\"\n    },\n    {\n      \"name\": \"Iodine\",\n      \"appearance\": \"lustrous metallic gray, violet as a gas\",\n      \"atomic_mass\": 126.904473,\n      \"boil\": 457.4,\n      \"category\": \"diatomic nonmetal\",\n      \"color\": null,\n      \"density\": 4.933,\n      \"discovered_by\": \"Bernard Courtois\",\n      \"melt\": 386.85,\n      \"molar_heat\": null,\n      \"named_by\": null,\n      \"number\": 53,\n      \"period\": 5,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Iodine\",\n      \"spectral_img\": null,\n      \"summary\": \"Iodine is a chemical element with symbol I and atomic number 53. The name is from Greek ἰοειδής ioeidēs, meaning violet or purple, due to the color of iodine vapor. Iodine and its compounds are primarily used in nutrition, and industrially in the production of acetic acid and certain polymers.\",\n      \"symbol\": \"I\",\n      \"xpos\": 17,\n      \"ypos\": 5,\n      \"shells\": [\n        2,\n        8,\n        18,\n        18,\n        7\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p5\",\n      \"electron_configuration_semantic\": \"[Kr] 4d10 5s2 5p5\",\n      \"electron_affinity\": 295.1531,\n      \"electronegativity_pauling\": 2.66,\n      \"ionization_energies\": [\n        1008.4,\n        1845.9,\n        3180\n      ],\n      \"cpk-hex\": \"940094\"\n    },\n    {\n      \"name\": \"Xenon\",\n      \"appearance\": \"colorless gas, exhibiting a blue glow when placed in a high voltage electric field\",\n      \"atomic_mass\": 131.2936,\n      \"boil\": 165.051,\n      \"category\": \"noble gas\",\n      \"color\": null,\n      \"density\": 5.894,\n      \"discovered_by\": \"William Ramsay\",\n      \"melt\": 161.4,\n      \"molar_heat\": null,\n      \"named_by\": null,\n      \"number\": 54,\n      \"period\": 5,\n      \"phase\": \"Gas\",\n      \"source\": \"https://en.wikipedia.org/wiki/Xenon\",\n      \"spectral_img\": \"https://en.wikipedia.org/wiki/File:Xenon_Spectrum.jpg\",\n      \"summary\": \"Xenon is a chemical element with symbol Xe and atomic number 54. It is a colorless, dense, odorless noble gas, that occurs in the Earth's atmosphere in trace amounts. Although generally unreactive, xenon can undergo a few chemical reactions such as the formation of xenon hexafluoroplatinate, the first noble gas compound to be synthesized.\",\n      \"symbol\": \"Xe\",\n      \"xpos\": 18,\n      \"ypos\": 5,\n      \"shells\": [\n        2,\n        8,\n        18,\n        18,\n        8\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6\",\n      \"electron_configuration_semantic\": \"[Kr] 4d10 5s2 5p6\",\n      \"electron_affinity\": -77,\n      \"electronegativity_pauling\": 2.6,\n      \"ionization_energies\": [\n        1170.4,\n        2046.4,\n        3099.4\n      ],\n      \"cpk-hex\": \"429eb0\"\n    },\n    {\n      \"name\": \"Cesium\",\n      \"appearance\": \"silvery gold\",\n      \"atomic_mass\": 132.905451966,\n      \"boil\": 944,\n      \"category\": \"alkali metal\",\n      \"color\": null,\n      \"density\": 1.93,\n      \"discovered_by\": \"Robert Bunsen\",\n      \"melt\": 301.7,\n      \"molar_heat\": 32.21,\n      \"named_by\": null,\n      \"number\": 55,\n      \"period\": 6,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Cesium\",\n      \"spectral_img\": null,\n      \"summary\": \"Caesium or cesium is a chemical element with symbol Cs and atomic number 55. It is a soft, silvery-gold alkali metal with a melting point of 28 °C (82 °F), which makes it one of only five elemental metals that are liquid at or near room temperature. Caesium is an alkali metal and has physical and chemical properties similar to those of rubidium and potassium.\",\n      \"symbol\": \"Cs\",\n      \"xpos\": 1,\n      \"ypos\": 6,\n      \"shells\": [\n        2,\n        8,\n        18,\n        18,\n        8,\n        1\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s1\",\n      \"electron_configuration_semantic\": \"[Xe] 6s1\",\n      \"electron_affinity\": 45.505,\n      \"electronegativity_pauling\": 0.79,\n      \"ionization_energies\": [\n        375.7,\n        2234.3,\n        3400\n      ],\n      \"cpk-hex\": \"57178f\"\n    },\n    {\n      \"name\": \"Barium\",\n      \"appearance\": null,\n      \"atomic_mass\": 137.3277,\n      \"boil\": 2118,\n      \"category\": \"alkaline earth metal\",\n      \"color\": null,\n      \"density\": 3.51,\n      \"discovered_by\": \"Carl Wilhelm Scheele\",\n      \"melt\": 1000,\n      \"molar_heat\": 28.07,\n      \"named_by\": null,\n      \"number\": 56,\n      \"period\": 6,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Barium\",\n      \"spectral_img\": null,\n      \"summary\": \"Barium is a chemical element with symbol Ba and atomic number 56. It is the fifth element in Group 2, a soft silvery metallic alkaline earth metal. Because of its high chemical reactivity barium is never found in nature as a free element.\",\n      \"symbol\": \"Ba\",\n      \"xpos\": 2,\n      \"ypos\": 6,\n      \"shells\": [\n        2,\n        8,\n        18,\n        18,\n        8,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2\",\n      \"electron_configuration_semantic\": \"[Xe] 6s2\",\n      \"electron_affinity\": 13.954,\n      \"electronegativity_pauling\": 0.89,\n      \"ionization_energies\": [\n        502.9,\n        965.2,\n        3600\n      ],\n      \"cpk-hex\": \"00c900\"\n    },\n    {\n      \"name\": \"Lanthanum\",\n      \"appearance\": \"silvery white\",\n      \"atomic_mass\": 138.905477,\n      \"boil\": 3737,\n      \"category\": \"lanthanide\",\n      \"color\": null,\n      \"density\": 6.162,\n      \"discovered_by\": \"Carl Gustaf Mosander\",\n      \"melt\": 1193,\n      \"molar_heat\": 27.11,\n      \"named_by\": null,\n      \"number\": 57,\n      \"period\": 6,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Lanthanum\",\n      \"spectral_img\": null,\n      \"summary\": \"Lanthanum is a soft, ductile, silvery-white metallic chemical element with symbol La and atomic number 57. It tarnishes rapidly when exposed to air and is soft enough to be cut with a knife. It gave its name to the lanthanide series, a group of 15 similar elements between lanthanum and lutetium in the periodic table:it is also sometimes considered the first element of the 6th-period transition metals.\",\n      \"symbol\": \"La\",\n      \"xpos\": 3,\n      \"ypos\": 9,\n      \"shells\": [\n        2,\n        8,\n        18,\n        18,\n        9,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 5d1\",\n      \"electron_configuration_semantic\": \"[Xe] 5d16s2\",\n      \"electron_affinity\": 53,\n      \"electronegativity_pauling\": 1.1,\n      \"ionization_energies\": [\n        538.1,\n        1067,\n        1850.3,\n        4819,\n        5940\n      ],\n      \"cpk-hex\": \"70d4ff\"\n    },\n    {\n      \"name\": \"Cerium\",\n      \"appearance\": \"silvery white\",\n      \"atomic_mass\": 140.1161,\n      \"boil\": 3716,\n      \"category\": \"lanthanide\",\n      \"color\": null,\n      \"density\": 6.77,\n      \"discovered_by\": \"Martin Heinrich Klaproth\",\n      \"melt\": 1068,\n      \"molar_heat\": 26.94,\n      \"named_by\": null,\n      \"number\": 58,\n      \"period\": 6,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Cerium\",\n      \"spectral_img\": null,\n      \"summary\": \"Cerium is a chemical element with symbol Ce and atomic number 58. It is a soft, silvery, ductile metal which easily oxidizes in air. Cerium was named after the dwarf planet Ceres (itself named after the Roman goddess of agriculture).\",\n      \"symbol\": \"Ce\",\n      \"xpos\": 4,\n      \"ypos\": 9,\n      \"shells\": [\n        2,\n        8,\n        18,\n        19,\n        9,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 5d1 4f1\",\n      \"electron_configuration_semantic\": \"[Xe] 4f1 5d1 6s2\",\n      \"electron_affinity\": 55,\n      \"electronegativity_pauling\": 1.12,\n      \"ionization_energies\": [\n        534.4,\n        1050,\n        1949,\n        3547,\n        6325,\n        7490\n      ],\n      \"cpk-hex\": \"ffffc7\"\n    },\n    {\n      \"name\": \"Praseodymium\",\n      \"appearance\": \"grayish white\",\n      \"atomic_mass\": 140.907662,\n      \"boil\": 3403,\n      \"category\": \"lanthanide\",\n      \"color\": null,\n      \"density\": 6.77,\n      \"discovered_by\": \"Carl Auer von Welsbach\",\n      \"melt\": 1208,\n      \"molar_heat\": 27.2,\n      \"named_by\": null,\n      \"number\": 59,\n      \"period\": 6,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Praseodymium\",\n      \"spectral_img\": null,\n      \"summary\": \"Praseodymium is a chemical element with symbol Pr and atomic number 59. Praseodymium is a soft, silvery, malleable and ductile metal in the lanthanide group. It is valued for its magnetic, electrical, chemical, and optical properties.\",\n      \"symbol\": \"Pr\",\n      \"xpos\": 5,\n      \"ypos\": 9,\n      \"shells\": [\n        2,\n        8,\n        18,\n        21,\n        8,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 4f3\",\n      \"electron_configuration_semantic\": \"[Xe] 4f3 6s2\",\n      \"electron_affinity\": 93,\n      \"electronegativity_pauling\": 1.13,\n      \"ionization_energies\": [\n        527,\n        1020,\n        2086,\n        3761,\n        5551\n      ],\n      \"cpk-hex\": \"d9ffc7\"\n    },\n    {\n      \"name\": \"Neodymium\",\n      \"appearance\": \"silvery white\",\n      \"atomic_mass\": 144.2423,\n      \"boil\": 3347,\n      \"category\": \"lanthanide\",\n      \"color\": null,\n      \"density\": 7.01,\n      \"discovered_by\": \"Carl Auer von Welsbach\",\n      \"melt\": 1297,\n      \"molar_heat\": 27.45,\n      \"named_by\": null,\n      \"number\": 60,\n      \"period\": 6,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Neodymium\",\n      \"spectral_img\": null,\n      \"summary\": \"Neodymium is a chemical element with symbol Nd and atomic number 60. It is a soft silvery metal that tarnishes in air. Neodymium was discovered in 1885 by the Austrian chemist Carl Auer von Welsbach.\",\n      \"symbol\": \"Nd\",\n      \"xpos\": 6,\n      \"ypos\": 9,\n      \"shells\": [\n        2,\n        8,\n        18,\n        22,\n        8,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 4f4\",\n      \"electron_configuration_semantic\": \"[Xe] 4f4 6s2\",\n      \"electron_affinity\": 184.87,\n      \"electronegativity_pauling\": 1.14,\n      \"ionization_energies\": [\n        533.1,\n        1040,\n        2130,\n        3900\n      ],\n      \"cpk-hex\": \"c7ffc7\"\n    },\n    {\n      \"name\": \"Promethium\",\n      \"appearance\": \"metallic\",\n      \"atomic_mass\": 145,\n      \"boil\": 3273,\n      \"category\": \"lanthanide\",\n      \"color\": null,\n      \"density\": 7.26,\n      \"discovered_by\": \"Chien Shiung Wu\",\n      \"melt\": 1315,\n      \"molar_heat\": null,\n      \"named_by\": \"Isotopes of promethium\",\n      \"number\": 61,\n      \"period\": 6,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Promethium\",\n      \"spectral_img\": null,\n      \"summary\": \"Promethium, originally prometheum, is a chemical element with the symbol Pm and atomic number 61. All of its isotopes are radioactive; it is one of only two such elements that are followed in the periodic table by elements with stable forms, a distinction shared with technetium. Chemically, promethium is a lanthanide, which forms salts when combined with other elements.\",\n      \"symbol\": \"Pm\",\n      \"xpos\": 7,\n      \"ypos\": 9,\n      \"shells\": [\n        2,\n        8,\n        18,\n        23,\n        8,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 4f5\",\n      \"electron_configuration_semantic\": \"[Xe] 4f5 6s2\",\n      \"electron_affinity\": 12.45,\n      \"electronegativity_pauling\": 1.13,\n      \"ionization_energies\": [\n        540,\n        1050,\n        2150,\n        3970\n      ],\n      \"cpk-hex\": \"a3ffc7\"\n    },\n    {\n      \"name\": \"Samarium\",\n      \"appearance\": \"silvery white\",\n      \"atomic_mass\": 150.362,\n      \"boil\": 2173,\n      \"category\": \"lanthanide\",\n      \"color\": null,\n      \"density\": 7.52,\n      \"discovered_by\": \"Lecoq de Boisbaudran\",\n      \"melt\": 1345,\n      \"molar_heat\": 29.54,\n      \"named_by\": null,\n      \"number\": 62,\n      \"period\": 6,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Samarium\",\n      \"spectral_img\": null,\n      \"summary\": \"Samarium is a chemical element with symbol Sm and atomic number 62. It is a moderately hard silvery metal that readily oxidizes in air. Being a typical member of the lanthanide series, samarium usually assumes the oxidation state +3.\",\n      \"symbol\": \"Sm\",\n      \"xpos\": 8,\n      \"ypos\": 9,\n      \"shells\": [\n        2,\n        8,\n        18,\n        24,\n        8,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 4f6\",\n      \"electron_configuration_semantic\": \"[Xe] 4f6 6s2\",\n      \"electron_affinity\": 15.63,\n      \"electronegativity_pauling\": 1.17,\n      \"ionization_energies\": [\n        544.5,\n        1070,\n        2260,\n        3990\n      ],\n      \"cpk-hex\": \"8fffc7\"\n    },\n    {\n      \"name\": \"Europium\",\n      \"appearance\": null,\n      \"atomic_mass\": 151.9641,\n      \"boil\": 1802,\n      \"category\": \"lanthanide\",\n      \"color\": null,\n      \"density\": 5.264,\n      \"discovered_by\": \"Eugène-Anatole Demarçay\",\n      \"melt\": 1099,\n      \"molar_heat\": 27.66,\n      \"named_by\": null,\n      \"number\": 63,\n      \"period\": 6,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Europium\",\n      \"spectral_img\": null,\n      \"summary\": \"Europium is a chemical element with symbol Eu and atomic number 63. It was isolated in 1901 and is named after the continent of Europe. It is a moderately hard, silvery metal which readily oxidizes in air and water.\",\n      \"symbol\": \"Eu\",\n      \"xpos\": 9,\n      \"ypos\": 9,\n      \"shells\": [\n        2,\n        8,\n        18,\n        25,\n        8,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 4f7\",\n      \"electron_configuration_semantic\": \"[Xe] 4f7 6s2\",\n      \"electron_affinity\": 11.2,\n      \"electronegativity_pauling\": 1.2,\n      \"ionization_energies\": [\n        547.1,\n        1085,\n        2404,\n        4120\n      ],\n      \"cpk-hex\": \"61ffc7\"\n    },\n    {\n      \"name\": \"Gadolinium\",\n      \"appearance\": \"silvery white\",\n      \"atomic_mass\": 157.253,\n      \"boil\": 3273,\n      \"category\": \"lanthanide\",\n      \"color\": null,\n      \"density\": 7.9,\n      \"discovered_by\": \"Jean Charles Galissard de Marignac\",\n      \"melt\": 1585,\n      \"molar_heat\": 37.03,\n      \"named_by\": null,\n      \"number\": 64,\n      \"period\": 6,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Gadolinium\",\n      \"spectral_img\": null,\n      \"summary\": \"Gadolinium is a chemical element with symbol Gd and atomic number 64. It is a silvery-white, malleable and ductile rare-earth metal. It is found in nature only in combined (salt) form.\",\n      \"symbol\": \"Gd\",\n      \"xpos\": 10,\n      \"ypos\": 9,\n      \"shells\": [\n        2,\n        8,\n        18,\n        25,\n        9,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 4f7 5d1\",\n      \"electron_configuration_semantic\": \"[Xe] 4f7 5d1 6s2\",\n      \"electron_affinity\": 13.22,\n      \"electronegativity_pauling\": 1.2,\n      \"ionization_energies\": [\n        593.4,\n        1170,\n        1990,\n        4250\n      ],\n      \"cpk-hex\": \"45ffc7\"\n    },\n    {\n      \"name\": \"Terbium\",\n      \"appearance\": \"silvery white\",\n      \"atomic_mass\": 158.925352,\n      \"boil\": 3396,\n      \"category\": \"lanthanide\",\n      \"color\": null,\n      \"density\": 8.23,\n      \"discovered_by\": \"Carl Gustaf Mosander\",\n      \"melt\": 1629,\n      \"molar_heat\": 28.91,\n      \"named_by\": null,\n      \"number\": 65,\n      \"period\": 6,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Terbium\",\n      \"spectral_img\": null,\n      \"summary\": \"Terbium is a chemical element with symbol Tb and atomic number 65. It is a silvery-white rare earth metal that is malleable, ductile and soft enough to be cut with a knife. Terbium is never found in nature as a free element, but it is contained in many minerals, including cerite, gadolinite, monazite, xenotime and euxenite.\",\n      \"symbol\": \"Tb\",\n      \"xpos\": 11,\n      \"ypos\": 9,\n      \"shells\": [\n        2,\n        8,\n        18,\n        27,\n        8,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 4f9\",\n      \"electron_configuration_semantic\": \"[Xe] 4f9 6s2\",\n      \"electron_affinity\": 112.4,\n      \"electronegativity_pauling\": 1.1,\n      \"ionization_energies\": [\n        565.8,\n        1110,\n        2114,\n        3839\n      ],\n      \"cpk-hex\": \"30ffc7\"\n    },\n    {\n      \"name\": \"Dysprosium\",\n      \"appearance\": \"silvery white\",\n      \"atomic_mass\": 162.5001,\n      \"boil\": 2840,\n      \"category\": \"lanthanide\",\n      \"color\": null,\n      \"density\": 8.54,\n      \"discovered_by\": \"Lecoq de Boisbaudran\",\n      \"melt\": 1680,\n      \"molar_heat\": 27.7,\n      \"named_by\": null,\n      \"number\": 66,\n      \"period\": 6,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Dysprosium\",\n      \"spectral_img\": null,\n      \"summary\": \"Dysprosium is a chemical element with the symbol Dy and atomic number 66. It is a rare earth element with a metallic silver luster. Dysprosium is never found in nature as a free element, though it is found in various minerals, such as xenotime.\",\n      \"symbol\": \"Dy\",\n      \"xpos\": 12,\n      \"ypos\": 9,\n      \"shells\": [\n        2,\n        8,\n        18,\n        28,\n        8,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 4f10\",\n      \"electron_configuration_semantic\": \"[Xe] 4f10 6s2\",\n      \"electron_affinity\": 33.96,\n      \"electronegativity_pauling\": 1.22,\n      \"ionization_energies\": [\n        573,\n        1130,\n        2200,\n        3990\n      ],\n      \"cpk-hex\": \"1fffc7\"\n    },\n    {\n      \"name\": \"Holmium\",\n      \"appearance\": \"silvery white\",\n      \"atomic_mass\": 164.930332,\n      \"boil\": 2873,\n      \"category\": \"lanthanide\",\n      \"color\": null,\n      \"density\": 8.79,\n      \"discovered_by\": \"Marc Delafontaine\",\n      \"melt\": 1734,\n      \"molar_heat\": 27.15,\n      \"named_by\": null,\n      \"number\": 67,\n      \"period\": 6,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Holmium\",\n      \"spectral_img\": null,\n      \"summary\": \"Holmium is a chemical element with symbol Ho and atomic number 67. Part of the lanthanide series, holmium is a rare earth element. Holmium was discovered by Swedish chemist Per Theodor Cleve.\",\n      \"symbol\": \"Ho\",\n      \"xpos\": 13,\n      \"ypos\": 9,\n      \"shells\": [\n        2,\n        8,\n        18,\n        29,\n        8,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 4f11\",\n      \"electron_configuration_semantic\": \"[Xe] 4f11 6s2\",\n      \"electron_affinity\": 32.61,\n      \"electronegativity_pauling\": 1.23,\n      \"ionization_energies\": [\n        581,\n        1140,\n        2204,\n        4100\n      ],\n      \"cpk-hex\": \"00ff9c\"\n    },\n    {\n      \"name\": \"Erbium\",\n      \"appearance\": \"silvery white\",\n      \"atomic_mass\": 167.2593,\n      \"boil\": 3141,\n      \"category\": \"lanthanide\",\n      \"color\": null,\n      \"density\": 9.066,\n      \"discovered_by\": \"Carl Gustaf Mosander\",\n      \"melt\": 1802,\n      \"molar_heat\": 28.12,\n      \"named_by\": null,\n      \"number\": 68,\n      \"period\": 6,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Erbium\",\n      \"spectral_img\": null,\n      \"summary\": \"Erbium is a chemical element in the lanthanide series, with symbol Er and atomic number 68. A silvery-white solid metal when artificially isolated, natural erbium is always found in chemical combination with other elements on Earth. As such, it is a rare earth element which is associated with several other rare elements in the mineral gadolinite from Ytterby in Sweden, where yttrium, ytterbium, and terbium were discovered.\",\n      \"symbol\": \"Er\",\n      \"xpos\": 14,\n      \"ypos\": 9,\n      \"shells\": [\n        2,\n        8,\n        18,\n        30,\n        8,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 4f12\",\n      \"electron_configuration_semantic\": \"[Xe] 4f12 6s2\",\n      \"electron_affinity\": 30.1,\n      \"electronegativity_pauling\": 1.24,\n      \"ionization_energies\": [\n        589.3,\n        1150,\n        2194,\n        4120\n      ],\n      \"cpk-hex\": \"00e675\"\n    },\n    {\n      \"name\": \"Thulium\",\n      \"appearance\": \"silvery gray\",\n      \"atomic_mass\": 168.934222,\n      \"boil\": 2223,\n      \"category\": \"lanthanide\",\n      \"color\": null,\n      \"density\": 9.32,\n      \"discovered_by\": \"Per Teodor Cleve\",\n      \"melt\": 1818,\n      \"molar_heat\": 27.03,\n      \"named_by\": null,\n      \"number\": 69,\n      \"period\": 6,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Thulium\",\n      \"spectral_img\": null,\n      \"summary\": \"Thulium is a chemical element with symbol Tm and atomic number 69. It is the thirteenth and antepenultimate (third-last) element in the lanthanide series. Like the other lanthanides, the most common oxidation state is +3, seen in its oxide, halides and other compounds.\",\n      \"symbol\": \"Tm\",\n      \"xpos\": 15,\n      \"ypos\": 9,\n      \"shells\": [\n        2,\n        8,\n        18,\n        31,\n        8,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 4f13\",\n      \"electron_configuration_semantic\": \"[Xe] 4f13 6s2\",\n      \"electron_affinity\": 99,\n      \"electronegativity_pauling\": 1.25,\n      \"ionization_energies\": [\n        596.7,\n        1160,\n        2285,\n        4120\n      ],\n      \"cpk-hex\": \"00d452\"\n    },\n    {\n      \"name\": \"Ytterbium\",\n      \"appearance\": null,\n      \"atomic_mass\": 173.0451,\n      \"boil\": 1469,\n      \"category\": \"lanthanide\",\n      \"color\": null,\n      \"density\": 6.9,\n      \"discovered_by\": \"Jean Charles Galissard de Marignac\",\n      \"melt\": 1097,\n      \"molar_heat\": 26.74,\n      \"named_by\": null,\n      \"number\": 70,\n      \"period\": 6,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Ytterbium\",\n      \"spectral_img\": null,\n      \"summary\": \"Ytterbium is a chemical element with symbol Yb and atomic number 70. It is the fourteenth and penultimate element in the lanthanide series, which is the basis of the relative stability of its +2 oxidation state. However, like the other lanthanides, its most common oxidation state is +3, seen in its oxide, halides and other compounds.\",\n      \"symbol\": \"Yb\",\n      \"xpos\": 16,\n      \"ypos\": 9,\n      \"shells\": [\n        2,\n        8,\n        18,\n        32,\n        8,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 4f14\",\n      \"electron_configuration_semantic\": \"[Xe] 4f14 6s2\",\n      \"electron_affinity\": -1.93,\n      \"electronegativity_pauling\": 1.1,\n      \"ionization_energies\": [\n        603.4,\n        1174.8,\n        2417,\n        4203\n      ],\n      \"cpk-hex\": \"00bf38\"\n    },\n    {\n      \"name\": \"Lutetium\",\n      \"appearance\": \"silvery white\",\n      \"atomic_mass\": 174.96681,\n      \"boil\": 3675,\n      \"category\": \"lanthanide\",\n      \"color\": null,\n      \"density\": 9.841,\n      \"discovered_by\": \"Georges Urbain\",\n      \"melt\": 1925,\n      \"molar_heat\": 26.86,\n      \"named_by\": null,\n      \"number\": 71,\n      \"period\": 6,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Lutetium\",\n      \"spectral_img\": null,\n      \"summary\": \"Lutetium is a chemical element with symbol Lu and atomic number 71. It is a silvery white metal, which resists corrosion in dry, but not in moist air. It is considered the first element of the 6th-period transition metals and the last element in the lanthanide series, and is traditionally counted among the rare earths.\",\n      \"symbol\": \"Lu\",\n      \"xpos\": 17,\n      \"ypos\": 9,\n      \"shells\": [\n        2,\n        8,\n        18,\n        32,\n        9,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 4f14 5d1\",\n      \"electron_configuration_semantic\": \"[Xe] 4f14 5d1 6s2\",\n      \"electron_affinity\": 33.4,\n      \"electronegativity_pauling\": 1.27,\n      \"ionization_energies\": [\n        523.5,\n        1340,\n        2022.3,\n        4370,\n        6445\n      ],\n      \"cpk-hex\": \"00ab24\"\n    },\n    {\n      \"name\": \"Hafnium\",\n      \"appearance\": \"steel gray\",\n      \"atomic_mass\": 178.492,\n      \"boil\": 4876,\n      \"category\": \"transition metal\",\n      \"color\": null,\n      \"density\": 13.31,\n      \"discovered_by\": \"Dirk Coster\",\n      \"melt\": 2506,\n      \"molar_heat\": 25.73,\n      \"named_by\": null,\n      \"number\": 72,\n      \"period\": 6,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Hafnium\",\n      \"spectral_img\": \"https://en.wikipedia.org/wiki/File:Hafnium_spectrum_visible.png\",\n      \"summary\": \"Hafnium is a chemical element with symbol Hf and atomic number 72. A lustrous, silvery gray, tetravalent transition metal, hafnium chemically resembles zirconium and is found in zirconium minerals. Its existence was predicted by Dmitri Mendeleev in 1869, though it was not identified until 1923, making it the penultimate stable element to be discovered (rhenium was identified two years later).\",\n      \"symbol\": \"Hf\",\n      \"xpos\": 4,\n      \"ypos\": 6,\n      \"shells\": [\n        2,\n        8,\n        18,\n        32,\n        10,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 4f14 5d2\",\n      \"electron_configuration_semantic\": \"[Xe] 4f14 5d2 6s2\",\n      \"electron_affinity\": 17.18,\n      \"electronegativity_pauling\": 1.3,\n      \"ionization_energies\": [\n        658.5,\n        1440,\n        2250,\n        3216\n      ],\n      \"cpk-hex\": \"4dc2ff\"\n    },\n    {\n      \"name\": \"Tantalum\",\n      \"appearance\": \"gray blue\",\n      \"atomic_mass\": 180.947882,\n      \"boil\": 5731,\n      \"category\": \"transition metal\",\n      \"color\": null,\n      \"density\": 16.69,\n      \"discovered_by\": \"Anders Gustaf Ekeberg\",\n      \"melt\": 3290,\n      \"molar_heat\": 25.36,\n      \"named_by\": null,\n      \"number\": 73,\n      \"period\": 6,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Tantalum\",\n      \"spectral_img\": \"https://en.wikipedia.org/wiki/File:Tantalum_spectrum_visible.png\",\n      \"summary\": \"Tantalum is a chemical element with symbol Ta and atomic number 73. Previously known as tantalium, its name comes from Tantalus, an antihero from Greek mythology. Tantalum is a rare, hard, blue-gray, lustrous transition metal that is highly corrosion-resistant.\",\n      \"symbol\": \"Ta\",\n      \"xpos\": 5,\n      \"ypos\": 6,\n      \"shells\": [\n        2,\n        8,\n        18,\n        32,\n        11,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 4f14 5d3\",\n      \"electron_configuration_semantic\": \"[Xe] 4f14 5d3 6s2\",\n      \"electron_affinity\": 31,\n      \"electronegativity_pauling\": 1.5,\n      \"ionization_energies\": [\n        761,\n        1500\n      ],\n      \"cpk-hex\": \"4da6ff\"\n    },\n    {\n      \"name\": \"Tungsten\",\n      \"appearance\": \"grayish white, lustrous\",\n      \"atomic_mass\": 183.841,\n      \"boil\": 6203,\n      \"category\": \"transition metal\",\n      \"color\": null,\n      \"density\": 19.25,\n      \"discovered_by\": \"Carl Wilhelm Scheele\",\n      \"melt\": 3695,\n      \"molar_heat\": 24.27,\n      \"named_by\": null,\n      \"number\": 74,\n      \"period\": 6,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Tungsten\",\n      \"spectral_img\": null,\n      \"summary\": \"Tungsten, also known as wolfram, is a chemical element with symbol W and atomic number 74. The word tungsten comes from the Swedish language tung sten, which directly translates to heavy stone. Its name in Swedish is volfram, however, in order to distinguish it from scheelite, which in Swedish is alternatively named tungsten.\",\n      \"symbol\": \"W\",\n      \"xpos\": 6,\n      \"ypos\": 6,\n      \"shells\": [\n        2,\n        8,\n        18,\n        32,\n        12,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 4f14 5d4\",\n      \"electron_configuration_semantic\": \"[Xe] 4f14 5d4 6s2\",\n      \"electron_affinity\": 78.76,\n      \"electronegativity_pauling\": 2.36,\n      \"ionization_energies\": [\n        770,\n        1700\n      ],\n      \"cpk-hex\": \"2194d6\"\n    },\n    {\n      \"name\": \"Rhenium\",\n      \"appearance\": \"silvery-grayish\",\n      \"atomic_mass\": 186.2071,\n      \"boil\": 5869,\n      \"category\": \"transition metal\",\n      \"color\": null,\n      \"density\": 21.02,\n      \"discovered_by\": \"Masataka Ogawa\",\n      \"melt\": 3459,\n      \"molar_heat\": 25.48,\n      \"named_by\": \"Walter Noddack\",\n      \"number\": 75,\n      \"period\": 6,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Rhenium\",\n      \"spectral_img\": null,\n      \"summary\": \"Rhenium is a chemical element with symbol Re and atomic number 75. It is a silvery-white, heavy, third-row transition metal in group 7 of the periodic table. With an estimated average concentration of 1 part per billion (ppb), rhenium is one of the rarest elements in the Earth's crust.\",\n      \"symbol\": \"Re\",\n      \"xpos\": 7,\n      \"ypos\": 6,\n      \"shells\": [\n        2,\n        8,\n        18,\n        32,\n        13,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 4f14 5d5\",\n      \"electron_configuration_semantic\": \"[Xe] 4f14 5d5 6s2\",\n      \"electron_affinity\": 5.8273,\n      \"electronegativity_pauling\": 1.9,\n      \"ionization_energies\": [\n        760,\n        1260,\n        2510,\n        3640\n      ],\n      \"cpk-hex\": \"267dab\"\n    },\n    {\n      \"name\": \"Osmium\",\n      \"appearance\": \"silvery, blue cast\",\n      \"atomic_mass\": 190.233,\n      \"boil\": 5285,\n      \"category\": \"transition metal\",\n      \"color\": null,\n      \"density\": 22.59,\n      \"discovered_by\": \"Smithson Tennant\",\n      \"melt\": 3306,\n      \"molar_heat\": 24.7,\n      \"named_by\": null,\n      \"number\": 76,\n      \"period\": 6,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Osmium\",\n      \"spectral_img\": null,\n      \"summary\": \"Osmium (from Greek osme (ὀσμή) meaning \\\"smell\\\") is a chemical element with symbol Os and atomic number 76. It is a hard, brittle, bluish-white transition metal in the platinum group that is found as a trace element in alloys, mostly in platinum ores. Osmium is the densest naturally occurring element, with a density of 22.59 g/cm3.\",\n      \"symbol\": \"Os\",\n      \"xpos\": 8,\n      \"ypos\": 6,\n      \"shells\": [\n        2,\n        8,\n        18,\n        32,\n        14,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 4f14 5d6\",\n      \"electron_configuration_semantic\": \"[Xe] 4f14 5d6 6s2\",\n      \"electron_affinity\": 103.99,\n      \"electronegativity_pauling\": 2.2,\n      \"ionization_energies\": [\n        840,\n        1600\n      ],\n      \"cpk-hex\": \"266696\"\n    },\n    {\n      \"name\": \"Iridium\",\n      \"appearance\": \"silvery white\",\n      \"atomic_mass\": 192.2173,\n      \"boil\": 4403,\n      \"category\": \"transition metal\",\n      \"color\": null,\n      \"density\": 22.56,\n      \"discovered_by\": \"Smithson Tennant\",\n      \"melt\": 2719,\n      \"molar_heat\": 25.1,\n      \"named_by\": null,\n      \"number\": 77,\n      \"period\": 6,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Iridium\",\n      \"spectral_img\": null,\n      \"summary\": \"Iridium is a chemical element with symbol Ir and atomic number 77. A very hard, brittle, silvery-white transition metal of the platinum group, iridium is generally credited with being the second densest element (after osmium) based on measured density, although calculations involving the space lattices of the elements show that iridium is denser. It is also the most corrosion-resistant metal, even at temperatures as high as 2000 °C. Although only certain molten salts and halogens are corrosive to solid iridium, finely divided iridium dust is much more reactive and can be flammable.\",\n      \"symbol\": \"Ir\",\n      \"xpos\": 9,\n      \"ypos\": 6,\n      \"shells\": [\n        2,\n        8,\n        18,\n        32,\n        15,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 4f14 5d7\",\n      \"electron_configuration_semantic\": \"[Xe] 4f14 5d7 6s2\",\n      \"electron_affinity\": 150.94,\n      \"electronegativity_pauling\": 2.2,\n      \"ionization_energies\": [\n        880,\n        1600\n      ],\n      \"cpk-hex\": \"175487\"\n    },\n    {\n      \"name\": \"Platinum\",\n      \"appearance\": \"silvery white\",\n      \"atomic_mass\": 195.0849,\n      \"boil\": 4098,\n      \"category\": \"transition metal\",\n      \"color\": null,\n      \"density\": 21.45,\n      \"discovered_by\": \"Antonio de Ulloa\",\n      \"melt\": 2041.4,\n      \"molar_heat\": 25.86,\n      \"named_by\": null,\n      \"number\": 78,\n      \"period\": 6,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Platinum\",\n      \"spectral_img\": null,\n      \"summary\": \"Platinum is a chemical element with symbol Pt and atomic number 78. It is a dense, malleable, ductile, highly unreactive, precious, gray-white transition metal. Its name is derived from the Spanish term platina, which is literally translated into \\\"little silver\\\".\",\n      \"symbol\": \"Pt\",\n      \"xpos\": 10,\n      \"ypos\": 6,\n      \"shells\": [\n        2,\n        8,\n        18,\n        32,\n        17,\n        1\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s1 4f14 5d9\",\n      \"electron_configuration_semantic\": \"[Xe] 4f14 5d9 6s1\",\n      \"electron_affinity\": 205.041,\n      \"electronegativity_pauling\": 2.28,\n      \"ionization_energies\": [\n        870,\n        1791\n      ],\n      \"cpk-hex\": \"d0d0e0\"\n    },\n    {\n      \"name\": \"Gold\",\n      \"appearance\": \"metallic yellow\",\n      \"atomic_mass\": 196.9665695,\n      \"boil\": 3243,\n      \"category\": \"transition metal\",\n      \"color\": null,\n      \"density\": 19.3,\n      \"discovered_by\": \"Middle East\",\n      \"melt\": 1337.33,\n      \"molar_heat\": 25.418,\n      \"named_by\": null,\n      \"number\": 79,\n      \"period\": 6,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Gold\",\n      \"spectral_img\": null,\n      \"summary\": \"Gold is a chemical element with symbol Au (from Latin:aurum) and atomic number 79. In its purest form, it is a bright, slightly reddish yellow, dense, soft, malleable and ductile metal. Chemically, gold is a transition metal and a group 11 element.\",\n      \"symbol\": \"Au\",\n      \"xpos\": 11,\n      \"ypos\": 6,\n      \"shells\": [\n        2,\n        8,\n        18,\n        32,\n        18,\n        1\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s1 4f14 5d10\",\n      \"electron_configuration_semantic\": \"[Xe] 4f14 5d10 6s1\",\n      \"electron_affinity\": 222.747,\n      \"electronegativity_pauling\": 2.54,\n      \"ionization_energies\": [\n        890.1,\n        1980\n      ],\n      \"cpk-hex\": \"ffd123\"\n    },\n    {\n      \"name\": \"Mercury\",\n      \"appearance\": \"silvery\",\n      \"atomic_mass\": 200.5923,\n      \"boil\": 629.88,\n      \"category\": \"transition metal\",\n      \"color\": null,\n      \"density\": 13.534,\n      \"discovered_by\": \"unknown, before 2000 BCE\",\n      \"melt\": 234.321,\n      \"molar_heat\": 27.983,\n      \"named_by\": null,\n      \"number\": 80,\n      \"period\": 6,\n      \"phase\": \"Liquid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Mercury (Element)\",\n      \"spectral_img\": null,\n      \"summary\": \"Mercury is a chemical element with symbol Hg and atomic number 80. It is commonly known as quicksilver and was formerly named hydrargyrum (/haɪˈdrɑːrdʒərəm/). A heavy, silvery d-block element, mercury is the only metallic element that is liquid at standard conditions for temperature and pressure; the only other element that is liquid under these conditions is bromine, though metals such as caesium, gallium, and rubidium melt just above room temperature.\",\n      \"symbol\": \"Hg\",\n      \"xpos\": 12,\n      \"ypos\": 6,\n      \"shells\": [\n        2,\n        8,\n        18,\n        32,\n        18,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 4f14 5d10\",\n      \"electron_configuration_semantic\": \"[Xe] 4f14 5d10 6s2\",\n      \"electron_affinity\": -48,\n      \"electronegativity_pauling\": 2,\n      \"ionization_energies\": [\n        1007.1,\n        1810,\n        3300\n      ],\n      \"cpk-hex\": \"b8b8d0\"\n    },\n    {\n      \"name\": \"Thallium\",\n      \"appearance\": \"silvery white\",\n      \"atomic_mass\": 204.38,\n      \"boil\": 1746,\n      \"category\": \"post-transition metal\",\n      \"color\": null,\n      \"density\": 11.85,\n      \"discovered_by\": \"William Crookes\",\n      \"melt\": 577,\n      \"molar_heat\": 26.32,\n      \"named_by\": null,\n      \"number\": 81,\n      \"period\": 6,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Thallium\",\n      \"spectral_img\": null,\n      \"summary\": \"Thallium is a chemical element with symbol Tl and atomic number 81. This soft gray post-transition metal is not found free in nature. When isolated, it resembles tin, but discolors when exposed to air.\",\n      \"symbol\": \"Tl\",\n      \"xpos\": 13,\n      \"ypos\": 6,\n      \"shells\": [\n        2,\n        8,\n        18,\n        32,\n        18,\n        3\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 4f14 5d10 6p1\",\n      \"electron_configuration_semantic\": \"[Xe] 4f14 5d10 6s2 6p1\",\n      \"electron_affinity\": 36.4,\n      \"electronegativity_pauling\": 1.62,\n      \"ionization_energies\": [\n        589.4,\n        1971,\n        2878\n      ],\n      \"cpk-hex\": \"a6544d\"\n    },\n    {\n      \"name\": \"Lead\",\n      \"appearance\": \"metallic gray\",\n      \"atomic_mass\": 207.21,\n      \"boil\": 2022,\n      \"category\": \"post-transition metal\",\n      \"color\": null,\n      \"density\": 11.34,\n      \"discovered_by\": \"Middle East\",\n      \"melt\": 600.61,\n      \"molar_heat\": 26.65,\n      \"named_by\": null,\n      \"number\": 82,\n      \"period\": 6,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Lead_(element)\",\n      \"spectral_img\": null,\n      \"summary\": \"Lead (/lɛd/) is a chemical element in the carbon group with symbol Pb (from Latin:plumbum) and atomic number 82. Lead is a soft, malleable and heavy post-transition metal. Metallic lead has a bluish-white color after being freshly cut, but it soon tarnishes to a dull grayish color when exposed to air.\",\n      \"symbol\": \"Pb\",\n      \"xpos\": 14,\n      \"ypos\": 6,\n      \"shells\": [\n        2,\n        8,\n        18,\n        32,\n        18,\n        4\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 4f14 5d10 6p2\",\n      \"electron_configuration_semantic\": \"[Xe] 4f14 5d10 6s2 6p2\",\n      \"electron_affinity\": 34.4204,\n      \"electronegativity_pauling\": 1.87,\n      \"ionization_energies\": [\n        715.6,\n        1450.5,\n        3081.5,\n        4083,\n        6640\n      ],\n      \"cpk-hex\": \"575961\"\n    },\n    {\n      \"name\": \"Bismuth\",\n      \"appearance\": \"lustrous silver\",\n      \"atomic_mass\": 208.980401,\n      \"boil\": 1837,\n      \"category\": \"post-transition metal\",\n      \"color\": null,\n      \"density\": 9.78,\n      \"discovered_by\": \"Claude François Geoffroy\",\n      \"melt\": 544.7,\n      \"molar_heat\": 25.52,\n      \"named_by\": null,\n      \"number\": 83,\n      \"period\": 6,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Bismuth\",\n      \"spectral_img\": null,\n      \"summary\": \"Bismuth is a chemical element with symbol Bi and atomic number 83. Bismuth, a pentavalent post-transition metal, chemically resembles arsenic and antimony. Elemental bismuth may occur naturally, although its sulfide and oxide form important commercial ores.\",\n      \"symbol\": \"Bi\",\n      \"xpos\": 15,\n      \"ypos\": 6,\n      \"shells\": [\n        2,\n        8,\n        18,\n        32,\n        18,\n        5\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 4f14 5d10 6p3\",\n      \"electron_configuration_semantic\": \"[Xe] 4f14 5d10 6s2 6p3\",\n      \"electron_affinity\": 90.924,\n      \"electronegativity_pauling\": 2.02,\n      \"ionization_energies\": [\n        703,\n        1610,\n        2466,\n        4370,\n        5400,\n        8520\n      ],\n      \"cpk-hex\": \"9e4fb5\"\n    },\n    {\n      \"name\": \"Polonium\",\n      \"appearance\": \"silvery\",\n      \"atomic_mass\": 209,\n      \"boil\": 1235,\n      \"category\": \"post-transition metal\",\n      \"color\": null,\n      \"density\": 9.196,\n      \"discovered_by\": \"Pierre Curie\",\n      \"melt\": 527,\n      \"molar_heat\": 26.4,\n      \"named_by\": null,\n      \"number\": 84,\n      \"period\": 6,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Polonium\",\n      \"spectral_img\": null,\n      \"summary\": \"Polonium is a chemical element with symbol Po and atomic number 84, discovered in 1898 by Marie Curie and Pierre Curie. A rare and highly radioactive element with no stable isotopes, polonium is chemically similar to bismuth and tellurium, and it occurs in uranium ores. Applications of polonium are few.\",\n      \"symbol\": \"Po\",\n      \"xpos\": 16,\n      \"ypos\": 6,\n      \"shells\": [\n        2,\n        8,\n        18,\n        32,\n        18,\n        6\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 4f14 5d10 6p4\",\n      \"electron_configuration_semantic\": \"[Xe] 4f14 5d10 6s2 6p4\",\n      \"electron_affinity\": 136,\n      \"electronegativity_pauling\": 2,\n      \"ionization_energies\": [\n        812.1\n      ],\n      \"cpk-hex\": \"ab5c00\"\n    },\n    {\n      \"name\": \"Astatine\",\n      \"appearance\": \"unknown, probably metallic\",\n      \"atomic_mass\": 210,\n      \"boil\": 610,\n      \"category\": \"metalloid\",\n      \"color\": null,\n      \"density\": 6.35,\n      \"discovered_by\": \"Dale R. Corson\",\n      \"melt\": 575,\n      \"molar_heat\": null,\n      \"named_by\": null,\n      \"number\": 85,\n      \"period\": 6,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Astatine\",\n      \"spectral_img\": null,\n      \"summary\": \"Astatine is a very rare radioactive chemical element with the chemical symbol At and atomic number 85. It occurs on Earth as the decay product of various heavier elements. All its isotopes are short-lived; the most stable is astatine-210, with a half-life of 8.1 hours.\",\n      \"symbol\": \"At\",\n      \"xpos\": 17,\n      \"ypos\": 6,\n      \"shells\": [\n        2,\n        8,\n        18,\n        32,\n        18,\n        7\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 4f14 5d10 6p5\",\n      \"electron_configuration_semantic\": \"[Xe] 4f14 5d10 6s2 6p5\",\n      \"electron_affinity\": 233,\n      \"electronegativity_pauling\": 2.2,\n      \"ionization_energies\": [\n        899.003\n      ],\n      \"cpk-hex\": \"754f45\"\n    },\n    {\n      \"name\": \"Radon\",\n      \"appearance\": \"colorless gas, occasionally glows green or red in discharge tubes\",\n      \"atomic_mass\": 222,\n      \"boil\": 211.5,\n      \"category\": \"noble gas\",\n      \"color\": null,\n      \"density\": 9.73,\n      \"discovered_by\": \"Friedrich Ernst Dorn\",\n      \"melt\": 202,\n      \"molar_heat\": null,\n      \"named_by\": null,\n      \"number\": 86,\n      \"period\": 6,\n      \"phase\": \"Gas\",\n      \"source\": \"https://en.wikipedia.org/wiki/Radon\",\n      \"spectral_img\": \"https://en.wikipedia.org/wiki/File:Radon_spectrum.png\",\n      \"summary\": \"Radon is a chemical element with symbol Rn and atomic number 86. It is a radioactive, colorless, odorless, tasteless noble gas, occurring naturally as a decay product of radium. Its most stable isotope, 222Rn, has a half-life of 3.8 days.\",\n      \"symbol\": \"Rn\",\n      \"xpos\": 18,\n      \"ypos\": 6,\n      \"shells\": [\n        2,\n        8,\n        18,\n        32,\n        18,\n        8\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 4f14 5d10 6p6\",\n      \"electron_configuration_semantic\": \"[Xe] 4f14 5d10 6s2 6p6\",\n      \"electron_affinity\": -68,\n      \"electronegativity_pauling\": 2.2,\n      \"ionization_energies\": [\n        1037\n      ],\n      \"cpk-hex\": \"428296\"\n    },\n    {\n      \"name\": \"Francium\",\n      \"appearance\": null,\n      \"atomic_mass\": 223,\n      \"boil\": 950,\n      \"category\": \"alkali metal\",\n      \"color\": null,\n      \"density\": 1.87,\n      \"discovered_by\": \"Marguerite Perey\",\n      \"melt\": 300,\n      \"molar_heat\": null,\n      \"named_by\": null,\n      \"number\": 87,\n      \"period\": 7,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Francium\",\n      \"spectral_img\": null,\n      \"summary\": \"Francium is a chemical element with symbol Fr and atomic number 87. It used to be known as eka-caesium and actinium K. It is the second-least electronegative element, behind only caesium. Francium is a highly radioactive metal that decays into astatine, radium, and radon.\",\n      \"symbol\": \"Fr\",\n      \"xpos\": 1,\n      \"ypos\": 7,\n      \"shells\": [\n        2,\n        8,\n        18,\n        32,\n        18,\n        8,\n        1\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 4f14 5d10 6p6 7s1\",\n      \"electron_configuration_semantic\": \"[Rn] 7s1\",\n      \"electron_affinity\": 46.89,\n      \"electronegativity_pauling\": 0.79,\n      \"ionization_energies\": [\n        380\n      ],\n      \"cpk-hex\": \"420066\"\n    },\n    {\n      \"name\": \"Radium\",\n      \"appearance\": \"silvery white metallic\",\n      \"atomic_mass\": 226,\n      \"boil\": 2010,\n      \"category\": \"alkaline earth metal\",\n      \"color\": null,\n      \"density\": 5.5,\n      \"discovered_by\": \"Pierre Curie\",\n      \"melt\": 1233,\n      \"molar_heat\": null,\n      \"named_by\": null,\n      \"number\": 88,\n      \"period\": 7,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Radium\",\n      \"spectral_img\": null,\n      \"summary\": \"Radium is a chemical element with symbol Ra and atomic number 88. It is the sixth element in group 2 of the periodic table, also known as the alkaline earth metals. Pure radium is almost colorless, but it readily combines with nitrogen (rather than oxygen) on exposure to air, forming a black surface layer of radium nitride (Ra3N2).\",\n      \"symbol\": \"Ra\",\n      \"xpos\": 2,\n      \"ypos\": 7,\n      \"shells\": [\n        2,\n        8,\n        18,\n        32,\n        18,\n        8,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 4f14 5d10 6p6 7s2\",\n      \"electron_configuration_semantic\": \"[Rn] 7s2\",\n      \"electron_affinity\": 9.6485,\n      \"electronegativity_pauling\": 0.9,\n      \"ionization_energies\": [\n        509.3,\n        979\n      ],\n      \"cpk-hex\": \"007d00\"\n    },\n    {\n      \"name\": \"Actinium\",\n      \"appearance\": null,\n      \"atomic_mass\": 227,\n      \"boil\": 3500,\n      \"category\": \"actinide\",\n      \"color\": null,\n      \"density\": 10,\n      \"discovered_by\": \"Friedrich Oskar Giesel\",\n      \"melt\": 1500,\n      \"molar_heat\": 27.2,\n      \"named_by\": null,\n      \"number\": 89,\n      \"period\": 7,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Actinium\",\n      \"spectral_img\": null,\n      \"summary\": \"Actinium is a radioactive chemical element with symbol Ac (not to be confused with the abbreviation for an acetyl group) and atomic number 89, which was discovered in 1899. It was the first non-primordial radioactive element to be isolated. Polonium, radium and radon were observed before actinium, but they were not isolated until 1902.\",\n      \"symbol\": \"Ac\",\n      \"xpos\": 3,\n      \"ypos\": 10,\n      \"shells\": [\n        2,\n        8,\n        18,\n        32,\n        18,\n        9,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 4f14 5d10 6p6 7s2 6d1\",\n      \"electron_configuration_semantic\": \"[Rn] 6d1 7s2\",\n      \"electron_affinity\": 33.77,\n      \"electronegativity_pauling\": 1.1,\n      \"ionization_energies\": [\n        499,\n        1170\n      ],\n      \"cpk-hex\": \"70abfa\"\n    },\n    {\n      \"name\": \"Thorium\",\n      \"appearance\": \"silvery, often with black tarnish\",\n      \"atomic_mass\": 232.03774,\n      \"boil\": 5061,\n      \"category\": \"actinide\",\n      \"color\": null,\n      \"density\": 11.724,\n      \"discovered_by\": \"Jöns Jakob Berzelius\",\n      \"melt\": 2023,\n      \"molar_heat\": 26.23,\n      \"named_by\": null,\n      \"number\": 90,\n      \"period\": 7,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Thorium\",\n      \"spectral_img\": null,\n      \"summary\": \"Thorium is a chemical element with symbol Th and atomic number 90. A radioactive actinide metal, thorium is one of only two significantly radioactive elements that still occur naturally in large quantities as a primordial element (the other being uranium). It was discovered in 1828 by the Norwegian Reverend and amateur mineralogist Morten Thrane Esmark and identified by the Swedish chemist Jöns Jakob Berzelius, who named it after Thor, the Norse god of thunder.\",\n      \"symbol\": \"Th\",\n      \"xpos\": 4,\n      \"ypos\": 10,\n      \"shells\": [\n        2,\n        8,\n        18,\n        32,\n        18,\n        10,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 4f14 5d10 6p6 7s2 6d2\",\n      \"electron_configuration_semantic\": \"[Rn] 6d2 7s2\",\n      \"electron_affinity\": 112.72,\n      \"electronegativity_pauling\": 1.3,\n      \"ionization_energies\": [\n        587,\n        1110,\n        1930,\n        2780\n      ],\n      \"cpk-hex\": \"00baff\"\n    },\n    {\n      \"name\": \"Protactinium\",\n      \"appearance\": \"bright, silvery metallic luster\",\n      \"atomic_mass\": 231.035882,\n      \"boil\": 4300,\n      \"category\": \"actinide\",\n      \"color\": null,\n      \"density\": 15.37,\n      \"discovered_by\": \"William Crookes\",\n      \"melt\": 1841,\n      \"molar_heat\": null,\n      \"named_by\": \"Otto Hahn\",\n      \"number\": 91,\n      \"period\": 7,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Protactinium\",\n      \"spectral_img\": null,\n      \"summary\": \"Protactinium is a chemical element with symbol Pa and atomic number 91. It is a dense, silvery-gray metal which readily reacts with oxygen, water vapor and inorganic acids. It forms various chemical compounds where protactinium is usually present in the oxidation state +5, but can also assume +4 and even +2 or +3 states.\",\n      \"symbol\": \"Pa\",\n      \"xpos\": 5,\n      \"ypos\": 10,\n      \"shells\": [\n        2,\n        8,\n        18,\n        32,\n        20,\n        9,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 4f14 5d10 6p6 7s2 5f2 6d1\",\n      \"electron_configuration_semantic\": \"[Rn] 5f2 6d1 7s2\",\n      \"electron_affinity\": 53.03,\n      \"electronegativity_pauling\": 1.5,\n      \"ionization_energies\": [\n        568\n      ],\n      \"cpk-hex\": \"00a1ff\"\n    },\n    {\n      \"name\": \"Uranium\",\n      \"appearance\": null,\n      \"atomic_mass\": 238.028913,\n      \"boil\": 4404,\n      \"category\": \"actinide\",\n      \"color\": null,\n      \"density\": 19.1,\n      \"discovered_by\": \"Martin Heinrich Klaproth\",\n      \"melt\": 1405.3,\n      \"molar_heat\": 27.665,\n      \"named_by\": null,\n      \"number\": 92,\n      \"period\": 7,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Uranium\",\n      \"spectral_img\": null,\n      \"summary\": \"Uranium is a chemical element with symbol U and atomic number 92. It is a silvery-white metal in the actinide series of the periodic table. A uranium atom has 92 protons and 92 electrons, of which 6 are valence electrons.\",\n      \"symbol\": \"U\",\n      \"xpos\": 6,\n      \"ypos\": 10,\n      \"shells\": [\n        2,\n        8,\n        18,\n        32,\n        21,\n        9,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 4f14 5d10 6p6 7s2 5f3 6d1\",\n      \"electron_configuration_semantic\": \"[Rn] 5f3 6d1 7s2\",\n      \"electron_affinity\": 50.94,\n      \"electronegativity_pauling\": 1.38,\n      \"ionization_energies\": [\n        597.6,\n        1420\n      ],\n      \"cpk-hex\": \"008fff\"\n    },\n    {\n      \"name\": \"Neptunium\",\n      \"appearance\": \"silvery metallic\",\n      \"atomic_mass\": 237,\n      \"boil\": 4447,\n      \"category\": \"actinide\",\n      \"color\": null,\n      \"density\": 20.45,\n      \"discovered_by\": \"Edwin McMillan\",\n      \"melt\": 912,\n      \"molar_heat\": 29.46,\n      \"named_by\": null,\n      \"number\": 93,\n      \"period\": 7,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Neptunium\",\n      \"spectral_img\": null,\n      \"summary\": \"Neptunium is a chemical element with symbol Np and atomic number 93. A radioactive actinide metal, neptunium is the first transuranic element. Its position in the periodic table just after uranium, named after the planet Uranus, led to it being named after Neptune, the next planet beyond Uranus.\",\n      \"symbol\": \"Np\",\n      \"xpos\": 7,\n      \"ypos\": 10,\n      \"shells\": [\n        2,\n        8,\n        18,\n        32,\n        22,\n        9,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 4f14 5d10 6p6 7s2 5f4 6d1\",\n      \"electron_configuration_semantic\": \"[Rn] 5f4 6d1 7s2\",\n      \"electron_affinity\": 45.85,\n      \"electronegativity_pauling\": 1.36,\n      \"ionization_energies\": [\n        604.5\n      ],\n      \"cpk-hex\": \"0080ff\"\n    },\n    {\n      \"name\": \"Plutonium\",\n      \"appearance\": \"silvery white, tarnishing to dark gray in air\",\n      \"atomic_mass\": 244,\n      \"boil\": 3505,\n      \"category\": \"actinide\",\n      \"color\": null,\n      \"density\": 19.816,\n      \"discovered_by\": \"Glenn T. Seaborg\",\n      \"melt\": 912.5,\n      \"molar_heat\": 35.5,\n      \"named_by\": null,\n      \"number\": 94,\n      \"period\": 7,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Plutonium\",\n      \"spectral_img\": null,\n      \"summary\": \"Plutonium is a transuranic radioactive chemical element with symbol Pu and atomic number 94. It is an actinide metal of silvery-gray appearance that tarnishes when exposed to air, and forms a dull coating when oxidized. The element normally exhibits six allotropes and four oxidation states.\",\n      \"symbol\": \"Pu\",\n      \"xpos\": 8,\n      \"ypos\": 10,\n      \"shells\": [\n        2,\n        8,\n        18,\n        32,\n        24,\n        8,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 4f14 5d10 6p6 7s2 5f6\",\n      \"electron_configuration_semantic\": \"[Rn] 5f6 7s2\",\n      \"electron_affinity\": -48.33,\n      \"electronegativity_pauling\": 1.28,\n      \"ionization_energies\": [\n        584.7\n      ],\n      \"cpk-hex\": \"006bff\"\n    },\n    {\n      \"name\": \"Americium\",\n      \"appearance\": \"silvery white\",\n      \"atomic_mass\": 243,\n      \"boil\": 2880,\n      \"category\": \"actinide\",\n      \"color\": null,\n      \"density\": 12,\n      \"discovered_by\": \"Glenn T. Seaborg\",\n      \"melt\": 1449,\n      \"molar_heat\": 62.7,\n      \"named_by\": null,\n      \"number\": 95,\n      \"period\": 7,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Americium\",\n      \"spectral_img\": \"https://en.wikipedia.org/wiki/File:Americium_spectrum_visible.png\",\n      \"summary\": \"Americium is a radioactive transuranic chemical element with symbol Am and atomic number 95. This member of the actinide series is located in the periodic table under the lanthanide element europium, and thus by analogy was named after the Americas. Americium was first produced in 1944 by the group of Glenn T.Seaborg from Berkeley, California, at the metallurgical laboratory of University of Chicago.\",\n      \"symbol\": \"Am\",\n      \"xpos\": 9,\n      \"ypos\": 10,\n      \"shells\": [\n        2,\n        8,\n        18,\n        32,\n        25,\n        8,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 4f14 5d10 6p6 7s2 5f7\",\n      \"electron_configuration_semantic\": \"[Rn] 5f7 7s2\",\n      \"electron_affinity\": 9.93,\n      \"electronegativity_pauling\": 1.13,\n      \"ionization_energies\": [\n        578\n      ],\n      \"cpk-hex\": \"545cf2\"\n    },\n    {\n      \"name\": \"Curium\",\n      \"appearance\": \"silvery metallic, glows purple in the dark\",\n      \"atomic_mass\": 247,\n      \"boil\": 3383,\n      \"category\": \"actinide\",\n      \"color\": null,\n      \"density\": 13.51,\n      \"discovered_by\": \"Glenn T. Seaborg\",\n      \"melt\": 1613,\n      \"molar_heat\": null,\n      \"named_by\": null,\n      \"number\": 96,\n      \"period\": 7,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Curium\",\n      \"spectral_img\": null,\n      \"summary\": \"Curium is a transuranic radioactive chemical element with symbol Cm and atomic number 96. This element of the actinide series was named after Marie and Pierre Curie – both were known for their research on radioactivity. Curium was first intentionally produced and identified in July 1944 by the group of Glenn T. Seaborg at the University of California, Berkeley.\",\n      \"symbol\": \"Cm\",\n      \"xpos\": 10,\n      \"ypos\": 10,\n      \"shells\": [\n        2,\n        8,\n        18,\n        32,\n        25,\n        9,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 4f14 5d10 6p6 7s2 5f7 6d1\",\n      \"electron_configuration_semantic\": \"[Rn] 5f7 6d1 7s2\",\n      \"electron_affinity\": 27.17,\n      \"electronegativity_pauling\": 1.28,\n      \"ionization_energies\": [\n        581\n      ],\n      \"cpk-hex\": \"785ce3\"\n    },\n    {\n      \"name\": \"Berkelium\",\n      \"appearance\": \"silvery\",\n      \"atomic_mass\": 247,\n      \"boil\": 2900,\n      \"category\": \"actinide\",\n      \"color\": null,\n      \"density\": 14.78,\n      \"discovered_by\": \"Lawrence Berkeley National Laboratory\",\n      \"melt\": 1259,\n      \"molar_heat\": null,\n      \"named_by\": null,\n      \"number\": 97,\n      \"period\": 7,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Berkelium\",\n      \"spectral_img\": null,\n      \"summary\": \"Berkelium is a transuranic radioactive chemical element with symbol Bk and atomic number 97. It is a member of the actinide and transuranium element series. It is named after the city of Berkeley, California, the location of the University of California Radiation Laboratory where it was discovered in December 1949.\",\n      \"symbol\": \"Bk\",\n      \"xpos\": 11,\n      \"ypos\": 10,\n      \"shells\": [\n        2,\n        8,\n        18,\n        32,\n        27,\n        8,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 4f14 5d10 6p6 7s2 5f9\",\n      \"electron_configuration_semantic\": \"[Rn] 5f9 7s2\",\n      \"electron_affinity\": -165.24,\n      \"electronegativity_pauling\": 1.3,\n      \"ionization_energies\": [\n        601\n      ],\n      \"cpk-hex\": \"8a4fe3\"\n    },\n    {\n      \"name\": \"Californium\",\n      \"appearance\": \"silvery\",\n      \"atomic_mass\": 251,\n      \"boil\": 1743,\n      \"category\": \"actinide\",\n      \"color\": null,\n      \"density\": 15.1,\n      \"discovered_by\": \"Lawrence Berkeley National Laboratory\",\n      \"melt\": 1173,\n      \"molar_heat\": null,\n      \"named_by\": null,\n      \"number\": 98,\n      \"period\": 7,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Californium\",\n      \"spectral_img\": null,\n      \"summary\": \"Californium is a radioactive metallic chemical element with symbol Cf and atomic number 98. The element was first made in 1950 at the University of California Radiation Laboratory in Berkeley, by bombarding curium with alpha particles (helium-4 ions). It is an actinide element, the sixth transuranium element to be synthesized, and has the second-highest atomic mass of all the elements that have been produced in amounts large enough to see with the unaided eye (after einsteinium).\",\n      \"symbol\": \"Cf\",\n      \"xpos\": 12,\n      \"ypos\": 10,\n      \"shells\": [\n        2,\n        8,\n        18,\n        32,\n        28,\n        8,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 4f14 5d10 6p6 7s2 5f10\",\n      \"electron_configuration_semantic\": \"[Rn] 5f10 7s2\",\n      \"electron_affinity\": -97.31,\n      \"electronegativity_pauling\": 1.3,\n      \"ionization_energies\": [\n        608\n      ],\n      \"cpk-hex\": \"a136d4\"\n    },\n    {\n      \"name\": \"Einsteinium\",\n      \"appearance\": \"silver-colored\",\n      \"atomic_mass\": 252,\n      \"boil\": 1269,\n      \"category\": \"actinide\",\n      \"color\": null,\n      \"density\": 8.84,\n      \"discovered_by\": \"Lawrence Berkeley National Laboratory\",\n      \"melt\": 1133,\n      \"molar_heat\": null,\n      \"named_by\": null,\n      \"number\": 99,\n      \"period\": 7,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Einsteinium\",\n      \"spectral_img\": null,\n      \"summary\": \"Einsteinium is a synthetic element with symbol Es and atomic number 99. It is the seventh transuranic element, and an actinide. Einsteinium was discovered as a component of the debris of the first hydrogen bomb explosion in 1952, and named after Albert Einstein.\",\n      \"symbol\": \"Es\",\n      \"xpos\": 13,\n      \"ypos\": 10,\n      \"shells\": [\n        2,\n        8,\n        18,\n        32,\n        29,\n        8,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 4f14 5d10 6p6 7s2 5f11\",\n      \"electron_configuration_semantic\": \"[Rn] 5f11 7s2\",\n      \"electron_affinity\": -28.6,\n      \"electronegativity_pauling\": 1.3,\n      \"ionization_energies\": [\n        619\n      ],\n      \"cpk-hex\": \"b31fd4\"\n    },\n    {\n      \"name\": \"Fermium\",\n      \"appearance\": null,\n      \"atomic_mass\": 257,\n      \"boil\": null,\n      \"category\": \"actinide\",\n      \"color\": null,\n      \"density\": null,\n      \"discovered_by\": \"Lawrence Berkeley National Laboratory\",\n      \"melt\": 1800,\n      \"molar_heat\": null,\n      \"named_by\": null,\n      \"number\": 100,\n      \"period\": 7,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Fermium\",\n      \"spectral_img\": null,\n      \"summary\": \"Fermium is a synthetic element with symbol Fm and atomic number 100. It is a member of the actinide series. It is the heaviest element that can be formed by neutron bombardment of lighter elements, and hence the last element that can be prepared in macroscopic quantities, although pure fermium metal has not yet been prepared.\",\n      \"symbol\": \"Fm\",\n      \"xpos\": 14,\n      \"ypos\": 10,\n      \"shells\": [\n        2,\n        8,\n        18,\n        32,\n        30,\n        8,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 4f14 5d10 6p6 7s2 5f12\",\n      \"electron_configuration_semantic\": \"[Rn] 5f12 7s2\",\n      \"electron_affinity\": 33.96,\n      \"electronegativity_pauling\": 1.3,\n      \"ionization_energies\": [\n        627\n      ],\n      \"cpk-hex\": \"b31fba\"\n    },\n    {\n      \"name\": \"Mendelevium\",\n      \"appearance\": null,\n      \"atomic_mass\": 258,\n      \"boil\": null,\n      \"category\": \"actinide\",\n      \"color\": null,\n      \"density\": null,\n      \"discovered_by\": \"Lawrence Berkeley National Laboratory\",\n      \"melt\": 1100,\n      \"molar_heat\": null,\n      \"named_by\": null,\n      \"number\": 101,\n      \"period\": 7,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Mendelevium\",\n      \"spectral_img\": null,\n      \"summary\": \"Mendelevium is a synthetic element with chemical symbol Md (formerly Mv) and atomic number 101. A metallic radioactive transuranic element in the actinide series, it is the first element that currently cannot be produced in macroscopic quantities through neutron bombardment of lighter elements. It is the antepenultimate actinide and the ninth transuranic element.\",\n      \"symbol\": \"Md\",\n      \"xpos\": 15,\n      \"ypos\": 10,\n      \"shells\": [\n        2,\n        8,\n        18,\n        32,\n        31,\n        8,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 4f14 5d10 6p6 7s2 5f13\",\n      \"electron_configuration_semantic\": \"[Rn] 5f13 7s2\",\n      \"electron_affinity\": 93.91,\n      \"electronegativity_pauling\": 1.3,\n      \"ionization_energies\": [\n        635\n      ],\n      \"cpk-hex\": \"b30da6\"\n    },\n    {\n      \"name\": \"Nobelium\",\n      \"appearance\": null,\n      \"atomic_mass\": 259,\n      \"boil\": null,\n      \"category\": \"actinide\",\n      \"color\": null,\n      \"density\": null,\n      \"discovered_by\": \"Joint Institute for Nuclear Research\",\n      \"melt\": 1100,\n      \"molar_heat\": null,\n      \"named_by\": null,\n      \"number\": 102,\n      \"period\": 7,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Nobelium\",\n      \"spectral_img\": null,\n      \"summary\": \"Nobelium is a synthetic chemical element with symbol No and atomic number 102. It is named in honor of Alfred Nobel, the inventor of dynamite and benefactor of science. A radioactive metal, it is the tenth transuranic element and is the penultimate member of the actinide series.\",\n      \"symbol\": \"No\",\n      \"xpos\": 16,\n      \"ypos\": 10,\n      \"shells\": [\n        2,\n        8,\n        18,\n        32,\n        32,\n        8,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 4f14 5d10 6p6 7s2 5f14\",\n      \"electron_configuration_semantic\": \"[Rn] 5f14 7s2\",\n      \"electron_affinity\": -223.22,\n      \"electronegativity_pauling\": 1.3,\n      \"ionization_energies\": [\n        642\n      ],\n      \"cpk-hex\": \"bd0d87\"\n    },\n    {\n      \"name\": \"Lawrencium\",\n      \"appearance\": null,\n      \"atomic_mass\": 266,\n      \"boil\": null,\n      \"category\": \"actinide\",\n      \"color\": null,\n      \"density\": null,\n      \"discovered_by\": \"Lawrence Berkeley National Laboratory\",\n      \"melt\": 1900,\n      \"molar_heat\": null,\n      \"named_by\": null,\n      \"number\": 103,\n      \"period\": 7,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Lawrencium\",\n      \"spectral_img\": null,\n      \"summary\": \"Lawrencium is a synthetic chemical element with chemical symbol Lr (formerly Lw) and atomic number 103. It is named in honor of Ernest Lawrence, inventor of the cyclotron, a device that was used to discover many artificial radioactive elements. A radioactive metal, lawrencium is the eleventh transuranic element and is also the final member of the actinide series.\",\n      \"symbol\": \"Lr\",\n      \"xpos\": 17,\n      \"ypos\": 10,\n      \"shells\": [\n        2,\n        8,\n        18,\n        32,\n        32,\n        8,\n        3\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 4f14 5d10 6p6 7s2 5f14 7p1\",\n      \"electron_configuration_semantic\": \"[Rn] 5f14 7s2 7p1\",\n      \"electron_affinity\": -30.04,\n      \"electronegativity_pauling\": 1.3,\n      \"ionization_energies\": [\n        470\n      ],\n      \"cpk-hex\": \"c70066\"\n    },\n    {\n      \"name\": \"Rutherfordium\",\n      \"appearance\": null,\n      \"atomic_mass\": 267,\n      \"boil\": 5800,\n      \"category\": \"transition metal\",\n      \"color\": null,\n      \"density\": 23.2,\n      \"discovered_by\": \"Joint Institute for Nuclear Research\",\n      \"melt\": 2400,\n      \"molar_heat\": null,\n      \"named_by\": null,\n      \"number\": 104,\n      \"period\": 7,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Rutherfordium\",\n      \"spectral_img\": null,\n      \"summary\": \"Rutherfordium is a chemical element with symbol Rf and atomic number 104, named in honor of physicist Ernest Rutherford. It is a synthetic element (an element that can be created in a laboratory but is not found in nature) and radioactive; the most stable known isotope, 267Rf, has a half-life of approximately 1.3 hours. In the periodic table of the elements, it is a d - block element and the second of the fourth - row transition elements.\",\n      \"symbol\": \"Rf\",\n      \"xpos\": 4,\n      \"ypos\": 7,\n      \"shells\": [\n        2,\n        8,\n        18,\n        32,\n        32,\n        10,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 4f14 5d10 6p6 7s2 5f14 6d2\",\n      \"electron_configuration_semantic\": \"[Rn] 5f14 6d2 7s2\",\n      \"electron_affinity\": null,\n      \"electronegativity_pauling\": null,\n      \"ionization_energies\": [\n        580\n      ],\n      \"cpk-hex\": \"cc0059\"\n    },\n    {\n      \"name\": \"Dubnium\",\n      \"appearance\": null,\n      \"atomic_mass\": 268,\n      \"boil\": null,\n      \"category\": \"transition metal\",\n      \"color\": null,\n      \"density\": 29.3,\n      \"discovered_by\": \"Joint Institute for Nuclear Research\",\n      \"melt\": null,\n      \"molar_heat\": null,\n      \"named_by\": null,\n      \"number\": 105,\n      \"period\": 7,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Dubnium\",\n      \"spectral_img\": null,\n      \"summary\": \"Dubnium is a chemical element with symbol Db and atomic number 105. It is named after the town of Dubna in Russia (north of Moscow), where it was first produced. It is a synthetic element (an element that can be created in a laboratory but is not found in nature) and radioactive; the most stable known isotope, dubnium-268, has a half-life of approximately 28 hours.\",\n      \"symbol\": \"Db\",\n      \"xpos\": 5,\n      \"ypos\": 7,\n      \"shells\": [\n        2,\n        8,\n        18,\n        32,\n        32,\n        11,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 4f14 5d10 6p6 7s2 5f14 6d3\",\n      \"electron_configuration_semantic\": \"*[Rn] 5f14 6d3 7s2\",\n      \"electron_affinity\": null,\n      \"electronegativity_pauling\": null,\n      \"ionization_energies\": [],\n      \"cpk-hex\": \"d1004f\"\n    },\n    {\n      \"name\": \"Seaborgium\",\n      \"appearance\": null,\n      \"atomic_mass\": 269,\n      \"boil\": null,\n      \"category\": \"transition metal\",\n      \"color\": null,\n      \"density\": 35,\n      \"discovered_by\": \"Lawrence Berkeley National Laboratory\",\n      \"melt\": null,\n      \"molar_heat\": null,\n      \"named_by\": null,\n      \"number\": 106,\n      \"period\": 7,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Seaborgium\",\n      \"spectral_img\": null,\n      \"summary\": \"Seaborgium is a synthetic element with symbol Sg and atomic number 106. Its most stable isotope 271Sg has a half-life of 1.9 minutes. A more recently discovered isotope 269Sg has a potentially slightly longer half-life (ca.\",\n      \"symbol\": \"Sg\",\n      \"xpos\": 6,\n      \"ypos\": 7,\n      \"shells\": [\n        2,\n        8,\n        18,\n        32,\n        32,\n        12,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 4f14 5d10 6p6 7s2 5f14 6d4\",\n      \"electron_configuration_semantic\": \"*[Rn] 5f14 6d4 7s2\",\n      \"electron_affinity\": null,\n      \"electronegativity_pauling\": null,\n      \"ionization_energies\": [],\n      \"cpk-hex\": \"d90045\"\n    },\n    {\n      \"name\": \"Bohrium\",\n      \"appearance\": null,\n      \"atomic_mass\": 270,\n      \"boil\": null,\n      \"category\": \"transition metal\",\n      \"color\": null,\n      \"density\": 37.1,\n      \"discovered_by\": \"Gesellschaft für Schwerionenforschung\",\n      \"melt\": null,\n      \"molar_heat\": null,\n      \"named_by\": null,\n      \"number\": 107,\n      \"period\": 7,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Bohrium\",\n      \"spectral_img\": null,\n      \"summary\": \"Bohrium is a chemical element with symbol Bh and atomic number 107. It is named after Danish physicist Niels Bohr. It is a synthetic element (an element that can be created in a laboratory but is not found in nature) and radioactive; the most stable known isotope, 270Bh, has a half-life of approximately 61 seconds.\",\n      \"symbol\": \"Bh\",\n      \"xpos\": 7,\n      \"ypos\": 7,\n      \"shells\": [\n        2,\n        8,\n        18,\n        32,\n        32,\n        13,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 4f14 5d10 6p6 7s2 5f14 6d5\",\n      \"electron_configuration_semantic\": \"*[Rn] 5f14 6d5 7s2\",\n      \"electron_affinity\": null,\n      \"electronegativity_pauling\": null,\n      \"ionization_energies\": [],\n      \"cpk-hex\": \"e00038\"\n    },\n    {\n      \"name\": \"Hassium\",\n      \"appearance\": null,\n      \"atomic_mass\": 269,\n      \"boil\": null,\n      \"category\": \"transition metal\",\n      \"color\": null,\n      \"density\": 40.7,\n      \"discovered_by\": \"Gesellschaft für Schwerionenforschung\",\n      \"melt\": 126,\n      \"molar_heat\": null,\n      \"named_by\": null,\n      \"number\": 108,\n      \"period\": 7,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Hassium\",\n      \"spectral_img\": null,\n      \"summary\": \"Hassium is a chemical element with symbol Hs and atomic number 108, named after the German state of Hesse. It is a synthetic element (an element that can be created in a laboratory but is not found in nature) and radioactive; the most stable known isotope, 269Hs, has a half-life of approximately 9.7 seconds, although an unconfirmed metastable state, 277mHs, may have a longer half-life of about 130 seconds. More than 100 atoms of hassium have been synthesized to date.\",\n      \"symbol\": \"Hs\",\n      \"xpos\": 8,\n      \"ypos\": 7,\n      \"shells\": [\n        2,\n        8,\n        18,\n        32,\n        32,\n        14,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 4f14 5d10 6p6 7s2 5f14 6d6\",\n      \"electron_configuration_semantic\": \"*[Rn] 5f14 6d6 7s2\",\n      \"electron_affinity\": null,\n      \"electronegativity_pauling\": null,\n      \"ionization_energies\": [],\n      \"cpk-hex\": \"e6002e\"\n    },\n    {\n      \"name\": \"Meitnerium\",\n      \"appearance\": null,\n      \"atomic_mass\": 278,\n      \"boil\": null,\n      \"category\": \"unknown, probably transition metal\",\n      \"color\": null,\n      \"density\": 37.4,\n      \"discovered_by\": \"Gesellschaft für Schwerionenforschung\",\n      \"melt\": null,\n      \"molar_heat\": null,\n      \"named_by\": null,\n      \"number\": 109,\n      \"period\": 7,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Meitnerium\",\n      \"spectral_img\": null,\n      \"summary\": \"Meitnerium is a chemical element with symbol Mt and atomic number 109. It is an extremely radioactive synthetic element (an element not found in nature that can be created in a laboratory). The most stable known isotope, meitnerium-278, has a half-life of 7.6 seconds.\",\n      \"symbol\": \"Mt\",\n      \"xpos\": 9,\n      \"ypos\": 7,\n      \"shells\": [\n        2,\n        8,\n        18,\n        32,\n        32,\n        15,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 4f14 5d10 6p6 7s2 5f14 6d7\",\n      \"electron_configuration_semantic\": \"*[Rn] 5f14 6d7 7s2\",\n      \"electron_affinity\": null,\n      \"electronegativity_pauling\": null,\n      \"ionization_energies\": [],\n      \"cpk-hex\": \"eb0026\"\n    },\n    {\n      \"name\": \"Darmstadtium\",\n      \"appearance\": null,\n      \"atomic_mass\": 281,\n      \"boil\": null,\n      \"category\": \"unknown, probably transition metal\",\n      \"color\": null,\n      \"density\": 34.8,\n      \"discovered_by\": \"Gesellschaft für Schwerionenforschung\",\n      \"melt\": null,\n      \"molar_heat\": null,\n      \"named_by\": null,\n      \"number\": 110,\n      \"period\": 7,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Darmstadtium\",\n      \"spectral_img\": null,\n      \"summary\": \"Darmstadtium is a chemical element with symbol Ds and atomic number 110. It is an extremely radioactive synthetic element. The most stable known isotope, darmstadtium-281, has a half-life of approximately 10 seconds.\",\n      \"symbol\": \"Ds\",\n      \"xpos\": 10,\n      \"ypos\": 7,\n      \"shells\": [\n        2,\n        8,\n        18,\n        32,\n        32,\n        16,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 4f14 5d10 6p6 7s2 5f14 6d8\",\n      \"electron_configuration_semantic\": \"*[Rn] 5f14 6d9 7s1\",\n      \"electron_affinity\": null,\n      \"electronegativity_pauling\": null,\n      \"ionization_energies\": [],\n      \"cpk-hex\": null\n    },\n    {\n      \"name\": \"Roentgenium\",\n      \"appearance\": null,\n      \"atomic_mass\": 282,\n      \"boil\": null,\n      \"category\": \"unknown, probably transition metal\",\n      \"color\": null,\n      \"density\": 28.7,\n      \"discovered_by\": \"Gesellschaft für Schwerionenforschung\",\n      \"melt\": null,\n      \"molar_heat\": null,\n      \"named_by\": null,\n      \"number\": 111,\n      \"period\": 7,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Roentgenium\",\n      \"spectral_img\": null,\n      \"summary\": \"Roentgenium is a chemical element with symbol Rg and atomic number 111. It is an extremely radioactive synthetic element (an element that can be created in a laboratory but is not found in nature); the most stable known isotope, roentgenium-282, has a half-life of 2.1 minutes. Roentgenium was first created in 1994 by the GSI Helmholtz Centre for Heavy Ion Research near Darmstadt, Germany.\",\n      \"symbol\": \"Rg\",\n      \"xpos\": 11,\n      \"ypos\": 7,\n      \"shells\": [\n        2,\n        8,\n        18,\n        32,\n        32,\n        17,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 4f14 5d10 6p6 7s2 5f14 6d9\",\n      \"electron_configuration_semantic\": \"*[Rn] 5f14 6d10 7s1\",\n      \"electron_affinity\": 151,\n      \"electronegativity_pauling\": null,\n      \"ionization_energies\": [],\n      \"cpk-hex\": null\n    },\n    {\n      \"name\": \"Copernicium\",\n      \"appearance\": null,\n      \"atomic_mass\": 285,\n      \"boil\": 3570,\n      \"category\": \"transition metal\",\n      \"color\": null,\n      \"density\": 23.7,\n      \"discovered_by\": \"Gesellschaft für Schwerionenforschung\",\n      \"melt\": null,\n      \"molar_heat\": null,\n      \"named_by\": null,\n      \"number\": 112,\n      \"period\": 7,\n      \"phase\": \"Gas\",\n      \"source\": \"https://en.wikipedia.org/wiki/Copernicium\",\n      \"spectral_img\": null,\n      \"summary\": \"Copernicium is a chemical element with symbol Cn and atomic number 112. It is an extremely radioactive synthetic element that can only be created in a laboratory. The most stable known isotope, copernicium-285, has a half-life of approximately 29 seconds, but it is possible that this copernicium isotope may have a nuclear isomer with a longer half-life, 8.9 min.\",\n      \"symbol\": \"Cn\",\n      \"xpos\": 12,\n      \"ypos\": 7,\n      \"shells\": [\n        2,\n        8,\n        18,\n        32,\n        32,\n        18,\n        2\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 4f14 5d10 6p6 7s2 5f14 6d10\",\n      \"electron_configuration_semantic\": \"*[Rn] 5f14 6d10 7s2\",\n      \"electron_affinity\": null,\n      \"electronegativity_pauling\": null,\n      \"ionization_energies\": [],\n      \"cpk-hex\": null\n    },\n    {\n      \"name\": \"Nihonium\",\n      \"appearance\": null,\n      \"atomic_mass\": 286,\n      \"boil\": 1430,\n      \"category\": \"unknown, probably transition metal\",\n      \"color\": null,\n      \"density\": 16,\n      \"discovered_by\": \"RIKEN\",\n      \"melt\": 700,\n      \"molar_heat\": null,\n      \"named_by\": null,\n      \"number\": 113,\n      \"period\": 7,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Ununtrium\",\n      \"spectral_img\": null,\n      \"summary\": \"Nihonium is a chemical element with atomic number 113. It has a symbol Nh. It is a synthetic element (an element that can be created in a laboratory but is not found in nature) and is extremely radioactive; its most stable known isotope, nihonium-286, has a half-life of 20 seconds.\",\n      \"symbol\": \"Nh\",\n      \"xpos\": 13,\n      \"ypos\": 7,\n      \"shells\": [\n        2,\n        8,\n        18,\n        32,\n        32,\n        18,\n        3\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 4f14 5d10 6p6 7s2 5f14 6d10 7p1\",\n      \"electron_configuration_semantic\": \"*[Rn] 5f14 6d10 7s2 7p1\",\n      \"electron_affinity\": 66.6,\n      \"electronegativity_pauling\": null,\n      \"ionization_energies\": [],\n      \"cpk-hex\": null\n    },\n    {\n      \"name\": \"Flerovium\",\n      \"appearance\": null,\n      \"atomic_mass\": 289,\n      \"boil\": 420,\n      \"category\": \"post-transition metal\",\n      \"color\": null,\n      \"density\": 14,\n      \"discovered_by\": \"Joint Institute for Nuclear Research\",\n      \"melt\": 340,\n      \"molar_heat\": null,\n      \"named_by\": null,\n      \"number\": 114,\n      \"period\": 7,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Flerovium\",\n      \"spectral_img\": null,\n      \"summary\": \"Flerovium is a superheavy artificial chemical element with symbol Fl and atomic number 114. It is an extremely radioactive synthetic element. The element is named after the Flerov Laboratory of Nuclear Reactions of the Joint Institute for Nuclear Research in Dubna, Russia, where the element was discovered in 1998.\",\n      \"symbol\": \"Fl\",\n      \"xpos\": 14,\n      \"ypos\": 7,\n      \"shells\": [\n        2,\n        8,\n        18,\n        32,\n        32,\n        18,\n        4\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 4f14 5d10 6p6 7s2 5f14 6d10 7p2\",\n      \"electron_configuration_semantic\": \"*[Rn] 5f14 6d10 7s2 7p2\",\n      \"electron_affinity\": null,\n      \"electronegativity_pauling\": null,\n      \"ionization_energies\": [],\n      \"cpk-hex\": null\n    },\n    {\n      \"name\": \"Moscovium\",\n      \"appearance\": null,\n      \"atomic_mass\": 289,\n      \"boil\": 1400,\n      \"category\": \"unknown, probably post-transition metal\",\n      \"color\": null,\n      \"density\": 13.5,\n      \"discovered_by\": \"Joint Institute for Nuclear Research\",\n      \"melt\": 670,\n      \"molar_heat\": null,\n      \"named_by\": null,\n      \"number\": 115,\n      \"period\": 7,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Ununpentium\",\n      \"spectral_img\": null,\n      \"summary\": \"Moscovium is the name of a synthetic superheavy element in the periodic table that has the symbol Mc and has the atomic number 115. It is an extremely radioactive element; its most stable known isotope, moscovium-289, has a half-life of only 220 milliseconds. It is also known as eka-bismuth or simply element 115.\",\n      \"symbol\": \"Mc\",\n      \"xpos\": 15,\n      \"ypos\": 7,\n      \"shells\": [\n        2,\n        8,\n        18,\n        32,\n        32,\n        18,\n        5\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 4f14 5d10 6p6 7s2 5f14 6d10 7p3\",\n      \"electron_configuration_semantic\": \"*[Rn] 5f14 6d10 7s2 7p3\",\n      \"electron_affinity\": 35.3,\n      \"electronegativity_pauling\": null,\n      \"ionization_energies\": [],\n      \"cpk-hex\": null\n    },\n    {\n      \"name\": \"Livermorium\",\n      \"appearance\": null,\n      \"atomic_mass\": 293,\n      \"boil\": 1085,\n      \"category\": \"unknown, probably post-transition metal\",\n      \"color\": null,\n      \"density\": 12.9,\n      \"discovered_by\": \"Joint Institute for Nuclear Research\",\n      \"melt\": 709,\n      \"molar_heat\": null,\n      \"named_by\": null,\n      \"number\": 116,\n      \"period\": 7,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Livermorium\",\n      \"spectral_img\": null,\n      \"summary\": \"Livermorium is a synthetic superheavy element with symbol Lv and atomic number 116. It is an extremely radioactive element that has only been created in the laboratory and has not been observed in nature. The element is named after the Lawrence Livermore National Laboratory in the United States, which collaborated with the Joint Institute for Nuclear Research in Dubna, Russia to discover livermorium in 2000.\",\n      \"symbol\": \"Lv\",\n      \"xpos\": 16,\n      \"ypos\": 7,\n      \"shells\": [\n        2,\n        8,\n        18,\n        32,\n        32,\n        18,\n        6\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 4f14 5d10 6p6 7s2 5f14 6d10 7p4\",\n      \"electron_configuration_semantic\": \"*[Rn] 5f14 6d10 7s2 7p4\",\n      \"electron_affinity\": 74.9,\n      \"electronegativity_pauling\": null,\n      \"ionization_energies\": [],\n      \"cpk-hex\": null\n    },\n    {\n      \"name\": \"Tennessine\",\n      \"appearance\": null,\n      \"atomic_mass\": 294,\n      \"boil\": 883,\n      \"category\": \"unknown, probably metalloid\",\n      \"color\": null,\n      \"density\": 7.17,\n      \"discovered_by\": \"Joint Institute for Nuclear Research\",\n      \"melt\": 723,\n      \"molar_heat\": null,\n      \"named_by\": null,\n      \"number\": 117,\n      \"period\": 7,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Tennessine\",\n      \"spectral_img\": null,\n      \"summary\": \"Tennessine is a superheavy artificial chemical element with an atomic number of 117 and a symbol of Ts. Also known as eka-astatine or element 117, it is the second-heaviest known element and penultimate element of the 7th period of the periodic table. As of 2016, fifteen tennessine atoms have been observed:six when it was first synthesized in 2010, seven in 2012, and two in 2014.\",\n      \"symbol\": \"Ts\",\n      \"xpos\": 17,\n      \"ypos\": 7,\n      \"shells\": [\n        2,\n        8,\n        18,\n        32,\n        32,\n        18,\n        7\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 4f14 5d10 6p6 7s2 5f14 6d10 7p5\",\n      \"electron_configuration_semantic\": \"*[Rn] 5f14 6d10 7s2 7p5\",\n      \"electron_affinity\": 165.9,\n      \"electronegativity_pauling\": null,\n      \"ionization_energies\": [],\n      \"cpk-hex\": null\n    },\n    {\n      \"name\": \"Oganesson\",\n      \"appearance\": null,\n      \"atomic_mass\": 294,\n      \"boil\": 350,\n      \"category\": \"unknown, predicted to be noble gas\",\n      \"color\": null,\n      \"density\": 4.95,\n      \"discovered_by\": \"Joint Institute for Nuclear Research\",\n      \"melt\": null,\n      \"molar_heat\": null,\n      \"named_by\": null,\n      \"number\": 118,\n      \"period\": 7,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Oganesson\",\n      \"spectral_img\": null,\n      \"summary\": \"Oganesson is IUPAC's name for the transactinide element with the atomic number 118 and element symbol Og. It is also known as eka-radon or element 118, and on the periodic table of the elements it is a p-block element and the last one of the 7th period. Oganesson is currently the only synthetic member of group 18.\",\n      \"symbol\": \"Og\",\n      \"xpos\": 18,\n      \"ypos\": 7,\n      \"shells\": [\n        2,\n        8,\n        18,\n        32,\n        32,\n        18,\n        8\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 4f14 5d10 6p6 7s2 5f14 6d10 7p6\",\n      \"electron_configuration_semantic\": \"*[Rn] 5f14 6d10 7s2 7p6\",\n      \"electron_affinity\": 5.40318,\n      \"electronegativity_pauling\": null,\n      \"ionization_energies\": [],\n      \"cpk-hex\": null\n    },\n    {\n      \"name\": \"Ununennium\",\n      \"appearance\": null,\n      \"atomic_mass\": 315,\n      \"boil\": 630,\n      \"category\": \"unknown, but predicted to be an alkali metal\",\n      \"color\": null,\n      \"density\": 3,\n      \"discovered_by\": \"GSI Helmholtz Centre for Heavy Ion Research\",\n      \"melt\": null,\n      \"molar_heat\": null,\n      \"named_by\": null,\n      \"number\": 119,\n      \"period\": 8,\n      \"phase\": \"Solid\",\n      \"source\": \"https://en.wikipedia.org/wiki/Ununennium\",\n      \"spectral_img\": null,\n      \"summary\": \"Ununennium, also known as eka-francium or simply element 119, is the hypothetical chemical element with symbol Uue and atomic number 119. Ununennium and Uue are the temporary systematic IUPAC name and symbol respectively, until a permanent name is decided upon. In the periodic table of the elements, it is expected to be an s-block element, an alkali metal, and the first element in the eighth period.\",\n      \"symbol\": \"Uue\",\n      \"xpos\": 1,\n      \"ypos\": 8,\n      \"shells\": [\n        2,\n        8,\n        18,\n        32,\n        32,\n        18,\n        8,\n        1\n      ],\n      \"electron_configuration\": \"1s2 2s2 2p6 3s2 3p6 4s2 3d10 4p6 5s2 4d10 5p6 6s2 4f14 5d10 6p6 7s2 5f14 6d10 7p6 8s1\",\n      \"electron_configuration_semantic\": \"*[Uuo] 8s1\",\n      \"electron_affinity\": 63.87,\n      \"electronegativity_pauling\": null,\n      \"ionization_energies\": [],\n      \"cpk-hex\": null\n    }\n  ]\n}\n"
  },
  {
    "path": "example/lib/responsive_app_layout.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:flutter_layout_grid/flutter_layout_grid.dart';\n\nvoid main() {\n  runApp(const ResponsiveLayoutApp());\n}\n\nclass ResponsiveLayoutApp extends StatelessWidget {\n  const ResponsiveLayoutApp({Key? key}) : super(key: key);\n\n  @override\n  Widget build(BuildContext context) {\n    return WidgetsApp(\n        color: Colors.white,\n        builder: (context, child) {\n          return LayoutBuilder(builder: (_, constraints) {\n            return ResponsiveLayout(viewportWidth: constraints.maxWidth);\n          });\n        });\n  }\n}\n\nclass ResponsiveLayout extends StatelessWidget {\n  const ResponsiveLayout({\n    Key? key,\n    required this.viewportWidth,\n  }) : super(key: key);\n\n  final double viewportWidth;\n\n  GridConfiguration computeGridConfig() {\n    if (viewportWidth > 700) {\n      // Desktop\n      return GridConfiguration(\n        areas: '''\n          header header  header\n          nav    content sidebar\n          nav    content ad\n          footer footer  footer\n        ''',\n        columnSizes: [186.px, 1.fr, 186.px],\n        rowSizes: [\n          144.px,\n          auto,\n          1.fr,\n          112.px,\n        ],\n      );\n    } else if (viewportWidth > 500) {\n      // Larger mobile\n      return GridConfiguration(\n        areas: '''\n          header  header\n          nav     nav\n          sidebar content\n          ad      footer\n        ''',\n        columnSizes: [1.fr, 3.fr],\n        rowSizes: [\n          104.px,\n          96.px,\n          1.fr,\n          72.px,\n        ],\n      );\n    } else {\n      // Small mobile\n      return GridConfiguration(\n        areas: '''\n          header\n          nav\n          content\n          sidebar\n          ad\n          footer\n        ''',\n        columnSizes: [1.fr],\n        rowSizes: [\n          96.px,\n          72.px,\n          1.fr,\n          72.px,\n          auto,\n          54.px,\n        ],\n      );\n    }\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    final gridConfig = computeGridConfig();\n    return Container(\n      color: Colors.grey[400],\n      child: LayoutGrid(\n        areas: gridConfig.areas,\n        // A number of extension methods are provided for concise track sizing\n        columnSizes: gridConfig.columnSizes,\n        rowSizes: gridConfig.rowSizes,\n        children: [\n          const Header().inGridArea('header'),\n          const Navigation().inGridArea('nav'),\n          const Content().inGridArea('content'),\n          const Sidebar().inGridArea('sidebar'),\n          const Footer().inGridArea('footer'),\n          const Ad().inGridArea('ad'),\n        ],\n      ),\n    );\n  }\n}\n\nclass GridConfiguration {\n  final String areas;\n  final List<TrackSize> columnSizes;\n  final List<TrackSize> rowSizes;\n  GridConfiguration(\n      {required this.areas, required this.columnSizes, required this.rowSizes});\n}\n\nclass Header extends StatelessWidget {\n  const Header({Key? key}) : super(key: key);\n\n  @override\n  Widget build(BuildContext context) => Container(color: Colors.red);\n}\n\nclass Navigation extends StatelessWidget {\n  const Navigation({Key? key}) : super(key: key);\n\n  @override\n  Widget build(BuildContext context) => Container(color: Colors.purple);\n}\n\nclass Content extends StatelessWidget {\n  const Content({Key? key}) : super(key: key);\n\n  @override\n  Widget build(BuildContext context) => Container(color: Colors.grey[300]);\n}\n\nclass Sidebar extends StatelessWidget {\n  const Sidebar({Key? key}) : super(key: key);\n\n  @override\n  Widget build(BuildContext context) =>\n      Container(color: Colors.grey[600], width: 184);\n}\n\nclass Footer extends StatelessWidget {\n  const Footer({Key? key}) : super(key: key);\n\n  @override\n  Widget build(BuildContext context) => Container(color: Colors.deepPurple);\n}\n\nclass Ad extends StatelessWidget {\n  const Ad({Key? key}) : super(key: key);\n\n  @override\n  Widget build(BuildContext context) => Container(color: Colors.deepOrange);\n}\n"
  },
  {
    "path": "example/lib/scrabble.dart",
    "content": "import 'dart:convert';\n\nimport 'package:flutter/material.dart';\nimport 'package:flutter_layout_grid/flutter_layout_grid.dart';\nimport 'package:google_fonts/google_fonts.dart';\n\nimport 'support/inner_shadow.dart';\n\nvoid main() {\n  runApp(const ScrabbleApp());\n}\n\nclass ScrabbleApp extends StatelessWidget {\n  const ScrabbleApp({Key? key}) : super(key: key);\n\n  @override\n  Widget build(BuildContext context) {\n    return WidgetsApp(\n      title: 'Layout Grid Scrabble Example',\n      debugShowCheckedModeBanner: false,\n      color: Colors.white,\n      builder: (context, child) => Container(\n        color: const Color(0xfffefdff),\n        child: Center(\n          child: ScrabbleBoard(\n            tiles: getTiles(),\n          ),\n        ),\n      ),\n    );\n  }\n}\n\nList<TileInfo> getTiles() {\n  const tileLayout = '''\n    .  .  .  .  .  .  .  .  .  .  .  .  .  .  .\n    .  .  .  .  .  .  .  .  .  .  .  .  .  .  .\n    .  .  .  .  .  .  .  .  G  .  .  .  .  .  .\n    .  .  .  .  .  .  .  .  R  .  .  .  .  .  .\n    .  .  .  .  .  .  .  .  E  .  .  .  .  .  .\n    .  .  .  .  .  .  .  .  A  .  .  G  .  .  .\n    .  .  .  .  .  F  L  U  T  T  E  R  .  .  .\n    .  .  .  W  .  .  A  H  .  .  .  I  S  .  .\n    .  .  .  O  .  .  Y  .  .  .  .  D  .  .  .\n    .  .  A  W  E  S  O  M  E  .  .  .  .  .  .\n    .  .  U  .  .  .  U  .  .  .  .  .  .  .  .\n    .  .  T  .  .  .  T  R  Y  .  .  .  .  .  .\n    .  N  O  W  .  .  .  .  .  .  .  .  .  .  .\n    .  .  .  .  .  .  .  .  .  .  .  .  .  .  .\n    .  .  .  .  .  .  .  .  .  .  .  .  .  .  .\n  ''';\n  return parseTiles(tileLayout).toList();\n}\n\nconst trackCount = 15;\nconst doubleLetterCount = 24;\nconst doubleWordCount = 16;\nconst tripleLetterCount = 12;\nconst tripleWordCount = 8;\nconst tileCount = trackCount * trackCount; // star\n\nclass ScrabbleBoard extends StatelessWidget {\n  const ScrabbleBoard({\n    Key? key,\n    required this.tiles,\n  }) : super(key: key);\n\n  final List<TileInfo> tiles;\n\n  @override\n  Widget build(BuildContext context) {\n    return LayoutGrid(\n      areas: '''\n        tw0 .  . dl0 .  .  . tw1 .  .  . dl1 .  . tw2\n         . dw0 .  .  . tl0 .  .  . tl1 .  .  . dw1 .\n         .  . dw2 .  .  . dl2 . dl3 .  .  . dw3 .  .\n        dl4 .  . dw4 .  .  . dl5 .  .  . dw5 .  .  dl6\n         .  .  .  . dw6 .  .  .  .  . dw7 .  .  .  .\n         . tl2 .  .  . tl3 .  .  . tl4 .  .  . tl5 .\n         .  . dl7 .  .  . dl8 . dl9 .  .  . dla .  .\n        tw3 .  . dlb .  .  .  ★  .  .  . dlc .  .  tw4\n         .  . dld .  .  . dle . dlf .  .  . dlg .  .\n         . tl6 .  .  . tl7 .  .  . tl8 .  .  . tl9 .\n         .  .  .  . dw8 .  .  .  .  . dw9 .  .  .  .\n        dlh .  . dwa .  .  . dli .  .  . dwb .  .  dlj\n         .  . dwc .  .  . dlk . dll .  .  . dwd .  .\n         . dwe .  .  . tla .  .  . tlb .  .  . dwf .\n        tw5 .  . dlm .  .  . tw6 .  .  . dln .  .  tw7\n      ''',\n      // A number of extension methods are provided for concise track sizing\n      columnSizes: repeat(trackCount, [36.px]),\n      rowSizes: repeat(trackCount, [36.px]),\n      children: [\n        // First, square bases\n        for (int i = 0; i < trackCount; i++)\n          for (int j = 0; j < trackCount; j++)\n            const StandardSquare()\n                .withGridPlacement(columnStart: i, rowStart: j),\n\n        // Then put bonuses on top\n        const StartingSquare().inGridArea('★'),\n        for (int i = 0; i < doubleLetterCount; i++)\n          const DoubleLetterSquare().inGridArea('dl${i.toRadixString(36)}'),\n        for (int i = 0; i < doubleWordCount; i++)\n          const DoubleWordSquare().inGridArea('dw${i.toRadixString(36)}'),\n        for (int i = 0; i < tripleLetterCount; i++)\n          const TripleLetterSquare().inGridArea('tl${i.toRadixString(36)}'),\n        for (int i = 0; i < tripleWordCount; i++)\n          const TripleWordSquare().inGridArea('tw${i.toRadixString(36)}'),\n\n        // Then place tiles on top of those\n        for (final tile in tiles)\n          LetterTile(letter: tile.letter).withGridPlacement(\n            columnStart: tile.col,\n            rowStart: tile.row,\n          ),\n      ],\n    );\n  }\n}\n\nconst orangeSquareBackground = Color(0xfffd8e73);\nconst magentaSquareBackground = Color(0xfff01c7a);\nconst lightBlueSquareBackground = Color(0xff8ecafc);\nconst darkBlueSquareBackground = Color(0xff1375b0);\n\nclass LetterTile extends StatelessWidget {\n  LetterTile({Key? key, required String letter})\n      : letter = letter.toUpperCase(),\n        super(key: key);\n\n  final String letter;\n\n  double get lockupRightPadding {\n    switch (letter) {\n      case 'M':\n        return 1.5;\n      case 'G':\n        return 3;\n      default:\n        return 1;\n    }\n  }\n\n  double get pointsRightPadding {\n    switch (letter) {\n      case 'G':\n        return 0;\n      case 'A':\n      case 'M':\n        return 1;\n      case 'T':\n        return 3;\n      default:\n        return 2;\n    }\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    return Padding(\n      padding: const EdgeInsets.all(1.5),\n      child: SizedBox.expand(\n        child: InnerShadow(\n          offset: const Offset(0, -1.5),\n          blurX: 0.8,\n          blurY: 1,\n          color: Colors.black.withAlpha(64), // Changed from withOpacity(.25)\n          child: _buildTileContents(),\n        ),\n      ),\n    );\n  }\n\n  DecoratedBox _buildTileContents() {\n    return DecoratedBox(\n      decoration: BoxDecoration(\n        color: const Color(0xfffaeac2),\n        border: Border.all(\n          color: Colors.black.withAlpha(18),\n          width: 1.5,\n        ),\n        borderRadius: BorderRadius.circular(3),\n      ),\n      child: Padding(\n        padding: EdgeInsets.only(\n          right: lockupRightPadding + 0.3,\n          bottom: 0.8,\n        ),\n        child: Stack(\n          alignment: Alignment.center,\n          children: [\n            _buildLetterLabel(),\n            _buildPointLabel(),\n          ],\n        ),\n      ),\n    );\n  }\n\n  Text _buildLetterLabel() {\n    return Text(\n      letter,\n      style: GoogleFonts.nunitoSans(\n        color: Colors.black,\n        fontSize: 20,\n        fontWeight: FontWeight.w900,\n      ),\n    );\n  }\n\n  Positioned _buildPointLabel() {\n    return Positioned(\n      right: pointsRightPadding,\n      bottom: 1,\n      child: Text(\n        '${letterPointMapping[letter]}',\n        style: GoogleFonts.nunitoSans(\n          color: Colors.black,\n          fontSize: 10,\n          fontWeight: FontWeight.w700,\n        ),\n      ),\n    );\n  }\n}\n\nclass StartingSquare extends Square {\n  const StartingSquare({Key? key})\n      : super(\n          key: key,\n          label: '★',\n          color: orangeSquareBackground,\n          edgeInsetsOverride: const EdgeInsets.only(left: 0.2, bottom: 0.5),\n          labelFontSizeOverride: 14,\n        );\n}\n\nclass DoubleLetterSquare extends Square {\n  const DoubleLetterSquare({Key? key})\n      : super(\n          key: key,\n          label: 'DL',\n          color: lightBlueSquareBackground,\n        );\n}\n\nclass DoubleWordSquare extends Square {\n  const DoubleWordSquare({Key? key})\n      : super(\n          key: key,\n          label: 'DW',\n          color: orangeSquareBackground,\n        );\n}\n\nclass TripleLetterSquare extends Square {\n  const TripleLetterSquare({Key? key})\n      : super(\n          key: key,\n          label: 'TL',\n          color: darkBlueSquareBackground,\n        );\n}\n\nclass TripleWordSquare extends Square {\n  const TripleWordSquare({Key? key})\n      : super(\n          key: key,\n          label: 'TW',\n          color: magentaSquareBackground,\n        );\n}\n\nclass StandardSquare extends Square {\n  const StandardSquare({Key? key})\n      : super(\n          key: key,\n          color: const Color(0xffe7eaef),\n        );\n}\n\nclass Square extends StatelessWidget {\n  const Square({\n    Key? key,\n    required this.color,\n    this.label,\n    this.labelFontSizeOverride,\n    this.edgeInsetsOverride,\n  }) : super(key: key);\n\n  final Color color;\n  final String? label;\n  final double? labelFontSizeOverride;\n  final EdgeInsets? edgeInsetsOverride;\n\n  @override\n  Widget build(BuildContext context) {\n    return Padding(\n      padding: const EdgeInsets.all(3.0),\n      child: InnerShadow(\n        offset: const Offset(0, 0.5),\n        blurX: 0.8,\n        blurY: 0.7,\n        color: Colors.black.withAlpha(64), // Changed from withOpacity(.25)\n        child: SizedBox.expand(\n          child: DecoratedBox(\n            decoration: BoxDecoration(\n              color: color,\n              borderRadius: const BorderRadius.all(Radius.elliptical(6, 4)),\n            ),\n            child: _buildLabel(context),\n          ),\n        ),\n      ),\n    );\n  }\n\n  Widget _buildLabel(BuildContext context) {\n    final label = this.label;\n    if (label == null) return const SizedBox();\n\n    return Center(\n      child: Padding(\n        padding:\n            edgeInsetsOverride ?? const EdgeInsets.only(top: 1.0, left: 0.5),\n        child: Text(\n          label,\n          style: GoogleFonts.robotoCondensed(\n            fontWeight: FontWeight.w500,\n            fontSize: labelFontSizeOverride ?? 12,\n            letterSpacing: 0,\n          ),\n        ),\n      ),\n    );\n  }\n}\n\nclass TileInfo {\n  TileInfo(this.letter, this.col, this.row)\n      : points = letterPointMapping[letter]!;\n\n  final String letter;\n  final int col;\n  final int row;\n  final int points;\n\n  @override\n  String toString() => '$letter@($col, $row)=$points';\n}\n\nconst letterPointMapping = {\n  'A': 1,\n  'B': 3,\n  'C': 3,\n  'D': 2,\n  'E': 1,\n  'F': 4,\n  'G': 2,\n  'H': 4,\n  'I': 1,\n  'J': 8,\n  'K': 5,\n  'L': 1,\n  'M': 3,\n  'N': 1,\n  'O': 1,\n  'P': 3,\n  'Q': 10,\n  'R': 1,\n  'S': 1,\n  'T': 1,\n  'U': 1,\n  'V': 4,\n  'W': 4,\n  'X': 8,\n  'Y': 4,\n  'Z': 10,\n};\n\nIterable<TileInfo> parseTiles(String tileLayout) sync* {\n  final rows = LineSplitter.split(tileLayout)\n      .map((row) => row.trim())\n      .where((row) => row.isNotEmpty)\n      .toList();\n  for (int i = 0; i < rows.length; i++) {\n    final row = rows[i];\n    final columns = row.split(RegExp(r'\\s+'));\n    for (int j = 0; j < columns.length; j++) {\n      final cell = columns[j];\n      if (cell == '.') continue;\n\n      yield TileInfo(cell, j, i);\n    }\n  }\n}\n"
  },
  {
    "path": "example/lib/semantic_ordering.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:flutter/semantics.dart';\nimport 'package:flutter_layout_grid/flutter_layout_grid.dart';\n\nvoid main() {\n  runApp(const SemanticOrderingApp());\n}\n\nclass SemanticOrderingApp extends StatelessWidget {\n  const SemanticOrderingApp({Key? key}) : super(key: key);\n\n  @override\n  Widget build(BuildContext context) {\n    return WidgetsApp(\n      color: Colors.white,\n      builder: (_, __) => const SemanticOrdering(),\n    );\n  }\n}\n\nclass SemanticOrdering extends StatelessWidget {\n  const SemanticOrdering({Key? key}) : super(key: key);\n\n  @override\n  Widget build(BuildContext context) {\n    return Semantics(\n      // We need to wrap the entire grid in a Semantics widget, with\n      // `explicitChildNodes: true`, in order for sorting to work properly.\n      explicitChildNodes: true,\n      child: LayoutGrid(\n        areas: '''\n          header\n          content\n          footer\n        ''',\n        columnSizes: const [auto],\n        rowSizes: const [\n          auto,\n          auto,\n          auto,\n        ],\n        children: [\n          // Using the Semantics widget and its sortKey tells screenreaders to\n          // announce the children in the order you specify, regardless of their\n          // ordering in source code (which is the default).\n          //\n          // In this example, you wouldn't want Footer() to be announced by the\n          // screenreader first, would you? sortKey fixes that.\n          Semantics(sortKey: const OrdinalSortKey(3), child: const Footer())\n              .inGridArea('footer'),\n          Semantics(sortKey: const OrdinalSortKey(1), child: const Header())\n              .inGridArea('header'),\n          Semantics(sortKey: const OrdinalSortKey(2), child: const Content())\n              .inGridArea('content'),\n        ],\n      ),\n    );\n  }\n}\n\nclass Header extends StatelessWidget {\n  const Header({Key? key}) : super(key: key);\n\n  @override\n  Widget build(BuildContext context) => Container(\n        color: Colors.red,\n        child: const Text('Header'),\n      );\n}\n\nclass Content extends StatelessWidget {\n  const Content({Key? key}) : super(key: key);\n\n  @override\n  Widget build(BuildContext context) => Container(\n        color: Colors.grey[300],\n        child: const Text('Content'),\n      );\n}\n\nclass Footer extends StatelessWidget {\n  const Footer({Key? key}) : super(key: key);\n\n  @override\n  Widget build(BuildContext context) => Container(\n        color: Colors.deepPurple,\n        child: const Text('Footer'),\n      );\n}\n"
  },
  {
    "path": "example/lib/support/inner_shadow.dart",
    "content": "// Source:\n// https://github.com/luigi-rosso/flutter-inner-shadow/blob/master/lib/inner_shadow.dart,\n// written by one of the creators of Rive (https://rive.app) (which you should\n// check out, because it's very cool)\n\nimport 'dart:ui';\n\nimport 'package:flutter/material.dart';\nimport 'package:flutter/rendering.dart';\n\nclass InnerShadow extends SingleChildRenderObjectWidget {\n  const InnerShadow({\n    Key? key,\n    required this.color,\n    required this.blurX,\n    required this.blurY,\n    required this.offset,\n    required Widget child,\n  }) : super(key: key, child: child);\n\n  final Color color;\n  final double blurX;\n  final double blurY;\n  final Offset offset;\n\n  @override\n  RenderInnerShadow createRenderObject(BuildContext context) {\n    return RenderInnerShadow(\n      color: color,\n      blurX: blurX,\n      blurY: blurY,\n      offset: offset,\n    );\n  }\n\n  @override\n  void updateRenderObject(\n      BuildContext context, RenderInnerShadow renderObject) {\n    renderObject\n      ..color = color\n      ..blurX = blurX\n      ..blurY = blurY\n      ..offset = offset;\n  }\n}\n\nclass RenderInnerShadow extends RenderProxyBox {\n  RenderInnerShadow({\n    RenderBox? child,\n    required Color color,\n    required double blurX,\n    required double blurY,\n    required Offset offset,\n  })  : _color = color,\n        _blurX = blurX,\n        _blurY = blurY,\n        _offset = offset,\n        super(child);\n\n  @override\n  bool get alwaysNeedsCompositing => child != null;\n\n  Color _color;\n  double _blurX;\n  double _blurY;\n  Offset _offset;\n\n  Color get color => _color;\n  set color(Color value) {\n    if (_color == value) return;\n    _color = value;\n    markNeedsPaint();\n  }\n\n  double get blurX => _blurX;\n  set blurX(double value) {\n    if (_blurX == value) return;\n    _blurX = value;\n    markNeedsPaint();\n  }\n\n  double get blurY => _blurY;\n  set blurY(double value) {\n    if (_blurY == value) return;\n    _blurY = value;\n    markNeedsPaint();\n  }\n\n  Offset get offset => _offset;\n  set offset(Offset value) {\n    if (_offset == value) return;\n    _offset = value;\n    markNeedsPaint();\n  }\n\n  @override\n  void paint(PaintingContext context, Offset offset) {\n    final child = this.child;\n    if (child != null) {\n      final layerPaint = Paint()..color = Colors.white;\n\n      context.canvas.saveLayer(offset & size, layerPaint);\n      context.paintChild(child, offset);\n      final shadowPaint = Paint()\n        ..blendMode = BlendMode.srcATop\n        ..imageFilter = ImageFilter.blur(sigmaX: blurX, sigmaY: blurY)\n        ..colorFilter = ColorFilter.mode(color, BlendMode.srcIn);\n      context.canvas.saveLayer(offset & size, shadowPaint);\n\n      // Invert the alpha to compute inner part.\n      final invertPaint = Paint()\n        ..colorFilter = const ColorFilter.matrix(\n            [1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, -1, 255]);\n      context.canvas.saveLayer(offset & size, invertPaint);\n      context.canvas.translate(_offset.dx, _offset.dy);\n      context.paintChild(child, offset);\n      context.canvas.restore();\n      context.canvas.restore();\n      context.canvas.restore();\n    }\n  }\n\n  @override\n  void visitChildrenForSemantics(RenderObjectVisitor visitor) {\n    final child = this.child;\n    if (child != null) visitor(child);\n  }\n}\n"
  },
  {
    "path": "example/linux/.gitignore",
    "content": "flutter/ephemeral\n"
  },
  {
    "path": "example/linux/CMakeLists.txt",
    "content": "# Project-level configuration.\ncmake_minimum_required(VERSION 3.10)\nproject(runner LANGUAGES CXX)\n\n# The name of the executable created for the application. Change this to change\n# the on-disk name of your application.\nset(BINARY_NAME \"example\")\n# The unique GTK application identifier for this application. See:\n# https://wiki.gnome.org/HowDoI/ChooseApplicationID\nset(APPLICATION_ID \"com.example.example\")\n\n# Explicitly opt in to modern CMake behaviors to avoid warnings with recent\n# versions of CMake.\ncmake_policy(SET CMP0063 NEW)\n\n# Load bundled libraries from the lib/ directory relative to the binary.\nset(CMAKE_INSTALL_RPATH \"$ORIGIN/lib\")\n\n# Root filesystem for cross-building.\nif(FLUTTER_TARGET_PLATFORM_SYSROOT)\n  set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT})\n  set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT})\n  set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)\n  set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)\n  set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)\n  set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)\nendif()\n\n# Define build configuration options.\nif(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)\n  set(CMAKE_BUILD_TYPE \"Debug\" CACHE\n    STRING \"Flutter build mode\" FORCE)\n  set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS\n    \"Debug\" \"Profile\" \"Release\")\nendif()\n\n# Compilation settings that should be applied to most targets.\n#\n# Be cautious about adding new options here, as plugins use this function by\n# default. In most cases, you should add new options to specific targets instead\n# of modifying this function.\nfunction(APPLY_STANDARD_SETTINGS TARGET)\n  target_compile_features(${TARGET} PUBLIC cxx_std_14)\n  target_compile_options(${TARGET} PRIVATE -Wall -Werror)\n  target_compile_options(${TARGET} PRIVATE \"$<$<NOT:$<CONFIG:Debug>>:-O3>\")\n  target_compile_definitions(${TARGET} PRIVATE \"$<$<NOT:$<CONFIG:Debug>>:NDEBUG>\")\nendfunction()\n\n# Flutter library and tool build rules.\nset(FLUTTER_MANAGED_DIR \"${CMAKE_CURRENT_SOURCE_DIR}/flutter\")\nadd_subdirectory(${FLUTTER_MANAGED_DIR})\n\n# System-level dependencies.\nfind_package(PkgConfig REQUIRED)\npkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)\n\nadd_definitions(-DAPPLICATION_ID=\"${APPLICATION_ID}\")\n\n# Define the application target. To change its name, change BINARY_NAME above,\n# not the value here, or `flutter run` will no longer work.\n#\n# Any new source files that you add to the application should be added here.\nadd_executable(${BINARY_NAME}\n  \"main.cc\"\n  \"my_application.cc\"\n  \"${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc\"\n)\n\n# Apply the standard set of build settings. This can be removed for applications\n# that need different build settings.\napply_standard_settings(${BINARY_NAME})\n\n# Add dependency libraries. Add any application-specific dependencies here.\ntarget_link_libraries(${BINARY_NAME} PRIVATE flutter)\ntarget_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK)\n\n# Run the Flutter tool portions of the build. This must not be removed.\nadd_dependencies(${BINARY_NAME} flutter_assemble)\n\n# Only the install-generated bundle's copy of the executable will launch\n# correctly, since the resources must in the right relative locations. To avoid\n# people trying to run the unbundled copy, put it in a subdirectory instead of\n# the default top-level location.\nset_target_properties(${BINARY_NAME}\n  PROPERTIES\n  RUNTIME_OUTPUT_DIRECTORY \"${CMAKE_BINARY_DIR}/intermediates_do_not_run\"\n)\n\n# Generated plugin build rules, which manage building the plugins and adding\n# them to the application.\ninclude(flutter/generated_plugins.cmake)\n\n\n# === Installation ===\n# By default, \"installing\" just makes a relocatable bundle in the build\n# directory.\nset(BUILD_BUNDLE_DIR \"${PROJECT_BINARY_DIR}/bundle\")\nif(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)\n  set(CMAKE_INSTALL_PREFIX \"${BUILD_BUNDLE_DIR}\" CACHE PATH \"...\" FORCE)\nendif()\n\n# Start with a clean build bundle directory every time.\ninstall(CODE \"\n  file(REMOVE_RECURSE \\\"${BUILD_BUNDLE_DIR}/\\\")\n  \" COMPONENT Runtime)\n\nset(INSTALL_BUNDLE_DATA_DIR \"${CMAKE_INSTALL_PREFIX}/data\")\nset(INSTALL_BUNDLE_LIB_DIR \"${CMAKE_INSTALL_PREFIX}/lib\")\n\ninstall(TARGETS ${BINARY_NAME} RUNTIME DESTINATION \"${CMAKE_INSTALL_PREFIX}\"\n  COMPONENT Runtime)\n\ninstall(FILES \"${FLUTTER_ICU_DATA_FILE}\" DESTINATION \"${INSTALL_BUNDLE_DATA_DIR}\"\n  COMPONENT Runtime)\n\ninstall(FILES \"${FLUTTER_LIBRARY}\" DESTINATION \"${INSTALL_BUNDLE_LIB_DIR}\"\n  COMPONENT Runtime)\n\nforeach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES})\n  install(FILES \"${bundled_library}\"\n    DESTINATION \"${INSTALL_BUNDLE_LIB_DIR}\"\n    COMPONENT Runtime)\nendforeach(bundled_library)\n\n# Fully re-copy the assets directory on each build to avoid having stale files\n# from a previous install.\nset(FLUTTER_ASSET_DIR_NAME \"flutter_assets\")\ninstall(CODE \"\n  file(REMOVE_RECURSE \\\"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\\\")\n  \" COMPONENT Runtime)\ninstall(DIRECTORY \"${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}\"\n  DESTINATION \"${INSTALL_BUNDLE_DATA_DIR}\" COMPONENT Runtime)\n\n# Install the AOT library on non-Debug builds only.\nif(NOT CMAKE_BUILD_TYPE MATCHES \"Debug\")\n  install(FILES \"${AOT_LIBRARY}\" DESTINATION \"${INSTALL_BUNDLE_LIB_DIR}\"\n    COMPONENT Runtime)\nendif()\n"
  },
  {
    "path": "example/linux/flutter/CMakeLists.txt",
    "content": "# This file controls Flutter-level build steps. It should not be edited.\ncmake_minimum_required(VERSION 3.10)\n\nset(EPHEMERAL_DIR \"${CMAKE_CURRENT_SOURCE_DIR}/ephemeral\")\n\n# Configuration provided via flutter tool.\ninclude(${EPHEMERAL_DIR}/generated_config.cmake)\n\n# TODO: Move the rest of this into files in ephemeral. See\n# https://github.com/flutter/flutter/issues/57146.\n\n# Serves the same purpose as list(TRANSFORM ... PREPEND ...),\n# which isn't available in 3.10.\nfunction(list_prepend LIST_NAME PREFIX)\n    set(NEW_LIST \"\")\n    foreach(element ${${LIST_NAME}})\n        list(APPEND NEW_LIST \"${PREFIX}${element}\")\n    endforeach(element)\n    set(${LIST_NAME} \"${NEW_LIST}\" PARENT_SCOPE)\nendfunction()\n\n# === Flutter Library ===\n# System-level dependencies.\nfind_package(PkgConfig REQUIRED)\npkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)\npkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0)\npkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0)\n\nset(FLUTTER_LIBRARY \"${EPHEMERAL_DIR}/libflutter_linux_gtk.so\")\n\n# Published to parent scope for install step.\nset(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE)\nset(FLUTTER_ICU_DATA_FILE \"${EPHEMERAL_DIR}/icudtl.dat\" PARENT_SCOPE)\nset(PROJECT_BUILD_DIR \"${PROJECT_DIR}/build/\" PARENT_SCOPE)\nset(AOT_LIBRARY \"${PROJECT_DIR}/build/lib/libapp.so\" PARENT_SCOPE)\n\nlist(APPEND FLUTTER_LIBRARY_HEADERS\n  \"fl_basic_message_channel.h\"\n  \"fl_binary_codec.h\"\n  \"fl_binary_messenger.h\"\n  \"fl_dart_project.h\"\n  \"fl_engine.h\"\n  \"fl_json_message_codec.h\"\n  \"fl_json_method_codec.h\"\n  \"fl_message_codec.h\"\n  \"fl_method_call.h\"\n  \"fl_method_channel.h\"\n  \"fl_method_codec.h\"\n  \"fl_method_response.h\"\n  \"fl_plugin_registrar.h\"\n  \"fl_plugin_registry.h\"\n  \"fl_standard_message_codec.h\"\n  \"fl_standard_method_codec.h\"\n  \"fl_string_codec.h\"\n  \"fl_value.h\"\n  \"fl_view.h\"\n  \"flutter_linux.h\"\n)\nlist_prepend(FLUTTER_LIBRARY_HEADERS \"${EPHEMERAL_DIR}/flutter_linux/\")\nadd_library(flutter INTERFACE)\ntarget_include_directories(flutter INTERFACE\n  \"${EPHEMERAL_DIR}\"\n)\ntarget_link_libraries(flutter INTERFACE \"${FLUTTER_LIBRARY}\")\ntarget_link_libraries(flutter INTERFACE\n  PkgConfig::GTK\n  PkgConfig::GLIB\n  PkgConfig::GIO\n)\nadd_dependencies(flutter flutter_assemble)\n\n# === Flutter tool backend ===\n# _phony_ is a non-existent file to force this command to run every time,\n# since currently there's no way to get a full input/output list from the\n# flutter tool.\nadd_custom_command(\n  OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS}\n    ${CMAKE_CURRENT_BINARY_DIR}/_phony_\n  COMMAND ${CMAKE_COMMAND} -E env\n    ${FLUTTER_TOOL_ENVIRONMENT}\n    \"${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh\"\n      ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE}\n  VERBATIM\n)\nadd_custom_target(flutter_assemble DEPENDS\n  \"${FLUTTER_LIBRARY}\"\n  ${FLUTTER_LIBRARY_HEADERS}\n)\n"
  },
  {
    "path": "example/linux/flutter/generated_plugin_registrant.cc",
    "content": "//\n//  Generated file. Do not edit.\n//\n\n// clang-format off\n\n#include \"generated_plugin_registrant.h\"\n\n\nvoid fl_register_plugins(FlPluginRegistry* registry) {\n}\n"
  },
  {
    "path": "example/linux/flutter/generated_plugin_registrant.h",
    "content": "//\n//  Generated file. Do not edit.\n//\n\n// clang-format off\n\n#ifndef GENERATED_PLUGIN_REGISTRANT_\n#define GENERATED_PLUGIN_REGISTRANT_\n\n#include <flutter_linux/flutter_linux.h>\n\n// Registers Flutter plugins.\nvoid fl_register_plugins(FlPluginRegistry* registry);\n\n#endif  // GENERATED_PLUGIN_REGISTRANT_\n"
  },
  {
    "path": "example/linux/flutter/generated_plugins.cmake",
    "content": "#\n# Generated file, do not edit.\n#\n\nlist(APPEND FLUTTER_PLUGIN_LIST\n)\n\nlist(APPEND FLUTTER_FFI_PLUGIN_LIST\n)\n\nset(PLUGIN_BUNDLED_LIBRARIES)\n\nforeach(plugin ${FLUTTER_PLUGIN_LIST})\n  add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin})\n  target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin)\n  list(APPEND PLUGIN_BUNDLED_LIBRARIES $<TARGET_FILE:${plugin}_plugin>)\n  list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})\nendforeach(plugin)\n\nforeach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})\n  add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin})\n  list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})\nendforeach(ffi_plugin)\n"
  },
  {
    "path": "example/linux/main.cc",
    "content": "#include \"my_application.h\"\n\nint main(int argc, char** argv) {\n  g_autoptr(MyApplication) app = my_application_new();\n  return g_application_run(G_APPLICATION(app), argc, argv);\n}\n"
  },
  {
    "path": "example/linux/my_application.cc",
    "content": "#include \"my_application.h\"\n\n#include <flutter_linux/flutter_linux.h>\n#ifdef GDK_WINDOWING_X11\n#include <gdk/gdkx.h>\n#endif\n\n#include \"flutter/generated_plugin_registrant.h\"\n\nstruct _MyApplication {\n  GtkApplication parent_instance;\n  char** dart_entrypoint_arguments;\n};\n\nG_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION)\n\n// Implements GApplication::activate.\nstatic void my_application_activate(GApplication* application) {\n  MyApplication* self = MY_APPLICATION(application);\n  GtkWindow* window =\n      GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application)));\n\n  // Use a header bar when running in GNOME as this is the common style used\n  // by applications and is the setup most users will be using (e.g. Ubuntu\n  // desktop).\n  // If running on X and not using GNOME then just use a traditional title bar\n  // in case the window manager does more exotic layout, e.g. tiling.\n  // If running on Wayland assume the header bar will work (may need changing\n  // if future cases occur).\n  gboolean use_header_bar = TRUE;\n#ifdef GDK_WINDOWING_X11\n  GdkScreen* screen = gtk_window_get_screen(window);\n  if (GDK_IS_X11_SCREEN(screen)) {\n    const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen);\n    if (g_strcmp0(wm_name, \"GNOME Shell\") != 0) {\n      use_header_bar = FALSE;\n    }\n  }\n#endif\n  if (use_header_bar) {\n    GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new());\n    gtk_widget_show(GTK_WIDGET(header_bar));\n    gtk_header_bar_set_title(header_bar, \"example\");\n    gtk_header_bar_set_show_close_button(header_bar, TRUE);\n    gtk_window_set_titlebar(window, GTK_WIDGET(header_bar));\n  } else {\n    gtk_window_set_title(window, \"example\");\n  }\n\n  gtk_window_set_default_size(window, 1280, 720);\n  gtk_widget_show(GTK_WIDGET(window));\n\n  g_autoptr(FlDartProject) project = fl_dart_project_new();\n  fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments);\n\n  FlView* view = fl_view_new(project);\n  gtk_widget_show(GTK_WIDGET(view));\n  gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view));\n\n  fl_register_plugins(FL_PLUGIN_REGISTRY(view));\n\n  gtk_widget_grab_focus(GTK_WIDGET(view));\n}\n\n// Implements GApplication::local_command_line.\nstatic gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) {\n  MyApplication* self = MY_APPLICATION(application);\n  // Strip out the first argument as it is the binary name.\n  self->dart_entrypoint_arguments = g_strdupv(*arguments + 1);\n\n  g_autoptr(GError) error = nullptr;\n  if (!g_application_register(application, nullptr, &error)) {\n     g_warning(\"Failed to register: %s\", error->message);\n     *exit_status = 1;\n     return TRUE;\n  }\n\n  g_application_activate(application);\n  *exit_status = 0;\n\n  return TRUE;\n}\n\n// Implements GObject::dispose.\nstatic void my_application_dispose(GObject* object) {\n  MyApplication* self = MY_APPLICATION(object);\n  g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev);\n  G_OBJECT_CLASS(my_application_parent_class)->dispose(object);\n}\n\nstatic void my_application_class_init(MyApplicationClass* klass) {\n  G_APPLICATION_CLASS(klass)->activate = my_application_activate;\n  G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line;\n  G_OBJECT_CLASS(klass)->dispose = my_application_dispose;\n}\n\nstatic void my_application_init(MyApplication* self) {}\n\nMyApplication* my_application_new() {\n  return MY_APPLICATION(g_object_new(my_application_get_type(),\n                                     \"application-id\", APPLICATION_ID,\n                                     \"flags\", G_APPLICATION_NON_UNIQUE,\n                                     nullptr));\n}\n"
  },
  {
    "path": "example/linux/my_application.h",
    "content": "#ifndef FLUTTER_MY_APPLICATION_H_\n#define FLUTTER_MY_APPLICATION_H_\n\n#include <gtk/gtk.h>\n\nG_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION,\n                     GtkApplication)\n\n/**\n * my_application_new:\n *\n * Creates a new Flutter-based application.\n *\n * Returns: a new #MyApplication.\n */\nMyApplication* my_application_new();\n\n#endif  // FLUTTER_MY_APPLICATION_H_\n"
  },
  {
    "path": "example/macos/.gitignore",
    "content": "# Flutter-related\n**/Flutter/ephemeral/\n**/Pods/\n\n# Xcode-related\n**/dgph\n**/xcuserdata/\n"
  },
  {
    "path": "example/macos/Flutter/Flutter-Debug.xcconfig",
    "content": "#include? \"Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig\"\n#include \"ephemeral/Flutter-Generated.xcconfig\"\n"
  },
  {
    "path": "example/macos/Flutter/Flutter-Release.xcconfig",
    "content": "#include? \"Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig\"\n#include \"ephemeral/Flutter-Generated.xcconfig\"\n"
  },
  {
    "path": "example/macos/Podfile",
    "content": "platform :osx, '10.11'\n\n# CocoaPods analytics sends network stats synchronously affecting flutter build latency.\nENV['COCOAPODS_DISABLE_STATS'] = 'true'\n\nproject 'Runner', {\n  'Debug' => :debug,\n  'Profile' => :release,\n  'Release' => :release,\n}\n\ndef flutter_root\n  generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__)\n  unless File.exist?(generated_xcode_build_settings_path)\n    raise \"#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \\\"flutter pub get\\\" is executed first\"\n  end\n\n  File.foreach(generated_xcode_build_settings_path) do |line|\n    matches = line.match(/FLUTTER_ROOT\\=(.*)/)\n    return matches[1].strip if matches\n  end\n  raise \"FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \\\"flutter pub get\\\"\"\nend\n\nrequire File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)\n\nflutter_macos_podfile_setup\n\ntarget 'Runner' do\n  use_frameworks!\n  use_modular_headers!\n\n  flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__))\nend\n\npost_install do |installer|\n  installer.pods_project.targets.each do |target|\n    flutter_additional_macos_build_settings(target)\n  end\nend\n"
  },
  {
    "path": "example/macos/Runner/AppDelegate.swift",
    "content": "import Cocoa\nimport FlutterMacOS\n\n@NSApplicationMain\nclass AppDelegate: FlutterAppDelegate {\n  override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {\n    return true\n  }\n}\n"
  },
  {
    "path": "example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"size\" : \"16x16\",\n      \"idiom\" : \"mac\",\n      \"filename\" : \"app_icon_16.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"16x16\",\n      \"idiom\" : \"mac\",\n      \"filename\" : \"app_icon_32.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"32x32\",\n      \"idiom\" : \"mac\",\n      \"filename\" : \"app_icon_32.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"32x32\",\n      \"idiom\" : \"mac\",\n      \"filename\" : \"app_icon_64.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"128x128\",\n      \"idiom\" : \"mac\",\n      \"filename\" : \"app_icon_128.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"128x128\",\n      \"idiom\" : \"mac\",\n      \"filename\" : \"app_icon_256.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"256x256\",\n      \"idiom\" : \"mac\",\n      \"filename\" : \"app_icon_256.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"256x256\",\n      \"idiom\" : \"mac\",\n      \"filename\" : \"app_icon_512.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"512x512\",\n      \"idiom\" : \"mac\",\n      \"filename\" : \"app_icon_512.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"512x512\",\n      \"idiom\" : \"mac\",\n      \"filename\" : \"app_icon_1024.png\",\n      \"scale\" : \"2x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}\n"
  },
  {
    "path": "example/macos/Runner/Base.lproj/MainMenu.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"14490.70\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" customObjectInstantitationMethod=\"direct\">\n    <dependencies>\n        <deployment identifier=\"macosx\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"14490.70\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"NSApplication\">\n            <connections>\n                <outlet property=\"delegate\" destination=\"Voe-Tx-rLC\" id=\"GzC-gU-4Uq\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <customObject id=\"Voe-Tx-rLC\" customClass=\"AppDelegate\" customModule=\"Runner\" customModuleProvider=\"target\">\n            <connections>\n                <outlet property=\"applicationMenu\" destination=\"uQy-DD-JDr\" id=\"XBo-yE-nKs\"/>\n                <outlet property=\"mainFlutterWindow\" destination=\"QvC-M9-y7g\" id=\"gIp-Ho-8D9\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"YLy-65-1bz\" customClass=\"NSFontManager\"/>\n        <menu title=\"Main Menu\" systemMenu=\"main\" id=\"AYu-sK-qS6\">\n            <items>\n                <menuItem title=\"APP_NAME\" id=\"1Xt-HY-uBw\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <menu key=\"submenu\" title=\"APP_NAME\" systemMenu=\"apple\" id=\"uQy-DD-JDr\">\n                        <items>\n                            <menuItem title=\"About APP_NAME\" id=\"5kV-Vb-QxS\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"orderFrontStandardAboutPanel:\" target=\"-1\" id=\"Exp-CZ-Vem\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"VOq-y0-SEH\"/>\n                            <menuItem title=\"Preferences…\" keyEquivalent=\",\" id=\"BOF-NM-1cW\"/>\n                            <menuItem isSeparatorItem=\"YES\" id=\"wFC-TO-SCJ\"/>\n                            <menuItem title=\"Services\" id=\"NMo-om-nkz\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Services\" systemMenu=\"services\" id=\"hz9-B4-Xy5\"/>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"4je-JR-u6R\"/>\n                            <menuItem title=\"Hide APP_NAME\" keyEquivalent=\"h\" id=\"Olw-nP-bQN\">\n                                <connections>\n                                    <action selector=\"hide:\" target=\"-1\" id=\"PnN-Uc-m68\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Hide Others\" keyEquivalent=\"h\" id=\"Vdr-fp-XzO\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                <connections>\n                                    <action selector=\"hideOtherApplications:\" target=\"-1\" id=\"VT4-aY-XCT\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Show All\" id=\"Kd2-mp-pUS\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"unhideAllApplications:\" target=\"-1\" id=\"Dhg-Le-xox\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"kCx-OE-vgT\"/>\n                            <menuItem title=\"Quit APP_NAME\" keyEquivalent=\"q\" id=\"4sb-4s-VLi\">\n                                <connections>\n                                    <action selector=\"terminate:\" target=\"-1\" id=\"Te7-pn-YzF\"/>\n                                </connections>\n                            </menuItem>\n                        </items>\n                    </menu>\n                </menuItem>\n                <menuItem title=\"Edit\" id=\"5QF-Oa-p0T\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <menu key=\"submenu\" title=\"Edit\" id=\"W48-6f-4Dl\">\n                        <items>\n                            <menuItem title=\"Undo\" keyEquivalent=\"z\" id=\"dRJ-4n-Yzg\">\n                                <connections>\n                                    <action selector=\"undo:\" target=\"-1\" id=\"M6e-cu-g7V\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Redo\" keyEquivalent=\"Z\" id=\"6dh-zS-Vam\">\n                                <connections>\n                                    <action selector=\"redo:\" target=\"-1\" id=\"oIA-Rs-6OD\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"WRV-NI-Exz\"/>\n                            <menuItem title=\"Cut\" keyEquivalent=\"x\" id=\"uRl-iY-unG\">\n                                <connections>\n                                    <action selector=\"cut:\" target=\"-1\" id=\"YJe-68-I9s\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Copy\" keyEquivalent=\"c\" id=\"x3v-GG-iWU\">\n                                <connections>\n                                    <action selector=\"copy:\" target=\"-1\" id=\"G1f-GL-Joy\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Paste\" keyEquivalent=\"v\" id=\"gVA-U4-sdL\">\n                                <connections>\n                                    <action selector=\"paste:\" target=\"-1\" id=\"UvS-8e-Qdg\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Paste and Match Style\" keyEquivalent=\"V\" id=\"WeT-3V-zwk\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                <connections>\n                                    <action selector=\"pasteAsPlainText:\" target=\"-1\" id=\"cEh-KX-wJQ\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Delete\" id=\"pa3-QI-u2k\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"delete:\" target=\"-1\" id=\"0Mk-Ml-PaM\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Select All\" keyEquivalent=\"a\" id=\"Ruw-6m-B2m\">\n                                <connections>\n                                    <action selector=\"selectAll:\" target=\"-1\" id=\"VNm-Mi-diN\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"uyl-h8-XO2\"/>\n                            <menuItem title=\"Find\" id=\"4EN-yA-p0u\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Find\" id=\"1b7-l0-nxx\">\n                                    <items>\n                                        <menuItem title=\"Find…\" tag=\"1\" keyEquivalent=\"f\" id=\"Xz5-n4-O0W\">\n                                            <connections>\n                                                <action selector=\"performFindPanelAction:\" target=\"-1\" id=\"cD7-Qs-BN4\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Find and Replace…\" tag=\"12\" keyEquivalent=\"f\" id=\"YEy-JH-Tfz\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"performFindPanelAction:\" target=\"-1\" id=\"WD3-Gg-5AJ\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Find Next\" tag=\"2\" keyEquivalent=\"g\" id=\"q09-fT-Sye\">\n                                            <connections>\n                                                <action selector=\"performFindPanelAction:\" target=\"-1\" id=\"NDo-RZ-v9R\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Find Previous\" tag=\"3\" keyEquivalent=\"G\" id=\"OwM-mh-QMV\">\n                                            <connections>\n                                                <action selector=\"performFindPanelAction:\" target=\"-1\" id=\"HOh-sY-3ay\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Use Selection for Find\" tag=\"7\" keyEquivalent=\"e\" id=\"buJ-ug-pKt\">\n                                            <connections>\n                                                <action selector=\"performFindPanelAction:\" target=\"-1\" id=\"U76-nv-p5D\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Jump to Selection\" keyEquivalent=\"j\" id=\"S0p-oC-mLd\">\n                                            <connections>\n                                                <action selector=\"centerSelectionInVisibleArea:\" target=\"-1\" id=\"IOG-6D-g5B\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Spelling and Grammar\" id=\"Dv1-io-Yv7\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Spelling\" id=\"3IN-sU-3Bg\">\n                                    <items>\n                                        <menuItem title=\"Show Spelling and Grammar\" keyEquivalent=\":\" id=\"HFo-cy-zxI\">\n                                            <connections>\n                                                <action selector=\"showGuessPanel:\" target=\"-1\" id=\"vFj-Ks-hy3\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Check Document Now\" keyEquivalent=\";\" id=\"hz2-CU-CR7\">\n                                            <connections>\n                                                <action selector=\"checkSpelling:\" target=\"-1\" id=\"fz7-VC-reM\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"bNw-od-mp5\"/>\n                                        <menuItem title=\"Check Spelling While Typing\" id=\"rbD-Rh-wIN\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"toggleContinuousSpellChecking:\" target=\"-1\" id=\"7w6-Qz-0kB\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Check Grammar With Spelling\" id=\"mK6-2p-4JG\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"toggleGrammarChecking:\" target=\"-1\" id=\"muD-Qn-j4w\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Correct Spelling Automatically\" id=\"78Y-hA-62v\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"toggleAutomaticSpellingCorrection:\" target=\"-1\" id=\"2lM-Qi-WAP\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Substitutions\" id=\"9ic-FL-obx\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Substitutions\" id=\"FeM-D8-WVr\">\n                                    <items>\n                                        <menuItem title=\"Show Substitutions\" id=\"z6F-FW-3nz\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"orderFrontSubstitutionsPanel:\" target=\"-1\" id=\"oku-mr-iSq\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"gPx-C9-uUO\"/>\n                                        <menuItem title=\"Smart Copy/Paste\" id=\"9yt-4B-nSM\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"toggleSmartInsertDelete:\" target=\"-1\" id=\"3IJ-Se-DZD\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Smart Quotes\" id=\"hQb-2v-fYv\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"toggleAutomaticQuoteSubstitution:\" target=\"-1\" id=\"ptq-xd-QOA\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Smart Dashes\" id=\"rgM-f4-ycn\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"toggleAutomaticDashSubstitution:\" target=\"-1\" id=\"oCt-pO-9gS\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Smart Links\" id=\"cwL-P1-jid\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"toggleAutomaticLinkDetection:\" target=\"-1\" id=\"Gip-E3-Fov\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Data Detectors\" id=\"tRr-pd-1PS\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"toggleAutomaticDataDetection:\" target=\"-1\" id=\"R1I-Nq-Kbl\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Text Replacement\" id=\"HFQ-gK-NFA\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"toggleAutomaticTextReplacement:\" target=\"-1\" id=\"DvP-Fe-Py6\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Transformations\" id=\"2oI-Rn-ZJC\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Transformations\" id=\"c8a-y6-VQd\">\n                                    <items>\n                                        <menuItem title=\"Make Upper Case\" id=\"vmV-6d-7jI\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"uppercaseWord:\" target=\"-1\" id=\"sPh-Tk-edu\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Make Lower Case\" id=\"d9M-CD-aMd\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"lowercaseWord:\" target=\"-1\" id=\"iUZ-b5-hil\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Capitalize\" id=\"UEZ-Bs-lqG\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"capitalizeWord:\" target=\"-1\" id=\"26H-TL-nsh\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Speech\" id=\"xrE-MZ-jX0\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Speech\" id=\"3rS-ZA-NoH\">\n                                    <items>\n                                        <menuItem title=\"Start Speaking\" id=\"Ynk-f8-cLZ\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"startSpeaking:\" target=\"-1\" id=\"654-Ng-kyl\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Stop Speaking\" id=\"Oyz-dy-DGm\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"stopSpeaking:\" target=\"-1\" id=\"dX8-6p-jy9\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </menuItem>\n                        </items>\n                    </menu>\n                </menuItem>\n                <menuItem title=\"View\" id=\"H8h-7b-M4v\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <menu key=\"submenu\" title=\"View\" id=\"HyV-fh-RgO\">\n                        <items>\n                            <menuItem title=\"Enter Full Screen\" keyEquivalent=\"f\" id=\"4J7-dP-txa\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\" command=\"YES\"/>\n                                <connections>\n                                    <action selector=\"toggleFullScreen:\" target=\"-1\" id=\"dU3-MA-1Rq\"/>\n                                </connections>\n                            </menuItem>\n                        </items>\n                    </menu>\n                </menuItem>\n                <menuItem title=\"Window\" id=\"aUF-d1-5bR\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <menu key=\"submenu\" title=\"Window\" systemMenu=\"window\" id=\"Td7-aD-5lo\">\n                        <items>\n                            <menuItem title=\"Minimize\" keyEquivalent=\"m\" id=\"OY7-WF-poV\">\n                                <connections>\n                                    <action selector=\"performMiniaturize:\" target=\"-1\" id=\"VwT-WD-YPe\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Zoom\" id=\"R4o-n2-Eq4\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"performZoom:\" target=\"-1\" id=\"DIl-cC-cCs\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" id=\"eu3-7i-yIM\"/>\n                            <menuItem title=\"Bring All to Front\" id=\"LE2-aR-0XJ\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"arrangeInFront:\" target=\"-1\" id=\"DRN-fu-gQh\"/>\n                                </connections>\n                            </menuItem>\n                        </items>\n                    </menu>\n                </menuItem>\n                <menuItem title=\"Help\" id=\"EPT-qC-fAb\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <menu key=\"submenu\" title=\"Help\" systemMenu=\"help\" id=\"rJ0-wn-3NY\"/>\n                </menuItem>\n            </items>\n            <point key=\"canvasLocation\" x=\"142\" y=\"-258\"/>\n        </menu>\n        <window title=\"APP_NAME\" allowsToolTipsWhenApplicationIsInactive=\"NO\" autorecalculatesKeyViewLoop=\"NO\" releasedWhenClosed=\"NO\" animationBehavior=\"default\" id=\"QvC-M9-y7g\" customClass=\"MainFlutterWindow\" customModule=\"Runner\" customModuleProvider=\"target\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\" closable=\"YES\" miniaturizable=\"YES\" resizable=\"YES\"/>\n            <rect key=\"contentRect\" x=\"335\" y=\"390\" width=\"800\" height=\"600\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"2560\" height=\"1577\"/>\n            <view key=\"contentView\" wantsLayer=\"YES\" id=\"EiT-Mj-1SZ\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"800\" height=\"600\"/>\n                <autoresizingMask key=\"autoresizingMask\"/>\n            </view>\n        </window>\n    </objects>\n</document>\n"
  },
  {
    "path": "example/macos/Runner/Configs/AppInfo.xcconfig",
    "content": "// Application-level settings for the Runner target.\n//\n// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the\n// future. If not, the values below would default to using the project name when this becomes a\n// 'flutter create' template.\n\n// The application's name. By default this is also the title of the Flutter window.\nPRODUCT_NAME = Flutter Layout Grid\n\n// The application's bundle identifier\nPRODUCT_BUNDLE_IDENTIFIER = com.example.flutterLayoutGrid\n\n// The copyright displayed in application information\nPRODUCT_COPYRIGHT = Copyright © 2021 com.example. All rights reserved.\n"
  },
  {
    "path": "example/macos/Runner/Configs/Debug.xcconfig",
    "content": "#include \"../../Flutter/Flutter-Debug.xcconfig\"\n#include \"Warnings.xcconfig\"\n"
  },
  {
    "path": "example/macos/Runner/Configs/Release.xcconfig",
    "content": "#include \"../../Flutter/Flutter-Release.xcconfig\"\n#include \"Warnings.xcconfig\"\n"
  },
  {
    "path": "example/macos/Runner/Configs/Warnings.xcconfig",
    "content": "WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings\nGCC_WARN_UNDECLARED_SELECTOR = YES\nCLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES\nCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE\nCLANG_WARN__DUPLICATE_METHOD_MATCH = YES\nCLANG_WARN_PRAGMA_PACK = YES\nCLANG_WARN_STRICT_PROTOTYPES = YES\nCLANG_WARN_COMMA = YES\nGCC_WARN_STRICT_SELECTOR_MATCH = YES\nCLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES\nCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES\nGCC_WARN_SHADOW = YES\nCLANG_WARN_UNREACHABLE_CODE = YES\n"
  },
  {
    "path": "example/macos/Runner/DebugProfile.entitlements",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>com.apple.security.app-sandbox</key>\n\t<true/>\n\t<key>com.apple.security.cs.allow-jit</key>\n\t<true/>\n\t<key>com.apple.security.network.client</key>\n\t<true/>\n\t<key>com.apple.security.network.server</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "example/macos/Runner/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>$(DEVELOPMENT_LANGUAGE)</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIconFile</key>\n\t<string></string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>$(FLUTTER_BUILD_NAME)</string>\n\t<key>CFBundleVersion</key>\n\t<string>$(FLUTTER_BUILD_NUMBER)</string>\n\t<key>LSMinimumSystemVersion</key>\n\t<string>$(MACOSX_DEPLOYMENT_TARGET)</string>\n\t<key>NSHumanReadableCopyright</key>\n\t<string>$(PRODUCT_COPYRIGHT)</string>\n\t<key>NSMainNibFile</key>\n\t<string>MainMenu</string>\n\t<key>NSPrincipalClass</key>\n\t<string>NSApplication</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "example/macos/Runner/MainFlutterWindow.swift",
    "content": "import Cocoa\nimport FlutterMacOS\n\nclass MainFlutterWindow: NSWindow {\n  override func awakeFromNib() {\n    let flutterViewController = FlutterViewController.init()\n    let windowFrame = self.frame\n    self.contentViewController = flutterViewController\n    self.setFrame(windowFrame, display: true)\n\n    RegisterGeneratedPlugins(registry: flutterViewController)\n\n    super.awakeFromNib()\n  }\n}\n"
  },
  {
    "path": "example/macos/Runner/Release.entitlements",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>com.apple.security.app-sandbox</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "example/macos/Runner.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 51;\n\tobjects = {\n\n/* Begin PBXAggregateTarget section */\n\t\t33CC111A2044C6BA0003C045 /* Flutter Assemble */ = {\n\t\t\tisa = PBXAggregateTarget;\n\t\t\tbuildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget \"Flutter Assemble\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t33CC111E2044C6BF0003C045 /* ShellScript */,\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = \"Flutter Assemble\";\n\t\t\tproductName = FLX;\n\t\t};\n/* End PBXAggregateTarget section */\n\n/* Begin PBXBuildFile section */\n\t\t335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; };\n\t\t33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; };\n\t\t33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; };\n\t\t33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; };\n\t\t33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; };\n\t\t8815B0F3A29FC1385CF756F4 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6E8F5A4D8780AB8D8C762C95 /* Pods_Runner.framework */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXContainerItemProxy section */\n\t\t33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 33CC10E52044A3C60003C045 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 33CC111A2044C6BA0003C045;\n\t\t\tremoteInfo = FLX;\n\t\t};\n/* End PBXContainerItemProxy section */\n\n/* Begin PBXCopyFilesBuildPhase section */\n\t\t33CC110E2044A8840003C045 /* Bundle Framework */ = {\n\t\t\tisa = PBXCopyFilesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tdstPath = \"\";\n\t\t\tdstSubfolderSpec = 10;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tname = \"Bundle Framework\";\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXCopyFilesBuildPhase section */\n\n/* Begin PBXFileReference section */\n\t\t0563EE70CEF5E33F3580B358 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-Runner.debug.xcconfig\"; path = \"Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = \"<group>\"; };\n\t\t335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = \"<group>\"; };\n\t\t33CC10ED2044A3C60003C045 /* Flutter Layout Grid.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = \"Flutter Layout Grid.app\"; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = \"<group>\"; };\n\t\t33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = \"<group>\"; };\n\t\t33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = \"<group>\"; };\n\t\t33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = \"<group>\"; };\n\t\t33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = \"<group>\"; };\n\t\t33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = \"Flutter-Debug.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = \"Flutter-Release.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = \"Flutter-Generated.xcconfig\"; path = \"ephemeral/Flutter-Generated.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = \"<group>\"; };\n\t\t33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = \"<group>\"; };\n\t\t33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = \"<group>\"; };\n\t\t6E8F5A4D8780AB8D8C762C95 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t7378D2C7C138E8A5D707CC48 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-Runner.profile.xcconfig\"; path = \"Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = \"<group>\"; };\n\t\t9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = \"<group>\"; };\n\t\tA30B91E86958AF5E12DDACF8 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-Runner.release.xcconfig\"; path = \"Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig\"; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t33CC10EA2044A3C60003C045 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t8815B0F3A29FC1385CF756F4 /* Pods_Runner.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t04D0F362C8AC0DB9FD3754B1 /* Pods */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t0563EE70CEF5E33F3580B358 /* Pods-Runner.debug.xcconfig */,\n\t\t\t\tA30B91E86958AF5E12DDACF8 /* Pods-Runner.release.xcconfig */,\n\t\t\t\t7378D2C7C138E8A5D707CC48 /* Pods-Runner.profile.xcconfig */,\n\t\t\t);\n\t\t\tname = Pods;\n\t\t\tpath = Pods;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t33BA886A226E78AF003329D5 /* Configs */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t33E5194F232828860026EE4D /* AppInfo.xcconfig */,\n\t\t\t\t9740EEB21CF90195004384FC /* Debug.xcconfig */,\n\t\t\t\t7AFA3C8E1D35360C0083082E /* Release.xcconfig */,\n\t\t\t\t333000ED22D3DE5D00554162 /* Warnings.xcconfig */,\n\t\t\t);\n\t\t\tpath = Configs;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t33CC10E42044A3C60003C045 = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t33FAB671232836740065AC1E /* Runner */,\n\t\t\t\t33CEB47122A05771004F2AC0 /* Flutter */,\n\t\t\t\t33CC10EE2044A3C60003C045 /* Products */,\n\t\t\t\tD73912EC22F37F3D000D13A0 /* Frameworks */,\n\t\t\t\t04D0F362C8AC0DB9FD3754B1 /* Pods */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t33CC10EE2044A3C60003C045 /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t33CC10ED2044A3C60003C045 /* Flutter Layout Grid.app */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t33CC11242044D66E0003C045 /* Resources */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t33CC10F22044A3C60003C045 /* Assets.xcassets */,\n\t\t\t\t33CC10F42044A3C60003C045 /* MainMenu.xib */,\n\t\t\t\t33CC10F72044A3C60003C045 /* Info.plist */,\n\t\t\t);\n\t\t\tname = Resources;\n\t\t\tpath = ..;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t33CEB47122A05771004F2AC0 /* Flutter */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */,\n\t\t\t\t33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */,\n\t\t\t\t33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */,\n\t\t\t\t33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */,\n\t\t\t);\n\t\t\tpath = Flutter;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t33FAB671232836740065AC1E /* Runner */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t33CC10F02044A3C60003C045 /* AppDelegate.swift */,\n\t\t\t\t33CC11122044BFA00003C045 /* MainFlutterWindow.swift */,\n\t\t\t\t33E51913231747F40026EE4D /* DebugProfile.entitlements */,\n\t\t\t\t33E51914231749380026EE4D /* Release.entitlements */,\n\t\t\t\t33CC11242044D66E0003C045 /* Resources */,\n\t\t\t\t33BA886A226E78AF003329D5 /* Configs */,\n\t\t\t);\n\t\t\tpath = Runner;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tD73912EC22F37F3D000D13A0 /* Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t6E8F5A4D8780AB8D8C762C95 /* Pods_Runner.framework */,\n\t\t\t);\n\t\t\tname = Frameworks;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t33CC10EC2044A3C60003C045 /* Runner */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget \"Runner\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t7EDA30E94B48E8D49E624B8D /* [CP] Check Pods Manifest.lock */,\n\t\t\t\t33CC10E92044A3C60003C045 /* Sources */,\n\t\t\t\t33CC10EA2044A3C60003C045 /* Frameworks */,\n\t\t\t\t33CC10EB2044A3C60003C045 /* Resources */,\n\t\t\t\t33CC110E2044A8840003C045 /* Bundle Framework */,\n\t\t\t\t3399D490228B24CF009A79C7 /* ShellScript */,\n\t\t\t\t8B019104F9D609ED877E544F /* [CP] Embed Pods Frameworks */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\t33CC11202044C79F0003C045 /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = Runner;\n\t\t\tproductName = Runner;\n\t\t\tproductReference = 33CC10ED2044A3C60003C045 /* Flutter Layout Grid.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t33CC10E52044A3C60003C045 /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastSwiftUpdateCheck = 0920;\n\t\t\t\tLastUpgradeCheck = 0930;\n\t\t\t\tORGANIZATIONNAME = \"Google LLC\";\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t33CC10EC2044A3C60003C045 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 9.2;\n\t\t\t\t\t\tLastSwiftMigration = 1100;\n\t\t\t\t\t\tProvisioningStyle = Automatic;\n\t\t\t\t\t\tSystemCapabilities = {\n\t\t\t\t\t\t\tcom.apple.Sandbox = {\n\t\t\t\t\t\t\t\tenabled = 1;\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t};\n\t\t\t\t\t};\n\t\t\t\t\t33CC111A2044C6BA0003C045 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 9.2;\n\t\t\t\t\t\tProvisioningStyle = Manual;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject \"Runner\" */;\n\t\t\tcompatibilityVersion = \"Xcode 8.0\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = 33CC10E42044A3C60003C045;\n\t\t\tproductRefGroup = 33CC10EE2044A3C60003C045 /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t33CC10EC2044A3C60003C045 /* Runner */,\n\t\t\t\t33CC111A2044C6BA0003C045 /* Flutter Assemble */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t33CC10EB2044A3C60003C045 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */,\n\t\t\t\t33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXShellScriptBuildPhase section */\n\t\t3399D490228B24CF009A79C7 /* ShellScript */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputFileListPaths = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t);\n\t\t\toutputFileListPaths = (\n\t\t\t);\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"echo \\\"$PRODUCT_NAME.app\\\" > \\\"$PROJECT_DIR\\\"/Flutter/ephemeral/.app_filename && \\\"$FLUTTER_ROOT\\\"/packages/flutter_tools/bin/macos_assemble.sh embed\\n\";\n\t\t};\n\t\t33CC111E2044C6BF0003C045 /* ShellScript */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputFileListPaths = (\n\t\t\t\tFlutter/ephemeral/FlutterInputs.xcfilelist,\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t\tFlutter/ephemeral/tripwire,\n\t\t\t);\n\t\t\toutputFileListPaths = (\n\t\t\t\tFlutter/ephemeral/FlutterOutputs.xcfilelist,\n\t\t\t);\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"\\\"$FLUTTER_ROOT\\\"/packages/flutter_tools/bin/macos_assemble.sh\\ntouch Flutter/ephemeral/tripwire\\n\";\n\t\t};\n\t\t7EDA30E94B48E8D49E624B8D /* [CP] Check Pods Manifest.lock */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputFileListPaths = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t\t\"${PODS_PODFILE_DIR_PATH}/Podfile.lock\",\n\t\t\t\t\"${PODS_ROOT}/Manifest.lock\",\n\t\t\t);\n\t\t\tname = \"[CP] Check Pods Manifest.lock\";\n\t\t\toutputFileListPaths = (\n\t\t\t);\n\t\t\toutputPaths = (\n\t\t\t\t\"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt\",\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"diff \\\"${PODS_PODFILE_DIR_PATH}/Podfile.lock\\\" \\\"${PODS_ROOT}/Manifest.lock\\\" > /dev/null\\nif [ $? != 0 ] ; then\\n    # print error to STDERR\\n    echo \\\"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\\\" >&2\\n    exit 1\\nfi\\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\\necho \\\"SUCCESS\\\" > \\\"${SCRIPT_OUTPUT_FILE_0}\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n\t\t8B019104F9D609ED877E544F /* [CP] Embed Pods Frameworks */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t\t\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\",\n\t\t\t\t\"${BUILT_PRODUCTS_DIR}/path_provider_macos/path_provider_macos.framework\",\n\t\t\t);\n\t\t\tname = \"[CP] Embed Pods Frameworks\";\n\t\t\toutputPaths = (\n\t\t\t\t\"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/path_provider_macos.framework\",\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"\\\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n/* End PBXShellScriptBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t33CC10E92044A3C60003C045 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */,\n\t\t\t\t33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */,\n\t\t\t\t335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXTargetDependency section */\n\t\t33CC11202044C79F0003C045 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 33CC111A2044C6BA0003C045 /* Flutter Assemble */;\n\t\t\ttargetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */;\n\t\t};\n/* End PBXTargetDependency section */\n\n/* Begin PBXVariantGroup section */\n\t\t33CC10F42044A3C60003C045 /* MainMenu.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t33CC10F52044A3C60003C045 /* Base */,\n\t\t\t);\n\t\t\tname = MainMenu.xib;\n\t\t\tpath = Runner;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXVariantGroup section */\n\n/* Begin XCBuildConfiguration section */\n\t\t338D0CE9231458BD00FA5F75 /* Profile */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++14\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"-\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu11;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 10.11;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tSDKROOT = macosx;\n\t\t\t\tSWIFT_COMPILATION_MODE = wholemodule;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-O\";\n\t\t\t};\n\t\t\tname = Profile;\n\t\t};\n\t\t338D0CEA231458BD00FA5F75 /* Profile */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tFRAMEWORK_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"$(PROJECT_DIR)/Flutter/ephemeral\",\n\t\t\t\t);\n\t\t\t\tINFOPLIST_FILE = Runner/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/../Frameworks\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.example.flutterLayoutGrid;\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t};\n\t\t\tname = Profile;\n\t\t};\n\t\t338D0CEB231458BD00FA5F75 /* Profile */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCODE_SIGN_STYLE = Manual;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t};\n\t\t\tname = Profile;\n\t\t};\n\t\t33CC10F92044A3C60003C045 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++14\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"-\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu11;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 10.11;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = macosx;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t33CC10FA2044A3C60003C045 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++14\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"-\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu11;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 10.11;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tSDKROOT = macosx;\n\t\t\t\tSWIFT_COMPILATION_MODE = wholemodule;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-O\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t33CC10FC2044A3C60003C045 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tFRAMEWORK_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"$(PROJECT_DIR)/Flutter/ephemeral\",\n\t\t\t\t);\n\t\t\t\tINFOPLIST_FILE = Runner/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/../Frameworks\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.example.flutterLayoutGrid;\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t33CC10FD2044A3C60003C045 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tFRAMEWORK_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"$(PROJECT_DIR)/Flutter/ephemeral\",\n\t\t\t\t);\n\t\t\t\tINFOPLIST_FILE = Runner/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/../Frameworks\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.example.flutterLayoutGrid;\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t33CC111C2044C6BA0003C045 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCODE_SIGN_STYLE = Manual;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t33CC111D2044C6BA0003C045 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t33CC10E82044A3C60003C045 /* Build configuration list for PBXProject \"Runner\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t33CC10F92044A3C60003C045 /* Debug */,\n\t\t\t\t33CC10FA2044A3C60003C045 /* Release */,\n\t\t\t\t338D0CE9231458BD00FA5F75 /* Profile */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget \"Runner\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t33CC10FC2044A3C60003C045 /* Debug */,\n\t\t\t\t33CC10FD2044A3C60003C045 /* Release */,\n\t\t\t\t338D0CEA231458BD00FA5F75 /* Profile */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget \"Flutter Assemble\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t33CC111C2044C6BA0003C045 /* Debug */,\n\t\t\t\t33CC111D2044C6BA0003C045 /* Release */,\n\t\t\t\t338D0CEB231458BD00FA5F75 /* Profile */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = 33CC10E52044A3C60003C045 /* Project object */;\n}\n"
  },
  {
    "path": "example/macos/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"self:/Users/stuartmorgan/src/embedder-opensource/flutter-desktop-embedding/example/macos/Runner.xcodeproj\">\n   </FileRef>\n</Workspace>\n"
  },
  {
    "path": "example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>IDEDidComputeMac32BitWarning</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1000\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"33CC10EC2044A3C60003C045\"\n               BuildableName = \"flutter_grid_layout.app\"\n               BlueprintName = \"Runner\"\n               ReferencedContainer = \"container:Runner.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <Testables>\n         <TestableReference\n            skipped = \"NO\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"00380F9121DF178D00097171\"\n               BuildableName = \"RunnerUITests.xctest\"\n               BlueprintName = \"RunnerUITests\"\n               ReferencedContainer = \"container:Runner.xcodeproj\">\n            </BuildableReference>\n         </TestableReference>\n      </Testables>\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"33CC10EC2044A3C60003C045\"\n            BuildableName = \"flutter_grid_layout.app\"\n            BlueprintName = \"Runner\"\n            ReferencedContainer = \"container:Runner.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"33CC10EC2044A3C60003C045\"\n            BuildableName = \"flutter_grid_layout.app\"\n            BlueprintName = \"Runner\"\n            ReferencedContainer = \"container:Runner.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"33CC10EC2044A3C60003C045\"\n            BuildableName = \"flutter_grid_layout.app\"\n            BlueprintName = \"Runner\"\n            ReferencedContainer = \"container:Runner.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "example/macos/Runner.xcworkspace/contents.xcworkspacedata",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"group:Runner.xcodeproj\">\n   </FileRef>\n   <FileRef\n      location = \"group:Pods/Pods.xcodeproj\">\n   </FileRef>\n</Workspace>\n"
  },
  {
    "path": "example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>IDEDidComputeMac32BitWarning</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "example/pubspec.yaml",
    "content": "name: flutter_layout_grid_examples\ndescription: Examples for flutter_layout_grid.\nprivate: true\n\nenvironment:\n  sdk: \">=2.14.0 <4.0.0\"\n\ndependencies:\n  flutter:\n    sdk: flutter\n  flutter_layout_grid:\n    path: ../\n  google_fonts: ^6.2.1\n\ndev_dependencies:\n  flutter_lints: ^3.0.0\n\nflutter:\n  assets:\n    - lib/periodic_table_data.json\n"
  },
  {
    "path": "lib/flutter_layout_grid.dart",
    "content": "library flutter_layout_grid;\n\nexport 'src/foundation/placement.dart' show GridArea;\nexport 'src/helpers.dart';\nexport 'src/rendering/track_size.dart' hide trackSizeListsEqual;\nexport 'src/widgets/layout_grid.dart';\nexport 'src/widgets/placement.dart';\n"
  },
  {
    "path": "lib/src/foundation/box.dart",
    "content": "import 'package:flutter/rendering.dart';\nimport 'package:flutter_layout_grid/src/widgets/layout_grid.dart';\n\nextension LayoutGridExtensionsForBoxConstraints on BoxConstraints {\n  /// Returns a new [BoxConstraints] with unbounded (infinite) maximums.\n  BoxConstraints get unbound =>\n      copyWith(maxWidth: double.infinity, maxHeight: double.infinity);\n\n  /// Returns a new [BoxConstraints] tightening or loosening the receiver as\n  /// specified by [gridFit].\n  BoxConstraints constraintsForGridFit(GridFit gridFit) {\n    switch (gridFit) {\n      case GridFit.expand:\n        final upperBound = biggest;\n        return BoxConstraints.tightForFinite(\n          width: upperBound.width,\n          height: upperBound.height,\n        );\n\n      case GridFit.loose:\n        return loosen();\n\n      case GridFit.passthrough:\n        return this;\n    }\n  }\n}\n"
  },
  {
    "path": "lib/src/foundation/collections.dart",
    "content": "extension IterableExt<E> on Iterable<E> {\n  /// Returns a new iterable based on this one with all duplicates removed. The\n  /// first occurrence of each element with a duplicate will be retained.\n  Iterable<E> removeDuplicates() =>\n      _WhereBuilderIterable(this, _removeDuplicatesPredicate);\n}\n\n/// Removes duplicate elements from a collection. The type `T` should implement\n/// [Object.hashCode] and [Object.==], if value-based comparison is desired.\n///\n/// Can be provided as a predicate to [List.removeWhere], [Set.removeWhere],\n/// and others.\nbool Function(T) _removeDuplicatesPredicate<T>() {\n  final seen = <T>{};\n  return seen.add;\n}\n\n/// Sums the elements of [numbers], and returns the result.\nT sum<T extends num>(Iterable<T> numbers) {\n  return numbers.fold(zeroForType<T>(), (acc, number) => (acc + number) as T);\n}\n\n/// Returns an iterable of [number]'s cumulative sums.\n///\n/// ```\n/// cumulativeSum([1, 2, 3]) // 0, 1, 3, 6\n/// cumulativeSum([2.0, 4.0, 6.0]) // 0.0, 2.0, 6.0, 12.0\n/// ```\nIterable<T> cumulativeSum<T extends num>(\n  Iterable<T> numbers, {\n  bool includeLast = true,\n}) sync* {\n  T current = zeroForType<T>();\n  for (final i in numbers) {\n    yield current;\n    current = (current + i) as T;\n  }\n  if (includeLast) yield current;\n}\n\n/// Returns the representation of `0` for a [num] type `T`.\nT zeroForType<T extends num>() => (T == int ? 0 : 0.0) as T;\n\n/// A filtering iterable, that invokes the provided predicate builder every time\n/// an iterator is requested. This allows predicates to hold state.\nclass _WhereBuilderIterable<E> extends Iterable<E> {\n  final Iterable<E> _iterable;\n  final _ElementPredicate<E> Function() _predicateBuilder;\n\n  _WhereBuilderIterable(this._iterable, this._predicateBuilder);\n\n  @override\n  Iterator<E> get iterator =>\n      _WhereIterator(_iterable.iterator, _predicateBuilder());\n}\n\nclass _WhereIterator<E> extends Iterator<E> {\n  final Iterator<E> _iterator;\n  final _ElementPredicate<E> _f;\n\n  _WhereIterator(this._iterator, this._f);\n\n  @override\n  bool moveNext() {\n    while (_iterator.moveNext()) {\n      if (_f(_iterator.current)) {\n        return true;\n      }\n    }\n    return false;\n  }\n\n  @override\n  E get current => _iterator.current;\n}\n\ntypedef _ElementPredicate<E> = bool Function(E element);\n"
  },
  {
    "path": "lib/src/foundation/placement.dart",
    "content": "// ignore_for_file: unnecessary_this\n\nimport 'dart:convert';\nimport 'dart:math';\n\nimport 'package:flutter/foundation.dart';\nimport 'package:flutter/painting.dart';\nimport 'package:quiver/core.dart';\n\n/// Represents a rectangular region on the grid.\n@immutable\nclass GridArea {\n  const GridArea({\n    this.name,\n    required this.columnStart,\n    required this.columnEnd,\n    required this.rowStart,\n    required this.rowEnd,\n  });\n\n  const GridArea.withSpans({\n    this.name,\n    required this.columnStart,\n    required int columnSpan,\n    required this.rowStart,\n    required int rowSpan,\n  })  : this.columnEnd = columnStart + columnSpan,\n        this.rowEnd = rowStart + rowSpan;\n\n  final String? name;\n  final int columnStart;\n  final int rowStart;\n\n  /// The end column, exclusive\n  final int columnEnd;\n  int get columnSpan => columnEnd - columnStart;\n\n  /// The end row, exclusive\n  final int rowEnd;\n  int get rowSpan => rowEnd - rowStart;\n\n  int startForAxis(Axis axis) =>\n      axis == Axis.horizontal ? columnStart : rowStart;\n  int endForAxis(Axis axis) => axis == Axis.horizontal ? columnEnd : rowEnd;\n  int spanForAxis(Axis axis) => endForAxis(axis) - startForAxis(axis);\n\n  @override\n  int get hashCode =>\n      hashObjects(<dynamic>[name, columnStart, columnEnd, rowStart, rowEnd]);\n\n  @override\n  bool operator ==(Object other) {\n    if (other.runtimeType != runtimeType) return false;\n    if (identical(other, this)) return true;\n    return other is GridArea &&\n        other.name == name &&\n        other.columnStart == columnStart &&\n        other.columnEnd == columnEnd &&\n        other.rowStart == rowStart &&\n        other.rowEnd == rowEnd;\n  }\n\n  @override\n  String toString() {\n    return 'GridArea('\n        '${(name != null ? 'name=$name, ' : '')}'\n        'columnSpan=[$columnStart–$columnEnd], rowSpan=[$rowStart–$rowEnd])';\n  }\n}\n\n/// Describes the named areas of a grid for [LayoutGrid.areas].\n///\n/// Named areas can be used for the placement of grid items, via\n/// [NamedAreaGridPlacement].\n///\n/// Use [parseNamedAreasSpec] to produce one of these objects based on a string\n/// formatted similarly to CSS's `grid-template-areas`.\n/// ``\nclass NamedGridAreas {\n  NamedGridAreas({\n    required this.columnCount,\n    required this.rowCount,\n    required Map<String, GridArea> areas,\n  }) : _areas = areas;\n\n  final int columnCount;\n  final int rowCount;\n  final Map<String, GridArea> _areas;\n\n  /// The number of named areas\n  int get length => _areas.length;\n\n  /// The [GridArea] named [areaName], or `null` if it does not exist\n  GridArea? operator [](String? areaName) => _areas[areaName!];\n}\n\n/// Parses a set of strings into a description of the grid's named areas.\n///\n/// The format of [namedAreasSpec] is similar to the format supplied to CSS Grid\n/// Layout's `grid-template-areas` property:\n/// https://developer.mozilla.org/en-US/docs/Web/CSS/grid-template-areas\n///\n/// The only difference is that it is a multiline string. Rows must be separated\n/// by newlines.\n///\n/// Example input:\n///\n/// ```dart\n/// parseNamedAreasSpec('''\n///   head head,\n///   nav  main,\n///   nav  foot,\n/// ''');\n/// ```\n///\nNamedGridAreas parseNamedAreasSpec(String namedAreasSpec) {\n  final gridAreaBuilders = <String, _GridAreaBuilder>{};\n  int? columnCount;\n\n  final rowSpecs = LineSplitter.split(namedAreasSpec)\n      .map((line) => line.trim())\n      .where((line) => line.isNotEmpty)\n      .toList();\n\n  for (int currentRow = 0; currentRow < rowSpecs.length; currentRow++) {\n    final rowSpec = rowSpecs[currentRow];\n    final cellSpecs = rowSpec.split(_tokenSeparatorPattern);\n\n    if (columnCount == null) {\n      columnCount = cellSpecs.length;\n    } else if (columnCount != cellSpecs.length) {\n      throw ArgumentError(\n          'Row ($currentRow) has the wrong number of area names, '\n          'expected=$columnCount found=${cellSpecs.length}');\n    }\n\n    for (int currentColumn = 0;\n        currentColumn < cellSpecs.length;\n        currentColumn++) {\n      final token = cellSpecs[currentColumn];\n      if (_isNamedCellToken(token)) {\n        final builder =\n            gridAreaBuilders.putIfAbsent(token, () => _GridAreaBuilder(token));\n        builder.addCell(currentColumn, currentRow);\n      } else if (!_isNullCellToken(token)) {\n        throw ArgumentError('Invalid area name, name=$token\\n'\n            r'Must be in /^[a-zA-Z][\\w\\d-_]*$/');\n      }\n    }\n  }\n\n  return NamedGridAreas(\n    columnCount: columnCount!,\n    rowCount: rowSpecs.length,\n    areas: gridAreaBuilders.map(\n      (name, builder) => MapEntry(name, builder.build()),\n    ),\n  );\n}\n\nfinal _tokenSeparatorPattern = RegExp(r'\\s+');\n\nfinal _nullCellPattern = RegExp(r'^\\.$');\nbool _isNullCellToken(String token) => _nullCellPattern.hasMatch(token);\n\nfinal _namedCellPattern = RegExp(r'^[^\\.\\s]+$');\nbool _isNamedCellToken(String token) => _namedCellPattern.hasMatch(token);\n\n/// Determines the region of a [GridArea] by adding individual (column, row)\n/// pairs.\nclass _GridAreaBuilder {\n  _GridAreaBuilder(this.areaName);\n  final String areaName;\n\n  int? _minColumn;\n  int? _maxColumn;\n  int? _minRow;\n  int? _maxRow;\n\n  /// When a new column or row is introduced to the area when adding a cell,\n  /// there will be a number of cells that require filling in order for the area\n  /// to become a complete rectangle. This keeps track of that count. If\n  /// non-zero, the [build] method will throw.\n  int _missingCells = 0;\n\n  void addCell(int column, int row) {\n    if (_minColumn == null) {\n      _minColumn = _maxColumn = column;\n      _missingCells++;\n    } else if (_ensureColumnInRange(column)) {\n      _missingCells += _addedColumnCount(column) * (_maxRow! - _minRow! + 1);\n      _minColumn = min(_minColumn!, column);\n      _maxColumn = max(_maxColumn!, column);\n    } else {\n      throw ArgumentError(\n          'Area disjoint, column=$column row=$row name=$areaName');\n    }\n\n    if (_minRow == null) {\n      _minRow = _maxRow = row;\n    } else if (_ensureRowInRange(row)) {\n      _missingCells += _addedRowCount(row) * (_maxColumn! - _minColumn! + 1);\n      _minRow = min(_minRow!, row);\n      _maxRow = max(_maxRow!, row);\n    } else {\n      throw ArgumentError(\n          'Area disjoint, column=$column row=$row name=$areaName');\n    }\n\n    _missingCells--;\n  }\n\n  bool _ensureColumnInRange(int column) => _addedColumnCount(column) <= 1;\n  int _addedColumnCount(int column) {\n    return column <= _minColumn!\n        ? _minColumn! - column\n        : column >= _maxColumn!\n            ? column - _maxColumn!\n            : 0;\n  }\n\n  bool _ensureRowInRange(int row) => _addedRowCount(row) <= 1;\n  int _addedRowCount(int row) {\n    return row <= _minRow!\n        ? _minRow! - row\n        : row >= _maxRow!\n            ? row - _maxRow!\n            : 0;\n  }\n\n  GridArea build() {\n    if (_missingCells != 0) {\n      throw ArgumentError('Missing cells from grid area template. '\n          'Areas must be rectangular. name=$areaName');\n    }\n\n    return GridArea(\n      name: areaName,\n      columnStart: _minColumn!,\n      columnEnd: _maxColumn! + 1,\n      rowStart: _minRow!,\n      rowEnd: _maxRow! + 1,\n    );\n  }\n}\n"
  },
  {
    "path": "lib/src/helpers.dart",
    "content": "import 'package:flutter/widgets.dart';\n\nimport 'rendering/track_size.dart';\nimport 'widgets/placement.dart';\n\n/// An [IntrinsicContentTrackSize], mirroring CSS's name for the track sizing\n/// function.\nconst auto = IntrinsicContentTrackSize();\n\n/// Returns a track size that is sized based on its contents.\nIntrinsicContentTrackSize intrinsic({String? debugLabel}) =>\n    IntrinsicContentTrackSize(debugLabel: debugLabel);\n\n/// Returns a new track size that is exactly [sizeInPx] wide.\nFixedTrackSize fixed(double sizeInPx, {String? debugLabel}) =>\n    FixedTrackSize(sizeInPx, debugLabel: debugLabel);\n\n/// Returns a new track size that expands to fill available space.\nFlexibleTrackSize flex(double flexFactor, {String? debugLabel}) =>\n    FlexibleTrackSize(flexFactor, debugLabel: debugLabel);\n\n/// Defines a set of extension methods on [num] for creating tracks\nextension TrackUnitsNumExtension on num {\n  FixedTrackSize get px => fixed(toDouble());\n  FlexibleTrackSize get fr => flex(toDouble());\n}\n\n/// Returns this list repeated [times] times.\n///\n///     repeat(2, [fixed(100), fixed(200)])\n///     // [fixed(100), fixed(200), fixed(100), fixed(200)]\n///\nList<TrackSize> repeat(int times, List<TrackSize> tracks) =>\n    _repeat(times, tracks).toList();\n\nIterable<T> _repeat<T>(int times, Iterable<T> source) sync* {\n  for (int i = 0; i < times; i++) {\n    yield* source;\n  }\n}\n\n/// Convenience function for pretty grid definitions, ala:\n///\n///     LayoutGrid(\n///       areas: '''\n///         pink   pink   .\n///         pink   pink   red\n///         orange yellow red\n///       ''',\n///       columnSizes: [fixed(100), fixed(100), fixed(100)],\n///       rowSizes: [\n///         fixed(100),\n///         fixed(100),\n///         fixed(100),\n///        ],\n///       children: [\n///         //!!!\n///         gridArea('pink').containing(Container(color: Colors.pink)),\n///         gridArea('red').containing(Container(color: Colors.red)),\n///         gridArea('orange').containing(Container(color: Colors.orange)),\n///         gridArea('yellow').containing(Container(color: Colors.yellow)),\n///       ],\n///     )\n///\nNamedAreaGridPlacementBuilder gridArea(String name) {\n  return NamedAreaGridPlacementBuilder._(name);\n}\n\n/// Dumb little helper class for slightly cleaner grid child placement\n@immutable\nclass NamedAreaGridPlacementBuilder {\n  const NamedAreaGridPlacementBuilder._(this.name);\n\n  final String name;\n\n  NamedAreaGridPlacement containing(Widget child) {\n    return NamedAreaGridPlacement(\n      areaName: name,\n      child: child,\n    );\n  }\n}\n"
  },
  {
    "path": "lib/src/rendering/debug.dart",
    "content": "import 'package:flutter/widgets.dart';\n\nimport 'layout_grid.dart';\n\n/// If `true`, track sizing will be logged to the console via Flutter's\n/// [debugPrint] function.\nbool debugPrintGridLayout = false;\n\n/// If `true`, unplaced children will be logged to the console via Flutter's\n/// [debugPrint] function.\nbool debugPrintUnplacedChildren = false;\n\nString debugTrackIndicesString(Iterable<GridTrack> tracks,\n    {bool trackPrefix = false}) {\n  final trackIndices = debugPrettyIndices(tracks.map((t) => t.index));\n\n  return tracks.isEmpty\n      ? trackIndices\n      : tracks.length == 1\n          ? 'track $trackIndices'\n          : 'tracks $trackIndices';\n}\n\nString debugPrettyIndices(Iterable<int> indices) {\n  return indices.isEmpty\n      ? '(none)'\n      : indices.length > 1\n          ? '[${indices.join(',')}]'\n          : '${indices.first}';\n}\n"
  },
  {
    "path": "lib/src/rendering/layout_grid.dart",
    "content": "// ignore_for_file: unnecessary_this\n\nimport 'dart:math' as math;\n\nimport 'package:collection/collection.dart';\nimport 'package:flutter/foundation.dart';\nimport 'package:flutter/rendering.dart';\nimport 'package:quiver/iterables.dart';\n\nimport '../foundation/box.dart';\nimport '../foundation/collections.dart';\nimport '../foundation/placement.dart';\nimport '../widgets/layout_grid.dart';\nimport 'debug.dart';\nimport 'placement.dart';\nimport 'track_size.dart';\n\n/// Parent data for use with [RenderLayoutGrid].\nclass GridParentData extends ContainerBoxParentData<RenderBox> {\n  GridParentData({\n    this.columnStart,\n    this.columnSpan = 1,\n    this.rowStart,\n    this.rowSpan = 1,\n    this.debugLabel,\n  });\n\n  /// If `null`, the item is auto-placed.\n  int? columnStart;\n  int? columnSpan;\n\n  /// If `null`, the item is auto-placed.\n  int? rowStart;\n  int? rowSpan;\n\n  String? _areaName;\n\n  String? debugLabel;\n\n  String? get areaName => _areaName;\n  set areaName(String? value) {\n    if (value == _areaName) {\n      return;\n    }\n\n    _areaName = value;\n    columnStart = rowStart = null;\n\n    // If an area name has been specified, we mark the data as needing area\n    // resolution, and null out all fields.\n    if (value != null) {\n      columnSpan = rowSpan = null;\n    } else {\n      // If no area name has been specified, we reset the data to base state.\n      // These values are likely to be overwritten momentarily.\n      columnSpan = rowSpan = 1;\n    }\n  }\n\n  int? startForAxis(Axis axis) =>\n      axis == Axis.horizontal ? columnStart : rowStart;\n\n  int? spanForAxis(Axis axis) => //\n      axis == Axis.horizontal ? columnSpan : rowSpan;\n\n  GridArea get area {\n    assert(isDefinitelyPlaced);\n    return GridArea(\n      name: areaName,\n      columnStart: columnStart!,\n      columnEnd: columnStart! + columnSpan!,\n      rowStart: rowStart!,\n      rowEnd: rowStart! + rowSpan!,\n    );\n  }\n\n  set area(GridArea? value) {\n    // If null, clear out all track starts/spans\n    if (value == null) {\n      columnStart = columnSpan = rowStart = rowSpan = null;\n    }\n    // Otherwise set the specifics\n    else {\n      columnStart = value.columnStart;\n      columnSpan = value.columnSpan;\n      rowStart = value.rowStart;\n      rowSpan = value.rowSpan;\n    }\n  }\n\n  /// `true` if the item is placed in the grid, whether definitely or through\n  /// the auto-flow algorithm.\n  bool get isPlaced => !isNotPlaced;\n\n  /// `true` if the item is not placed in the grid at all (probably because\n  /// it references a named area that does not exist).\n  bool get isNotPlaced =>\n      columnStart == null &&\n      columnSpan == null &&\n      rowStart == null &&\n      rowSpan == null;\n\n  /// `true` if the item has definite placement in the grid.\n  bool get isDefinitelyPlaced => columnStart != null && rowStart != null;\n\n  /// `true` if the item is definitely placed on the provided axis.\n  bool isDefinitelyPlacedOnAxis(Axis axis) =>\n      axis == Axis.horizontal ? columnStart != null : rowStart != null;\n\n  @override\n  String toString() {\n    final List<String> values = <String>[\n      if (areaName != null) 'areaName=$areaName',\n      if (columnStart != null) 'columnStart=$columnStart',\n      if (columnSpan != null) 'columnSpan=$columnSpan',\n      if (rowStart != null) 'rowStart=$rowStart',\n      if (rowSpan != null) 'rowSpan=$rowSpan',\n      if (debugLabel != null) 'debugLabel=$debugLabel',\n    ];\n    values.add(super.toString());\n    return values.join('; ');\n  }\n}\n\n/// Implements the grid layout algorithm.\n///\n/// The layout algorithm is a rough approximation of the one described in\n/// https://drafts.csswg.org/css-grid/#algo-track-sizing, adapted for Flutter.\n///\n/// See [performLayout] for the details.\nclass RenderLayoutGrid extends RenderBox\n    with\n        ContainerRenderObjectMixin<RenderBox, GridParentData>,\n        RenderBoxContainerDefaultsMixin<RenderBox, GridParentData>,\n        DebugOverflowIndicatorMixin {\n  /// Creates a layout grid render object.\n  RenderLayoutGrid({\n    AutoPlacement autoPlacement = AutoPlacement.rowSparse,\n    GridFit gridFit = GridFit.expand,\n    List<RenderBox>? children,\n    double columnGap = 0,\n    double rowGap = 0,\n    String? areasSpec,\n    required List<TrackSize> columnSizes,\n    required List<TrackSize> rowSizes,\n    required TextDirection textDirection,\n  })  : _autoPlacementMode = autoPlacement,\n        _gridFit = gridFit,\n        _columnSizes = columnSizes,\n        _rowSizes = rowSizes,\n        _areasSpec = areasSpec,\n        _areas = areasSpec != null ? parseNamedAreasSpec(areasSpec) : null,\n        _columnGap = columnGap,\n        _rowGap = rowGap,\n        _textDirection = textDirection {\n    addAll(children);\n  }\n\n  @visibleForTesting\n  bool needsPlacement = true;\n  late PlacementGrid _placementGrid;\n\n  /// The row and column sizing information calculated during the previous\n  /// grid layout pass.\n  late GridSizingInfo lastGridSizing;\n\n  /// The union of children contained in this grid. Only set during debug\n  /// builds.\n  late Rect _debugChildRect;\n\n  /// Controls how the auto-placement algorithm works, specifying exactly how\n  /// auto-placed items get flowed into the grid.\n  AutoPlacement get autoPlacement => _autoPlacementMode;\n  AutoPlacement _autoPlacementMode;\n  set autoPlacement(AutoPlacement value) {\n    if (_autoPlacementMode == value) return;\n    _autoPlacementMode = value;\n    markNeedsPlacement();\n    markNeedsLayout();\n  }\n\n  /// Determines the constraints available to the grid layout algorithm.\n  GridFit get gridFit => _gridFit;\n  GridFit _gridFit;\n  set gridFit(GridFit value) {\n    if (_gridFit == value) return;\n    _gridFit = value;\n    // Placement is not required\n    markNeedsLayout();\n  }\n\n  /// The string representation of [areas].\n  String? get areasSpec => _areasSpec;\n  String? _areasSpec;\n  set areasSpec(String? value) {\n    if (_areasSpec == value) return;\n    _areasSpec = value;\n    areas = value != null ? parseNamedAreasSpec(value) : null;\n  }\n\n  /// Named areas that can be used for placement.\n  NamedGridAreas? get areas => _areas;\n  NamedGridAreas? _areas;\n  set areas(NamedGridAreas? value) {\n    if (_areas == value) return;\n    _areas = value;\n    markNeedsPlacement();\n    markNeedsLayout();\n  }\n\n  /// Defines the sizing functions of the grid's columns.\n  List<TrackSize> get columnSizes => _columnSizes;\n  List<TrackSize> _columnSizes;\n  set columnSizes(List<TrackSize> value) {\n    if (trackSizeListsEqual(_columnSizes, value)) return;\n\n    // No placement required if the number of columns is the same\n    if (value.length != _columnSizes.length) markNeedsPlacement();\n\n    markNeedsLayout();\n    _columnSizes = value;\n  }\n\n  /// Defines the sizing functions of the grid's rows.\n  List<TrackSize> get rowSizes => _rowSizes;\n  List<TrackSize> _rowSizes;\n  set rowSizes(List<TrackSize> value) {\n    if (trackSizeListsEqual(_rowSizes, value)) return;\n\n    // No placement required if the number of rows is the same\n    if (value.length != _rowSizes.length) markNeedsPlacement();\n\n    markNeedsLayout();\n\n    _rowSizes = value;\n  }\n\n  /// The space between column tracks\n  double get columnGap => _columnGap;\n  double _columnGap;\n  set columnGap(double value) {\n    if (_columnGap == value) return;\n    _columnGap = value;\n    markNeedsLayout();\n  }\n\n  /// The space between row tracks\n  double get rowGap => _rowGap;\n  double _rowGap;\n  set rowGap(double value) {\n    if (_rowGap == value) return;\n    _rowGap = value;\n    markNeedsLayout();\n  }\n\n  /// The text direction with which to resolve column ordering.\n  TextDirection get textDirection => _textDirection;\n  TextDirection _textDirection;\n  set textDirection(TextDirection value) {\n    if (_textDirection == value) return;\n    _textDirection = value;\n    markNeedsLayout();\n  }\n\n  @override\n  void setupParentData(RenderBox child) {\n    if (child.parentData is! GridParentData) {\n      child.parentData = GridParentData();\n    }\n  }\n\n  @override\n  double computeMinIntrinsicWidth(double height) =>\n      _computeIntrinsicSize(BoxConstraints.tightFor(height: height))\n          .minWidthOfTracks;\n\n  @override\n  double computeMaxIntrinsicWidth(double height) =>\n      _computeIntrinsicSize(BoxConstraints(maxHeight: height)).maxTracksWidth;\n\n  @override\n  double computeMinIntrinsicHeight(double width) =>\n      _computeIntrinsicSize(BoxConstraints.tightFor(width: width))\n          .minHeightOfTracks;\n\n  @override\n  double computeMaxIntrinsicHeight(double width) =>\n      _computeIntrinsicSize(BoxConstraints(maxWidth: width)).maxTracksHeight;\n\n  // TODO(https://github.com/shyndman/flutter_layout_grid/issues/1):\n  // This implementation is not likely to be correct. Revisit once Flutter's\n  // sizing rules are better understood.\n  GridSizingInfo _computeIntrinsicSize(BoxConstraints constraints) =>\n      computeGridSize(constraints);\n\n  @override\n  double? computeDistanceToActualBaseline(TextBaseline baseline) {\n    return defaultComputeDistanceToHighestActualBaseline(baseline);\n  }\n\n  List<RenderBox> getChildrenInTrack(TrackType trackType, int trackIndex) {\n    return _placementGrid\n        .getCellsInTrack(trackIndex, trackType)\n        .expand((cell) => cell.occupants)\n        .removeDuplicates()\n        .toList(growable: false);\n  }\n\n  @override\n  void performLayout() {\n    if (debugPrintGridLayout) {\n      debugPrint('Starting grid layout for constraints $constraints, '\n          'child constraints ${constraints.constraintsForGridFit(gridFit)}');\n    }\n\n    // Size the grid\n    final gridSizing = lastGridSizing = computeGridSize(constraints);\n    this.size = gridSizing.gridSize!;\n\n    if (debugPrintGridLayout) {\n      debugPrint('Determined track sizes:');\n\n      for (var c = 0; c < gridSizing.columnTracks.length; c++) {\n        final columnWidth = gridSizing\n            .sizeForArea(GridArea(\n              columnStart: c,\n              columnEnd: c + 1,\n              rowStart: 0,\n              rowEnd: 1,\n            ))\n            .width;\n        debugPrint('  column $c: $columnWidth');\n      }\n\n      for (var r = 0; r < gridSizing.rowTracks.length; r++) {\n        final rowHeight = gridSizing\n            .sizeForArea(GridArea(\n              columnStart: 0,\n              columnEnd: 1,\n              rowStart: r,\n              rowEnd: r + 1,\n            ))\n            .height;\n        debugPrint('  row $r: $rowHeight');\n      }\n\n      debugPrint('Finished track sizing');\n    }\n\n    bool shouldComputeChildRect = false;\n    assert(() {\n      _debugChildRect = Rect.zero;\n      shouldComputeChildRect = true;\n      return true;\n    }());\n\n    // Position and lay out the grid items\n    var child = firstChild;\n    while (child != null) {\n      final parentData = child.parentData as GridParentData;\n      if (parentData.isPlaced) {\n        final area = _placementGrid.itemAreas[child]!;\n        final areaRect =\n            gridSizing.offsetForArea(area) & gridSizing.sizeForArea(area);\n\n        parentData.offset = areaRect.topLeft;\n\n        child.layout(\n          BoxConstraints.loose(areaRect.size),\n          // Note that we do not use the parentUsesSize argument, as we already\n          // ask for intrinsics sizes from every child that we care about, and\n          // that has the same effect of registering the grid for relayout\n          // whenever those children change.\n          //\n          // Unless, that is, we're in a debug mode. Then we do so that we can\n          // compute overflow.\n          parentUsesSize: shouldComputeChildRect,\n        );\n\n        if (shouldComputeChildRect) {\n          _debugChildRect =\n              _debugChildRect.expandToInclude(areaRect.topLeft & child.size);\n        }\n      } else if (debugPrintUnplacedChildren) {\n        debugPrint('Area \"${parentData.areaName}\" not found. \\n'\n            '$child will not be rendered. ($parentData)');\n      }\n\n      child = parentData.nextSibling;\n    }\n  }\n\n  @override\n  @visibleForTesting\n  Size computeDryLayout(BoxConstraints constraints) {\n    return computeGridSize(constraints).gridSize!;\n  }\n\n  @visibleForTesting\n  GridSizingInfo computeGridSize(\n    BoxConstraints gridConstraints, {\n    BoxConstraints? childConstraints,\n  }) {\n    childConstraints ??= gridConstraints.constraintsForGridFit(gridFit);\n\n    // Distribute grid items into cells\n    performItemPlacement();\n\n    // Ready an object that contains our sizing information\n    final gridSizing = GridSizingInfo.fromTrackSizeFunctions(\n      columnSizeFunctions: _columnSizes,\n      rowSizeFunctions: _rowSizes,\n      textDirection: textDirection,\n      columnGap: columnGap,\n      rowGap: rowGap,\n    );\n\n    // Determine the size of the column tracks\n    _performTrackSizing(\n      TrackType.column,\n      gridSizing,\n      constraints: childConstraints,\n    );\n\n    // Determine the size of the row tracks\n    _performTrackSizing(\n      TrackType.row,\n      gridSizing,\n      constraints: childConstraints,\n    );\n\n    // Stretch intrinsics\n    _stretchIntrinsicTracks(TrackType.column, gridSizing,\n        constraints: childConstraints);\n    _stretchIntrinsicTracks(TrackType.row, gridSizing,\n        constraints: childConstraints);\n\n    // Constrain the size of the grid to whatever the parent provides. This\n    // may overflow children.\n    gridSizing.gridSize =\n        gridConstraints.constrain(gridSizing.internalGridSize);\n\n    return gridSizing;\n  }\n\n  /// Determines where each grid item is positioned in the grid, using the\n  /// auto-placement algorithm if necessary.\n  void performItemPlacement() {\n    if (needsPlacement) {\n      needsPlacement = false;\n      _placementGrid = computeItemPlacement(this);\n    }\n  }\n\n  List<GridTrack> _performTrackSizing(\n    TrackType typeBeingSized,\n    GridSizingInfo gridSizing, {\n    BoxConstraints? constraints,\n  }) {\n    final tracks = _performTrackSizingInternal(typeBeingSized, gridSizing,\n        constraints: constraints);\n    gridSizing.markTrackTypeSized(typeBeingSized);\n    return tracks;\n  }\n\n  /// A rough approximation of\n  /// https://drafts.csswg.org/css-grid/#algo-track-sizing. There are a bunch of\n  /// steps left out because our model is simpler.\n  List<GridTrack> _performTrackSizingInternal(\n    TrackType typeBeingSized,\n    GridSizingInfo gridSizing, {\n    BoxConstraints? constraints,\n  }) {\n    final sizingAxis = measurementAxisForTrackType(typeBeingSized);\n    final intrinsicTracks = <GridTrack>[];\n    final flexibleTracks = <GridTrack>[];\n    final tracks = gridSizing.tracksForType(typeBeingSized);\n    final bounds = constraintBoundsForType(constraints, typeBeingSized);\n    final totalGapAlongAxis =\n        gridSizing.unitGapAlongAxis(sizingAxis) * (tracks.length - 1);\n    final initialFreeSpace =\n        bounds.max.isFinite ? bounds.max - totalGapAlongAxis : 0.0;\n    final isAxisUpperBound = bounds.max.isFinite;\n\n    if (debugPrintGridLayout) {\n      debugPrint('${typeBeingSized.name.toUpperCase()} tracks with a '\n          'maximum free space of $initialFreeSpace, '\n          'isAxisUpperBound=$isAxisUpperBound');\n    }\n\n    // 1. Initialize track sizes\n\n    for (int i = 0; i < tracks.length; i++) {\n      final track = tracks[i];\n\n      if (track.sizeFunction\n          .isFixedForConstraints(typeBeingSized, constraints!)) {\n        // Fixed, definite\n        final fixedSize =\n            track.sizeFunction.minIntrinsicSize(typeBeingSized, []);\n        track.baseSize = track.growthLimit = fixedSize;\n      } else if (track.sizeFunction.isFlexible) {\n        // Flexible sizing\n        track.baseSize = track.growthLimit = 0;\n        flexibleTracks.add(track);\n      } else {\n        // Intrinsic sizing\n        track.baseSize = 0;\n        track.growthLimit = double.infinity; // Set in next step\n        intrinsicTracks.add(track);\n      }\n\n      track.growthLimit = math.max(track.growthLimit, track.baseSize);\n    }\n\n    // 2. Resolve intrinsic track sizes\n\n    _resolveIntrinsicTrackSizes(typeBeingSized, sizingAxis, tracks,\n        intrinsicTracks, gridSizing, constraints);\n\n    // 3. Grow all tracks from their baseSize up to their growthLimit value\n    //    until freeSpace is exhausted.\n\n    var axisMinSize = totalGapAlongAxis, axisMaxSize = totalGapAlongAxis;\n    for (final track in tracks) {\n      assert(!track.isInfinite);\n      axisMinSize += track.baseSize;\n      axisMaxSize += track.growthLimit;\n    }\n\n    double freeSpace = initialFreeSpace - axisMinSize;\n    gridSizing.setMinMaxTrackSizesForAxis(axisMinSize, axisMaxSize, sizingAxis);\n\n    if (debugPrintGridLayout) {\n      debugPrint('min-max: ${MinMax(axisMinSize, axisMaxSize)}');\n      debugPrint('free space: $freeSpace');\n    }\n\n    // We're already overflowing\n    if (isAxisUpperBound && freeSpace < 0) {\n      if (debugPrintGridLayout) debugPrint('Overflowing by $freeSpace');\n      return tracks;\n    }\n\n    if (isAxisUpperBound && axisMaxSize > axisMinSize) {\n      if (debugPrintGridLayout) {\n        debugPrint('Can grow within free space');\n      }\n      freeSpace =\n          _distributeFreeSpace(freeSpace, tracks, [], _IntrinsicDimension.min);\n      if (debugPrintGridLayout) {\n        debugPrint('  Finished distribution. Free space is now $freeSpace');\n      }\n    } else {\n      for (final track in tracks) {\n        freeSpace -= track.growthLimit - track.baseSize;\n        track.baseSize = track.growthLimit;\n      }\n    }\n\n    // 4. Size flexible tracks to fill remaining space, if any\n\n    if (flexibleTracks.isEmpty || freeSpace <= 0) {\n      return tracks;\n    }\n\n    // TODO(shyndman): This is not to spec. Flexible rows should have a minimum\n    // size of their content's minimum contribution. We may add this as soon\n    // as we have the notion of distinct minimum and maximum track size\n    // functions, but requires some consideration because of the expense to\n    // compute.\n    // https://drafts.csswg.org/css-grid/#valdef-grid-template-columns-flex\n    final flexFraction =\n        _findFlexFactorUnitSize(tracks, flexibleTracks, initialFreeSpace);\n\n    for (final track in flexibleTracks) {\n      track.baseSize = flexFraction * track.sizeFunction.flex!;\n\n      freeSpace -= track.baseSize;\n      axisMinSize += track.baseSize;\n      axisMaxSize += track.baseSize;\n    }\n\n    gridSizing.setMinMaxTrackSizesForAxis(axisMinSize, axisMaxSize, sizingAxis);\n\n    return tracks;\n  }\n\n  void _resolveIntrinsicTrackSizes(\n    TrackType type,\n    Axis sizingAxis,\n    List<GridTrack> tracks,\n    List<GridTrack> intrinsicTracks,\n    GridSizingInfo gridSizing,\n    BoxConstraints? constraints,\n  ) {\n    if (intrinsicTracks.isNotEmpty && debugPrintGridLayout) {\n      debugPrint('Resolving intrinsic ${type.name} '\n          '${type == TrackType.column ? 'widths' : 'heights'} '\n          '[${debugTrackIndicesString(intrinsicTracks)}]');\n    }\n\n    final itemsInIntrinsicTracks = intrinsicTracks\n        .expand((t) => getChildrenInTrack(type, t.index))\n        .removeDuplicates();\n\n    final itemsBySpan = groupBy(itemsInIntrinsicTracks, (RenderObject item) {\n      return _placementGrid.itemAreas[item as RenderBox]!\n          .spanForAxis(sizingAxis);\n    });\n    final sortedSpans = itemsBySpan.keys.toList()..sort();\n\n    // Iterate over the spans we find in our items list, in ascending order.\n    for (int span in sortedSpans) {\n      final spanItems = itemsBySpan[span]!;\n      // TODO(shyndman): This is unnecessary work. We should be able to\n      // construct what we need above.\n      final spanItemsByTrack = groupBy<RenderBox, int>(\n        spanItems,\n        (item) => _placementGrid.itemAreas[item]!.startForAxis(sizingAxis),\n      );\n\n      // Size all spans containing at least one intrinsic track and zero\n      // flexible tracks.\n      for (final i in spanItemsByTrack.keys) {\n        final spannedTracks = tracks.getRange(i, i + span);\n        final spanItemsInTrack = spanItemsByTrack[i];\n        final intrinsicTrack =\n            spannedTracks.firstWhereOrNull((t) => t.sizeFunction.isIntrinsic);\n\n        // We don't size flexible tracks until later\n        if (intrinsicTrack == null ||\n            spannedTracks.any((t) => t.sizeFunction.isFlexible)) {\n          continue;\n        }\n\n        final crossAxis = flipAxis(sizingAxis);\n        final crossAxisSizeForItem = gridSizing.isAxisSized(crossAxis)\n            ? (RenderBox item) {\n                return gridSizing.sizeForAreaOnAxis(\n                    _placementGrid.itemAreas[item]!, crossAxis);\n              }\n            : (RenderBox _) => double.infinity;\n\n        // Calculate the min-size of the spanned items, and distribute the\n        // additional space to the spanned tracks' base sizes.\n        final minSpanSize = intrinsicTrack.sizeFunction.minIntrinsicSize(\n            type, spanItemsInTrack!,\n            crossAxisSizeForItem: crossAxisSizeForItem);\n        if (debugPrintGridLayout) {\n          debugPrint('  min size of '\n              '${debugTrackIndicesString(spannedTracks, trackPrefix: true)} '\n              '= $minSpanSize');\n        }\n\n        _distributeCalculatedSpaceToSpannedTracks(\n            minSpanSize, type, spannedTracks, _IntrinsicDimension.min);\n\n        // Calculate the max-size of the spanned items, and distribute the\n        // additional space to the spanned tracks' growth limits.\n        final maxSpanSize = intrinsicTrack.sizeFunction.maxIntrinsicSize(\n            type, spanItemsInTrack,\n            crossAxisSizeForItem: crossAxisSizeForItem);\n        _distributeCalculatedSpaceToSpannedTracks(\n            maxSpanSize, type, spannedTracks, _IntrinsicDimension.max);\n        if (debugPrintGridLayout) {\n          debugPrint('  max size of '\n              '${debugTrackIndicesString(spannedTracks, trackPrefix: true)} '\n              '= $maxSpanSize');\n        }\n      }\n    }\n\n    // The time for infinite growth limits is over!\n    for (final track in intrinsicTracks) {\n      if (track.isInfinite) track.growthLimit = track.baseSize;\n\n      if (debugPrintGridLayout) {\n        debugPrint('  update track ${track.index} = '\n            '${track.toPrettySizeString()}');\n      }\n    }\n  }\n\n  /// Distributes free space among [spannedTracks]\n  void _distributeCalculatedSpaceToSpannedTracks(\n    double calculatedSpace,\n    TrackType type,\n    Iterable<GridTrack> spannedTracks,\n    _IntrinsicDimension dimension,\n  ) {\n    // Subtract calculated dimensions of the tracks\n    double freeSpace = calculatedSpace;\n    for (final track in spannedTracks) {\n      freeSpace -= dimension == _IntrinsicDimension.min\n          ? track.baseSize\n          : track.isInfinite\n              ? track.baseSize\n              : track.growthLimit;\n    }\n\n    // If there's no free space to distribute, freeze the tracks and we're done\n    if (freeSpace <= 0) {\n      for (final track in spannedTracks) {\n        if (track.isInfinite) {\n          track.growthLimit = track.baseSize;\n        }\n      }\n      return;\n    }\n\n    // Filter to the intrinsicly sized tracks in the span\n    final intrinsicTracks = spannedTracks\n        .where((track) => track.sizeFunction.isIntrinsic)\n        .toList(growable: false);\n\n    // Now distribute the free space between them\n    if (intrinsicTracks.isNotEmpty) {\n      _distributeFreeSpace(\n          freeSpace, intrinsicTracks, intrinsicTracks, dimension);\n    }\n  }\n\n  double _distributeFreeSpace(\n    double freeSpace,\n    List<GridTrack> tracks,\n    List<GridTrack> growableAboveMaxTracks,\n    _IntrinsicDimension dimension,\n  ) {\n    assert(freeSpace >= 0);\n\n    if (debugPrintGridLayout) {\n      debugPrint('  distributing $freeSpace across '\n          '${debugTrackIndicesString(tracks)} on '\n          '${dimension.name}');\n    }\n\n    // Grab a mutable copy of our tracks\n    tracks = tracks.toList();\n\n    void distribute(\n      List<GridTrack> tracks,\n      double Function(GridTrack, double) getShareForTrack,\n    ) {\n      final trackCount = tracks.length;\n      for (int i = 0; i < trackCount; i++) {\n        final track = tracks[i];\n        final availableShare = freeSpace / (trackCount - i);\n        final shareForTrack = getShareForTrack(track, availableShare);\n        assert(shareForTrack >= 0.0, 'Never shrink a track');\n\n        track.sizeDuringDistribution += shareForTrack;\n        freeSpace -= shareForTrack;\n      }\n    }\n\n    // Setup a size that will be used for distribution calculations, and\n    // assigned back to the sizes when we complete.\n    for (final track in tracks) {\n      track.sizeDuringDistribution = dimension == _IntrinsicDimension.min\n          ? track.baseSize\n          : track.isInfinite\n              ? track.baseSize\n              : track.growthLimit;\n    }\n\n    tracks.sort(_sortByGrowthPotential);\n\n    // Distribute the free space between tracks\n    distribute(tracks, (track, availableShare) {\n      return track.isInfinite\n          ? availableShare\n          // Grow up until limit\n          : math.min(\n              availableShare,\n              track.growthLimit - track.sizeDuringDistribution,\n            );\n    });\n\n    // If we still have space leftover, let's unfreeze and grow some more\n    // (ignoring limit)\n    if (freeSpace > 0 && growableAboveMaxTracks.isNotEmpty) {\n      distribute(\n          growableAboveMaxTracks, (track, availableShare) => availableShare);\n    }\n\n    // Assign back the calculated sizes\n    for (final track in tracks) {\n      if (dimension == _IntrinsicDimension.min) {\n        track.baseSize = math.max(track.baseSize, track.sizeDuringDistribution);\n      } else {\n        track.growthLimit = track.isInfinite\n            ? track.sizeDuringDistribution\n            : math.max(track.growthLimit, track.sizeDuringDistribution);\n      }\n    }\n\n    return freeSpace;\n  }\n\n  double _findFlexFactorUnitSize(\n    List<GridTrack> tracks,\n    List<GridTrack> flexibleTracks,\n    double freeSpace,\n  ) {\n    double flexSum = 0;\n    for (final track in tracks) {\n      if (!track.sizeFunction.isFlexible) {\n        freeSpace -= track.baseSize;\n      } else {\n        flexSum += track.sizeFunction.flex!;\n      }\n    }\n\n    assert(flexSum > 0);\n    // TODO(shyndman): This is not to spec. We need to consider track base sizes\n    // (when measuring the content minimum) that are bigger than what the flex\n    // would provide.\n    return freeSpace / flexSum;\n  }\n\n  /// TODO(shyndman): Feels like this could be rolled into\n  /// [_distributeFreeSpace].\n  void _stretchIntrinsicTracks(\n    TrackType type,\n    GridSizingInfo gridSizing, {\n    required BoxConstraints constraints,\n  }) {\n    final minimumGridSize = constraintBoundsForType(constraints, type).min;\n    final freeSpace = minimumGridSize -\n        gridSizing.totalBaseSizeOfTracksForType(type) -\n        gridSizing.totalGapForType(type);\n\n    if (freeSpace <= 0) return;\n\n    final tracks = gridSizing.tracksForType(type);\n    final intrinsicTracks = tracks.where((t) => t.sizeFunction.isIntrinsic);\n    if (intrinsicTracks.isEmpty) return;\n\n    final shareForTrack = freeSpace / intrinsicTracks.length;\n    for (final track in intrinsicTracks) {\n      track.baseSize += shareForTrack;\n    }\n    gridSizing.invalidateTrackStartsForType(type);\n  }\n\n  @override\n  void adoptChild(RenderObject child) {\n    super.adoptChild(child);\n    markNeedsPlacementIfRequired(child);\n  }\n\n  @override\n  void dropChild(RenderObject child) {\n    super.dropChild(child);\n    markNeedsPlacementIfRequired(child);\n  }\n\n  /// Determines whether [child] may represent a change in grid item\n  /// positioning, and if so, ensures that we will regenerate the placement grid\n  /// on next layout.\n  void markNeedsPlacementIfRequired(RenderObject child) {\n    if (needsPlacement) return;\n    final parentData = child.parentData as GridParentData?;\n    if (parentData != null && !parentData.isDefinitelyPlaced) {\n      markNeedsPlacement();\n    }\n  }\n\n  void markNeedsPlacement() => needsPlacement = true;\n\n  @override\n  bool hitTestChildren(BoxHitTestResult result, {required Offset position}) {\n    return defaultHitTestChildren(result, position: position);\n  }\n\n  @override\n  void visitChildrenForSemantics(visitor) {\n    var child = firstChild;\n    while (child != null) {\n      final GridParentData childParentData = child.parentData as GridParentData;\n      if (childParentData.isPlaced) {\n        visitor(child);\n      }\n      child = childParentData.nextSibling;\n    }\n  }\n\n  @override\n  void paint(PaintingContext context, Offset offset) {\n    visitChildrenForSemantics((child) {\n      final childParentData = child.parentData as GridParentData;\n      context.paintChild(child, childParentData.offset + offset);\n    });\n\n    assert(() {\n      final gridRect = Offset.zero & size;\n      // We massage the child rect a bit to make sure that we aren't marking\n      // overflows when they're very minor.\n      //\n      // The reason this isn't a boolean response is because tiny overflows are\n      // common, which is fine, but when one of the edges is overflowing by\n      // a meaningful amount, both edges will frequently show the indicator.\n      final childRect =\n          _childRectForOverflowComparison(gridRect, _debugChildRect);\n      paintOverflowIndicator(context, offset, gridRect, childRect);\n\n      return true;\n    }());\n  }\n\n  @override\n  void debugPaintSize(PaintingContext context, Offset offset) {\n    assert(() {\n      super.debugPaintSize(context, offset);\n\n      final gapPaint = Paint()..color = const Color(0x90909090);\n      final cellEdgePaint = Paint()\n        ..style = PaintingStyle.stroke\n        ..strokeWidth = 1.0\n        ..color = const Color(0x90909090);\n\n      var gapPath = Path()..addRect(offset & size);\n      for (int c = 0; c < _columnSizes.length; c++) {\n        for (int r = 0; r < _rowSizes.length; r++) {\n          final cellRect = lastGridSizing.rectForArea(GridArea(\n            columnStart: c,\n            columnEnd: c + 1,\n            rowStart: r,\n            rowEnd: r + 1,\n          ));\n\n          gapPath = Path.combine(\n            PathOperation.difference,\n            gapPath,\n            Path()..addRect(cellRect.deflate(0.1)),\n          );\n        }\n      }\n      final drawGaps = _columnGap != 0 || _rowGap != 0;\n      context.canvas.drawPath(gapPath, drawGaps ? gapPaint : cellEdgePaint);\n\n      return true;\n    }());\n  }\n}\n\nMinMax<double> constraintBoundsForType(\n    BoxConstraints? constraints, TrackType type) {\n  return type == TrackType.column\n      ? MinMax(constraints!.minWidth, constraints.maxWidth)\n      : MinMax(constraints!.minHeight, constraints.maxHeight);\n}\n\nenum _IntrinsicDimension { min, max }\n\nclass GridTrack {\n  GridTrack(this.index, this.sizeFunction);\n\n  final int index;\n  final TrackSize sizeFunction;\n\n  double _baseSize = 0;\n  double _growthLimit = 0;\n\n  double sizeDuringDistribution = 0;\n\n  double get baseSize => _baseSize;\n  set baseSize(double value) {\n    _baseSize = value;\n    _increaseGrowthLimitIfNecessary();\n  }\n\n  double get growthLimit => _growthLimit;\n  set growthLimit(double value) {\n    _growthLimit = value;\n    _increaseGrowthLimitIfNecessary();\n  }\n\n  bool get isInfinite => _growthLimit == double.infinity;\n\n  void _increaseGrowthLimitIfNecessary() {\n    if (_growthLimit != double.infinity && _growthLimit < _baseSize) {\n      _growthLimit = _baseSize;\n    }\n  }\n\n  @override\n  String toString() {\n    return 'GridTrack(baseSize=$baseSize, growthLimit=$growthLimit, sizeFunction=$sizeFunction)';\n  }\n\n  String toPrettySizeString() {\n    return _baseSize == _growthLimit\n        ? _baseSize.toStringAsFixed(1)\n        : '${_baseSize.toStringAsFixed(1)}->${_growthLimit.toStringAsFixed(1)}';\n  }\n}\n\nUnmodifiableListView<GridTrack> _sizesToTracks(Iterable<TrackSize> sizes) =>\n    UnmodifiableListView(\n      enumerate(sizes)\n          .map((s) => GridTrack(s.index, s.value))\n          .toList(growable: false),\n    );\n\nclass GridSizingInfo {\n  GridSizingInfo({\n    required List<GridTrack> columnTracks,\n    required List<GridTrack> rowTracks,\n    required this.columnGap,\n    required this.rowGap,\n    required this.textDirection,\n  })  : columnTracks = UnmodifiableListView(columnTracks),\n        rowTracks = UnmodifiableListView(rowTracks);\n\n  GridSizingInfo.fromTrackSizeFunctions({\n    required List<TrackSize> columnSizeFunctions,\n    required List<TrackSize> rowSizeFunctions,\n    required TextDirection textDirection,\n    double columnGap = 0,\n    double rowGap = 0,\n  }) : this(\n          columnTracks: _sizesToTracks(columnSizeFunctions),\n          rowTracks: _sizesToTracks(rowSizeFunctions),\n          textDirection: textDirection,\n          columnGap: columnGap,\n          rowGap: rowGap,\n        );\n\n  Size? gridSize;\n  final double columnGap;\n  final double rowGap;\n\n  final UnmodifiableListView<GridTrack> columnTracks;\n  final UnmodifiableListView<GridTrack> rowTracks;\n\n  final TextDirection textDirection;\n\n  List<double>? _ltrColumnStarts;\n  List<double>? get columnStartsWithoutGaps {\n    return _ltrColumnStarts ??= cumulativeSum(\n      columnTracks.map((t) => t.baseSize),\n      includeLast: false,\n    ).toList(growable: false);\n  }\n\n  List<double>? _rowStarts;\n  List<double>? get rowStartsWithoutGaps {\n    return _rowStarts ??= cumulativeSum(\n      rowTracks.map((t) => t.baseSize),\n      includeLast: false,\n    ).toList(growable: false);\n  }\n\n  double minWidthOfTracks = 0.0;\n  double minHeightOfTracks = 0.0;\n\n  double maxTracksWidth = 0.0;\n  double maxTracksHeight = 0.0;\n\n  bool hasColumnSizing = false;\n  bool hasRowSizing = false;\n\n  /// The size occupied by the grid's tracks and gaps, without considering the\n  /// constraints applied to the grid itself.\n  Size get internalGridSize {\n    final gridWidth = sum(columnTracks.map((t) => t.baseSize)) +\n        columnGap * (columnTracks.length - 1);\n    final gridHeight =\n        sum(rowTracks.map((t) => t.baseSize)) + rowGap * (rowTracks.length - 1);\n    return Size(gridWidth, gridHeight);\n  }\n\n  Offset offsetForArea(GridArea area) {\n    return Offset(\n        textDirection == TextDirection.ltr\n            ? columnStartsWithoutGaps![area.columnStart] +\n                columnGap * area.columnStart\n            : gridSize!.width -\n                columnStartsWithoutGaps![area.columnStart] -\n                sizeForAreaOnAxis(area, Axis.horizontal) -\n                columnGap * area.columnStart,\n        rowStartsWithoutGaps![area.rowStart] + rowGap * area.rowStart);\n  }\n\n  Size sizeForArea(GridArea area) {\n    return Size(\n      sizeForAreaOnAxis(area, Axis.horizontal),\n      sizeForAreaOnAxis(area, Axis.vertical),\n    );\n  }\n\n  Rect rectForArea(GridArea area) {\n    return offsetForArea(area) & sizeForArea(area);\n  }\n\n  void markTrackTypeSized(TrackType type) {\n    if (type == TrackType.column) {\n      hasColumnSizing = true;\n    } else {\n      hasRowSizing = true;\n    }\n  }\n\n  MinMax minMaxTrackSizesForAxis(Axis axis) {\n    return axis == Axis.horizontal\n        ? MinMax(minWidthOfTracks, maxTracksWidth)\n        : MinMax(minHeightOfTracks, maxTracksHeight);\n  }\n\n  List<double> baseSizesForType(TrackType type) =>\n      tracksForType(type).map((t) => t.baseSize).toList();\n\n  double totalBaseSizeOfTracksForType(TrackType type) =>\n      sum(baseSizesForType(type));\n\n  void setMinMaxTrackSizesForAxis(double min, double max, Axis axis) {\n    if (axis == Axis.horizontal) {\n      minWidthOfTracks = min;\n      maxTracksWidth = max;\n    } else {\n      minHeightOfTracks = min;\n      maxTracksHeight = max;\n    }\n  }\n\n  double unitGapAlongAxis(Axis axis) =>\n      axis == Axis.horizontal ? columnGap : rowGap;\n\n  double unitGapForType(TrackType type) =>\n      unitGapAlongAxis(measurementAxisForTrackType(type));\n\n  double totalGapForType(TrackType type) =>\n      (tracksForType(type).length - 1) * unitGapForType(type);\n\n  bool isAxisSized(Axis sizingAxis) =>\n      sizingAxis == Axis.horizontal ? hasColumnSizing : hasRowSizing;\n\n  List<GridTrack> tracksForType(TrackType type) =>\n      type == TrackType.column ? columnTracks : rowTracks;\n\n  List<GridTrack> tracksAlongAxis(Axis sizingAxis) =>\n      sizingAxis == Axis.horizontal ? columnTracks : rowTracks;\n\n  double sizeForAreaOnAxis(GridArea area, Axis axis) {\n    assert(isAxisSized(axis));\n\n    // TODO(shyndman): Support row/col gaps\n\n    final trackBaseSizes = tracksAlongAxis(axis)\n        .getRange(area.startForAxis(axis), area.endForAxis(axis))\n        .map((t) => t.baseSize);\n    final gapSize = (area.spanForAxis(axis) - 1) * unitGapAlongAxis(axis);\n    return math.max(0, sum(trackBaseSizes) + gapSize);\n  }\n\n  void invalidateTrackStartsForType(TrackType type) {\n    if (type == TrackType.column) {\n      _ltrColumnStarts = null;\n    } else {\n      _rowStarts = null;\n    }\n  }\n}\n\nint _sortByGrowthPotential(GridTrack a, GridTrack b) {\n  if (a.isInfinite != b.isInfinite) return a.isInfinite ? -1 : 1;\n  return (a.growthLimit - a.baseSize).compareTo(b.growthLimit - b.baseSize);\n}\n\nRect _childRectForOverflowComparison(Rect gridRect, Rect childRect) {\n  return Rect.fromLTRB(\n    gridRect.left - childRect.left < precisionErrorTolerance\n        ? gridRect.left\n        : childRect.left,\n    gridRect.top - childRect.top < precisionErrorTolerance\n        ? gridRect.top\n        : childRect.top,\n    childRect.right - gridRect.right < precisionErrorTolerance\n        ? gridRect.right\n        : childRect.right,\n    childRect.bottom - gridRect.bottom < precisionErrorTolerance\n        ? gridRect.bottom\n        : childRect.bottom,\n  );\n}\n\nclass MinMax<T extends num> {\n  const MinMax(this.min, this.max);\n  final T min;\n  final T max;\n\n  @override\n  String toString() {\n    return '${min.toStringAsFixed(1)}->${max.toStringAsFixed(1)}'\n        '${min == max ? ' (same)' : ''}';\n  }\n}\n"
  },
  {
    "path": "lib/src/rendering/placement.dart",
    "content": "import 'package:flutter/foundation.dart';\nimport 'package:flutter/rendering.dart';\nimport 'package:quiver/iterables.dart';\n\nimport '../foundation/placement.dart';\nimport '../widgets/layout_grid.dart';\nimport '../widgets/placement.dart';\nimport 'layout_grid.dart';\nimport 'track_size.dart';\n\n/// Implementation of the auto-placement algorithm, described here:\n/// https://drafts.csswg.org/css-grid/#auto-placement-algo\nPlacementGrid computeItemPlacement(RenderLayoutGrid grid) {\n  final autoPlacement = grid.autoPlacement;\n  final occupancy = PlacementGrid(grid: grid);\n\n  final growthAxis = autoPlacement.trackType == TrackType.row\n      ? Axis.vertical\n      : Axis.horizontal;\n  final fixedAxis = flipAxis(growthAxis);\n\n  final fullyPlacedChildren = <RenderBox>[];\n  final flowAxisPlacedChildren = <RenderBox>[];\n  final toPlaceChildren = <RenderBox>[];\n\n  // 0. Bucket children into lists based on their placement priority:\n  //\n  //    definitely on 2 axes > definitely on 1 axis > rest\n  //\n  RenderBox? child = grid.firstChild;\n  while (child != null) {\n    final childParentData = child.parentData as GridParentData;\n\n    if (childParentData.areaName != null) {\n      _resolveChildNamedArea(childParentData, grid);\n    }\n\n    if (childParentData.isDefinitelyPlaced) {\n      fullyPlacedChildren.add(child);\n    } else if (childParentData.isDefinitelyPlacedOnAxis(growthAxis)) {\n      flowAxisPlacedChildren.add(child);\n    } else if (childParentData.isPlaced) {\n      toPlaceChildren.add(child);\n    }\n\n    child = childParentData.nextSibling;\n  }\n\n  // 1. Occupy cells with definitely placed items (have both columns and rows\n  //    specified)\n  for (final child in fullyPlacedChildren) {\n    final childParentData = child.parentData as GridParentData;\n    occupancy.addItemToArea(child, childParentData.area);\n  }\n\n  // 2. Iterate over the children definitely placed on the flow axis, finding\n  //    them spots\n  for (final child in flowAxisPlacedChildren) {\n    final childParentData = child.parentData as GridParentData;\n    final cursor = occupancy.createCursor(autoPlacement)\n      ..fixToAxisIndex(childParentData.startForAxis(growthAxis), growthAxis);\n\n    final area = cursor.moveToNextEmptyArea(\n        childParentData.columnSpan, childParentData.rowSpan);\n    occupancy.addItemToArea(child, area);\n  }\n\n  // 3. Distribute the rest of the children, using a cursor appropriate for the\n  //    auto-flow mode.\n  final autoFlowCursor = occupancy.createCursor(autoPlacement);\n  for (final child in toPlaceChildren) {\n    final childParentData = child.parentData as GridParentData;\n    if (childParentData.isDefinitelyPlacedOnAxis(fixedAxis)) {\n      autoFlowCursor.fixToAxisIndex(\n          childParentData.startForAxis(fixedAxis), growthAxis);\n    } else {\n      autoFlowCursor.unfixFromTrack();\n    }\n\n    final area = autoFlowCursor.moveToNextEmptyArea(\n        childParentData.columnSpan, childParentData.rowSpan);\n    occupancy.addItemToArea(child, area);\n  }\n\n  return occupancy;\n}\n\n/// Resolves [childParentData]'s area to a concrete set of track starts and\n/// spans.\nvoid _resolveChildNamedArea(\n  GridParentData childParentData,\n  RenderLayoutGrid grid,\n) {\n  childParentData.area =\n      grid.areas != null ? grid.areas![childParentData.areaName] : null;\n}\n\n/// Used to determine unoccupied space by the auto-placement algorithm.\n///\n/// TODO(shyndman): This would be much more space efficient for sparse or large\n/// grids by using range sets or a segment tree, but that's an exercise for\n/// another day. Improving space complexity is also a must-have for implicit\n/// grid tracks.\n///\n/// Update: Looks like Chromium uses doubly linked lists to store this\n/// information.\nclass PlacementGrid {\n  PlacementGrid({\n    required this.grid,\n  })  : explicitColumnCount = grid.columnSizes.length,\n        explicitRowCount = grid.rowSizes.length {\n    _cells = List<GridCell>.generate(\n        explicitColumnCount * explicitRowCount, (i) => GridCell(this, i));\n  }\n\n  final RenderLayoutGrid grid;\n  final int explicitColumnCount;\n  final int explicitRowCount;\n\n  Map<RenderBox, GridArea> itemAreas = {};\n  late List<GridCell> _cells;\n\n  GridCell getCellAt(int column, int row) =>\n      _cells[row * explicitColumnCount + column];\n\n  Iterable<GridCell> getCellsInTrack(\n    int trackIndex,\n    TrackType trackType,\n  ) sync* {\n    final trackMainAxis = mainAxisForTrackType(trackType);\n    final firstCellIndex = trackMainAxis == Axis.vertical\n        ? trackIndex\n        : trackIndex * explicitColumnCount;\n\n    final cell = _cells.length > firstCellIndex ? _cells[firstCellIndex] : null;\n    if (cell != null) {\n      yield* [cell].followedBy(cell.nextCellsAlongAxis(trackMainAxis));\n    }\n  }\n\n  Iterable<GridCell> getCellsInArea(GridArea area) sync* {\n    for (int x = area.columnStart; x < area.columnEnd; x++) {\n      for (int y = area.rowStart; y < area.rowEnd; y++) {\n        yield getCellAt(x, y);\n      }\n    }\n  }\n\n  /// Returns `true` if the specified [area] is vacant.\n  bool checkIsVacant(GridArea area) =>\n      getCellsInArea(area).every((c) => c.isVacant);\n\n  /// Creates a cursor that for traversing the grid to find vacancy.\n  PlacementGridCursor createCursor(AutoPlacement autoPlacementMode) =>\n      PlacementGridCursor(this, autoPlacementMode: autoPlacementMode);\n\n  void addItemToArea(RenderBox item, GridArea area) {\n    if (area.columnEnd > explicitColumnCount) {\n      throw FlutterError.fromParts([\n        ErrorSummary('GridPlacement.columnEnd cannot exceed column count\\n'),\n        grid.toDiagnosticsNode(name: 'grid'),\n        item.toDiagnosticsNode(name: 'gridItem'),\n      ]);\n    }\n\n    if (area.rowEnd > explicitRowCount) {\n      throw FlutterError.fromParts([\n        ErrorSummary('GridPlacement.rowEnd cannot exceed row count\\n'),\n        grid.toDiagnosticsNode(name: 'grid'),\n        item.toDiagnosticsNode(name: 'gridItem'),\n      ]);\n    }\n\n    for (final cell in getCellsInArea(area)) {\n      cell.occupants.add(item);\n    }\n    itemAreas[item] = area;\n  }\n\n  @override\n  String toString() {\n    final cap = '┼${'-' * (explicitColumnCount * 2 - 1)}┼';\n    final rows = partition(\n            _cells.map((c) => c.isOccupied ? c.debugLabel ?? 'x' : ' '),\n            explicitColumnCount)\n        .map((row) => row.join(','));\n    return '$cap\\n|${rows.join('|\\n|')}|\\n$cap';\n  }\n}\n\n/// Navigates the grid in order to find empty spots.\nclass PlacementGridCursor {\n  PlacementGridCursor(\n    this.grid, {\n    this.autoPlacementMode,\n  });\n\n  final PlacementGrid grid;\n  final AutoPlacement? autoPlacementMode;\n\n  Axis get autoPlacementTraversalAxis =>\n      autoPlacementMode!.trackType == TrackType.row\n          ? Axis.horizontal\n          : Axis.vertical;\n\n  /// The column under the cursor\n  int? currentColumn = -1;\n\n  /// The row under the cursor\n  int? currentRow = -1;\n\n  /// The current position of the cursor on the specified axis.\n  int? currentIndexOnAxis(Axis? axis) =>\n      axis == Axis.horizontal ? currentColumn : currentRow;\n\n  /// Sets the current position of the cursor on the specified axis.\n  void setCurrentIndexOnAxis(int? index, Axis? axis) {\n    if (axis == Axis.vertical) {\n      currentRow = index;\n    } else {\n      currentColumn = index;\n    }\n  }\n\n  int getAxisLength(Axis axis) => axis == Axis.horizontal\n      ? grid.explicitColumnCount\n      : grid.explicitRowCount;\n\n  /// The index of the track that we're currently searching for space.\n  int? fixedTrackIndex;\n\n  /// horizontal for column, vertical for row\n  Axis? fixedAxis;\n\n  /// `true` if this cursor is fixed to traversing a single track\n  bool get isFixedToTrack => fixedAxis != null;\n\n  /// `true` if this cursor is fixed to an axis, but requires a\n  /// [moveToNextEmptyArea] to be positioned correctly\n  bool get requiresMoveToFixedAxisIndex =>\n      isFixedToTrack && currentIndexOnAxis(fixedAxis) != fixedTrackIndex;\n\n  void fixToAxisIndex(int? index, Axis axis) {\n    fixedTrackIndex = index;\n    fixedAxis = axis;\n  }\n\n  void unfixFromTrack() {\n    fixedTrackIndex = null;\n    fixedAxis = null;\n  }\n\n  GridArea moveToNextEmptyArea(int? columnSpan, int? rowSpan) {\n    Iterable<GridArea> Function(int?, int?) moveFn;\n    if (isFixedToTrack) {\n      moveFn = _moveFixedToNext;\n    } else {\n      // If we're packing dense, reset the cursor positioning\n      if (autoPlacementMode!.packing == AutoPlacementPacking.dense) {\n        currentColumn = -1;\n        currentRow = -1;\n      }\n      moveFn = _moveAutoToNext;\n    }\n\n    return moveFn(columnSpan, rowSpan).firstWhere(grid.checkIsVacant);\n  }\n\n  Iterable<GridArea> _moveFixedToNext(int? columnSpan, int? rowSpan) sync* {\n    final traversalAxis = flipAxis(fixedAxis!);\n    traversalAxisIndex() => currentIndexOnAxis(traversalAxis);\n\n    if (requiresMoveToFixedAxisIndex) {\n      if (currentColumn == -1 && currentRow == -1) {\n        setCurrentIndexOnAxis(0, traversalAxis);\n      } else {\n        final fixedAxisIndex = currentIndexOnAxis(fixedAxis)!;\n        if (fixedTrackIndex! < fixedAxisIndex) {\n          setCurrentIndexOnAxis(traversalAxisIndex()! + 1, traversalAxis);\n        }\n      }\n      setCurrentIndexOnAxis(fixedTrackIndex, fixedAxis);\n      yield _currentAreaForSpans(columnSpan!, rowSpan!);\n    }\n\n    while (true) {\n      setCurrentIndexOnAxis(traversalAxisIndex()! + 1, traversalAxis);\n      yield _currentAreaForSpans(columnSpan!, rowSpan!);\n    }\n  }\n\n  Iterable<GridArea> _moveAutoToNext(int? columnSpan, int? rowSpan) sync* {\n    // The axis we will attempt to fill before moving to the next index on the\n    // growth axis.\n    final fixedAxis = autoPlacementTraversalAxis;\n    fixedAxisIndex() => currentIndexOnAxis(fixedAxis);\n\n    // The direction of growth of the grid.\n    final growthAxis = flipAxis(autoPlacementTraversalAxis);\n    growthAxisIndex() => currentIndexOnAxis(growthAxis);\n\n    // Auto-placement flow\n    while (true) {\n      if (currentColumn == -1 && currentRow == -1) {\n        currentColumn = currentRow = 0;\n      } else if (fixedAxisIndex()! + 1 == getAxisLength(fixedAxis)) {\n        setCurrentIndexOnAxis(0, fixedAxis);\n        setCurrentIndexOnAxis(growthAxisIndex()! + 1, growthAxis);\n      } else {\n        setCurrentIndexOnAxis(fixedAxisIndex()! + 1, fixedAxis);\n      }\n\n      yield _currentAreaForSpans(columnSpan!, rowSpan!);\n    }\n  }\n\n  GridArea _currentAreaForSpans(int columnSpan, int rowSpan) {\n    return GridArea.withSpans(\n      columnStart: currentColumn!,\n      columnSpan: columnSpan,\n      rowStart: currentRow!,\n      rowSpan: rowSpan,\n    );\n  }\n}\n\n@immutable\nclass GridCell {\n  GridCell(this.grid, this.index);\n\n  final PlacementGrid grid;\n  final int index;\n  final occupants = <RenderBox>{};\n\n  int get column => index % grid.explicitColumnCount;\n  int get row => index ~/ grid.explicitColumnCount;\n\n  bool get isOccupied => occupants.isNotEmpty;\n  bool get isVacant => !isOccupied;\n\n  String? get debugLabel => occupants.isNotEmpty\n      ? (occupants.first.parentData as GridParentData).debugLabel\n      : null;\n\n  Iterable<GridCell> nextCellsAlongAxis(Axis axis) sync* {\n    final next = axis == Axis.horizontal ? nextInRow : nextInColumn;\n    if (next != null) {\n      yield next;\n      yield* next.nextCellsAlongAxis(axis);\n    }\n  }\n\n  /// The cell next to this one in the row, or `null` if none.\n  GridCell? get nextInRow {\n    final column = (index + 1) % grid.explicitColumnCount;\n    return column == 0 ? null : grid._cells[index + 1];\n  }\n\n  /// The cell below this one in the column, or `null` if none.\n  GridCell? get nextInColumn {\n    final i = index + grid.explicitColumnCount;\n    return i >= grid._cells.length ? null : grid._cells[i];\n  }\n\n  @override\n  String toString() {\n    return 'GridCell($column, $row, isOccupied=$isOccupied)';\n  }\n}\n"
  },
  {
    "path": "lib/src/rendering/track_size.dart",
    "content": "import 'package:flutter/foundation.dart';\nimport 'package:flutter/rendering.dart';\nimport 'package:quiver/iterables.dart';\n\n/// Passed to [TrackSize] functions to indicate the type of track whose\n/// cross-axis is being measured.\nenum TrackType {\n  column,\n  row,\n}\n\n/// Returns the direction of cell layout for the provided [type].\nAxis mainAxisForTrackType(TrackType type) =>\n    type == TrackType.column ? Axis.vertical : Axis.horizontal;\n\n/// Returns the axis measured by a [TrackSize] associated with a particular\n/// [TrackType].\nAxis measurementAxisForTrackType(TrackType type) {\n  return type == TrackType.column ? Axis.horizontal : Axis.vertical;\n}\n\n/// Base class to describe the width (for columns) or height (for rows) of a\n/// track in a [RenderLayoutGrid].\n///\n/// To size a track to a specific number of pixels, use a [FixedTrackSize]. This\n/// is the cheapest way to size a track.\n///\n/// Another algorithm that is relatively cheap include [FlexibleTrackSize],\n/// which distributes the space equally among the flexible tracks.\n@immutable\nabstract class TrackSize with Diagnosticable {\n  /// Abstract const constructor. This constructor enables subclasses to provide\n  /// const constructors so that they can be used in const expressions.\n  const TrackSize({this.debugLabel});\n\n  /// A label that is included in debug output\n  final String? debugLabel;\n\n  /// Returns whether this size can resolve to a fixed value provided the\n  /// grid's box constraints.\n  bool isFixedForConstraints(TrackType type, BoxConstraints gridConstraints) {\n    return false;\n  }\n\n  /// Returns whether this sizing function requires measurement of a track's\n  /// items to resolve its size.\n  bool get isIntrinsic {\n    return false;\n  }\n\n  /// Returns whether this sizing function consumes space left over from the\n  /// initial sizing of the grid.\n  bool get isFlexible {\n    return false;\n  }\n\n  /// The smallest width (for columns) or height (for rows) that a track can\n  /// have.\n  ///\n  /// The [type] argument indicates whether this track represents a row or\n  /// a column.\n  ///\n  /// The [items] argument is an iterable that provides all the items in the\n  /// grid for this track. Walking the items is by definition O(N), so\n  /// algorithms that do that should be considered expensive.\n  ///\n  /// The [measurementAxisMaxSize] argument is the `maxWidth` or `maxHeight` of\n  /// the incoming constraints for grid, and might be infinite.\n  ///\n  /// The [crossAxisSizeForItem] will be provided to assist in calculations if\n  /// the cross axis sizing is known.\n  double minIntrinsicSize(\n    TrackType type,\n    Iterable<RenderBox> items, {\n    double Function(RenderBox)? crossAxisSizeForItem,\n  });\n\n  /// The ideal cross axis size of this track. This must be equal to or greater\n  /// than the [minIntrinsicSize] for the same [type]. The track might be bigger\n  /// than this size, e.g. if the track is flexible or if the grid's size ends\n  /// up being forced to be bigger than the sum of all the maxIntrinsicSize\n  /// values.\n  ///\n  /// The [type] argument indicates whether this track represents a row or a\n  /// column. If vertical, this function returns a width. If horizontal, a\n  /// height.\n  ///\n  /// The [items] argument is an iterable that provides all the items in the\n  /// grid for this track. Walking the items is by definition O(N), so\n  /// algorithms that do that should be considered expensive.\n  ///\n  /// The [measurementAxisMaxSize] argument is the `maxWidth` (for column\n  /// tracks) or `maxHeight` (for row tracks) of the incoming constraints for\n  /// the grid, and might be infinite.\n  ///\n  /// The [crossAxisSizeForItem] will be provided to assist in calculations if\n  /// the cross axis sizing is known.\n  double maxIntrinsicSize(\n    TrackType type,\n    Iterable<RenderBox> items, {\n    required double Function(RenderBox) crossAxisSizeForItem,\n  });\n\n  /// The flex factor to apply to the track if there is any room left over when\n  /// laying out the grid. The remaining space is distributed to any tracks\n  /// with flex in proportion to their flex value (higher values get more\n  /// space).\n  double? get flex => null;\n\n  /// Helper function for determining the minimum intrinsic size of an item\n  /// along the vertical or horizontal axis.\n  @protected\n  double _itemMinIntrinsicSizeOnAxis(\n      RenderBox item, Axis axis, double crossAxisSize) {\n    return axis == Axis.horizontal\n        ? item.getMinIntrinsicWidth(crossAxisSize)\n        : item.getMinIntrinsicHeight(crossAxisSize);\n  }\n\n  /// Helper function for determining the maximum intrinsic size of an item\n  /// along the vertical or horizontal axis.\n  @protected\n  double _itemMaxIntrinsicSizeOnAxis(\n      RenderBox item, Axis axis, double crossAxisSize) {\n    return axis == Axis.horizontal\n        ? item.getMaxIntrinsicWidth(crossAxisSize)\n        : item.getMaxIntrinsicHeight(crossAxisSize);\n  }\n\n  @override\n  void debugFillProperties(DiagnosticPropertiesBuilder properties) {\n    super.debugFillProperties(properties);\n\n    if (debugLabel != null) {\n      properties.add(StringProperty('debugLabel', debugLabel));\n    }\n  }\n}\n\n/// Sizes the track to a specific number of pixels.\n///\n/// This is the cheapest way to size a track.\nclass FixedTrackSize extends TrackSize {\n  const FixedTrackSize(this.sizeInPx, {String? debugLabel})\n      : super(debugLabel: debugLabel);\n\n  /// The size (width for columns, height for rows) the track should occupy\n  /// in logical pixels.\n  final double sizeInPx;\n\n  @override\n  bool isFixedForConstraints(TrackType type, BoxConstraints gridConstraints) {\n    return true;\n  }\n\n  @override\n  double minIntrinsicSize(\n    TrackType type,\n    Iterable<RenderBox> items, {\n    double Function(RenderBox)? crossAxisSizeForItem,\n  }) {\n    return sizeInPx;\n  }\n\n  @override\n  double maxIntrinsicSize(\n    TrackType type,\n    Iterable<RenderBox> items, {\n    required double Function(RenderBox) crossAxisSizeForItem,\n  }) {\n    return sizeInPx;\n  }\n\n  @override\n  int get hashCode => Object.hash(sizeInPx, debugLabel);\n\n  @override\n  bool operator ==(Object other) {\n    if (identical(this, other)) return true;\n    if (other.runtimeType != runtimeType) return false;\n    return other is FixedTrackSize && other.sizeInPx == sizeInPx;\n  }\n\n  @override\n  void debugFillProperties(DiagnosticPropertiesBuilder properties) {\n    super.debugFillProperties(properties);\n    properties.add(DoubleProperty('sizeInPx', sizeInPx));\n  }\n}\n\n/// Sizes the track by taking a part of the remaining space once all the other\n/// tracks have been laid out on the same axis.\n///\n/// For example, if two columns have a [FlexibleTrackSize] with the same\n/// [flexFactor], then half the space will go to one and half the space will go\n/// to the other.\n///\n/// This is a cheap way to size a track.\nclass FlexibleTrackSize extends TrackSize {\n  /// Creates a track size based on a fraction of the grid's leftover space.\n  ///\n  /// The [flexFactor] argument must not be null.\n  const FlexibleTrackSize(this.flexFactor, {String? debugLabel})\n      : assert(flexFactor > 0),\n        super(debugLabel: debugLabel);\n\n  /// The flex factor to use for this track\n  ///\n  /// The amount of space the track can occupy on the track's cross axis is\n  /// determined by dividing the free space (after placing the inflexible\n  /// children) according to the flex factors of the flexible children.\n  final double flexFactor;\n\n  @override\n  bool get isFlexible {\n    return true;\n  }\n\n  @override\n  double minIntrinsicSize(\n    TrackType type,\n    Iterable<RenderBox> items, {\n    double Function(RenderBox)? crossAxisSizeForItem,\n  }) {\n    return 0;\n  }\n\n  @override\n  double maxIntrinsicSize(\n    TrackType type,\n    Iterable<RenderBox> items, {\n    required double Function(RenderBox) crossAxisSizeForItem,\n  }) {\n    return 0;\n  }\n\n  @override\n  double get flex => flexFactor;\n\n  @override\n  void debugFillProperties(DiagnosticPropertiesBuilder properties) {\n    super.debugFillProperties(properties);\n\n    properties.add(DoubleProperty('flex', flex));\n  }\n\n  @override\n  int get hashCode => Object.hash(flex, debugLabel);\n\n  @override\n  bool operator ==(Object other) {\n    if (identical(this, other)) return true;\n    if (other.runtimeType != runtimeType) return false;\n    return other is FlexibleTrackSize && other.flex == flex;\n  }\n}\n\n/// Sizes the track according to the intrinsic dimensions of all its cells.\n///\n/// This is a very expensive way to size a column.\nclass IntrinsicContentTrackSize extends TrackSize {\n  const IntrinsicContentTrackSize({String? debugLabel})\n      : super(debugLabel: debugLabel);\n\n  @override\n  bool get isIntrinsic {\n    return true;\n  }\n\n  @override\n  double minIntrinsicSize(\n    TrackType type,\n    Iterable<RenderBox> items, {\n    double Function(RenderBox)? crossAxisSizeForItem,\n  }) {\n    crossAxisSizeForItem ??= (_) => double.infinity;\n    final minContentContributions = items.map(\n      (item) => _itemMinIntrinsicSizeOnAxis(\n        item,\n        measurementAxisForTrackType(type),\n        crossAxisSizeForItem!(item),\n      ),\n    );\n    return max(\n      minContentContributions,\n    )!;\n  }\n\n  @override\n  double maxIntrinsicSize(\n    TrackType type,\n    Iterable<RenderBox> items, {\n    required double Function(RenderBox) crossAxisSizeForItem,\n  }) {\n    final maxContentContributions = items.map(\n      (item) => _itemMaxIntrinsicSizeOnAxis(\n        item,\n        measurementAxisForTrackType(type),\n        crossAxisSizeForItem(item),\n      ),\n    );\n    return max(maxContentContributions)!;\n  }\n\n  @override\n  int get hashCode => debugLabel.hashCode;\n\n  @override\n  bool operator ==(Object other) {\n    if (identical(this, other)) return true;\n    return other.runtimeType == runtimeType;\n  }\n}\n\nbool trackSizeListsEqual(List<TrackSize> a, List<TrackSize> b) {\n  if (identical(a, b)) return true;\n  return a.length == b.length &&\n      zip([a, b]).every((pair) => pair[0] == pair[1]);\n}\n"
  },
  {
    "path": "lib/src/widgets/layout_grid.dart",
    "content": "// ignore_for_file: deprecated_member_use_from_same_package, unnecessary_this\n\nimport 'package:flutter/foundation.dart';\nimport 'package:flutter/rendering.dart';\nimport 'package:flutter/widgets.dart';\n\nimport '../foundation/placement.dart';\nimport '../rendering/layout_grid.dart';\nimport '../rendering/track_size.dart';\nimport 'placement.dart';\n\n/// Controls how the auto-placement algorithm works, specifying exactly how\n/// auto-placed items get flowed into the grid.\nclass AutoPlacement {\n  /// Items are placed by filling each row in turn, adding new rows as\n  /// necessary. If neither row nor column is provided, row is assumed.\n  static const rowSparse =\n      AutoPlacement._(TrackType.row, AutoPlacementPacking.sparse);\n\n  /// Items are placed by filling each row in turn, attempting to fill in holes\n  /// earlier in the grid, if smaller items come up later, adding rows as\n  /// necessary. This may cause items to appear out-of-order, when doing so\n  /// would fill in holes left by larger items.\n  static const rowDense =\n      AutoPlacement._(TrackType.row, AutoPlacementPacking.dense);\n\n  /// Items are placed by filling each column in turn, adding new columns as\n  /// necessary.\n  static const columnSparse =\n      AutoPlacement._(TrackType.column, AutoPlacementPacking.sparse);\n\n  /// Items are placed by filling each column in turn, attempting to fill in\n  /// holes earlier in the grid, if smaller items come up later, adding columns\n  /// as necessary. This may cause items to appear out-of-order, when doing so\n  /// would fill in holes left by larger items.\n  static const columnDense =\n      AutoPlacement._(TrackType.column, AutoPlacementPacking.dense);\n\n  const AutoPlacement._(this.trackType, this.packing);\n  final TrackType trackType;\n  final AutoPlacementPacking packing;\n\n  @override\n  String toString() {\n    switch (this) {\n      case rowSparse:\n        return 'AutoPlacement.rowSparse';\n      case rowDense:\n        return 'AutoPlacement.rowDense';\n      case columnSparse:\n        return 'AutoPlacement.columnSparse';\n      case columnDense:\n        return 'AutoPlacement.columnDense';\n    }\n    throw StateError('toString() called on unknown AutoPlacement');\n  }\n\n  /// The list of all available AutoPlacement values\n  static const List<AutoPlacement> values = [\n    rowSparse,\n    rowDense,\n    columnSparse,\n    columnDense,\n  ];\n}\n\n/// Determines the constraints available to the grid layout algorithm.\nenum GridFit {\n  /// The constraints passed to the grid from its parent are tightened to the\n  /// biggest size allowed. For example, if the grid has loose constraints with\n  /// a width in the range 10 to 100 and a height in the range 0 to 600, then\n  /// the children will be instructed to fill the entire 100×600 size.\n  ///\n  /// If the constraints passed to the grid are unbounded on a dimension, the\n  /// children will be allowed to maximize their sizes on that axis (column\n  /// taking preference).\n  expand,\n\n  /// The constraints passed to the grid from its parent are loosened. For\n  /// example, if the grid has constraints that force it to 350x600, then this\n  /// would allow the children of the grid to collectively have a width between\n  /// zero and 350 and a height from zero to 600.\n  loose,\n\n  /// The constraints passed to the grid from its parent are interpreted as-is.\n  passthrough,\n}\n\n/// Lays out its children using a approximation of the CSS Grid Layout\n/// algorithm, as described here:\n///\n/// https://drafts.csswg.org/css-grid/\n///\n/// If a grid item falls outside of the area defined by the template tracks, an\n/// [FlutterError] will be thrown during layout.\nclass LayoutGrid extends MultiChildRenderObjectWidget {\n  LayoutGrid({\n    Key? key,\n    this.autoPlacement = AutoPlacement.rowSparse,\n    this.gridFit = GridFit.expand,\n    this.areas,\n    required this.columnSizes,\n    required this.rowSizes,\n    double? rowGap,\n    double? columnGap,\n    this.textDirection,\n    List<Widget> children = const [],\n  })  : this.rowGap = rowGap ?? 0,\n        this.columnGap = columnGap ?? 0,\n        super(key: key, children: children) {\n    assert(columnSizes.isNotEmpty);\n    assert(rowSizes.isNotEmpty);\n    assert(() {\n      if (areas == null) return true;\n      final parsedAreas = parseNamedAreasSpec(areas!);\n\n      assert(parsedAreas.columnCount == columnSizes.length,\n          'areas.columnCount != columnSizes.length');\n      assert(parsedAreas.rowCount == rowSizes.length,\n          'areas.rowCount != rowSizes.length');\n      return true;\n    }(), 'areas ');\n  }\n\n  /// Controls how the auto-placement algorithm works, specifying exactly how\n  /// auto-placed items get flowed into the grid.\n  final AutoPlacement autoPlacement;\n\n  /// Determines the constraints available to the grid layout algorithm.\n  final GridFit gridFit;\n\n  /// Defines named areas of the grid for placement of grid items by name.\n  ///\n  /// This string is similar to `grid-template-areas` in CSS, as described in\n  /// https://developer.mozilla.org/en-US/docs/Web/CSS/grid-template-areas,\n  /// but unlike CSS is a single multiline string.\n  ///\n  /// Can be `null`, meaning that any grid item placed by name will not appear\n  /// in the grid.\n  ///\n  /// Example:\n  ///\n  /// ```dart\n  /// LayoutGrid(\n  ///   areas: '''\n  ///     header header  header\n  ///     nav    content aside\n  ///     nav    content .\n  ///     footer footer  footer\n  ///   ''',\n  /// )\n  /// ```\n  ///\n  final String? areas;\n\n  /// Defines the track sizing functions of the grid's columns.\n  final List<TrackSize> columnSizes;\n\n  /// Defines the track sizing functions of the grid's rows.\n  final List<TrackSize> rowSizes;\n\n  /// Space between column tracks\n  final double columnGap;\n\n  /// Space between row tracks\n  final double rowGap;\n\n  /// The text direction used to resolve column ordering.\n  ///\n  /// Defaults to the ambient [Directionality].\n  final TextDirection? textDirection;\n\n  @override\n  RenderLayoutGrid createRenderObject(BuildContext context) {\n    return RenderLayoutGrid(\n      autoPlacement: autoPlacement,\n      gridFit: gridFit,\n      areasSpec: areas,\n      columnSizes: columnSizes,\n      rowSizes: rowSizes,\n      columnGap: columnGap,\n      rowGap: rowGap,\n      textDirection: textDirection ?? Directionality.of(context),\n    );\n  }\n\n  @override\n  void updateRenderObject(BuildContext context, RenderLayoutGrid renderObject) {\n    renderObject\n      ..autoPlacement = autoPlacement\n      ..gridFit = gridFit\n      ..areasSpec = areas\n      ..columnSizes = columnSizes\n      ..rowSizes = rowSizes\n      ..columnGap = columnGap\n      ..rowGap = rowGap\n      ..textDirection = textDirection ?? Directionality.of(context);\n  }\n\n  @override\n  void debugFillProperties(DiagnosticPropertiesBuilder properties) {\n    super.debugFillProperties(properties);\n\n    properties.add(IterableProperty(\n      'columnSizes',\n      columnSizes,\n    ));\n    properties.add(IterableProperty(\n      'rowSizes',\n      rowSizes,\n    ));\n    properties.add(DiagnosticsProperty('autoPlacement', autoPlacement));\n    properties.add(DiagnosticsProperty('gridFit', gridFit));\n    properties.add(DoubleProperty('columnGap', columnGap));\n    properties.add(DoubleProperty('rowGap', rowGap));\n    if (textDirection != null) {\n      properties.add(DiagnosticsProperty('textDirection', textDirection));\n    }\n  }\n}\n"
  },
  {
    "path": "lib/src/widgets/placement.dart",
    "content": "import 'package:flutter/foundation.dart';\nimport 'package:flutter/widgets.dart';\n\nimport '../rendering/layout_grid.dart';\nimport 'layout_grid.dart';\n\n/// Packing strategies used by the auto-placement algorithm.\nenum AutoPlacementPacking {\n  /// The placement algorithm only ever moves “forward” in the grid when placing\n  /// items, never backtracking to fill holes. This ensures that all of the\n  /// auto-placed items appear “in order”, even if this leaves holes that could\n  /// have been filled by later items.\n  sparse,\n\n  /// The auto-placement algorithm uses a “dense” packing algorithm, which\n  /// attempts to fill in holes earlier in the grid if smaller items come up\n  /// later. This may cause items to appear out-of-order, when doing so would\n  /// fill in holes left by larger items.\n  dense,\n}\n\n/// A widget that controls where a child of a [LayoutGrid] is placed. If a grid\n/// item is not wrapped by a [GridPlacement], it will be placed in the first\n/// available space, spanning one row and one column.\nclass GridPlacement extends ParentDataWidget<GridParentData> {\n  const GridPlacement({\n    Key? key,\n    required Widget child,\n    this.columnStart,\n    this.columnSpan = 1,\n    this.rowStart,\n    this.rowSpan = 1,\n  }) : super(key: key, child: child);\n\n  /// If `null`, the child will be auto-placed.\n  final int? columnStart;\n\n  /// The number of columns spanned by the child. Defaults to `1`.\n  final int columnSpan;\n\n  /// If `null`, the child will be auto-placed.\n  final int? rowStart;\n\n  /// The number of rows spanned by the child. Defaults to `1`.\n  final int rowSpan;\n\n  @override\n  void applyParentData(RenderObject renderObject) {\n    assert(renderObject.parentData is GridParentData);\n    final parentData = renderObject.parentData as GridParentData;\n    bool needsLayout = false;\n\n    // TODO(shyndman): I don't like that we clear out a field that another\n    // placement widget uses. We should probably enter a mode specific to this\n    // placement widget, and have the ParentData figure out its internal state.\n    if (parentData.areaName != null) {\n      parentData.areaName = null;\n      needsLayout = true;\n    }\n\n    if (parentData.columnStart != columnStart) {\n      parentData.columnStart = columnStart;\n      needsLayout = true;\n    }\n\n    if (parentData.columnSpan != columnSpan) {\n      parentData.columnSpan = columnSpan;\n      needsLayout = true;\n    }\n\n    if (parentData.rowStart != rowStart) {\n      parentData.rowStart = rowStart;\n      needsLayout = true;\n    }\n\n    if (parentData.rowSpan != rowSpan) {\n      parentData.rowSpan = rowSpan;\n      needsLayout = true;\n    }\n\n    if (needsLayout) {\n      final targetParent = renderObject.parent;\n      if (targetParent is RenderLayoutGrid) targetParent.markNeedsPlacement();\n      if (targetParent is RenderObject) targetParent.markNeedsLayout();\n    }\n  }\n\n  @override\n  void debugFillProperties(DiagnosticPropertiesBuilder properties) {\n    super.debugFillProperties(properties);\n    if (columnStart != null) {\n      properties.add(IntProperty('columnStart', columnStart));\n    } else {\n      properties.add(StringProperty('columnStart', 'auto'));\n    }\n    properties.add(IntProperty('columnSpan', columnSpan));\n\n    if (rowStart != null) {\n      properties.add(IntProperty('rowStart', rowStart));\n    } else {\n      properties.add(StringProperty('rowStart', 'auto'));\n    }\n    properties.add(IntProperty('rowSpan', rowSpan));\n  }\n\n  @override\n  Type get debugTypicalAncestorWidgetClass => LayoutGrid;\n}\n\n/// Grid placement based on the name of an area provided to the grid via\n/// [LayoutGrid.areas].\n///\n/// If [areaName] does not exist in the grid's [LayoutGrid.areas], the\n/// child of this widget is not shown.\nclass NamedAreaGridPlacement extends ParentDataWidget<GridParentData> {\n  const NamedAreaGridPlacement({\n    Key? key,\n    required this.areaName,\n    required Widget child,\n  }) : super(key: key, child: child);\n\n  final String areaName;\n\n  @override\n  void applyParentData(RenderObject renderObject) {\n    assert(renderObject.parentData is GridParentData);\n    final parentData = renderObject.parentData as GridParentData;\n\n    if (parentData.areaName != areaName) {\n      parentData.areaName = areaName;\n\n      final targetParent = renderObject.parent;\n      if (targetParent is RenderLayoutGrid) targetParent.markNeedsPlacement();\n      if (targetParent is RenderObject) targetParent.markNeedsLayout();\n    }\n  }\n\n  @override\n  void debugFillProperties(DiagnosticPropertiesBuilder properties) {\n    super.debugFillProperties(properties);\n    properties.add(StringProperty('areaName', areaName));\n  }\n\n  @override\n  Type get debugTypicalAncestorWidgetClass => LayoutGrid;\n}\n\n/// Extension methods for terse placement syntax\nextension GridPlacementExtensions on Widget {\n  NamedAreaGridPlacement inGridArea(String areaName, {Key? key}) {\n    return NamedAreaGridPlacement(\n      key: key,\n      areaName: areaName,\n      child: this,\n    );\n  }\n\n  GridPlacement withGridPlacement({\n    Key? key,\n    int? columnStart,\n    int columnSpan = 1,\n    int? rowStart,\n    int rowSpan = 1,\n  }) {\n    return GridPlacement(\n      key: key,\n      columnStart: columnStart,\n      columnSpan: columnSpan,\n      rowStart: rowStart,\n      rowSpan: rowSpan,\n      child: this,\n    );\n  }\n}\n"
  },
  {
    "path": "pubspec.yaml",
    "content": "name: flutter_layout_grid\ndescription: A powerful grid layout system for Flutter, optimized for complex\n  user interface design.\nversion: 2.0.8\nhomepage: https://github.com/shyndman/flutter_layout_grid\n\nenvironment:\n  flutter: '>=1.25.0'\n  sdk: '>=2.15.0 <4.0.0'\n\ndependencies:\n  flutter:\n    sdk: flutter\n  collection: ^1.15.0\n  quiver: ^3.0.0\n\ndev_dependencies:\n  flutter_lints: ^3.0.0\n  flutter_test:\n    sdk: flutter\n"
  },
  {
    "path": "test/accessibility_test.dart",
    "content": "// ignore_for_file: prefer_const_literals_to_create_immutables, prefer_const_constructors\n\nimport 'package:flutter/material.dart';\nimport 'package:flutter/rendering.dart';\nimport 'package:flutter_layout_grid/flutter_layout_grid.dart';\nimport 'package:flutter_test/flutter_test.dart';\n\nimport 'test_helpers.dart';\n\nvoid main() {\n  group('accessibility', () {\n    testWidgets('presents children in source order', (tester) async {\n      final gridSemantics = await _pumpAndReturnSemantics(\n        tester,\n        LayoutGrid(\n          columnSizes: [auto],\n          rowSizes: repeat(5, [auto]),\n          children: [\n            Text('this'),\n            Text('is'),\n            Text('in'),\n            Text('source'),\n            Text('order'),\n          ],\n        ),\n      );\n\n      final gridChildLabels = gridSemantics\n          .debugListChildrenInOrder(DebugSemanticsDumpOrder.traversalOrder)\n          .map((node) => node.label);\n      expect(\n        gridChildLabels,\n        ['this', 'is', 'in', 'source', 'order'],\n      );\n    });\n\n    testWidgets('respects ordering provided by Semantics.sortKey',\n        (tester) async {\n      final gridSemantics = await _pumpAndReturnSemantics(\n        tester,\n        LayoutGrid(\n          columnSizes: [auto],\n          rowSizes: repeat(5, [auto]),\n          children: [\n            Semantics(\n              sortKey: OrdinalSortKey(1),\n              child: Text('this'),\n            ),\n            Semantics(\n              sortKey: OrdinalSortKey(3),\n              child: Text('isn\\'t'),\n            ),\n            Semantics(\n              sortKey: OrdinalSortKey(2),\n              child: Text('in'),\n            ),\n            Semantics(\n              sortKey: OrdinalSortKey(4),\n              child: Text('source'),\n            ),\n            Semantics(\n              sortKey: OrdinalSortKey(0),\n              child: Text('order'),\n            ),\n          ],\n        ),\n      );\n\n      final gridChildLabels = gridSemantics\n          .debugListChildrenInOrder(DebugSemanticsDumpOrder.traversalOrder)\n          .map((node) => node.label);\n      expect(\n        gridChildLabels,\n        ['order', 'this', 'in', 'isn\\'t', 'source'],\n      );\n    });\n  });\n}\n\nFuture<SemanticsNode> _pumpAndReturnSemantics(\n    WidgetTester tester, LayoutGrid grid) async {\n  await tester.pumpWidget(wrapInMinimalApp(\n    Semantics(\n      explicitChildNodes: true,\n      child: grid,\n    ),\n  ));\n  return tester.getSemantics(find.byType(LayoutGrid));\n}\n"
  },
  {
    "path": "test/areas_parsing_test.dart",
    "content": "// ignore_for_file: prefer_const_constructors\n\nimport 'package:flutter_layout_grid/src/foundation/placement.dart';\nimport 'package:flutter_test/flutter_test.dart';\n\nvoid main() {\n  group('template area parsing', () {\n    test('produces correctly named GridAreas', () {\n      final areas = parseNamedAreasSpec('''\n        logo     nav      nav      nav\n        bar      main     main     main\n        bar      main     main     main\n        bar      main     main     main\n        footer   footer   footer   footer\n      ''');\n      expect(areas.length, 5);\n      expect(\n        areas['logo'],\n        GridArea(\n          name: 'logo',\n          columnStart: 0,\n          columnEnd: 1,\n          rowStart: 0,\n          rowEnd: 1,\n        ),\n      );\n      expect(\n        areas['nav'],\n        GridArea(\n          name: 'nav',\n          columnStart: 1,\n          columnEnd: 4,\n          rowStart: 0,\n          rowEnd: 1,\n        ),\n      );\n      expect(\n        areas['bar'],\n        GridArea(\n          name: 'bar',\n          columnStart: 0,\n          columnEnd: 1,\n          rowStart: 1,\n          rowEnd: 4,\n        ),\n      );\n      expect(\n        areas['main'],\n        GridArea(\n          name: 'main',\n          columnStart: 1,\n          columnEnd: 4,\n          rowStart: 1,\n          rowEnd: 4,\n        ),\n      );\n      expect(\n        areas['footer'],\n        GridArea(\n          name: 'footer',\n          columnStart: 0,\n          columnEnd: 4,\n          rowStart: 4,\n          rowEnd: 5,\n        ),\n      );\n    });\n\n    test('throws with disjoint area', () {\n      expect(\n        () => parseNamedAreasSpec('a . . a'),\n        throwsA(isInstanceOf<ArgumentError>()),\n      );\n    });\n\n    test('throws with incomplete area rectangles', () {\n      expect(\n        () => parseNamedAreasSpec('''\n          a . . .\n          a a . .\n          a a . .\n        '''),\n        throwsArgumentError,\n      );\n    });\n\n    test('throws with varying column counts', () {\n      expect(\n        () => parseNamedAreasSpec('''\n          a . . .\n          a . . . .\n          a . . .\n        '''),\n        throwsArgumentError,\n      );\n    });\n\n    test(\"throws when periods (unnamed cells) aren't spaced\", () {\n      expect(\n        () => parseNamedAreasSpec('''\n          .. . .\n        '''),\n        throwsArgumentError,\n      );\n    });\n  });\n}\n"
  },
  {
    "path": "test/ensure_debug_flags_off_test.dart",
    "content": "import 'package:flutter_layout_grid/src/rendering/debug.dart';\nimport 'package:flutter_test/flutter_test.dart';\n\n// A bunch of sanity checks to make sure we don't release anything with debug\n// features turned on.\nvoid main() {\n  test('Ensure that debug printing is turned off', () {\n    expect(debugPrintGridLayout, false);\n  });\n\n  test('Ensure that debug overflow printing is turned off', () {\n    expect(debugPrintUnplacedChildren, false);\n  });\n}\n"
  },
  {
    "path": "test/golden_test.dart",
    "content": "// ignore_for_file: prefer_const_constructors, use_key_in_widget_constructors\n\nimport 'package:flutter/material.dart';\nimport 'package:flutter_layout_grid/flutter_layout_grid.dart';\nimport 'package:flutter_test/flutter_test.dart';\n\nvoid main() {\n  testWidgets('Piet screenshot test', (tester) async {\n    await tester.pumpWidget(PietApp());\n    await expectLater(\n      find.byType(PietApp),\n      matchesGoldenFile('goldens/piet.png'),\n    );\n  });\n}\n\nconst cellRed = Color(0xffc73232);\nconst cellMustard = Color(0xffd7aa22);\nconst cellGrey = Color(0xffcfd4e0);\nconst cellBlue = Color(0xff1553be);\nconst background = Color(0xff242830);\n\nclass PietApp extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return WidgetsApp(\n      title: 'Layout Grid Desktop Example',\n      debugShowCheckedModeBanner: false,\n      color: Colors.white,\n      builder: (context, child) => PietPainting(),\n    );\n  }\n}\n\nclass PietPainting extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Container(\n      color: background,\n      child: LayoutGrid(\n        columnGap: 12,\n        rowGap: 12,\n        columnSizes: [1.fr, 3.5.fr, 1.3.fr, 1.3.fr, 1.3.fr],\n        rowSizes: [\n          1.fr,\n          0.3.fr,\n          1.5.fr,\n          1.2.fr,\n        ],\n        children: [\n          // Column 1\n          Container(color: cellRed).withGridPlacement(\n            columnStart: 0,\n            rowStart: 0,\n            rowSpan: 2,\n          ),\n          Container(color: cellMustard).withGridPlacement(\n            columnStart: 0,\n            rowStart: 2,\n            rowSpan: 2,\n          ),\n          // Column 2\n          Container(color: cellRed).withGridPlacement(\n            columnStart: 1,\n            rowStart: 0,\n            rowSpan: 4,\n          ),\n          // Column 3\n          Container(color: cellBlue).withGridPlacement(\n            columnStart: 2,\n            columnSpan: 3,\n            rowStart: 0,\n          ),\n          Container(color: cellMustard).withGridPlacement(\n            columnStart: 2,\n            columnSpan: 3,\n            rowStart: 1,\n            rowSpan: 2,\n          ),\n          Container(color: cellGrey).withGridPlacement(\n            columnStart: 2,\n            rowStart: 3,\n          ),\n          // Column 4\n          Container(color: cellBlue).withGridPlacement(\n            columnStart: 3,\n            rowStart: 3,\n          ),\n          // Column 5\n          Container(color: cellMustard).withGridPlacement(\n            columnStart: 4,\n            rowStart: 3,\n          ),\n        ],\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "test/grid_sizing_test.dart",
    "content": "// ignore_for_file: prefer_const_constructors, prefer_const_literals_to_create_immutables\n\nimport 'package:flutter/material.dart';\nimport 'package:flutter/widgets.dart';\nimport 'package:flutter_layout_grid/flutter_layout_grid.dart';\nimport 'package:flutter_layout_grid/src/rendering/layout_grid.dart';\nimport 'package:flutter_test/flutter_test.dart';\n\nimport 'test_helpers.dart';\n\nvoid main() {\n  group('Grid fit', () {\n    testWidgets('GridFit.loose sizes only as much as it needs to',\n        (tester) async {\n      await tester.pumpWidget(_gridFitHarness(\n        constraints: BoxConstraints.loose(Size(200, 200)),\n        // This grid wants to size to be 100x100, but its parent dictates\n        // otherwise\n        child: LayoutGrid(\n          gridFit: GridFit.loose,\n          columnSizes: [fixed(100)],\n          rowSizes: [fixed(100)],\n          children: [],\n        ),\n      ));\n\n      expect(findGridSizing(tester).gridSize, Size(100, 100));\n    });\n\n    testWidgets('GridFit.loose respects minimum constraints', (tester) async {\n      await tester.pumpWidget(_gridFitHarness(\n        constraints: BoxConstraints(minWidth: 200, minHeight: 200),\n        // This grid wants to size to be 100x100, but its parent dictates\n        // otherwise\n        child: LayoutGrid(\n          gridFit: GridFit.loose,\n          columnSizes: [fixed(100)],\n          rowSizes: [fixed(100)],\n          children: [],\n        ),\n      ));\n\n      final sizing = findGridSizing(tester);\n      expect(sizing.gridSize, Size(200, 200));\n      expect(sizing.baseSizesForType(TrackType.column), [100]);\n      expect(sizing.baseSizesForType(TrackType.row), [100]);\n    });\n\n    testWidgets('GridFit.expand with bounded constraints sizes to maximum',\n        (tester) async {\n      await tester.pumpWidget(_gridFitHarness(\n        constraints: BoxConstraints.tightFor(width: 400, height: 400),\n        child: LayoutGrid(\n          gridFit: GridFit.expand,\n          columnSizes: [intrinsic()],\n          rowSizes: [intrinsic()],\n          children: [],\n        ),\n      ));\n\n      expect(findGridSizing(tester).gridSize, Size(400, 400));\n    });\n  });\n\n  group('Overflowing children', () {\n    testWidgets('do not overflow the grid', (tester) async {\n      await tester.pumpWidget(_gridFitHarness(\n        constraints: BoxConstraints.tightFor(width: 400, height: 400),\n        child: LayoutGrid(\n          gridFit: GridFit.expand,\n          columnSizes: [fixed(800)],\n          rowSizes: [fixed(800)],\n          children: [Container()],\n        ),\n      ));\n\n      tester.takeException(); // Ignore overflow exception\n\n      expect(findGridSizing(tester).gridSize, Size(400, 400));\n    });\n\n    testWidgets('are reported to the user', (tester) async {\n      await tester.pumpWidget(_gridFitHarness(\n        constraints: BoxConstraints.tightFor(width: 400, height: 400),\n        child: LayoutGrid(\n          gridFit: GridFit.expand,\n          columnSizes: [fixed(800)],\n          rowSizes: [fixed(800)],\n          children: [Container()],\n        ),\n      ));\n\n      // Ignore overflow exception\n      final dynamic exception = tester.takeException();\n      expect(exception, isFlutterError);\n      expect(exception.diagnostics.first.level, DiagnosticLevel.summary);\n      expect(\n        exception.diagnostics.first.toString(),\n        startsWith('A RenderLayoutGrid overflowed by '),\n      );\n    });\n  });\n\n  group('Intrinsic grid sizing', () {\n    testWidgets('Computes fixed intrinsic sizes', (tester) async {\n      final grid = LayoutGrid(\n        columnSizes: [FixedTrackSize(10)],\n        rowSizes: [FixedTrackSize(10)],\n        textDirection: TextDirection.ltr,\n      );\n      await tester.pumpWidget(grid);\n      final renderObject =\n          tester.firstRenderObject<RenderLayoutGrid>(find.byType(LayoutGrid));\n\n      expect(renderObject.getMinIntrinsicWidth(double.infinity), 10);\n      expect(renderObject.getMinIntrinsicHeight(double.infinity), 10);\n      expect(renderObject.getMaxIntrinsicWidth(double.infinity), 10);\n      expect(renderObject.getMaxIntrinsicHeight(double.infinity), 10);\n    });\n\n    testWidgets('Computes intrinsic sizes with nested grid and rowGaps',\n        (tester) async {\n      final grid = LayoutGrid(\n        areas: '''\n          parentRow1\n        ''',\n        textDirection: TextDirection.ltr,\n        columnSizes: [10.px],\n        rowSizes: [auto],\n        children: [\n          LayoutGrid(\n            areas: '''\n              nestedRow1\n              nestedRow2\n              nestedRow3\n            ''',\n            textDirection: TextDirection.ltr,\n            columnSizes: [1.fr],\n            rowSizes: [auto, auto, auto],\n            rowGap: 10,\n            children: [\n              Container(height: 5).inGridArea('nestedRow1'),\n              Container(height: 7).inGridArea('nestedRow2'),\n              Container(height: 9).inGridArea('nestedRow3'),\n            ],\n          ).inGridArea('parentRow1'),\n        ],\n      );\n\n      await tester.pumpWidget(grid);\n      final renderObject =\n          tester.firstRenderObject<RenderLayoutGrid>(find.byType(LayoutGrid));\n\n      expect(renderObject.getMinIntrinsicWidth(double.infinity), 10);\n      // Height should be row sizes 21 (5+7+9) + 20 (2 gaps of 10) = 41\n      expect(renderObject.getMinIntrinsicHeight(double.infinity), 41);\n      expect(renderObject.getMaxIntrinsicWidth(double.infinity), 10);\n      expect(renderObject.getMaxIntrinsicHeight(double.infinity), 41);\n    });\n  });\n\n  group('computeDryLayout', () {\n    testWidgets('computes the same size that layout does', (tester) async {\n      final testConstraints = BoxConstraints.tightFor(width: 400, height: 400);\n      await tester.pumpWidget(_gridFitHarness(\n        constraints: testConstraints,\n        child: LayoutGrid(\n          gridFit: GridFit.expand,\n          columnSizes: [1.fr],\n          rowSizes: [1.fr],\n          children: [],\n        ),\n      ));\n\n      final renderGrid =\n          tester.renderObject<RenderLayoutGrid>(find.byType(LayoutGrid));\n      expect(\n        renderGrid.lastGridSizing.gridSize,\n        renderGrid.computeDryLayout(testConstraints),\n      );\n    });\n\n    testWidgets('does not call layout() in children', (tester) async {\n      final testConstraints = BoxConstraints.tightFor(width: 400, height: 400);\n\n      // This will layout the child once\n      await tester.pumpWidget(_gridFitHarness(\n        constraints: testConstraints,\n        child: LayoutGrid(\n          gridFit: GridFit.expand,\n          columnSizes: [auto],\n          rowSizes: [auto],\n          children: [TestLayoutCountingWidget()],\n        ),\n      ));\n\n      final renderGrid =\n          tester.renderObject<RenderLayoutGrid>(find.byType(LayoutGrid));\n      final renderGridItem =\n          tester.renderObject<RenderTestLayoutCountingWidget>(\n              find.byType(TestLayoutCountingWidget));\n\n      // Ensure the child has been laid out once, then reset the count\n      expect(renderGridItem.layoutCount, 1);\n      renderGridItem.resetCount();\n      renderGrid.computeDryLayout(testConstraints);\n      expect(renderGridItem.layoutCount, 0);\n    });\n  });\n}\n\nWidget _gridFitHarness({\n  BoxConstraints? constraints,\n  required Widget child,\n}) {\n  if (constraints != null) {\n    child = ConstrainedBox(constraints: constraints, child: child);\n  }\n  return wrapInMinimalApp(UnconstrainedBox(child: child));\n}\n"
  },
  {
    "path": "test/invalidation_test.dart",
    "content": "import 'package:flutter/widgets.dart';\nimport 'package:flutter_layout_grid/flutter_layout_grid.dart';\nimport 'package:flutter_layout_grid/src/rendering/layout_grid.dart';\nimport 'package:flutter_test/flutter_test.dart';\n\nimport 'test_helpers.dart';\n\nconst initialColumnSizes = [FixedTrackSize(10)];\nconst initialRowSizes = [FixedTrackSize(10)];\n\nvoid main() {\n  group('grid invalidation', () {\n    testWidgets('# of columns change', (tester) async {\n      final renderGrid = await _setupInvalidationTest(tester);\n\n      // We expect that placement is not required, because we allowed the\n      // engine to go through a full layout pass.\n      expect(renderGrid.needsPlacement, false);\n\n      await tester.pumpWidget(\n        _testGrid(\n          columnSizes: [10.px, 10.px], // NOTE we added a column\n          rowSizes: initialRowSizes,\n        ),\n        // NOTE Only build, do not layout\n        phase: EnginePhase.build,\n      );\n\n      expect(renderGrid.needsPlacement, true);\n      expect(renderGrid.debugNeedsLayout, true);\n    });\n\n    testWidgets('columns change sizing function (same # of cols)',\n        (tester) async {\n      final renderGrid = await _setupInvalidationTest(tester);\n\n      // We pump again, with the same number of columns, but different functions\n      await tester.pumpWidget(\n        _testGrid(\n          columnSizes: [100.px], // Was 10.px\n          rowSizes: initialRowSizes,\n        ),\n        // NOTE Only build, do not layout\n        phase: EnginePhase.build,\n      );\n\n      expect(renderGrid.needsPlacement, false);\n      expect(renderGrid.debugNeedsLayout, true);\n    });\n\n    testWidgets('# of rows change', (tester) async {\n      final renderGrid = await _setupInvalidationTest(tester);\n\n      // We expect that placement is not required, because we allowed the\n      // engine to go through a full layout pass.\n      expect(renderGrid.needsPlacement, false);\n\n      await tester.pumpWidget(\n        _testGrid(\n          columnSizes: initialColumnSizes,\n          rowSizes: [10.px, 10.px], // NOTE we added a row\n        ),\n        // NOTE Only build, do not layout\n        phase: EnginePhase.build,\n      );\n\n      expect(renderGrid.needsPlacement, true);\n      expect(renderGrid.debugNeedsLayout, true);\n    });\n\n    testWidgets('rows change sizing function (same # of rows)', (tester) async {\n      final renderGrid = await _setupInvalidationTest(tester);\n\n      // We pump again, with the same number of rows, but different functions\n      await tester.pumpWidget(\n        _testGrid(\n          columnSizes: initialColumnSizes,\n          rowSizes: [100.px], // Was 10.px\n        ),\n        // NOTE Only build, do not layout\n        phase: EnginePhase.build,\n      );\n\n      expect(renderGrid.needsPlacement, false);\n      expect(renderGrid.debugNeedsLayout, true);\n    });\n\n    testWidgets('areas change', (tester) async {\n      final renderGrid = await _setupInvalidationTest(tester, areas: 'a');\n\n      // We expect that placement is not required, because we allowed the\n      // engine to go through a full layout pass.\n      expect(renderGrid.needsPlacement, false);\n\n      await tester.pumpWidget(\n        _testGrid(\n          areas: 'b',\n          columnSizes: initialColumnSizes,\n          rowSizes: initialRowSizes,\n        ),\n        // NOTE Only build, do not layout\n        phase: EnginePhase.build,\n      );\n\n      expect(renderGrid.needsPlacement, true);\n      expect(renderGrid.debugNeedsLayout, true);\n    });\n\n    testWidgets('identical areas/rows/columns', (tester) async {\n      final renderGrid = await _setupInvalidationTest(tester, areas: 'a');\n\n      // We pump again, with the same number of columns, but different functions\n      await tester.pumpWidget(\n        _testGrid(\n          areas: 'a',\n          columnSizes: initialColumnSizes,\n          rowSizes: initialRowSizes,\n        ),\n        // NOTE Only build, do not layout\n        phase: EnginePhase.build,\n      );\n\n      expect(renderGrid.needsPlacement, false);\n      expect(renderGrid.debugNeedsLayout, false);\n    });\n  });\n}\n\n/// Pumps an initial grid with one 10px column and row\nFuture<RenderLayoutGrid> _setupInvalidationTest(\n  WidgetTester tester, {\n  String? areas,\n}) async {\n  await tester.pumpWidget(\n    _testGrid(\n      areas: areas,\n      columnSizes: initialColumnSizes,\n      rowSizes: initialRowSizes,\n    ),\n  );\n  return tester.firstRenderObject<RenderLayoutGrid>(find.byType(LayoutGrid));\n}\n\nWidget _testGrid({\n  String? areas,\n  required List<TrackSize> columnSizes,\n  required List<TrackSize> rowSizes,\n}) {\n  return wrapInMinimalApp(\n    LayoutGrid(\n      areas: areas,\n      columnSizes: columnSizes,\n      rowSizes: rowSizes,\n    ),\n  );\n}\n"
  },
  {
    "path": "test/placement_test.dart",
    "content": "// ignore_for_file: prefer_const_constructors\n\nimport 'package:flutter/material.dart';\nimport 'package:flutter_layout_grid/flutter_layout_grid.dart';\nimport 'package:flutter_layout_grid/src/rendering/layout_grid.dart';\nimport 'package:flutter_test/flutter_test.dart';\n\nimport 'test_helpers.dart';\n\nvoid main() {\n  group('NameAreaGridPlacement', () {\n    testWidgets('positions items correctly', (tester) async {\n      final keyA = ValueKey('a'),\n          keyB = ValueKey('b'),\n          keyC = ValueKey('c'),\n          keyD = ValueKey('d');\n\n      await sizeGridWithChildren(\n        tester,\n        areas: '''\n          a a a .\n          a a a d\n          b . . d\n          c c c c\n        ''',\n        columnSizes: [fixed(10), fixed(10), fixed(10), fixed(10)],\n        rowSizes: [\n          fixed(10),\n          fixed(10),\n          fixed(10),\n          fixed(10),\n        ],\n        children: [\n          Container(key: keyA).inGridArea('a'),\n          Container(key: keyB).inGridArea('b'),\n          Container(key: keyC).inGridArea('c'),\n          Container(key: keyD).inGridArea('d'),\n        ],\n      );\n\n      expect(definiteAreaByKey(tester, keyA), [0, 3, 0, 2]);\n      expect(definiteAreaByKey(tester, keyB), [0, 1, 2, 1]);\n      expect(definiteAreaByKey(tester, keyC), [0, 4, 3, 1]);\n      expect(definiteAreaByKey(tester, keyD), [3, 1, 1, 2]);\n    });\n\n    testWidgets(\n        'is not placed when its area is not defined by LayoutGrid.areas',\n        (tester) async {\n      final keyA = ValueKey('a');\n      final keyNotInGrid = ValueKey('not-in-grid');\n\n      await sizeGridWithChildren(\n        tester,\n        areas: 'a',\n        columnSizes: [fixed(10)],\n        rowSizes: [\n          fixed(10),\n        ],\n        children: [\n          Container(key: keyA).inGridArea('a'),\n          Container(key: keyNotInGrid).inGridArea('not-in-grid'),\n        ],\n      );\n\n      // Just to be safe, we check the placed child\n      expect(definiteAreaByKey(tester, keyA), [0, 1, 0, 1]);\n\n      // Then check the child whose area is not defined\n      final notInGridParentData = parentDataByKey(tester, keyNotInGrid)!;\n      expect(notInGridParentData.isNotPlaced, true);\n    });\n\n    testWidgets('is not placed when LayoutGrid.areas is null', (tester) async {\n      final keyNotInGrid = ValueKey('not-in-grid');\n\n      await sizeGridWithChildren(\n        tester,\n        columnSizes: [fixed(10)],\n        rowSizes: [\n          fixed(10),\n        ],\n        children: [\n          Container(key: keyNotInGrid).inGridArea('not-in-grid'),\n        ],\n      );\n\n      // Then check the child whose area is not defined\n      final notInGridParentData = parentDataByKey(tester, keyNotInGrid)!;\n      expect(notInGridParentData.isNotPlaced, true);\n    });\n  });\n}\n\n/// Returned value is [colStart, colSpan, rowStart, rowSpan]\nList<int> definiteAreaByKey(WidgetTester tester, Key key) {\n  final parentData = parentDataByKey(tester, key)!;\n  final area = parentData.area;\n  return [\n    area.columnStart,\n    area.columnSpan,\n    area.rowStart,\n    area.rowSpan,\n  ];\n}\n\nGridParentData? parentDataByKey(WidgetTester tester, Key key) {\n  return tester.firstRenderObject(find.byKey(key)).parentData\n      as GridParentData?;\n}\n\nRenderBox gridItem({\n  int? columnStart,\n  int columnSpan = 1,\n  int? rowStart,\n  int rowSpan = 1,\n  String? debugLabel,\n}) {\n  return TestRenderBox()\n    ..parentData = GridParentData(\n      columnStart: columnStart,\n      columnSpan: columnSpan,\n      rowStart: rowStart,\n      rowSpan: rowSpan,\n      debugLabel: debugLabel,\n    );\n}\n\nclass TestRenderBox extends RenderBox {}\n"
  },
  {
    "path": "test/test_helpers.dart",
    "content": "// ignore_for_file: prefer_const_constructors, use_key_in_widget_constructors\n\nimport 'package:flutter/material.dart';\nimport 'package:flutter_layout_grid/flutter_layout_grid.dart';\nimport 'package:flutter_layout_grid/src/rendering/layout_grid.dart';\nimport 'package:flutter_test/flutter_test.dart';\n\nfinal testConstraints = BoxConstraints.loose(Size(800, 600));\n\n/// Sizes a grid that does not require the Flutter framework (ie, no children)\n/// or widget pumping.\nGridSizingInfo sizeEmptyGrid({\n  GridFit gridFit = GridFit.passthrough,\n  required List<TrackSize> columnSizes,\n  required List<TrackSize> rowSizes,\n  BoxConstraints? constraints,\n}) {\n  final renderGrid = RenderLayoutGrid(\n    gridFit: gridFit,\n    columnSizes: columnSizes,\n    rowSizes: rowSizes,\n    textDirection: TextDirection.ltr,\n  );\n  return renderGrid.computeGridSize(constraints ?? testConstraints);\n}\n\nFuture<GridSizingInfo> sizeGridWithChildren(\n  WidgetTester tester, {\n  GridFit gridFit = GridFit.passthrough,\n  String? areas,\n  required List<TrackSize> columnSizes,\n  required List<TrackSize> rowSizes,\n  required List<Widget> children,\n  BoxConstraints? constraints,\n}) async {\n  await tester.pumpWidget(\n    wrapInMinimalApp(\n      ConstrainedBox(\n        constraints: constraints ?? testConstraints,\n        child: LayoutGrid(\n          gridFit: gridFit,\n          areas: areas,\n          columnSizes: columnSizes,\n          rowSizes: rowSizes,\n          children: children,\n        ),\n      ),\n    ),\n  );\n\n  return findGridSizing(tester);\n}\n\nGridSizingInfo findGridSizing(WidgetTester tester) {\n  final renderGrid =\n      tester.renderObject<RenderLayoutGrid>(find.byType(LayoutGrid));\n  return renderGrid.lastGridSizing;\n}\n\nWidget wrapInMinimalApp(Widget child) {\n  return WidgetsApp(\n    color: Colors.white,\n    builder: (context, _) => child,\n  );\n}\n\n/// A widget whose [RenderObject] counts how many times it has been laid out.\nclass TestLayoutCountingWidget extends LeafRenderObjectWidget {\n  @override\n  RenderObject createRenderObject(BuildContext context) =>\n      RenderTestLayoutCountingWidget();\n}\n\nclass RenderTestLayoutCountingWidget extends RenderBox {\n  int layoutCount = 0;\n\n  void resetCount() => layoutCount = 0;\n\n  @override\n  void performLayout() {\n    layoutCount++;\n    size = constraints.biggest;\n  }\n}\n"
  },
  {
    "path": "test/track_size_test.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:flutter_layout_grid/flutter_layout_grid.dart';\nimport 'package:flutter_test/flutter_test.dart';\n\nimport 'test_helpers.dart';\n\nvoid main() {\n  group('fixed track sizes', () {\n    test('are correctly sized', () {\n      final gridSize = sizeEmptyGrid(\n        columnSizes: [fixed(40), fixed(80)],\n        rowSizes: [fixed(20), fixed(30)],\n      );\n\n      expect(\n        gridSize.baseSizesForType(TrackType.column),\n        [40, 80],\n      );\n      expect(\n        gridSize.baseSizesForType(TrackType.row),\n        [20, 30],\n      );\n    });\n\n    test('do not expand to fill remaining space', () {\n      final gridSize = sizeEmptyGrid(\n        gridFit: GridFit.expand,\n        columnSizes: [fixed(40), fixed(80)],\n        rowSizes: [fixed(20), fixed(30)],\n      );\n\n      expect(\n        gridSize.baseSizesForType(TrackType.column),\n        [40, 80],\n      );\n      expect(\n        gridSize.baseSizesForType(TrackType.row),\n        [20, 30],\n      );\n    });\n  });\n\n  group('flexible track sizes', () {\n    test('fill remaining space', () {\n      final gridSize = sizeEmptyGrid(\n        columnSizes: [fixed(100), flex(1)],\n        rowSizes: [fixed(100), flex(1)],\n      );\n\n      expect(\n        gridSize.baseSizesForType(TrackType.column),\n        [100, 700],\n      );\n      expect(\n        gridSize.baseSizesForType(TrackType.row),\n        [100, 500],\n      );\n    });\n\n    test('share space according to their factor (same factor)', () {\n      final gridSize = sizeEmptyGrid(\n        columnSizes: [fixed(100), flex(1), flex(1)],\n        rowSizes: [fixed(100), flex(1), flex(1)],\n      );\n\n      expect(\n        gridSize.baseSizesForType(TrackType.column),\n        [100, 350, 350],\n      );\n      expect(\n        gridSize.baseSizesForType(TrackType.row),\n        [100, 250, 250],\n      );\n    });\n\n    test('share space according to their factor (varying factors)', () {\n      final gridSize = sizeEmptyGrid(\n        columnSizes: [fixed(100), flex(1), flex(3)],\n        rowSizes: [fixed(100), flex(7), flex(1)],\n      );\n\n      expect(\n        gridSize.baseSizesForType(TrackType.column),\n        [100, 700 / 4, 3 * 700 / 4],\n      );\n      expect(\n        gridSize.baseSizesForType(TrackType.row),\n        [100, 7 * 500 / 8, 500 / 8],\n      );\n    });\n\n    test('occupy no space if none available', () {\n      final gridSize = sizeEmptyGrid(\n        columnSizes: [fixed(800), flex(1)],\n        rowSizes: [fixed(100)],\n        constraints: testConstraints,\n      );\n\n      expect(\n        gridSize.baseSizesForType(TrackType.column),\n        [800, 0],\n      );\n      expect(\n        gridSize.baseSizesForType(TrackType.row),\n        [100],\n      );\n    });\n  });\n\n  group('intrinsic track sizes', () {\n    test('stretch to fill the constraint\\'s remaining space', () {\n      final gridSize = sizeEmptyGrid(\n        gridFit: GridFit.expand,\n        columnSizes: [fixed(100), intrinsic(), fixed(100)],\n        rowSizes: [fixed(100), intrinsic(), fixed(100)],\n      );\n\n      expect(\n        gridSize.baseSizesForType(TrackType.column),\n        [100, 600, 100],\n      );\n      expect(\n        gridSize.baseSizesForType(TrackType.row),\n        [100, 400, 100],\n      );\n    });\n\n    test('share while stretching to fill remaining space', () {\n      final gridSize = sizeEmptyGrid(\n        gridFit: GridFit.expand,\n        columnSizes: [intrinsic(), intrinsic(), intrinsic(), intrinsic()],\n        rowSizes: [intrinsic(), intrinsic(), intrinsic(), intrinsic()],\n      );\n\n      expect(\n        gridSize.baseSizesForType(TrackType.column),\n        [200, 200, 200, 200],\n      );\n      expect(\n        gridSize.baseSizesForType(TrackType.row),\n        [150, 150, 150, 150],\n      );\n    });\n\n    test('do not stretch if a flexible track is involved', () {\n      final gridSize = sizeEmptyGrid(\n        columnSizes: [flex(1), intrinsic()],\n        rowSizes: [flex(1), intrinsic()],\n      );\n\n      expect(\n        gridSize.baseSizesForType(TrackType.column),\n        [800, 0],\n      );\n      expect(\n        gridSize.baseSizesForType(TrackType.row),\n        [600, 0],\n      );\n    });\n\n    testWidgets('sizes to content minimums, then shares what\\'s left',\n        (tester) async {\n      final gridSize = await sizeGridWithChildren(\n        tester,\n        gridFit: GridFit.expand,\n        columnSizes: [intrinsic(), intrinsic()],\n        rowSizes: [intrinsic(), intrinsic()],\n        children: [\n          constrainedBox(100, 400)\n              .withGridPlacement(columnStart: 0, rowStart: 0),\n          constrainedBox(200, 100)\n              .withGridPlacement(columnStart: 1, rowStart: 1),\n        ],\n      );\n\n      expect(\n        gridSize.baseSizesForType(TrackType.column),\n        [100 + 250, 200 + 250],\n      );\n      expect(\n        gridSize.baseSizesForType(TrackType.row),\n        [400 + 50, 100 + 50],\n      );\n    });\n  });\n}\n\nConstrainedBox constrainedBox(\n  double minW,\n  double minH, [\n  double? maxW,\n  double? maxH,\n]) {\n  maxW ??= minW;\n  maxH ??= minH;\n  return ConstrainedBox(\n    constraints: BoxConstraints(\n      minWidth: minW,\n      maxWidth: maxW,\n      minHeight: minH,\n      maxHeight: maxH,\n    ),\n  );\n}\n"
  },
  {
    "path": "tool/ci_test.sh",
    "content": "#!/bin/bash\n\nset -o errexit\nset -o nounset\nset -o xtrace\n\nflutter packages get\nflutter analyze\nflutter test --coverage --coverage-path coverage/lcov.info\n\n# Upload coverage results to codecov.io\n# bash <(curl -s https://codecov.io/bash) -c -F $PACKAGE\n"
  }
]