[
  {
    "path": ".github/FUNDING.yml",
    "content": "github: [thlorenz]\n"
  },
  {
    "path": ".gitignore",
    "content": ".DS_Store\n.idea/\n.metadata\n\n## Flutter ###\n# Flutter/Dart/Pub related\n**/doc/api/\n.dart_tool/\n.flutter-plugins\n.flutter-plugins-dependencies\n.fvm/\n.packages\n.pub-cache/\n.pub/\nbuild/\ncoverage/\nlib/generated_plugin_registrant.dart\n# For library packages, don’t commit the pubspec.lock file.\n# Regenerating the pubspec.lock file lets you test your package against the latest compatible versions of its dependencies.\n# See https://dart.dev/guides/libraries/private-files#pubspeclock\n#pubspec.lock\n\n# Android related\n**/android/**/gradle-wrapper.jar\n**/android/.gradle\n**/android/captures/\n**/android/gradlew\n**/android/gradlew.bat\n**/android/key.properties\n**/android/local.properties\n**/android/**/GeneratedPluginRegistrant.java\n\n# Linux related\n**/linux/**/*.so\n**/linux/**/*.a\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/.last_build_id\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# 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\n### Rust ###\n**/target/**\n**/Cargo.lock\n"
  },
  {
    "path": "README.md",
    "content": "# rid-examples\n\nExamples showing how to use [**Rid**](https://thlorenz.com/rid-site/) in order to build Dart/Flutter apps integrated with Rust.\n\n## What is Rid?\n\n_Rid_ stands for _Rust integrates Dart_ and is a tool I am working on that allows to call Rust\nfunctions from Dart and Flutter applications by simply annotating them.\nIts main goal is to **make it super easy to implement your UI in Flutter and the logic in\nRust**.\n\nThis in turn allows you to benefit from the respective strength of each platform.\n\nLearn more by following the [Getting\nStarted](https://thlorenz.com/rid-site/docs/getting-started/introduction/) guide.\n\n## How does Rid work?\n\n_Rid_ consumes the annotations added to your Rust code to generate all the\n[FFI](https://doc.rust-lang.org/nomicon/ffi.html) boilerplate to interact with them from Dart\n/Flutter.\n\nAdditionally it generates extension methods on entities, such as _models_ in order to expose an\nAPI on the Dart/Flutter end that is super fun to work with.\n\nLearn more _rids_ [application\narchitecture](https://thlorenz.com/rid-site/docs/getting-started/architecture/).\n\n## Examples\n\n### Flutter\n\n- [Todo App](./flutter/todo)\n\n### Dart Only\n\n- [Command Line Todo App](./dart/todo)\n\n## Is Rid open sourced?\n\n_Rid_ is _[Sponsorware](https://github.com/sponsorware/docs)_ and thus not open sourced yet. \n\nPlease [learn more here](https://thlorenz.com/rid-site/docs/contributing/sponsor/) about how\nyou can [sponsor rid via a monthly contribution](https://github.com/sponsors/thlorenz) and when\n_rid_ will be fully open sourced.\n\n## LICENSE\n\nMIT\n"
  },
  {
    "path": "dart/todo/.gitignore",
    "content": "**/generated/\n"
  },
  {
    "path": "dart/todo/Cargo.toml",
    "content": "[package]\nname = \"rid_dart_todo\"\nversion = \"0.1.0\"\nauthors = [\"Thorsten Lorenz <thlorenz@gmx.de>\"]\nedition = \"2018\"\n\n[lib]\nname = \"rid_dart_todo\"\ncrate-type = [\"cdylib\"]\npath = \"src/app.rs\"\ndoctest = false\ntest = false\n\n[[bin]]\nname = \"rid_build\"\npath = \"rid_build.rs\"\n\n# Note that until rid is open sourced and published to crates.io the examples\n# assume it to reside in a relative folder\n[dependencies]\nrid = { path = \"../../../rid\" }\nrid_build = { path = \"../../../rid/rid-build\" }\n\n[build-dependencies]\nrid_build = { path = \"../../../rid/rid-build\" }\n"
  },
  {
    "path": "dart/todo/README.md",
    "content": "# Rid Todo Example\n\nAn example todo app with user interaction implemented in Dart and app logic in Rust.\n\n## Getting Started\n\n_Please see [Caveats](#Caveats) first_.\n\n```sh\n./sh/build\n./sh/run\n```\n\nRepeat the first step every time you modify Rust code.\n\n## Rid Model \n\nWhat the Model annotations communicate to _rid_:\n\n```rust\n#[rid::model]                 // this is a model and all its fields should be accessible from Dart\n#[rid::structs(Todo)]         // the referenced Todo type is a struct\n#[rid::enums(Filter)]         // the referenced Filter type is an enum\n#[derive(Debug)]              // expose a `model.debug(pretty?)` function to Dart \npub struct Model {\n    last_added_id: u32,\n    todos: Vec<Todo>,\n    filter: Filter,\n}\n```\n\nPossible Model use in Dart code:\n\n```dart\nfinal filter = model.filter;\nfor (final todo in model.todos.iter()) {\n  // do something\n}\n```\n\n## Rid Message\n\nHow to setup sending messages to the _Model_ via _rid_:\n\n```rust\n#[rid::message(Model)]    // this is a message that will update the model\n#[rid::enums(Filter)]     // the referenced Filter type is an enum\npub enum Msg {\n    AddTodo(String),      // sent via Dart: model.msgAddTodo(\"Learn Rid\");\n\n    ToggleTodo(u32),      // sent via Dart: model.msgToggleTodo(todoId);\n    CompleteAll,          // sent via Dart: model.msgCompleteAll();\n\n    SetFilter(Filter),    // sent via Dart: model.msgSetFilter(RidFilter.index);\n}\n\nimpl Model {\n    fn update(&mut self, msg: Msg) {\n      // handle the message here\n    }\n}\n```\n\n## Exporting Methods\n\n```rust\n#[rid::export]                      // rid will scan this impl block for exports\nimpl Model {\n    #[rid::export(initModel)]       // exports this method to be called via Dart: rid_ffi.initModel(); \n    fn new() -> Self {\n        Self {\n            last_added_id: 0,\n            todos: vec![],\n            filter: Filter::All,\n        }\n    }\n}\n```\n\n## Caveats\n\nAt this point _Rid_ hasn't been published, therefore the build step cannot be performed and\nthis example only serves to demonstrate what is possible once it _is_ published and open\nsourced.\n\nFor more information please see [_Is Rid Open Sourced?_](../../README.md#is-rid-open-sourced)\n"
  },
  {
    "path": "dart/todo/lib/main.dart",
    "content": "import 'generated/rid_api.dart';\nimport 'dart:io';\n\nprintStatus(Store store) {\n  final todos = store.todos;\n  final total = todos.length;\n\n  final filter = store.filter;\n\n  print(\"Total Todos:     $total\");\n  print(\"Filter:          ${filter.display()}\");\n  print(\"\\nMatching Todos:\");\n\n  // NOTE: using raw API here to access `display`.\n  // To do that properly we lock the store while we're iterating.\n  store.raw.runLocked((rawStore) {\n    final matchingTodos = rawStore.filtered_todos();\n    for (final todo in matchingTodos.iter()) {\n      print(\"    ${todo.display()}\");\n    }\n    matchingTodos.dispose();\n  });\n}\n\nFuture<bool> handleCommand(Store store, String line) async {\n  String cmd;\n  String payload;\n\n  if (line.length > 2) {\n    cmd = line.substring(0, 3);\n    payload = line.substring(3).trim();\n  } else {\n    cmd = line.substring(0, 2);\n    payload = \"\";\n  }\n\n  switch (cmd) {\n    case \"add\":\n      await store.msgAddTodo(payload);\n      break;\n    case \"del\":\n      await store.msgRemoveTodo(int.parse(payload));\n      break;\n    case \"cmp\":\n      await store.msgCompleteTodo(int.parse(payload));\n      break;\n    case \"tog\":\n      await store.msgToggleTodo(int.parse(payload));\n      break;\n    case \"rst\":\n      store.msgRestartTodo(int.parse(payload));\n      break;\n    case \"fil\":\n      final filter = payload == \"cmp\"\n          ? Filter.Completed\n          : payload == \"pen\"\n              ? Filter.Pending\n              : Filter.All;\n      await store.msgSetFilter(filter);\n      break;\n    case \"ca\":\n      await store.msgCompleteAll();\n      break;\n    case \"dc\":\n      await store.msgRemoveCompleted();\n      break;\n    case \"ra\":\n      await store.msgRestartAll();\n      break;\n\n    default:\n      print(\"\\nUnknown command '$cmd'\\n\");\n      return false;\n  }\n  return true;\n}\n\nprintCommands() {\n  print(\"\\nPlease select one of the below:\\n\");\n  print(\"  add <todo title>  -- to add a todo\");\n  print(\"  del <todo id>     -- to delete a todo by id\");\n  print(\"  cmp <todo id>     -- to complete a todo by id\");\n  print(\"  rst <todo id>     -- to restart a todo by id\");\n  print(\"  tog <todo id>     -- to toggle a todo by id\");\n  print(\"  fil all|cmp|pen   -- to set filter to\");\n  print(\"  ca                -- to completed all todos\");\n  print(\"  dc                -- to delete completed todos\");\n  print(\"  ra                -- to restart all todos\");\n  print(\"  q                 -- to quit\");\n}\n\nvoid main(List<String> args) async {\n  final store = Store.instance;\n  {\n    await store.msgAddTodo(\"Complete this Todo via:     cmp 1\");\n    await store.msgAddTodo(\"Delete this Todo via:       del 2\");\n    await store.msgAddTodo(\"Toggle this Todo via:       tog 3\");\n    await store.msgAddTodo(\"Restart the first Todo via: rst 1\");\n\n    String? input;\n    bool ok = true;\n\n    while (true) {\n      if (ok) {\n        print(\"\\x1B[2J\\x1B[0;0H\");\n      }\n\n      printStatus(store);\n\n      printCommands();\n      stdout.write(\"\\n> \");\n      input = stdin.readLineSync();\n      if (input == \"q\") {\n        break;\n      }\n      if (input != null && input.length > 1) {\n        ok = await handleCommand(store, input.trim());\n      }\n    }\n  }\n  store.dispose();\n}\n"
  },
  {
    "path": "dart/todo/pubspec.yaml",
    "content": "name: rid_dart_todo \nversion: 0.0.0\nenvironment:\n  sdk: '>=2.13.0 <=3.0.0'\n\ndependencies: \n  ffi: ^1.0.0\n  ffigen: 4.0.0-dev.2\n"
  },
  {
    "path": "dart/todo/rid_build.rs",
    "content": "use rid_build::{build, BuildConfig, BuildTarget, Project};\nuse std::env;\n\nfn main() {\n    let crate_dir = env::var(\"CARGO_MANIFEST_DIR\")\n        .expect(\"Missing CARGO_MANIFEST_DIR, please run this via 'cargo run'\");\n\n    let crate_name = &env::var(\"CARGO_PKG_NAME\")\n        .expect(\"Missing CARGO_PKG_NAME, please run this via 'cargo run'\");\n\n    let lib_name = &format!(\"lib{}\", &crate_name);\n\n    let build_config = BuildConfig {\n        target: BuildTarget::Debug,\n        project: Project::Dart,\n        lib_name,\n        crate_name,\n        project_root: &crate_dir,\n        workspace_root: Some(&crate_dir),\n    };\n    let build_result = build(&build_config).expect(\"Build failed\");\n\n    eprintln!(\"{}\", build_result);\n}\n"
  },
  {
    "path": "dart/todo/sh/build",
    "content": "#!/usr/bin/env bash\n\nDIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" >/dev/null 2>&1 && pwd )\"\n\n(cd $DIR/.. && cargo run rid_build)\n"
  },
  {
    "path": "dart/todo/sh/run",
    "content": "#!/usr/bin/env bash\n\ndart                          \\\n  --enable-asserts            \\\n  --packages=.packages        \\\n  package:rid_dart_todo/main.dart \n"
  },
  {
    "path": "dart/todo/src/app.rs",
    "content": "#![allow(dead_code)]\n\nuse rid::RidStore;\nuse std::fmt::Display;\n\n// -----------------\n// Store\n// -----------------\n#[rid::store]\n#[rid::structs(Todo)]\n#[rid::enums(Filter)]\n#[derive(Debug)]\npub struct Store {\n    last_added_id: u32,\n    todos: Vec<Todo>,\n    filter: Filter,\n}\n\nimpl RidStore<Msg> for Store {\n    fn create() -> Self {\n        Self {\n            last_added_id: 0,\n            todos: vec![],\n            filter: Filter::All,\n        }\n    }\n\n    fn update(&mut self, req_id: u64, msg: Msg) {\n        use Msg::*;\n        match msg {\n            AddTodo(title) => {\n                self.last_added_id += 1;\n                let todo = Todo {\n                    id: self.last_added_id,\n                    title,\n                    completed: false,\n                };\n                self.todos.push(todo);\n                rid::post(Reply::AddedTodo(req_id, self.last_added_id.to_string()));\n            }\n            RemoveTodo(id) => {\n                let mut enumerated = self.todos.iter().enumerate();\n                let idx = match enumerated.find(|(_, todo)| todo.id == id) {\n                    Some((idx, _)) => idx,\n                    None => return eprintln!(\"Could not find Todo with id '{}'\", id),\n                };\n                self.todos.remove(idx);\n                rid::post(Reply::RemovedTodo(req_id, self.last_added_id.to_string()));\n            }\n\n            RemoveCompleted => {\n                self.todos.retain(|todo| !todo.completed);\n                rid::post(Reply::RemovedCompleted(req_id));\n            }\n\n            CompleteTodo(id) => {\n                self.update_todo(id, |todo| todo.completed = true);\n                rid::post(Reply::CompletedTodo(req_id, id.to_string()));\n            }\n            RestartTodo(id) => {\n                self.update_todo(id, |todo| todo.completed = false);\n                rid::post(Reply::RestartedTodo(req_id, id.to_string()));\n            }\n            ToggleTodo(id) => {\n                self.update_todo(id, |todo| todo.completed = !todo.completed);\n                rid::post(Reply::ToggledTodo(req_id, id.to_string()));\n            }\n\n            CompleteAll => {\n                self.todos.iter_mut().for_each(|x| x.completed = true);\n                rid::post(Reply::CompletedAll(req_id));\n            }\n            RestartAll => {\n                self.todos.iter_mut().for_each(|x| x.completed = false);\n                rid::post(Reply::RestartedAll(req_id));\n            }\n\n            SetFilter(filter) => {\n                self.filter = filter;\n                rid::post(Reply::SetFilter(req_id));\n            }\n        };\n    }\n}\n\n#[rid::export]\nimpl Store {\n    fn update_todo<F: FnOnce(&mut Todo)>(&mut self, id: u32, update: F) {\n        match self.todos.iter_mut().find(|x| x.id == id) {\n            Some(todo) => update(todo),\n            None => eprintln!(\"Could not find Todo with id '{}'\", id),\n        };\n    }\n\n    #[rid::export]\n    #[rid::structs(Todo)]\n    fn filtered_todos(&self) -> Vec<&Todo> {\n        let mut vec: Vec<&Todo> = match self.filter {\n            Filter::Completed => self.todos.iter().filter(|x| x.completed).collect(),\n            Filter::Pending => self.todos.iter().filter(|x| !x.completed).collect(),\n            Filter::All => self.todos.iter().collect(),\n        };\n        vec.sort();\n        vec\n    }\n}\n\n// -----------------\n// Todo Model\n// -----------------\n#[rid::model]\n#[derive(Debug, PartialEq, Eq, PartialOrd, rid::Display)]\npub struct Todo {\n    id: u32,\n    title: String,\n    completed: bool,\n}\n\nimpl Ord for Todo {\n    fn cmp(&self, other: &Self) -> std::cmp::Ordering {\n        self.id.cmp(&other.id)\n    }\n}\n\nimpl Display for Todo {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        let status = if self.completed { \"✓\" } else { \" \" };\n        write!(f, \"[{}] ({}) '{}'\", status, self.id, self.title)\n    }\n}\n\n// -----------------\n// Filter\n// -----------------\n#[rid::model]\n#[derive(Clone, Debug, rid::Display)]\npub enum Filter {\n    Completed,\n    Pending,\n    All,\n}\n\nimpl Display for Filter {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        match self {\n            Filter::Completed => write!(f, \"Completed\"),\n            Filter::Pending => write!(f, \"Pending\"),\n            Filter::All => write!(f, \"All\"),\n        }\n    }\n}\n\n// -----------------\n// Msg\n// -----------------\n#[rid::message(Reply)]\n#[rid::enums(Filter)]\n#[derive(Debug)]\npub enum Msg {\n    AddTodo(String),\n    RemoveTodo(u32),\n    RemoveCompleted,\n\n    CompleteTodo(u32),\n    RestartTodo(u32),\n    ToggleTodo(u32),\n    CompleteAll,\n    RestartAll,\n\n    SetFilter(Filter),\n}\n\n// -----------------\n// Reply\n// -----------------\n#[rid::reply]\npub enum Reply {\n    AddedTodo(u64, String),\n    RemovedTodo(u64, String),\n    RemovedCompleted(u64),\n\n    CompletedTodo(u64, String),\n    RestartedTodo(u64, String),\n    ToggledTodo(u64, String),\n    CompletedAll(u64),\n    RestartedAll(u64),\n\n    SetFilter(u64),\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/.gitignore",
    "content": ".DS_Store\n.idea/\n.metadata\n\n## Flutter ###\n# Flutter/Dart/Pub related\n**/doc/api/\n.dart_tool/\n.flutter-plugins\n.flutter-plugins-dependencies\n.fvm/\n.packages\n.pub-cache/\n.pub/\nbuild/\ncoverage/\nlib/generated_plugin_registrant.dart\n# For library packages, don’t commit the pubspec.lock file.\n# Regenerating the pubspec.lock file lets you test your package against the latest compatible versions of its dependencies.\n# See https://dart.dev/guides/libraries/private-files#pubspeclock\n#pubspec.lock\n\n# Android related\n**/android/**/gradle-wrapper.jar\n**/android/.gradle\n**/android/captures/\n**/android/gradlew\n**/android/gradlew.bat\n**/android/key.properties\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/.last_build_id\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# 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\n### Rust ###\n**/target/**\n**/Cargo.lock\n\n### Rid ###\n**/generated/**\n**/Classes/bindings.h\n**/macos/*.a\n**/ios/*.a\n**/android/src/main/jniLibs/*\n"
  },
  {
    "path": "flutter/reddit_ticker/Cargo.toml",
    "content": "[package]\nname = \"reddit_ticker\"\nversion = \"0.1.0\"\nauthors = [\"Thorsten Lorenz <thlorenz@gmx.de>\"]\nedition = \"2018\"\n\n[lib]\ncrate-type = [\"cdylib\", \"staticlib\" ]\n\n[[bin]]\nname = \"rid_build\"\npath = \"rid_build.rs\"\n\n[dependencies]\ncbindgen = \"0.20.0\"\nrid_build = { path = \"../../../rid/rid-build\" }\nrid = { path = \"../../../rid\" }\nserde = { version =  \"1.0.123\", features = [ \"derive\" ] }\nserde_json = \"1.0.64\"\nureq = { version = \"2.0.2\", features = [ \"json\" ] }\nanyhow = \"1.0.38\"\nrusqlite = { version = \"0.24.2\", features = [ \"bundled\" ] }\n"
  },
  {
    "path": "flutter/reddit_ticker/README.md",
    "content": "# reddit_ticker\n\nRust integrated Dart Flutter Project\n\n## Getting Started\n\nUse the below scripts to get the app ready to run with Flutter.\n\n### 1. Generate Glue Code\n\n```sh\n./sh/bindgen\n```\n\n### 2. Build For Desired Target/Device\n\nRun any of the below three to build the binary for the specific device and have it placed into\nthe devices specific plugin folder.\n\n```sh\n./sh/macos\n```\n\n### 3. Run with Flutter\n\nRun on the device.\n\n```sh\nflutter run -d macos\n```\n\n### 4. Develop\n\nRun step `1` whenever a function exposed to Flutter changes.\n\nRun step `2` whenever any of your Rust code changes.\n\n**Note** that to apply changes from Rust you need to restart the app to reload the compiled binary.\nA hot restart/reload does not achieve this.\n\n## Folder Structure\n\n```\n├── android\n├── ios\n├── macos\n├── lib\n├── plugin\n│   ├── android\n│   ├── ios\n│   ├── macos\n│   └── lib\n└── src\n```\n\n### `./plugin`\n\nProvides connection from Flutter to Rust.\n\nRust binaries are placed into the respective plugin folders `./ios, ./macos, ./android` when\nthey are built.\n\nGenerated Dart glue code is placed inside `./plugin/lib/generated` while\n`./plugin/lib/plugin.dart` just exposes the API to the app.\n\n### `./src`\n\nContains the starter Rust code inside `./src/lib.rs`. Keep developing the Rust part of your app\nhere.\n\n### `./lib`\n\nContains the starter Flutter app inside `./lib/main.dart`.\n\n### `./sh`\n\nProvides scripts to run build and code generation tasks. In the future a tool will provide the\nfunctionality currently provided by these scripts.\n\n- `bindgen` generates the `binding.h` header file for the extern Rust functions found inside\n  `./src`. These are then placed inside the `./plugin` device folders were needed as well as\n  `./plugin/lib/generated/binding.h` where they are used to generate Dart glue code\n  - as part of this script `ffigen` generates Dart glue code inside\n    `./plugin/lib/generated/ffigen_binding.dart` using `./plugin/lib/generated/binding.h` as input\n- `./android` builds the Rust binary to run on Android devices/emulators and places it inside\n  `./plugin/lib/android`\n- `./ios` builds the Rust binary to run on IOS devices/emulators and places it inside\n  `./plugin/lib/ios`\n- `./macos` builds the Rust binary to run on MacOs directly and places it inside\n  `./plugin/lib/macos`, this is the same format as running `cargo build` on your Mac\n- `clean` cleans both the Flutter plugin and application, run this to reset Flutter when things\n  aren't working\n"
  },
  {
    "path": "flutter/reddit_ticker/analysis_options.yaml",
    "content": "# This file configures the analyzer, which statically analyzes Dart code to\n# check for errors, warnings, and lints.\n#\n# The issues identified by the analyzer are surfaced in the UI of Dart-enabled\n# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be\n# invoked from the command line by running `flutter analyze`.\n\n# The following line activates a set of recommended lints for Flutter apps,\n# packages, and plugins designed to encourage good coding practices.\ninclude: package:flutter_lints/flutter.yaml\n\nlinter:\n  # The lint rules applied to this project can be customized in the\n  # section below to disable rules from the `package:flutter_lints/flutter.yaml`\n  # included above or to enable additional rules. A list of all available lints\n  # and their documentation is published at\n  # https://dart-lang.github.io/linter/lints/index.html.\n  #\n  # Instead of disabling a lint rule for the entire project in the\n  # section below, it can also be suppressed for a single line of code\n  # or a specific dart file by using the `// ignore: name_of_lint` and\n  # `// ignore_for_file: name_of_lint` syntax on the line or in the file\n  # producing the lint.\n  rules:\n    # avoid_print: false  # Uncomment to disable the `avoid_print` rule\n    # prefer_single_quotes: true  # Uncomment to enable the `prefer_single_quotes` rule\n\n# Additional information about this file can be found at\n# https://dart.dev/guides/language/analysis-options\n"
  },
  {
    "path": "flutter/reddit_ticker/android/.gitignore",
    "content": "gradle-wrapper.jar\n/.gradle\n/captures/\n/gradlew\n/gradlew.bat\n/local.properties\nGeneratedPluginRegistrant.java\n\n# Remember to never publicly share your keystore.\n# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app\nkey.properties\n**/*.keystore\n**/*.jks\n"
  },
  {
    "path": "flutter/reddit_ticker/android/app/build.gradle",
    "content": "def localProperties = new Properties()\ndef localPropertiesFile = rootProject.file('local.properties')\nif (localPropertiesFile.exists()) {\n    localPropertiesFile.withReader('UTF-8') { reader ->\n        localProperties.load(reader)\n    }\n}\n\ndef flutterRoot = localProperties.getProperty('flutter.sdk')\nif (flutterRoot == null) {\n    throw new GradleException(\"Flutter SDK not found. Define location with flutter.sdk in the local.properties file.\")\n}\n\ndef flutterVersionCode = localProperties.getProperty('flutter.versionCode')\nif (flutterVersionCode == null) {\n    flutterVersionCode = '1'\n}\n\ndef flutterVersionName = localProperties.getProperty('flutter.versionName')\nif (flutterVersionName == null) {\n    flutterVersionName = '1.0'\n}\n\napply plugin: 'com.android.application'\napply plugin: 'kotlin-android'\napply from: \"$flutterRoot/packages/flutter_tools/gradle/flutter.gradle\"\n\nandroid {\n    compileSdkVersion 30\n\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n\n    kotlinOptions {\n        jvmTarget = '1.8'\n    }\n\n    sourceSets {\n        main.java.srcDirs += 'src/main/kotlin'\n    }\n\n    defaultConfig {\n        // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).\n        applicationId \"com.example.reddit_ticker\"\n        minSdkVersion 16\n        targetSdkVersion 30\n        versionCode flutterVersionCode.toInteger()\n        versionName flutterVersionName\n    }\n\n    buildTypes {\n        release {\n            // TODO: Add your own signing config for the release build.\n            // Signing with the debug keys for now, so `flutter run --release` works.\n            signingConfig signingConfigs.debug\n        }\n    }\n}\n\nflutter {\n    source '../..'\n}\n\ndependencies {\n    implementation \"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version\"\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/android/app/src/debug/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.example.reddit_ticker\">\n    <!-- Flutter needs it to communicate with the running application\n         to allow setting breakpoints, to provide hot reload, etc.\n    -->\n    <uses-permission android:name=\"android.permission.INTERNET\"/>\n</manifest>\n"
  },
  {
    "path": "flutter/reddit_ticker/android/app/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.example.reddit_ticker\">\n   <application\n        android:label=\"reddit_ticker\"\n        android:icon=\"@mipmap/ic_launcher\">\n        <activity\n            android:name=\".MainActivity\"\n            android:launchMode=\"singleTop\"\n            android:theme=\"@style/LaunchTheme\"\n            android:configChanges=\"orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode\"\n            android:hardwareAccelerated=\"true\"\n            android:windowSoftInputMode=\"adjustResize\">\n            <!-- Specifies an Android theme to apply to this Activity as soon as\n                 the Android process has started. This theme is visible to the user\n                 while the Flutter UI initializes. After that, this theme continues\n                 to determine the Window background behind the Flutter UI. -->\n            <meta-data\n              android:name=\"io.flutter.embedding.android.NormalTheme\"\n              android:resource=\"@style/NormalTheme\"\n              />\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\"/>\n                <category android:name=\"android.intent.category.LAUNCHER\"/>\n            </intent-filter>\n        </activity>\n        <!-- Don't delete the meta-data below.\n             This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->\n        <meta-data\n            android:name=\"flutterEmbedding\"\n            android:value=\"2\" />\n    </application>\n</manifest>\n"
  },
  {
    "path": "flutter/reddit_ticker/android/app/src/main/kotlin/com/example/reddit_ticker/MainActivity.kt",
    "content": "package com.example.reddit_ticker\n\nimport io.flutter.embedding.android.FlutterActivity\n\nclass MainActivity: FlutterActivity() {\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/android/app/src/main/res/drawable/launch_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- Modify this file to customize your launch splash screen -->\n<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:drawable=\"@android:color/white\" />\n\n    <!-- You can insert your own image assets here -->\n    <!-- <item>\n        <bitmap\n            android:gravity=\"center\"\n            android:src=\"@mipmap/launch_image\" />\n    </item> -->\n</layer-list>\n"
  },
  {
    "path": "flutter/reddit_ticker/android/app/src/main/res/drawable-v21/launch_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- Modify this file to customize your launch splash screen -->\n<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:drawable=\"?android:colorBackground\" />\n\n    <!-- You can insert your own image assets here -->\n    <!-- <item>\n        <bitmap\n            android:gravity=\"center\"\n            android:src=\"@mipmap/launch_image\" />\n    </item> -->\n</layer-list>\n"
  },
  {
    "path": "flutter/reddit_ticker/android/app/src/main/res/values/styles.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->\n    <style name=\"LaunchTheme\" parent=\"@android:style/Theme.Light.NoTitleBar\">\n        <!-- Show a splash screen on the activity. Automatically removed when\n             Flutter draws its first frame -->\n        <item name=\"android:windowBackground\">@drawable/launch_background</item>\n    </style>\n    <!-- Theme applied to the Android Window as soon as the process has started.\n         This theme determines the color of the Android Window while your\n         Flutter UI initializes, as well as behind your Flutter UI while its\n         running.\n         \n         This Theme is only used starting with V2 of Flutter's Android embedding. -->\n    <style name=\"NormalTheme\" parent=\"@android:style/Theme.Light.NoTitleBar\">\n        <item name=\"android:windowBackground\">?android:colorBackground</item>\n    </style>\n</resources>\n"
  },
  {
    "path": "flutter/reddit_ticker/android/app/src/main/res/values-night/styles.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->\n    <style name=\"LaunchTheme\" parent=\"@android:style/Theme.Black.NoTitleBar\">\n        <!-- Show a splash screen on the activity. Automatically removed when\n             Flutter draws its first frame -->\n        <item name=\"android:windowBackground\">@drawable/launch_background</item>\n    </style>\n    <!-- Theme applied to the Android Window as soon as the process has started.\n         This theme determines the color of the Android Window while your\n         Flutter UI initializes, as well as behind your Flutter UI while its\n         running.\n         \n         This Theme is only used starting with V2 of Flutter's Android embedding. -->\n    <style name=\"NormalTheme\" parent=\"@android:style/Theme.Black.NoTitleBar\">\n        <item name=\"android:windowBackground\">?android:colorBackground</item>\n    </style>\n</resources>\n"
  },
  {
    "path": "flutter/reddit_ticker/android/app/src/profile/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.example.reddit_ticker\">\n    <!-- Flutter needs it to communicate with the running application\n         to allow setting breakpoints, to provide hot reload, etc.\n    -->\n    <uses-permission android:name=\"android.permission.INTERNET\"/>\n</manifest>\n"
  },
  {
    "path": "flutter/reddit_ticker/android/build.gradle",
    "content": "buildscript {\n    ext.kotlin_version = '1.3.50'\n    repositories {\n        google()\n        mavenCentral()\n    }\n\n    dependencies {\n        classpath 'com.android.tools.build:gradle:4.1.0'\n        classpath \"org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version\"\n    }\n}\n\nallprojects {\n    repositories {\n        google()\n        mavenCentral()\n    }\n}\n\nrootProject.buildDir = '../build'\nsubprojects {\n    project.buildDir = \"${rootProject.buildDir}/${project.name}\"\n    project.evaluationDependsOn(':app')\n}\n\ntask clean(type: Delete) {\n    delete rootProject.buildDir\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/android/gradle/wrapper/gradle-wrapper.properties",
    "content": "#Fri Jun 23 08:50:38 CEST 2017\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-6.7-all.zip\n"
  },
  {
    "path": "flutter/reddit_ticker/android/gradle.properties",
    "content": "org.gradle.jvmargs=-Xmx1536M\nandroid.useAndroidX=true\nandroid.enableJetifier=true\n"
  },
  {
    "path": "flutter/reddit_ticker/android/reddit_ticker_android.iml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<module type=\"JAVA_MODULE\" version=\"4\">\n  <component name=\"FacetManager\">\n    <facet type=\"android\" name=\"Android\">\n      <configuration>\n        <option name=\"ALLOW_USER_CONFIGURATION\" value=\"false\" />\n        <option name=\"GEN_FOLDER_RELATIVE_PATH_APT\" value=\"/gen\" />\n        <option name=\"GEN_FOLDER_RELATIVE_PATH_AIDL\" value=\"/gen\" />\n        <option name=\"MANIFEST_FILE_RELATIVE_PATH\" value=\"/app/src/main/AndroidManifest.xml\" />\n        <option name=\"RES_FOLDER_RELATIVE_PATH\" value=\"/app/src/main/res\" />\n        <option name=\"ASSETS_FOLDER_RELATIVE_PATH\" value=\"/app/src/main/assets\" />\n        <option name=\"LIBS_FOLDER_RELATIVE_PATH\" value=\"/app/src/main/libs\" />\n        <option name=\"PROGUARD_LOGS_FOLDER_RELATIVE_PATH\" value=\"/app/src/main/proguard_logs\" />\n      </configuration>\n    </facet>\n  </component>\n  <component name=\"NewModuleRootManager\" inherit-compiler-output=\"true\">\n    <exclude-output />\n    <content url=\"file://$MODULE_DIR$\">\n      <sourceFolder url=\"file://$MODULE_DIR$/app/src/main/java\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/app/src/main/kotlin\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/gen\" isTestSource=\"false\" generated=\"true\" />\n    </content>\n    <orderEntry type=\"jdk\" jdkName=\"Android API 29 Platform\" jdkType=\"Android SDK\" />\n    <orderEntry type=\"sourceFolder\" forTests=\"false\" />\n    <orderEntry type=\"library\" name=\"Flutter for Android\" level=\"project\" />\n    <orderEntry type=\"library\" name=\"KotlinJavaRuntime\" level=\"project\" />\n  </component>\n</module>\n"
  },
  {
    "path": "flutter/reddit_ticker/android/settings.gradle",
    "content": "include ':app'\n\ndef localPropertiesFile = new File(rootProject.projectDir, \"local.properties\")\ndef properties = new Properties()\n\nassert localPropertiesFile.exists()\nlocalPropertiesFile.withReader(\"UTF-8\") { reader -> properties.load(reader) }\n\ndef flutterSdkPath = properties.getProperty(\"flutter.sdk\")\nassert flutterSdkPath != null, \"flutter.sdk not set in local.properties\"\napply from: \"$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle\"\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/.gitignore",
    "content": ".dart_tool/\n.packages\npubspec.lock\n\n.bundle\n_site\n\nbuild/\n**/ios/.generated/\n**/ios/Flutter/Generated.xcconfig\n**/ios/Runner/GeneratedPluginRegistrant.*\n\n**/doc/\n**/example/\n**/test/\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/.travis.yml",
    "content": "matrix:\n  include:\n    # Job 1) Run tests\n    - os: linux\n      env:\n        - SHARD=Tests\n      sudo: false\n      addons:\n        apt:\n          # Flutter depends on /usr/lib/x86_64-linux-gnu/libstdc++.so.6 version GLIBCXX_3.4.18\n          sources:\n            - ubuntu-toolchain-r-test # if we don't specify this, the libstdc++6 we get is the wrong version\n          packages:\n            - libstdc++6\n            - fonts-droid-fallback\n      before_script:\n        - git clone https://github.com/flutter/flutter.git\n        - export PATH=`pwd`/flutter/bin:`pwd`/flutter/bin/cache/dart-sdk/bin:$PATH\n        - flutter doctor\n      script:\n        - cd charts_common\n        # TODO  Enable travis to run charts common test after fixing timezone test bug.\n        #- pub get\n        #- pub run test\n        - cd ../charts_flutter\n        - flutter test\n\ncache:\n  directories:\n    - $HOME/.pub-cache\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/AUTHORS",
    "content": "# Below is a list of people and organizations that have contributed\n# to the Charts project. Names should be added to the list like so:\n#\n#   Name/Organization <email address>\n\nGoogle Inc.\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/CONTRIBUTING.md",
    "content": "This project is developed internally at Google and published for external\nconsumption, external contributions unfortunately cannot be taken at this time.\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/README.md",
    "content": "Charts is a general charting library, currently enabled for the\n[Flutter mobile UI framework](https://flutter.io).\n\nSee the [online gallery](https://google.github.io/charts/flutter/gallery.html) for supported chart\ntypes and examples of how to custom components of the chart.\n\n*Note*: This is not an official Google product.\n\n[![Travis CI Build Status](https://travis-ci.org/google/charts.svg?branch=master)](https://travis-ci.org/google/charts)\n\n## charts_common\n\n[![charts_common pub package](https://img.shields.io/pub/v/charts_common.svg)](https://pub.dartlang.org/packages/charts_common)\n\nA common library for charting packages.\n\n## charts_flutter\n\n[![charts_flutter pub package](https://img.shields.io/pub/v/charts_flutter.svg)](https://pub.dartlang.org/packages/charts_flutter)\n\nA charting package for [Flutter](https://flutter.io), supporting both Android\nand iOS.\n\nAll charts packages are licensed under the Apache 2 license, see the\n[LICENSE](LICENSE) and [AUTHORS](AUTHORS) files for details.\n\n## Development\nThis project is developed internally at Google and published for external\nconsumption, external contributions unfortunately cannot be taken at this time.\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/CHANGELOG.md",
    "content": "# 0.11.0\n* Null support\n* Update to latest from internal repo\n\n# 0.10.0\n* Internal bug fixes\n* Bump versions of intl due to pull request\n\n# 0.9.0\n* Internal bug fixes\n* Bump versions in Gemlock file due to security alerts\n\n# 0.8.1\n* Update intl version.\n\n# 0.8.0\n* Bug fixes from open source.\n\n# 0.7.0\n* Added vertical bar label\n\n# 0.6.0\n* Bars can now be rendered on line charts.\n* Negative measure values will now be rendered on bar charts as a separate stack from the positive\nvalues.\n* Added a Datum Legend, which displays one entry per value in the first series on the chart. This is\n useful for pie and scatter plot charts.\n* The AxisPosition enum in RTLSpec was refactored to AxisDirection to better reflect its effect on\nswapping the positions of all start and end components, and not just positioning the measure axes.\n* Added custom colors for line renderer area skirts and confidence intervals. A new \"areaColorFn\"\nhas been added to Series, and corresponding data to the datum. We could not use the fillColorFn for\nthese elements, because that color is already applied to the internal section of points on line\ncharts (including highlighter behaviors).\n\n# 0.5.0\n* SelectionModelConfig's listener parameter has been renamed to \"changeListener\". This is a breaking\nchange. Please rename any existing uses of the \"listener\" parameter to \"changeListener\". This was\nnamed in order to add an additional listener \"updateListener\" that listens to any update requests,\nregardless if the selection model has changed.\n* CartesianChart's method getMeasureAxis(String axisId) has been changed to\ngetMeasureAxis({String axisId) so that getting the primary measure axis will not need passing any id\nthat does not match the secondary measure axis id. This affects users implementing custom behaviors\nusing the existing method.\n\n# 0.4.0\n* Declare compatibility with Dart 2.\n* BasicNumericTickFormatterSpec now takes in a callback instead of NumberFormat as the default constructor. Use named constructor withNumberFormat instead. This is a breaking change.\n* BarRendererConfig is no longer default of type String, please change current usage to BarRendererConfig<String>. This is a breaking change.\n* BarTargetLineRendererConfig is no longer default of type String, please change current usage to BarTargetLineRendererConfig<String>. This is a breaking change.\n\n\n# 0.3.0\n* Simplified API by removing the requirement for specifying the datum type when creating a chart.\nFor example, previously to construct a bar chart the syntax was 'new BarChart<MyDatumType>()'.\nThe syntax is now cleaned up to be 'new BarChart()'. Please refer to the\n[online gallery](https://google.github.io/charts/flutter/gallery.html) for the correct syntax.\n* Added scatter plot charts\n* Added tap to hide for legends\n* Added support for rendering area skirts to line charts\n* Added support for configurable fill colors to bar charts\n\n# 0.2.0\n\n* Update color palette. Please use MaterialPalette instead of QuantumPalette.\n* Dart2 fixes\n\n# 0.1.0\n\nInitial release.\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/README.md",
    "content": "# Common Charting library\n\n[![pub package](https://img.shields.io/pub/v/charts_common.svg)](https://pub.dartlang.org/packages/charts_common)\n\nCommon componnets for charting libraries.\n\n## Development\nThis project is developed internally at Google and published for external\nconsumption, external contributions unfortunately cannot be taken at this time.\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/charts_common.gwsq",
    "content": "send_cls_to('dart-charts-team+reviews');\nsend_cls_to('dart-charts-team');\n\ndefine Main {\n  reassign_to_list(from_owners_file('third_party/dart/charts_common/OWNERS'));\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/common.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nexport 'src/chart/bar/bar_chart.dart' show BarChart;\nexport 'src/chart/bar/bar_error_decorator.dart' show BarErrorDecorator;\nexport 'src/chart/bar/bar_label_decorator.dart'\n    show BarLabelAnchor, BarLabelDecorator, BarLabelPlacement, BarLabelPosition;\nexport 'src/chart/bar/bar_lane_renderer_config.dart' show BarLaneRendererConfig;\nexport 'src/chart/bar/bar_renderer.dart'\n    show BarRenderer, BarRendererElement, ImmutableBarRendererElement;\nexport 'src/chart/bar/bar_renderer_config.dart'\n    show\n        BarRendererConfig,\n        CornerStrategy,\n        ConstCornerStrategy,\n        NoCornerStrategy;\nexport 'src/chart/bar/bar_renderer_decorator.dart' show BarRendererDecorator;\nexport 'src/chart/bar/bar_target_line_renderer.dart' show BarTargetLineRenderer;\nexport 'src/chart/bar/bar_target_line_renderer_config.dart'\n    show BarTargetLineRendererConfig;\nexport 'src/chart/bar/base_bar_renderer.dart'\n    show barGroupIndexKey, barGroupCountKey, barGroupWeightKey;\nexport 'src/chart/bar/base_bar_renderer_config.dart'\n    show BarGroupingType, BaseBarRendererConfig;\nexport 'src/chart/cartesian/axis/axis.dart'\n    show\n        domainAxisKey,\n        measureAxisIdKey,\n        measureAxisKey,\n        Axis,\n        ImmutableAxis,\n        AxisOrientation,\n        NumericAxis,\n        OrdinalAxis,\n        OrdinalViewport;\nexport 'src/chart/cartesian/axis/draw_strategy/base_tick_draw_strategy.dart'\n    show BaseRenderSpec, BaseTickDrawStrategy;\nexport 'src/chart/cartesian/axis/draw_strategy/gridline_draw_strategy.dart'\n    show GridlineRendererSpec;\nexport 'src/chart/cartesian/axis/draw_strategy/none_draw_strategy.dart'\n    show NoneRenderSpec;\nexport 'src/chart/cartesian/axis/draw_strategy/range_tick_draw_strategy.dart'\n    show RangeTickRendererSpec;\nexport 'src/chart/cartesian/axis/draw_strategy/small_tick_draw_strategy.dart'\n    show SmallTickRendererSpec;\nexport 'src/chart/cartesian/axis/draw_strategy/tick_draw_strategy.dart'\n    show TickDrawStrategy;\nexport 'src/chart/cartesian/axis/numeric_extents.dart' show NumericExtents;\nexport 'src/chart/cartesian/axis/spec/axis_spec.dart'\n    show\n        AxisSpec,\n        LineStyleSpec,\n        RenderSpec,\n        TextStyleSpec,\n        TickLabelAnchor,\n        TickLabelJustification,\n        TickFormatterSpec,\n        TickProviderSpec;\nexport 'src/chart/cartesian/axis/spec/bucketing_axis_spec.dart'\n    show BucketingAxisSpec, BucketingNumericTickProviderSpec;\nexport 'src/chart/cartesian/axis/spec/date_time_axis_spec.dart'\n    show\n        DateTimeAxisSpec,\n        DayTickProviderSpec,\n        AutoDateTimeTickFormatterSpec,\n        AutoDateTimeTickProviderSpec,\n        DateTimeEndPointsTickProviderSpec,\n        DateTimeTickFormatterSpec,\n        DateTimeTickProviderSpec,\n        BasicDateTimeTickFormatterSpec,\n        TimeFormatterSpec,\n        StaticDateTimeTickProviderSpec;\nexport 'src/chart/cartesian/axis/spec/end_points_time_axis_spec.dart'\n    show EndPointsTimeAxisSpec;\nexport 'src/chart/cartesian/axis/spec/numeric_axis_spec.dart'\n    show\n        NumericAxisSpec,\n        NumericEndPointsTickProviderSpec,\n        NumericTickProviderSpec,\n        NumericTickFormatterSpec,\n        BasicNumericTickFormatterSpec,\n        BasicNumericTickProviderSpec,\n        StaticNumericTickProviderSpec;\nexport 'src/chart/cartesian/axis/spec/ordinal_axis_spec.dart'\n    show\n        BasicOrdinalTickProviderSpec,\n        BasicOrdinalTickFormatterSpec,\n        FixedPixelOrdinalScaleSpec,\n        FixedPixelSpaceOrdinalScaleSpec,\n        OrdinalAxisSpec,\n        OrdinalTickFormatterSpec,\n        OrdinalTickProviderSpec,\n        OrdinalScaleSpec,\n        RangeOrdinalTickProviderSpec,\n        SimpleOrdinalScaleSpec,\n        StaticOrdinalTickProviderSpec;\nexport 'src/chart/cartesian/axis/spec/percent_axis_spec.dart'\n    show PercentAxisSpec;\nexport 'src/chart/cartesian/axis/spec/range_tick_spec.dart' show RangeTickSpec;\nexport 'src/chart/cartesian/axis/spec/tick_spec.dart' show TickSpec;\nexport 'src/chart/cartesian/axis/tick.dart' show Tick;\nexport 'src/chart/cartesian/axis/tick_formatter.dart'\n    show SimpleTickFormatterBase, TickFormatter;\nexport 'src/chart/cartesian/axis/time/auto_adjusting_date_time_tick_provider.dart'\n    show AutoAdjustingDateTimeTickProvider;\nexport 'src/chart/cartesian/axis/time/base_time_stepper.dart'\n    show BaseTimeStepper;\nexport 'src/chart/cartesian/axis/time/date_time_extents.dart'\n    show DateTimeExtents;\nexport 'src/chart/cartesian/axis/time/date_time_tick_formatter.dart'\n    show DateTimeTickFormatter;\nexport 'src/chart/cartesian/axis/time/time_range_tick_provider_impl.dart'\n    show TimeRangeTickProviderImpl;\nexport 'src/chart/cartesian/cartesian_chart.dart'\n    show CartesianChart, NumericCartesianChart, OrdinalCartesianChart;\nexport 'src/chart/cartesian/cartesian_renderer.dart' show BaseCartesianRenderer;\nexport 'src/chart/common/base_chart.dart' show BaseChart, LifecycleListener;\nexport 'src/chart/common/behavior/a11y/a11y_explore_behavior.dart'\n    show ExploreModeTrigger;\nexport 'src/chart/common/behavior/a11y/a11y_node.dart' show A11yNode;\nexport 'src/chart/common/behavior/a11y/domain_a11y_explore_behavior.dart'\n    show DomainA11yExploreBehavior, VocalizationCallback;\nexport 'src/chart/common/behavior/a11y/keyboard_domain_navigator.dart'\n    show KeyboardDomainNavigator;\nexport 'src/chart/common/behavior/calculation/percent_injector.dart'\n    show PercentInjector, PercentInjectorTotalType;\nexport 'src/chart/common/behavior/chart_behavior.dart'\n    show\n        BehaviorPosition,\n        ChartBehavior,\n        InsideJustification,\n        OutsideJustification;\nexport 'src/chart/common/behavior/chart_title/chart_title.dart'\n    show ChartTitle, ChartTitleDirection;\nexport 'src/chart/common/behavior/domain_highlighter.dart'\n    show DomainHighlighter;\nexport 'src/chart/common/behavior/domain_outliner.dart' show DomainOutliner;\nexport 'src/chart/common/behavior/initial_selection.dart' show InitialSelection;\nexport 'src/chart/common/behavior/legend/datum_legend.dart' show DatumLegend;\nexport 'src/chart/common/behavior/legend/legend.dart'\n    show Legend, LegendCellPadding, LegendState, LegendTapHandling;\nexport 'src/chart/common/behavior/legend/legend_entry.dart'\n    show LegendEntry, LegendCategory, LegendEntryBase;\nexport 'src/chart/common/behavior/legend/legend_entry_generator.dart'\n    show LegendEntryGenerator, LegendDefaultMeasure;\nexport 'src/chart/common/behavior/legend/series_legend.dart' show SeriesLegend;\nexport 'src/chart/common/behavior/line_point_highlighter.dart'\n    show LinePointHighlighter, LinePointHighlighterFollowLineType;\nexport 'src/chart/common/behavior/range_annotation.dart'\n    show\n        AnnotationLabelAnchor,\n        AnnotationLabelDirection,\n        AnnotationLabelPosition,\n        AnnotationSegment,\n        LineAnnotationSegment,\n        RangeAnnotation,\n        RangeAnnotationAxisType,\n        RangeAnnotationSegment;\nexport 'src/chart/common/behavior/selection/lock_selection.dart'\n    show LockSelection;\nexport 'src/chart/common/behavior/selection/select_nearest.dart'\n    show SelectNearest, SelectionMode;\nexport 'src/chart/common/behavior/selection/selection_trigger.dart'\n    show SelectionTrigger;\nexport 'src/chart/common/behavior/slider/slider.dart'\n    show\n        Slider,\n        SliderHandlePosition,\n        SliderListenerCallback,\n        SliderListenerDragState,\n        SliderStyle;\nexport 'src/chart/common/behavior/sliding_viewport.dart' show SlidingViewport;\nexport 'src/chart/common/behavior/sunburst_ring_expander.dart'\n    show SunburstRingExpander;\nexport 'src/chart/common/behavior/zoom/initial_hint_behavior.dart'\n    show InitialHintBehavior;\nexport 'src/chart/common/behavior/zoom/pan_and_zoom_behavior.dart'\n    show PanAndZoomBehavior;\nexport 'src/chart/common/behavior/zoom/pan_behavior.dart'\n    show PanBehavior, PanningCompletedCallback;\nexport 'src/chart/common/behavior/zoom/panning_tick_provider.dart'\n    show PanningTickProviderMode;\nexport 'src/chart/common/canvas_shapes.dart'\n    show CanvasBarStack, CanvasPie, CanvasPieSlice, CanvasRect;\nexport 'src/chart/common/chart_canvas.dart'\n    show ChartCanvas, FillPatternType, BlendMode;\nexport 'src/chart/common/chart_context.dart' show ChartContext;\nexport 'src/chart/common/datum_details.dart'\n    show DatumDetails, DomainFormatter, MeasureFormatter;\nexport 'src/chart/common/processed_series.dart'\n    show ImmutableSeries, MutableSeries;\nexport 'src/chart/common/selection_model/selection_model.dart'\n    show\n        MutableSelectionModel,\n        SelectionModel,\n        SelectionModelType,\n        SelectionModelListener;\nexport 'src/chart/common/series_datum.dart' show SeriesDatum, SeriesDatumConfig;\nexport 'src/chart/common/series_renderer.dart'\n    show rendererIdKey, rendererKey, SeriesRenderer;\nexport 'src/chart/common/series_renderer_config.dart'\n    show RendererAttributeKey, SeriesRendererConfig;\nexport 'src/chart/layout/layout_config.dart' show LayoutConfig, MarginSpec;\nexport 'src/chart/layout/layout_view.dart'\n    show\n        LayoutPosition,\n        LayoutView,\n        LayoutViewConfig,\n        LayoutViewPaintOrder,\n        LayoutViewPositionOrder,\n        ViewMargin,\n        ViewMeasuredSizes;\nexport 'src/chart/line/line_chart.dart' show LineChart;\nexport 'src/chart/line/line_renderer.dart' show LineRenderer;\nexport 'src/chart/line/line_renderer_config.dart' show LineRendererConfig;\nexport 'src/chart/pie/arc_label_decorator.dart'\n    show ArcLabelDecorator, ArcLabelLeaderLineStyleSpec, ArcLabelPosition;\nexport 'src/chart/pie/arc_renderer.dart' show ArcRenderer;\nexport 'src/chart/pie/arc_renderer_config.dart' show ArcRendererConfig;\nexport 'src/chart/pie/pie_chart.dart' show PieChart;\nexport 'src/chart/scatter_plot/comparison_points_decorator.dart'\n    show ComparisonPointsDecorator;\nexport 'src/chart/scatter_plot/point_renderer.dart'\n    show\n        boundsLineRadiusPxKey,\n        boundsLineRadiusPxFnKey,\n        pointSymbolRendererFnKey,\n        pointSymbolRendererIdKey,\n        PointRenderer,\n        PointRendererElement;\nexport 'src/chart/scatter_plot/point_renderer_config.dart'\n    show PointRendererConfig;\nexport 'src/chart/scatter_plot/point_renderer_decorator.dart'\n    show PointRendererDecorator;\nexport 'src/chart/scatter_plot/scatter_plot_chart.dart' show ScatterPlotChart;\nexport 'src/chart/scatter_plot/symbol_annotation_renderer.dart'\n    show SymbolAnnotationRenderer;\nexport 'src/chart/sunburst/sunburst_chart.dart' show SunburstChart;\nexport 'src/chart/sunburst/sunburst_arc_renderer.dart' show SunburstArcRenderer;\nexport 'src/chart/sunburst/sunburst_arc_renderer_config.dart'\n    show SunburstArcRendererConfig, SunburstColorStrategy;\nexport 'src/chart/sunburst/sunburst_arc_label_decorator.dart'\n    show SunburstArcLabelDecorator;\nexport 'src/chart/scatter_plot/symbol_annotation_renderer_config.dart'\n    show SymbolAnnotationRendererConfig;\nexport 'src/chart/time_series/time_series_chart.dart' show TimeSeriesChart;\nexport 'src/chart/treemap/squarified_treemap_renderer.dart'\n    show SquarifiedTreeMapRenderer;\nexport 'src/chart/treemap/treemap_chart.dart' show TreeMapChart;\nexport 'src/chart/treemap/treemap_label_decorator.dart'\n    show TreeMapLabelDecorator;\nexport 'src/chart/treemap/treemap_renderer_config.dart'\n    show TreeMapRendererConfig, TreeMapTileType;\nexport 'src/common/color.dart' show Color;\nexport 'src/common/date_time_factory.dart'\n    show DateTimeFactory, LocalDateTimeFactory, UTCDateTimeFactory;\nexport 'src/common/gesture_listener.dart' show GestureListener;\nexport 'src/common/graphics_factory.dart' show GraphicsFactory;\nexport 'src/common/line_style.dart' show LineStyle;\nexport 'src/common/material_palette.dart' show MaterialPalette;\nexport 'src/common/math.dart' show NullablePoint;\nexport 'src/common/performance.dart' show Performance;\nexport 'src/common/proxy_gesture_listener.dart' show ProxyGestureListener;\nexport 'src/common/rtl_spec.dart' show AxisDirection, RTLSpec;\nexport 'src/common/style/material_style.dart' show MaterialStyle;\nexport 'src/common/style/style_factory.dart' show StyleFactory;\nexport 'src/common/symbol_renderer.dart'\n    show\n        CircleSymbolRenderer,\n        CylinderSymbolRenderer,\n        LineSymbolRenderer,\n        PointSymbolRenderer,\n        RectSymbolRenderer,\n        RectangleRangeSymbolRenderer,\n        RoundedRectSymbolRenderer,\n        SymbolRenderer,\n        TriangleSymbolRenderer;\nexport 'src/common/text_element.dart'\n    show TextElement, TextDirection, MaxWidthStrategy;\nexport 'src/common/text_measurement.dart' show TextMeasurement;\nexport 'src/common/text_style.dart' show TextStyle;\nexport 'src/data/series.dart' show AttributeKey, Series, TypedAccessorFn;\nexport 'src/data/tree.dart' show Tree, TreeNode;\n//\n// DO NOT ADD ANYTHING BELOW THIS. IT WILL BREAK OPENSOURCE.\n//\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/bar/bar_chart.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:collection' show LinkedHashMap;\n\nimport '../bar/bar_renderer.dart' show BarRenderer;\nimport '../cartesian/axis/axis.dart' show NumericAxis;\nimport '../cartesian/cartesian_chart.dart' show OrdinalCartesianChart;\nimport '../common/series_renderer.dart' show SeriesRenderer;\nimport '../layout/layout_config.dart' show LayoutConfig;\n\nclass BarChart extends OrdinalCartesianChart {\n  BarChart(\n      {bool? vertical,\n      LayoutConfig? layoutConfig,\n      NumericAxis? primaryMeasureAxis,\n      NumericAxis? secondaryMeasureAxis,\n      LinkedHashMap<String, NumericAxis>? disjointMeasureAxes})\n      : super(\n            vertical: vertical,\n            layoutConfig: layoutConfig,\n            primaryMeasureAxis: primaryMeasureAxis,\n            secondaryMeasureAxis: secondaryMeasureAxis,\n            disjointMeasureAxes: disjointMeasureAxes);\n\n  @override\n  SeriesRenderer<String> makeDefaultRenderer() {\n    return BarRenderer<String>()..rendererId = SeriesRenderer.defaultRendererId;\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/bar/bar_error_decorator.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math';\n\nimport '../../common/color.dart' show Color;\nimport '../../common/graphics_factory.dart' show GraphicsFactory;\nimport '../common/chart_canvas.dart' show ChartCanvas;\nimport 'bar_renderer.dart' show ImmutableBarRendererElement;\nimport 'bar_renderer_decorator.dart' show BarRendererDecorator;\nimport '../cartesian/axis/axis.dart' show ImmutableAxis, measureAxisKey;\n\n/// Decorates bars with error whiskers.\n///\n/// Used to represent confidence intervals for bar charts.\nclass BarErrorDecorator<D> extends BarRendererDecorator<D> {\n  static const Color _defaultStrokeColor = Color.black;\n  static const double _defaultStrokeWidthPx = 1;\n  static const double _defaultEndpointLengthPx = 16;\n\n  static const Color _defaultOutlineColor = Color.white;\n  static const double _defaultOutlineWidthPx = 0;\n\n  final double strokeWidthPx;\n  final double endpointLengthPx;\n  final double outlineWidthPx;\n\n  final Color strokeColor;\n  final Color outlineColor;\n\n  BarErrorDecorator(\n      {this.strokeColor = _defaultStrokeColor,\n      this.strokeWidthPx = _defaultStrokeWidthPx,\n      this.endpointLengthPx = _defaultEndpointLengthPx,\n      this.outlineWidthPx = _defaultOutlineWidthPx,\n      this.outlineColor = _defaultOutlineColor});\n\n  @override\n  void decorate(\n    Iterable<ImmutableBarRendererElement<D>> barElements,\n    ChartCanvas canvas,\n    GraphicsFactory graphicsFactory, {\n    required Rectangle<num> drawBounds,\n    required double animationPercent,\n    required bool renderingVertically,\n    bool rtl = false,\n  }) {\n    // Only decorate the bars when animation is at 100%.\n    if (animationPercent != 1.0) {\n      return;\n    }\n\n    for (var element in barElements) {\n      final bounds = element.bounds!;\n      final datumIndex = element.index;\n\n      final series = element.series!;\n\n      final measureLowerBoundFn = series.measureLowerBoundFn;\n      final measureUpperBoundFn = series.measureUpperBoundFn;\n\n      if (measureLowerBoundFn != null && measureUpperBoundFn != null) {\n        final measureOffsetFn = series.measureOffsetFn!;\n        final measureAxis =\n            series.getAttr(measureAxisKey) as ImmutableAxis<num>;\n\n        if (renderingVertically) {\n          final startY = measureAxis.getLocation(\n              (measureLowerBoundFn(datumIndex) ?? 0) +\n                  measureOffsetFn(datumIndex)!)!;\n          final endY = measureAxis.getLocation(\n              (measureUpperBoundFn(datumIndex) ?? 0) +\n                  measureOffsetFn(datumIndex)!)!;\n\n          if (startY != endY) {\n            final barWidth = bounds.right - bounds.left;\n            final x = (bounds.left + bounds.right) / 2;\n            final rectWidth =\n                min(strokeWidthPx + 2 * outlineWidthPx, barWidth.toDouble());\n            final strokeWidth = rectWidth - 2 * outlineWidthPx;\n            final rectEndpointLength =\n                min(endpointLengthPx + 2 * outlineWidthPx, barWidth.toDouble());\n            final endpointLength = rectEndpointLength - 2 * outlineWidthPx;\n\n            if (outlineWidthPx > 0) {\n              // Draw rectangle rendering the outline for the vertical line.\n              canvas.drawRect(\n                  Rectangle.fromPoints(Point(x - rectWidth / 2, startY),\n                      Point(x + rectWidth / 2, endY)),\n                  fill: outlineColor,\n                  strokeWidthPx: outlineWidthPx);\n\n              // Draw rectangle rendering the outline for the horizontal\n              // endpoint representing the lower bound.\n              canvas.drawRect(\n                  Rectangle(x - rectEndpointLength / 2, startY - rectWidth / 2,\n                      rectEndpointLength, rectWidth),\n                  fill: outlineColor,\n                  strokeWidthPx: outlineWidthPx);\n\n              // Draw rectangle rendering the outline for the horizontal\n              // endpoint representing the upper bound.\n              canvas.drawRect(\n                  Rectangle(x - rectEndpointLength / 2, endY - rectWidth / 2,\n                      rectEndpointLength, rectWidth),\n                  fill: outlineColor,\n                  strokeWidthPx: outlineWidthPx);\n            }\n\n            // Draw vertical whisker line.\n            canvas.drawLine(\n                points: [Point(x, startY), Point(x, endY)],\n                stroke: strokeColor,\n                strokeWidthPx: strokeWidth);\n\n            // Draw horizontal whisker line for the lower bound.\n            canvas.drawLine(points: [\n              Point(x - endpointLength / 2, startY),\n              Point(x + endpointLength / 2, startY)\n            ], stroke: strokeColor, strokeWidthPx: strokeWidth);\n\n            // Draw horizontal whisker line for the upper bound.\n            canvas.drawLine(points: [\n              Point(x - endpointLength / 2, endY),\n              Point(x + endpointLength / 2, endY)\n            ], stroke: strokeColor, strokeWidthPx: strokeWidth);\n          }\n        } else {\n          final startX = measureAxis.getLocation(\n              (measureLowerBoundFn(datumIndex) ?? 0) +\n                  measureOffsetFn(datumIndex)!)!;\n          final endX = measureAxis.getLocation(\n              (measureUpperBoundFn(datumIndex) ?? 0) +\n                  measureOffsetFn(datumIndex)!)!;\n\n          if (startX != endX) {\n            final barWidth = bounds.bottom - bounds.top;\n            final y = (bounds.top + bounds.bottom) / 2;\n            final rectWidth =\n                min(strokeWidthPx + 2 * outlineWidthPx, barWidth.toDouble());\n            final strokeWidth = rectWidth - 2 * outlineWidthPx;\n            final rectEndpointLength =\n                min(endpointLengthPx + 2 * outlineWidthPx, barWidth.toDouble());\n            final endpointLength = rectEndpointLength - 2 * outlineWidthPx;\n\n            if (outlineWidthPx > 0) {\n              // Draw rectangle rendering the outline for the horizontal line.\n              canvas.drawRect(\n                  Rectangle.fromPoints(Point(startX, y - rectWidth / 2),\n                      Point(endX, y + rectWidth / 2)),\n                  fill: outlineColor,\n                  strokeWidthPx: outlineWidthPx);\n\n              // Draw rectangle rendering the outline for the vertical\n              // endpoint representing the lower bound.\n              canvas.drawRect(\n                  Rectangle(startX - rectWidth / 2, y - rectEndpointLength / 2,\n                      rectWidth, rectEndpointLength),\n                  fill: outlineColor,\n                  strokeWidthPx: outlineWidthPx);\n\n              // Draw rectangle rendering the outline for the vertical\n              // endpoint representing the upper bound.\n              canvas.drawRect(\n                  Rectangle(endX - rectWidth / 2, y - rectEndpointLength / 2,\n                      rectWidth, rectEndpointLength),\n                  fill: outlineColor,\n                  strokeWidthPx: outlineWidthPx);\n            }\n\n            // Draw horizontal whisker line.\n            canvas.drawLine(\n                points: [Point(startX, y), Point(endX, y)],\n                stroke: strokeColor,\n                strokeWidthPx: strokeWidth);\n\n            // Draw vertical whisker line for the lower bound.\n            canvas.drawLine(points: [\n              Point(startX, y - endpointLength / 2),\n              Point(startX, y + endpointLength / 2)\n            ], stroke: strokeColor, strokeWidthPx: strokeWidth);\n\n            // Draw vertical whisker line for the upper bound.\n            canvas.drawLine(points: [\n              Point(endX, y - endpointLength / 2),\n              Point(endX, y + endpointLength / 2)\n            ], stroke: strokeColor, strokeWidthPx: strokeWidth);\n          }\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/bar/bar_label_decorator.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math' show Rectangle;\n\nimport '../../common/color.dart' show Color;\nimport '../../common/graphics_factory.dart' show GraphicsFactory;\nimport '../../common/text_element.dart' show TextDirection, TextElement;\nimport '../../common/text_style.dart' show TextStyle;\nimport '../../data/series.dart' show AccessorFn;\nimport '../cartesian/axis/spec/axis_spec.dart' show TextStyleSpec;\nimport '../common/chart_canvas.dart' show ChartCanvas;\nimport 'bar_renderer.dart' show ImmutableBarRendererElement;\nimport 'bar_renderer_decorator.dart' show BarRendererDecorator;\n\nclass BarLabelDecorator<D> extends BarRendererDecorator<D> {\n  // Default configuration\n  static const _defaultLabelPosition = BarLabelPosition.auto;\n  static const _defaultLabelPadding = 5;\n  static const _defaultLabelPlacement = BarLabelPlacement.followMeasureAxis;\n  static const _defaultHorizontalLabelAnchor = BarLabelAnchor.start;\n  static const _defaultVerticalLabelAnchor = BarLabelAnchor.end;\n  static final _defaultInsideLabelStyle =\n      TextStyleSpec(fontSize: 12, color: Color.white);\n  static final _defaultOutsideLabelStyle =\n      TextStyleSpec(fontSize: 12, color: Color.black);\n  static final _labelSplitPattern = '\\n';\n  static final _defaultMultiLineLabelPadding = 2;\n\n  /// Configures [TextStyleSpec] for labels placed inside the bars.\n  final TextStyleSpec insideLabelStyleSpec;\n\n  /// Configures [TextStyleSpec] for labels placed outside the bars.\n  final TextStyleSpec outsideLabelStyleSpec;\n\n  /// Configures where to place the label relative to the bars.\n  final BarLabelPosition labelPosition;\n\n  /// Configures where to place the label relative to the axis.\n  final BarLabelPlacement labelPlacement;\n\n  /// For labels drawn inside the bar, configures label anchor position.\n  final BarLabelAnchor? labelAnchor;\n\n  /// Space before and after the label text.\n  final int labelPadding;\n\n  BarLabelDecorator(\n      {TextStyleSpec? insideLabelStyleSpec,\n      TextStyleSpec? outsideLabelStyleSpec,\n      this.labelAnchor,\n      this.labelPosition = _defaultLabelPosition,\n      this.labelPlacement = _defaultLabelPlacement,\n      this.labelPadding = _defaultLabelPadding})\n      : insideLabelStyleSpec = insideLabelStyleSpec ?? _defaultInsideLabelStyle,\n        outsideLabelStyleSpec =\n            outsideLabelStyleSpec ?? _defaultOutsideLabelStyle;\n\n  @override\n  void decorate(Iterable<ImmutableBarRendererElement<D>> barElements,\n      ChartCanvas canvas, GraphicsFactory graphicsFactory,\n      {required Rectangle<int> drawBounds,\n      required double animationPercent,\n      required bool renderingVertically,\n      bool rtl = false}) {\n    // Only decorate the bars when animation is at 100%.\n    if (animationPercent != 1.0) {\n      return;\n    }\n\n    if (renderingVertically) {\n      _decorateVerticalBars(\n          barElements, canvas, graphicsFactory, drawBounds, rtl);\n    } else {\n      _decorateHorizontalBars(\n          barElements, canvas, graphicsFactory, drawBounds, rtl);\n    }\n  }\n\n  void _decorateVerticalBars(\n      Iterable<ImmutableBarRendererElement<D>> barElements,\n      ChartCanvas canvas,\n      GraphicsFactory graphicsFactory,\n      Rectangle<int> drawBounds,\n      bool rtl) {\n    // Create [TextStyle] from [TextStyleSpec] to be used by all the elements.\n    // The [GraphicsFactory] is needed so it can't be created earlier.\n    final insideLabelStyle =\n        _getTextStyle(graphicsFactory, insideLabelStyleSpec);\n    final outsideLabelStyle =\n        _getTextStyle(graphicsFactory, outsideLabelStyleSpec);\n\n    for (var element in barElements) {\n      final labelFn = element.series!.labelAccessorFn;\n      final measureFn = element.series!.measureFn;\n      final datumIndex = element.index;\n      final label = labelFn?.call(datumIndex);\n      final measure = measureFn(datumIndex) ?? 0.0;\n\n      // If there are custom styles, use that instead of the default or the\n      // style defined for the entire decorator.\n      final datumInsideLabelStyle = _getDatumStyle(\n          element.series!.insideLabelStyleAccessorFn,\n          datumIndex,\n          graphicsFactory,\n          defaultStyle: insideLabelStyle);\n      final datumOutsideLabelStyle = _getDatumStyle(\n          element.series!.outsideLabelStyleAccessorFn,\n          datumIndex,\n          graphicsFactory,\n          defaultStyle: outsideLabelStyle);\n\n      // Skip calculation and drawing for this element if no label.\n      if (label == null || label.isEmpty) {\n        continue;\n      }\n\n      var labelElements = label\n          .split(_labelSplitPattern)\n          .map((labelPart) => graphicsFactory.createTextElement(labelPart));\n\n      final bounds = element.bounds!;\n\n      // Get space available inside and outside the bar.\n      final totalPadding = labelPadding * 2;\n      final insideBarHeight = bounds.height - totalPadding;\n\n      var calculatedLabelPosition = labelPosition;\n      if (calculatedLabelPosition == BarLabelPosition.auto) {\n        // For auto, first try to fit the text inside the bar.\n        labelElements = labelElements.map(\n            (labelElement) => labelElement..textStyle = datumInsideLabelStyle);\n\n        final labelMaxWidth = labelElements\n            .map(\n                (labelElement) => labelElement.measurement.horizontalSliceWidth)\n            .fold<double>(0, (max, current) => max > current ? max : current);\n\n        // Total label height depends on the label element's text style.\n        final totalLabelHeight = _getTotalLabelHeight(labelElements);\n\n        // A label fits if the length and width of the text fits.\n        calculatedLabelPosition =\n            totalLabelHeight < insideBarHeight && labelMaxWidth < bounds.width\n                ? BarLabelPosition.inside\n                : BarLabelPosition.outside;\n      }\n\n      // Set the max width, text style, and text direction.\n      labelElements = labelElements.map((labelElement) => labelElement\n        ..textStyle = calculatedLabelPosition == BarLabelPosition.inside\n            ? datumInsideLabelStyle\n            : datumOutsideLabelStyle\n        ..maxWidth = bounds.width\n        ..textDirection = rtl ? TextDirection.rtl : TextDirection.ltr);\n\n      // Total label height depends on the label element's text style.\n      final totalLabelHeight = _getTotalLabelHeight(labelElements);\n\n      var labelsDrawn = 0;\n      for (var labelElement in labelElements) {\n        // Calculate the start position of label based on [labelAnchor].\n        final int labelY;\n        final labelHeight = labelElement.measurement.verticalSliceWidth.round();\n        final offsetHeight =\n            (labelHeight + _defaultMultiLineLabelPadding) * labelsDrawn;\n\n        if (calculatedLabelPosition == BarLabelPosition.inside) {\n          final anchor = _resolveLabelAnchor(\n              measure, labelAnchor ?? _defaultVerticalLabelAnchor);\n          switch (anchor) {\n            case BarLabelAnchor.end:\n              labelY = bounds.top + labelPadding + offsetHeight;\n              break;\n            case BarLabelAnchor.middle:\n              labelY = (bounds.bottom -\n                      bounds.height / 2 -\n                      totalLabelHeight / 2 +\n                      offsetHeight)\n                  .round();\n              break;\n            case BarLabelAnchor.start:\n              labelY = bounds.bottom -\n                  labelPadding -\n                  totalLabelHeight +\n                  offsetHeight;\n              break;\n          }\n        } else {\n          // calculatedLabelPosition == LabelPosition.outside\n          if (measure < 0 &&\n              labelPlacement == BarLabelPlacement.opposeAxisBaseline) {\n            labelY = bounds.bottom + labelPadding + offsetHeight;\n          } else {\n            labelY =\n                bounds.top - labelPadding - totalLabelHeight + offsetHeight;\n          }\n        }\n\n        // Center the label inside the bar.\n        final labelX = (bounds.left +\n                bounds.width / 2 -\n                labelElement.measurement.horizontalSliceWidth / 2)\n            .round();\n\n        canvas.drawText(labelElement, labelX, labelY);\n        labelsDrawn += 1;\n      }\n    }\n  }\n\n  void _decorateHorizontalBars(\n      Iterable<ImmutableBarRendererElement<D>> barElements,\n      ChartCanvas canvas,\n      GraphicsFactory graphicsFactory,\n      Rectangle<int> drawBounds,\n      bool rtl) {\n    // Create [TextStyle] from [TextStyleSpec] to be used by all the elements.\n    // The [GraphicsFactory] is needed so it can't be created earlier.\n    final insideLabelStyle =\n        _getTextStyle(graphicsFactory, insideLabelStyleSpec);\n    final outsideLabelStyle =\n        _getTextStyle(graphicsFactory, outsideLabelStyleSpec);\n\n    for (var element in barElements) {\n      final labelFn = element.series!.labelAccessorFn;\n      final measureFn = element.series!.measureFn;\n      final datumIndex = element.index;\n      final label = labelFn?.call(datumIndex);\n      final measure = measureFn(datumIndex) ?? 0.0;\n\n      // If there are custom styles, use that instead of the default or the\n      // style defined for the entire decorator.\n      final datumInsideLabelStyle = _getDatumStyle(\n          element.series!.insideLabelStyleAccessorFn,\n          datumIndex,\n          graphicsFactory,\n          defaultStyle: insideLabelStyle);\n      final datumOutsideLabelStyle = _getDatumStyle(\n          element.series!.outsideLabelStyleAccessorFn,\n          datumIndex,\n          graphicsFactory,\n          defaultStyle: outsideLabelStyle);\n\n      // Skip calculation and drawing for this element if no label.\n      if (label == null || label.isEmpty) {\n        continue;\n      }\n\n      final bounds = element.bounds!;\n\n      // Get space available inside and outside the bar.\n      final totalPadding = labelPadding * 2;\n      final insideBarWidth = bounds.width - totalPadding;\n      final outsideBarWidth = drawBounds.width - bounds.width - totalPadding;\n\n      final labelElement = graphicsFactory.createTextElement(label);\n      var calculatedLabelPosition = labelPosition;\n      if (calculatedLabelPosition == BarLabelPosition.auto) {\n        // For auto, first try to fit the text inside the bar.\n        labelElement.textStyle = datumInsideLabelStyle;\n\n        // A label fits if the space inside the bar is >= outside bar or if the\n        // length of the text fits and the space. This is because if the bar has\n        // more space than the outside, it makes more sense to place the label\n        // inside the bar, even if the entire label does not fit.\n        calculatedLabelPosition = (insideBarWidth >= outsideBarWidth ||\n                labelElement.measurement.horizontalSliceWidth < insideBarWidth)\n            ? BarLabelPosition.inside\n            : BarLabelPosition.outside;\n      }\n\n      // Set the max width and text style.\n      if (calculatedLabelPosition == BarLabelPosition.inside) {\n        labelElement.textStyle = datumInsideLabelStyle;\n        labelElement.maxWidth = insideBarWidth;\n      } else {\n        // calculatedLabelPosition == LabelPosition.outside\n        labelElement.textStyle = datumOutsideLabelStyle;\n        labelElement.maxWidth = outsideBarWidth;\n      }\n\n      // Only calculate and draw label if there's actually space for the label.\n      if (labelElement.maxWidth! < 0 ||\n          (labelElement.maxWidthStrategy == null &&\n              labelElement.measurement.horizontalSliceWidth >\n                  labelElement.maxWidth!)) {\n        return;\n      }\n\n      // Calculate the start position of label based on [labelAnchor].\n      final int labelX;\n      if (calculatedLabelPosition == BarLabelPosition.inside) {\n        final anchor = _resolveLabelAnchor(\n            measure, labelAnchor ?? _defaultHorizontalLabelAnchor);\n\n        switch (anchor) {\n          case BarLabelAnchor.middle:\n            labelX = (bounds.left +\n                    bounds.width / 2 -\n                    labelElement.measurement.horizontalSliceWidth / 2)\n                .round();\n            labelElement.textDirection =\n                rtl ? TextDirection.rtl : TextDirection.ltr;\n            break;\n\n          case BarLabelAnchor.end:\n          case BarLabelAnchor.start:\n            final alignLeft = rtl\n                ? (anchor == BarLabelAnchor.end)\n                : (anchor == BarLabelAnchor.start);\n\n            if (alignLeft) {\n              labelX = bounds.left + labelPadding;\n              labelElement.textDirection = TextDirection.ltr;\n            } else {\n              labelX = bounds.right - labelPadding;\n              labelElement.textDirection = TextDirection.rtl;\n            }\n            break;\n        }\n      } else {\n        // calculatedLabelPosition == LabelPosition.outside\n        if (measure < 0 &&\n            labelPlacement == BarLabelPlacement.opposeAxisBaseline) {\n          labelX = bounds.left - labelPadding;\n          labelElement.textDirection = TextDirection.rtl;\n        } else {\n          labelX = bounds.right + labelPadding;\n          labelElement.textDirection = TextDirection.ltr;\n        }\n      }\n\n      // Center the label inside the bar.\n      final labelY = (bounds.top +\n              (bounds.bottom - bounds.top) / 2 -\n              labelElement.measurement.verticalSliceWidth / 2)\n          .round();\n\n      canvas.drawText(labelElement, labelX, labelY);\n    }\n  }\n\n  /// Helper function to get the total height for a group of labels.\n  /// This includes the padding in between the labels.\n  int _getTotalLabelHeight(Iterable<TextElement> labelElements) =>\n      (labelElements.first.measurement.verticalSliceWidth *\n              labelElements.length)\n          .round() +\n      _defaultMultiLineLabelPadding * (labelElements.length - 1);\n\n  // Helper function that converts [TextStyleSpec] to [TextStyle].\n  TextStyle _getTextStyle(\n      GraphicsFactory graphicsFactory, TextStyleSpec? labelSpec) {\n    return graphicsFactory.createTextPaint()\n      ..color = labelSpec?.color ?? Color.black\n      ..fontFamily = labelSpec?.fontFamily\n      ..fontSize = labelSpec?.fontSize ?? 12\n      ..lineHeight = labelSpec?.lineHeight;\n  }\n\n  /// Helper function to get datum specific style\n  TextStyle _getDatumStyle(\n    AccessorFn<TextStyleSpec>? labelFn,\n    int? datumIndex,\n    GraphicsFactory graphicsFactory, {\n    required TextStyle defaultStyle,\n  }) {\n    final styleSpec = labelFn?.call(datumIndex);\n    return (styleSpec != null)\n        ? _getTextStyle(graphicsFactory, styleSpec)\n        : defaultStyle;\n  }\n\n  /// Helper function to get the bar label anchor when [BarLabelPostion] is\n  /// inside.\n  BarLabelAnchor _resolveLabelAnchor(num measure, BarLabelAnchor anchor) {\n    if (labelPlacement == BarLabelPlacement.opposeAxisBaseline) {\n      if (measure >= 0) return anchor;\n      if (anchor == BarLabelAnchor.start) return BarLabelAnchor.end;\n      if (anchor == BarLabelAnchor.end) return BarLabelAnchor.start;\n      return anchor;\n    }\n    return anchor;\n  }\n}\n\n/// Configures where to place the label relative to the bars.\nenum BarLabelPosition {\n  /// Automatically try to place the label inside the bar first and place it on\n  /// the outside of the space available outside the bar is greater than space\n  /// available inside the bar.\n  auto,\n\n  /// Always place label on the outside.\n  outside,\n\n  /// Always place label on the inside.\n  inside,\n}\n\n/// Configures where to place the label relative to the axis.\nenum BarLabelPlacement {\n  /// Places the label with respect to the increase in measure axis units. The\n  /// bar end is the most positive position along the axis.\n  ///\n  /// This is the default placement.\n  followMeasureAxis,\n\n  /// Places the label with respect to the zero baseline. The bar end is the\n  /// absolute value aways from the zero baseline.\n  opposeAxisBaseline,\n}\n\n/// Configures where to anchor the label for labels drawn inside the bars.\nenum BarLabelAnchor {\n  /// Anchor to the measure start.\n  start,\n\n  /// Anchor to the middle of the measure range.\n  middle,\n\n  /// Anchor to the measure end.\n  end,\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/bar/bar_lane_renderer.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:collection' show LinkedHashMap;\nimport 'package:collection/collection.dart' show IterableExtension;\n\nimport '../../data/series.dart' show AttributeKey;\nimport '../cartesian/axis/axis.dart'\n    show ImmutableAxis, domainAxisKey, measureAxisKey;\nimport '../common/chart_canvas.dart' show ChartCanvas;\nimport '../common/processed_series.dart' show ImmutableSeries, MutableSeries;\nimport 'bar_lane_renderer_config.dart' show BarLaneRendererConfig;\nimport 'bar_renderer.dart' show AnimatedBar, BarRenderer, BarRendererElement;\nimport 'base_bar_renderer.dart'\n    show\n        allBarGroupWeightsKey,\n        barGroupCountKey,\n        barGroupIndexKey,\n        barGroupWeightKey,\n        previousBarGroupWeightKey,\n        stackKeyKey;\n\n/// Key for storing a list of all domain values that exist in the series data.\n///\n/// In grouped stacked mode, this list will contain a combination of domain\n/// value and series category.\nconst domainValuesKey =\n    AttributeKey<Set<Object>>('BarLaneRenderer.domainValues');\n\n/// Renders series data as a series of bars with lanes.\n///\n/// Every stack of bars will have a swim lane rendered underneath the series\n/// data, in a gray color by default. The swim lane occupies the same width as\n/// the bar elements, and will be completely covered up if the bar stack happens\n/// to take up the entire measure domain range.\n///\n/// If every bar that shares a domain value has a null measure value, then the\n/// swim lanes may optionally be merged together into one wide lane that covers\n/// the full domain range band width.\nclass BarLaneRenderer<D> extends BarRenderer<D> {\n  /// Store a map of domain+barGroupIndex+category index to bar lanes in a\n  /// stack.\n  ///\n  /// This map is used to render all the bars in a stack together, to account\n  /// for rendering effects that need to take the full stack into account (e.g.\n  /// corner rounding).\n  ///\n  /// [LinkedHashMap] is used to render the bars on the canvas in the same order\n  /// as the data was given to the chart. For the case where both grouping and\n  /// stacking are disabled, this means that bars for data later in the series\n  /// will be drawn \"on top of\" bars earlier in the series.\n  // ignore: prefer_collection_literals, https://github.com/dart-lang/linter/issues/1649\n  final _barLaneStackMap = LinkedHashMap<String, List<AnimatedBar<D>>>();\n\n  /// Store a map of flags to track whether all measure values for a given\n  /// domain value are null, for every series on the chart.\n  // ignore: prefer_collection_literals, https://github.com/dart-lang/linter/issues/1649\n  final _allMeasuresForDomainNullMap = LinkedHashMap<D, bool>();\n\n  factory BarLaneRenderer({\n    BarLaneRendererConfig? config,\n    String? rendererId,\n  }) {\n    rendererId ??= 'bar';\n    config ??= BarLaneRendererConfig();\n    return BarLaneRenderer._internal(config: config, rendererId: rendererId);\n  }\n\n  BarLaneRenderer._internal({\n    required BarLaneRendererConfig config,\n    required String rendererId,\n  }) : super.internal(config: config, rendererId: rendererId);\n\n  @override\n  void preprocessSeries(List<MutableSeries<D>> seriesList) {\n    super.preprocessSeries(seriesList);\n\n    _allMeasuresForDomainNullMap.clear();\n\n    seriesList.forEach((MutableSeries<D> series) {\n      final domainFn = series.domainFn;\n      final measureFn = series.rawMeasureFn;\n\n      final domainValues = <D>{};\n\n      for (var barIndex = 0; barIndex < series.data.length; barIndex++) {\n        final domain = domainFn(barIndex);\n        final measure = measureFn(barIndex);\n\n        domainValues.add(domain);\n\n        // Update the \"all measure null\" tracking for bars that have the\n        // current domain value.\n        if ((config as BarLaneRendererConfig).mergeEmptyLanes) {\n          final allNull = _allMeasuresForDomainNullMap[domain];\n          final isNull = measure == null;\n\n          _allMeasuresForDomainNullMap[domain] =\n              allNull != null ? allNull && isNull : isNull;\n        }\n      }\n\n      series.setAttr(domainValuesKey, domainValues);\n    });\n  }\n\n  @override\n  void update(List<ImmutableSeries<D>> seriesList, bool isAnimatingThisDraw) {\n    super.update(seriesList, isAnimatingThisDraw);\n\n    // Add gray bars to render under every bar stack.\n    seriesList.forEach((ImmutableSeries<D> series) {\n      var domainValues = series.getAttr(domainValuesKey) as Set<D>;\n\n      final domainAxis = series.getAttr(domainAxisKey) as ImmutableAxis<D>;\n      final measureAxis = series.getAttr(measureAxisKey) as ImmutableAxis<num>;\n      final seriesStackKey = series.getAttr(stackKeyKey);\n      final barGroupCount = series.getAttr(barGroupCountKey)!;\n      final barGroupIndex = series.getAttr(barGroupIndexKey)!;\n      final previousBarGroupWeight = series.getAttr(previousBarGroupWeightKey);\n      final barGroupWeight = series.getAttr(barGroupWeightKey);\n      final allBarGroupWeights = series.getAttr(allBarGroupWeightsKey);\n      final measureAxisPosition = measureAxis.getLocation(0.0);\n      final maxMeasureValue = _getMaxMeasureValue(measureAxis);\n\n      // Create a fake series for [BarLabelDecorator] to use when looking up the\n      // index of each datum.\n      final laneSeries =\n          MutableSeries<D>.clone(seriesList[0] as MutableSeries<D>);\n      laneSeries.data = <Object>[];\n\n      // Don't render any labels on the swim lanes.\n      laneSeries.labelAccessorFn = (int? index) => '';\n\n      var laneSeriesIndex = 0;\n      domainValues.forEach((D domainValue) {\n        // Skip adding any background bars if they will be covered up by the\n        // domain-spanning null bar.\n        if (_allMeasuresForDomainNullMap[domainValue] == true) {\n          return;\n        }\n\n        // Add a fake datum to the series for [BarLabelDecorator].\n        final datum = {'index': laneSeriesIndex};\n        laneSeries.data.add(datum);\n\n        // Each bar should be stored in barStackMap in a structure that mirrors\n        // the visual rendering of the bars. Thus, they should be grouped by\n        // domain value, series category (by way of the stack keys that were\n        // generated for each series in the preprocess step), and bar group\n        // index to account for all combinations of grouping and stacking.\n        final barStackMapKey =\n            '${domainValue}__${seriesStackKey}__${barGroupIndex}';\n\n        final barKey = barStackMapKey + '0';\n\n        final barStackList = _barLaneStackMap.putIfAbsent(\n            barStackMapKey, () => <AnimatedBar<D>>[]);\n\n        // If we already have an AnimatingBar for that index, use it.\n        var animatingBar =\n            barStackList.firstWhereOrNull((bar) => bar.key == barKey);\n\n        // If we don't have any existing bar element, create a new bar and have\n        // it animate in from the domain axis.\n        if (animatingBar == null) {\n          animatingBar = makeAnimatedBar(\n              key: barKey,\n              series: laneSeries,\n              datum: datum,\n              barGroupIndex: barGroupIndex,\n              previousBarGroupWeight: previousBarGroupWeight,\n              barGroupWeight: barGroupWeight,\n              allBarGroupWeights: allBarGroupWeights,\n              color: (config as BarLaneRendererConfig).backgroundBarColor,\n              details: BarRendererElement<D>(),\n              domainValue: domainValue,\n              domainAxis: domainAxis,\n              domainWidth: domainAxis.rangeBand.round(),\n              fillColor: (config as BarLaneRendererConfig).backgroundBarColor,\n              measureValue: maxMeasureValue,\n              measureOffsetValue: 0.0,\n              measureAxisPosition: measureAxisPosition,\n              measureAxis: measureAxis,\n              numBarGroups: barGroupCount,\n              strokeWidthPx: config.strokeWidthPx,\n              measureIsNull: false,\n              measureIsNegative: false);\n\n          barStackList.add(animatingBar);\n        } else {\n          animatingBar\n            ..datum = datum\n            ..series = laneSeries\n            ..domainValue = domainValue;\n        }\n\n        // Get the barElement we are going to setup.\n        // Optimization to prevent allocation in non-animating case.\n        final barElement = makeBarRendererElement(\n            barGroupIndex: barGroupIndex,\n            previousBarGroupWeight: previousBarGroupWeight,\n            barGroupWeight: barGroupWeight,\n            allBarGroupWeights: allBarGroupWeights,\n            color: (config as BarLaneRendererConfig).backgroundBarColor,\n            details: BarRendererElement<D>(),\n            domainValue: domainValue,\n            domainAxis: domainAxis,\n            domainWidth: domainAxis.rangeBand.round(),\n            fillColor: (config as BarLaneRendererConfig).backgroundBarColor,\n            measureValue: maxMeasureValue,\n            measureOffsetValue: 0.0,\n            measureAxisPosition: measureAxisPosition,\n            measureAxis: measureAxis,\n            numBarGroups: barGroupCount,\n            strokeWidthPx: config.strokeWidthPx,\n            measureIsNull: false,\n            measureIsNegative: false);\n\n        animatingBar.setNewTarget(barElement);\n\n        laneSeriesIndex++;\n      });\n    });\n\n    // Add domain-spanning bars to render when every measure value for every\n    // datum of a given domain is null.\n    if ((config as BarLaneRendererConfig).mergeEmptyLanes) {\n      // Use the axes from the first series.\n      final domainAxis =\n          seriesList[0].getAttr(domainAxisKey) as ImmutableAxis<D>;\n      final measureAxis =\n          seriesList[0].getAttr(measureAxisKey) as ImmutableAxis<num>;\n\n      final measureAxisPosition = measureAxis.getLocation(0.0);\n      final maxMeasureValue = _getMaxMeasureValue(measureAxis);\n\n      final barGroupIndex = 0;\n      final previousBarGroupWeight = 0.0;\n      final barGroupWeight = 1.0;\n      final barGroupCount = 1;\n\n      // Create a fake series for [BarLabelDecorator] to use when looking up the\n      // index of each datum. We don't care about any other series values for\n      // the merged lanes, so just clone the first series.\n      final mergedSeries =\n          MutableSeries<D>.clone(seriesList[0] as MutableSeries<D>);\n      mergedSeries.data = <Object>[];\n\n      // Add a label accessor that returns the empty lane label.\n      mergedSeries.labelAccessorFn =\n          (int? index) => (config as BarLaneRendererConfig).emptyLaneLabel;\n\n      var mergedSeriesIndex = 0;\n      _allMeasuresForDomainNullMap.forEach((D domainValue, bool allNull) {\n        if (allNull) {\n          // Add a fake datum to the series for [BarLabelDecorator].\n          final datum = {'index': mergedSeriesIndex};\n          mergedSeries.data.add(datum);\n\n          final barStackMapKey = '${domainValue}__allNull__';\n\n          final barKey = barStackMapKey + '0';\n\n          final barStackList = _barLaneStackMap.putIfAbsent(\n              barStackMapKey, () => <AnimatedBar<D>>[]);\n\n          // If we already have an AnimatingBar for that index, use it.\n          var animatingBar =\n              barStackList.firstWhereOrNull((bar) => bar.key == barKey);\n\n          // If we don't have any existing bar element, create a new bar and have\n          // it animate in from the domain axis.\n          if (animatingBar == null) {\n            animatingBar = makeAnimatedBar(\n                key: barKey,\n                series: mergedSeries,\n                datum: datum,\n                barGroupIndex: barGroupIndex,\n                previousBarGroupWeight: previousBarGroupWeight,\n                barGroupWeight: barGroupWeight,\n                color: (config as BarLaneRendererConfig).backgroundBarColor,\n                details: BarRendererElement<D>(),\n                domainValue: domainValue,\n                domainAxis: domainAxis,\n                domainWidth: domainAxis.rangeBand.round(),\n                fillColor: (config as BarLaneRendererConfig).backgroundBarColor,\n                measureValue: maxMeasureValue,\n                measureOffsetValue: 0.0,\n                measureAxisPosition: measureAxisPosition,\n                measureAxis: measureAxis,\n                numBarGroups: barGroupCount,\n                strokeWidthPx: config.strokeWidthPx,\n                measureIsNull: false,\n                measureIsNegative: false);\n\n            barStackList.add(animatingBar);\n          } else {\n            animatingBar\n              ..datum = datum\n              ..series = mergedSeries\n              ..domainValue = domainValue;\n          }\n\n          // Get the barElement we are going to setup.\n          // Optimization to prevent allocation in non-animating case.\n          final barElement = makeBarRendererElement(\n              barGroupIndex: barGroupIndex,\n              previousBarGroupWeight: previousBarGroupWeight,\n              barGroupWeight: barGroupWeight,\n              color: (config as BarLaneRendererConfig).backgroundBarColor,\n              details: BarRendererElement<D>(),\n              domainValue: domainValue,\n              domainAxis: domainAxis,\n              domainWidth: domainAxis.rangeBand.round(),\n              fillColor: (config as BarLaneRendererConfig).backgroundBarColor,\n              measureValue: maxMeasureValue,\n              measureOffsetValue: 0.0,\n              measureAxisPosition: measureAxisPosition,\n              measureAxis: measureAxis,\n              numBarGroups: barGroupCount,\n              strokeWidthPx: config.strokeWidthPx,\n              measureIsNull: false,\n              measureIsNegative: false);\n\n          animatingBar.setNewTarget(barElement);\n\n          mergedSeriesIndex++;\n        }\n      });\n    }\n  }\n\n  /// Gets the maximum measure value that will fit in the draw area.\n  num _getMaxMeasureValue(ImmutableAxis<num> measureAxis) {\n    final pos = chart.vertical\n        ? chart.drawAreaBounds.top\n        : isRtl\n            ? chart.drawAreaBounds.left\n            : chart.drawAreaBounds.right;\n\n    return measureAxis.getDomain(pos.toDouble());\n  }\n\n  /// Paints the current bar data on the canvas.\n  @override\n  void paint(ChartCanvas canvas, double animationPercent) {\n    _barLaneStackMap.forEach((String stackKey, List<AnimatedBar<D>> barStack) {\n      // Turn this into a list so that the getCurrentBar isn't called more than\n      // once for each animationPercent if the barElements are iterated more\n      // than once.\n      final barElements = barStack\n          .map((animatingBar) => animatingBar.getCurrentBar(animationPercent))\n          .toList();\n\n      paintBar(canvas, animationPercent, barElements);\n    });\n\n    super.paint(canvas, animationPercent);\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/bar/bar_lane_renderer_config.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport '../../common/color.dart' show Color;\nimport '../../common/style/style_factory.dart' show StyleFactory;\nimport '../../common/symbol_renderer.dart';\nimport '../common/chart_canvas.dart' show FillPatternType;\nimport '../layout/layout_view.dart' show LayoutViewPaintOrder;\nimport 'bar_label_decorator.dart' show BarLabelDecorator;\nimport 'bar_lane_renderer.dart' show BarLaneRenderer;\nimport 'bar_renderer_config.dart' show BarRendererConfig, CornerStrategy;\nimport 'bar_renderer_decorator.dart' show BarRendererDecorator;\nimport 'base_bar_renderer_config.dart' show BarGroupingType;\n\n/// Configuration for a bar lane renderer.\nclass BarLaneRendererConfig extends BarRendererConfig<String> {\n  /// The color of background bars.\n  final Color backgroundBarColor;\n\n  /// Label text to draw on a merged empty lane.\n  ///\n  /// This will only be drawn if all of the measures for a domain are null, and\n  /// [mergeEmptyLanes] is enabled.\n  ///\n  /// The renderer must be configured with a [BarLabelDecorator] for this label\n  /// to be drawn.\n  final String emptyLaneLabel;\n\n  /// Whether or not all lanes for a given domain value should be merged into\n  /// one wide lane if all measure values for said domain are null.\n  final bool mergeEmptyLanes;\n\n  BarLaneRendererConfig({\n    String? customRendererId,\n    CornerStrategy? cornerStrategy,\n    this.emptyLaneLabel = 'No data',\n    FillPatternType? fillPattern,\n    BarGroupingType? groupingType,\n    int layoutPaintOrder = LayoutViewPaintOrder.bar,\n    this.mergeEmptyLanes = false,\n    int minBarLengthPx = 0,\n    int stackedBarPaddingPx = 1,\n    double strokeWidthPx = 0.0,\n    BarRendererDecorator<String>? barRendererDecorator,\n    SymbolRenderer? symbolRenderer,\n    Color? backgroundBarColor,\n    List<int>? weightPattern,\n  })  : backgroundBarColor =\n            backgroundBarColor ?? StyleFactory.style.noDataColor,\n        super(\n          barRendererDecorator: barRendererDecorator,\n          cornerStrategy: cornerStrategy,\n          customRendererId: customRendererId,\n          groupingType: groupingType ?? BarGroupingType.grouped,\n          layoutPaintOrder: layoutPaintOrder,\n          minBarLengthPx: minBarLengthPx,\n          fillPattern: fillPattern,\n          stackedBarPaddingPx: stackedBarPaddingPx,\n          strokeWidthPx: strokeWidthPx,\n          symbolRenderer: symbolRenderer,\n          weightPattern: weightPattern,\n        );\n\n  @override\n  BarLaneRenderer<String> build() {\n    return BarLaneRenderer<String>(config: this, rendererId: customRendererId);\n  }\n\n  @override\n  bool operator ==(Object other) {\n    if (identical(this, other)) {\n      return true;\n    }\n    return other is BarLaneRendererConfig &&\n        other.backgroundBarColor == backgroundBarColor &&\n        other.emptyLaneLabel == emptyLaneLabel &&\n        other.mergeEmptyLanes == mergeEmptyLanes &&\n        super == other;\n  }\n\n  @override\n  int get hashCode {\n    var hash = super.hashCode;\n    hash = hash * 31 + backgroundBarColor.hashCode;\n    hash = hash * 31 + emptyLaneLabel.hashCode;\n    hash = hash * 31 + mergeEmptyLanes.hashCode;\n    return hash;\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/bar/bar_renderer.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math' show max, min, Rectangle;\n\nimport 'package:meta/meta.dart' show protected;\n\nimport '../../common/color.dart' show Color;\nimport '../../common/math.dart' show NullablePoint;\nimport '../cartesian/axis/axis.dart'\n    show ImmutableAxis, domainAxisKey, measureAxisKey;\nimport '../common/canvas_shapes.dart' show CanvasBarStack, CanvasRect;\nimport '../common/chart_canvas.dart' show ChartCanvas, FillPatternType;\nimport '../common/datum_details.dart' show DatumDetails;\nimport '../common/processed_series.dart' show ImmutableSeries, MutableSeries;\nimport '../common/series_datum.dart' show SeriesDatum;\nimport 'bar_renderer_config.dart' show BarRendererConfig, CornerStrategy;\nimport 'bar_renderer_decorator.dart' show BarRendererDecorator;\nimport 'base_bar_renderer.dart'\n    show\n        BaseBarRenderer,\n        allBarGroupWeightsKey,\n        barGroupCountKey,\n        barGroupIndexKey,\n        barGroupWeightKey,\n        previousBarGroupWeightKey;\nimport 'base_bar_renderer_element.dart'\n    show BaseAnimatedBar, BaseBarRendererElement;\n\n/// Renders series data as a series of bars.\nclass BarRenderer<D>\n    extends BaseBarRenderer<D, BarRendererElement<D>, AnimatedBar<D>> {\n  /// If we are grouped, use this spacing between the bars in a group.\n  final _barGroupInnerPadding = 2;\n\n  /// The padding between bar stacks.\n  ///\n  /// The padding comes out of the bottom of the bar.\n  final int _stackedBarPaddingPx;\n\n  final BarRendererDecorator<Object?>? barRendererDecorator;\n\n  factory BarRenderer({BarRendererConfig<D>? config, String? rendererId}) {\n    rendererId ??= 'bar';\n    config ??= BarRendererConfig();\n    return BarRenderer.internal(config: config, rendererId: rendererId);\n  }\n\n  /// This constructor is protected because it is used by child classes, which\n  /// cannot call the factory in their own constructors.\n  @protected\n  BarRenderer.internal({\n    required BarRendererConfig<Object?> config,\n    required String rendererId,\n  })   : barRendererDecorator = config.barRendererDecorator,\n        _stackedBarPaddingPx = config.stackedBarPaddingPx,\n        super(\n            config: config,\n            rendererId: rendererId,\n            layoutPaintOrder: config.layoutPaintOrder ?? 0);\n\n  @override\n  void configureSeries(List<MutableSeries<D>> seriesList) {\n    assignMissingColors(getOrderedSeriesList(seriesList),\n        emptyCategoryUsesSinglePalette: true);\n  }\n\n  @override\n  DatumDetails<D> addPositionToDetailsForSeriesDatum(\n      DatumDetails<D> details, SeriesDatum<D> seriesDatum) {\n    final series = details.series!;\n\n    final domainAxis = series.getAttr(domainAxisKey) as ImmutableAxis<D>;\n    final measureAxis = series.getAttr(measureAxisKey) as ImmutableAxis<num>;\n\n    final barGroupIndex = series.getAttr(barGroupIndexKey)!;\n    final previousBarGroupWeight = series.getAttr(previousBarGroupWeightKey);\n    final barGroupWeight = series.getAttr(barGroupWeightKey);\n    final allBarGroupWeights = series.getAttr(allBarGroupWeightsKey);\n    final numBarGroups = series.getAttr(barGroupCountKey)!;\n\n    final bounds = _getBarBounds(\n        details.domain,\n        domainAxis,\n        domainAxis.rangeBand.round(),\n        config.maxBarWidthPx,\n        details.measure,\n        details.measureOffset!,\n        measureAxis,\n        barGroupIndex,\n        previousBarGroupWeight,\n        barGroupWeight,\n        allBarGroupWeights,\n        numBarGroups);\n\n    NullablePoint chartPosition;\n\n    if (renderingVertically) {\n      chartPosition = NullablePoint(\n          (bounds.left + (bounds.width / 2)).toDouble(), bounds.top.toDouble());\n    } else {\n      chartPosition = NullablePoint(\n          isRtl ? bounds.left.toDouble() : bounds.right.toDouble(),\n          (bounds.top + (bounds.height / 2)).toDouble());\n    }\n\n    return DatumDetails.from(details,\n        chartPosition: chartPosition, bounds: bounds);\n  }\n\n  @override\n  BarRendererElement<D> getBaseDetails(dynamic datum, int index) {\n    return BarRendererElement<D>();\n  }\n\n  CornerStrategy get cornerStrategy {\n    return (config as BarRendererConfig).cornerStrategy;\n  }\n\n  /// Generates an [AnimatedBar] to represent the previous and current state\n  /// of one bar on the chart.\n  @override\n  AnimatedBar<D> makeAnimatedBar(\n      {required String key,\n      required ImmutableSeries<D> series,\n      List<int>? dashPattern,\n      dynamic datum,\n      Color? color,\n      required BarRendererElement<D> details,\n      D? domainValue,\n      required ImmutableAxis<D> domainAxis,\n      required int domainWidth,\n      num? measureValue,\n      required num measureOffsetValue,\n      required ImmutableAxis<num> measureAxis,\n      double? measureAxisPosition,\n      Color? fillColor,\n      FillPatternType? fillPattern,\n      double? strokeWidthPx,\n      required int barGroupIndex,\n      double? previousBarGroupWeight,\n      double? barGroupWeight,\n      List<double>? allBarGroupWeights,\n      required int numBarGroups,\n      bool? measureIsNull,\n      bool? measureIsNegative}) {\n    return AnimatedBar<D>(\n        key: key, datum: datum, series: series, domainValue: domainValue)\n      ..setNewTarget(makeBarRendererElement(\n          color: color,\n          dashPattern: dashPattern,\n          details: details,\n          domainValue: domainValue,\n          domainAxis: domainAxis,\n          domainWidth: domainWidth,\n          measureValue: measureValue,\n          measureOffsetValue: measureOffsetValue,\n          measureAxisPosition: measureAxisPosition,\n          measureAxis: measureAxis,\n          fillColor: fillColor,\n          fillPattern: fillPattern,\n          strokeWidthPx: strokeWidthPx,\n          barGroupIndex: barGroupIndex,\n          previousBarGroupWeight: previousBarGroupWeight,\n          barGroupWeight: barGroupWeight,\n          allBarGroupWeights: allBarGroupWeights,\n          numBarGroups: numBarGroups,\n          measureIsNull: measureIsNull,\n          measureIsNegative: measureIsNegative));\n  }\n\n  /// Generates a [BarRendererElement] to represent the rendering data for one\n  /// bar on the chart.\n  @override\n  BarRendererElement<D> makeBarRendererElement(\n      {Color? color,\n      List<int>? dashPattern,\n      required BarRendererElement<D> details,\n      D? domainValue,\n      required ImmutableAxis<D> domainAxis,\n      required int domainWidth,\n      num? measureValue,\n      required num measureOffsetValue,\n      required ImmutableAxis<num> measureAxis,\n      double? measureAxisPosition,\n      Color? fillColor,\n      FillPatternType? fillPattern,\n      double? strokeWidthPx,\n      required int barGroupIndex,\n      double? previousBarGroupWeight,\n      double? barGroupWeight,\n      List<double>? allBarGroupWeights,\n      required int numBarGroups,\n      bool? measureIsNull,\n      bool? measureIsNegative}) {\n    return BarRendererElement<D>()\n      ..color = color\n      ..dashPattern = dashPattern\n      ..fillColor = fillColor\n      ..fillPattern = fillPattern\n      ..measureAxisPosition = measureAxisPosition\n      ..roundPx = details.roundPx\n      ..strokeWidthPx = strokeWidthPx\n      ..measureIsNull = measureIsNull\n      ..measureIsNegative = measureIsNegative\n      ..bounds = _getBarBounds(\n          domainValue,\n          domainAxis,\n          domainWidth,\n          config.maxBarWidthPx,\n          measureValue,\n          measureOffsetValue,\n          measureAxis,\n          barGroupIndex,\n          previousBarGroupWeight,\n          barGroupWeight,\n          allBarGroupWeights,\n          numBarGroups);\n  }\n\n  @override\n  void paintBar(ChartCanvas canvas, double animationPercent,\n      Iterable<BarRendererElement<D>> barElements) {\n    final bars = <CanvasRect>[];\n\n    // When adjusting bars for stacked bar padding, do not modify the first bar\n    // if rendering vertically and do not modify the last bar if rendering\n    // horizontally.\n    final unmodifiedBar =\n        renderingVertically ? barElements.first : barElements.last;\n\n    // Find the max bar width from each segment to calculate corner radius.\n    var maxBarWidth = 0;\n\n    var measureIsNegative = false;\n\n    for (var bar in barElements) {\n      var bounds = bar.bounds;\n\n      measureIsNegative = measureIsNegative || bar.measureIsNegative!;\n\n      if (bar != unmodifiedBar) {\n        bounds = renderingVertically\n            ? Rectangle<int>(\n                bar.bounds!.left,\n                max(\n                    0,\n                    bar.bounds!.top +\n                        (measureIsNegative ? _stackedBarPaddingPx : 0)),\n                bar.bounds!.width,\n                max(0, bar.bounds!.height - _stackedBarPaddingPx),\n              )\n            : Rectangle<int>(\n                max(\n                    0,\n                    bar.bounds!.left +\n                        (measureIsNegative ? _stackedBarPaddingPx : 0)),\n                bar.bounds!.top,\n                max(0, bar.bounds!.width - _stackedBarPaddingPx),\n                bar.bounds!.height,\n              );\n      }\n\n      bars.add(CanvasRect(bounds!,\n          dashPattern: bar.dashPattern,\n          fill: bar.fillColor,\n          pattern: bar.fillPattern,\n          stroke: bar.color,\n          strokeWidthPx: bar.strokeWidthPx));\n\n      maxBarWidth =\n          max(maxBarWidth, renderingVertically ? bounds.width : bounds.height);\n    }\n\n    bool roundTopLeft;\n    bool roundTopRight;\n    bool roundBottomLeft;\n    bool roundBottomRight;\n\n    if (measureIsNegative) {\n      // Negative bars should be rounded towards the negative axis direction.\n      // In vertical mode, this is the bottom. In horizontal mode, this is the\n      // left side of the chart for LTR, or the right side for RTL.\n      roundTopLeft = !renderingVertically && !isRtl;\n      roundTopRight = !renderingVertically && isRtl;\n      roundBottomLeft = renderingVertically || !isRtl;\n      roundBottomRight = renderingVertically || isRtl;\n    } else {\n      // Positive bars should be rounded towards the positive axis direction.\n      // In vertical mode, this is the top. In horizontal mode, this is the\n      // right side of the chart for LTR, or the left side for RTL.\n      roundTopLeft = renderingVertically || isRtl;\n      roundTopRight = !isRtl;\n      roundBottomLeft = isRtl;\n      roundBottomRight = !(renderingVertically || isRtl);\n    }\n\n    final barStack = CanvasBarStack(\n      bars,\n      radius: cornerStrategy.getRadius(maxBarWidth),\n      stackedBarPadding: _stackedBarPaddingPx,\n      roundTopLeft: roundTopLeft,\n      roundTopRight: roundTopRight,\n      roundBottomLeft: roundBottomLeft,\n      roundBottomRight: roundBottomRight,\n    );\n\n    // If bar stack's range width is:\n    // * Within the component bounds, then draw the bar stack.\n    // * Partially out of component bounds, then clip the stack where it is out\n    // of bounds.\n    // * Fully out of component bounds, do not draw.\n\n    final componentBounds = this.componentBounds!;\n    final barOutsideBounds = renderingVertically\n        ? barStack.fullStackRect.left < componentBounds.left ||\n            barStack.fullStackRect.right > componentBounds.right\n        : barStack.fullStackRect.top < componentBounds.top ||\n            barStack.fullStackRect.bottom > componentBounds.bottom;\n\n    // TODO: When we have initial viewport, add image test for\n    // clipping.\n    if (barOutsideBounds) {\n      final clipBounds = _getBarStackBounds(barStack.fullStackRect);\n\n      // Do not draw the bar stack if it is completely outside of the component\n      // bounds.\n      if (clipBounds.width <= 0 || clipBounds.height <= 0) {\n        return;\n      }\n\n      canvas.setClipBounds(clipBounds);\n    }\n\n    canvas.drawBarStack(barStack, drawAreaBounds: componentBounds);\n\n    if (barOutsideBounds) {\n      canvas.resetClipBounds();\n    }\n\n    // Decorate the bar segments if there is a decorator.\n    barRendererDecorator?.decorate(barElements, canvas, graphicsFactory!,\n        drawBounds: drawBounds!,\n        animationPercent: animationPercent,\n        renderingVertically: renderingVertically,\n        rtl: isRtl);\n  }\n\n  /// Calculate the clipping region for a rectangle that represents the full bar\n  /// stack.\n  Rectangle<int> _getBarStackBounds(Rectangle<int> barStackRect) {\n    int left;\n    int right;\n    int top;\n    int bottom;\n\n    final componentBounds = this.componentBounds!;\n\n    if (renderingVertically) {\n      // Only clip at the start and end so that the bar's width stays within\n      // the viewport, but any bar decorations above the bar can still show.\n      left = max(componentBounds.left, barStackRect.left);\n      right = min(componentBounds.right, barStackRect.right);\n      top = barStackRect.top;\n      bottom = barStackRect.bottom;\n    } else {\n      // Only clip at the top and bottom so that the bar's height stays within\n      // the viewport, but any bar decorations to the right of the bar can still\n      // show.\n      left = barStackRect.left;\n      right = barStackRect.right;\n      top = max(componentBounds.top, barStackRect.top);\n      bottom = min(componentBounds.bottom, barStackRect.bottom);\n    }\n\n    final width = right - left;\n    final height = bottom - top;\n\n    return Rectangle(left, top, width, height);\n  }\n\n  /// Generates a set of bounds that describe a bar.\n  Rectangle<int> _getBarBounds(\n      D? domainValue,\n      ImmutableAxis<D> domainAxis,\n      int domainWidth,\n      int? maxBarWidthPx,\n      num? measureValue,\n      num measureOffsetValue,\n      ImmutableAxis<num> measureAxis,\n      int barGroupIndex,\n      double? previousBarGroupWeight,\n      double? barGroupWeight,\n      List<double>? allBarGroupWeights,\n      int numBarGroups) {\n    // TODO: Investigate why this is negative for a DateTime domain\n    // in RTL mode.\n    domainWidth = domainWidth.abs();\n\n    // If no weights were passed in, default to equal weight per bar.\n    if (barGroupWeight == null) {\n      barGroupWeight = 1 / numBarGroups;\n      previousBarGroupWeight = barGroupIndex * barGroupWeight;\n    }\n\n    // Calculate how wide each bar should be within the group of bars. If we\n    // only have one series, or are stacked, then barWidth should equal\n    // domainWidth.\n    final spacingLoss = _barGroupInnerPadding * (numBarGroups - 1);\n    var desiredWidth = ((domainWidth - spacingLoss) / numBarGroups).round();\n\n    if (maxBarWidthPx != null) {\n      desiredWidth = min(desiredWidth, maxBarWidthPx);\n      domainWidth = desiredWidth * numBarGroups + spacingLoss;\n    }\n\n    // If the series was configured with a weight pattern, treat the \"max\" bar\n    // width as the average max width. The overall total width will still equal\n    // max times number of bars, but this results in a nicer final picture.\n    var barWidth = desiredWidth;\n    if (allBarGroupWeights != null) {\n      barWidth =\n          (desiredWidth * numBarGroups * allBarGroupWeights[barGroupIndex])\n              .round();\n    }\n\n    // Make sure that bars are at least one pixel wide, so that they will always\n    // be visible on the chart. Ideally we should do something clever with the\n    // size of the chart, and the density and periodicity of the data, but this\n    // at least ensures that dense charts still have visible data.\n    barWidth = max(1, barWidth);\n\n    // Flip bar group index for calculating location on the domain axis if RTL.\n    final adjustedBarGroupIndex =\n        isRtl ? numBarGroups - barGroupIndex - 1 : barGroupIndex;\n\n    // Calculate the start and end of the bar, taking into account accumulated\n    // padding for grouped bars.\n    final previousAverageWidth = adjustedBarGroupIndex > 0\n        ? ((domainWidth - spacingLoss) *\n                (previousBarGroupWeight! / adjustedBarGroupIndex))\n            .round()\n        : 0;\n\n    final domainStart = (domainAxis.getLocation(domainValue)! -\n            (domainWidth / 2) +\n            (previousAverageWidth + _barGroupInnerPadding) *\n                adjustedBarGroupIndex)\n        .round();\n\n    final domainEnd = domainStart + barWidth;\n\n    measureValue ??= 0;\n\n    // Calculate measure locations. Stacked bars should have their\n    // offset calculated previously.\n    int measureStart;\n    int measureEnd;\n    if (measureValue < 0) {\n      measureEnd = measureAxis.getLocation(measureOffsetValue)!.round();\n      measureStart =\n          measureAxis.getLocation(measureValue + measureOffsetValue)!.round();\n    } else {\n      measureStart = measureAxis.getLocation(measureOffsetValue)!.round();\n      measureEnd =\n          measureAxis.getLocation(measureValue + measureOffsetValue)!.round();\n    }\n\n    Rectangle<int> bounds;\n    if (renderingVertically) {\n      // Rectangle clamps to zero width/height\n      bounds = Rectangle<int>(domainStart, measureEnd, domainEnd - domainStart,\n          measureStart - measureEnd);\n    } else {\n      // Rectangle clamps to zero width/height\n      bounds = Rectangle<int>(min(measureStart, measureEnd), domainStart,\n          (measureEnd - measureStart).abs(), domainEnd - domainStart);\n    }\n    return bounds;\n  }\n\n  @override\n  Rectangle<int>? getBoundsForBar(BarRendererElement<D> bar) => bar.bounds;\n}\n\nabstract class ImmutableBarRendererElement<D> {\n  ImmutableSeries<D>? get series;\n\n  dynamic get datum;\n\n  int? get index;\n\n  Rectangle<int>? get bounds;\n}\n\nclass BarRendererElement<D> extends BaseBarRendererElement\n    implements ImmutableBarRendererElement<D> {\n  @override\n  ImmutableSeries<D>? series;\n\n  @override\n  Rectangle<int>? bounds;\n\n  int? roundPx;\n\n  @override\n  int? index;\n\n  dynamic _datum;\n\n  @override\n  dynamic get datum => _datum;\n\n  set datum(dynamic datum) {\n    _datum = datum;\n    index = series?.data.indexOf(datum);\n  }\n\n  BarRendererElement();\n\n  BarRendererElement.clone(BarRendererElement<D> other) : super.clone(other) {\n    series = other.series;\n    bounds = other.bounds;\n    roundPx = other.roundPx;\n    index = other.index;\n    _datum = other._datum;\n  }\n\n  @override\n  void updateAnimationPercent(BaseBarRendererElement previous,\n      BaseBarRendererElement target, double animationPercent) {\n    final localPrevious = previous as BarRendererElement<D>;\n    final localTarget = target as BarRendererElement<D>;\n\n    final previousBounds = localPrevious.bounds!;\n    final targetBounds = localTarget.bounds!;\n\n    var top = ((targetBounds.top - previousBounds.top) * animationPercent) +\n        previousBounds.top;\n    var right =\n        ((targetBounds.right - previousBounds.right) * animationPercent) +\n            previousBounds.right;\n    var bottom =\n        ((targetBounds.bottom - previousBounds.bottom) * animationPercent) +\n            previousBounds.bottom;\n    var left = ((targetBounds.left - previousBounds.left) * animationPercent) +\n        previousBounds.left;\n\n    bounds = Rectangle<int>(left.round(), top.round(), (right - left).round(),\n        (bottom - top).round());\n\n    roundPx = localTarget.roundPx;\n\n    super.updateAnimationPercent(previous, target, animationPercent);\n  }\n}\n\nclass AnimatedBar<D> extends BaseAnimatedBar<D, BarRendererElement<D>> {\n  AnimatedBar(\n      {required String key,\n      required dynamic datum,\n      required ImmutableSeries<D> series,\n      required D? domainValue})\n      : super(key: key, datum: datum, series: series, domainValue: domainValue);\n\n  @override\n  void animateElementToMeasureAxisPosition(BaseBarRendererElement target) {\n    final localTarget = target as BarRendererElement<D>;\n\n    // TODO: Animate out bars in the middle of a stack.\n    localTarget.bounds = Rectangle<int>(\n        localTarget.bounds!.left + (localTarget.bounds!.width / 2).round(),\n        localTarget.measureAxisPosition!.round(),\n        0,\n        0);\n  }\n\n  @override\n  BarRendererElement<D> getCurrentBar(double animationPercent) {\n    final bar = super.getCurrentBar(animationPercent);\n\n    // Update with series and datum information to pass to bar decorator.\n    bar.series = series;\n    bar.datum = datum;\n\n    return bar;\n  }\n\n  @override\n  BarRendererElement<D> clone(BarRendererElement<D> bar) =>\n      BarRendererElement<D>.clone(bar);\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/bar/bar_renderer_config.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport '../../common/symbol_renderer.dart';\nimport '../common/chart_canvas.dart' show FillPatternType;\nimport '../layout/layout_view.dart' show LayoutViewPaintOrder;\nimport 'bar_renderer.dart' show BarRenderer;\nimport 'bar_renderer_decorator.dart' show BarRendererDecorator;\nimport 'base_bar_renderer_config.dart'\n    show BarGroupingType, BaseBarRendererConfig;\n\n/// Configuration for a bar renderer.\nclass BarRendererConfig<D> extends BaseBarRendererConfig<D> {\n  /// Strategy for determining the corner radius of a bar.\n  final CornerStrategy cornerStrategy;\n\n  /// Decorator for optionally decorating painted bars.\n  final BarRendererDecorator<D>? barRendererDecorator;\n\n  BarRendererConfig({\n    String? customRendererId,\n    CornerStrategy? cornerStrategy,\n    FillPatternType? fillPattern,\n    BarGroupingType? groupingType,\n    int layoutPaintOrder = LayoutViewPaintOrder.bar,\n    int minBarLengthPx = 0,\n    int? maxBarWidthPx,\n    int stackedBarPaddingPx = 1,\n    double strokeWidthPx = 0.0,\n    this.barRendererDecorator,\n    SymbolRenderer? symbolRenderer,\n    List<int>? weightPattern,\n  })  : cornerStrategy = cornerStrategy ?? const ConstCornerStrategy(2),\n        super(\n          customRendererId: customRendererId,\n          groupingType: groupingType ?? BarGroupingType.grouped,\n          layoutPaintOrder: layoutPaintOrder,\n          minBarLengthPx: minBarLengthPx,\n          maxBarWidthPx: maxBarWidthPx,\n          fillPattern: fillPattern,\n          stackedBarPaddingPx: stackedBarPaddingPx,\n          strokeWidthPx: strokeWidthPx,\n          symbolRenderer: symbolRenderer,\n          weightPattern: weightPattern,\n        );\n\n  @override\n  BarRenderer<D> build() {\n    return BarRenderer<D>(config: this, rendererId: customRendererId);\n  }\n\n  @override\n  bool operator ==(Object other) {\n    if (identical(this, other)) {\n      return true;\n    }\n    return other is BarRendererConfig &&\n        other.cornerStrategy == cornerStrategy &&\n        super == other;\n  }\n\n  @override\n  int get hashCode {\n    var hash = super.hashCode;\n    hash = hash * 31 + cornerStrategy.hashCode;\n    return hash;\n  }\n}\n\nabstract class CornerStrategy {\n  /// Returns the radius of the rounded corners in pixels.\n  int getRadius(int barWidth);\n}\n\n/// Strategy for constant corner radius.\nclass ConstCornerStrategy implements CornerStrategy {\n  final int radius;\n\n  const ConstCornerStrategy(this.radius);\n\n  @override\n  int getRadius(_) => radius;\n\n  @override\n  bool operator ==(Object other) {\n    if (identical(this, other)) {\n      return true;\n    }\n    return other is ConstCornerStrategy && other.radius == radius;\n  }\n\n  @override\n  int get hashCode => radius.hashCode;\n}\n\n/// Strategy for no corner radius.\nclass NoCornerStrategy extends ConstCornerStrategy {\n  const NoCornerStrategy() : super(0);\n\n  @override\n  bool operator ==(other) => other is NoCornerStrategy;\n\n  @override\n  int get hashCode => 31;\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/bar/bar_renderer_decorator.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math' show Rectangle;\n\nimport '../../common/graphics_factory.dart' show GraphicsFactory;\nimport '../common/chart_canvas.dart' show ChartCanvas;\nimport 'bar_renderer.dart' show ImmutableBarRendererElement;\n\n/// Decorates bars after the bars have already been painted.\nabstract class BarRendererDecorator<D> {\n  const BarRendererDecorator();\n\n  void decorate(Iterable<ImmutableBarRendererElement<D>> barElements,\n      ChartCanvas canvas, GraphicsFactory graphicsFactory,\n      {required Rectangle<int> drawBounds,\n      required double animationPercent,\n      required bool renderingVertically,\n      bool rtl = false});\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/bar/bar_target_line_renderer.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math' show Point, Rectangle, max, min;\n\nimport '../../common/color.dart' show Color;\nimport '../../common/math.dart' show NullablePoint;\nimport '../cartesian/axis/axis.dart'\n    show ImmutableAxis, domainAxisKey, measureAxisKey;\nimport '../common/chart_canvas.dart' show ChartCanvas, FillPatternType;\nimport '../common/datum_details.dart' show DatumDetails;\nimport '../common/processed_series.dart' show ImmutableSeries, MutableSeries;\nimport '../common/series_datum.dart' show SeriesDatum;\nimport '../layout/layout_view.dart' show LayoutViewPaintOrder;\nimport 'bar_target_line_renderer_config.dart' show BarTargetLineRendererConfig;\nimport 'base_bar_renderer.dart'\n    show\n        BaseBarRenderer,\n        allBarGroupWeightsKey,\n        barGroupWeightKey,\n        barGroupCountKey,\n        barGroupIndexKey,\n        previousBarGroupWeightKey;\nimport 'base_bar_renderer_element.dart'\n    show BaseAnimatedBar, BaseBarRendererElement;\n\n/// Renders series data as a series of bar target lines.\n///\n/// Usually paired with a BarRenderer to display target metrics alongside actual\n/// metrics.\nclass BarTargetLineRenderer<D> extends BaseBarRenderer<D,\n    _BarTargetLineRendererElement, _AnimatedBarTargetLine<D>> {\n  /// If we are grouped, use this spacing between the bars in a group.\n  final _barGroupInnerPadding = 2;\n\n  /// Standard color for all bar target lines.\n  final _color = Color(r: 0, g: 0, b: 0, a: 153);\n\n  factory BarTargetLineRenderer({\n    BarTargetLineRendererConfig<D>? config,\n    String? rendererId,\n  }) {\n    config ??= BarTargetLineRendererConfig<D>();\n    rendererId ??= 'barTargetLine';\n    return BarTargetLineRenderer._internal(\n        config: config, rendererId: rendererId);\n  }\n\n  BarTargetLineRenderer._internal({\n    required BarTargetLineRendererConfig<D> config,\n    required String rendererId,\n  }) : super(\n            config: config,\n            rendererId: rendererId,\n            layoutPaintOrder:\n                config.layoutPaintOrder ?? LayoutViewPaintOrder.barTargetLine);\n\n  @override\n  void configureSeries(List<MutableSeries<D>> seriesList) {\n    seriesList.forEach((MutableSeries<D> series) {\n      series.colorFn ??= (_) => _color;\n      series.fillColorFn ??= (_) => _color;\n\n      // Fill in missing seriesColor values with the color of the first datum in\n      // the series. Note that [Series.colorFn] should always return a color.\n      if (series.seriesColor == null) {\n        try {\n          series.seriesColor = series.colorFn!(0);\n        } catch (exception) {\n          series.seriesColor = _color;\n        }\n      }\n    });\n  }\n\n  @override\n  DatumDetails<D> addPositionToDetailsForSeriesDatum(\n      DatumDetails<D> details, SeriesDatum<D> seriesDatum) {\n    final series = details.series!;\n\n    final domainAxis = series.getAttr(domainAxisKey) as ImmutableAxis<D>;\n    final measureAxis = series.getAttr(measureAxisKey) as ImmutableAxis<num>;\n\n    final barGroupIndex = series.getAttr(barGroupIndexKey)!;\n    final previousBarGroupWeight = series.getAttr(previousBarGroupWeightKey);\n    final barGroupWeight = series.getAttr(barGroupWeightKey);\n    final allBarGroupWeights = series.getAttr(allBarGroupWeightsKey);\n    final numBarGroups = series.getAttr(barGroupCountKey)!;\n\n    final points = _getTargetLinePoints(\n        details.domain,\n        domainAxis,\n        domainAxis.rangeBand.round(),\n        config.maxBarWidthPx,\n        details.measure,\n        details.measureOffset!,\n        measureAxis,\n        barGroupIndex,\n        previousBarGroupWeight,\n        barGroupWeight,\n        allBarGroupWeights,\n        numBarGroups);\n\n    NullablePoint chartPosition;\n\n    if (renderingVertically) {\n      chartPosition = NullablePoint(\n          (points[0].x + (points[1].x - points[0].x) / 2).toDouble(),\n          points[0].y.toDouble());\n    } else {\n      chartPosition = NullablePoint(points[0].x.toDouble(),\n          (points[0].y + (points[1].y - points[0].y) / 2).toDouble());\n    }\n\n    return DatumDetails.from(details, chartPosition: chartPosition);\n  }\n\n  @override\n  _BarTargetLineRendererElement getBaseDetails(dynamic datum, int index) {\n    final localConfig = config as BarTargetLineRendererConfig<D>;\n    return _BarTargetLineRendererElement(\n        roundEndCaps: localConfig.roundEndCaps);\n  }\n\n  /// Generates an [_AnimatedBarTargetLine] to represent the previous and\n  /// current state of one bar target line on the chart.\n  @override\n  _AnimatedBarTargetLine<D> makeAnimatedBar(\n      {required String key,\n      required ImmutableSeries<D> series,\n      dynamic datum,\n      Color? color,\n      List<int>? dashPattern,\n      required _BarTargetLineRendererElement details,\n      D? domainValue,\n      required ImmutableAxis<D> domainAxis,\n      required int domainWidth,\n      num? measureValue,\n      required num measureOffsetValue,\n      required ImmutableAxis<num> measureAxis,\n      double? measureAxisPosition,\n      Color? fillColor,\n      FillPatternType? fillPattern,\n      required int barGroupIndex,\n      double? previousBarGroupWeight,\n      double? barGroupWeight,\n      List<double>? allBarGroupWeights,\n      required int numBarGroups,\n      double? strokeWidthPx,\n      bool? measureIsNull,\n      bool? measureIsNegative}) {\n    return _AnimatedBarTargetLine(\n        key: key, datum: datum, series: series, domainValue: domainValue)\n      ..setNewTarget(makeBarRendererElement(\n          color: color,\n          details: details,\n          dashPattern: dashPattern,\n          domainValue: domainValue,\n          domainAxis: domainAxis,\n          domainWidth: domainWidth,\n          measureValue: measureValue,\n          measureOffsetValue: measureOffsetValue,\n          measureAxisPosition: measureAxisPosition,\n          measureAxis: measureAxis,\n          fillColor: fillColor,\n          fillPattern: fillPattern,\n          strokeWidthPx: strokeWidthPx,\n          barGroupIndex: barGroupIndex,\n          previousBarGroupWeight: previousBarGroupWeight,\n          barGroupWeight: barGroupWeight,\n          allBarGroupWeights: allBarGroupWeights,\n          numBarGroups: numBarGroups,\n          measureIsNull: measureIsNull,\n          measureIsNegative: measureIsNegative));\n  }\n\n  /// Generates a [_BarTargetLineRendererElement] to represent the rendering\n  /// data for one bar target line on the chart.\n  @override\n  _BarTargetLineRendererElement makeBarRendererElement(\n      {Color? color,\n      List<int>? dashPattern,\n      required _BarTargetLineRendererElement details,\n      D? domainValue,\n      required ImmutableAxis<D> domainAxis,\n      required int domainWidth,\n      num? measureValue,\n      required num measureOffsetValue,\n      required ImmutableAxis<num> measureAxis,\n      double? measureAxisPosition,\n      Color? fillColor,\n      FillPatternType? fillPattern,\n      double? strokeWidthPx,\n      required int barGroupIndex,\n      double? previousBarGroupWeight,\n      double? barGroupWeight,\n      List<double>? allBarGroupWeights,\n      required int numBarGroups,\n      bool? measureIsNull,\n      bool? measureIsNegative}) {\n    return _BarTargetLineRendererElement(roundEndCaps: details.roundEndCaps)\n      ..color = color\n      ..dashPattern = dashPattern\n      ..fillColor = fillColor\n      ..fillPattern = fillPattern\n      ..measureAxisPosition = measureAxisPosition\n      ..strokeWidthPx = strokeWidthPx\n      ..measureIsNull = measureIsNull\n      ..measureIsNegative = measureIsNegative\n      ..points = _getTargetLinePoints(\n          domainValue,\n          domainAxis,\n          domainWidth,\n          config.maxBarWidthPx,\n          measureValue,\n          measureOffsetValue,\n          measureAxis,\n          barGroupIndex,\n          previousBarGroupWeight,\n          barGroupWeight,\n          allBarGroupWeights,\n          numBarGroups);\n  }\n\n  @override\n  void paintBar(\n    ChartCanvas canvas,\n    double animationPercent,\n    Iterable<_BarTargetLineRendererElement> barElements,\n  ) {\n    barElements.forEach((_BarTargetLineRendererElement bar) {\n      // TODO: Combine common line attributes into\n      // GraphicsFactory.lineStyle or similar.\n      canvas.drawLine(\n          clipBounds: drawBounds,\n          points: bar.points,\n          stroke: bar.color,\n          roundEndCaps: bar.roundEndCaps,\n          strokeWidthPx: bar.strokeWidthPx,\n          dashPattern: bar.dashPattern);\n    });\n  }\n\n  /// Generates a set of points that describe a bar target line.\n  List<Point<int>> _getTargetLinePoints(\n      D? domainValue,\n      ImmutableAxis<D> domainAxis,\n      int domainWidth,\n      int? maxBarWidthPx,\n      num? measureValue,\n      num measureOffsetValue,\n      ImmutableAxis<num> measureAxis,\n      int barGroupIndex,\n      double? previousBarGroupWeight,\n      double? barGroupWeight,\n      List<double>? allBarGroupWeights,\n      int numBarGroups) {\n    // If no weights were passed in, default to equal weight per bar.\n    if (barGroupWeight == null) {\n      barGroupWeight = 1 / numBarGroups;\n      previousBarGroupWeight = barGroupIndex * barGroupWeight;\n    }\n\n    final localConfig = config as BarTargetLineRendererConfig<D>;\n\n    // Calculate how wide each bar target line should be within the group of\n    // bar target lines. If we only have one series, or are stacked, then\n    // barWidth should equal domainWidth.\n    var spacingLoss = _barGroupInnerPadding * (numBarGroups - 1);\n    var desiredWidth = ((domainWidth - spacingLoss) / numBarGroups).round();\n\n    if (maxBarWidthPx != null) {\n      desiredWidth = min(desiredWidth, maxBarWidthPx);\n      domainWidth = desiredWidth * numBarGroups + spacingLoss;\n    }\n\n    // If the series was configured with a weight pattern, treat the \"max\" bar\n    // width as the average max width. The overall total width will still equal\n    // max times number of bars, but this results in a nicer final picture.\n    var barWidth = desiredWidth;\n    if (allBarGroupWeights != null) {\n      barWidth =\n          (desiredWidth * numBarGroups * allBarGroupWeights[barGroupIndex])\n              .floor();\n    }\n    // Get the overdraw boundaries.\n    var overDrawOuterPx = localConfig.overDrawOuterPx;\n    var overDrawPx = localConfig.overDrawPx;\n\n    var overDrawStartPx = (barGroupIndex == 0) && overDrawOuterPx != null\n        ? overDrawOuterPx\n        : overDrawPx;\n\n    var overDrawEndPx =\n        (barGroupIndex == numBarGroups - 1) && overDrawOuterPx != null\n            ? overDrawOuterPx\n            : overDrawPx;\n\n    // Flip bar group index for calculating location on the domain axis if RTL.\n    final adjustedBarGroupIndex =\n        isRtl ? numBarGroups - barGroupIndex - 1 : barGroupIndex;\n\n    // Calculate the start and end of the bar target line, taking into account\n    // accumulated padding for grouped bars.\n    num previousAverageWidth = adjustedBarGroupIndex > 0\n        ? ((domainWidth - spacingLoss) *\n                (previousBarGroupWeight! / adjustedBarGroupIndex))\n            .round()\n        : 0;\n\n    var domainStart = (domainAxis.getLocation(domainValue)! -\n            (domainWidth / 2) +\n            (previousAverageWidth + _barGroupInnerPadding) *\n                adjustedBarGroupIndex -\n            overDrawStartPx)\n        .round();\n\n    var domainEnd = domainStart + barWidth + overDrawStartPx + overDrawEndPx;\n\n    measureValue = measureValue ?? 0;\n\n    // Calculate measure locations. Stacked bars should have their\n    // offset calculated previously.\n    var measureStart =\n        measureAxis.getLocation(measureValue + measureOffsetValue)!.round();\n\n    List<Point<int>> points;\n    if (renderingVertically) {\n      points = [\n        Point<int>(domainStart, measureStart),\n        Point<int>(domainEnd, measureStart)\n      ];\n    } else {\n      points = [\n        Point<int>(measureStart, domainStart),\n        Point<int>(measureStart, domainEnd)\n      ];\n    }\n    return points;\n  }\n\n  @override\n  Rectangle<int> getBoundsForBar(_BarTargetLineRendererElement bar) {\n    final points = bar.points;\n    assert(points.isNotEmpty);\n    var top = points.first.y;\n    var bottom = points.first.y;\n    var left = points.first.x;\n    var right = points.first.x;\n    for (final point in points.skip(1)) {\n      top = min(top, point.y);\n      left = min(left, point.x);\n      bottom = max(bottom, point.y);\n      right = max(right, point.x);\n    }\n    return Rectangle<int>(left, top, right - left, bottom - top);\n  }\n}\n\nclass _BarTargetLineRendererElement extends BaseBarRendererElement {\n  late List<Point<int>> points;\n\n  bool roundEndCaps;\n\n  _BarTargetLineRendererElement({required this.roundEndCaps});\n\n  _BarTargetLineRendererElement.clone(_BarTargetLineRendererElement other)\n      : points = List.of(other.points),\n        roundEndCaps = other.roundEndCaps,\n        super.clone(other);\n\n  @override\n  void updateAnimationPercent(BaseBarRendererElement previous,\n      BaseBarRendererElement target, double animationPercent) {\n    final localPrevious = previous as _BarTargetLineRendererElement;\n    final localTarget = target as _BarTargetLineRendererElement;\n\n    final previousPoints = localPrevious.points;\n    final targetPoints = localTarget.points;\n\n    late Point<int> lastPoint;\n\n    int pointIndex;\n    for (pointIndex = 0; pointIndex < targetPoints.length; pointIndex++) {\n      var targetPoint = targetPoints[pointIndex];\n\n      // If we have more points than the previous line, animate in the new point\n      // by starting its measure position at the last known official point.\n      Point<int> previousPoint;\n      if (previousPoints.length - 1 >= pointIndex) {\n        previousPoint = previousPoints[pointIndex];\n        lastPoint = previousPoint;\n      } else {\n        previousPoint = Point<int>(targetPoint.x, lastPoint.y);\n      }\n\n      var x = ((targetPoint.x - previousPoint.x) * animationPercent) +\n          previousPoint.x;\n\n      var y = ((targetPoint.y - previousPoint.y) * animationPercent) +\n          previousPoint.y;\n\n      if (points.length - 1 >= pointIndex) {\n        points[pointIndex] = Point<int>(x.round(), y.round());\n      } else {\n        points.add(Point<int>(x.round(), y.round()));\n      }\n    }\n\n    // Removing extra points that don't exist anymore.\n    if (pointIndex < points.length) {\n      points.removeRange(pointIndex, points.length);\n    }\n\n    strokeWidthPx =\n        ((localTarget.strokeWidthPx! - localPrevious.strokeWidthPx!) *\n                animationPercent) +\n            localPrevious.strokeWidthPx!;\n\n    roundEndCaps = localTarget.roundEndCaps;\n\n    super.updateAnimationPercent(previous, target, animationPercent);\n  }\n}\n\nclass _AnimatedBarTargetLine<D>\n    extends BaseAnimatedBar<D, _BarTargetLineRendererElement> {\n  _AnimatedBarTargetLine(\n      {required String key,\n      required dynamic datum,\n      required ImmutableSeries<D> series,\n      required D? domainValue})\n      : super(key: key, datum: datum, series: series, domainValue: domainValue);\n\n  @override\n  void animateElementToMeasureAxisPosition(BaseBarRendererElement target) {\n    final localTarget = target as _BarTargetLineRendererElement;\n\n    final newPoints = <Point<int>>[];\n    for (var index = 0; index < localTarget.points.length; index++) {\n      final targetPoint = localTarget.points[index];\n\n      newPoints.add(\n          Point<int>(targetPoint.x, localTarget.measureAxisPosition!.round()));\n    }\n    localTarget.points = newPoints;\n  }\n\n  @override\n  _BarTargetLineRendererElement clone(_BarTargetLineRendererElement bar) =>\n      _BarTargetLineRendererElement.clone(bar);\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/bar/bar_target_line_renderer_config.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport '../../common/symbol_renderer.dart'\n    show SymbolRenderer, LineSymbolRenderer;\nimport '../layout/layout_view.dart' show LayoutViewPaintOrder;\nimport 'bar_target_line_renderer.dart' show BarTargetLineRenderer;\nimport 'base_bar_renderer_config.dart'\n    show BarGroupingType, BaseBarRendererConfig;\n\n/// Configuration for a bar target line renderer.\nclass BarTargetLineRendererConfig<D> extends BaseBarRendererConfig<D> {\n  /// The number of pixels that the line will extend beyond the bandwidth at the\n  /// edges of the bar group.\n  ///\n  /// If set, this overrides overDrawPx for the beginning side of the first bar\n  /// target line in the group, and the ending side of the last bar target line.\n  /// overDrawPx will be used for overdrawing the target lines for interior\n  /// sides of the bars.\n  final int? overDrawOuterPx;\n\n  /// The number of pixels that the line will extend beyond the bandwidth for\n  /// every bar in a group.\n  final int overDrawPx;\n\n  /// Whether target lines should have round end caps, or square if false.\n  final bool roundEndCaps;\n\n  BarTargetLineRendererConfig(\n      {String? customRendererId,\n      List<int>? dashPattern,\n      BarGroupingType groupingType = BarGroupingType.grouped,\n      int layoutPaintOrder = LayoutViewPaintOrder.barTargetLine,\n      int minBarLengthPx = 0,\n      this.overDrawOuterPx,\n      this.overDrawPx = 0,\n      this.roundEndCaps = true,\n      double strokeWidthPx = 3.0,\n      SymbolRenderer? symbolRenderer,\n      List<int>? weightPattern})\n      : super(\n          customRendererId: customRendererId,\n          dashPattern: dashPattern,\n          groupingType: groupingType,\n          layoutPaintOrder: layoutPaintOrder,\n          minBarLengthPx: minBarLengthPx,\n          strokeWidthPx: strokeWidthPx,\n          symbolRenderer: symbolRenderer ?? LineSymbolRenderer(),\n          weightPattern: weightPattern,\n        );\n\n  @override\n  BarTargetLineRenderer<D> build() {\n    return BarTargetLineRenderer<D>(config: this, rendererId: customRendererId);\n  }\n\n  @override\n  bool operator ==(Object other) {\n    if (identical(this, other)) {\n      return true;\n    }\n    return other is BarTargetLineRendererConfig &&\n        other.overDrawOuterPx == overDrawOuterPx &&\n        other.overDrawPx == overDrawPx &&\n        other.roundEndCaps == roundEndCaps &&\n        super == other;\n  }\n\n  @override\n  int get hashCode {\n    var hash = 1;\n    hash = hash * 31 + overDrawOuterPx.hashCode;\n    hash = hash * 31 + overDrawPx.hashCode;\n    hash = hash * 31 + roundEndCaps.hashCode;\n    return hash;\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/bar/base_bar_renderer.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:collection' show LinkedHashMap, HashSet;\nimport 'dart:math' show Point, Rectangle, max;\n\nimport 'package:collection/collection.dart' show IterableExtension;\nimport 'package:meta/meta.dart' show protected;\n\nimport '../../common/color.dart' show Color;\nimport '../../common/math.dart' show clamp;\nimport '../../data/series.dart' show AttributeKey;\nimport '../cartesian/axis/axis.dart'\n    show ImmutableAxis, OrdinalAxis, domainAxisKey, measureAxisKey;\nimport '../cartesian/axis/scale.dart' show RangeBandConfig;\nimport '../cartesian/cartesian_renderer.dart' show BaseCartesianRenderer;\nimport '../common/chart_canvas.dart' show ChartCanvas, FillPatternType;\nimport '../common/datum_details.dart' show DatumDetails;\nimport '../common/processed_series.dart' show ImmutableSeries, MutableSeries;\nimport 'base_bar_renderer_config.dart' show BaseBarRendererConfig;\nimport 'base_bar_renderer_element.dart'\n    show BaseAnimatedBar, BaseBarRendererElement;\n\nconst barGroupIndexKey = AttributeKey<int>('BarRenderer.barGroupIndex');\n\nconst barGroupCountKey = AttributeKey<int>('BarRenderer.barGroupCount');\n\nconst barGroupWeightKey = AttributeKey<double>('BarRenderer.barGroupWeight');\n\nconst previousBarGroupWeightKey =\n    AttributeKey<double>('BarRenderer.previousBarGroupWeight');\n\nconst allBarGroupWeightsKey =\n    AttributeKey<List<double>>('BarRenderer.allBarGroupWeights');\n\nconst stackKeyKey = AttributeKey<String>('BarRenderer.stackKey');\n\nconst barElementsKey =\n    AttributeKey<List<BaseBarRendererElement>>('BarRenderer.elements');\n\n/// Base class for bar renderers that implements common stacking and grouping\n/// logic.\n///\n/// Bar renderers support 4 different modes of rendering multiple series on the\n/// chart, configured by the grouped and stacked flags.\n/// * grouped - Render bars for each series that shares a domain value\n///   side-by-side.\n/// * stacked - Render bars for each series that shares a domain value in a\n///   stack, ordered in the same order as the series list.\n/// * grouped-stacked: Render bars for each series that shares a domain value in\n///   a group of bar stacks. Each stack will contain all the series that share a\n///   series category.\n/// * floating style - When grouped and stacked are both false, all bars that\n///   share a domain value will be rendered in the same domain space. Each datum\n///   should be configured with a measure offset to position its bar along the\n///   measure axis. Bars will freely overlap if their measure values and measure\n///   offsets overlap. Note that bars for each series will be rendered in order,\n///   such that bars from the last series will be \"on top\" of bars from previous\n///   series.\nabstract class BaseBarRenderer<D, R extends BaseBarRendererElement,\n    B extends BaseAnimatedBar<D, R>> extends BaseCartesianRenderer<D> {\n  // `config` can't be a `BaseBarRendererConfig<D>` because `BarLaneRenderer<D>`\n  // passes a `BarLaneRendererConfig`, but `BarLaneRendererConfig` is a\n  // `BarRendererConfig<String>`.\n  final BaseBarRendererConfig<Object?> config;\n\n  // Save the chart.vertical value at the start of every draw cycle. If it\n  // changes, delete all of the cached rendering element information so that we\n  // start with a fresh state.\n  var _lastVertical = true;\n\n  /// Store a map of domain+barGroupIndex+category index to bars in a stack.\n  ///\n  /// This map is used to render all the bars in a stack together, to account\n  /// for rendering effects that need to take the full stack into account (e.g.\n  /// corner rounding).\n  ///\n  /// [LinkedHashMap] is used to render the bars on the canvas in the same order\n  /// as the data was given to the chart. For the case where both grouping and\n  /// stacking are disabled, this means that bars for data later in the series\n  /// will be drawn \"on top of\" bars earlier in the series.\n  // ignore: prefer_collection_literals, https://github.com/dart-lang/linter/issues/1649\n  final _barStackMap = LinkedHashMap<String, List<B>>();\n\n  // Store a list of bar stacks that exist in the series data.\n  //\n  // This list will be used to remove any AnimatingBars that were rendered in\n  // previous draw cycles, but no longer have a corresponding datum in the new\n  // data.\n  final _currentKeys = <String>[];\n\n  /// Stores a list of stack keys for each group key.\n  // ignore: prefer_collection_literals, https://github.com/dart-lang/linter/issues/1649\n  final _currentGroupsStackKeys = LinkedHashMap<D, Set<String>>();\n\n  /// Optimization for getNearest to avoid scanning all data if possible.\n  ImmutableAxis<D>? _prevDomainAxis;\n\n  BaseBarRenderer(\n      {required this.config,\n      required String rendererId,\n      required int layoutPaintOrder})\n      : super(\n          rendererId: rendererId,\n          layoutPaintOrder: layoutPaintOrder,\n          symbolRenderer: config.symbolRenderer,\n        );\n\n  @override\n  void preprocessSeries(List<MutableSeries<D>> seriesList) {\n    // If the orientation of the chart changed, delete all data from the last\n    // draw cycle. This allows us to start in a fresh state, so that we do not\n    // get bad animations from the previously drawn data.\n    //\n    // Ideally we should animate the old bars out smoothly in some ways, but\n    // this was the cheapest option.\n    if (_lastVertical != chart.vertical) {\n      _barStackMap.clear();\n      _currentKeys.clear();\n      _currentGroupsStackKeys.clear();\n    }\n\n    _lastVertical = chart.vertical;\n\n    var barGroupIndex = 0;\n\n    // Maps used to store the final measure offset of the previous series, for\n    // each domain value.\n    final posDomainToStackKeyToDetailsMap =\n        <D, Map<String, BaseBarRendererElement>>{};\n    final negDomainToStackKeyToDetailsMap =\n        <D, Map<String, BaseBarRendererElement>>{};\n    final categoryToIndexMap = <String, int>{};\n\n    // Keep track of the largest bar stack size. This should be 1 for grouped\n    // bars, and it should be the size of the tallest stack for stacked or\n    // grouped stacked bars.\n    var maxBarStackSize = 0;\n\n    final orderedSeriesList = getOrderedSeriesList(seriesList);\n\n    orderedSeriesList.forEach((MutableSeries<D> series) {\n      var elements = <BaseBarRendererElement>[];\n\n      var domainFn = series.domainFn;\n      var measureFn = series.measureFn;\n      var measureOffsetFn = series.measureOffsetFn;\n      var fillPatternFn = series.fillPatternFn;\n      var strokeWidthPxFn = series.strokeWidthPxFn;\n\n      series.dashPatternFn ??= (_) => config.dashPattern;\n\n      // Identifies which stack the series will go in, by default a single\n      // stack.\n      var stackKey = '__defaultKey__';\n\n      // Override the stackKey with seriesCategory if we are GROUPED_STACKED\n      // so we have a way to choose which series go into which stacks.\n      if (config.grouped && config.stacked) {\n        if (series.seriesCategory != null) {\n          stackKey = series.seriesCategory!;\n        }\n\n        if (categoryToIndexMap.containsKey(stackKey)) {\n          barGroupIndex = categoryToIndexMap[stackKey]!;\n        } else {\n          barGroupIndex = categoryToIndexMap.length;\n          categoryToIndexMap[stackKey] = barGroupIndex;\n        }\n      }\n\n      var needsMeasureOffset = false;\n\n      for (var barIndex = 0; barIndex < series.data.length; barIndex++) {\n        dynamic datum = series.data[barIndex];\n        final details = getBaseDetails(datum, barIndex);\n\n        details.barStackIndex = 0;\n        details.measureOffset = measureOffsetFn!(barIndex);\n\n        if (fillPatternFn != null) {\n          details.fillPattern = fillPatternFn(barIndex);\n        } else {\n          details.fillPattern = config.fillPattern;\n        }\n\n        if (strokeWidthPxFn != null) {\n          details.strokeWidthPx = strokeWidthPxFn(barIndex)?.toDouble();\n        } else {\n          details.strokeWidthPx = config.strokeWidthPx;\n        }\n\n        // When stacking is enabled, adjust the measure offset for each domain\n        // value in each series by adding up the measures and offsets of lower\n        // series.\n        if (config.stacked) {\n          needsMeasureOffset = true;\n          var domain = domainFn(barIndex);\n          var measure = measureFn(barIndex);\n\n          // We will render positive bars in one stack, and negative bars in a\n          // separate stack. Keep track of the measure offsets for these stacks\n          // independently.\n          var domainToCategoryToDetailsMap = measure == null || measure >= 0\n              ? posDomainToStackKeyToDetailsMap\n              : negDomainToStackKeyToDetailsMap;\n\n          var categoryToDetailsMap = domainToCategoryToDetailsMap.putIfAbsent(\n              domain, () => <String, BaseBarRendererElement>{});\n\n          var prevDetail = categoryToDetailsMap[stackKey];\n\n          if (prevDetail != null) {\n            details.barStackIndex = prevDetail.barStackIndex! + 1;\n          }\n\n          details.cumulativeTotal = measure ?? 0;\n\n          // Get the previous series' measure offset.\n          var measureOffset = measureOffsetFn(barIndex)!;\n          if (prevDetail != null) {\n            measureOffset += prevDetail.measureOffsetPlusMeasure!;\n\n            details.cumulativeTotal =\n                details.cumulativeTotal! + prevDetail.cumulativeTotal!;\n          }\n\n          // And overwrite the details measure offset.\n          details.measureOffset = measureOffset;\n          var measureValue = measure ?? 0;\n          details.measureOffsetPlusMeasure = measureOffset + measureValue;\n\n          categoryToDetailsMap[stackKey] = details;\n        }\n\n        maxBarStackSize = max(maxBarStackSize, details.barStackIndex! + 1);\n\n        elements.add(details);\n      }\n\n      if (needsMeasureOffset) {\n        // Override the measure offset function to return the measure offset we\n        // calculated for each datum. This already includes any measure offset\n        // that was configured in the series data.\n        series.measureOffsetFn = (index) => elements[index!].measureOffset!;\n      }\n\n      series.setAttr(barGroupIndexKey, barGroupIndex);\n      series.setAttr(stackKeyKey, stackKey);\n      series.setAttr(barElementsKey, elements);\n\n      if (config.grouped) {\n        barGroupIndex++;\n      }\n    });\n\n    // Compute number of bar groups. This must be done after we have processed\n    // all of the series once, so that we know how many categories we have.\n    var numBarGroups = 0;\n    if (config.grouped && config.stacked) {\n      // For grouped stacked bars, categoryToIndexMap effectively one list per\n      // group of stacked bars.\n      numBarGroups = categoryToIndexMap.length;\n    } else if (config.stacked) {\n      numBarGroups = 1;\n    } else {\n      numBarGroups = seriesList.length;\n    }\n\n    // Compute bar group weights.\n    final barWeights = _calculateBarWeights(numBarGroups);\n\n    seriesList.forEach((MutableSeries<D> series) {\n      series.setAttr(barGroupCountKey, numBarGroups);\n\n      if (barWeights.isNotEmpty) {\n        final barGroupIndex = series.getAttr(barGroupIndexKey)!;\n        final barWeight = barWeights[barGroupIndex];\n\n        // In RTL mode, we need to grab the weights for the bars that follow\n        // this datum in the series (instead of precede it). The first datum is\n        // physically positioned on the canvas to the right of all the rest of\n        // the bar group data that follows it.\n        final previousBarWeights = isRtl\n            ? barWeights.getRange(barGroupIndex + 1, numBarGroups)\n            : barWeights.getRange(0, barGroupIndex);\n\n        final previousBarWeight = previousBarWeights.isNotEmpty\n            ? previousBarWeights.reduce((a, b) => a + b)\n            : 0.0;\n\n        series.setAttr(barGroupWeightKey, barWeight);\n        series.setAttr(previousBarGroupWeightKey, previousBarWeight);\n        series.setAttr(allBarGroupWeightsKey, barWeights);\n      }\n    });\n  }\n\n  /// Calculates bar weights for a list of series from [config.weightPattern].\n  ///\n  /// If [config.weightPattern] is not set, then this will assign a weight\n  /// proportional to the number of bar groups for every series.\n  List<double> _calculateBarWeights(int numBarGroups) {\n    // Set up bar weights for each series as a ratio of the total weight.\n    final weights = <double>[];\n\n    if (config.weightPattern != null) {\n      if (numBarGroups > config.weightPattern!.length) {\n        throw ArgumentError('Number of series exceeds length of weight '\n            'pattern ${config.weightPattern}');\n      }\n\n      var totalBarWeight = 0;\n\n      for (var i = 0; i < numBarGroups; i++) {\n        totalBarWeight += config.weightPattern![i];\n      }\n\n      for (var i = 0; i < numBarGroups; i++) {\n        weights.add(config.weightPattern![i] / totalBarWeight);\n      }\n    } else {\n      for (var i = 0; i < numBarGroups; i++) {\n        weights.add(1 / numBarGroups);\n      }\n    }\n\n    return weights;\n  }\n\n  /// Construct a base details element for a given datum.\n  ///\n  /// This is intended to be overridden by child classes that need to add\n  /// customized rendering properties.\n  @protected\n  R getBaseDetails(dynamic datum, int index);\n\n  @override\n  void configureDomainAxes(List<MutableSeries<D>> seriesList) {\n    super.configureDomainAxes(seriesList);\n\n    // Configure the domain axis to use a range band configuration.\n    if (seriesList.isNotEmpty) {\n      // Given that charts can only have one domain axis, just grab it from the\n      // first series.\n      final domainAxis = seriesList.first.getAttr(domainAxisKey)!;\n      // rangeBandConfig is set when current config is not valid to render\n      // bars (this is necessary with combo charts that have NumericAxis)\n      if (!domainAxis.hasValidBarChartRangeBandConfig) {\n        domainAxis.setRangeBandConfig(RangeBandConfig.styleAssignedPercent());\n      }\n    }\n  }\n\n  @override\n  void update(List<ImmutableSeries<D>> seriesList, bool isAnimatingThisDraw) {\n    _currentKeys.clear();\n    _currentGroupsStackKeys.clear();\n\n    final orderedSeriesList = getOrderedSeriesList(seriesList);\n\n    orderedSeriesList.forEach((final ImmutableSeries<D> series) {\n      final domainAxis = series.getAttr(domainAxisKey) as ImmutableAxis<D>;\n      final domainFn = series.domainFn;\n      final measureAxis = series.getAttr(measureAxisKey) as ImmutableAxis<num>;\n      final measureFn = series.measureFn;\n      final colorFn = series.colorFn;\n      final dashPatternFn = series.dashPatternFn;\n      final fillColorFn = series.fillColorFn;\n      final seriesStackKey = series.getAttr(stackKeyKey);\n      final barGroupCount = series.getAttr(barGroupCountKey);\n      final barGroupIndex = series.getAttr(barGroupIndexKey);\n      final previousBarGroupWeight = series.getAttr(previousBarGroupWeightKey);\n      final barGroupWeight = series.getAttr(barGroupWeightKey);\n      final allBarGroupWeights = series.getAttr(allBarGroupWeightsKey);\n      final measureAxisPosition = measureAxis.getLocation(0.0);\n\n      var elementsList = series.getAttr(barElementsKey);\n\n      // Save off domainAxis for getNearest.\n      _prevDomainAxis = domainAxis;\n\n      for (var barIndex = 0; barIndex < series.data.length; barIndex++) {\n        final Object? datum = series.data[barIndex];\n        final details = elementsList![barIndex];\n        final domainValue = domainFn(barIndex);\n\n        final measureValue = measureFn(barIndex);\n        final measureIsNull = measureValue == null;\n        final measureIsNegative = !measureIsNull && measureValue! < 0;\n\n        // Each bar should be stored in barStackMap in a structure that mirrors\n        // the visual rendering of the bars. Thus, they should be grouped by\n        // domain value, series category (by way of the stack keys that were\n        // generated for each series in the preprocess step), and bar group\n        // index to account for all combinations of grouping and stacking.\n        var barStackMapKey = '$domainValue'\n            '__'\n            '$seriesStackKey'\n            '__'\n            '${measureIsNegative ? 'pos' : 'neg'}'\n            '__'\n            '$barGroupIndex';\n\n        var barKey = '${barStackMapKey}${details.barStackIndex}';\n\n        var barStackList = _barStackMap.putIfAbsent(barStackMapKey, () => []);\n\n        // If we already have an AnimatingBarfor that index, use it.\n        var animatingBar =\n            barStackList.firstWhereOrNull((B bar) => bar.key == barKey);\n\n        // If we don't have any existing bar element, create a new bar and have\n        // it animate in from the domain axis.\n        // TODO: Animate bars in the middle of a stack from their\n        // nearest neighbors, instead of the measure axis.\n        if (animatingBar == null) {\n          // If the measure is null and there was no existing animating bar, it\n          // means we don't need to draw this bar at all.\n          if (!measureIsNull) {\n            animatingBar = makeAnimatedBar(\n                key: barKey,\n                series: series,\n                datum: datum,\n                barGroupIndex: barGroupIndex!,\n                previousBarGroupWeight: previousBarGroupWeight,\n                barGroupWeight: barGroupWeight,\n                allBarGroupWeights: allBarGroupWeights,\n                color: colorFn!(barIndex),\n                dashPattern: dashPatternFn!(barIndex),\n                details: details as R,\n                domainValue: domainFn(barIndex),\n                domainAxis: domainAxis,\n                domainWidth: domainAxis.rangeBand.round(),\n                fillColor: fillColorFn!(barIndex),\n                fillPattern: details.fillPattern,\n                measureValue: 0.0,\n                measureOffsetValue: 0.0,\n                measureAxisPosition: measureAxisPosition,\n                measureAxis: measureAxis,\n                numBarGroups: barGroupCount!,\n                strokeWidthPx: details.strokeWidthPx,\n                measureIsNull: measureIsNull,\n                measureIsNegative: measureIsNegative);\n\n            barStackList.add(animatingBar);\n          }\n        } else {\n          animatingBar\n            ..datum = datum\n            ..series = series\n            ..domainValue = domainValue;\n        }\n\n        if (animatingBar == null) {\n          continue;\n        }\n\n        // Update the set of bars that still exist in the series data.\n        _currentKeys.add(barKey);\n\n        // Store off stack keys for each bar group to help getNearest identify\n        // groups of stacks.\n        _currentGroupsStackKeys\n            .putIfAbsent(domainValue, () => <String>{})\n            .add(barStackMapKey);\n\n        // Get the barElement we are going to setup.\n        // Optimization to prevent allocation in non-animating case.\n        BaseBarRendererElement barElement = makeBarRendererElement(\n            barGroupIndex: barGroupIndex!,\n            previousBarGroupWeight: previousBarGroupWeight,\n            barGroupWeight: barGroupWeight,\n            allBarGroupWeights: allBarGroupWeights,\n            color: colorFn!(barIndex),\n            dashPattern: dashPatternFn!(barIndex),\n            details: details as R,\n            domainValue: domainFn(barIndex),\n            domainAxis: domainAxis,\n            domainWidth: domainAxis.rangeBand.round(),\n            fillColor: fillColorFn!(barIndex),\n            fillPattern: details.fillPattern,\n            measureValue: measureValue,\n            measureOffsetValue: details.measureOffset!,\n            measureAxisPosition: measureAxisPosition,\n            measureAxis: measureAxis,\n            numBarGroups: barGroupCount!,\n            strokeWidthPx: details.strokeWidthPx,\n            measureIsNull: measureIsNull,\n            measureIsNegative: measureIsNegative);\n\n        animatingBar.setNewTarget(barElement as R);\n      }\n    });\n\n    // Animate out bars that don't exist anymore.\n    _barStackMap.forEach((String key, List<B> barStackList) {\n      for (var barIndex = 0; barIndex < barStackList.length; barIndex++) {\n        final bar = barStackList[barIndex];\n        if (_currentKeys.contains(bar.key) != true) {\n          bar.animateOut();\n        }\n      }\n    });\n  }\n\n  /// Generates a [BaseAnimatedBar] to represent the previous and current state\n  /// of one bar on the chart.\n  @protected\n  B makeAnimatedBar(\n      {required String key,\n      required ImmutableSeries<D> series,\n      dynamic datum,\n      required int barGroupIndex,\n      double? previousBarGroupWeight,\n      double? barGroupWeight,\n      List<double>? allBarGroupWeights,\n      Color? color,\n      List<int>? dashPattern,\n      required R details,\n      D? domainValue,\n      required ImmutableAxis<D> domainAxis,\n      required int domainWidth,\n      num? measureValue,\n      required num measureOffsetValue,\n      required ImmutableAxis<num> measureAxis,\n      double? measureAxisPosition,\n      required int numBarGroups,\n      Color? fillColor,\n      FillPatternType? fillPattern,\n      double? strokeWidthPx,\n      bool? measureIsNull,\n      bool? measureIsNegative});\n\n  /// Generates a [BaseBarRendererElement] to represent the rendering data for\n  /// one bar on the chart.\n  @protected\n  R makeBarRendererElement(\n      {required int barGroupIndex,\n      double? previousBarGroupWeight,\n      double? barGroupWeight,\n      List<double>? allBarGroupWeights,\n      Color? color,\n      List<int>? dashPattern,\n      required R details,\n      D? domainValue,\n      required ImmutableAxis<D> domainAxis,\n      required int domainWidth,\n      num? measureValue,\n      required num measureOffsetValue,\n      required ImmutableAxis<num> measureAxis,\n      double? measureAxisPosition,\n      required int numBarGroups,\n      Color? fillColor,\n      FillPatternType? fillPattern,\n      double? strokeWidthPx,\n      bool? measureIsNull,\n      bool? measureIsNegative});\n\n  /// Paints the current bar data on the canvas.\n  @override\n  void paint(ChartCanvas canvas, double animationPercent) {\n    // Clean up the bars that no longer exist.\n    if (animationPercent == 1.0) {\n      final keysToRemove = HashSet<String>();\n\n      _barStackMap.forEach((String key, List<B> barStackList) {\n        barStackList.retainWhere(\n            (B bar) => !bar.animatingOut && !bar.targetBar!.measureIsNull!);\n\n        if (barStackList.isEmpty) {\n          keysToRemove.add(key);\n        }\n      });\n\n      // When cleaning up the animation, also clean up the keys used to lookup\n      // if a bar is selected.\n      for (final key in keysToRemove) {\n        _barStackMap.remove(key);\n        _currentKeys.remove(key);\n      }\n      _currentGroupsStackKeys.forEach((domain, keys) {\n        keys.removeWhere(keysToRemove.contains);\n      });\n    }\n\n    _barStackMap.forEach((String stackKey, List<B> barStack) {\n      // Turn this into a list so that the getCurrentBar isn't called more than\n      // once for each animationPercent if the barElements are iterated more\n      // than once.\n      final barElements = barStack\n          .map((B animatingBar) => animatingBar.getCurrentBar(animationPercent))\n          .toList();\n\n      if (barElements.isNotEmpty) {\n        paintBar(canvas, animationPercent, barElements);\n      }\n    });\n  }\n\n  /// Paints a stack of bar elements on the canvas.\n  @protected\n  void paintBar(\n      ChartCanvas canvas, double animationPercent, Iterable<R> barElements);\n\n  @override\n  List<DatumDetails<D>> getNearestDatumDetailPerSeries(\n    Point<double> chartPoint,\n    bool byDomain,\n    Rectangle<int>? boundsOverride, {\n    bool selectOverlappingPoints = false,\n    bool selectExactEventLocation = false,\n  }) {\n    var nearest = <DatumDetails<D>>[];\n\n    // Was it even in the component bounds?\n    if (!isPointWithinBounds(chartPoint, boundsOverride)) {\n      return nearest;\n    }\n\n    if (_prevDomainAxis is OrdinalAxis) {\n      final domainValue = _prevDomainAxis!\n          .getDomain(renderingVertically ? chartPoint.x : chartPoint.y);\n\n      // If we have a domainValue for the event point, then find all segments\n      // that match it.\n      if (domainValue != null) {\n        if (renderingVertically) {\n          nearest = _getVerticalDetailsForDomainValue(domainValue, chartPoint);\n        } else {\n          nearest =\n              _getHorizontalDetailsForDomainValue(domainValue, chartPoint);\n        }\n      }\n    } else {\n      if (renderingVertically) {\n        nearest = _getVerticalDetailsForDomainValue(null, chartPoint);\n      } else {\n        nearest = _getHorizontalDetailsForDomainValue(null, chartPoint);\n      }\n\n      // Find the closest domain and only keep values that match the domain.\n      var minRelativeDistance = double.maxFinite;\n      var minDomainDistance = double.maxFinite;\n      var minMeasureDistance = double.maxFinite;\n      D? nearestDomain;\n\n      // TODO: Optimize this with a binary search based on chartX.\n      for (final detail in nearest) {\n        if (byDomain) {\n          if (detail.domainDistance! < minDomainDistance ||\n              (detail.domainDistance! == minDomainDistance &&\n                  detail.measureDistance! < minMeasureDistance)) {\n            minDomainDistance = detail.domainDistance!;\n            minMeasureDistance = detail.measureDistance!;\n            nearestDomain = detail.domain;\n          }\n        } else {\n          if (detail.relativeDistance! < minRelativeDistance) {\n            minRelativeDistance = detail.relativeDistance!;\n            nearestDomain = detail.domain;\n          }\n        }\n      }\n\n      nearest.retainWhere((d) => d.domain == nearestDomain);\n    }\n\n    // Note: the details are already sorted by domain & measure distance in\n    // base chart.\n    return nearest;\n  }\n\n  @protected\n  Rectangle<int>? getBoundsForBar(R bar);\n\n  @protected\n  List<BaseAnimatedBar<D, R>> _getSegmentsForDomainValue(D? domainValue,\n      {bool Function(BaseAnimatedBar<D, R> bar)? where}) {\n    final matchingSegments = <BaseAnimatedBar<D, R>>[];\n\n    // [domainValue] is null only when the bar renderer is being used with in\n    // a non ordinal axis (ex. date time axis).\n    //\n    // In the case of null [domainValue] return all values to be compared, since\n    // we can't use the optimized comparison for [OrdinalAxis].\n    final stackKeys = (domainValue != null)\n        ? _currentGroupsStackKeys[domainValue]\n        : _currentGroupsStackKeys.values\n            .reduce((allKeys, keys) => allKeys..addAll(keys));\n    stackKeys?.forEach((String stackKey) {\n      if (where != null) {\n        matchingSegments.addAll(_barStackMap[stackKey]!.where(where));\n      } else {\n        matchingSegments.addAll(_barStackMap[stackKey]!);\n      }\n    });\n\n    return matchingSegments;\n  }\n\n  // In the case of null [domainValue] return all values to be compared, since\n  // we can't use the optimized comparison for [OrdinalAxis].\n  List<DatumDetails<D>> _getVerticalDetailsForDomainValue(\n      D? domainValue, Point<double> chartPoint) {\n    return List<DatumDetails<D>>.from(_getSegmentsForDomainValue(domainValue,\n            where: (BaseAnimatedBar<D, R> bar) => !bar.series.overlaySeries)\n        .map<DatumDetails<D>>((BaseAnimatedBar<D, R> bar) {\n      final barBounds = getBoundsForBar(bar.currentBar!)!;\n      final segmentDomainDistance =\n          _getDistance(chartPoint.x.round(), barBounds.left, barBounds.right);\n      final segmentMeasureDistance =\n          _getDistance(chartPoint.y.round(), barBounds.top, barBounds.bottom);\n\n      final nearestPoint = Point<double>(\n          clamp(chartPoint.x, barBounds.left, barBounds.right).toDouble(),\n          clamp(chartPoint.y, barBounds.top, barBounds.bottom).toDouble());\n\n      final relativeDistance = chartPoint.distanceTo(nearestPoint);\n\n      return DatumDetails<D>(\n        series: bar.series,\n        datum: bar.datum,\n        domain: bar.domainValue,\n        domainDistance: segmentDomainDistance,\n        measureDistance: segmentMeasureDistance,\n        relativeDistance: relativeDistance,\n      );\n    }));\n  }\n\n  List<DatumDetails<D>> _getHorizontalDetailsForDomainValue(\n      D? domainValue, Point<double> chartPoint) {\n    return List<DatumDetails<D>>.from(_getSegmentsForDomainValue(domainValue,\n            where: (BaseAnimatedBar<D, R> bar) => !bar.series.overlaySeries)\n        .map<DatumDetails<D>>((BaseAnimatedBar<D, R> bar) {\n      final barBounds = getBoundsForBar(bar.currentBar!)!;\n      final segmentDomainDistance =\n          _getDistance(chartPoint.y.round(), barBounds.top, barBounds.bottom);\n      final segmentMeasureDistance =\n          _getDistance(chartPoint.x.round(), barBounds.left, barBounds.right);\n\n      return DatumDetails<D>(\n        series: bar.series,\n        datum: bar.datum,\n        domain: bar.domainValue,\n        domainDistance: segmentDomainDistance,\n        measureDistance: segmentMeasureDistance,\n      );\n    }));\n  }\n\n  double _getDistance(int point, int min, int max) {\n    if (max >= point && min <= point) {\n      return 0.0;\n    }\n    return (point > max ? (point - max) : (min - point)).toDouble();\n  }\n\n  /// Gets the iterator for the series based grouped/stacked and orientation.\n  ///\n  /// For vertical stacked bars:\n  /// * If grouped, return the iterator that keeps the category order but\n  /// reverse the order of the series so the first series is on the top of the\n  /// stack.\n  /// * Otherwise, return iterator of the reversed list\n  ///\n  /// All other types, use the in order iterator.\n  @protected\n  Iterable<S> getOrderedSeriesList<S extends ImmutableSeries<D>>(\n      List<S> seriesList) {\n    return (renderingVertically && config.stacked)\n        ? config.grouped\n            ? _ReversedSeriesIterable(seriesList)\n            : seriesList.reversed\n        : seriesList;\n  }\n\n  bool get isRtl => chart.context.isRtl;\n}\n\n/// Iterable wrapping the seriesList that returns the ReversedSeriesItertor.\nclass _ReversedSeriesIterable<S extends ImmutableSeries<Object?>>\n    extends Iterable<S> {\n  final List<S> seriesList;\n\n  _ReversedSeriesIterable(this.seriesList);\n\n  @override\n  Iterator<S> get iterator => _ReversedSeriesIterator(seriesList);\n}\n\n/// Iterator that keeps reverse series order but keeps category order.\n///\n/// This is needed because for grouped stacked bars, the category stays in the\n/// order it was passed in for the grouping, but the series is flipped so that\n/// the first series of that category is on the top of the stack.\nclass _ReversedSeriesIterator<S extends ImmutableSeries<Object?>>\n    extends Iterator<S> {\n  final List<S> _list;\n  final _visitIndex = <int>[];\n  int? _current;\n\n  _ReversedSeriesIterator(List<S> list) : _list = list {\n    // In the order of the list, save the category and the indices of the series\n    // with the same category.\n    final categoryAndSeriesIndexMap = <String?, List<int>>{};\n    for (var i = 0; i < list.length; i++) {\n      categoryAndSeriesIndexMap\n          .putIfAbsent(list[i].seriesCategory, () => <int>[])\n          .add(i);\n    }\n\n    // Creates a visit that is categories in order, but the series is reversed.\n    categoryAndSeriesIndexMap\n        .forEach((_, indices) => _visitIndex.addAll(indices.reversed));\n  }\n\n  @override\n  bool moveNext() {\n    _current = (_current == null) ? 0 : _current! + 1;\n\n    return _current! < _list.length;\n  }\n\n  @override\n  S get current => _list[_visitIndex[_current!]];\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/bar/base_bar_renderer_config.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'package:collection/collection.dart' show ListEquality;\n\nimport '../../common/symbol_renderer.dart'\n    show SymbolRenderer, RoundedRectSymbolRenderer;\nimport '../common/chart_canvas.dart' show FillPatternType;\nimport '../common/series_renderer_config.dart'\n    show RendererAttributes, SeriesRendererConfig;\nimport '../layout/layout_view.dart' show LayoutViewConfig;\n\n/// Shared configuration for bar chart renderers.\n///\n/// Bar renderers support 4 different modes of rendering multiple series on the\n/// chart, configured by the grouped and stacked flags.\n/// * grouped - Render bars for each series that shares a domain value\n///   side-by-side.\n/// * stacked - Render bars for each series that shares a domain value in a\n///   stack, ordered in the same order as the series list.\n/// * grouped-stacked: Render bars for each series that shares a domain value in\n///   a group of bar stacks. Each stack will contain all the series that share a\n///   series category.\n/// * floating style - When grouped and stacked are both false, all bars that\n///   share a domain value will be rendered in the same domain space. Each datum\n///   should be configured with a measure offset to position its bar along the\n///   measure axis. Bars will freely overlap if their measure values and measure\n///   offsets overlap. Note that bars for each series will be rendered in order,\n///   such that bars from the last series will be \"on top\" of bars from previous\n///   series.\nabstract class BaseBarRendererConfig<D> extends LayoutViewConfig\n    implements SeriesRendererConfig<D> {\n  @override\n  final String? customRendererId;\n\n  @override\n  final SymbolRenderer symbolRenderer;\n\n  /// Dash pattern for the stroke line around the edges of the bar.\n  final List<int>? dashPattern;\n\n  /// Defines the way multiple series of bars are rendered per domain.\n  final BarGroupingType groupingType;\n\n  /// The order to paint this renderer on the canvas.\n  final int? layoutPaintOrder;\n\n  final int minBarLengthPx;\n\n  // The maximum bar group width in pixels, or null if bars can be arbitrarily\n  // wide.\n  final int? maxBarWidthPx;\n\n  final FillPatternType? fillPattern;\n\n  /// The padding between bar stacks.\n  final int stackedBarPaddingPx;\n\n  /// Stroke width of the target line.\n  final double strokeWidthPx;\n\n  /// Sets the series weight pattern. This is a pattern of weights used to\n  /// calculate the width of bars within a bar group. If not specified, each bar\n  /// in the group will have an equal width.\n  ///\n  /// The pattern will not repeat. If more series are assigned to the renderer\n  /// than there are segments in the weight pattern, an error will be thrown.\n  ///\n  /// e.g. For the pattern [2, 1], the first bar in a group should be rendered\n  /// twice as wide as the second bar.\n  ///\n  /// If the expected bar width of the chart is 12px, then the first bar will\n  /// render at 16px and the second will render at 8px. The default weight\n  /// pattern of null means that all bars should be the same width, or 12px in\n  /// this case.\n  ///\n  /// Not used for stacked bars.\n  final List<int>? weightPattern;\n\n  @override\n  final rendererAttributes = RendererAttributes();\n\n  BaseBarRendererConfig(\n      {this.customRendererId,\n      this.dashPattern,\n      this.groupingType = BarGroupingType.grouped,\n      this.layoutPaintOrder,\n      this.minBarLengthPx = 0,\n      this.maxBarWidthPx,\n      this.fillPattern,\n      this.stackedBarPaddingPx = 1,\n      this.strokeWidthPx = 0.0,\n      SymbolRenderer? symbolRenderer,\n      this.weightPattern})\n      : symbolRenderer = symbolRenderer ?? RoundedRectSymbolRenderer();\n\n  /// Whether or not the bars should be organized into groups.\n  bool get grouped =>\n      groupingType == BarGroupingType.grouped ||\n      groupingType == BarGroupingType.groupedStacked;\n\n  /// Whether or not the bars should be organized into stacks.\n  bool get stacked =>\n      groupingType == BarGroupingType.stacked ||\n      groupingType == BarGroupingType.groupedStacked;\n\n  @override\n  bool operator ==(Object other) {\n    if (identical(this, other)) {\n      return true;\n    }\n    return other is BaseBarRendererConfig &&\n        other.customRendererId == customRendererId &&\n        other.dashPattern == dashPattern &&\n        other.fillPattern == fillPattern &&\n        other.groupingType == groupingType &&\n        other.minBarLengthPx == minBarLengthPx &&\n        other.maxBarWidthPx == maxBarWidthPx &&\n        other.stackedBarPaddingPx == stackedBarPaddingPx &&\n        other.strokeWidthPx == strokeWidthPx &&\n        other.symbolRenderer == symbolRenderer &&\n        ListEquality<int>().equals(other.weightPattern, weightPattern);\n  }\n\n  @override\n  int get hashCode {\n    var hash = 1;\n    hash = hash * 31 + customRendererId.hashCode;\n    hash = hash * 31 + dashPattern.hashCode;\n    hash = hash * 31 + fillPattern.hashCode;\n    hash = hash * 31 + groupingType.hashCode;\n    hash = hash * 31 + minBarLengthPx.hashCode;\n    hash = hash * 31 + maxBarWidthPx.hashCode;\n    hash = hash * 31 + stackedBarPaddingPx.hashCode;\n    hash = hash * 31 + strokeWidthPx.hashCode;\n    hash = hash * 31 + symbolRenderer.hashCode;\n    hash = hash * 31 + weightPattern.hashCode;\n    return hash;\n  }\n}\n\n/// Defines the way multiple series of bars are renderered per domain.\n///\n/// * [grouped] - Render bars for each series that shares a domain value\n///   side-by-side.\n/// * [stacked] - Render bars for each series that shares a domain value in a\n///   stack, ordered in the same order as the series list.\n/// * [groupedStacked]: Render bars for each series that shares a domain value\n///   in a group of bar stacks. Each stack will contain all the series that\n///   share a series category.\nenum BarGroupingType { grouped, groupedStacked, stacked }\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/bar/base_bar_renderer_element.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport '../../common/color.dart' show Color;\nimport '../common/chart_canvas.dart' show getAnimatedColor, FillPatternType;\nimport '../common/processed_series.dart' show ImmutableSeries;\n\nabstract class BaseBarRendererElement {\n  int? barStackIndex;\n  Color? color;\n  num? cumulativeTotal;\n  List<int>? dashPattern;\n  Color? fillColor;\n  FillPatternType? fillPattern;\n  double? measureAxisPosition;\n  num? measureOffset;\n  num? measureOffsetPlusMeasure;\n  double? strokeWidthPx;\n  bool? measureIsNull;\n  bool? measureIsNegative;\n\n  BaseBarRendererElement();\n\n  BaseBarRendererElement.clone(BaseBarRendererElement other) {\n    barStackIndex = other.barStackIndex;\n    color = other.color != null ? Color.fromOther(color: other.color!) : null;\n    cumulativeTotal = other.cumulativeTotal;\n    dashPattern = other.dashPattern;\n    fillColor = other.fillColor != null\n        ? Color.fromOther(color: other.fillColor!)\n        : null;\n    fillPattern = other.fillPattern;\n    measureAxisPosition = other.measureAxisPosition;\n    measureOffset = other.measureOffset;\n    measureOffsetPlusMeasure = other.measureOffsetPlusMeasure;\n    strokeWidthPx = other.strokeWidthPx;\n    measureIsNull = other.measureIsNull;\n    measureIsNegative = other.measureIsNegative;\n  }\n\n  void updateAnimationPercent(BaseBarRendererElement previous,\n      BaseBarRendererElement target, double animationPercent) {\n    color = getAnimatedColor(previous.color!, target.color!, animationPercent);\n    fillColor = getAnimatedColor(\n        previous.fillColor!, target.fillColor!, animationPercent);\n    measureIsNull = target.measureIsNull;\n    measureIsNegative = target.measureIsNegative;\n  }\n}\n\nabstract class BaseAnimatedBar<D, R extends BaseBarRendererElement> {\n  final String key;\n  dynamic datum;\n  ImmutableSeries<D> series;\n  D? domainValue;\n\n  R? _previousBar;\n  R? _targetBar;\n  R? _currentBar;\n\n  // Flag indicating whether this bar is being animated out of the chart.\n  bool animatingOut = false;\n\n  BaseAnimatedBar({\n    required this.key,\n    required this.datum,\n    required this.series,\n    required this.domainValue,\n  });\n\n  /// Animates a bar that was removed from the series out of the view.\n  ///\n  /// This should be called in place of \"setNewTarget\" for bars that represent\n  /// data that has been removed from the series.\n  ///\n  /// Animates the height of the bar down to the measure axis position (position\n  /// of 0). Animates the width of the bar down to 0, centered in the middle of\n  /// the original bar width.\n  void animateOut() {\n    var newTarget = clone(_currentBar!);\n\n    animateElementToMeasureAxisPosition(newTarget);\n\n    setNewTarget(newTarget);\n    animatingOut = true;\n  }\n\n  /// Sets the bounds for the target to the measure axis position.\n  void animateElementToMeasureAxisPosition(R target);\n\n  /// Sets a new element to render.\n  void setNewTarget(R newTarget) {\n    animatingOut = false;\n    _currentBar ??= clone(newTarget);\n    _previousBar = clone(_currentBar!);\n    _targetBar = newTarget;\n  }\n\n  R? get currentBar => _currentBar;\n\n  R? get previousBar => _previousBar;\n\n  R? get targetBar => _targetBar;\n\n  /// Gets the new state of the bar element for painting, updated for a\n  /// transition between the previous state and the new animationPercent.\n  R getCurrentBar(double animationPercent) {\n    assert(_targetBar != null);\n\n    if (animationPercent == 1.0 || _previousBar == null) {\n      _currentBar = _targetBar;\n      _previousBar = _targetBar;\n      return _currentBar!;\n    }\n\n    _currentBar!\n        .updateAnimationPercent(_previousBar!, _targetBar!, animationPercent);\n\n    return _currentBar!;\n  }\n\n  R clone(R bar);\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/cartesian/axis/axis.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math' show Rectangle, min, max;\n\nimport 'package:collection/collection.dart' show IterableExtension;\nimport 'package:meta/meta.dart' show protected, visibleForTesting;\n\nimport '../../../../common.dart';\nimport '../../../common/graphics_factory.dart' show GraphicsFactory;\nimport '../../../common/text_element.dart' show TextElement;\nimport '../../../data/series.dart' show AttributeKey;\nimport '../../common/chart_canvas.dart' show ChartCanvas;\nimport '../../common/chart_context.dart' show ChartContext;\nimport '../../layout/layout_view.dart'\n    show\n        LayoutPosition,\n        LayoutView,\n        LayoutViewConfig,\n        LayoutViewPaintOrder,\n        LayoutViewPositionOrder,\n        ViewMeasuredSizes;\nimport 'axis_tick.dart' show AxisTicks;\nimport 'draw_strategy/small_tick_draw_strategy.dart' show SmallTickDrawStrategy;\nimport 'draw_strategy/tick_draw_strategy.dart' show TickDrawStrategy;\nimport 'linear/linear_scale.dart' show LinearScale;\nimport 'numeric_extents.dart' show NumericExtents;\nimport 'numeric_scale.dart' show NumericScale;\nimport 'numeric_tick_provider.dart' show NumericTickProvider;\nimport 'ordinal_scale.dart' show OrdinalScale;\nimport 'ordinal_tick_provider.dart' show OrdinalTickProvider;\nimport 'range_axis_tick.dart' show RangeAxisTicks;\nimport 'range_tick.dart' show RangeTick;\nimport 'scale.dart'\n    show MutableScale, RangeBandConfig, RangeBandType, ScaleOutputExtent, Scale;\nimport 'simple_ordinal_scale.dart' show SimpleOrdinalScale;\nimport 'tick.dart' show Tick;\nimport 'tick_formatter.dart'\n    show TickFormatter, OrdinalTickFormatter, NumericTickFormatter;\nimport 'tick_provider.dart' show TickProvider;\n\nconst measureAxisIdKey = AttributeKey<String>('Axis.measureAxisId');\nconst measureAxisKey = AttributeKey<Axis<Object>>('Axis.measureAxis');\nconst domainAxisKey = AttributeKey<Axis<Object>>('Axis.domainAxis');\n\n/// Orientation of an Axis.\nenum AxisOrientation { top, right, bottom, left }\n\nabstract class ImmutableAxis<D> {\n  /// Compare domain to the viewport.\n  ///\n  /// 0 if the domain is in the viewport.\n  /// 1 if the domain is to the right of the viewport.\n  /// -1 if the domain is to the left of the viewport.\n  int compareDomainValueToViewport(D domain);\n\n  /// Get location for the domain.\n  double? getLocation(D? domain);\n\n  D getDomain(double location);\n\n  /// Rangeband for this axis.\n  double get rangeBand;\n\n  /// Step size for this axis.\n  double get stepSize;\n\n  /// Output range for this axis.\n  ScaleOutputExtent? get range;\n}\n\nabstract class Axis<D> extends ImmutableAxis<D> implements LayoutView {\n  static const primaryMeasureAxisId = 'primaryMeasureAxisId';\n  static const secondaryMeasureAxisId = 'secondaryMeasureAxisId';\n  static const _autoViewportDefault = true;\n\n  final MutableScale<D>? _defaultScale;\n\n  /// [Scale] of this axis.\n  MutableScale<D>? scale;\n\n  /// Previous [Scale] of this axis, used to calculate tick animation.\n  MutableScale<D>? _previousScale;\n\n  final TickProvider<D>? _defaultTickProvider;\n\n  /// [TickProvider] for this axis.\n  TickProvider<D>? tickProvider;\n\n  final TickFormatter<D>? _defaultTickFormatter;\n\n  TickFormatter<D>? _tickFormatter;\n\n  set tickFormatter(TickFormatter<D>? formatter) {\n    if (_tickFormatter != formatter) {\n      _tickFormatter = formatter;\n      _formatterValueCache.clear();\n    }\n  }\n\n  /// [TickFormatter] for this axis.\n  TickFormatter<D>? get tickFormatter => _tickFormatter;\n\n  final _formatterValueCache = <D, String>{};\n\n  /// [TickDrawStrategy] for this axis.\n  TickDrawStrategy<D>? tickDrawStrategy;\n\n  /// [AxisOrientation] for this axis.\n  AxisOrientation? axisOrientation;\n\n  ChartContext? context;\n\n  /// If the output range should be reversed.\n  bool reverseOutputRange = false;\n\n  /// Configures whether the viewport should be reset back to default values\n  /// when the domain is reset.\n  ///\n  /// This should generally be disabled when the viewport will be managed\n  /// externally, e.g. from pan and zoom behaviors.\n  bool autoViewport = _autoViewportDefault;\n\n  /// If the axis line should always be drawn.\n  bool? forceDrawAxisLine;\n\n  /// If true, do not allow axis to be modified.\n  ///\n  /// Ticks (including their location) are not updated.\n  /// Viewport changes not allowed.\n  bool lockAxis = false;\n\n  /// Ticks provided by the tick provider.\n  List<Tick<D>>? _providedTicks;\n\n  /// Ticks used by the axis for drawing.\n  final _axisTicks = <AxisTicks<D>>[];\n\n  Rectangle<int>? _componentBounds;\n  Rectangle<int>? _drawAreaBounds;\n\n  /// Order for chart layout painting.\n  ///\n  /// In general, domain axes should be drawn on top of measure axes to ensure\n  /// that the domain axis line appears on top of any measure axis grid lines.\n  int layoutPaintOrder = LayoutViewPaintOrder.measureAxis;\n\n  /// If true, a collision has occurred between ticks on this axis.\n  bool hasTickCollision = false;\n\n  Axis({this.tickProvider, TickFormatter<D>? tickFormatter, this.scale})\n      : _defaultScale = scale,\n        _defaultTickProvider = tickProvider,\n        _defaultTickFormatter = tickFormatter,\n        _tickFormatter = tickFormatter;\n\n  @protected\n  MutableScale<D>? get mutableScale => scale;\n\n  /// Rangeband for this axis.\n  @override\n  double get rangeBand => scale!.rangeBand;\n\n  @override\n  double get stepSize => scale!.stepSize;\n\n  @override\n  ScaleOutputExtent? get range => scale!.range;\n\n  void setRangeBandConfig(RangeBandConfig rangeBandConfig) {\n    mutableScale!.rangeBandConfig = rangeBandConfig;\n  }\n\n  /// For bars to be renderer properly the RangeBandConfig must be set and\n  /// type must not be RangeBandType.none.\n  bool get hasValidBarChartRangeBandConfig =>\n      (mutableScale?.rangeBandConfig.type ?? RangeBandType.none) !=\n      RangeBandType.none;\n\n  void addDomainValue(D domain) {\n    if (lockAxis) {\n      return;\n    }\n\n    scale!.addDomain(domain);\n  }\n\n  void resetDefaultConfiguration() {\n    forceDrawAxisLine = null;\n    autoViewport = _autoViewportDefault;\n    scale = _defaultScale;\n    _tickFormatter = _defaultTickFormatter;\n    tickProvider = _defaultTickProvider;\n  }\n\n  void resetDomains() {\n    if (lockAxis) {\n      return;\n    }\n\n    // If the series list changes, clear the cache.\n    //\n    // There are cases where tick formatter has not \"changed\", but if measure\n    // formatter provided to the tick formatter uses a closure value, the\n    // formatter cache needs to be cleared.\n    //\n    // This type of use case for the measure formatter surfaced where the series\n    // list also changes. So this is a round about way to also clear the\n    // tick formatter cache.\n    //\n    // TODO: Measure formatter should be changed from a typedef to\n    // a concrete class to force users to create a new tick formatter when\n    // formatting is different, so we can recognize when the tick formatter is\n    // changed and then clear cache accordingly.\n    //\n    // Remove this when bug above is fixed, and verify it did not cause\n    // regression for b/110371453.\n    _formatterValueCache.clear();\n\n    final scale = this.scale!;\n    scale.resetDomain();\n    reverseOutputRange = false;\n\n    if (autoViewport) {\n      scale.resetViewportSettings();\n    }\n\n    // TODO: Reset rangeband and step size when we port over config\n    //scale.rangeBandConfig = get range band config\n    //scale.stepSizeConfig = get step size config\n  }\n\n  @override\n  double? getLocation(D? domain) {\n    const epsilon = 2e-10;\n    if (domain != null) {\n      final scale = this.scale!;\n      final range = scale.range!;\n\n      var domainLocation = scale[domain]!.toDouble();\n\n      // If domain location is outside of scale range but only outside by less\n      // than epsilon, correct the potential mislocation caused by floating\n      // point computation by moving it inside of scale range.\n      if (domainLocation > range.max && domainLocation - epsilon < range.max) {\n        return domainLocation - epsilon;\n      } else if (domainLocation < range.min &&\n          domainLocation + epsilon > range.min) {\n        return domainLocation + epsilon;\n      }\n      return domainLocation;\n    }\n    return null;\n  }\n\n  @override\n  D getDomain(double location) => scale!.reverse(location);\n\n  @override\n  int compareDomainValueToViewport(D domain) {\n    return scale!.compareDomainValueToViewport(domain);\n  }\n\n  void setOutputRange(int start, int end) {\n    scale!.range = ScaleOutputExtent(start, end);\n  }\n\n  /// Request update ticks from tick provider and update the painted ticks.\n  void updateTicks() {\n    _updateProvidedTicks();\n    if (_componentBounds != null) {\n      _updateProvidedTickWidth(\n          _componentBounds!.width, _componentBounds!.height);\n    }\n    _updateAxisTicks();\n  }\n\n  /// Request ticks from tick provider.\n  void _updateProvidedTicks() {\n    if (lockAxis) {\n      return;\n    }\n\n    assert(\n        graphicsFactory != null, 'Axis<D>.graphicsFactory must be set first');\n    assert(\n        tickDrawStrategy != null, 'Axis<D>.tickDrawStrategy must be set first');\n\n    // TODO: Ensure that tick providers take manually configured\n    // viewport settings into account, so that we still get the right number.\n    _providedTicks = tickProvider!.getTicks(\n        context: context,\n        graphicsFactory: graphicsFactory!,\n        scale: scale!,\n        formatter: tickFormatter!,\n        formatterValueCache: _formatterValueCache,\n        tickDrawStrategy: tickDrawStrategy!,\n        orientation: axisOrientation,\n        viewportExtensionEnabled: autoViewport);\n\n    hasTickCollision = tickDrawStrategy!\n        .collides(_providedTicks, axisOrientation)\n        .ticksCollide;\n  }\n\n  /// Updates the current provided tick labels with a max width.\n  void _updateProvidedTickWidth(int maxWidth, int maxHeight) {\n    if (axisOrientation != null) {\n      tickDrawStrategy!.updateTickWidth(\n        _providedTicks!,\n        maxWidth,\n        maxHeight,\n        axisOrientation!,\n        collision: hasTickCollision,\n      );\n    }\n  }\n\n  /// Updates the ticks that are actually used for drawing.\n  void _updateAxisTicks() {\n    if (lockAxis) {\n      return;\n    }\n\n    final providedTicks = List.of(_providedTicks ?? <Tick<D>>[]);\n\n    final scale = this.scale!;\n\n    for (final animatedTick in _axisTicks) {\n      final tick =\n          providedTicks.firstWhereOrNull((t) => t.value == animatedTick.value);\n\n      if (tick != null) {\n        // Swap out the text element only if the settings are different.\n        // This prevents a costly new TextPainter in Flutter.\n        if (!TextElement.elementSettingsSame(\n            animatedTick.textElement!, tick.textElement!)) {\n          animatedTick.textElement = tick.textElement;\n        }\n        var newTarget = scale[tick.value]?.toDouble();\n        if (scale.isRangeValueWithinViewport(newTarget!)) {\n          // Update target for all existing ticks\n          animatedTick.setNewTarget(newTarget);\n        } else {\n          // Animate out ticks that are outside the viewport.\n          animatedTick.animateOut(animatedTick.locationPx);\n        }\n        providedTicks.remove(tick);\n      } else {\n        // Animate out ticks that do not exist any more.\n        animatedTick.animateOut(scale[animatedTick.value]!.toDouble());\n      }\n    }\n\n    // Add new ticks\n    providedTicks.forEach((tick) {\n      AxisTicks<D> animatedTick;\n      if (tick is RangeTick<D>) {\n        animatedTick = RangeAxisTicks<D>(tick);\n      } else {\n        animatedTick = AxisTicks<D>(tick);\n      }\n      if (scale.isRangeValueWithinViewport(animatedTick.locationPx!)) {\n        if (_previousScale != null) {\n          animatedTick.animateInFrom(_previousScale![tick.value]!.toDouble());\n        }\n        _axisTicks.add(animatedTick);\n      }\n    });\n\n    _axisTicks.sort();\n\n    // Save a copy of the current scale to be used as the previous scale when\n    // ticks are updated.\n    _previousScale = scale.copy();\n  }\n\n  /// Configures the zoom and translate.\n  ///\n  /// [viewportScale] is the zoom factor to use, likely >= 1.0 where 1.0 maps\n  /// the complete data extents to the output range, and 2.0 only maps half the\n  /// data to the output range.\n  ///\n  /// [viewportTranslatePx] is the translate/pan to use in pixel units,\n  /// likely <= 0 which shifts the start of the data before the edge of the\n  /// chart giving us a pan.\n  ///\n  /// [drawAreaWidth] is the width of the draw area for the series data in pixel\n  /// units, at minimum viewport scale level (1.0). When provided,\n  /// [drawAreaHeight] is the height of the draw area for the series data in\n  /// pixel units, at minimum viewport scale level (1.0). When provided,\n  /// [viewportTranslatePx] will be clamped such that the axis cannot be panned\n  /// beyond the bounds of the data.\n  void setViewportSettings(double viewportScale, double viewportTranslatePx,\n      {int? drawAreaWidth, int? drawAreaHeight}) {\n    // Don't let the viewport be panned beyond the bounds of the data.\n    viewportTranslatePx = _clampTranslatePx(viewportScale, viewportTranslatePx,\n        drawAreaWidth: drawAreaWidth, drawAreaHeight: drawAreaHeight);\n\n    scale!.setViewportSettings(viewportScale, viewportTranslatePx);\n  }\n\n  /// Returns the current viewport scale.\n  ///\n  /// A scale of 1.0 would map the data directly to the output range, while a\n  /// value of 2.0 would map the data to an output of double the range so you\n  /// only see half the data in the viewport.  This is the equivalent to\n  /// zooming.  Its value is likely >= 1.0.\n  double get viewportScalingFactor => scale!.viewportScalingFactor;\n\n  /// Returns the current pixel viewport offset\n  ///\n  /// The translate is used by the scale function when it applies the scale.\n  /// This is the equivalent to panning.  Its value is likely <= 0 to pan the\n  /// data to the left.\n  double get viewportTranslatePx => scale!.viewportTranslatePx;\n\n  /// Clamps a possible change in domain translation to fit within the range of\n  /// the data.\n  double _clampTranslatePx(\n      double viewportScalingFactor, double viewportTranslatePx,\n      {int? drawAreaWidth, int? drawAreaHeight}) {\n    if (isVertical) {\n      if (drawAreaHeight == null) {\n        return viewportTranslatePx;\n      }\n      // Bound the viewport translate to the range of the data.\n      final maxPositiveTranslate =\n          (drawAreaHeight * viewportScalingFactor) - drawAreaHeight;\n\n      viewportTranslatePx =\n          max(min(viewportTranslatePx, maxPositiveTranslate), 0.0);\n    } else {\n      if (drawAreaWidth == null) {\n        return viewportTranslatePx;\n      }\n      // Bound the viewport translate to the range of the data.\n      final maxNegativeTranslate =\n          -1.0 * ((drawAreaWidth * viewportScalingFactor) - drawAreaWidth);\n\n      viewportTranslatePx =\n          min(max(viewportTranslatePx, maxNegativeTranslate), 0.0);\n    }\n    return viewportTranslatePx;\n  }\n\n  //\n  // LayoutView methods.\n  //\n\n  @override\n  GraphicsFactory? graphicsFactory;\n\n  @override\n  LayoutViewConfig get layoutConfig => LayoutViewConfig(\n      paintOrder: layoutPaintOrder,\n      position: _layoutPosition,\n      positionOrder: LayoutViewPositionOrder.axis);\n\n  /// Get layout position from axis orientation.\n  LayoutPosition? get _layoutPosition {\n    LayoutPosition? position;\n    switch (axisOrientation) {\n      case AxisOrientation.top:\n        position = LayoutPosition.Top;\n        break;\n      case AxisOrientation.right:\n        position = LayoutPosition.Right;\n        break;\n      case AxisOrientation.bottom:\n        position = LayoutPosition.Bottom;\n        break;\n      case AxisOrientation.left:\n        position = LayoutPosition.Left;\n        break;\n      case null:\n        break;\n    }\n\n    return position;\n  }\n\n  /// The axis is rendered vertically.\n  bool get isVertical =>\n      axisOrientation == AxisOrientation.left ||\n      axisOrientation == AxisOrientation.right;\n\n  @override\n  ViewMeasuredSizes measure(int maxWidth, int maxHeight) {\n    return isVertical\n        ? _measureVerticalAxis(maxWidth, maxHeight)\n        : _measureHorizontalAxis(maxWidth, maxHeight);\n  }\n\n  ViewMeasuredSizes _measureVerticalAxis(int maxWidth, int maxHeight) {\n    setOutputRange(maxHeight, 0);\n    _updateProvidedTicks();\n\n    return tickDrawStrategy!.measureVerticallyDrawnTicks(\n        _providedTicks!, maxWidth, maxHeight,\n        collision: hasTickCollision);\n  }\n\n  ViewMeasuredSizes _measureHorizontalAxis(int maxWidth, int maxHeight) {\n    setOutputRange(0, maxWidth);\n    _updateProvidedTicks();\n\n    return tickDrawStrategy!.measureHorizontallyDrawnTicks(\n        _providedTicks!, maxWidth, maxHeight,\n        collision: hasTickCollision);\n  }\n\n  /// Layout this component.\n  @override\n  void layout(Rectangle<int> componentBounds, Rectangle<int> drawAreaBounds) {\n    _componentBounds = componentBounds;\n    _drawAreaBounds = drawAreaBounds;\n\n    // Update the output range if it is different than the current one.\n    // This is necessary because during the measure cycle, the output range is\n    // set between zero and the max range available. On layout, the output range\n    // needs to be updated to account of the offset of the axis view.\n\n    final outputStart =\n        isVertical ? componentBounds.bottom : componentBounds.left;\n    final outputEnd = isVertical ? componentBounds.top : componentBounds.right;\n\n    final outputRange = reverseOutputRange\n        ? ScaleOutputExtent(outputEnd, outputStart)\n        : ScaleOutputExtent(outputStart, outputEnd);\n\n    final scale = this.scale!;\n    if (scale.range != outputRange) {\n      scale.range = outputRange;\n    }\n\n    _updateProvidedTicks();\n    _updateProvidedTickWidth(_componentBounds!.width, _componentBounds!.height);\n    // Update animated ticks in layout, because updateTicks are called during\n    // measure and we don't want to update the animation at that time.\n    _updateAxisTicks();\n  }\n\n  @override\n  bool get isSeriesRenderer => false;\n\n  @override\n  Rectangle<int>? get componentBounds => _componentBounds;\n\n  bool get drawAxisLine {\n    if (forceDrawAxisLine != null) {\n      return forceDrawAxisLine!;\n    }\n\n    return tickDrawStrategy is SmallTickDrawStrategy;\n  }\n\n  @override\n  void paint(ChartCanvas canvas, double animationPercent) {\n    if (animationPercent == 1.0) {\n      _axisTicks.removeWhere((t) => t.markedForRemoval);\n    }\n\n    for (var i = 0; i < _axisTicks.length; i++) {\n      final animatedTick = _axisTicks[i];\n      tickDrawStrategy!.draw(\n          canvas, animatedTick..setCurrentTick(animationPercent),\n          orientation: axisOrientation!,\n          axisBounds: _componentBounds!,\n          collision: hasTickCollision,\n          drawAreaBounds: _drawAreaBounds!,\n          isFirst: i == 0,\n          isLast: i == _axisTicks.length - 1);\n    }\n\n    if (drawAxisLine) {\n      tickDrawStrategy!\n          .drawAxisLine(canvas, axisOrientation!, _componentBounds!);\n    }\n  }\n}\n\nclass NumericAxis extends Axis<num> {\n  NumericAxis({TickProvider<num>? tickProvider})\n      : super(\n          tickProvider: tickProvider ?? NumericTickProvider(),\n          tickFormatter: NumericTickFormatter(),\n          scale: LinearScale(),\n        );\n\n  void setScaleViewport(NumericExtents viewport) {\n    autoViewport = false;\n    (scale as NumericScale).viewportDomain = viewport;\n  }\n}\n\nclass OrdinalAxis extends Axis<String> {\n  OrdinalAxis({\n    TickDrawStrategy<String>? tickDrawStrategy,\n    TickProvider<String>? tickProvider,\n    TickFormatter<String>? tickFormatter,\n  }) : super(\n          tickProvider: tickProvider ?? const OrdinalTickProvider(),\n          tickFormatter: tickFormatter ?? const OrdinalTickFormatter(),\n          scale: SimpleOrdinalScale(),\n        ) {\n    this.tickDrawStrategy = tickDrawStrategy;\n  }\n\n  void setScaleViewport(OrdinalViewport viewport) {\n    autoViewport = false;\n    (scale as OrdinalScale)\n        .setViewport(viewport.dataSize, viewport.startingDomain);\n  }\n\n  @override\n  void layout(Rectangle<int> componentBounds, Rectangle<int> drawAreaBounds) {\n    super.layout(componentBounds, drawAreaBounds);\n\n    // We are purposely clearing the viewport starting domain and data size\n    // post layout.\n    //\n    // Originally we set a flag in [setScaleViewport] to recalculate viewport\n    // settings on next scale update and then reset the flag. This doesn't work\n    // because chart's measure cycle provides different ranges to the scale,\n    // causing the scale to update multiple times before it is finalized after\n    // layout.\n    //\n    // By resetting the viewport after layout, we guarantee the correct range\n    // was used to apply the viewport and behaviors that update the viewport\n    // based on translate and scale changes will not be affected (pan/zoom).\n    (scale as OrdinalScale).setViewport(null, null);\n  }\n}\n\n/// Viewport to cover [dataSize] data points starting at [startingDomain] value.\nclass OrdinalViewport {\n  final String startingDomain;\n  final int dataSize;\n\n  OrdinalViewport(this.startingDomain, this.dataSize);\n\n  @override\n  bool operator ==(Object other) {\n    return other is OrdinalViewport &&\n        startingDomain == other.startingDomain &&\n        dataSize == other.dataSize;\n  }\n\n  @override\n  int get hashCode {\n    var hashcode = startingDomain.hashCode;\n    hashcode = (hashcode * 37) + dataSize;\n    return hashcode;\n  }\n}\n\n@visibleForTesting\nclass AxisTester<D> {\n  final Axis<D> _axis;\n\n  AxisTester(this._axis);\n\n  List<AxisTicks<D>> get axisTicks => _axis._axisTicks;\n\n  MutableScale<D>? get scale => _axis.scale;\n\n  List<D> get axisValues => axisTicks.map((t) => t.value).toList();\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/cartesian/axis/axis_tick.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'tick.dart' show Tick;\n\nclass AxisTicks<D> extends Tick<D> implements Comparable<AxisTicks<D>> {\n  /// This tick is being animated out.\n  bool _markedForRemoval;\n\n  /// This tick's current location.\n  double? _currentLocation;\n\n  /// This tick's previous target location.\n  double? _previousLocation;\n\n  /// This tick's current target location.\n  double? _targetLocation;\n\n  /// This tick's current opacity.\n  double? _currentOpacity;\n\n  /// This tick's previous opacity.\n  double? _previousOpacity;\n\n  /// This tick's target opacity.\n  double? _targetOpacity;\n\n  AxisTicks(Tick<D> tick)\n      : // Set the initial target for a new animated tick.\n        _markedForRemoval = false,\n        _targetLocation = tick.locationPx,\n        super(\n            value: tick.value,\n            textElement: tick.textElement,\n            locationPx: tick.locationPx,\n            labelOffsetPx: tick.labelOffsetPx);\n\n  bool get markedForRemoval => _markedForRemoval;\n\n  /// Animate the tick in from [previousLocation].\n  void animateInFrom(double previousLocation) {\n    _markedForRemoval = false;\n    _previousLocation = previousLocation;\n    _previousOpacity = 0.0;\n    _targetOpacity = 1.0;\n  }\n\n  /// Animate out this tick to [newLocation].\n  void animateOut(double? newLocation) {\n    _markedForRemoval = true;\n    _previousLocation = _currentLocation;\n    _targetLocation = newLocation;\n    _previousOpacity = _currentOpacity;\n    _targetOpacity = 0.0;\n  }\n\n  /// Set new target for this tick to be [newLocation].\n  void setNewTarget(double? newLocation) {\n    _markedForRemoval = false;\n    _previousLocation = _currentLocation;\n    _targetLocation = newLocation;\n    _previousOpacity = _currentOpacity;\n    _targetOpacity = 1.0;\n  }\n\n  /// Update tick's location and opacity based on animation percent.\n  void setCurrentTick(double animationPercent) {\n    if (animationPercent == 1.0) {\n      _currentLocation = _targetLocation;\n      _previousLocation = _targetLocation;\n      _currentOpacity = markedForRemoval ? 0.0 : 1.0;\n    } else if (_previousLocation == null) {\n      _currentLocation = _targetLocation;\n      _currentOpacity = 1.0;\n    } else {\n      _currentLocation =\n          _lerpDouble(_previousLocation, _targetLocation, animationPercent);\n      _currentOpacity =\n          _lerpDouble(_previousOpacity, _targetOpacity, animationPercent);\n    }\n\n    locationPx = _currentLocation;\n    textElement!.opacity = _currentOpacity;\n  }\n\n  /// Linearly interpolate between two numbers.\n  ///\n  /// From lerpDouble in dart:ui which is Flutter only.\n  double? _lerpDouble(double? a, double? b, double t) {\n    if (a == null && b == null) return null;\n    a ??= 0.0;\n    b ??= 0.0;\n    return a + (b - a) * t;\n  }\n\n  @override\n  int compareTo(AxisTicks<D> other) =>\n      _targetLocation!.compareTo(other._targetLocation!);\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/cartesian/axis/collision_report.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'tick.dart' show Tick;\n\n/// A report that contains a list of ticks and if they collide.\nclass CollisionReport<D> {\n  /// If [ticks] collide.\n  final bool ticksCollide;\n\n  final List<Tick<D>> ticks;\n\n  final bool alternateTicksUsed;\n\n  CollisionReport(\n      {required this.ticksCollide,\n      required List<Tick<D>>? ticks,\n      bool? alternateTicksUsed})\n      : ticks = ticks ?? [],\n        alternateTicksUsed = alternateTicksUsed ?? false;\n\n  CollisionReport.empty()\n      : ticksCollide = false,\n        ticks = [],\n        alternateTicksUsed = false;\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/cartesian/axis/draw_strategy/base_tick_draw_strategy.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math';\n\nimport 'package:meta/meta.dart' show immutable, protected;\n\nimport '../../../../common/graphics_factory.dart' show GraphicsFactory;\nimport '../../../../common/line_style.dart' show LineStyle;\nimport '../../../../common/style/style_factory.dart' show StyleFactory;\nimport '../../../../common/text_element.dart'\n    show TextDirection, TextElement, MaxWidthStrategy;\nimport '../../../../common/text_style.dart' show TextStyle;\nimport '../../../common/chart_canvas.dart' show ChartCanvas;\nimport '../../../common/chart_context.dart' show ChartContext;\nimport '../../../layout/layout_view.dart' show ViewMeasuredSizes;\nimport '../axis.dart' show AxisOrientation;\nimport '../collision_report.dart' show CollisionReport;\nimport '../spec/axis_spec.dart'\n    show\n        TextStyleSpec,\n        TickLabelAnchor,\n        TickLabelJustification,\n        LineStyleSpec,\n        RenderSpec;\nimport '../tick.dart' show Tick;\nimport 'tick_draw_strategy.dart' show TickDrawStrategy;\n\n@immutable\nabstract class BaseRenderSpec<D> implements RenderSpec<D> {\n  final TextStyleSpec? labelStyle;\n  final TickLabelAnchor? labelAnchor;\n  final TickLabelJustification? labelJustification;\n\n  /// Distance from the axis line in px.\n  final int? labelOffsetFromAxisPx;\n\n  /// Distance from the axis line in px when a collision between ticks has\n  /// occurred.\n  final int? labelCollisionOffsetFromAxisPx;\n\n  /// Absolute distance from the tick to the text if using start/end\n  final int? labelOffsetFromTickPx;\n\n  /// Absolute distance from the tick to the text when a collision between ticks\n  /// has occurred.\n  final int? labelCollisionOffsetFromTickPx;\n\n  final int? minimumPaddingBetweenLabelsPx;\n\n  /// Angle of rotation for tick labels, in degrees. When set to a non-zero\n  /// value, all labels drawn for this axis will be rotated.\n  final int? labelRotation;\n\n  /// Angle of rotation for tick labels, in degrees when a collision between\n  /// ticks has occurred.\n  final int? labelCollisionRotation;\n\n  final LineStyleSpec? axisLineStyle;\n\n  const BaseRenderSpec({\n    this.labelStyle,\n    this.labelAnchor,\n    this.labelJustification,\n    this.labelOffsetFromAxisPx,\n    this.labelCollisionOffsetFromAxisPx,\n    this.labelOffsetFromTickPx,\n    this.labelCollisionOffsetFromTickPx,\n    this.minimumPaddingBetweenLabelsPx,\n    this.labelRotation,\n    this.labelCollisionRotation,\n    this.axisLineStyle,\n  });\n\n  @override\n  bool operator ==(Object other) {\n    return identical(this, other) ||\n        (other is BaseRenderSpec &&\n            labelStyle == other.labelStyle &&\n            labelAnchor == other.labelAnchor &&\n            labelJustification == other.labelJustification &&\n            labelOffsetFromTickPx == other.labelOffsetFromTickPx &&\n            labelCollisionOffsetFromTickPx ==\n                other.labelCollisionOffsetFromTickPx &&\n            labelOffsetFromAxisPx == other.labelOffsetFromAxisPx &&\n            labelCollisionOffsetFromAxisPx ==\n                other.labelCollisionOffsetFromAxisPx &&\n            minimumPaddingBetweenLabelsPx ==\n                other.minimumPaddingBetweenLabelsPx &&\n            labelRotation == other.labelRotation &&\n            labelCollisionRotation == other.labelCollisionRotation &&\n            axisLineStyle == other.axisLineStyle);\n  }\n\n  @override\n  int get hashCode {\n    var hashcode = labelStyle.hashCode;\n    hashcode = (hashcode * 37) + labelAnchor.hashCode;\n    hashcode = (hashcode * 37) + labelJustification.hashCode;\n    hashcode = (hashcode * 37) + labelOffsetFromTickPx.hashCode;\n    hashcode = (hashcode * 37) + labelCollisionOffsetFromTickPx.hashCode;\n    hashcode = (hashcode * 37) + labelOffsetFromAxisPx.hashCode;\n    hashcode = (hashcode * 37) + labelCollisionOffsetFromAxisPx.hashCode;\n    hashcode = (hashcode * 37) + minimumPaddingBetweenLabelsPx.hashCode;\n    hashcode = (hashcode * 37) + labelRotation.hashCode;\n    hashcode = (hashcode * 37) + labelCollisionRotation.hashCode;\n    hashcode = (hashcode * 37) + axisLineStyle.hashCode;\n    return hashcode;\n  }\n}\n\n/// Base strategy that draws tick labels and checks for label collisions.\nabstract class BaseTickDrawStrategy<D> implements TickDrawStrategy<D> {\n  static final _labelSplitPattern = '\\n';\n  static final multiLineLabelPadding = 2;\n\n  static double _degToRad(double deg) => deg * (pi / 180.0);\n\n  final ChartContext chartContext;\n  final GraphicsFactory graphicsFactory;\n\n  LineStyle axisLineStyle;\n  TextStyle labelStyle;\n  TickLabelJustification tickLabelJustification;\n  final TickLabelAnchor _defaultTickLabelAnchor;\n  final int _labelDefaultOffsetFromAxisPx;\n  final int _labelCollisionOffsetFromAxisPx;\n  final int _labelDefaultOffsetFromTickPx;\n  final int _labelCollisionOffsetFromTickPx;\n  final int _labelDefaultRotation;\n  final int _labelCollisionRotation;\n  final bool _rotateOnCollision;\n\n  int minimumPaddingBetweenLabelsPx;\n\n  int labelRotation({required bool collision}) =>\n      collision && _rotateOnCollision\n          ? _labelCollisionRotation\n          : _labelDefaultRotation;\n\n  int labelOffsetFromAxisPx({required bool collision}) =>\n      collision && _rotateOnCollision\n          ? _labelCollisionOffsetFromAxisPx\n          : _labelDefaultOffsetFromAxisPx;\n\n  int labelOffsetFromTickPx({required bool collision}) =>\n      collision && _rotateOnCollision\n          ? _labelCollisionOffsetFromTickPx\n          : _labelDefaultOffsetFromTickPx;\n\n  TickLabelAnchor tickLabelAnchor({required bool collision}) =>\n      collision && _rotateOnCollision\n          ? TickLabelAnchor.after\n          : _defaultTickLabelAnchor;\n\n  BaseTickDrawStrategy(\n    this.chartContext,\n    this.graphicsFactory, {\n    TextStyleSpec? labelStyleSpec,\n    LineStyleSpec? axisLineStyleSpec,\n    TickLabelAnchor? labelAnchor,\n    TickLabelJustification? labelJustification,\n    int? labelOffsetFromAxisPx,\n    int? labelCollisionOffsetFromAxisPx,\n    int? labelOffsetFromTickPx,\n    int? labelCollisionOffsetFromTickPx,\n    int? minimumPaddingBetweenLabelsPx,\n    int? labelRotation,\n    int? labelCollisionRotation,\n  })  : labelStyle = graphicsFactory.createTextPaint(),\n        axisLineStyle = graphicsFactory.createLinePaint(),\n        _defaultTickLabelAnchor = labelAnchor ?? TickLabelAnchor.centered,\n        tickLabelJustification =\n            labelJustification ?? TickLabelJustification.inside,\n        _rotateOnCollision = labelCollisionRotation != null,\n        minimumPaddingBetweenLabelsPx = minimumPaddingBetweenLabelsPx ?? 50,\n        _labelDefaultOffsetFromAxisPx = labelOffsetFromAxisPx ?? 5,\n        _labelDefaultOffsetFromTickPx = labelOffsetFromTickPx ?? 5,\n        _labelDefaultRotation = labelRotation ?? 0,\n        _labelCollisionOffsetFromAxisPx = labelCollisionOffsetFromAxisPx ?? 5,\n        _labelCollisionOffsetFromTickPx = labelCollisionOffsetFromTickPx ?? 5,\n        _labelCollisionRotation = labelCollisionRotation ?? 0 {\n    labelStyle\n      ..color = labelStyleSpec?.color ?? StyleFactory.style.tickColor\n      ..fontFamily = labelStyleSpec?.fontFamily\n      ..fontSize = labelStyleSpec?.fontSize ?? 12\n      ..lineHeight = labelStyleSpec?.lineHeight;\n\n    axisLineStyle\n      ..color = axisLineStyleSpec?.color ?? labelStyle.color\n      ..dashPattern = axisLineStyleSpec?.dashPattern\n      ..strokeWidth = axisLineStyleSpec?.thickness ?? 1;\n  }\n\n  @override\n  void decorateTicks(List<Tick<D>> ticks) {\n    for (final tick in ticks) {\n      var textElement = tick.textElement;\n      if (textElement == null) {\n        continue;\n      }\n\n      // If no style at all, set the default style.\n      if (textElement.textStyle == null) {\n        textElement.textStyle = labelStyle;\n      } else {\n        // Fill in whatever is missing\n        var textStyle = textElement.textStyle!;\n        textStyle.color ??= labelStyle.color;\n        textStyle.fontFamily ??= labelStyle.fontFamily;\n        textStyle.fontSize ??= labelStyle.fontSize;\n        textStyle.lineHeight ??= labelStyle.lineHeight;\n      }\n    }\n  }\n\n  @override\n  void updateTickWidth(List<Tick<D>> ticks, int maxWidth, int maxHeight,\n      AxisOrientation orientation,\n      {bool collision = false}) {\n    final isVertical =\n        orientation != null && orientation == AxisOrientation.right ||\n            orientation == AxisOrientation.left;\n    final rotationRelativeToAxis =\n        labelRotation(collision: collision).toDouble();\n    final rotationRads =\n        _degToRad(rotationRelativeToAxis - (isVertical ? 90 : 0)).abs();\n    final availableSpace = (isVertical ? maxWidth : maxHeight) -\n        labelOffsetFromAxisPx(collision: collision);\n    final maxTextWidth = sin(rotationRads) == 0\n        ? null\n        : (availableSpace / sin(rotationRads)).floor();\n\n    for (final tick in ticks) {\n      if (maxTextWidth != null) {\n        tick.textElement!.maxWidth = maxTextWidth;\n        tick.textElement!.maxWidthStrategy = MaxWidthStrategy.ellipsize;\n      } else {\n        tick.textElement!.maxWidth = null;\n        tick.textElement!.maxWidthStrategy = null;\n      }\n    }\n  }\n\n  @override\n  CollisionReport<D> collides(\n      List<Tick<D>>? ticks, AxisOrientation? orientation) {\n    // TODO: Collision analysis for rotated labels are not\n    // supported yet.\n\n    // If there are no ticks, they do not collide.\n    if (ticks == null) {\n      return CollisionReport(\n          ticksCollide: false, ticks: ticks, alternateTicksUsed: false);\n    }\n\n    final vertical = orientation == AxisOrientation.left ||\n        orientation == AxisOrientation.right;\n\n    ticks = [\n      for (var tick in ticks)\n        if (tick.locationPx != null) tick,\n    ];\n\n    // First sort ticks by smallest locationPx first (NOT sorted by value).\n    // This allows us to only check if a tick collides with the previous tick.\n    ticks.sort((a, b) => a.locationPx!.compareTo(b.locationPx!));\n\n    var previousEnd = double.negativeInfinity;\n    var collides = false;\n\n    for (final tick in ticks) {\n      final tickSize = tick.textElement?.measurement;\n      final tickLocationPx = tick.locationPx!;\n\n      if (vertical) {\n        final adjustedHeight = (tickSize?.verticalSliceWidth ?? 0.0) +\n            minimumPaddingBetweenLabelsPx;\n\n        if (_defaultTickLabelAnchor == TickLabelAnchor.inside) {\n          if (identical(tick, ticks.first)) {\n            // Top most tick draws down from the location\n            collides = false;\n            previousEnd = tickLocationPx + adjustedHeight;\n          } else if (identical(tick, ticks.last)) {\n            // Bottom most tick draws up from the location\n            collides = previousEnd > tickLocationPx - adjustedHeight;\n            previousEnd = tickLocationPx;\n          } else {\n            // All other ticks is centered.\n            final halfHeight = adjustedHeight / 2;\n            collides = previousEnd > tickLocationPx - halfHeight;\n            previousEnd = tickLocationPx + halfHeight;\n          }\n        } else {\n          collides = previousEnd > tickLocationPx;\n          previousEnd = tickLocationPx + adjustedHeight;\n        }\n      } else {\n        // Use the text direction the ticks specified, unless the label anchor\n        // is set to [TickLabelAnchor.inside]. When 'inside' is set, the text\n        // direction is normalized such that the left most tick is drawn ltr,\n        // the last tick is drawn rtl, and all other ticks are in the center.\n        // This is not set until it is painted, so collision check needs to get\n        // the value also.\n        final textDirection = _normalizeHorizontalAnchor(\n            _defaultTickLabelAnchor,\n            chartContext.isRtl,\n            identical(tick, ticks.first),\n            identical(tick, ticks.last));\n        final adjustedWidth = (tickSize?.horizontalSliceWidth ?? 0.0) +\n            minimumPaddingBetweenLabelsPx;\n        switch (textDirection) {\n          case TextDirection.ltr:\n            collides = previousEnd > tickLocationPx;\n            previousEnd = tickLocationPx + adjustedWidth;\n            break;\n          case TextDirection.rtl:\n            collides = previousEnd > (tickLocationPx - adjustedWidth);\n            previousEnd = tickLocationPx;\n            break;\n          case TextDirection.center:\n            final halfWidth = adjustedWidth / 2;\n            collides = previousEnd > tickLocationPx - halfWidth;\n            previousEnd = tickLocationPx + halfWidth;\n\n            break;\n        }\n      }\n\n      if (collides) {\n        return CollisionReport(\n            ticksCollide: true, ticks: ticks, alternateTicksUsed: false);\n      }\n    }\n\n    return CollisionReport(\n        ticksCollide: false, ticks: ticks, alternateTicksUsed: false);\n  }\n\n  @override\n  ViewMeasuredSizes measureVerticallyDrawnTicks(\n      List<Tick<D>> ticks, int maxWidth, int maxHeight,\n      {bool collision = false}) {\n    // TODO: Add spacing to account for the distance between the\n    // text and the axis baseline (even if it isn't drawn).\n\n    final maxHorizontalSliceWidth = ticks.fold(0.0, (double prevMax, tick) {\n      final labelElements = splitLabel(tick.textElement!);\n\n      return max(\n          prevMax,\n          calculateWidthForRotatedLabel(\n                labelRotation(collision: collision),\n                getLabelHeight(labelElements),\n                getLabelWidth(labelElements),\n              ) +\n              labelOffsetFromAxisPx(collision: collision));\n    }).round();\n\n    return ViewMeasuredSizes(\n        preferredWidth: maxHorizontalSliceWidth, preferredHeight: maxHeight);\n  }\n\n  @override\n  ViewMeasuredSizes measureHorizontallyDrawnTicks(\n      List<Tick<D>> ticks, int maxWidth, int maxHeight,\n      {bool collision = false}) {\n    final maxVerticalSliceWidth = ticks.fold(0.0, (double prevMax, tick) {\n      final labelElements = splitLabel(tick.textElement!);\n\n      return max(\n          prevMax,\n          calculateHeightForRotatedLabel(\n            labelRotation(collision: collision),\n            getLabelHeight(labelElements),\n            getLabelWidth(labelElements),\n          ));\n    }).round();\n\n    return ViewMeasuredSizes(\n        preferredWidth: maxWidth,\n        preferredHeight: min(\n            maxHeight,\n            maxVerticalSliceWidth +\n                labelOffsetFromAxisPx(collision: collision)));\n  }\n\n  @override\n  void drawAxisLine(ChartCanvas canvas, AxisOrientation orientation,\n      Rectangle<int> axisBounds) {\n    Point<num> start;\n    Point<num> end;\n\n    switch (orientation) {\n      case AxisOrientation.top:\n        start = axisBounds.bottomLeft;\n        end = axisBounds.bottomRight;\n        break;\n      case AxisOrientation.bottom:\n        start = axisBounds.topLeft;\n        end = axisBounds.topRight;\n        break;\n      case AxisOrientation.right:\n        start = axisBounds.topLeft;\n        end = axisBounds.bottomLeft;\n        break;\n      case AxisOrientation.left:\n        start = axisBounds.topRight;\n        end = axisBounds.bottomRight;\n        break;\n    }\n\n    canvas.drawLine(\n      points: [start, end],\n      fill: axisLineStyle.color,\n      stroke: axisLineStyle.color,\n      strokeWidthPx: axisLineStyle.strokeWidth.toDouble(),\n      dashPattern: axisLineStyle.dashPattern,\n    );\n  }\n\n  // TODO: Why is drawAreaBounds required when it is unused?\n  @protected\n  void drawLabel(\n    ChartCanvas canvas,\n    Tick<D> tick, {\n    required AxisOrientation orientation,\n    required Rectangle<int> axisBounds,\n    required Rectangle<int>? drawAreaBounds,\n    required bool isFirst,\n    required bool isLast,\n    bool collision = false,\n  }) {\n    final locationPx = tick.locationPx ?? 0;\n    final labelOffsetPx = tick.labelOffsetPx ?? 0;\n    final isRtl = chartContext.isRtl;\n    final labelElements = splitLabel(tick.textElement!);\n    final labelHeight = getLabelHeight(labelElements);\n    var multiLineLabelOffset = 0;\n\n    for (final line in labelElements) {\n      var x = 0;\n      var y = 0;\n\n      if (orientation == AxisOrientation.bottom ||\n          orientation == AxisOrientation.top) {\n        y = orientation == AxisOrientation.bottom\n            ? axisBounds.top + labelOffsetFromAxisPx(collision: collision)\n            : axisBounds.bottom -\n                (labelHeight.toInt() - multiLineLabelOffset) -\n                labelOffsetFromAxisPx(collision: collision);\n\n        final direction = _normalizeHorizontalAnchor(\n            tickLabelAnchor(collision: collision), isRtl, isFirst, isLast);\n\n        line.textDirection = direction;\n\n        switch (direction) {\n          case TextDirection.rtl:\n            x = (locationPx +\n                    labelOffsetFromTickPx(collision: collision) +\n                    labelOffsetPx)\n                .toInt();\n            break;\n          case TextDirection.ltr:\n            x = (locationPx -\n                    labelOffsetFromTickPx(collision: collision) -\n                    labelOffsetPx)\n                .toInt();\n            break;\n          case TextDirection.center:\n          default:\n            x = (locationPx - labelOffsetPx).toInt();\n            break;\n        }\n      } else {\n        if (orientation == AxisOrientation.left) {\n          if (tickLabelJustification == TickLabelJustification.inside) {\n            x = axisBounds.right - labelOffsetFromAxisPx(collision: collision);\n            line.textDirection = TextDirection.rtl;\n          } else {\n            x = axisBounds.left;\n            line.textDirection = TextDirection.ltr;\n          }\n        } else {\n          // orientation == right\n          if (tickLabelJustification == TickLabelJustification.inside) {\n            x = axisBounds.left + labelOffsetFromAxisPx(collision: collision);\n            line.textDirection = TextDirection.ltr;\n          } else {\n            x = axisBounds.right;\n            line.textDirection = TextDirection.rtl;\n          }\n        }\n\n        switch (normalizeVerticalAnchor(\n            tickLabelAnchor(collision: collision), isFirst, isLast)) {\n          case _PixelVerticalDirection.over:\n            y = (locationPx -\n                    (labelHeight - multiLineLabelOffset) -\n                    labelOffsetFromTickPx(collision: collision) -\n                    labelOffsetPx)\n                .toInt();\n            break;\n          case _PixelVerticalDirection.under:\n            y = (locationPx +\n                    labelOffsetFromTickPx(collision: collision) +\n                    labelOffsetPx)\n                .toInt();\n            break;\n          case _PixelVerticalDirection.center:\n          default:\n            y = (locationPx - labelHeight / 2 + labelOffsetPx).toInt();\n            break;\n        }\n      }\n      canvas.drawText(line, x, y + multiLineLabelOffset,\n          rotation: _degToRad(labelRotation(collision: collision).toDouble()));\n      multiLineLabelOffset +=\n          multiLineLabelPadding + line.measurement.verticalSliceWidth.round();\n    }\n  }\n\n  TextDirection _normalizeHorizontalAnchor(\n      TickLabelAnchor anchor, bool isRtl, bool isFirst, bool isLast) {\n    switch (anchor) {\n      case TickLabelAnchor.before:\n        return isRtl ? TextDirection.ltr : TextDirection.rtl;\n      case TickLabelAnchor.after:\n        return isRtl ? TextDirection.rtl : TextDirection.ltr;\n      case TickLabelAnchor.inside:\n        if (isFirst) {\n          return TextDirection.ltr;\n        }\n        if (isLast) {\n          return TextDirection.rtl;\n        }\n        return TextDirection.center;\n      case TickLabelAnchor.centered:\n      default:\n        return TextDirection.center;\n    }\n  }\n\n  @protected\n  _PixelVerticalDirection normalizeVerticalAnchor(\n      TickLabelAnchor anchor, bool isFirst, bool isLast) {\n    switch (anchor) {\n      case TickLabelAnchor.before:\n        return _PixelVerticalDirection.under;\n      case TickLabelAnchor.after:\n        return _PixelVerticalDirection.over;\n      case TickLabelAnchor.inside:\n        if (isFirst) {\n          return _PixelVerticalDirection.over;\n        }\n        if (isLast) {\n          return _PixelVerticalDirection.under;\n        }\n        return _PixelVerticalDirection.center;\n      case TickLabelAnchor.centered:\n      default:\n        return _PixelVerticalDirection.center;\n    }\n  }\n\n  /// Returns the width of a rotated labels on a domain axis.\n  double calculateWidthForRotatedLabel(\n      int rotation, double labelHeight, double labelLength) {\n    if (rotation == 0) return labelLength;\n    var rotationRadian = _degToRad(rotation.toDouble());\n\n    // Imagine a right triangle with a base that is parallel to the axis\n    // baseline. The side of this triangle that is perpendicular to the baseline\n    // is the height of the axis we wish to calculate. The hypotenuse of the\n    // triangle is the given length of the tick labels, labelLength. The angle\n    // between the perpendicular line and the hypotenuse (the tick label) is 90\n    // - the label rotation angle, since the tick label transformation is\n    // applied relative to the axis baseline. Given this triangle, we can\n    // calculate the height of the axis by using the cosine of this angle.\n\n    // The triangle assumes a zero-height line for the labels, but the actual\n    // rendered text will be drawn above and below this center line. To account\n    // for this, extend the label length by using a triangle with half the\n    // height of the label.\n    labelLength += labelHeight / 2.0 * tan(rotationRadian);\n\n    // To compute the label width, we need the angle between the label and a\n    // line perpendicular to the axis baseline, in radians.\n    return labelLength * cos(rotationRadian);\n  }\n\n  /// Returns the height of a rotated labels on a domain axis.\n  double calculateHeightForRotatedLabel(\n      int rotation, double labelHeight, double labelLength) {\n    if (rotation == 0) return labelHeight;\n    var rotationRadian = _degToRad(rotation.toDouble());\n\n    // Imagine a right triangle with a base that is parallel to the axis\n    // baseline. The side of this triangle that is perpendicular to the baseline\n    // is the height of the axis we wish to calculate. The hypotenuse of the\n    // triangle is the given length of the tick labels, labelLength. The angle\n    // between the perpendicular line and the hypotenuse (the tick label) is 90\n    // - the label rotation angle, since the tick label transformation is\n    // applied relative to the axis baseline. Given this triangle, we can\n    // calculate the height of the axis by using the cosine of this angle.\n\n    // The triangle assumes a zero-height line for the labels, but the actual\n    // rendered text will be drawn above and below this center line. To account\n    // for this, extend the label length by using a triangle with half the\n    // height of the label.\n    labelLength += labelHeight / 2.0 * tan(rotationRadian);\n\n    // To compute the label height, we need the angle between the label and a\n    // line perpendicular to the axis baseline, in radians.\n    var angle = pi / 2.0 - rotationRadian.abs();\n    return max(labelHeight, labelLength * cos(angle));\n  }\n\n  /// The [wholeLabel] is split into constituent chunks if it is multiline.\n  List<TextElement> splitLabel(TextElement wholeLabel) => wholeLabel.text\n      .split(_labelSplitPattern)\n      .map((line) => (graphicsFactory.createTextElement(line.trim())\n        ..textStyle = wholeLabel.textStyle))\n      .toList();\n\n  /// The width of the label (handles labels spanning multiple lines).\n  ///\n  /// If the label spans multiple lines then it returns the width of the\n  /// longest line.\n  double getLabelWidth(Iterable<TextElement> labelElements) => labelElements\n      .map((line) => line.measurement.horizontalSliceWidth)\n      .reduce(max);\n\n  /// The height of the label (handles labels spanning multiple lines).\n  double getLabelHeight(Iterable<TextElement> labelElements) {\n    if (labelElements.isEmpty) return 0;\n    final textHeight = labelElements.first.measurement.verticalSliceWidth;\n    final numLines = labelElements.length;\n    return (textHeight * numLines) + (multiLineLabelPadding * (numLines - 1));\n  }\n}\n\nenum _PixelVerticalDirection {\n  over,\n  center,\n  under,\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/cartesian/axis/draw_strategy/gridline_draw_strategy.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math';\n\nimport 'package:meta/meta.dart' show immutable;\n\nimport '../../../../common/graphics_factory.dart' show GraphicsFactory;\nimport '../../../../common/line_style.dart' show LineStyle;\nimport '../../../../common/style/style_factory.dart' show StyleFactory;\nimport '../../../common/chart_canvas.dart' show ChartCanvas;\nimport '../../../common/chart_context.dart' show ChartContext;\nimport '../axis.dart' show AxisOrientation;\nimport '../spec/axis_spec.dart'\n    show TextStyleSpec, LineStyleSpec, TickLabelAnchor, TickLabelJustification;\nimport '../tick.dart' show Tick;\nimport 'base_tick_draw_strategy.dart' show BaseTickDrawStrategy;\nimport 'small_tick_draw_strategy.dart' show SmallTickRendererSpec;\nimport 'tick_draw_strategy.dart' show TickDrawStrategy;\n\n@immutable\nclass GridlineRendererSpec<D> extends SmallTickRendererSpec<D> {\n  const GridlineRendererSpec({\n    TextStyleSpec? labelStyle,\n    LineStyleSpec? lineStyle,\n    LineStyleSpec? axisLineStyle,\n    TickLabelAnchor? labelAnchor,\n    TickLabelJustification? labelJustification,\n    int? tickLengthPx,\n    int? labelOffsetFromAxisPx,\n    int? labelCollisionOffsetFromAxisPx,\n    int? labelOffsetFromTickPx,\n    int? labelCollisionOffsetFromTickPx,\n    int? minimumPaddingBetweenLabelsPx,\n    int? labelRotation,\n    int? labelCollisionRotation,\n  }) : super(\n            labelStyle: labelStyle,\n            lineStyle: lineStyle,\n            labelAnchor: labelAnchor,\n            labelJustification: labelJustification,\n            labelOffsetFromAxisPx: labelOffsetFromAxisPx,\n            labelCollisionOffsetFromAxisPx: labelCollisionOffsetFromAxisPx,\n            labelOffsetFromTickPx: labelOffsetFromTickPx,\n            labelCollisionOffsetFromTickPx: labelCollisionOffsetFromTickPx,\n            minimumPaddingBetweenLabelsPx: minimumPaddingBetweenLabelsPx,\n            labelRotation: labelRotation,\n            labelCollisionRotation: labelCollisionRotation,\n            tickLengthPx: tickLengthPx,\n            axisLineStyle: axisLineStyle);\n\n  @override\n  TickDrawStrategy<D> createDrawStrategy(\n          ChartContext context, GraphicsFactory graphicsFactory) =>\n      GridlineTickDrawStrategy<D>(context, graphicsFactory,\n          tickLengthPx: tickLengthPx,\n          lineStyleSpec: lineStyle,\n          labelStyleSpec: labelStyle,\n          axisLineStyleSpec: axisLineStyle,\n          labelAnchor: labelAnchor,\n          labelJustification: labelJustification,\n          labelOffsetFromAxisPx: labelOffsetFromAxisPx,\n          labelCollisionOffsetFromAxisPx: labelCollisionOffsetFromAxisPx,\n          labelOffsetFromTickPx: labelOffsetFromTickPx,\n          labelCollisionOffsetFromTickPx: labelCollisionOffsetFromTickPx,\n          minimumPaddingBetweenLabelsPx: minimumPaddingBetweenLabelsPx,\n          labelRotation: labelRotation,\n          labelCollisionRotation: labelCollisionRotation);\n\n  @override\n  // ignore: hash_and_equals\n  bool operator ==(Object other) {\n    return identical(this, other) ||\n        (other is GridlineRendererSpec && super == other);\n  }\n}\n\n/// Draws line across chart draw area for each tick.\n///\n/// Extends [BaseTickDrawStrategy].\nclass GridlineTickDrawStrategy<D> extends BaseTickDrawStrategy<D> {\n  int tickLength;\n  LineStyle lineStyle;\n\n  GridlineTickDrawStrategy(\n    ChartContext chartContext,\n    GraphicsFactory graphicsFactory, {\n    int? tickLengthPx,\n    LineStyleSpec? lineStyleSpec,\n    TextStyleSpec? labelStyleSpec,\n    LineStyleSpec? axisLineStyleSpec,\n    TickLabelAnchor? labelAnchor,\n    TickLabelJustification? labelJustification,\n    int? labelOffsetFromAxisPx,\n    int? labelCollisionOffsetFromAxisPx,\n    int? labelOffsetFromTickPx,\n    int? labelCollisionOffsetFromTickPx,\n    int? minimumPaddingBetweenLabelsPx,\n    int? labelRotation,\n    int? labelCollisionRotation,\n  })  : tickLength = tickLengthPx ?? 0,\n        lineStyle = StyleFactory.style\n            .createGridlineStyle(graphicsFactory, lineStyleSpec),\n        super(chartContext, graphicsFactory,\n            labelStyleSpec: labelStyleSpec,\n            axisLineStyleSpec: axisLineStyleSpec ?? lineStyleSpec,\n            labelAnchor: labelAnchor,\n            labelJustification: labelJustification,\n            labelOffsetFromAxisPx: labelOffsetFromAxisPx,\n            labelCollisionOffsetFromAxisPx: labelCollisionOffsetFromAxisPx,\n            labelOffsetFromTickPx: labelOffsetFromTickPx,\n            labelCollisionOffsetFromTickPx: labelCollisionOffsetFromTickPx,\n            minimumPaddingBetweenLabelsPx: minimumPaddingBetweenLabelsPx,\n            labelRotation: labelRotation,\n            labelCollisionRotation: labelCollisionRotation);\n\n  @override\n  void draw(\n    ChartCanvas canvas,\n    Tick<D> tick, {\n    required AxisOrientation orientation,\n    required Rectangle<int> axisBounds,\n    required Rectangle<int> drawAreaBounds,\n    required bool isFirst,\n    required bool isLast,\n    bool collision = false,\n  }) {\n    Point<num> lineStart;\n    Point<num> lineEnd;\n    final tickLocationPx = tick.locationPx!;\n    switch (orientation) {\n      case AxisOrientation.top:\n        final x = tickLocationPx;\n        lineStart = Point(x, axisBounds.bottom - tickLength);\n        lineEnd = Point(x, drawAreaBounds.bottom);\n        break;\n      case AxisOrientation.bottom:\n        final x = tickLocationPx;\n        lineStart = Point(x, drawAreaBounds.top + tickLength);\n        lineEnd = Point(x, axisBounds.top);\n        break;\n      case AxisOrientation.right:\n        final y = tickLocationPx;\n        if (tickLabelAnchor(collision: collision) == TickLabelAnchor.after ||\n            tickLabelAnchor(collision: collision) == TickLabelAnchor.before) {\n          lineStart = Point(axisBounds.right, y);\n        } else {\n          lineStart = Point(axisBounds.left + tickLength, y);\n        }\n        lineEnd = Point(drawAreaBounds.left, y);\n        break;\n      case AxisOrientation.left:\n        final y = tickLocationPx;\n\n        if (tickLabelAnchor(collision: collision) == TickLabelAnchor.after ||\n            tickLabelAnchor(collision: collision) == TickLabelAnchor.before) {\n          lineStart = Point(axisBounds.left, y);\n        } else {\n          lineStart = Point(axisBounds.right - tickLength, y);\n        }\n        lineEnd = Point(drawAreaBounds.right, y);\n        break;\n    }\n\n    canvas.drawLine(\n      points: [lineStart, lineEnd],\n      dashPattern: lineStyle.dashPattern,\n      fill: lineStyle.color,\n      stroke: lineStyle.color,\n      strokeWidthPx: lineStyle.strokeWidth.toDouble(),\n    );\n\n    drawLabel(canvas, tick,\n        orientation: orientation,\n        axisBounds: axisBounds,\n        drawAreaBounds: drawAreaBounds,\n        isFirst: isFirst,\n        isLast: isLast,\n        collision: collision);\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/cartesian/axis/draw_strategy/none_draw_strategy.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math';\n\nimport 'package:meta/meta.dart' show immutable;\n\nimport '../../../../common/color.dart' show Color;\nimport '../../../../common/graphics_factory.dart' show GraphicsFactory;\nimport '../../../../common/line_style.dart' show LineStyle;\nimport '../../../../common/style/style_factory.dart' show StyleFactory;\nimport '../../../../common/text_style.dart' show TextStyle;\nimport '../../../common/chart_canvas.dart' show ChartCanvas;\nimport '../../../common/chart_context.dart' show ChartContext;\nimport '../../../layout/layout_view.dart' show ViewMeasuredSizes;\nimport '../axis.dart' show AxisOrientation;\nimport '../collision_report.dart' show CollisionReport;\nimport '../spec/axis_spec.dart' show RenderSpec, LineStyleSpec;\nimport '../tick.dart' show Tick;\nimport 'tick_draw_strategy.dart';\n\n/// Renders no ticks no labels, and claims no space in layout.\n/// However, it does render the axis line if asked to by the axis.\n@immutable\nclass NoneRenderSpec<D> extends RenderSpec<D> {\n  final LineStyleSpec? axisLineStyle;\n\n  const NoneRenderSpec({this.axisLineStyle});\n\n  @override\n  TickDrawStrategy<D> createDrawStrategy(\n          ChartContext context, GraphicsFactory graphicFactory) =>\n      NoneDrawStrategy<D>(context, graphicFactory,\n          axisLineStyleSpec: axisLineStyle);\n\n  @override\n  bool operator ==(Object other) =>\n      identical(this, other) || other is NoneRenderSpec;\n\n  @override\n  int get hashCode => 0;\n}\n\nclass NoneDrawStrategy<D> implements TickDrawStrategy<D> {\n  LineStyle axisLineStyle;\n  TextStyle noneTextStyle;\n\n  NoneDrawStrategy(\n    ChartContext chartContext,\n    GraphicsFactory graphicsFactory, {\n    LineStyleSpec? axisLineStyleSpec,\n  })  : axisLineStyle = StyleFactory.style\n            .createAxisLineStyle(graphicsFactory, axisLineStyleSpec),\n        noneTextStyle = graphicsFactory.createTextPaint()\n          ..color = Color.transparent\n          ..fontSize = 0;\n\n  @override\n  void updateTickWidth(List<Tick<D>> ticks, int maxWidth, int maxHeight,\n      AxisOrientation orientation,\n      {bool collision = false}) {}\n\n  @override\n  CollisionReport<D> collides(\n          List<Tick<D>>? ticks, AxisOrientation? orientation) =>\n      CollisionReport(ticksCollide: false, ticks: ticks);\n\n  @override\n  void decorateTicks(List<Tick<D>> ticks) {\n    // Even though no text is rendered, the text style for each element should\n    // still be set to handle the case of the draw strategy being switched to\n    // a different draw strategy. The new draw strategy will try to animate\n    // the old ticks out and the text style property is used.\n    ticks.forEach((tick) => tick.textElement!.textStyle = noneTextStyle);\n  }\n\n  @override\n  void drawAxisLine(ChartCanvas canvas, AxisOrientation orientation,\n      Rectangle<int> axisBounds) {\n    Point<num> start;\n    Point<num> end;\n\n    switch (orientation) {\n      case AxisOrientation.top:\n        start = axisBounds.bottomLeft;\n        end = axisBounds.bottomRight;\n\n        break;\n      case AxisOrientation.bottom:\n        start = axisBounds.topLeft;\n        end = axisBounds.topRight;\n        break;\n      case AxisOrientation.right:\n        start = axisBounds.topLeft;\n        end = axisBounds.bottomLeft;\n        break;\n      case AxisOrientation.left:\n        start = axisBounds.topRight;\n        end = axisBounds.bottomRight;\n        break;\n    }\n\n    canvas.drawLine(\n      points: [start, end],\n      dashPattern: axisLineStyle.dashPattern,\n      fill: axisLineStyle.color,\n      stroke: axisLineStyle.color,\n      strokeWidthPx: axisLineStyle.strokeWidth.toDouble(),\n    );\n  }\n\n  @override\n  void draw(ChartCanvas canvas, Tick<D> tick,\n      {required AxisOrientation orientation,\n      required Rectangle<int> axisBounds,\n      required Rectangle<int> drawAreaBounds,\n      required bool isFirst,\n      required bool isLast,\n      bool collision = false}) {}\n\n  @override\n  ViewMeasuredSizes measureHorizontallyDrawnTicks(\n      List<Tick<D>> ticks, int maxWidth, int maxHeight,\n      {bool collision = false}) {\n    return ViewMeasuredSizes(preferredWidth: 0, preferredHeight: 0);\n  }\n\n  @override\n  ViewMeasuredSizes measureVerticallyDrawnTicks(\n      List<Tick<D>> ticks, int maxWidth, int maxHeight,\n      {bool collision = false}) {\n    return ViewMeasuredSizes(preferredWidth: 0, preferredHeight: 0);\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/cartesian/axis/draw_strategy/range_tick_draw_strategy.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math';\n\nimport 'package:meta/meta.dart' show immutable;\n\nimport '../../../../common/graphics_factory.dart' show GraphicsFactory;\nimport '../../../../common/line_style.dart' show LineStyle;\nimport '../../../../common/material_palette.dart' show MaterialPalette;\nimport '../../../../common/style/style_factory.dart' show StyleFactory;\nimport '../../../../common/text_style.dart' show TextStyle;\nimport '../../../common/chart_canvas.dart' show ChartCanvas;\nimport '../../../common/chart_context.dart' show ChartContext;\nimport '../../../layout/layout_view.dart' show ViewMeasuredSizes;\nimport '../axis.dart' show AxisOrientation;\nimport '../range_axis_tick.dart' show RangeAxisTicks;\nimport '../spec/axis_spec.dart'\n    show TextStyleSpec, LineStyleSpec, TickLabelAnchor, TickLabelJustification;\nimport '../tick.dart' show Tick;\nimport 'base_tick_draw_strategy.dart' show BaseTickDrawStrategy;\nimport 'small_tick_draw_strategy.dart'\n    show SmallTickRendererSpec, SmallTickDrawStrategy;\nimport 'tick_draw_strategy.dart' show TickDrawStrategy;\n\n/// Displays individual ticks and range ticks and with a shade for ranges.\n/// Sample ticks looks like:\n/// -------------------------------------------------------------------\n///  |   |                       |            |                    |\n///  |   (Individual tick)       |            (Individual tick)    |\n///  |///////Range Label/////////|///////////Range Label///////////|\n@immutable\nclass RangeTickRendererSpec<D> extends SmallTickRendererSpec<D> {\n  // Specifies range shade's style.\n  final LineStyleSpec? rangeShadeStyle;\n  // Specifies range label text style.\n  final TextStyleSpec? rangeLabelStyle;\n  // Specifies range tick's length.\n  final int? rangeTickLengthPx;\n  // Specifies range shade's height.\n  final int? rangeShadeHeightPx;\n  // Specifies the starting offet of range shade from axis in pixels.\n  final int? rangeShadeOffsetFromAxisPx;\n  // A range tick offset from the original location. The start point offset is\n  // toward the origin and end point offset is toward the end of axis.\n  final int? rangeTickOffsetPx;\n\n  final TextStyleSpec defaultLabelStyleSpec;\n\n  static const int defaultLabelOffsetFromAxis = 2;\n  static const int defaultLabelOffsetFromTick = -4;\n\n  RangeTickRendererSpec(\n      {TextStyleSpec? labelStyle,\n      LineStyleSpec? lineStyle,\n      TickLabelAnchor? labelAnchor,\n      TickLabelJustification? labelJustification,\n      int? labelOffsetFromAxisPx,\n      int? labelCollisionOffsetFromAxisPx,\n      int? labelOffsetFromTickPx,\n      int? labelCollisionOffsetFromTickPx,\n      this.rangeShadeHeightPx,\n      this.rangeShadeOffsetFromAxisPx,\n      this.rangeShadeStyle,\n      this.rangeTickLengthPx,\n      this.rangeTickOffsetPx,\n      this.rangeLabelStyle,\n      int? tickLengthPx,\n      int? minimumPaddingBetweenLabelsPx,\n      int? labelRotation,\n      int? labelCollisionRotation})\n      : defaultLabelStyleSpec =\n            TextStyleSpec(fontSize: 9, color: StyleFactory.style.tickColor),\n        super(\n          axisLineStyle: lineStyle,\n          labelStyle: labelStyle,\n          labelAnchor: labelAnchor,\n          labelJustification: labelJustification,\n          labelOffsetFromAxisPx:\n              labelOffsetFromAxisPx ?? defaultLabelOffsetFromAxis,\n          labelCollisionOffsetFromAxisPx: labelCollisionOffsetFromAxisPx,\n          labelOffsetFromTickPx:\n              labelOffsetFromTickPx ?? defaultLabelOffsetFromTick,\n          labelCollisionOffsetFromTickPx: labelCollisionOffsetFromTickPx,\n          tickLengthPx: tickLengthPx,\n          minimumPaddingBetweenLabelsPx: minimumPaddingBetweenLabelsPx,\n          labelRotation: labelRotation,\n          labelCollisionRotation: labelCollisionRotation,\n        );\n\n  @override\n  TickDrawStrategy<D> createDrawStrategy(\n          ChartContext context, GraphicsFactory graphicsFactory) =>\n      RangeTickDrawStrategy<D>(context, graphicsFactory,\n          tickLength: tickLengthPx,\n          rangeLabelTextStyleSpec: rangeLabelStyle,\n          rangeTickLength: rangeTickLengthPx,\n          rangeShadeHeight: rangeShadeHeightPx,\n          rangeShadeOffsetFromAxis: rangeShadeOffsetFromAxisPx,\n          rangeTickOffset: rangeTickOffsetPx,\n          lineStyleSpec: lineStyle,\n          labelStyleSpec: labelStyle ?? defaultLabelStyleSpec,\n          axisLineStyleSpec: axisLineStyle,\n          rangeShadeStyleSpec: rangeShadeStyle,\n          labelAnchor: labelAnchor,\n          labelJustification: labelJustification,\n          labelOffsetFromAxisPx: labelOffsetFromAxisPx,\n          labelCollisionOffsetFromAxisPx: labelCollisionOffsetFromAxisPx,\n          labelOffsetFromTickPx: labelOffsetFromTickPx,\n          labelCollisionOffsetFromTickPx: labelCollisionOffsetFromTickPx,\n          minimumPaddingBetweenLabelsPx: minimumPaddingBetweenLabelsPx,\n          labelRotation: labelRotation,\n          labelCollisionRotation: labelCollisionRotation);\n\n  @override\n  // ignore: hash_and_equals\n  bool operator ==(Object other) {\n    return identical(this, other) ||\n        (other is RangeTickRendererSpec && super == other);\n  }\n}\n\n/// Draws small tick lines for each tick. Extends [BaseTickDrawStrategy].\nclass RangeTickDrawStrategy<D> extends SmallTickDrawStrategy<D> {\n  int rangeTickLengthPx = 24;\n  int rangeShadeHeightPx = 12;\n  int rangeShadeOffsetFromAxisPx = 12;\n  int rangeTickOffsetPx = 12;\n  late LineStyle rangeShadeStyle;\n  late TextStyle rangeLabelStyle;\n\n  RangeTickDrawStrategy(\n      ChartContext chartContext, GraphicsFactory graphicsFactory,\n      {int? tickLength,\n      int? rangeTickLength,\n      int? rangeShadeHeight,\n      int? rangeShadeOffsetFromAxis,\n      int? rangeTickOffset,\n      TextStyleSpec? rangeLabelTextStyleSpec,\n      LineStyleSpec? lineStyleSpec,\n      LineStyleSpec? rangeShadeStyleSpec,\n      TextStyleSpec? labelStyleSpec,\n      LineStyleSpec? axisLineStyleSpec,\n      TickLabelAnchor? labelAnchor,\n      int? labelOffsetFromAxisPx,\n      int? labelCollisionOffsetFromAxisPx,\n      int? labelOffsetFromTickPx,\n      int? labelCollisionOffsetFromTickPx,\n      TickLabelJustification? labelJustification,\n      int? minimumPaddingBetweenLabelsPx,\n      int? labelRotation,\n      int? labelCollisionRotation})\n      : super(chartContext, graphicsFactory,\n            tickLengthPx: tickLength,\n            axisLineStyleSpec: axisLineStyleSpec,\n            labelStyleSpec: labelStyleSpec,\n            lineStyleSpec: lineStyleSpec,\n            labelAnchor: labelAnchor ?? TickLabelAnchor.after,\n            labelJustification: labelJustification,\n            labelOffsetFromAxisPx: labelOffsetFromAxisPx,\n            labelCollisionOffsetFromAxisPx: labelCollisionOffsetFromAxisPx,\n            labelOffsetFromTickPx: labelOffsetFromTickPx,\n            labelCollisionOffsetFromTickPx: labelCollisionOffsetFromTickPx,\n            minimumPaddingBetweenLabelsPx: minimumPaddingBetweenLabelsPx,\n            labelRotation: labelRotation,\n            labelCollisionRotation: labelCollisionRotation) {\n    rangeTickOffsetPx = rangeTickOffset ?? rangeTickOffsetPx;\n    rangeTickLengthPx = rangeTickLength ?? rangeTickLengthPx;\n    rangeShadeHeightPx = rangeShadeHeight ?? rangeShadeHeightPx;\n    rangeShadeOffsetFromAxisPx =\n        rangeShadeOffsetFromAxis ?? rangeShadeOffsetFromAxisPx;\n    lineStyle =\n        StyleFactory.style.createTickLineStyle(graphicsFactory, lineStyleSpec);\n    rangeShadeStyleSpec = rangeShadeStyleSpec ??\n        LineStyleSpec(\n          color: MaterialPalette.gray.shade300,\n        );\n    rangeShadeStyle = StyleFactory.style\n        .createTickLineStyle(graphicsFactory, rangeShadeStyleSpec);\n    rangeLabelStyle = rangeLabelTextStyleSpec == null\n        ? (graphicsFactory.createTextPaint()\n          ..color = labelStyleSpec?.color ?? StyleFactory.style.tickColor\n          ..fontFamily = labelStyleSpec?.fontFamily\n          ..fontSize = rangeShadeHeightPx - 1)\n        : (graphicsFactory.createTextPaint()\n          ..color = rangeLabelTextStyleSpec.color\n          ..fontFamily = rangeLabelTextStyleSpec.fontFamily\n          ..fontSize = rangeLabelTextStyleSpec.fontSize\n          ..lineHeight = rangeLabelTextStyleSpec.lineHeight);\n  }\n\n  @override\n  void draw(ChartCanvas canvas, Tick<D> tick,\n      {required AxisOrientation orientation,\n      required Rectangle<int> axisBounds,\n      required Rectangle<int> drawAreaBounds,\n      required bool isFirst,\n      required bool isLast,\n      bool collision = false}) {\n    if (tick is RangeAxisTicks<D>) {\n      drawRangeShadeAndRangeLabel(tick, canvas, orientation, axisBounds,\n          drawAreaBounds, isFirst, isLast);\n    } else {\n      super.draw(canvas, tick,\n          orientation: orientation,\n          axisBounds: axisBounds,\n          drawAreaBounds: drawAreaBounds,\n          isFirst: isFirst,\n          isLast: isLast,\n          collision: collision);\n    }\n  }\n\n  @override\n  ViewMeasuredSizes measureVerticallyDrawnTicks(\n      List<Tick<D>> ticks, int maxWidth, int maxHeight,\n      {bool collision = false}) {\n    // TODO: Add spacing to account for the distance between the\n    // text and the axis baseline (even if it isn't drawn).\n\n    final maxHorizontalSliceWidth = ticks.fold(0.0, (num prevMax, tick) {\n      assert(tick.textElement != null);\n      final labelElements = splitLabel(tick.textElement!);\n      if (tick is RangeAxisTicks) {\n        // Find the maximum within prevMax, label total height and\n        // labelOffsetFromAxisPx + rangeShadeHeightPx.\n        return max(\n            max(\n                prevMax,\n                calculateWidthForRotatedLabel(\n                      labelRotation(collision: collision),\n                      getLabelHeight(labelElements),\n                      getLabelWidth(labelElements),\n                    ) +\n                    labelOffsetFromAxisPx(collision: collision)),\n            labelOffsetFromAxisPx(collision: collision) + rangeShadeHeightPx);\n      } else {\n        return max(\n            prevMax,\n            calculateWidthForRotatedLabel(\n                  labelRotation(collision: collision),\n                  getLabelHeight(labelElements),\n                  getLabelWidth(labelElements),\n                ) +\n                labelOffsetFromAxisPx(collision: collision));\n      }\n    }).round();\n\n    return ViewMeasuredSizes(\n        preferredWidth: maxHorizontalSliceWidth, preferredHeight: maxHeight);\n  }\n\n  @override\n  ViewMeasuredSizes measureHorizontallyDrawnTicks(\n      List<Tick<D>> ticks, int maxWidth, int maxHeight,\n      {bool collision = false}) {\n    var maxVerticalSliceWidth = ticks.fold(0.0, (num prevMax, tick) {\n      final labelElements = splitLabel(tick.textElement!);\n\n      if (tick is RangeAxisTicks) {\n        // Find the maximum within prevMax, label total height and\n        // labelOffsetFromAxisPx + rangeShadeHeightPx.\n        return max(\n            max(\n              prevMax,\n              calculateHeightForRotatedLabel(\n                    labelRotation(collision: collision),\n                    getLabelHeight(labelElements),\n                    getLabelWidth(labelElements),\n                  ) +\n                  rangeShadeOffsetFromAxisPx,\n            ),\n            rangeShadeOffsetFromAxisPx + rangeShadeHeightPx);\n      } else {\n        return max(\n                prevMax,\n                calculateHeightForRotatedLabel(\n                  labelRotation(collision: collision),\n                  getLabelHeight(labelElements),\n                  getLabelWidth(labelElements),\n                )) +\n            labelOffsetFromAxisPx(collision: collision);\n      }\n    }).round();\n\n    return ViewMeasuredSizes(\n        preferredWidth: maxWidth, preferredHeight: maxVerticalSliceWidth);\n  }\n\n  void drawRangeShadeAndRangeLabel(\n    RangeAxisTicks<D> tick,\n    ChartCanvas canvas,\n    AxisOrientation orientation,\n    Rectangle<int> axisBounds,\n    Rectangle<int> drawAreaBounds,\n    bool isFirst,\n    bool isLast,\n  ) {\n    // Create virtual range start and end ticks for position calculation.\n    var rangeStartTick = Tick<D>(\n      value: tick.rangeStartValue,\n      locationPx: tick.rangeStartLocationPx - rangeTickOffsetPx,\n      textElement: null,\n    );\n    var rangeEndTick = Tick<D>(\n      value: tick.rangeEndValue,\n      locationPx: isLast\n          ? tick.rangeEndLocationPx + rangeTickOffsetPx\n          : tick.rangeEndLocationPx - rangeTickOffsetPx,\n      textElement: null,\n    );\n    // Calculate range start positions.\n    var rangeStartPositions = calculateTickPositions(rangeStartTick,\n        orientation, axisBounds, drawAreaBounds, rangeTickLengthPx);\n    var rangeStartTickStart = rangeStartPositions.first;\n    var rangeStartTickEnd = rangeStartPositions.last;\n\n    // Calculate range end positions.\n    var rangeEndPositions = calculateTickPositions(rangeEndTick, orientation,\n        axisBounds, drawAreaBounds, rangeTickLengthPx);\n    var rangeEndTickStart = rangeEndPositions.first;\n    var rangeEndTickEnd = rangeEndPositions.last;\n\n    // Draw range shade.\n    Rectangle rangeShade;\n    switch (orientation) {\n      case AxisOrientation.top:\n      case AxisOrientation.bottom:\n        rangeShade = Rectangle(\n            rangeStartTickStart.x,\n            rangeStartTickStart.y + rangeShadeOffsetFromAxisPx,\n            rangeEndTickStart.x - rangeStartTickStart.x,\n            rangeShadeHeightPx);\n        break;\n      case AxisOrientation.right:\n        rangeShade = Rectangle(\n            rangeEndTickStart.x + rangeShadeOffsetFromAxisPx,\n            rangeEndTickStart.y,\n            rangeShadeHeightPx,\n            rangeEndTickStart.y - rangeEndTickStart.y);\n        break;\n      case AxisOrientation.left:\n        rangeShade = Rectangle(\n            rangeEndTickStart.x -\n                rangeShadeOffsetFromAxisPx -\n                rangeShadeHeightPx,\n            rangeEndTickStart.y,\n            rangeShadeHeightPx,\n            rangeEndTickStart.y - rangeEndTickStart.y);\n        break;\n    }\n    canvas.drawRect(rangeShade,\n        fill: rangeShadeStyle.color,\n        stroke: rangeShadeStyle.color,\n        strokeWidthPx: rangeShadeStyle.strokeWidth.toDouble());\n\n    // Draw the start and end boundaries of the range.\n    canvas.drawLine(\n      points: [rangeStartTickStart, rangeStartTickEnd],\n      dashPattern: lineStyle.dashPattern,\n      fill: lineStyle.color,\n      stroke: lineStyle.color,\n      strokeWidthPx: lineStyle.strokeWidth.toDouble(),\n    );\n    canvas.drawLine(\n      points: [rangeEndTickStart, rangeEndTickEnd],\n      dashPattern: lineStyle.dashPattern,\n      fill: lineStyle.color,\n      stroke: lineStyle.color,\n      strokeWidthPx: lineStyle.strokeWidth.toDouble(),\n    );\n\n    // Prepare range label.\n    final rangeLabelTextElement = tick.textElement!\n      ..textStyle = rangeLabelStyle;\n\n    final labelElements = splitLabel(rangeLabelTextElement);\n    final labelWidth = getLabelWidth(labelElements);\n\n    // Draw range label on top of range shade.\n    var multiLineLabelOffset = 0;\n    for (final line in labelElements) {\n      var x = 0;\n      var y = 0;\n\n      if (orientation == AxisOrientation.bottom ||\n          orientation == AxisOrientation.top) {\n        y = rangeStartTickStart.y.toInt() + rangeShadeOffsetFromAxisPx - 1;\n\n        x = (rangeStartTickStart.x +\n                (rangeEndTickStart.x - rangeStartTickStart.x - labelWidth) / 2)\n            .round();\n      }\n      // TODO: add support for orientation left and right.\n      canvas.drawText(line, x, y + multiLineLabelOffset);\n      multiLineLabelOffset += BaseTickDrawStrategy.multiLineLabelPadding +\n          line.measurement.verticalSliceWidth.round();\n    }\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/cartesian/axis/draw_strategy/small_tick_draw_strategy.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math';\n\nimport 'package:meta/meta.dart' show immutable;\n\nimport '../../../../common/graphics_factory.dart' show GraphicsFactory;\nimport '../../../../common/line_style.dart' show LineStyle;\nimport '../../../../common/style/style_factory.dart' show StyleFactory;\nimport '../../../common/chart_canvas.dart' show ChartCanvas;\nimport '../../../common/chart_context.dart' show ChartContext;\nimport '../axis.dart' show AxisOrientation;\nimport '../spec/axis_spec.dart'\n    show TextStyleSpec, LineStyleSpec, TickLabelAnchor, TickLabelJustification;\nimport '../tick.dart' show Tick;\nimport 'base_tick_draw_strategy.dart' show BaseRenderSpec, BaseTickDrawStrategy;\nimport 'tick_draw_strategy.dart' show TickDrawStrategy;\n\n@immutable\nclass SmallTickRendererSpec<D> extends BaseRenderSpec<D> {\n  final LineStyleSpec? lineStyle;\n  final int? tickLengthPx;\n\n  const SmallTickRendererSpec({\n    TextStyleSpec? labelStyle,\n    this.lineStyle,\n    LineStyleSpec? axisLineStyle,\n    TickLabelAnchor? labelAnchor,\n    TickLabelJustification? labelJustification,\n    int? labelOffsetFromAxisPx,\n    int? labelCollisionOffsetFromAxisPx,\n    int? labelOffsetFromTickPx,\n    int? labelCollisionOffsetFromTickPx,\n    this.tickLengthPx,\n    int? minimumPaddingBetweenLabelsPx,\n    int? labelRotation,\n    int? labelCollisionRotation,\n  }) : super(\n            labelStyle: labelStyle,\n            labelAnchor: labelAnchor,\n            labelJustification: labelJustification,\n            labelOffsetFromAxisPx: labelOffsetFromAxisPx,\n            labelCollisionOffsetFromAxisPx: labelCollisionOffsetFromAxisPx,\n            labelOffsetFromTickPx: labelOffsetFromTickPx,\n            labelCollisionOffsetFromTickPx: labelCollisionOffsetFromTickPx,\n            minimumPaddingBetweenLabelsPx: minimumPaddingBetweenLabelsPx,\n            labelRotation: labelRotation,\n            labelCollisionRotation: labelCollisionRotation,\n            axisLineStyle: axisLineStyle);\n\n  @override\n  TickDrawStrategy<D> createDrawStrategy(\n          ChartContext context, GraphicsFactory graphicsFactory) =>\n      SmallTickDrawStrategy<D>(\n        context,\n        graphicsFactory,\n        tickLengthPx: tickLengthPx,\n        lineStyleSpec: lineStyle,\n        labelStyleSpec: labelStyle,\n        axisLineStyleSpec: axisLineStyle,\n        labelAnchor: labelAnchor,\n        labelJustification: labelJustification,\n        labelOffsetFromAxisPx: labelOffsetFromAxisPx,\n        labelCollisionOffsetFromAxisPx: labelCollisionOffsetFromAxisPx,\n        labelOffsetFromTickPx: labelOffsetFromTickPx,\n        labelCollisionOffsetFromTickPx: labelCollisionOffsetFromTickPx,\n        minimumPaddingBetweenLabelsPx: minimumPaddingBetweenLabelsPx,\n        labelRotation: labelRotation,\n        labelCollisionRotation: labelCollisionRotation,\n      );\n\n  @override\n  bool operator ==(Object other) {\n    return identical(this, other) ||\n        (other is SmallTickRendererSpec &&\n            lineStyle == other.lineStyle &&\n            tickLengthPx == other.tickLengthPx &&\n            super == other);\n  }\n\n  @override\n  int get hashCode {\n    var hashcode = lineStyle.hashCode;\n    hashcode = (hashcode * 37) + tickLengthPx.hashCode;\n    hashcode = (hashcode * 37) + super.hashCode;\n    return hashcode;\n  }\n}\n\n/// Draws small tick lines for each tick. Extends [BaseTickDrawStrategy].\nclass SmallTickDrawStrategy<D> extends BaseTickDrawStrategy<D> {\n  int tickLength;\n  LineStyle lineStyle;\n\n  SmallTickDrawStrategy(\n      ChartContext chartContext, GraphicsFactory graphicsFactory,\n      {int? tickLengthPx,\n      LineStyleSpec? lineStyleSpec,\n      TextStyleSpec? labelStyleSpec,\n      LineStyleSpec? axisLineStyleSpec,\n      TickLabelAnchor? labelAnchor,\n      TickLabelJustification? labelJustification,\n      int? labelOffsetFromAxisPx,\n      int? labelCollisionOffsetFromAxisPx,\n      int? labelOffsetFromTickPx,\n      int? labelCollisionOffsetFromTickPx,\n      int? minimumPaddingBetweenLabelsPx,\n      int? labelRotation,\n      int? labelCollisionRotation})\n      : tickLength = tickLengthPx ?? StyleFactory.style.tickLength,\n        lineStyle = StyleFactory.style\n            .createTickLineStyle(graphicsFactory, lineStyleSpec),\n        super(\n          chartContext,\n          graphicsFactory,\n          labelStyleSpec: labelStyleSpec,\n          axisLineStyleSpec: axisLineStyleSpec ?? lineStyleSpec,\n          labelAnchor: labelAnchor,\n          labelJustification: labelJustification,\n          labelOffsetFromAxisPx: labelOffsetFromAxisPx,\n          labelCollisionOffsetFromAxisPx: labelCollisionOffsetFromAxisPx,\n          labelOffsetFromTickPx: labelOffsetFromTickPx,\n          labelCollisionOffsetFromTickPx: labelCollisionOffsetFromTickPx,\n          minimumPaddingBetweenLabelsPx: minimumPaddingBetweenLabelsPx,\n          labelRotation: labelRotation,\n          labelCollisionRotation: labelCollisionRotation,\n        );\n\n  @override\n  void draw(ChartCanvas canvas, Tick<D> tick,\n      {required AxisOrientation orientation,\n      required Rectangle<int> axisBounds,\n      required Rectangle<int> drawAreaBounds,\n      required bool isFirst,\n      required bool isLast,\n      bool collision = false}) {\n    var tickPositions = calculateTickPositions(\n      tick,\n      orientation,\n      axisBounds,\n      drawAreaBounds,\n      tickLength,\n    );\n    final tickStart = tickPositions.first;\n    final tickEnd = tickPositions.last;\n\n    canvas.drawLine(\n      points: [tickStart, tickEnd],\n      dashPattern: lineStyle.dashPattern,\n      fill: lineStyle.color,\n      stroke: lineStyle.color,\n      strokeWidthPx: lineStyle.strokeWidth.toDouble(),\n    );\n\n    drawLabel(canvas, tick,\n        orientation: orientation,\n        axisBounds: axisBounds,\n        drawAreaBounds: drawAreaBounds,\n        isFirst: isFirst,\n        isLast: isLast,\n        collision: collision);\n  }\n\n  List<Point<num>> calculateTickPositions(\n    Tick<D> tick,\n    AxisOrientation orientation,\n    Rectangle<int> axisBounds,\n    Rectangle<int> drawAreaBounds,\n    int tickLength,\n  ) {\n    Point<num> tickStart;\n    Point<num> tickEnd;\n    final tickLocationPx = tick.locationPx!;\n    switch (orientation) {\n      case AxisOrientation.top:\n        final x = tickLocationPx;\n        tickStart = Point(x, axisBounds.bottom - tickLength);\n        tickEnd = Point(x, axisBounds.bottom);\n        break;\n      case AxisOrientation.bottom:\n        final x = tickLocationPx;\n        tickStart = Point(x, axisBounds.top);\n        tickEnd = Point(x, axisBounds.top + tickLength);\n        break;\n      case AxisOrientation.right:\n        final y = tickLocationPx;\n        tickStart = Point(axisBounds.left, y);\n        tickEnd = Point(axisBounds.left + tickLength, y);\n        break;\n      case AxisOrientation.left:\n        final y = tickLocationPx;\n        tickStart = Point(axisBounds.right - tickLength, y);\n        tickEnd = Point(axisBounds.right, y);\n        break;\n    }\n    return [tickStart, tickEnd];\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/cartesian/axis/draw_strategy/tick_draw_strategy.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math';\n\nimport '../../../common/chart_canvas.dart' show ChartCanvas;\nimport '../../../layout/layout_view.dart' show ViewMeasuredSizes;\nimport '../axis.dart' show AxisOrientation;\nimport '../collision_report.dart' show CollisionReport;\nimport '../tick.dart' show Tick;\n\n/// Strategy for drawing ticks and checking for collisions.\nabstract class TickDrawStrategy<D> {\n  /// Decorate the existing list of ticks.\n  ///\n  /// This can be used to further modify ticks after they have been generated\n  /// with location data and formatted labels.\n  void decorateTicks(List<Tick<D>> ticks);\n\n  /// Returns a [CollisionReport] indicating if there are any collisions.\n  CollisionReport<D> collides(\n      List<Tick<D>>? ticks, AxisOrientation? orientation);\n\n  /// Returns measurement of ticks drawn vertically.\n  ViewMeasuredSizes measureVerticallyDrawnTicks(\n      List<Tick<D>> ticks, int maxWidth, int maxHeight,\n      {bool collision = false});\n\n  /// Returns measurement of ticks drawn horizontally.\n  ViewMeasuredSizes measureHorizontallyDrawnTicks(\n      List<Tick<D>> ticks, int maxWidth, int maxHeight,\n      {bool collision = false});\n\n  /// Updates max tick width to match fit max size.\n  void updateTickWidth(List<Tick<D>> ticks, int maxWidth, int maxHeight,\n      AxisOrientation orientation,\n      {bool collision = false});\n\n  /// Draws tick onto [ChartCanvas].\n  ///\n  /// [orientation] the orientation of the axis that this [tick] belongs to.\n  /// [axisBounds] the bounds of the axis.\n  /// [drawAreaBounds] the bounds of the chart draw area adjacent to the axis.\n  /// [collision] whether or not this [tick] should be drawn in such a way to\n  /// avoid colliding into other ticks.\n  void draw(ChartCanvas canvas, Tick<D> tick,\n      {required AxisOrientation orientation,\n      required Rectangle<int> axisBounds,\n      required Rectangle<int> drawAreaBounds,\n      required bool isFirst,\n      required bool isLast,\n      bool collision = false});\n\n  void drawAxisLine(ChartCanvas canvas, AxisOrientation orientation,\n      Rectangle<int> axisBounds);\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/cartesian/axis/end_points_tick_provider.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport '../../../common/graphics_factory.dart' show GraphicsFactory;\nimport '../../common/chart_context.dart' show ChartContext;\nimport 'axis.dart' show AxisOrientation;\nimport 'draw_strategy/tick_draw_strategy.dart' show TickDrawStrategy;\nimport 'numeric_scale.dart' show NumericScale;\nimport 'ordinal_scale.dart' show OrdinalScale;\nimport 'scale.dart' show MutableScale;\nimport 'tick.dart' show Tick;\nimport 'tick_formatter.dart' show TickFormatter;\nimport 'tick_provider.dart' show BaseTickProvider, TickHint;\nimport 'time/date_time_scale.dart' show DateTimeScale;\n\n/// Tick provider that provides ticks at the two end points of the axis range.\nclass EndPointsTickProvider<D> extends BaseTickProvider<D> {\n  @override\n  List<Tick<D>> getTicks({\n    required ChartContext? context,\n    required GraphicsFactory graphicsFactory,\n    required MutableScale<D> scale,\n    required TickFormatter<D> formatter,\n    required Map<D, String> formatterValueCache,\n    required TickDrawStrategy<D> tickDrawStrategy,\n    required AxisOrientation? orientation,\n    bool viewportExtensionEnabled = false,\n    TickHint<D>? tickHint,\n  }) {\n    final ticks = <Tick<D>>[];\n\n    // Check to see if the axis has been configured with some domain values.\n    //\n    // An un-configured axis has no domain step size, and its scale defaults to\n    // infinity.\n    if (scale.domainStepSize.abs() != double.infinity) {\n      final start = _getStartValue(tickHint, scale);\n      final end = _getEndValue(tickHint, scale);\n\n      final labels = formatter.format([start, end], formatterValueCache,\n          stepSize: scale.domainStepSize);\n\n      if (start != null) {\n        ticks.add(Tick(\n            value: start,\n            textElement: graphicsFactory.createTextElement(labels[0]),\n            locationPx: scale[start]?.toDouble()));\n      }\n\n      if (end != null) {\n        ticks.add(Tick(\n            value: end,\n            textElement: graphicsFactory.createTextElement(labels[1]),\n            locationPx: scale[end]?.toDouble()));\n      }\n\n      // Allow draw strategy to decorate the ticks.\n      tickDrawStrategy.decorateTicks(ticks);\n    }\n\n    return ticks;\n  }\n\n  /// Get the start value from the scale.\n  D _getStartValue(TickHint<D>? tickHint, MutableScale<D> scale) {\n    Object? start;\n\n    if (tickHint != null) {\n      start = tickHint.start;\n    } else {\n      // Upcast to allow type promotion.\n      // See https://github.com/dart-lang/sdk/issues/34018.\n      Object _scale = scale;\n      if (_scale is NumericScale) {\n        start = _scale.viewportDomain.min;\n      } else if (_scale is DateTimeScale) {\n        start = _scale.viewportDomain.start;\n      } else if (_scale is OrdinalScale) {\n        start = _scale.domain.first;\n      } else {\n        throw UnsupportedError('Unrecognized scale: {scale.runtimeType}');\n      }\n    }\n\n    return start as D;\n  }\n\n  /// Get the end value from the scale.\n  D _getEndValue(TickHint<D>? tickHint, MutableScale<D> scale) {\n    Object? end;\n\n    if (tickHint != null) {\n      end = tickHint.end;\n    } else {\n      // Upcast to allow type promotion.\n      // See https://github.com/dart-lang/sdk/issues/34018.\n      Object _scale = scale;\n      if (_scale is NumericScale) {\n        end = _scale.viewportDomain.max;\n      } else if (_scale is DateTimeScale) {\n        end = _scale.viewportDomain.end;\n      } else if (_scale is OrdinalScale) {\n        end = _scale.domain.last;\n      } else {\n        throw UnsupportedError('Unrecognized scale: {scale.runtimeType}');\n      }\n    }\n\n    return end as D;\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/cartesian/axis/linear/bucketing_numeric_axis.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport '../axis.dart' show NumericAxis;\nimport 'bucketing_numeric_tick_provider.dart' show BucketingNumericTickProvider;\n\n/// A numeric [Axis] that positions all values beneath a certain [threshold]\n/// into a reserved space on the axis range. The label for the bucket line will\n/// be drawn in the middle of the bucket range, rather than aligned with the\n/// gridline for that value's position on the scale.\n///\n/// An example illustration of a bucketing measure axis on a point chart\n/// follows. In this case, values such as \"6%\" and \"3%\" are drawn in the bucket\n/// of the axis, since they are less than the [threshold] value of 10%.\n///\n///  100% ┠─────────────────────────\n///       ┃                  *\n///       ┃         *\n///   50% ┠──────*──────────────────\n///       ┃\n///       ┠─────────────────────────\n/// < 10% ┃   *          *\n///       ┗┯━━━━━━━━━━┯━━━━━━━━━━━┯━\n///       0         50          100\n///\n/// This axis will format numbers as percents by default.\nclass BucketingNumericAxis extends NumericAxis {\n  /// All values smaller than the threshold will be bucketed into the same\n  /// position in the reserved space on the axis.\n  num? _threshold;\n\n  /// Whether or not measure values bucketed below the [threshold] should be\n  /// visible on the chart, or collapsed.\n  ///\n  /// If this is false, then any data with measure values smaller than\n  /// [threshold] will be rendered at the baseline of the chart. The\n  bool? _showBucket;\n\n  BucketingNumericAxis() : super(tickProvider: BucketingNumericTickProvider());\n\n  set threshold(num threshold) {\n    _threshold = threshold;\n    (tickProvider as BucketingNumericTickProvider).threshold = threshold;\n  }\n\n  set showBucket(bool showBucket) {\n    _showBucket = showBucket;\n    (tickProvider as BucketingNumericTickProvider).showBucket = showBucket;\n  }\n\n  /// Gets the location of [domain] on the axis, repositioning any value less\n  /// than [threshold] to the middle of the reserved bucket.\n  @override\n  double? getLocation(num? domain) {\n    if (domain == null) {\n      return null;\n    }\n\n    final scale = this.scale!;\n    if (_threshold != null && domain < _threshold!) {\n      return (_showBucket! ? scale[_threshold! / 2] : scale[0.0])!.toDouble();\n    } else {\n      return scale[domain]!.toDouble();\n    }\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/cartesian/axis/linear/bucketing_numeric_tick_provider.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport '../../../../common/graphics_factory.dart' show GraphicsFactory;\nimport '../../../common/chart_context.dart' show ChartContext;\nimport '../axis.dart' show AxisOrientation;\nimport '../draw_strategy/tick_draw_strategy.dart' show TickDrawStrategy;\nimport '../numeric_scale.dart' show NumericScale;\nimport '../numeric_tick_provider.dart' show NumericTickProvider;\nimport '../tick.dart' show Tick;\nimport '../tick_formatter.dart' show SimpleTickFormatterBase, TickFormatter;\nimport '../tick_provider.dart' show TickHint;\n\n/// Tick provider that generates ticks for a [BucketingNumericAxis].\n///\n/// An example illustration of a bucketing measure axis on a point chart\n/// follows. In this case, values such as \"6%\" and \"3%\" are drawn in the bucket\n/// of the axis, since they are less than the [threshold] value of 10%.\n///\n///  100% ┠─────────────────────────\n///       ┃                  *\n///       ┃         *\n///   50% ┠──────*──────────────────\n///       ┃\n///       ┠─────────────────────────\n/// < 10% ┃   *          *\n///       ┗┯━━━━━━━━━━┯━━━━━━━━━━━┯━\n///       0         50          100\n///\n/// This tick provider will generate ticks using the same strategy as\n/// [NumericTickProvider], except that any ticks that are smaller than\n/// [threshold] will be hidden with an empty label. A special tick will be added\n/// at the [threshold] position, with a label offset that moves its label down\n/// to the middle of the bucket.\nclass BucketingNumericTickProvider extends NumericTickProvider {\n  /// All values smaller than the threshold will be bucketed into the same\n  /// position in the reserved space on the axis.\n  num? _threshold;\n\n  set threshold(num threshold) {\n    _threshold = threshold;\n  }\n\n  /// Whether or not measure values bucketed below the [threshold] should be\n  /// visible on the chart, or collapsed.\n  bool? _showBucket;\n\n  set showBucket(bool showBucket) {\n    _showBucket = showBucket;\n  }\n\n  @override\n  List<Tick<num>> getTicks({\n    required ChartContext? context,\n    required GraphicsFactory graphicsFactory,\n    required NumericScale scale,\n    required TickFormatter<num> formatter,\n    required Map<num, String> formatterValueCache,\n    required TickDrawStrategy<num> tickDrawStrategy,\n    required AxisOrientation? orientation,\n    bool viewportExtensionEnabled = false,\n    TickHint<num>? tickHint,\n  }) {\n    final _threshold = this._threshold;\n    final _showBucket = this._showBucket;\n\n    if (_threshold == null) {\n      throw ArgumentError(\n          'Bucketing threshold must be set before getting ticks.');\n    }\n\n    if (_showBucket == null) {\n      throw ArgumentError(\n          'The showBucket flag must be set before getting ticks.');\n    }\n\n    final localFormatter = _BucketingFormatter(\n        threshold: _threshold,\n        originalFormatter: formatter as SimpleTickFormatterBase<num>);\n\n    final ticks = super.getTicks(\n        context: context,\n        graphicsFactory: graphicsFactory,\n        scale: scale,\n        formatter: localFormatter,\n        formatterValueCache: formatterValueCache,\n        tickDrawStrategy: tickDrawStrategy,\n        orientation: orientation,\n        viewportExtensionEnabled: viewportExtensionEnabled);\n\n    // Create a tick for the threshold.\n    final thresholdTick = Tick<num>(\n        value: _threshold,\n        textElement: graphicsFactory\n            .createTextElement(localFormatter.formatValue(_threshold)),\n        locationPx: (_showBucket ? scale[_threshold] : scale[0])!.toDouble(),\n        labelOffsetPx:\n            _showBucket ? -0.5 * (scale[_threshold]! - scale[0]!) : 0.0);\n    tickDrawStrategy.decorateTicks(<Tick<num>>[thresholdTick]);\n\n    // Filter out ticks that sit below the threshold.\n    ticks.removeWhere((Tick<num> tick) =>\n        tick.value <= thresholdTick.value && tick.value != 0.0);\n\n    // Finally, add our threshold tick to the list.\n    ticks.add(thresholdTick);\n\n    // Make sure they are sorted by increasing value.\n    ticks.sort((a, b) => a.value.compareTo(b.value));\n    return ticks;\n  }\n}\n\nclass _BucketingFormatter extends SimpleTickFormatterBase<num> {\n  _BucketingFormatter(\n      {required this.threshold, required this.originalFormatter});\n\n  /// All values smaller than the threshold will be formatted into an empty\n  /// string.\n  final num threshold;\n\n  final SimpleTickFormatterBase<num> originalFormatter;\n\n  /// Formats a single tick value.\n  @override\n  String formatValue(num value) {\n    if (value < threshold) {\n      return '';\n    } else if (value == threshold) {\n      return '< ' + originalFormatter.formatValue(value);\n    } else {\n      return originalFormatter.formatValue(value);\n    }\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/cartesian/axis/linear/linear_scale.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport '../numeric_extents.dart' show NumericExtents;\nimport '../numeric_scale.dart' show NumericScale;\nimport '../scale.dart' show RangeBandConfig, ScaleOutputExtent, StepSizeConfig;\nimport 'linear_scale_domain_info.dart' show LinearScaleDomainInfo;\nimport 'linear_scale_function.dart' show LinearScaleFunction;\nimport 'linear_scale_viewport.dart' show LinearScaleViewportSettings;\n\n/// [NumericScale] that lays out the domain linearly across the range.\n///\n/// A [Scale] which converts numeric domain units to a given numeric range units\n/// linearly (as opposed to other methods like log scales).  This is used to map\n/// the domain's values to the available pixel range of the chart using the\n/// apply method.\n///\n/// <p>The domain extent of the scale are determined by adding all domain\n/// values to the scale.  It can, however, be overwritten by calling\n/// [domainOverride] to define the extent of the data.\n///\n/// <p>The scale can be zoomed & panned by calling either [setViewportSettings]\n/// with a zoom and translate, or by setting [viewportExtent] with the domain\n/// extent to show in the output range.\n///\n/// <p>[rangeBandConfig]: By default, this scale will map the domain extent\n/// exactly to the output range in a simple ratio mapping.  If a\n/// [RangeBandConfig] other than NONE is used to define the width of bar groups,\n/// then the scale calculation may be altered to that there is a half a stepSize\n/// at the start and end of the range to ensure that a bar group can be shown\n/// and centered on the scale's result.\n///\n/// <p>[stepSizeConfig]: By default, this scale will calculate the stepSize as\n/// being auto detected using the minimal distance between two consecutive\n/// datum.  If you don't assign a [RangeBandConfig], then changing the\n/// [stepSizeConfig] is a no-op.\nclass LinearScale implements NumericScale {\n  final LinearScaleDomainInfo _domainInfo;\n  final LinearScaleViewportSettings _viewportSettings;\n  final LinearScaleFunction _scaleFunction = LinearScaleFunction();\n\n  @override\n  RangeBandConfig rangeBandConfig = const RangeBandConfig.none();\n\n  @override\n  StepSizeConfig stepSizeConfig = const StepSizeConfig.auto();\n\n  bool _scaleReady = false;\n\n  LinearScale()\n      : _domainInfo = LinearScaleDomainInfo(),\n        _viewportSettings = LinearScaleViewportSettings();\n\n  LinearScale._copy(LinearScale other)\n      : _domainInfo = LinearScaleDomainInfo.copy(other._domainInfo),\n        _viewportSettings =\n            LinearScaleViewportSettings.copy(other._viewportSettings),\n        rangeBandConfig = other.rangeBandConfig,\n        stepSizeConfig = other.stepSizeConfig;\n\n  @override\n  LinearScale copy() => LinearScale._copy(this);\n\n  //\n  // Domain methods\n  //\n\n  @override\n  void addDomain(num domainValue) {\n    _domainInfo.addDomainValue(domainValue);\n  }\n\n  @override\n  void resetDomain() {\n    _scaleReady = false;\n    _domainInfo.reset();\n  }\n\n  @override\n  void resetViewportSettings() {\n    _viewportSettings.reset();\n  }\n\n  @override\n  NumericExtents get dataExtent =>\n      NumericExtents(_domainInfo.dataDomainStart, _domainInfo.dataDomainEnd);\n\n  @override\n  num get minimumDomainStep => _domainInfo.minimumDetectedDomainStep;\n\n  @override\n  bool canTranslate(_) => true;\n\n  @override\n  set domainOverride(NumericExtents? domainMaxExtent) {\n    _domainInfo.domainOverride = domainMaxExtent;\n  }\n\n  @override\n  NumericExtents? get domainOverride => _domainInfo.domainOverride;\n\n  @override\n  int compareDomainValueToViewport(num domainValue) {\n    final dataExtent = _viewportSettings.domainExtent ?? _domainInfo.extent;\n    return dataExtent.compareValue(domainValue);\n  }\n\n  //\n  // Viewport methods\n  //\n\n  @override\n  void setViewportSettings(double viewportScale, double viewportTranslatePx) {\n    _viewportSettings\n      ..scalingFactor = viewportScale\n      ..translatePx = viewportTranslatePx\n      ..domainExtent = null;\n    _scaleReady = false;\n  }\n\n  @override\n  double get viewportScalingFactor => _viewportSettings.scalingFactor;\n\n  @override\n  double get viewportTranslatePx => _viewportSettings.translatePx;\n\n  @override\n  set viewportDomain(NumericExtents extent) {\n    _scaleReady = false;\n    _viewportSettings.domainExtent = extent;\n  }\n\n  @override\n  NumericExtents get viewportDomain {\n    _configureScale();\n    return _viewportSettings.domainExtent!;\n  }\n\n  @override\n  set keepViewportWithinData(bool autoAdjustViewportToNiceValues) {\n    _scaleReady = false;\n    _viewportSettings.keepViewportWithinData = true;\n  }\n\n  @override\n  bool get keepViewportWithinData => _viewportSettings.keepViewportWithinData;\n\n  @override\n  double computeViewportScaleFactor(double domainWindow) =>\n      _domainInfo.domainDiff / domainWindow;\n\n  @override\n  set range(ScaleOutputExtent? extent) {\n    _viewportSettings.range = extent;\n    _scaleReady = false;\n  }\n\n  @override\n  ScaleOutputExtent? get range => _viewportSettings.range;\n\n  //\n  // Scale application methods\n  //\n\n  @override\n  num operator [](num domainValue) {\n    _configureScale();\n    return _scaleFunction[domainValue];\n  }\n\n  @override\n  num reverse(double viewPixels) {\n    _configureScale();\n    final num domain = _scaleFunction.reverse(viewPixels);\n    return domain;\n  }\n\n  @override\n  double get rangeBand {\n    _configureScale();\n    return _scaleFunction.rangeBandPixels;\n  }\n\n  @override\n  double get stepSize {\n    _configureScale();\n    return _scaleFunction.stepSizePixels;\n  }\n\n  @override\n  double get domainStepSize => _domainInfo.minimumDetectedDomainStep.toDouble();\n\n  @override\n  int get rangeWidth => (range!.end - range!.start).abs().toInt();\n\n  @override\n  bool isRangeValueWithinViewport(double rangeValue) =>\n      range!.containsValue(rangeValue);\n\n  //\n  // Private update\n  //\n\n  void _configureScale() {\n    if (_scaleReady) return;\n\n    assert(_viewportSettings.range != null);\n\n    // If the viewport's domainExtent are set, then we can calculate the\n    // viewport's scaleFactor now that the domainInfo has been loaded.\n    // The viewport also has a chance to correct the scaleFactor.\n    _viewportSettings.updateViewportScaleFactor(_domainInfo);\n    // Now that the viewport's scalingFactor is setup, set it on the scale\n    // function.\n    _scaleFunction.updateScaleFactor(\n        _viewportSettings, _domainInfo, rangeBandConfig, stepSizeConfig);\n\n    // If the viewport's domainExtent are set, then we can calculate the\n    // viewport's translate now that the scaleFactor has been loaded.\n    // The viewport also has a chance to correct the translate.\n    _viewportSettings.updateViewportTranslatePx(\n        _domainInfo, _scaleFunction.scalingFactor);\n    // Now that the viewport has a chance to update the translate, set it on the\n    // scale function.\n    _scaleFunction.updateTranslateAndRangeBand(\n        _viewportSettings, _domainInfo, rangeBandConfig);\n\n    // Now that the viewport's scaleFactor and translate have been updated\n    // set the effective domainExtent of the viewport.\n    _viewportSettings.updateViewportDomainExtent(\n        _domainInfo, _scaleFunction.scalingFactor);\n\n    // Cached computed values are updated.\n    _scaleReady = true;\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/cartesian/axis/linear/linear_scale_domain_info.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport '../numeric_extents.dart' show NumericExtents;\n\n/// Encapsulation of all the domain processing logic for the [LinearScale].\nclass LinearScaleDomainInfo {\n  /// User (or axis) overridden extent in domain units.\n  NumericExtents? domainOverride;\n\n  /// The minimum added domain value.\n  num _dataDomainStart = double.infinity;\n  num get dataDomainStart => _dataDomainStart;\n\n  /// The maximum added domain value.\n  num _dataDomainEnd = double.negativeInfinity;\n  num get dataDomainEnd => _dataDomainEnd;\n\n  /// Previous domain added so we can calculate minimumDetectedDomainStep.\n  num? _previouslyAddedDomain;\n\n  /// The step size between data points in domain units.\n  ///\n  /// Measured as the minimum distance between consecutive added points.\n  num _minimumDetectedDomainStep = double.infinity;\n  num get minimumDetectedDomainStep => _minimumDetectedDomainStep;\n\n  ///The diff of the nicedDomain extent.\n  num get domainDiff => extent.width;\n\n  LinearScaleDomainInfo();\n\n  LinearScaleDomainInfo.copy(LinearScaleDomainInfo other) {\n    if (other.domainOverride != null) {\n      domainOverride = other.domainOverride;\n    }\n    _dataDomainStart = other._dataDomainStart;\n    _dataDomainEnd = other._dataDomainEnd;\n    _previouslyAddedDomain = other._previouslyAddedDomain;\n    _minimumDetectedDomainStep = other._minimumDetectedDomainStep;\n  }\n\n  /// Resets everything back to initial state.\n  void reset() {\n    _previouslyAddedDomain = null;\n    _dataDomainStart = double.infinity;\n    _dataDomainEnd = double.negativeInfinity;\n    _minimumDetectedDomainStep = double.infinity;\n  }\n\n  /// Updates the domain extent and detected step size given the [domainValue].\n  void addDomainValue(num? domainValue) {\n    if (domainValue == null || !domainValue.isFinite) {\n      return;\n    }\n\n    extendDomain(domainValue);\n\n    if (_previouslyAddedDomain != null) {\n      final domainStep = (domainValue - _previouslyAddedDomain!).abs();\n      if (domainStep != 0.0 && domainStep < minimumDetectedDomainStep) {\n        _minimumDetectedDomainStep = domainStep;\n      }\n    }\n    _previouslyAddedDomain = domainValue;\n  }\n\n  /// Extends the data domain extent without modifying step size detection.\n  ///\n  /// Returns whether the the domain interval was extended. If the domain value\n  /// was already contained in the domain interval, the domain interval does not\n  /// change.\n  bool extendDomain(num? domainValue) {\n    if (domainValue == null || !domainValue.isFinite) {\n      return false;\n    }\n\n    var domainExtended = false;\n    if (domainValue < _dataDomainStart) {\n      _dataDomainStart = domainValue;\n      domainExtended = true;\n    }\n    if (domainValue > _dataDomainEnd) {\n      _dataDomainEnd = domainValue;\n      domainExtended = true;\n    }\n    return domainExtended;\n  }\n\n  /// Returns the extent based on the current domain range and overrides.\n  NumericExtents get extent {\n    num tmpDomainStart;\n    num tmpDomainEnd;\n    if (domainOverride != null) {\n      // override was set.\n      tmpDomainStart = domainOverride!.min;\n      tmpDomainEnd = domainOverride!.max;\n    } else {\n      // domainEnd is less than domainStart if no domain values have been set.\n      tmpDomainStart = _dataDomainStart.isFinite ? _dataDomainStart : 0.0;\n      tmpDomainEnd = _dataDomainEnd.isFinite ? _dataDomainEnd : 1.0;\n    }\n\n    return NumericExtents(tmpDomainStart, tmpDomainEnd);\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/cartesian/axis/linear/linear_scale_function.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport '../scale.dart'\n    show RangeBandConfig, RangeBandType, StepSizeConfig, StepSizeType;\nimport 'linear_scale_domain_info.dart' show LinearScaleDomainInfo;\nimport 'linear_scale_viewport.dart' show LinearScaleViewportSettings;\n\n/// Component of the LinearScale which actually handles the apply and reverse\n/// function of the scale.\nclass LinearScaleFunction {\n  /// Cached rangeBand width in pixels given the RangeBandConfig and the current\n  /// domain & range.\n  double rangeBandPixels = 0.0;\n\n  /// Cached amount in domain units to shift the input value as a part of\n  /// translation.\n  num domainTranslate = 0.0;\n\n  /// Cached translation ratio for scale translation.\n  double scalingFactor = 1.0;\n\n  /// Cached amount in pixel units to shift the output value as a part of\n  /// translation.\n  double rangeTranslate = 0.0;\n\n  /// The calculated step size given the step size config.\n  double stepSizePixels = 0.0;\n\n  /// Translates the given domainValue to the range output.\n  double operator [](num domainValue) {\n    return (((domainValue + domainTranslate) * scalingFactor) + rangeTranslate)\n        .toDouble();\n  }\n\n  /// Translates the given range output back to a domainValue.\n  double reverse(double viewPixels) {\n    return ((viewPixels - rangeTranslate) / scalingFactor) - domainTranslate;\n  }\n\n  /// Update the scale function's scaleFactor given the current state of the\n  /// viewport.\n  void updateScaleFactor(\n      LinearScaleViewportSettings viewportSettings,\n      LinearScaleDomainInfo domainInfo,\n      RangeBandConfig rangeBandConfig,\n      StepSizeConfig stepSizeConfig) {\n    final rangeDiff = viewportSettings.range!.diff.toDouble();\n    // Note: if you provided a nicing function that extends the domain, we won't\n    // muck with the extended side.\n    final hasHalfStepAtStart =\n        domainInfo.extent.min == domainInfo.dataDomainStart;\n    final hasHalfStepAtEnd = domainInfo.extent.max == domainInfo.dataDomainEnd;\n\n    // Determine the stepSize and reserved range values.\n    // The percentage of the step reserved from the scale's range due to the\n    // possible half step at the start and end.\n    final reservedRangePercentOfStep =\n        getStepReservationPercent(hasHalfStepAtStart, hasHalfStepAtEnd);\n    _updateStepSizeAndScaleFactor(viewportSettings, domainInfo, rangeDiff,\n        reservedRangePercentOfStep, rangeBandConfig, stepSizeConfig);\n  }\n\n  /// Returns the percentage of the step reserved from the output range due to\n  /// maybe having to hold half stepSizes on the start and end of the output.\n  double getStepReservationPercent(\n      bool hasHalfStepAtStart, bool hasHalfStepAtEnd) {\n    if (!hasHalfStepAtStart && !hasHalfStepAtEnd) {\n      return 0.0;\n    }\n    if (hasHalfStepAtStart && hasHalfStepAtEnd) {\n      return 1.0;\n    }\n    return 0.5;\n  }\n\n  /// Updates the scale function's translate and rangeBand given the current\n  /// state of the viewport.\n  void updateTranslateAndRangeBand(LinearScaleViewportSettings viewportSettings,\n      LinearScaleDomainInfo domainInfo, RangeBandConfig rangeBandConfig) {\n    // Assign the rangeTranslate using the current viewportSettings.translatePx\n    // and diffs.\n    if (domainInfo.domainDiff == 0) {\n      // Translate it to the center of the range.\n      rangeTranslate =\n          viewportSettings.range!.start + (viewportSettings.range!.diff / 2);\n    } else {\n      final hasHalfStepAtStart =\n          domainInfo.extent.min == domainInfo.dataDomainStart;\n      // The pixel shift of the scale function due to the half a step at the\n      // beginning.\n      final reservedRangePixelShift =\n          hasHalfStepAtStart ? (stepSizePixels / 2.0) : 0.0;\n\n      rangeTranslate = viewportSettings.range!.start +\n          viewportSettings.translatePx +\n          reservedRangePixelShift;\n    }\n\n    // We need to subtract the start from any incoming domain to apply the\n    // scale, so flip its sign.\n    domainTranslate = -1 * domainInfo.extent.min;\n\n    // Update the rangeBand size.\n    rangeBandPixels = _calculateRangeBandSize(rangeBandConfig);\n  }\n\n  /// Calculates and stores the current rangeBand given the config and current\n  /// step size.\n  double _calculateRangeBandSize(RangeBandConfig rangeBandConfig) {\n    switch (rangeBandConfig.type) {\n      case RangeBandType.fixedDomain:\n        return rangeBandConfig.size * scalingFactor;\n      case RangeBandType.fixedPixel:\n        return rangeBandConfig.size;\n      case RangeBandType.fixedPixelSpaceFromStep:\n        return stepSizePixels - rangeBandConfig.size;\n      case RangeBandType.styleAssignedPercentOfStep:\n      case RangeBandType.fixedPercentOfStep:\n        return stepSizePixels * rangeBandConfig.size;\n      case RangeBandType.none:\n        return 0.0;\n    }\n  }\n\n  /// Calculates and Stores the current step size and scale factor together,\n  /// given the viewport, domain, and config.\n  ///\n  /// <p>Scale factor and step size are related closely and should be calculated\n  /// together so that we do not lose accuracy due to double arithmetic.\n  void _updateStepSizeAndScaleFactor(\n      LinearScaleViewportSettings viewportSettings,\n      LinearScaleDomainInfo domainInfo,\n      double rangeDiff,\n      double reservedRangePercentOfStep,\n      RangeBandConfig rangeBandConfig,\n      StepSizeConfig stepSizeConfig) {\n    final domainDiff = domainInfo.domainDiff.toDouble();\n\n    // If we are going to have any rangeBands, then ensure that we account for\n    // needed space on the beginning and end of the range.\n    if (rangeBandConfig.type != RangeBandType.none) {\n      switch (stepSizeConfig.type) {\n        case StepSizeType.autoDetect:\n          final minimumDetectedDomainStep =\n              domainInfo.minimumDetectedDomainStep.toDouble();\n          if (minimumDetectedDomainStep != null &&\n              minimumDetectedDomainStep.isFinite) {\n            scalingFactor = viewportSettings.scalingFactor *\n                (rangeDiff /\n                    (domainDiff +\n                        (minimumDetectedDomainStep *\n                            reservedRangePercentOfStep)));\n            stepSizePixels = minimumDetectedDomainStep * scalingFactor;\n          } else {\n            stepSizePixels = rangeDiff.abs();\n            scalingFactor = 1.0;\n          }\n          return;\n        case StepSizeType.fixedPixels:\n          stepSizePixels = stepSizeConfig.size;\n          final reservedRangeForStepPixels =\n              stepSizePixels * reservedRangePercentOfStep;\n          scalingFactor = domainDiff == 0\n              ? 1.0\n              : viewportSettings.scalingFactor *\n                  (rangeDiff - reservedRangeForStepPixels) /\n                  domainDiff;\n          return;\n        case StepSizeType.fixedDomain:\n          final domainStepWidth = stepSizeConfig.size;\n          final totalDomainDiff =\n              domainDiff + (domainStepWidth * reservedRangePercentOfStep);\n          scalingFactor = totalDomainDiff == 0\n              ? 1.0\n              : viewportSettings.scalingFactor * (rangeDiff / totalDomainDiff);\n          stepSizePixels = domainStepWidth * scalingFactor;\n          return;\n      }\n    }\n\n    // If no cases matched, use zero step size.\n    stepSizePixels = 0.0;\n    scalingFactor = domainDiff == 0\n        ? 1.0\n        : viewportSettings.scalingFactor * rangeDiff / domainDiff;\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/cartesian/axis/linear/linear_scale_viewport.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math' as math show max, min;\n\nimport '../numeric_extents.dart' show NumericExtents;\nimport '../scale.dart' show ScaleOutputExtent;\nimport 'linear_scale_domain_info.dart' show LinearScaleDomainInfo;\n\n/// Component of the LinearScale responsible for the configuration and\n/// calculations of the viewport.\nclass LinearScaleViewportSettings {\n  /// Output extent for the scale, typically set by the axis as the pixel\n  /// output.\n  ScaleOutputExtent? range;\n\n  /// Determines whether the scale should be extended to the nice values\n  /// provided by the tick provider.  If true, we wont touch the viewport config\n  /// since the axis will configure it, if false, we will still ensure sane zoom\n  /// and translates.\n  bool keepViewportWithinData = true;\n\n  /// User configured viewport scale as a zoom multiplier where 1.0 is\n  /// 100% (default) and 2.0 is 200% zooming in making the data take up twice\n  /// the space (showing half as much data in the viewport).\n  double scalingFactor = 1.0;\n\n  /// User configured viewport translate in pixel units.\n  double translatePx = 0.0;\n\n  /// The current extent of the viewport in domain units.\n  NumericExtents? _domainExtent;\n  set domainExtent(NumericExtents? extent) {\n    _domainExtent = extent;\n    _manualDomainExtent = extent != null;\n  }\n\n  NumericExtents? get domainExtent => _domainExtent;\n\n  /// Indicates that the viewportExtends are to be read from to determine the\n  /// internal scaleFactor and rangeTranslate.\n\n  bool _manualDomainExtent = false;\n\n  LinearScaleViewportSettings();\n\n  LinearScaleViewportSettings.copy(LinearScaleViewportSettings other) {\n    range = other.range;\n    keepViewportWithinData = other.keepViewportWithinData;\n    scalingFactor = other.scalingFactor;\n    translatePx = other.translatePx;\n    _manualDomainExtent = other._manualDomainExtent;\n    _domainExtent = other._domainExtent;\n  }\n\n  /// Resets the viewport calculated fields back to their initial settings.\n  void reset() {\n    // Likely an auto assigned viewport (niced), so reset it between draws.\n    scalingFactor = 1.0;\n    translatePx = 0.0;\n    domainExtent = null;\n  }\n\n  int get rangeWidth => range!.diff.abs().toInt();\n\n  bool isRangeValueWithinViewport(double rangeValue) =>\n      range!.containsValue(rangeValue);\n\n  /// Updates the viewport's internal scalingFactor given the current\n  /// domainInfo.\n  void updateViewportScaleFactor(LinearScaleDomainInfo domainInfo) {\n    // If we are loading from the viewport, then update the scalingFactor given\n    // the viewport size compared to the data size.\n    if (_manualDomainExtent) {\n      final viewportDomainDiff = _domainExtent?.width.toDouble();\n      if (domainInfo.domainDiff != 0.0) {\n        scalingFactor = domainInfo.domainDiff / viewportDomainDiff!;\n      } else {\n        scalingFactor = 1.0;\n        // The domain claims to have no date, extend it to the viewport's\n        domainInfo.extendDomain(_domainExtent?.min);\n        domainInfo.extendDomain(_domainExtent?.max);\n      }\n    }\n\n    // Make sure that the viewportSettings.scalingFactor is sane if desired.\n    if (!keepViewportWithinData) {\n      // Make sure we don't zoom out beyond the max domain extent.\n      scalingFactor = math.max(1.0, scalingFactor);\n    }\n  }\n\n  /// Updates the viewport's internal translate given the current domainInfo and\n  /// main scalingFactor from LinearScaleFunction (not internal scalingFactor).\n  void updateViewportTranslatePx(\n      LinearScaleDomainInfo domainInfo, double scaleScalingFactor) {\n    // If we are loading from the viewport, then update the translate now that\n    // the scaleFactor has been setup.\n    if (_manualDomainExtent) {\n      translatePx =\n          -scaleScalingFactor * (_domainExtent!.min - domainInfo.extent.min);\n    }\n\n    // Make sure that the viewportSettings.translatePx is sane if desired.\n    if (!keepViewportWithinData) {\n      // Make sure we don't translate beyond the max domain extent.\n      translatePx = math.min(0.0, translatePx);\n      translatePx = math.max(range!.diff * (1.0 - scalingFactor), translatePx);\n    }\n  }\n\n  /// Calculates and stores the viewport's domainExtent if we did not load from\n  /// them in the first place.\n  void updateViewportDomainExtent(\n      LinearScaleDomainInfo domainInfo, double scaleScalingFactor) {\n    // If we didn't load from the viewport extent, then update them given the\n    // current scale configuration.\n    if (!_manualDomainExtent) {\n      final viewportDomainDiff = domainInfo.domainDiff / scalingFactor;\n      final viewportStart =\n          (-translatePx / scaleScalingFactor) + domainInfo.extent.min;\n      _domainExtent =\n          NumericExtents(viewportStart, viewportStart + viewportDomainDiff);\n    }\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/cartesian/axis/numeric_extents.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'scale.dart' show Extents;\n\n/// Represents the starting and ending extent of a dataset.\nclass NumericExtents implements Extents<num> {\n  final num min;\n  final num max;\n\n  /// Precondition: [min] <= [max].\n  // TODO: When initializer list asserts are supported everywhere,\n  // add the precondition as an initializer list assert. This is supported in\n  // Flutter only.\n  const NumericExtents(this.min, this.max);\n\n  /// Returns [Extents] based on the min and max of the given values.\n  /// Returns [NumericExtents.empty] if [values] are empty\n  factory NumericExtents.fromValues(Iterable<num> values) {\n    if (values.isEmpty) {\n      return NumericExtents.empty;\n    }\n    var min = values.first;\n    var max = values.first;\n    for (final value in values) {\n      if (value < min) {\n        min = value;\n      } else if (max < value) {\n        max = value;\n      }\n    }\n    return NumericExtents(min, max);\n  }\n\n  /// Returns the union of this and other.\n  NumericExtents plus(NumericExtents other) {\n    if (min <= other.min) {\n      if (max >= other.max) {\n        return this;\n      } else {\n        return NumericExtents(min, other.max);\n      }\n    } else {\n      if (other.max >= max) {\n        return other;\n      } else {\n        return NumericExtents(other.min, max);\n      }\n    }\n  }\n\n  /// Compares the given [value] against the extents.\n  ///\n  /// Returns -1 if the value is less than the extents.\n  /// Returns 0 if the value is within the extents inclusive.\n  /// Returns 1 if the value is greater than the extents.\n  int compareValue(num value) {\n    if (value < min) {\n      return -1;\n    }\n    if (value > max) {\n      return 1;\n    }\n    return 0;\n  }\n\n  bool _containsValue(double value) => compareValue(value) == 0;\n\n  // Returns true if these [NumericExtents] collides with [other].\n  bool overlaps(NumericExtents other) {\n    return _containsValue(other.min.toDouble()) ||\n        _containsValue(other.max.toDouble()) ||\n        other._containsValue(min.toDouble()) ||\n        other._containsValue(max.toDouble());\n  }\n\n  @override\n  bool operator ==(Object other) {\n    return other is NumericExtents && min == other.min && max == other.max;\n  }\n\n  @override\n  int get hashCode => min.hashCode + (max.hashCode * 31);\n\n  num get width => max - min;\n\n  @override\n  String toString() => 'Extent($min, $max)';\n\n  static const NumericExtents unbounded =\n      NumericExtents(double.negativeInfinity, double.infinity);\n  static const NumericExtents empty = NumericExtents(0.0, 0.0);\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/cartesian/axis/numeric_scale.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'numeric_extents.dart' show NumericExtents;\nimport 'scale.dart' show MutableScale;\n\n/// Scale used to convert numeric domain input units to output range units.\n///\n/// The input represents a continuous numeric domain which maps to a given range\n/// output.  This is used to map the domain's values to the available pixel\n/// range of the chart.\nabstract class NumericScale extends MutableScale<num> {\n  /// Keeps the scale and translate sane if true (default).\n  ///\n  /// Setting this to false disables some pan/zoom protections that prevent you\n  /// from going beyond the data extent.\n  bool get keepViewportWithinData;\n  set keepViewportWithinData(bool keep);\n\n  /// Returns the extent of the actual data (not the viewport max).\n  NumericExtents get dataExtent;\n\n  /// Returns the minimum step size of the actual data.\n  num get minimumDomainStep;\n\n  /// Overrides the domain extent if set, null otherwise.\n  ///\n  /// Overrides the extent of the actual data to lie about the range of the\n  /// data so that panning has a start and end point to go between beyond the\n  /// received data.  This allows lazy loading of data into the gaps in the\n  /// expanded lied about areas.\n  NumericExtents? get domainOverride;\n  set domainOverride(NumericExtents? extent);\n\n  /// Returns the domain extent visible in the viewport of the drawArea.\n  NumericExtents get viewportDomain;\n\n  /// Sets the domain extent visible in the viewport of the drawArea.\n  ///\n  /// Invalidates the viewportScale & viewportTranslatePx.\n  set viewportDomain(NumericExtents extent);\n\n  /// Returns the viewportScaleFactor needed to present the given domainWindow.\n  double computeViewportScaleFactor(double domainWindow);\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/cartesian/axis/numeric_tick_provider.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math' show log, log10e, max, min, pow;\n\nimport '../../../common/graphics_factory.dart' show GraphicsFactory;\nimport '../../common/chart_context.dart' show ChartContext;\nimport '../../common/unitconverter/identity_converter.dart'\n    show IdentityConverter;\nimport '../../common/unitconverter/unit_converter.dart' show UnitConverter;\nimport 'axis.dart' show AxisOrientation;\nimport 'draw_strategy/tick_draw_strategy.dart' show TickDrawStrategy;\nimport 'numeric_extents.dart' show NumericExtents;\nimport 'numeric_scale.dart' show NumericScale;\nimport 'tick.dart' show Tick;\nimport 'tick_formatter.dart' show TickFormatter;\nimport 'tick_provider.dart' show BaseTickProvider, TickHint;\n\n/// Tick provider that allows you to specify how many ticks to present while\n/// also choosing tick values that appear \"nice\" or \"rounded\" to the user.  By\n/// default it will try to guess an appropriate number of ticks given the size\n/// of the range available, but the min and max tick counts can be set by\n/// calling setTickCounts().\n///\n/// You can control whether the axis is bound to zero (default) or follows the\n/// data by calling setZeroBound().\n///\n/// This provider will choose \"nice\" ticks with the following priority order.\n/// * Ticks do not collide with each other.\n/// * Alternate rendering is not used to avoid collisions.\n/// * Provide the least amount of domain range covering all data points (while\n/// still selecting \"nice\" ticks values.\nclass NumericTickProvider extends BaseTickProvider<num> {\n  /// Used to determine the automatic tick count calculation.\n  static const MIN_DIPS_BETWEEN_TICKS = 25;\n\n  /// Potential steps available to the baseTen value of the data.\n  static const DEFAULT_STEPS = [\n    0.01,\n    0.02,\n    0.025,\n    0.03,\n    0.04,\n    0.05,\n    0.06,\n    0.07,\n    0.08,\n    0.09,\n    0.1,\n    0.2,\n    0.25,\n    0.3,\n    0.4,\n    0.5,\n    0.6,\n    0.7,\n    0.8,\n    0.9,\n    1.0,\n    2.0,\n    2.50,\n    3.0,\n    4.0,\n    5.0,\n    6.0,\n    7.0,\n    8.0,\n    9.0\n  ];\n\n  // Settings\n\n  /// Sets whether the the tick provider should always include a zero tick.\n  ///\n  /// If set the data range may be extended to include zero.\n  ///\n  /// Note that the zero value in axis units is chosen, which may be different\n  /// than zero value in data units if a data to axis unit converter is set.\n  bool zeroBound = true;\n\n  /// If your data can only be in whole numbers, then set this to true.\n  ///\n  /// It should prevent the scale from choosing fractional ticks.  For example,\n  /// if you had a office head count, don't generate a tick for 1.5, instead\n  /// jump to 2.\n  ///\n  /// Note that the provider will choose whole number ticks in the axis units,\n  /// not data units if a data to axis unit converter is set.\n  bool dataIsInWholeNumbers = true;\n\n  // Desired min and max tick counts are set by [setFixedTickCount] and\n  // [setTickCount]. These are not guaranteed tick counts.\n  int? _desiredMaxTickCount;\n  int? _desiredMinTickCount;\n\n  /// Allowed steps the tick provider can choose from.\n  var _allowedSteps = DEFAULT_STEPS;\n\n  /// Convert input data units to the desired units on the axis.\n  /// If not set no conversion will take place.\n  ///\n  /// Combining this with an appropriate [TickFormatter] would result in axis\n  /// ticks that are in different unit than the actual data units.\n  UnitConverter<num, num> dataToAxisUnitConverter =\n      const IdentityConverter<num>();\n\n  // Internal tick calculation state for [getTicks].\n  //\n  // [_low] and [_high] are valid only after calling [_updateDomainExtents].\n  //\n  // [_minTickCount] and [_maxTickCount] are valid only after calling\n  // [_updateTickCounts].\n  late num _low;\n  late num _high;\n  int? _minTickCount;\n  int? _maxTickCount;\n\n  /// Sets the desired tick count.\n  ///\n  /// While the provider will try to satisfy the requirement, it is not\n  /// guaranteed, such as cases where ticks may overlap or are insufficient.\n  ///\n  /// [tickCount] the fixed number of major (labeled) ticks to draw for the axis\n  /// Passing null will result in falling back on the automatic tick count\n  /// assignment.\n  void setFixedTickCount(int? tickCount) {\n    // Don't allow a single tick, it doesn't make sense. so tickCount > 1\n    _desiredMinTickCount =\n        tickCount != null && tickCount > 1 ? tickCount : null;\n    _desiredMaxTickCount = _desiredMinTickCount;\n  }\n\n  /// Sets the desired min and max tick count when providing ticks.\n  ///\n  /// The values are suggested requirements but are not guaranteed to be the\n  /// actual tick count in cases where it is not possible.\n  ///\n  /// [maxTickCount] The max tick count must be greater than 1.\n  /// [minTickCount] The min tick count must be greater than 1.\n  void setTickCount(int maxTickCount, int minTickCount) {\n    // Don't allow a single tick, it doesn't make sense. so tickCount > 1\n    if (maxTickCount != null && maxTickCount > 1) {\n      _desiredMaxTickCount = maxTickCount;\n      if (minTickCount != null &&\n          minTickCount > 1 &&\n          minTickCount <= _desiredMaxTickCount!) {\n        _desiredMinTickCount = minTickCount;\n      } else {\n        _desiredMinTickCount = 2;\n      }\n    } else {\n      _desiredMaxTickCount = null;\n      _desiredMinTickCount = null;\n    }\n\n    assert((_desiredMinTickCount == null) == (_desiredMaxTickCount == null));\n  }\n\n  /// Sets the allowed step sizes this tick provider can choose from.\n  ///\n  /// All ticks will be a power of 10 multiple of the given step sizes.\n  ///\n  /// Note that if only very few step sizes are allowed the tick range maybe\n  /// much bigger than the data range.\n  ///\n  /// The step sizes setup here apply in axis units, which is different than\n  /// input units if a data to axis unit converter is set.\n  ///\n  /// [steps] allowed step sizes in the [1, 10) range.\n  set allowedSteps(List<double> steps) {\n    assert(steps != null && steps.isNotEmpty);\n    steps.sort();\n\n    final stepSet = Set.of(steps);\n    _allowedSteps = List<double>.filled(stepSet.length * 3, 0);\n    var stepIndex = 0;\n    for (final step in stepSet) {\n      assert(1.0 <= step && step < 10.0);\n      _allowedSteps[stepIndex] = _removeRoundingErrors(step / 100);\n      _allowedSteps[stepSet.length + stepIndex] =\n          _removeRoundingErrors(step / 10);\n      _allowedSteps[2 * stepSet.length + stepIndex] =\n          _removeRoundingErrors(step);\n      stepIndex++;\n    }\n  }\n\n  List<Tick<num>> _getTicksFromHint({\n    required ChartContext? context,\n    required GraphicsFactory graphicsFactory,\n    required NumericScale scale,\n    required TickFormatter<num> formatter,\n    required Map<num, String> formatterValueCache,\n    required TickDrawStrategy<num> tickDrawStrategy,\n    required TickHint<num> tickHint,\n  }) {\n    final stepSize = (tickHint.end - tickHint.start) / (tickHint.tickCount - 1);\n    // Find the first tick that is greater than or equal to the min\n    // viewportDomain.\n    final tickZeroShift = tickHint.start.toDouble() -\n        (stepSize *\n            (tickHint.start >= 0\n                ? (tickHint.start / stepSize).floor()\n                : (tickHint.start / stepSize).ceil()));\n    final tickStart =\n        (scale.viewportDomain.min / stepSize).ceil() * stepSize + tickZeroShift;\n    final stepInfo = _TickStepInfo(stepSize.abs(), tickStart);\n    final tickValues = _getTickValues(stepInfo, tickHint.tickCount);\n\n    // Create ticks from domain values.\n    return createTicks(tickValues,\n        context: context,\n        graphicsFactory: graphicsFactory,\n        scale: scale,\n        formatter: formatter,\n        formatterValueCache: formatterValueCache,\n        tickDrawStrategy: tickDrawStrategy,\n        stepSize: stepInfo.stepSize);\n  }\n\n  @override\n  List<Tick<num>> getTicks({\n    required ChartContext? context,\n    required GraphicsFactory graphicsFactory,\n    required NumericScale scale,\n    required TickFormatter<num> formatter,\n    required Map<num, String> formatterValueCache,\n    required TickDrawStrategy<num> tickDrawStrategy,\n    required AxisOrientation? orientation,\n    bool viewportExtensionEnabled = false,\n    TickHint<num>? tickHint,\n  }) {\n    _updateDomainExtents(scale.viewportDomain);\n\n    // Bypass searching for a tick range since we are getting ticks using\n    // information in [tickHint].\n    if (tickHint != null) {\n      return _getTicksFromHint(\n        context: context,\n        graphicsFactory: graphicsFactory,\n        scale: scale,\n        formatter: formatter,\n        formatterValueCache: formatterValueCache,\n        tickDrawStrategy: tickDrawStrategy,\n        tickHint: tickHint,\n      );\n    }\n\n    // TODO: Recalculate ticks only if something changed.\n    var selectedTicksRange = double.maxFinite;\n    var foundPreferredTicks = false;\n    var viewportDomain = scale.viewportDomain;\n    final axisUnitsHigh = dataToAxisUnitConverter.convert(_high);\n    final axisUnitsLow = dataToAxisUnitConverter.convert(_low);\n\n    _updateTickCounts(\n        high: axisUnitsHigh, low: axisUnitsLow, rangeWidth: scale.rangeWidth);\n\n    // Only create a copy of the scale if [viewportExtensionEnabled].\n    final mutableScale =\n        viewportExtensionEnabled ? scale.copy() as NumericScale : null;\n\n    // Walk to available tick count from max to min looking for the first one\n    // that gives you the least amount of range used. If a non colliding tick\n    // count is not found use the min tick count to generate ticks.\n    var ticks = <Tick<num>>[];\n    for (var tickCount = _maxTickCount!;\n        tickCount >= _minTickCount!;\n        tickCount--) {\n      final stepInfo =\n          _getStepsForTickCount(tickCount, axisUnitsHigh, axisUnitsLow);\n      final firstTick =\n          dataToAxisUnitConverter.invert(stepInfo.tickStart).toDouble();\n      final lastTick = dataToAxisUnitConverter\n          .invert(stepInfo.tickStart + stepInfo.stepSize * (tickCount - 1))\n          .toDouble();\n      final range = lastTick - firstTick;\n      // Calculate ticks if it is a better range or if preferred ticks have\n      // not been found yet.\n      if (range < selectedTicksRange || !foundPreferredTicks) {\n        final tickValues = _getTickValues(stepInfo, tickCount);\n\n        if (mutableScale != null) {\n          mutableScale.viewportDomain = NumericExtents(firstTick, lastTick);\n        }\n\n        // Create ticks from domain values.\n        final preferredTicks = createTicks(tickValues,\n            context: context,\n            graphicsFactory: graphicsFactory,\n            scale: mutableScale ?? scale,\n            formatter: formatter,\n            formatterValueCache: formatterValueCache,\n            tickDrawStrategy: tickDrawStrategy,\n            stepSize: stepInfo.stepSize);\n\n        // Request collision check from draw strategy.\n        final collisionReport =\n            tickDrawStrategy.collides(preferredTicks, orientation);\n\n        // Don't choose colliding ticks unless it was our last resort\n        if (collisionReport.ticksCollide && tickCount > _minTickCount!) {\n          continue;\n        }\n        // Only choose alternate ticks if preferred ticks is not found.\n        if (foundPreferredTicks && collisionReport.alternateTicksUsed) {\n          continue;\n        }\n\n        ticks = collisionReport.alternateTicksUsed\n            ? collisionReport.ticks\n            : preferredTicks;\n        foundPreferredTicks = !collisionReport.alternateTicksUsed;\n        selectedTicksRange = range;\n        // If viewport extended, save the viewport used.\n        viewportDomain = mutableScale?.viewportDomain ?? scale.viewportDomain;\n      }\n    }\n    // If [viewportExtensionEnabled] and has changed, then set the scale's\n    // viewport to what was used to generate ticks. By only setting viewport\n    // when it has changed, we do not trigger the flag to recalculate scale.\n    if (viewportExtensionEnabled && scale.viewportDomain != viewportDomain) {\n      scale.viewportDomain = viewportDomain;\n    }\n\n    return ticks;\n  }\n\n  /// Calculates the domain extents that this provider will cover based on the\n  /// axis extents passed in and the settings in the numeric tick provider.\n  /// Stores the domain extents in [_low] and [_high].\n  void _updateDomainExtents(NumericExtents axisExtents) {\n    _low = axisExtents.min;\n    _high = axisExtents.max;\n\n    // Correct the extents for zero bound\n    if (zeroBound) {\n      _low = _low > 0.0 ? 0.0 : _low;\n      _high = _high < 0.0 ? 0.0 : _high;\n    }\n\n    // Correct cases where high and low equal to give the tick provider an\n    // actual range to go off of when picking ticks.\n    if (_high == _low) {\n      if (_high == 0.0) {\n        // Corner case: the only values we've seen are zero, so lets just say\n        // the high is 1 and leave the low at zero.\n        _high = 1.0;\n      } else {\n        // The values are all the same, so assume a range of -5% to +5% from the\n        // single value.\n        if (_high > 0.0) {\n          _high *= 1.05;\n          _low *= 0.95;\n        } else {\n          // (_high == _low) < 0\n          _high *= 0.95;\n          _low *= 1.05;\n        }\n      }\n    }\n  }\n\n  /// Given [tickCount] and the domain range, finds the smallest tick increment,\n  /// chosen from power of 10 multiples of allowed steps, that covers the whole\n  /// data range.\n  _TickStepInfo _getStepsForTickCount(int tickCount, num high, num low) {\n    // A region is the space between ticks.\n    final regionCount = tickCount - 1;\n\n    // If the range contains zero, ensure that zero is a tick.\n    if (high >= 0 && low <= 0) {\n      // determine the ratio of regions that are above the zero axis.\n      final posRegionRatio = high > 0 ? min(1.0, high / (high - low)) : 0.0;\n      var positiveRegionCount = (regionCount * posRegionRatio).ceil();\n      var negativeRegionCount = regionCount - positiveRegionCount;\n      // Ensure that negative regions are not excluded, unless there are no\n      // regions to spare.\n      if (negativeRegionCount == 0 && low < 0 && regionCount > 1) {\n        positiveRegionCount--;\n        negativeRegionCount++;\n      }\n\n      // If we have positive and negative values, ensure that we have ticks in\n      // both regions.\n      //\n      // This should not happen unless the axis is manually configured with a\n      // tick count. [_updateTickCounts] should ensure that we have do not try\n      // to generate fewer than three.\n      assert(\n          !(low < 0 &&\n              high > 0 &&\n              (negativeRegionCount == 0 || positiveRegionCount == 0)),\n          'Numeric tick provider cannot generate ${tickCount} '\n          'ticks when the axis range contains both positive and negative '\n          'values. A minimum of three ticks are required to include zero.');\n\n      // Determine the \"favored\" axis direction (the one which will control the\n      // ticks based on having a greater value / regions).\n      //\n      // Example: 13 / 3 (4.33 per tick) vs -5 / 1 (5 per tick)\n      // making -5 the favored number.  A step size that includes this number\n      // ensures the other is also includes in the opposite direction.\n      final favorPositive = (high > 0 ? high / positiveRegionCount : 0).abs() >\n          (low < 0 ? low / negativeRegionCount : 0).abs();\n      final favoredNum = (favorPositive ? high : low).abs();\n      final favoredRegionCount =\n          favorPositive ? positiveRegionCount : negativeRegionCount;\n      final favoredTensBase = (_getEnclosingPowerOfTen(favoredNum)).abs();\n\n      // Check each step size and see if it would contain the \"favored\" value\n      for (final step in _allowedSteps) {\n        final tmpStepSize = _removeRoundingErrors(step * favoredTensBase);\n\n        // If prefer whole number, then don't allow a step that isn't one.\n        if (dataIsInWholeNumbers && tmpStepSize.round() != tmpStepSize) {\n          continue;\n        }\n\n        // TODO: Skip steps that format to the same string.\n        // But wait until the last step to prevent the cost of the formatter.\n        // Potentially store the formatted strings in TickStepInfo?\n        if (tmpStepSize * favoredRegionCount >= favoredNum) {\n          final stepStart = negativeRegionCount > 0\n              ? (-1 * tmpStepSize * negativeRegionCount)\n              : 0.0;\n          return _TickStepInfo(tmpStepSize, stepStart);\n        }\n      }\n    } else {\n      // Find the range base to calculate step sizes.\n      final diffTensBase = _getEnclosingPowerOfTen(high - low);\n      // Walk the step sizes calculating a starting point and seeing if the high\n      // end is included in the range given that step size.\n      for (final step in _allowedSteps) {\n        final tmpStepSize = _removeRoundingErrors(step * diffTensBase);\n\n        // If prefer whole number, then don't allow a step that isn't one.\n        if (dataIsInWholeNumbers && tmpStepSize.round() != tmpStepSize) {\n          continue;\n        }\n\n        // TODO: Skip steps that format to the same string.\n        // But wait until the last step to prevent the cost of the formatter.\n        final tmpStepStart = _getStepLessThan(low.toDouble(), tmpStepSize);\n        if (tmpStepStart + (tmpStepSize * regionCount) >= high) {\n          return _TickStepInfo(tmpStepSize, tmpStepStart);\n        }\n      }\n    }\n\n    return _TickStepInfo(1.0, low.floorToDouble());\n  }\n\n  List<double> _getTickValues(_TickStepInfo steps, int tickCount) {\n    // We have our size and start, assign all the tick values to the given array.\n    return [\n      for (int i = 0; i < tickCount; i++)\n        dataToAxisUnitConverter\n            .invert(\n                _removeRoundingErrors(steps.tickStart + (i * steps.stepSize)))\n            .toDouble(),\n    ];\n  }\n\n  /// Given the axisDimensions update the tick counts given they are not fixed.\n  void _updateTickCounts({\n    required num high,\n    required num low,\n    required int rangeWidth,\n  }) {\n    int tmpMaxNumMajorTicks;\n    int tmpMinNumMajorTicks;\n\n    // If the domain range contains both positive and negative values, then we\n    // need a minimum of three ticks to include zero as a tick. Otherwise, we\n    // only need an upper and lower tick.\n    final absoluteMinTicks = (low < 0 && 0 < high) ? 3 : 2;\n\n    // If there is a desired tick range use it, if not calculate one.\n    if (_desiredMaxTickCount != null) {\n      tmpMinNumMajorTicks = max(_desiredMinTickCount!, absoluteMinTicks);\n      tmpMaxNumMajorTicks = max(_desiredMaxTickCount!, tmpMinNumMajorTicks);\n    } else {\n      final minPixelsPerTick = MIN_DIPS_BETWEEN_TICKS.toDouble();\n      tmpMinNumMajorTicks = absoluteMinTicks;\n      tmpMaxNumMajorTicks =\n          max(absoluteMinTicks, (rangeWidth / minPixelsPerTick).floor());\n    }\n\n    // Don't blow away the previous array if it hasn't changed.\n    if (tmpMaxNumMajorTicks != _maxTickCount ||\n        tmpMinNumMajorTicks != _minTickCount) {\n      _maxTickCount = tmpMaxNumMajorTicks;\n      _minTickCount = tmpMinNumMajorTicks;\n    }\n  }\n\n  /// Returns the power of 10 which contains the [number].\n  ///\n  /// If [number] is 0 returns 1.\n  /// Examples:\n  /// [number] of 63 returns 100\n  /// [number] of -63 returns -100\n  /// [number] of 0.63 returns 1\n  static double _getEnclosingPowerOfTen(num number) {\n    if (number == 0) {\n      return 1.0;\n    }\n\n    return pow(10, (log10e * log(number.abs())).ceil()).toDouble() *\n        (number < 0.0 ? -1.0 : 1.0);\n  }\n\n  /// Returns the step numerically less than the number by step increments.\n  static double _getStepLessThan(double number, double stepSize) {\n    if (number == 0.0 || stepSize == 0.0) {\n      return 0.0;\n    }\n    return (stepSize > 0.0\n            ? (number / stepSize).floor()\n            : (number / stepSize).ceil()) *\n        stepSize;\n  }\n\n  /// Attempts to slice off very small floating point rounding effects for the\n  /// given number.\n  ///\n  /// @param number the number to round.\n  /// @return the rounded number.\n  static double _removeRoundingErrors(double number) {\n    // sufficiently large multiplier to handle generating ticks on the order\n    // of 10^-9.\n    const multiplier = 1.0e9;\n\n    return number > 100.0\n        ? number.roundToDouble()\n        : (number * multiplier).roundToDouble() / multiplier;\n  }\n}\n\nclass _TickStepInfo {\n  double stepSize;\n  double tickStart;\n\n  _TickStepInfo(this.stepSize, this.tickStart);\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/cartesian/axis/ordinal_extents.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:collection' show HashSet;\nimport 'scale.dart' show Extents;\n\n/// A range of ordinals.\nclass OrdinalExtents extends Extents<String> {\n  final List<String> _range;\n\n  /// The extents representing the ordinal values in [range].\n  ///\n  /// The elements of [range] must all be unique.\n  ///\n  /// [D] is the domain class type for the elements in the extents.\n  OrdinalExtents(List<String> range) : _range = range {\n    // This asserts that all elements in [range] are unique.\n    assert(() {\n      final uniqueValueCount = HashSet.of(_range).length;\n      return uniqueValueCount == range.length;\n    }());\n  }\n\n  factory OrdinalExtents.all(List<String> range) => OrdinalExtents(range);\n\n  bool get isEmpty => _range.isEmpty;\n\n  /// The number of values inside this extent.\n  int get length => _range.length;\n\n  String? operator [](int index) => _range[index];\n\n  int indexOf(String value) => _range.indexOf(value);\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/cartesian/axis/ordinal_scale.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'ordinal_scale_domain_info.dart' show OrdinalScaleDomainInfo;\nimport 'scale.dart' show MutableScale;\n\nabstract class OrdinalScale extends MutableScale<String> {\n  /// The current domain collection with all added unique values.\n  OrdinalScaleDomainInfo get domain;\n\n  /// Sets the viewport of the scale based on the number of data points to show\n  ///  and the starting domain value.\n  ///\n  /// [viewportDataSize] How many ordinal domain values to show in the viewport.\n  /// [startingDomain] The starting domain value of the viewport. Note that if\n  /// the starting domain is in terms of position less than [domainValuesToShow]\n  /// from the last domain value the viewport will be fixed to the last value\n  /// and not guaranteed that this domain value is the first in the viewport.\n  void setViewport(int? viewportDataSize, String? startingDomain);\n\n  /// The number of full ordinal steps that fit in the viewport.\n  int get viewportDataSize;\n\n  /// The first fully visible ordinal step within the viewport.\n  ///\n  /// Start is defined by the leftmost domain for horizontal axes, and\n  /// topmost domain for vertical axes.\n  ///\n  /// Null if no domains exist.\n  String? get viewportStartingDomain;\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/cartesian/axis/ordinal_scale_domain_info.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:collection' show HashMap;\nimport 'ordinal_extents.dart' show OrdinalExtents;\n\n/// A domain processor for [OrdinalScale].\n///\n/// [D] domain class type of the values being tracked.\n///\n/// Unique domain values are kept, so duplicates will not increase the extent.\nclass OrdinalScaleDomainInfo {\n  int _index = 0;\n\n  /// A map of domain value and the order it was added.\n  final _domainsToOrder = HashMap<String, int>();\n\n  /// A list of domain values kept to support [getDomainAtIndex].\n  final _domainList = <String>[];\n\n  OrdinalScaleDomainInfo();\n\n  OrdinalScaleDomainInfo copy() {\n    return OrdinalScaleDomainInfo()\n      .._domainsToOrder.addAll(_domainsToOrder)\n      .._index = _index\n      .._domainList.addAll(_domainList);\n  }\n\n  void add(String domain) {\n    if (!_domainsToOrder.containsKey(domain)) {\n      _domainsToOrder[domain] = _index;\n      _index += 1;\n      _domainList.add(domain);\n    }\n  }\n\n  int? indexOf(String domain) => _domainsToOrder[domain];\n\n  String getDomainAtIndex(int index) {\n    assert(index >= 0);\n    assert(index < _index);\n    return _domainList[index];\n  }\n\n  List<String> get domains => _domainList;\n\n  String? get first => _domainList.isEmpty ? null : _domainList.first;\n\n  String? get last => _domainList.isEmpty ? null : _domainList.last;\n\n  bool get isEmpty => _index == 0;\n  bool get isNotEmpty => !isEmpty;\n\n  OrdinalExtents get extent => OrdinalExtents.all(_domainList);\n\n  int get size => _index;\n\n  /// Clears all domain values.\n  void clear() {\n    _domainsToOrder.clear();\n    _domainList.clear();\n    _index = 0;\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/cartesian/axis/ordinal_tick_provider.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport '../../../common/graphics_factory.dart' show GraphicsFactory;\nimport '../../common/chart_context.dart' show ChartContext;\nimport 'axis.dart' show AxisOrientation;\nimport 'draw_strategy/tick_draw_strategy.dart' show TickDrawStrategy;\nimport 'ordinal_scale.dart' show OrdinalScale;\nimport 'tick.dart' show Tick;\nimport 'tick_formatter.dart' show TickFormatter;\nimport 'tick_provider.dart' show BaseTickProvider, TickHint;\n\n/// A strategy for selecting ticks to draw given ordinal domain values.\nclass OrdinalTickProvider extends BaseTickProvider<String> {\n  const OrdinalTickProvider();\n\n  @override\n  List<Tick<String>> getTicks({\n    required ChartContext? context,\n    required GraphicsFactory graphicsFactory,\n    required OrdinalScale scale,\n    required TickFormatter<String> formatter,\n    required Map<String, String> formatterValueCache,\n    required TickDrawStrategy<String> tickDrawStrategy,\n    required AxisOrientation? orientation,\n    bool viewportExtensionEnabled = false,\n    TickHint<String>? tickHint,\n  }) {\n    return createTicks(scale.domain.domains,\n        context: context,\n        graphicsFactory: graphicsFactory,\n        scale: scale,\n        formatter: formatter,\n        formatterValueCache: formatterValueCache,\n        tickDrawStrategy: tickDrawStrategy);\n  }\n\n  @override\n  bool operator ==(Object other) => other is OrdinalTickProvider;\n\n  @override\n  int get hashCode => 31;\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/cartesian/axis/range_axis_tick.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'axis_tick.dart' show AxisTicks;\nimport 'range_tick.dart' show RangeTick;\n\nclass RangeAxisTicks<D> extends AxisTicks<D> {\n  /// The value that this range tick starting point represents\n  final D rangeStartValue;\n\n  /// Position of the range tick starting point.\n  double rangeStartLocationPx;\n\n  /// The value that this range tick ending point represents.\n  final D rangeEndValue;\n\n  /// Position of the range tick ending point.\n  double rangeEndLocationPx;\n\n  RangeAxisTicks(RangeTick<D> tick)\n      : rangeStartValue = tick.rangeStartValue,\n        rangeStartLocationPx = tick.rangeStartLocationPx,\n        rangeEndValue = tick.rangeEndValue,\n        rangeEndLocationPx = tick.rangeEndLocationPx,\n        super(tick);\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/cartesian/axis/range_tick.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport '../../../common/text_element.dart';\n\nimport 'tick.dart' show Tick;\n\n/// A labeled range on an axis.\n///\n/// [D] is the type of the value this tick is associated with.\nclass RangeTick<D> extends Tick<D> {\n  /// The value that this range tick starting point represents\n  final D rangeStartValue;\n\n  /// Position of the range tick starting point.\n  double rangeStartLocationPx;\n\n  /// The value that this range tick ending point represents.\n  final D rangeEndValue;\n\n  /// Position of the range tick ending point.\n  double rangeEndLocationPx;\n\n  RangeTick(\n      {required D value,\n      required TextElement textElement,\n      double? locationPx,\n      double? labelOffsetPx,\n      required this.rangeStartValue,\n      required this.rangeStartLocationPx,\n      required this.rangeEndValue,\n      required this.rangeEndLocationPx})\n      : super(\n            value: value,\n            locationPx: locationPx,\n            textElement: textElement,\n            labelOffsetPx: labelOffsetPx);\n\n  @override\n  String toString() => 'RangeTick(value: $value, locationPx: $locationPx, '\n      'labelOffsetPx: $labelOffsetPx, rangeStartValue: $rangeStartValue, '\n      'rangeStartLocationPx: $rangeStartLocationPx, '\n      'rangeEndValue: $rangeEndValue,  rangeEndLocationPx: $rangeEndLocationPx)';\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/cartesian/axis/range_tick_provider.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport '../../../common/graphics_factory.dart' show GraphicsFactory;\nimport '../../common/chart_context.dart' show ChartContext;\nimport 'axis.dart' show AxisOrientation;\nimport 'draw_strategy/tick_draw_strategy.dart' show TickDrawStrategy;\nimport 'numeric_scale.dart' show NumericScale;\nimport 'range_tick.dart' show RangeTick;\nimport 'scale.dart' show MutableScale;\nimport 'spec/range_tick_spec.dart' show RangeTickSpec;\nimport 'spec/tick_spec.dart' show TickSpec;\nimport 'tick.dart' show Tick;\nimport 'tick_formatter.dart' show TickFormatter;\nimport 'tick_provider.dart' show TickProvider, TickHint;\nimport 'time/date_time_scale.dart' show DateTimeScale;\n\n/// A strategy that provides normal ticks and range ticks.\nclass RangeTickProvider<D> extends TickProvider<D> {\n  final List<TickSpec<D>> tickSpec;\n  RangeTickProvider(this.tickSpec);\n\n  @override\n  List<Tick<D>> getTicks({\n    required ChartContext? context,\n    required GraphicsFactory graphicsFactory,\n    required MutableScale<D> scale,\n    required TickFormatter<D> formatter,\n    required Map<D, String> formatterValueCache,\n    required TickDrawStrategy<D> tickDrawStrategy,\n    required AxisOrientation? orientation,\n    bool viewportExtensionEnabled = false,\n    TickHint<D>? tickHint,\n  }) {\n    final ticks = <Tick<D>>[];\n\n    var allTicksHaveLabels = true;\n\n    for (final spec in tickSpec) {\n      // When static ticks are being used with a numeric axis, extend the axis\n      // with the values specified.\n      if (scale is NumericScale || scale is DateTimeScale) {\n        scale.addDomain(spec.value);\n        if (spec is RangeTickSpec<D>) {\n          scale.addDomain(spec.rangeStartValue);\n          scale.addDomain(spec.rangeEndValue);\n        }\n      }\n\n      // Save off whether all ticks have labels.\n      allTicksHaveLabels &= spec.label != null;\n    }\n\n    // Use the formatter's label if the tick spec does not provide one.\n    List<String>? formattedValues;\n    if (!allTicksHaveLabels) {\n      formattedValues = formatter.format(\n          tickSpec.map((spec) => spec.value).toList(), formatterValueCache,\n          stepSize: scale.domainStepSize);\n    }\n\n    for (var i = 0; i < tickSpec.length; i++) {\n      final spec = tickSpec[i];\n      Tick<D>? tick;\n\n      if (spec is RangeTickSpec<D>) {\n        // If it is a range tick, we still check if the spec's start and end\n        // points are within the viewport because we do not extend the axis for\n        // OrdinalScale.\n        if (scale.compareDomainValueToViewport(spec.rangeStartValue) == 0 &&\n            scale.compareDomainValueToViewport(spec.rangeEndValue) == 0) {\n          tick = RangeTick<D>(\n            value: spec.value,\n            textElement: graphicsFactory\n                .createTextElement(spec.label ?? formattedValues![i]),\n            locationPx: (scale[spec.rangeStartValue]! +\n                    (scale[spec.rangeEndValue]! -\n                            scale[spec.rangeStartValue]!) /\n                        2)\n                .toDouble(),\n            rangeStartValue: spec.rangeStartValue,\n            rangeStartLocationPx: scale[spec.rangeStartValue]!.toDouble(),\n            rangeEndValue: spec.rangeEndValue,\n            rangeEndLocationPx: scale[spec.rangeEndValue]!.toDouble(),\n          );\n        }\n      } else {\n        // If it is a normal tick, we still check if the spec is within the\n        // viewport because we do not extend the axis for OrdinalScale.\n        if (scale.compareDomainValueToViewport(spec.value) == 0) {\n          tick = Tick<D>(\n            value: spec.value,\n            textElement: graphicsFactory\n                .createTextElement(spec.label ?? formattedValues![i]),\n            locationPx: scale[spec.value]?.toDouble(),\n          );\n        }\n      }\n\n      if (tick != null) {\n        final style = spec.style;\n        if (style != null) {\n          tick.textElement!.textStyle = graphicsFactory.createTextPaint()\n            ..fontFamily = style.fontFamily\n            ..fontSize = style.fontSize\n            ..color = style.color\n            ..lineHeight = style.lineHeight;\n        }\n        ticks.add(tick);\n      }\n    }\n\n    // Allow draw strategy to decorate the ticks.\n    tickDrawStrategy.decorateTicks(ticks);\n\n    return ticks;\n  }\n\n  @override\n  bool operator ==(Object other) =>\n      other is RangeTickProvider && tickSpec == other.tickSpec;\n\n  @override\n  int get hashCode => tickSpec.hashCode;\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/cartesian/axis/scale.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math' as math show max, min;\n\nimport 'package:charts_common/src/common/math.dart';\n\nimport '../../../common/style/style_factory.dart' show StyleFactory;\n\n/// Scale used to convert data input domain units to output range units.\n///\n/// This is the immutable portion of the Scale definition. Used for converting\n/// data from the dataset in domain units to an output in range units (likely\n/// pixel range of the area to draw on).\n///\n/// <p>The Scale/MutableScale split is to show the intention of what you can or\n/// should be doing with the scale during different stages of chart draw\n/// process.\n///\n/// [D] is the domain class type for the values passed in.\nabstract class Scale<D> {\n  /// Applies the scale function to the [domainValue].\n  ///\n  /// Returns the pixel location for the given [domainValue] or null if the\n  /// domainValue could not be found/translated by this scale.\n  /// Non-numeric scales should be the only ones that can return null.\n  num? operator [](D domainValue);\n\n  /// Reverse application of the scale.\n  D reverse(double pixelLocation);\n\n  /// Tests a [domainValue] to see if the scale can translate it.\n  ///\n  /// Returns true if the scale can translate the given domainValue.\n  /// (Ex: linear scales can translate any number, but ordinal scales can only\n  /// translate values previously passed in.)\n  bool canTranslate(D domainValue);\n\n  /// Returns the previously set output range for the scale function.\n  ScaleOutputExtent? get range;\n\n  /// Returns the absolute width between the max and min range values.\n  int get rangeWidth;\n\n  /// Returns the configuration used to determine the rangeBand.\n  ///\n  /// This is most often used to define the bar group width.\n  RangeBandConfig get rangeBandConfig;\n\n  /// Returns the rangeBand width in pixels.\n  ///\n  /// The rangeBand is determined using the RangeBandConfig potentially with the\n  /// measured step size.  This value is used as the bar group width.  If\n  /// StepSizeConfig is set to auto detect, then you must wait until after\n  /// the chart's onPostLayout phase before you'll get a valid number.\n  double get rangeBand;\n\n  /// Returns the stepSize width in pixels.\n  ///\n  /// The step size is determined using the [StepSizeConfig].\n  double get stepSize;\n\n  /// Returns the stepSize domain value.\n  double get domainStepSize;\n\n  /// Tests whether the given [domainValue] is within the axis' range.\n  ///\n  /// Returns < 0 if the [domainValue] would plot before the viewport, 0 if it\n  /// would plot within the viewport and > 0 if it would plot beyond the\n  /// viewport of the axis.\n  int compareDomainValueToViewport(D domainValue);\n\n  /// Returns true if the given [rangeValue] point is within the output range.\n  ///\n  /// Not to be confused with the start and end of the domain.\n  bool isRangeValueWithinViewport(double rangeValue);\n\n  /// Returns the current viewport scale.\n  ///\n  /// A scale of 1.0 would map the data directly to the output range, while a\n  /// value of 2.0 would map the data to an output of double the range so you\n  /// only see half the data in the viewport.  This is the equivalent to\n  /// zooming.  Its value is likely >= 1.0.\n  double get viewportScalingFactor;\n\n  /// Returns the current pixel viewport offset\n  ///\n  /// The translate is used by the scale function when it applies the scale.\n  /// This is the equivalent to panning.  Its value is likely <= 0 to pan the\n  /// data to the left.\n  double get viewportTranslatePx;\n\n  /// Returns a mutable copy of the scale.\n  ///\n  /// Mutating the returned scale will not effect the original one.\n  MutableScale<D> copy();\n}\n\n/// Mutable extension of the [Scale] definition.\n///\n/// Used for converting data from the dataset to some range (likely pixel range)\n/// of the area to draw on.\n///\n/// [D] the domain class type for the values passed in.\nabstract class MutableScale<D> extends Scale<D> {\n  /// Reset the domain for this [Scale].\n  void resetDomain();\n\n  /// Reset the viewport settings for this [Scale].\n  void resetViewportSettings();\n\n  /// Add [domainValue] to this [Scale]'s domain.\n  ///\n  /// Domains should be added in order to allow proper stepSize detection.\n  /// [domainValue] is the data value to add to the scale used to update the\n  /// domain extent.\n  void addDomain(D domainValue);\n\n  /// Sets the output range to use for the scale's conversion.\n  ///\n  /// The range start is mapped to the domain's min and the range end is\n  /// mapped to the domain's max for the conversion using the domain nicing\n  /// function.\n  ///\n  /// [extent] is the extent of the range which will likely be the pixel\n  /// range of the drawing area to convert to.\n  set range(ScaleOutputExtent? extent);\n\n  /// Configures the zoom and translate.\n  ///\n  /// [viewportScale] is the zoom factor to use, likely >= 1.0 where 1.0 maps\n  /// the complete data extents to the output range, and 2.0 only maps half the\n  /// data to the output range.\n  ///\n  /// [viewportTranslatePx] is the translate/pan to use in pixel units,\n  /// likely <= 0 which shifts the start of the data before the edge of the\n  /// chart giving us a pan.\n  void setViewportSettings(double viewportScale, double viewportTranslatePx);\n\n  /// Sets the configuration used to determine the rangeBand (bar group width).\n  set rangeBandConfig(RangeBandConfig barGroupWidthConfig);\n\n  /// Sets the method for determining the step size.\n  ///\n  /// This is the domain space between data points.\n  StepSizeConfig get stepSizeConfig;\n  set stepSizeConfig(StepSizeConfig config);\n}\n\n/// Tuple of the output for a scale in pixels from [start] to [end] inclusive.\n///\n/// It is different from [Extent] because it focuses on start and end and not\n/// min and max, meaning that start could be greater or less than end.\nclass ScaleOutputExtent {\n  final int start;\n  final int end;\n\n  const ScaleOutputExtent(this.start, this.end);\n\n  int get min => math.min(start, end);\n  int get max => math.max(start, end);\n\n  bool containsValue(double value) => withinBounds(value, min, max);\n\n  /// Returns the difference between the extents.\n  ///\n  /// If the [end] is less than the [start] (think vertical measure axis), then\n  /// this will correctly return a negative value.\n  int get diff => end - start;\n\n  /// Returns the width of the extent.\n  int get width => diff.abs();\n\n  @override\n  bool operator ==(Object other) =>\n      other is ScaleOutputExtent && start == other.start && end == other.end;\n\n  @override\n  int get hashCode => start.hashCode + (end.hashCode * 31);\n\n  @override\n  String toString() => 'ScaleOutputRange($start, $end)';\n}\n\n/// Type of RangeBand used to determine the rangeBand size units.\nenum RangeBandType {\n  /// No rangeBand (not suitable for bars or step line charts).\n  none,\n\n  /// Size is specified in pixel units.\n  fixedPixel,\n\n  /// Size is specified domain scale units.\n  fixedDomain,\n\n  /// Size is a percentage of the minimum step size between points.\n  fixedPercentOfStep,\n\n  /// Size is a style pack assigned percentage of the minimum step size between\n  /// points.\n  styleAssignedPercentOfStep,\n\n  /// Size is subtracted from the minimum step size between points in pixel\n  /// units.\n  fixedPixelSpaceFromStep,\n}\n\n/// Defines the method for calculating the rangeBand of the Scale.\n///\n/// The rangeBand is used to determine the width of a group of bars.  The term\n/// rangeBand comes from the d3 JavaScript library which the JS library uses\n/// internally.\n///\n/// <p>RangeBandConfig is immutable, See factory methods for creating one.\nclass RangeBandConfig {\n  final RangeBandType type;\n\n  /// The width of the band in units specified by the bandType.\n  final double size;\n\n  /// Creates a rangeBand definition of zero, no rangeBand.\n  const RangeBandConfig.none()\n      : type = RangeBandType.none,\n        size = 0.0;\n\n  /// Creates a fixed rangeBand definition in pixel width.\n  ///\n  /// Used to determine a bar width or a step width in the line renderer.\n  const RangeBandConfig.fixedPixel(double pixels)\n      : type = RangeBandType.fixedPixel,\n        size = pixels;\n\n  /// Creates a fixed rangeBand definition in domain unit width.\n  ///\n  /// Used to determine a bar width or a step width in the line renderer.\n  const RangeBandConfig.fixedDomain(double domainSize)\n      : type = RangeBandType.fixedDomain,\n        size = domainSize;\n\n  /// Creates a config that defines the rangeBand as equal to the stepSize.\n  const RangeBandConfig.stepChartBand()\n      : type = RangeBandType.fixedPercentOfStep,\n        size = 1.0;\n\n  /// Creates a config that defines the rangeBand as percentage of the stepSize.\n  ///\n  /// [percentOfStepWidth] is the percentage of the step from 0.0 - 1.0.\n  RangeBandConfig.percentOfStep(double percentOfStepWidth)\n      : type = RangeBandType.fixedPercentOfStep,\n        size = percentOfStepWidth {\n    assert(percentOfStepWidth >= 0 && percentOfStepWidth <= 1.0);\n  }\n\n  /// Creates a config that assigns the rangeBand according to the stylepack.\n  ///\n  /// <p>Note: renderers can detect this setting and update the percent based on\n  /// the number of series in their preprocess.\n  RangeBandConfig.styleAssignedPercent([int seriesCount = 1])\n      : type = RangeBandType.styleAssignedPercentOfStep,\n        size = StyleFactory.style.rangeBandSize;\n\n  /// Creates a config that defines the rangeBand as the stepSize - pixels.\n  ///\n  /// Where fixedPixels() gave you a constant rangBand in pixels, this will give\n  /// you a constant space between rangeBands in pixels.\n  const RangeBandConfig.fixedPixelSpaceBetweenStep(double pixels)\n      : type = RangeBandType.fixedPixelSpaceFromStep,\n        size = pixels;\n}\n\n/// Type of step size calculation to use.\nenum StepSizeType { autoDetect, fixedDomain, fixedPixels }\n\n/// Defines the method for calculating the stepSize between points.\n///\n/// Typically auto will work fine in most cases, but if your data is\n/// irregular or you only have one data point, then you may want to override the\n/// stepSize detection specifying the exact expected stepSize.\nclass StepSizeConfig {\n  final StepSizeType type;\n  final double size;\n\n  /// Creates a StepSizeConfig that calculates step size based on incoming data.\n  ///\n  /// The stepSize is determined is calculated by detecting the smallest\n  /// distance between two adjacent data points.  This may not be suitable if\n  /// you have irregular data or just a single data point.\n  const StepSizeConfig.auto()\n      : type = StepSizeType.autoDetect,\n        size = 0.0;\n\n  /// Creates a StepSizeConfig specifying the exact step size in pixel units.\n  const StepSizeConfig.fixedPixels(double pixels)\n      : type = StepSizeType.fixedPixels,\n        size = pixels;\n\n  /// Creates a StepSizeConfig specifying the exact step size in domain units.\n  const StepSizeConfig.fixedDomain(double domainSize)\n      : type = StepSizeType.fixedDomain,\n        size = domainSize;\n}\n\n// TODO: make other extent subclasses plural.\nabstract class Extents<D> {}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/cartesian/axis/simple_ordinal_scale.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math' show min, max;\n\nimport 'package:charts_common/src/common/math.dart';\n\nimport 'ordinal_scale.dart' show OrdinalScale;\nimport 'ordinal_scale_domain_info.dart' show OrdinalScaleDomainInfo;\nimport 'scale.dart'\n    show\n        RangeBandConfig,\n        RangeBandType,\n        StepSizeConfig,\n        StepSizeType,\n        ScaleOutputExtent;\n\n/// Scale that converts ordinal values of type [D] to a given range output.\n///\n/// A `SimpleOrdinalScale` is used to map values from its domain to the\n/// available pixel range of the chart. Typically used for bar charts where the\n/// width of the bar is [rangeBand] and the position of the bar is retrieved\n/// by [[]].\nclass SimpleOrdinalScale implements OrdinalScale {\n  final _stepSizeConfig = StepSizeConfig.auto();\n  final OrdinalScaleDomainInfo _domain;\n  ScaleOutputExtent _range = ScaleOutputExtent(0, 1);\n  double _viewportScale = 1.0;\n  double _viewportTranslatePx = 0.0;\n  RangeBandConfig _rangeBandConfig = RangeBandConfig.styleAssignedPercent();\n\n  bool _scaleChanged = true;\n  late double _cachedStepSizePixels;\n  late double _cachedRangeBandShift;\n  late double _cachedRangeBandSize;\n\n  int? _viewportDataSize;\n  String? _viewportStartingDomain;\n\n  // TODO: When there are horizontal bars increasing from where\n  // the domain and measure axis intersects but the desired behavior is\n  // flipped. The plan is to fix this by fixing code to flip the range in the\n  // code.\n  //\n  // If range start is less than range end, then the domain is calculated by\n  // adding the band width. If range start is greater than range end, then the\n  // domain is calculated by subtracting from the band width (ex. horizontal\n  // bar charts where first series is at the bottom of the chart).\n  bool get _isVertical => range.start > range.end;\n\n  SimpleOrdinalScale() : _domain = OrdinalScaleDomainInfo();\n\n  SimpleOrdinalScale._copy(SimpleOrdinalScale other)\n      : _domain = other._domain.copy(),\n        _range = ScaleOutputExtent(other._range.start, other._range.end),\n        _viewportScale = other._viewportScale,\n        _viewportTranslatePx = other._viewportTranslatePx,\n        _rangeBandConfig = other._rangeBandConfig;\n\n  @override\n  double get rangeBand {\n    if (_scaleChanged) {\n      _updateScale();\n    }\n\n    return _cachedRangeBandSize;\n  }\n\n  @override\n  double get stepSize {\n    if (_scaleChanged) {\n      _updateScale();\n    }\n\n    return _cachedStepSizePixels;\n  }\n\n  @override\n  double get domainStepSize => 1.0;\n\n  @override\n  set rangeBandConfig(RangeBandConfig barGroupWidthConfig) {\n    if (barGroupWidthConfig == null) {\n      throw ArgumentError.notNull('RangeBandConfig must not be null.');\n    }\n\n    if (barGroupWidthConfig.type == RangeBandType.fixedDomain ||\n        barGroupWidthConfig.type == RangeBandType.none) {\n      throw ArgumentError(\n          'barGroupWidthConfig must not be NONE or FIXED_DOMAIN');\n    }\n\n    _rangeBandConfig = barGroupWidthConfig;\n    _scaleChanged = true;\n  }\n\n  @override\n  RangeBandConfig get rangeBandConfig => _rangeBandConfig;\n\n  @override\n  set stepSizeConfig(StepSizeConfig? config) {\n    if (config != null && config.type != StepSizeType.autoDetect) {\n      throw ArgumentError(\n          'Ordinal scales only support StepSizeConfig of type Auto');\n    }\n    // Nothing is set because only auto is supported.\n  }\n\n  @override\n  StepSizeConfig get stepSizeConfig => _stepSizeConfig;\n\n  /// Converts [domainValue] to the position to place the band/bar.\n  ///\n  /// Returns 0 if not found.\n  @override\n  double operator [](String domainValue) {\n    if (_scaleChanged) {\n      _updateScale();\n    }\n\n    final i = _domain.indexOf(domainValue);\n    if (i != null) {\n      return viewportTranslatePx +\n          _range.start +\n          _cachedRangeBandShift +\n          (_cachedStepSizePixels * i);\n    }\n    // If it wasn't found\n    return 0.0;\n  }\n\n  @override\n  String reverse(double pixelLocation) {\n    final index = (pixelLocation -\n            viewportTranslatePx -\n            _range.start -\n            _cachedRangeBandShift) /\n        _cachedStepSizePixels;\n\n    // The last pixel belongs in the last step even if it tries to round up.\n    //\n    // Index may be less than 0 when [pixelLocation] is less than the width of\n    // the range band shift. This may happen on the far left side of the chart,\n    // where we want the first datum anyways. Wrapping the result in \"max(0, x)\"\n    // cuts off these negative values.\n    return _domain\n        .getDomainAtIndex(max(0, min(index.round(), domain.size - 1)));\n  }\n\n  @override\n  bool canTranslate(String domainValue) => _domain.indexOf(domainValue) != null;\n\n  @override\n  OrdinalScaleDomainInfo get domain => _domain;\n\n  /// Update the scale to include [domainValue].\n  @override\n  void addDomain(String domainValue) {\n    _domain.add(domainValue);\n    _scaleChanged = true;\n  }\n\n  @override\n  set range(ScaleOutputExtent? extent) {\n    _range = extent!;\n    _scaleChanged = true;\n  }\n\n  @override\n  ScaleOutputExtent get range => _range;\n\n  @override\n  void resetDomain() {\n    _domain.clear();\n    _scaleChanged = true;\n  }\n\n  @override\n  void resetViewportSettings() {\n    _viewportScale = 1.0;\n    _viewportTranslatePx = 0.0;\n    _scaleChanged = true;\n  }\n\n  @override\n  int get rangeWidth => (range.start - range.end).abs().toInt();\n\n  @override\n  double get viewportScalingFactor => _viewportScale;\n\n  @override\n  double get viewportTranslatePx => _viewportTranslatePx;\n\n  @override\n  void setViewportSettings(double viewportScale, double viewportTranslatePx) {\n    _viewportScale = viewportScale;\n    if (_isVertical) {\n      _viewportTranslatePx = max(\n          min(-(rangeWidth * (1.0 - viewportScale)), viewportTranslatePx), 0);\n    } else {\n      _viewportTranslatePx =\n          min(max(rangeWidth * (1.0 - viewportScale), viewportTranslatePx), 0);\n    }\n    _scaleChanged = true;\n  }\n\n  @override\n  void setViewport(int? viewportDataSize, String? startingDomain) {\n    if (startingDomain != null &&\n        viewportDataSize != null &&\n        viewportDataSize <= 0) {\n      throw ArgumentError('viewportDataSize cannot be less than 1.');\n    }\n\n    _scaleChanged = true;\n    _viewportDataSize = viewportDataSize;\n    _viewportStartingDomain = startingDomain;\n  }\n\n  /// Update this scale's viewport using settings [_viewportDataSize] and\n  /// [_viewportStartingDomain].\n  void _updateViewport() {\n    setViewportSettings(1.0, 0.0);\n    _recalculateScale();\n    if (_domain.isEmpty) {\n      return;\n    }\n\n    // Update the scale with zoom level to help find the correct translate.\n    setViewportSettings(_domain.size / min(_viewportDataSize!, _domain.size),\n        _isVertical ? double.maxFinite : 0.0);\n    _recalculateScale();\n    final domainIndex = _domain.indexOf(_viewportStartingDomain!);\n    if (domainIndex != null) {\n      var viewportTranslatePx = 0.0;\n      if (_isVertical) {\n        // Account for the domain values being reversed.\n        viewportTranslatePx =\n            (_viewportDataSize! - domainIndex - 1) * _cachedStepSizePixels;\n      } else {\n        viewportTranslatePx = -(_cachedStepSizePixels * domainIndex);\n      }\n      setViewportSettings(_viewportScale, viewportTranslatePx);\n    }\n  }\n\n  @override\n  int get viewportDataSize {\n    if (_scaleChanged) {\n      _updateScale();\n    }\n\n    return _domain.isEmpty ? 0 : (rangeWidth ~/ _cachedStepSizePixels.abs());\n  }\n\n  @override\n  String? get viewportStartingDomain {\n    if (_scaleChanged) {\n      _updateScale();\n    }\n    if (_domain.isEmpty) {\n      return null;\n    }\n    if (_isVertical) {\n      // Get topmost visible index.\n      var index = (-(rangeWidth + _viewportTranslatePx) / _cachedStepSizePixels)\n              .ceil()\n              .toInt() -\n          1;\n      return _domain.getDomainAtIndex(index);\n    } else {\n      return _domain.getDomainAtIndex(\n          (-_viewportTranslatePx / _cachedStepSizePixels).ceil().toInt());\n    }\n  }\n\n  @override\n  bool isRangeValueWithinViewport(double rangeValue) {\n    return withinBounds(rangeValue, range.min, range.max);\n  }\n\n  @override\n  int compareDomainValueToViewport(String domainValue) {\n    // TODO: This currently works because range defaults to 0-1\n    // This needs to be looked into further.\n    var i = _domain.indexOf(domainValue);\n    if (i != null && range != null) {\n      var domainPx = this[domainValue];\n      if (domainPx < range.min) {\n        return -1;\n      }\n      if (domainPx > range.max) {\n        return 1;\n      }\n      return 0;\n    }\n    return -1;\n  }\n\n  @override\n  SimpleOrdinalScale copy() => SimpleOrdinalScale._copy(this);\n\n  void _updateCachedFields(\n      double stepSizePixels, double rangeBandPixels, double rangeBandShift) {\n    _cachedStepSizePixels = stepSizePixels;\n    _cachedRangeBandSize = rangeBandPixels;\n    _cachedRangeBandShift = rangeBandShift;\n\n    if (_isVertical) {\n      _cachedStepSizePixels *= -1;\n      _cachedRangeBandShift *= -1;\n    }\n\n    _scaleChanged = false;\n  }\n\n  void _updateScale() {\n    if (_viewportStartingDomain != null && _viewportDataSize != null) {\n      // Update viewport recalculates the scale.\n      _updateViewport();\n    }\n    _recalculateScale();\n  }\n\n  void _recalculateScale() {\n    final stepSizePixels = _domain.isEmpty\n        ? 0.0\n        : _viewportScale * (rangeWidth.toDouble() / _domain.size.toDouble());\n    double rangeBandPixels;\n\n    switch (rangeBandConfig.type) {\n      case RangeBandType.fixedPixel:\n        rangeBandPixels = rangeBandConfig.size.toDouble();\n        break;\n      case RangeBandType.fixedPixelSpaceFromStep:\n        var spaceInPixels = rangeBandConfig.size.toDouble();\n        rangeBandPixels = max(0.0, stepSizePixels - spaceInPixels);\n        break;\n      case RangeBandType.styleAssignedPercentOfStep:\n      case RangeBandType.fixedPercentOfStep:\n        var percent = rangeBandConfig.size.toDouble();\n        rangeBandPixels = stepSizePixels * percent;\n        break;\n      case RangeBandType.fixedDomain:\n      case RangeBandType.none:\n        throw StateError('RangeBandType must not be NONE or FIXED_DOMAIN');\n    }\n\n    _updateCachedFields(stepSizePixels, rangeBandPixels, stepSizePixels / 2.0);\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/cartesian/axis/spec/axis_spec.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'package:meta/meta.dart' show immutable;\n\nimport '../../../../common/color.dart' show Color;\nimport '../../../../common/graphics_factory.dart' show GraphicsFactory;\nimport '../../../common/chart_context.dart' show ChartContext;\nimport '../axis.dart' show Axis;\nimport '../scale.dart' show Scale, MutableScale;\nimport '../draw_strategy/tick_draw_strategy.dart' show TickDrawStrategy;\nimport '../tick_formatter.dart' show TickFormatter;\nimport '../tick_provider.dart' show TickProvider;\n\n@immutable\nclass AxisSpec<D> {\n  final bool? showAxisLine;\n  final RenderSpec<D>? renderSpec;\n  final TickProviderSpec<D>? tickProviderSpec;\n  final TickFormatterSpec<D>? tickFormatterSpec;\n  final ScaleSpec<D>? scaleSpec;\n\n  const AxisSpec({\n    this.renderSpec,\n    this.tickProviderSpec,\n    this.tickFormatterSpec,\n    this.showAxisLine,\n    this.scaleSpec,\n  });\n\n  factory AxisSpec.from(\n    AxisSpec<D> other, {\n    RenderSpec<D>? renderSpec,\n    TickProviderSpec<D>? tickProviderSpec,\n    TickFormatterSpec<D>? tickFormatterSpec,\n    bool? showAxisLine,\n    ScaleSpec<D>? scaleSpec,\n  }) {\n    return AxisSpec(\n      renderSpec: renderSpec ?? other.renderSpec,\n      tickProviderSpec: tickProviderSpec ?? other.tickProviderSpec,\n      tickFormatterSpec: tickFormatterSpec ?? other.tickFormatterSpec,\n      showAxisLine: showAxisLine ?? other.showAxisLine,\n      scaleSpec: scaleSpec ?? other.scaleSpec,\n    );\n  }\n\n  void configure(\n      Axis<D> axis, ChartContext context, GraphicsFactory graphicsFactory) {\n    axis.resetDefaultConfiguration();\n\n    if (showAxisLine != null) {\n      axis.forceDrawAxisLine = showAxisLine;\n    }\n\n    if (renderSpec != null) {\n      axis.tickDrawStrategy =\n          renderSpec!.createDrawStrategy(context, graphicsFactory);\n    }\n\n    if (tickProviderSpec != null) {\n      axis.tickProvider = tickProviderSpec!.createTickProvider(context);\n    }\n\n    if (tickFormatterSpec != null) {\n      axis.tickFormatter = tickFormatterSpec!.createTickFormatter(context);\n    }\n\n    if (scaleSpec != null) {\n      axis.scale = scaleSpec!.createScale() as MutableScale<D>;\n    }\n  }\n\n  /// Creates an appropriately typed [Axis].\n  Axis<D>? createAxis() => null;\n\n  @override\n  bool operator ==(Object other) =>\n      identical(this, other) ||\n      (other is AxisSpec &&\n          renderSpec == other.renderSpec &&\n          tickProviderSpec == other.tickProviderSpec &&\n          tickFormatterSpec == other.tickFormatterSpec &&\n          showAxisLine == other.showAxisLine &&\n          scaleSpec == other.scaleSpec);\n\n  @override\n  int get hashCode {\n    var hashcode = renderSpec.hashCode;\n    hashcode = (hashcode * 37) + tickProviderSpec.hashCode;\n    hashcode = (hashcode * 37) + tickFormatterSpec.hashCode;\n    hashcode = (hashcode * 37) + showAxisLine.hashCode;\n    hashcode = (hashCode * 37) + scaleSpec.hashCode;\n    return hashcode;\n  }\n}\n\n@immutable\nabstract class TickProviderSpec<D> {\n  TickProvider<D> createTickProvider(ChartContext context);\n}\n\n@immutable\nabstract class TickFormatterSpec<D> {\n  TickFormatter<D> createTickFormatter(ChartContext context);\n}\n\n@immutable\nabstract class ScaleSpec<D> {\n  Scale<D> createScale();\n}\n\n@immutable\nabstract class RenderSpec<D> {\n  const RenderSpec();\n\n  TickDrawStrategy<D> createDrawStrategy(\n      ChartContext context, GraphicsFactory graphicFactory);\n}\n\n@immutable\nclass TextStyleSpec {\n  final String? fontFamily;\n  final int? fontSize;\n  final double? lineHeight;\n  final Color? color;\n  final String? fontWeight;\n\n  const TextStyleSpec(\n      {this.fontFamily,\n      this.fontSize,\n      this.lineHeight,\n      this.color,\n      this.fontWeight});\n\n  @override\n  bool operator ==(Object other) {\n    return identical(this, other) ||\n        (other is TextStyleSpec &&\n            fontFamily == other.fontFamily &&\n            fontSize == other.fontSize &&\n            lineHeight == other.lineHeight &&\n            color == other.color &&\n            fontWeight == other.fontWeight);\n  }\n\n  @override\n  int get hashCode {\n    var hashcode = fontFamily.hashCode;\n    hashcode = (hashcode * 37) + fontSize.hashCode;\n    hashcode = (hashcode * 37) + lineHeight.hashCode;\n    hashcode = (hashcode * 37) + color.hashCode;\n    hashcode = (hashcode * 37) + fontWeight.hashCode;\n    return hashcode;\n  }\n}\n\n@immutable\nclass LineStyleSpec {\n  final Color? color;\n  final List<int>? dashPattern;\n  final int? thickness;\n\n  const LineStyleSpec({this.color, this.dashPattern, this.thickness});\n\n  @override\n  bool operator ==(Object other) {\n    return identical(this, other) ||\n        (other is LineStyleSpec &&\n            color == other.color &&\n            dashPattern == other.dashPattern &&\n            thickness == other.thickness);\n  }\n\n  @override\n  int get hashCode {\n    var hashcode = color.hashCode;\n    hashcode = (hashcode * 37) + dashPattern.hashCode;\n    hashcode = (hashcode * 37) + thickness.hashCode;\n    return hashcode;\n  }\n}\n\nenum TickLabelAnchor {\n  before,\n  centered,\n  after,\n\n  /// The top most tick draws all text under the location.\n  /// The bottom most tick draws all text above the location.\n  /// The rest of the ticks are centered.\n  inside,\n}\n\nenum TickLabelJustification {\n  inside,\n  outside,\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/cartesian/axis/spec/bucketing_axis_spec.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'package:intl/intl.dart';\nimport 'package:meta/meta.dart' show immutable;\n\nimport '../../../../common/graphics_factory.dart' show GraphicsFactory;\nimport '../../../common/chart_context.dart' show ChartContext;\nimport '../axis.dart' show Axis, NumericAxis;\nimport '../linear/bucketing_numeric_axis.dart' show BucketingNumericAxis;\nimport '../linear/bucketing_numeric_tick_provider.dart'\n    show BucketingNumericTickProvider;\nimport '../numeric_extents.dart' show NumericExtents;\nimport 'axis_spec.dart' show AxisSpec, RenderSpec;\nimport 'numeric_axis_spec.dart'\n    show\n        BasicNumericTickFormatterSpec,\n        BasicNumericTickProviderSpec,\n        NumericAxisSpec,\n        NumericTickProviderSpec,\n        NumericTickFormatterSpec;\n\n/// A numeric [AxisSpec] that positions all values beneath a certain [threshold]\n/// into a reserved space on the axis range. The label for the bucket line will\n/// be drawn in the middle of the bucket range, rather than aligned with the\n/// gridline for that value's position on the scale.\n///\n/// An example illustration of a bucketing measure axis on a point chart\n/// follows. In this case, values such as \"6%\" and \"3%\" are drawn in the bucket\n/// of the axis, since they are less than the [threshold] value of 10%.\n///\n///  100% ┠─────────────────────────\n///       ┃                  *\n///       ┃         *\n///   50% ┠──────*──────────────────\n///       ┃\n///       ┠─────────────────────────\n/// < 10% ┃   *          *\n///       ┗┯━━━━━━━━━━┯━━━━━━━━━━━┯━\n///       0         50          100\n///\n/// This axis will format numbers as percents by default.\n@immutable\nclass BucketingAxisSpec extends NumericAxisSpec {\n  /// All values smaller than the threshold will be bucketed into the same\n  /// position in the reserved space on the axis.\n  final num? threshold;\n\n  /// Whether or not measure values bucketed below the [threshold] should be\n  /// visible on the chart, or collapsed.\n  ///\n  /// If this is false, then any data with measure values smaller than\n  /// [threshold] will not be rendered on the chart.\n  final bool showBucket;\n\n  /// Creates a [NumericAxisSpec] that is specialized for percentage data.\n  BucketingAxisSpec({\n    RenderSpec<num>? renderSpec,\n    NumericTickProviderSpec? tickProviderSpec,\n    NumericTickFormatterSpec? tickFormatterSpec,\n    bool? showAxisLine,\n    bool? showBucket,\n    this.threshold,\n    NumericExtents? viewport,\n  })  : showBucket = showBucket ?? true,\n        super(\n            renderSpec: renderSpec,\n            tickProviderSpec:\n                tickProviderSpec ?? const BucketingNumericTickProviderSpec(),\n            tickFormatterSpec: tickFormatterSpec ??\n                BasicNumericTickFormatterSpec.fromNumberFormat(\n                    NumberFormat.percentPattern()),\n            showAxisLine: showAxisLine,\n            viewport: viewport ?? const NumericExtents(0.0, 1.0));\n\n  @override\n  void configure(\n      Axis<num> axis, ChartContext context, GraphicsFactory graphicsFactory) {\n    super.configure(axis, context, graphicsFactory);\n\n    if (axis is NumericAxis && viewport != null) {\n      axis.setScaleViewport(viewport!);\n    }\n\n    if (axis is BucketingNumericAxis && threshold != null) {\n      axis.threshold = threshold!;\n    }\n\n    if (axis is BucketingNumericAxis) {\n      axis.showBucket = showBucket;\n    }\n  }\n\n  @override\n  BucketingNumericAxis createAxis() => BucketingNumericAxis();\n\n  @override\n  bool operator ==(Object other) =>\n      identical(this, other) ||\n      (other is BucketingAxisSpec &&\n          showBucket == other.showBucket &&\n          threshold == other.threshold &&\n          super == other);\n\n  @override\n  int get hashCode {\n    var hashcode = super.hashCode;\n    hashcode = (hashcode * 37) + showBucket.hashCode;\n    hashcode = (hashcode * 37) + threshold.hashCode;\n    return hashcode;\n  }\n}\n\n@immutable\nclass BucketingNumericTickProviderSpec extends BasicNumericTickProviderSpec {\n  /// Creates a [TickProviderSpec] that generates ticks for a bucketing axis.\n  ///\n  /// [zeroBound] automatically include zero in the data range.\n  /// [dataIsInWholeNumbers] skip over ticks that would produce\n  ///     fractional ticks that don't make sense for the domain (ie: headcount).\n  /// [desiredTickCount] the fixed number of ticks to try to make. Convenience\n  ///     that sets [desiredMinTickCount] and [desiredMaxTickCount] the same.\n  ///     Both min and max win out if they are set along with\n  ///     [desiredTickCount].\n  /// [desiredMinTickCount] automatically choose the best tick\n  ///     count to produce the 'nicest' ticks but make sure we have this many.\n  /// [desiredMaxTickCount] automatically choose the best tick\n  ///     count to produce the 'nicest' ticks but make sure we don't have more\n  ///     than this many.\n  const BucketingNumericTickProviderSpec(\n      {bool? zeroBound,\n      bool? dataIsInWholeNumbers,\n      int? desiredTickCount,\n      int? desiredMinTickCount,\n      int? desiredMaxTickCount})\n      : super(\n          zeroBound: zeroBound ?? true,\n          dataIsInWholeNumbers: dataIsInWholeNumbers ?? false,\n          desiredTickCount: desiredTickCount,\n          desiredMinTickCount: desiredMinTickCount,\n          desiredMaxTickCount: desiredMaxTickCount,\n        );\n\n  @override\n  BucketingNumericTickProvider createTickProvider(ChartContext context) {\n    final provider = BucketingNumericTickProvider()\n      ..zeroBound = zeroBound!\n      ..dataIsInWholeNumbers = dataIsInWholeNumbers!;\n\n    if (desiredMinTickCount != null ||\n        desiredMaxTickCount != null ||\n        desiredTickCount != null) {\n      provider.setTickCount(desiredMaxTickCount ?? desiredTickCount ?? 10,\n          desiredMinTickCount ?? desiredTickCount ?? 2);\n    }\n    return provider;\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/cartesian/axis/spec/date_time_axis_spec.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'package:meta/meta.dart' show immutable;\nimport 'package:intl/intl.dart' show DateFormat;\n\nimport '../../../../common/date_time_factory.dart' show DateTimeFactory;\nimport '../../../../common/graphics_factory.dart' show GraphicsFactory;\nimport '../../../common/chart_context.dart' show ChartContext;\nimport '../axis.dart' show Axis;\nimport '../end_points_tick_provider.dart' show EndPointsTickProvider;\nimport '../static_tick_provider.dart' show StaticTickProvider;\nimport '../time/auto_adjusting_date_time_tick_provider.dart'\n    show AutoAdjustingDateTimeTickProvider;\nimport '../time/date_time_axis.dart' show DateTimeAxis;\nimport '../time/date_time_extents.dart' show DateTimeExtents;\nimport '../time/date_time_tick_formatter.dart' show DateTimeTickFormatter;\nimport '../time/day_time_stepper.dart' show DayTimeStepper;\nimport '../time/hour_tick_formatter.dart' show HourTickFormatter;\nimport '../time/simple_time_tick_formatter.dart'\n    show DateTimeFormatterFunction, SimpleTimeTickFormatter;\nimport '../time/time_range_tick_provider_impl.dart'\n    show TimeRangeTickProviderImpl;\nimport '../time/time_tick_formatter.dart' show TimeTickFormatter;\nimport '../time/time_tick_formatter_impl.dart'\n    show CalendarField, TimeTickFormatterImpl;\nimport 'axis_spec.dart'\n    show AxisSpec, TickProviderSpec, TickFormatterSpec, RenderSpec;\nimport 'tick_spec.dart' show TickSpec;\n\n/// Generic [AxisSpec] specialized for Timeseries charts.\n@immutable\nclass DateTimeAxisSpec extends AxisSpec<DateTime> {\n  /// Sets viewport for this Axis.\n  ///\n  /// If pan / zoom behaviors are set, this is the initial viewport.\n  final DateTimeExtents? viewport;\n\n  /// Creates a [AxisSpec] that specialized for timeseries charts.\n  ///\n  /// [renderSpec] spec used to configure how the ticks and labels\n  ///     actually render. Possible values are [GridlineRendererSpec],\n  ///     [SmallTickRendererSpec] & [NoneRenderSpec]. Make sure that the <D>\n  ///     given to the RenderSpec is of type [DateTime] for Timeseries.\n  /// [tickProviderSpec] spec used to configure what ticks are generated.\n  /// [tickFormatterSpec] spec used to configure how the tick labels\n  ///     are formatted.\n  /// [showAxisLine] override to force the axis to draw the axis\n  ///     line.\n  const DateTimeAxisSpec({\n    RenderSpec<DateTime>? renderSpec,\n    DateTimeTickProviderSpec? tickProviderSpec,\n    DateTimeTickFormatterSpec? tickFormatterSpec,\n    bool? showAxisLine,\n    this.viewport,\n  }) : super(\n            renderSpec: renderSpec,\n            tickProviderSpec: tickProviderSpec,\n            tickFormatterSpec: tickFormatterSpec,\n            showAxisLine: showAxisLine);\n\n  @override\n  void configure(Axis<DateTime> axis, ChartContext context,\n      GraphicsFactory graphicsFactory) {\n    super.configure(axis, context, graphicsFactory);\n\n    if (axis is DateTimeAxis && viewport != null) {\n      axis.setScaleViewport(viewport!);\n    }\n  }\n\n  @override\n  Axis<DateTime>? createAxis() {\n    assert(false, 'Call createDateTimeAxis() to create a DateTimeAxis.');\n    return null;\n  }\n\n  /// Creates a [DateTimeAxis]. This should be called in place of createAxis.\n  DateTimeAxis createDateTimeAxis(DateTimeFactory dateTimeFactory) =>\n      DateTimeAxis(dateTimeFactory);\n\n  @override\n  bool operator ==(Object other) =>\n      other is DateTimeAxisSpec && viewport == other.viewport && super == other;\n\n  @override\n  int get hashCode {\n    var hashcode = super.hashCode;\n    hashcode = (hashcode * 37) + viewport.hashCode;\n    return hashcode;\n  }\n}\n\nabstract class DateTimeTickProviderSpec extends TickProviderSpec<DateTime> {}\n\nabstract class DateTimeTickFormatterSpec extends TickFormatterSpec<DateTime> {}\n\n/// [TickProviderSpec] that sets up the automatically assigned time ticks based\n/// on the extents of your data.\n@immutable\nclass AutoDateTimeTickProviderSpec implements DateTimeTickProviderSpec {\n  final bool includeTime;\n\n  /// Creates a [TickProviderSpec] that dynamically chooses ticks based on the\n  /// extents of the data.\n  ///\n  /// [includeTime] - flag that indicates whether the time should be\n  /// included when choosing appropriate tick intervals.\n  const AutoDateTimeTickProviderSpec({this.includeTime = true});\n\n  @override\n  AutoAdjustingDateTimeTickProvider createTickProvider(ChartContext context) {\n    if (includeTime) {\n      return AutoAdjustingDateTimeTickProvider.createDefault(\n          context.dateTimeFactory);\n    } else {\n      return AutoAdjustingDateTimeTickProvider.createWithoutTime(\n          context.dateTimeFactory);\n    }\n  }\n\n  @override\n  bool operator ==(Object other) =>\n      other is AutoDateTimeTickProviderSpec && includeTime == other.includeTime;\n\n  @override\n  int get hashCode => includeTime.hashCode;\n}\n\n/// [TickProviderSpec] that sets up time ticks with days increments only.\n@immutable\nclass DayTickProviderSpec implements DateTimeTickProviderSpec {\n  final List<int>? increments;\n\n  const DayTickProviderSpec({this.increments});\n\n  /// Creates a [TickProviderSpec] that dynamically chooses ticks based on the\n  /// extents of the data, limited to day increments.\n  ///\n  /// [increments] specify the number of day increments that can be chosen from\n  /// when searching for the appropriate tick intervals.\n  @override\n  AutoAdjustingDateTimeTickProvider createTickProvider(ChartContext context) {\n    return AutoAdjustingDateTimeTickProvider.createWith([\n      TimeRangeTickProviderImpl(DayTimeStepper(context.dateTimeFactory,\n          allowedTickIncrements: increments))\n    ]);\n  }\n\n  @override\n  bool operator ==(Object other) =>\n      other is DayTickProviderSpec && increments == other.increments;\n\n  @override\n  int get hashCode => increments.hashCode;\n}\n\n/// [TickProviderSpec] that sets up time ticks at the two end points of the axis\n/// range.\n@immutable\nclass DateTimeEndPointsTickProviderSpec implements DateTimeTickProviderSpec {\n  const DateTimeEndPointsTickProviderSpec();\n\n  /// Creates a [TickProviderSpec] that dynamically chooses time ticks at the\n  /// two end points of the axis range\n  @override\n  EndPointsTickProvider<DateTime> createTickProvider(ChartContext context) {\n    return EndPointsTickProvider<DateTime>();\n  }\n\n  @override\n  // ignore: hash_and_equals\n  bool operator ==(Object other) => other is DateTimeEndPointsTickProviderSpec;\n}\n\n/// [TickProviderSpec] that allows you to specific the ticks to be used.\n@immutable\nclass StaticDateTimeTickProviderSpec implements DateTimeTickProviderSpec {\n  final List<TickSpec<DateTime>> tickSpecs;\n\n  const StaticDateTimeTickProviderSpec(this.tickSpecs);\n\n  @override\n  StaticTickProvider<DateTime> createTickProvider(ChartContext context) =>\n      StaticTickProvider<DateTime>(tickSpecs);\n\n  @override\n  bool operator ==(Object other) =>\n      other is StaticDateTimeTickProviderSpec && tickSpecs == other.tickSpecs;\n\n  @override\n  int get hashCode => tickSpecs.hashCode;\n}\n\n/// Formatters for a single level of the [DateTimeTickFormatterSpec].\n@immutable\nclass TimeFormatterSpec {\n  final String? format;\n  final String? transitionFormat;\n  final String? noonFormat;\n\n  /// Creates a formatter for a particular granularity of data.\n  ///\n  /// [format] [DateFormat] format string used to format non-transition ticks.\n  ///     The string is given to the dateTimeFactory to support i18n formatting.\n  /// [transitionFormat] [DateFormat] format string used to format transition\n  ///     ticks. Examples of transition ticks:\n  ///       Day ticks would have a transition tick at month boundaries.\n  ///       Hour ticks would have a transition tick at day boundaries.\n  ///       The first tick is typically a transition tick.\n  /// [noonFormat] [DateFormat] format string used only for formatting hours\n  ///     in the event that you want to format noon differently than other\n  ///     hours (ie: [10, 11, 12p, 1, 2, 3]).\n  const TimeFormatterSpec(\n      {this.format, this.transitionFormat, this.noonFormat});\n\n  @override\n  bool operator ==(Object other) =>\n      other is TimeFormatterSpec &&\n      format == other.format &&\n      transitionFormat == other.transitionFormat &&\n      noonFormat == other.noonFormat;\n\n  @override\n  int get hashCode {\n    var hashcode = format.hashCode;\n    hashcode = (hashcode * 37) + transitionFormat.hashCode;\n    hashcode = (hashcode * 37) + noonFormat.hashCode;\n    return hashcode;\n  }\n}\n\n/// A [DateTimeTickFormatterSpec] that accepts a [DateFormat] or a\n/// [DateTimeFormatterFunction].\n@immutable\nclass BasicDateTimeTickFormatterSpec implements DateTimeTickFormatterSpec {\n  final DateTimeFormatterFunction? formatter;\n  final DateFormat? dateFormat;\n\n  const BasicDateTimeTickFormatterSpec(DateTimeFormatterFunction formatter)\n      : formatter = formatter,\n        dateFormat = null;\n\n  const BasicDateTimeTickFormatterSpec.fromDateFormat(DateFormat dateFormat)\n      : formatter = null,\n        dateFormat = dateFormat;\n\n  /// A formatter will be created with the [DateFormat] if it is not null.\n  /// Otherwise, it will create one with the provided\n  /// [DateTimeFormatterFunction].\n  @override\n  DateTimeTickFormatter createTickFormatter(ChartContext context) {\n    assert(dateFormat != null || formatter != null);\n    return DateTimeTickFormatter.uniform(SimpleTimeTickFormatter(\n        formatter: dateFormat != null ? dateFormat!.format : formatter!));\n  }\n\n  @override\n  bool operator ==(Object other) {\n    return identical(this, other) ||\n        (other is BasicDateTimeTickFormatterSpec &&\n            formatter == other.formatter &&\n            dateFormat == other.dateFormat);\n  }\n\n  @override\n  int get hashCode {\n    var hash = formatter.hashCode;\n    hash = (hash * 37) * dateFormat.hashCode;\n    return hash;\n  }\n}\n\n/// [TickFormatterSpec] that automatically chooses the appropriate level of\n/// formatting based on the tick stepSize. Each level of date granularity has\n/// its own [TimeFormatterSpec] used to specify the formatting strings at that\n/// level.\n@immutable\nclass AutoDateTimeTickFormatterSpec implements DateTimeTickFormatterSpec {\n  final TimeFormatterSpec? minute;\n  final TimeFormatterSpec? hour;\n  final TimeFormatterSpec? day;\n  final TimeFormatterSpec? month;\n  final TimeFormatterSpec? year;\n\n  /// Creates a [TickFormatterSpec] that automatically chooses the formatting\n  /// given the individual [TimeFormatterSpec] formatters that are set.\n  ///\n  /// There is a default formatter for each level that is configurable, but\n  /// by specifying a level here it replaces the default for that particular\n  /// granularity. This is useful for swapping out one or all of the formatters.\n  const AutoDateTimeTickFormatterSpec(\n      {this.minute, this.hour, this.day, this.month, this.year});\n\n  @override\n  DateTimeTickFormatter createTickFormatter(ChartContext context) {\n    final map = <int, TimeTickFormatter>{};\n\n    if (minute != null) {\n      map[DateTimeTickFormatter.MINUTE] =\n          _makeFormatter(minute!, CalendarField.hourOfDay, context);\n    }\n    if (hour != null) {\n      map[DateTimeTickFormatter.HOUR] =\n          _makeFormatter(hour!, CalendarField.date, context);\n    }\n    if (day != null) {\n      map[23 * DateTimeTickFormatter.HOUR] =\n          _makeFormatter(day!, CalendarField.month, context);\n    }\n    if (month != null) {\n      map[28 * DateTimeTickFormatter.DAY] =\n          _makeFormatter(month!, CalendarField.year, context);\n    }\n    if (year != null) {\n      map[364 * DateTimeTickFormatter.DAY] =\n          _makeFormatter(year!, CalendarField.year, context);\n    }\n\n    return DateTimeTickFormatter(context.dateTimeFactory, overrides: map);\n  }\n\n  TimeTickFormatterImpl _makeFormatter(TimeFormatterSpec spec,\n      CalendarField transitionField, ChartContext context) {\n    if (spec.noonFormat != null) {\n      return HourTickFormatter(\n          dateTimeFactory: context.dateTimeFactory,\n          simpleFormat: spec.format,\n          transitionFormat: spec.transitionFormat,\n          noonFormat: spec.noonFormat);\n    } else {\n      return TimeTickFormatterImpl(\n          dateTimeFactory: context.dateTimeFactory,\n          simpleFormat: spec.format,\n          transitionFormat: spec.transitionFormat,\n          transitionField: transitionField);\n    }\n  }\n\n  @override\n  bool operator ==(Object other) =>\n      identical(this, other) ||\n      (other is AutoDateTimeTickFormatterSpec &&\n          minute == other.minute &&\n          hour == other.hour &&\n          day == other.day &&\n          month == other.month &&\n          year == other.year);\n\n  @override\n  int get hashCode {\n    var hashcode = minute.hashCode;\n    hashcode = (hashcode * 37) + hour.hashCode;\n    hashcode = (hashcode * 37) + day.hashCode;\n    hashcode = (hashcode * 37) + month.hashCode;\n    hashcode = (hashcode * 37) + year.hashCode;\n    return hashcode;\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/cartesian/axis/spec/end_points_time_axis_spec.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'package:meta/meta.dart' show immutable;\n\nimport '../draw_strategy/small_tick_draw_strategy.dart'\n    show SmallTickRendererSpec;\nimport '../time/date_time_extents.dart' show DateTimeExtents;\nimport 'axis_spec.dart' show AxisSpec, RenderSpec, TickLabelAnchor;\nimport 'date_time_axis_spec.dart'\n    show\n        DateTimeAxisSpec,\n        DateTimeEndPointsTickProviderSpec,\n        DateTimeTickFormatterSpec,\n        DateTimeTickProviderSpec;\n\n/// Default [AxisSpec] used for Timeseries charts.\n@immutable\nclass EndPointsTimeAxisSpec extends DateTimeAxisSpec {\n  /// Creates a [AxisSpec] that specialized for timeseries charts.\n  ///\n  /// [renderSpec] spec used to configure how the ticks and labels\n  ///     actually render. Possible values are [GridlineRendererSpec],\n  ///     [SmallTickRendererSpec] & [NoneRenderSpec]. Make sure that the <D>\n  ///     given to the RenderSpec is of type [DateTime] for Timeseries.\n  /// [tickProviderSpec] spec used to configure what ticks are generated.\n  /// [tickFormatterSpec] spec used to configure how the tick labels\n  ///     are formatted.\n  /// [showAxisLine] override to force the axis to draw the axis\n  ///     line.\n  const EndPointsTimeAxisSpec({\n    RenderSpec<DateTime>? renderSpec,\n    DateTimeTickProviderSpec? tickProviderSpec,\n    DateTimeTickFormatterSpec? tickFormatterSpec,\n    bool? showAxisLine,\n    DateTimeExtents? viewport,\n  }) : super(\n            renderSpec: renderSpec ??\n                const SmallTickRendererSpec<DateTime>(\n                    labelAnchor: TickLabelAnchor.inside,\n                    labelOffsetFromTickPx: 0),\n            tickProviderSpec:\n                tickProviderSpec ?? const DateTimeEndPointsTickProviderSpec(),\n            tickFormatterSpec: tickFormatterSpec,\n            showAxisLine: showAxisLine,\n            viewport: viewport);\n\n  @override\n  bool operator ==(Object other) =>\n      identical(this, other) ||\n      (other is EndPointsTimeAxisSpec && super == other);\n\n  @override\n  int get hashCode {\n    var hashcode = super.hashCode;\n    hashcode = (hashcode * 37) + runtimeType.hashCode;\n    return hashcode;\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/cartesian/axis/spec/numeric_axis_spec.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'package:charts_common/src/chart/cartesian/axis/tick_formatter.dart';\nimport 'package:meta/meta.dart' show immutable;\nimport 'package:intl/intl.dart';\n\nimport '../../../../common/graphics_factory.dart' show GraphicsFactory;\nimport '../../../common/chart_context.dart' show ChartContext;\nimport '../../../common/datum_details.dart' show MeasureFormatter;\nimport '../axis.dart' show Axis, NumericAxis;\nimport '../end_points_tick_provider.dart' show EndPointsTickProvider;\nimport '../numeric_extents.dart' show NumericExtents;\nimport '../numeric_tick_provider.dart' show NumericTickProvider;\nimport '../static_tick_provider.dart' show StaticTickProvider;\nimport '../tick_formatter.dart' show NumericTickFormatter;\nimport 'axis_spec.dart'\n    show AxisSpec, TickProviderSpec, TickFormatterSpec, RenderSpec;\nimport 'tick_spec.dart' show TickSpec;\n\n/// [AxisSpec] specialized for numeric/continuous axes like the measure axis.\n@immutable\nclass NumericAxisSpec extends AxisSpec<num> {\n  /// Sets viewport for this Axis.\n  ///\n  /// If pan / zoom behaviors are set, this is the initial viewport.\n  final NumericExtents? viewport;\n\n  /// Creates a [AxisSpec] that specialized for numeric data.\n  ///\n  /// [renderSpec] spec used to configure how the ticks and labels\n  ///     actually render. Possible values are [GridlineRendererSpec],\n  ///     [SmallTickRendererSpec] & [NoneRenderSpec]. Make sure that the <D>\n  ///     given to the RenderSpec is of type [num] when using this spec.\n  /// [tickProviderSpec] spec used to configure what ticks are generated.\n  /// [tickFormatterSpec] spec used to configure how the tick labels are\n  ///     formatted.\n  /// [showAxisLine] override to force the axis to draw the axis line.\n  const NumericAxisSpec({\n    RenderSpec<num>? renderSpec,\n    NumericTickProviderSpec? tickProviderSpec,\n    NumericTickFormatterSpec? tickFormatterSpec,\n    bool? showAxisLine,\n    this.viewport,\n  }) : super(\n            renderSpec: renderSpec,\n            tickProviderSpec: tickProviderSpec,\n            tickFormatterSpec: tickFormatterSpec,\n            showAxisLine: showAxisLine);\n\n  factory NumericAxisSpec.from(\n    NumericAxisSpec other, {\n    RenderSpec<num>? renderSpec,\n    TickProviderSpec<num>? tickProviderSpec,\n    TickFormatterSpec<num>? tickFormatterSpec,\n    bool? showAxisLine,\n    NumericExtents? viewport,\n  }) {\n    return NumericAxisSpec(\n      renderSpec: renderSpec ?? other.renderSpec,\n      tickProviderSpec: (tickProviderSpec ?? other.tickProviderSpec)\n          as NumericTickProviderSpec?,\n      tickFormatterSpec: (tickFormatterSpec ?? other.tickFormatterSpec)\n          as NumericTickFormatterSpec?,\n      showAxisLine: showAxisLine ?? other.showAxisLine,\n      viewport: viewport ?? other.viewport,\n    );\n  }\n\n  @override\n  void configure(\n      Axis<num> axis, ChartContext context, GraphicsFactory graphicsFactory) {\n    super.configure(axis, context, graphicsFactory);\n\n    if (axis is NumericAxis && viewport != null) {\n      axis.setScaleViewport(viewport!);\n    }\n  }\n\n  @override\n  NumericAxis createAxis() => NumericAxis();\n\n  @override\n  bool operator ==(Object other) =>\n      other is NumericAxisSpec && viewport == other.viewport && super == other;\n\n  @override\n  int get hashCode {\n    var hashcode = super.hashCode;\n    hashcode = (hashcode * 37) + viewport.hashCode;\n    hashcode = (hashcode * 37) + super.hashCode;\n    return hashcode;\n  }\n}\n\nabstract class NumericTickProviderSpec extends TickProviderSpec<num> {}\n\nabstract class NumericTickFormatterSpec extends TickFormatterSpec<num> {}\n\n@immutable\nclass BasicNumericTickProviderSpec implements NumericTickProviderSpec {\n  final bool? zeroBound;\n  final bool? dataIsInWholeNumbers;\n  final int? desiredTickCount;\n  final int? desiredMinTickCount;\n  final int? desiredMaxTickCount;\n\n  /// Creates a [TickProviderSpec] that dynamically chooses the number of\n  /// ticks based on the extents of the data.\n  ///\n  /// [zeroBound] automatically include zero in the data range.\n  /// [dataIsInWholeNumbers] skip over ticks that would produce\n  ///     fractional ticks that don't make sense for the domain (ie: headcount).\n  /// [desiredTickCount] the fixed number of ticks to try to make. Convenience\n  ///     that sets [desiredMinTickCount] and [desiredMaxTickCount] the same.\n  ///     Both min and max win out if they are set along with\n  ///     [desiredTickCount].\n  /// [desiredMinTickCount] automatically choose the best tick\n  ///     count to produce the 'nicest' ticks but make sure we have this many.\n  /// [desiredMaxTickCount] automatically choose the best tick\n  ///     count to produce the 'nicest' ticks but make sure we don't have more\n  ///     than this many.\n  const BasicNumericTickProviderSpec(\n      {this.zeroBound,\n      this.dataIsInWholeNumbers,\n      this.desiredTickCount,\n      this.desiredMinTickCount,\n      this.desiredMaxTickCount});\n\n  @override\n  NumericTickProvider createTickProvider(ChartContext context) {\n    final provider = NumericTickProvider();\n    if (zeroBound != null) {\n      provider.zeroBound = zeroBound!;\n    }\n    if (dataIsInWholeNumbers != null) {\n      provider.dataIsInWholeNumbers = dataIsInWholeNumbers!;\n    }\n\n    if (desiredMinTickCount != null ||\n        desiredMaxTickCount != null ||\n        desiredTickCount != null) {\n      provider.setTickCount(desiredMaxTickCount ?? desiredTickCount ?? 10,\n          desiredMinTickCount ?? desiredTickCount ?? 2);\n    }\n    return provider;\n  }\n\n  @override\n  bool operator ==(Object other) =>\n      other is BasicNumericTickProviderSpec &&\n      zeroBound == other.zeroBound &&\n      dataIsInWholeNumbers == other.dataIsInWholeNumbers &&\n      desiredTickCount == other.desiredTickCount &&\n      desiredMinTickCount == other.desiredMinTickCount &&\n      desiredMaxTickCount == other.desiredMaxTickCount;\n\n  @override\n  int get hashCode {\n    var hashcode = zeroBound.hashCode;\n    hashcode = (hashcode * 37) + dataIsInWholeNumbers.hashCode;\n    hashcode = (hashcode * 37) + desiredTickCount.hashCode;\n    hashcode = (hashcode * 37) + desiredMinTickCount.hashCode;\n    hashcode = (hashcode * 37) + desiredMaxTickCount.hashCode;\n    return hashcode;\n  }\n}\n\n/// [TickProviderSpec] that sets up numeric ticks at the two end points of the\n/// axis range.\n@immutable\nclass NumericEndPointsTickProviderSpec implements NumericTickProviderSpec {\n  /// Creates a [TickProviderSpec] that dynamically chooses numeric ticks at the\n  /// two end points of the axis range\n  const NumericEndPointsTickProviderSpec();\n\n  @override\n  EndPointsTickProvider<num> createTickProvider(ChartContext context) {\n    return EndPointsTickProvider<num>();\n  }\n\n  @override\n  // ignore: hash_and_equals\n  bool operator ==(Object other) => other is NumericEndPointsTickProviderSpec;\n}\n\n/// [TickProviderSpec] that allows you to specific the ticks to be used.\n@immutable\nclass StaticNumericTickProviderSpec implements NumericTickProviderSpec {\n  final List<TickSpec<num>> tickSpecs;\n\n  const StaticNumericTickProviderSpec(this.tickSpecs);\n\n  @override\n  StaticTickProvider<num> createTickProvider(ChartContext context) =>\n      StaticTickProvider<num>(tickSpecs);\n\n  @override\n  bool operator ==(Object other) =>\n      identical(this, other) ||\n      (other is StaticNumericTickProviderSpec && tickSpecs == other.tickSpecs);\n\n  @override\n  int get hashCode => tickSpecs.hashCode;\n}\n\n@immutable\nclass BasicNumericTickFormatterSpec implements NumericTickFormatterSpec {\n  final MeasureFormatter? formatter;\n  final NumberFormat? numberFormat;\n\n  /// Simple [TickFormatterSpec] that delegates formatting to the given\n  /// [NumberFormat].\n  const BasicNumericTickFormatterSpec(this.formatter) : numberFormat = null;\n\n  const BasicNumericTickFormatterSpec.fromNumberFormat(this.numberFormat)\n      : formatter = null;\n\n  /// A formatter will be created with the number format if it is not null.\n  /// Otherwise, it will create one with the [MeasureFormatter] callback.\n  @override\n  NumericTickFormatter createTickFormatter(ChartContext context) {\n    return numberFormat != null\n        ? NumericTickFormatter.fromNumberFormat(numberFormat!)\n        : NumericTickFormatter(formatter: formatter);\n  }\n\n  @override\n  bool operator ==(Object other) {\n    return identical(this, other) ||\n        (other is BasicNumericTickFormatterSpec &&\n            formatter == other.formatter &&\n            numberFormat == other.numberFormat);\n  }\n\n  @override\n  int get hashCode {\n    var hashcode = formatter.hashCode;\n    hashcode = (hashcode * 37) * numberFormat.hashCode;\n    return hashcode;\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/cartesian/axis/spec/ordinal_axis_spec.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'package:charts_common/src/chart/cartesian/axis/scale.dart'\n    show RangeBandConfig;\nimport 'package:meta/meta.dart' show immutable;\n\nimport '../../../../common/graphics_factory.dart' show GraphicsFactory;\nimport '../../../common/chart_context.dart' show ChartContext;\nimport '../axis.dart' show Axis, OrdinalAxis, OrdinalViewport;\nimport '../ordinal_scale.dart' show OrdinalScale;\nimport '../ordinal_tick_provider.dart' show OrdinalTickProvider;\nimport '../range_tick_provider.dart' show RangeTickProvider;\nimport '../simple_ordinal_scale.dart' show SimpleOrdinalScale;\nimport '../static_tick_provider.dart' show StaticTickProvider;\nimport '../tick_formatter.dart' show OrdinalTickFormatter;\nimport 'axis_spec.dart'\n    show AxisSpec, TickProviderSpec, TickFormatterSpec, ScaleSpec, RenderSpec;\nimport 'tick_spec.dart' show TickSpec;\n\n/// [AxisSpec] specialized for ordinal/non-continuous axes typically for bars.\n@immutable\nclass OrdinalAxisSpec extends AxisSpec<String> {\n  /// Sets viewport for this Axis.\n  ///\n  /// If pan / zoom behaviors are set, this is the initial viewport.\n  final OrdinalViewport? viewport;\n\n  /// Creates a [AxisSpec] that specialized for ordinal domain charts.\n  ///\n  /// [renderSpec] spec used to configure how the ticks and labels\n  ///     actually render. Possible values are [GridlineRendererSpec],\n  ///     [SmallTickRendererSpec] & [NoneRenderSpec]. Make sure that the <D>\n  ///     given to the RenderSpec is of type [String] when using this spec.\n  /// [tickProviderSpec] spec used to configure what ticks are generated.\n  /// [tickFormatterSpec] spec used to configure how the tick labels are\n  ///     formatted.\n  /// [showAxisLine] override to force the axis to draw the axis line.\n  const OrdinalAxisSpec({\n    RenderSpec<String>? renderSpec,\n    OrdinalTickProviderSpec? tickProviderSpec,\n    OrdinalTickFormatterSpec? tickFormatterSpec,\n    bool? showAxisLine,\n    OrdinalScaleSpec? scaleSpec,\n    this.viewport,\n  }) : super(\n          renderSpec: renderSpec,\n          tickProviderSpec: tickProviderSpec,\n          tickFormatterSpec: tickFormatterSpec,\n          showAxisLine: showAxisLine,\n          scaleSpec: scaleSpec,\n        );\n\n  @override\n  void configure(Axis<String> axis, ChartContext context,\n      GraphicsFactory graphicsFactory) {\n    super.configure(axis, context, graphicsFactory);\n\n    if (axis is OrdinalAxis && viewport != null) {\n      axis.setScaleViewport(viewport!);\n    }\n  }\n\n  @override\n  OrdinalAxis createAxis() => OrdinalAxis();\n\n  @override\n  bool operator ==(Object other) {\n    return identical(this, other) ||\n        (other is OrdinalAxisSpec &&\n            viewport == other.viewport &&\n            super == other);\n  }\n\n  @override\n  int get hashCode {\n    var hashcode = super.hashCode;\n    hashcode = (hashcode * 37) + viewport.hashCode;\n    return hashcode;\n  }\n}\n\nabstract class OrdinalTickProviderSpec extends TickProviderSpec<String> {}\n\nabstract class OrdinalTickFormatterSpec extends TickFormatterSpec<String> {}\n\nabstract class OrdinalScaleSpec extends ScaleSpec<String> {}\n\n@immutable\nclass BasicOrdinalTickProviderSpec implements OrdinalTickProviderSpec {\n  const BasicOrdinalTickProviderSpec();\n\n  @override\n  OrdinalTickProvider createTickProvider(ChartContext context) =>\n      OrdinalTickProvider();\n\n  @override\n  bool operator ==(Object other) => other is BasicOrdinalTickProviderSpec;\n\n  @override\n  int get hashCode => 37;\n}\n\n/// [TickProviderSpec] that allows you to specify the ticks to be used.\n@immutable\nclass StaticOrdinalTickProviderSpec implements OrdinalTickProviderSpec {\n  final List<TickSpec<String>> tickSpecs;\n\n  const StaticOrdinalTickProviderSpec(this.tickSpecs);\n\n  @override\n  StaticTickProvider<String> createTickProvider(ChartContext context) =>\n      StaticTickProvider<String>(tickSpecs);\n\n  @override\n  bool operator ==(Object other) =>\n      identical(this, other) ||\n      (other is StaticOrdinalTickProviderSpec && tickSpecs == other.tickSpecs);\n\n  @override\n  int get hashCode => tickSpecs.hashCode;\n}\n\n/// [TickProviderSpec] that allows you to provide range ticks and normal ticks.\n@immutable\nclass RangeOrdinalTickProviderSpec implements OrdinalTickProviderSpec {\n  final List<TickSpec<String>> tickSpecs;\n  const RangeOrdinalTickProviderSpec(this.tickSpecs);\n\n  @override\n  RangeTickProvider<String> createTickProvider(ChartContext context) =>\n      RangeTickProvider<String>(tickSpecs);\n\n  @override\n  bool operator ==(Object other) =>\n      identical(this, other) ||\n      (other is RangeOrdinalTickProviderSpec && tickSpecs == other.tickSpecs);\n\n  @override\n  int get hashCode => tickSpecs.hashCode;\n}\n\n@immutable\nclass BasicOrdinalTickFormatterSpec implements OrdinalTickFormatterSpec {\n  const BasicOrdinalTickFormatterSpec();\n\n  @override\n  OrdinalTickFormatter createTickFormatter(ChartContext context) =>\n      OrdinalTickFormatter();\n\n  @override\n  bool operator ==(Object other) => other is BasicOrdinalTickFormatterSpec;\n\n  @override\n  int get hashCode => 37;\n}\n\n@immutable\nclass SimpleOrdinalScaleSpec implements OrdinalScaleSpec {\n  const SimpleOrdinalScaleSpec();\n\n  @override\n  OrdinalScale createScale() => SimpleOrdinalScale();\n\n  @override\n  bool operator ==(Object other) => other is SimpleOrdinalScaleSpec;\n\n  @override\n  int get hashCode => 37;\n}\n\n/// [OrdinalScaleSpec] which allows setting space between bars to be a fixed\n/// pixel size.\n@immutable\nclass FixedPixelSpaceOrdinalScaleSpec implements OrdinalScaleSpec {\n  final double pixelSpaceBetweenBars;\n\n  const FixedPixelSpaceOrdinalScaleSpec(this.pixelSpaceBetweenBars);\n\n  @override\n  OrdinalScale createScale() => SimpleOrdinalScale()\n    ..rangeBandConfig =\n        RangeBandConfig.fixedPixelSpaceBetweenStep(pixelSpaceBetweenBars);\n\n  @override\n  bool operator ==(Object other) => other is SimpleOrdinalScaleSpec;\n\n  @override\n  int get hashCode => 37;\n}\n\n/// [OrdinalScaleSpec] which allows setting bar width to be a fixed pixel size.\n@immutable\nclass FixedPixelOrdinalScaleSpec implements OrdinalScaleSpec {\n  final double pixels;\n\n  const FixedPixelOrdinalScaleSpec(this.pixels);\n\n  @override\n  OrdinalScale createScale() => SimpleOrdinalScale()\n    ..rangeBandConfig = RangeBandConfig.fixedPixel(pixels);\n\n  @override\n  bool operator ==(Object other) => other is SimpleOrdinalScaleSpec;\n\n  @override\n  int get hashCode => 37;\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/cartesian/axis/spec/percent_axis_spec.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'package:meta/meta.dart' show immutable;\nimport 'package:intl/intl.dart';\n\nimport '../numeric_extents.dart' show NumericExtents;\nimport 'axis_spec.dart' show AxisSpec, RenderSpec;\nimport 'numeric_axis_spec.dart'\n    show\n        BasicNumericTickFormatterSpec,\n        BasicNumericTickProviderSpec,\n        NumericAxisSpec,\n        NumericTickProviderSpec,\n        NumericTickFormatterSpec;\n\n/// Convenience [AxisSpec] specialized for numeric percentage axes.\n@immutable\nclass PercentAxisSpec extends NumericAxisSpec {\n  /// Creates a [NumericAxisSpec] that is specialized for percentage data.\n  PercentAxisSpec({\n    RenderSpec<num>? renderSpec,\n    NumericTickProviderSpec? tickProviderSpec,\n    NumericTickFormatterSpec? tickFormatterSpec,\n    bool? showAxisLine,\n    NumericExtents? viewport,\n  }) : super(\n            renderSpec: renderSpec,\n            tickProviderSpec: tickProviderSpec ??\n                const BasicNumericTickProviderSpec(dataIsInWholeNumbers: false),\n            tickFormatterSpec: tickFormatterSpec ??\n                BasicNumericTickFormatterSpec.fromNumberFormat(\n                    NumberFormat.percentPattern()),\n            showAxisLine: showAxisLine,\n            viewport: viewport ?? const NumericExtents(0.0, 1.0));\n\n  @override\n  bool operator ==(Object other) => other is PercentAxisSpec && super == other;\n\n  @override\n  int get hashCode {\n    var hashcode = super.hashCode;\n    hashcode = (hashcode * 37) + runtimeType.hashCode;\n    return hashcode;\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/cartesian/axis/spec/range_tick_spec.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'axis_spec.dart' show TextStyleSpec;\nimport 'tick_spec.dart' show TickSpec;\n\n/// Definition for a range tick.\n///\n/// Used to define a tick that is used by range tick provider.\nclass RangeTickSpec<D> extends TickSpec<D> {\n  final D rangeStartValue;\n  final D rangeEndValue;\n\n  /// Creates a range tick for [value].\n  /// A [label] optionally labels this tick. If not set, the tick formatter\n  /// formatter of the axis is used.\n  /// A [style] optionally sets the style for this tick. If not set, the style\n  /// of the axis is used.\n  /// A [rangeStartValue] represents value of this range tick's starting point.\n  /// A [rangeEndValue] represents the value of this range tick's ending point.\n  const RangeTickSpec(\n    D value, {\n    String? label,\n    TextStyleSpec? style,\n    required this.rangeStartValue,\n    required this.rangeEndValue,\n  }) : super(value, label: label, style: style);\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/cartesian/axis/spec/tick_spec.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'axis_spec.dart' show TextStyleSpec;\n\n/// Definition for a tick.\n///\n/// Used to define a tick that is used by static tick provider.\nclass TickSpec<D> {\n  final D value;\n  final String? label;\n  final TextStyleSpec? style;\n\n  /// [value] the value of this tick\n  /// [label] optional label for this tick. If not set, uses the tick formatter\n  /// of the axis.\n  /// [style] optional style for this tick. If not set, uses the style of the\n  /// axis.\n  const TickSpec(this.value, {this.label, this.style});\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/cartesian/axis/static_tick_provider.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport '../../../common/graphics_factory.dart' show GraphicsFactory;\nimport '../../common/chart_context.dart' show ChartContext;\nimport 'axis.dart' show AxisOrientation;\nimport 'draw_strategy/tick_draw_strategy.dart' show TickDrawStrategy;\nimport 'numeric_scale.dart' show NumericScale;\nimport 'scale.dart' show MutableScale;\nimport 'spec/tick_spec.dart' show TickSpec;\nimport 'tick.dart' show Tick;\nimport 'tick_formatter.dart' show TickFormatter;\nimport 'tick_provider.dart' show TickProvider, TickHint;\nimport 'time/date_time_scale.dart' show DateTimeScale;\n\n/// A strategy that uses the ticks provided and only assigns positioning.\n///\n/// The [TextStyle] is not overridden during [TickDrawStrategy.decorateTicks].\n/// If the [TickSpec] style is null, then the default [TextStyle] is used.\nclass StaticTickProvider<D> extends TickProvider<D> {\n  final List<TickSpec<D>> tickSpec;\n\n  StaticTickProvider(this.tickSpec);\n\n  @override\n  List<Tick<D>> getTicks({\n    required ChartContext? context,\n    required GraphicsFactory graphicsFactory,\n    required MutableScale<D> scale,\n    required TickFormatter<D> formatter,\n    required Map<D, String> formatterValueCache,\n    required TickDrawStrategy<D> tickDrawStrategy,\n    required AxisOrientation? orientation,\n    bool viewportExtensionEnabled = false,\n    TickHint<D>? tickHint,\n  }) {\n    final ticks = <Tick<D>>[];\n\n    var allTicksHaveLabels = true;\n\n    for (final spec in tickSpec) {\n      // When static ticks are being used with a numeric axis, extend the axis\n      // with the values specified.\n      if (scale is NumericScale || scale is DateTimeScale) {\n        scale.addDomain(spec.value);\n      }\n\n      // Save off whether all ticks have labels.\n      allTicksHaveLabels = allTicksHaveLabels && (spec.label != null);\n    }\n\n    // Use the formatter's label if the tick spec does not provide one.\n    late List<String> formattedValues;\n    if (!allTicksHaveLabels) {\n      formattedValues = formatter.format(\n          tickSpec.map((spec) => spec.value).toList(), formatterValueCache,\n          stepSize: scale.domainStepSize);\n    }\n\n    for (var i = 0; i < tickSpec.length; i++) {\n      final spec = tickSpec[i];\n      // We still check if the spec is within the viewport because we do not\n      // extend the axis for OrdinalScale.\n      if (scale.compareDomainValueToViewport(spec.value) == 0) {\n        final tick = Tick<D>(\n            value: spec.value,\n            textElement: graphicsFactory\n                .createTextElement(spec.label ?? formattedValues[i]),\n            locationPx: scale[spec.value]?.toDouble());\n        final style = spec.style;\n        if (style != null) {\n          tick.textElement!.textStyle = graphicsFactory.createTextPaint()\n            ..fontFamily = style.fontFamily\n            ..fontSize = style.fontSize\n            ..color = style.color\n            ..lineHeight = style.lineHeight;\n        }\n        ticks.add(tick);\n      }\n    }\n\n    // Allow draw strategy to decorate the ticks.\n    tickDrawStrategy.decorateTicks(ticks);\n\n    return ticks;\n  }\n\n  @override\n  bool operator ==(Object other) =>\n      other is StaticTickProvider && tickSpec == other.tickSpec;\n\n  @override\n  int get hashCode => tickSpec.hashCode;\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/cartesian/axis/tick.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport '../../../common/text_element.dart';\n\n/// A labeled point on an axis.\n///\n/// [D] is the type of the value this tick is associated with.\nclass Tick<D> {\n  /// The value that this tick represents\n  final D value;\n\n  /// [TextElement] for this tick.\n  TextElement? textElement;\n\n  /// Location on the axis where this tick is rendered (in canvas coordinates).\n  double? locationPx;\n\n  /// Offset of the label for this tick from its location.\n  ///\n  /// This is a vertical offset for ticks on a vertical axis, or horizontal\n  /// offset for ticks on a horizontal axis.\n  double? labelOffsetPx;\n\n  Tick(\n      {required this.value,\n      required this.textElement,\n      this.locationPx,\n      this.labelOffsetPx});\n\n  @override\n  String toString() => 'Tick(value: $value, locationPx: $locationPx, '\n      'labelOffsetPx: $labelOffsetPx)';\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/cartesian/axis/tick_formatter.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'package:intl/intl.dart';\nimport '../../common/datum_details.dart' show MeasureFormatter;\n\n// TODO: Break out into separate files.\n\n/// A strategy used for converting domain values of the ticks into Strings.\n///\n/// [D] is the domain type.\nabstract class TickFormatter<D> {\n  const TickFormatter();\n\n  /// Formats a list of tick values.\n  List<String> format(List<D> tickValues, Map<D, String> cache,\n      {num? stepSize});\n}\n\nabstract class SimpleTickFormatterBase<D> implements TickFormatter<D> {\n  const SimpleTickFormatterBase();\n\n  @override\n  List<String> format(List<D> tickValues, Map<D, String> cache,\n          {num? stepSize}) =>\n      tickValues.map((value) {\n        // Try to use the cached formats first.\n        var formattedString = cache[value];\n        if (formattedString == null) {\n          formattedString = formatValue(value);\n          cache[value] = formattedString;\n        }\n        return formattedString;\n      }).toList();\n\n  /// Formats a single tick value.\n  String formatValue(D value);\n}\n\n/// A strategy that converts tick labels using toString().\nclass OrdinalTickFormatter extends SimpleTickFormatterBase<String> {\n  const OrdinalTickFormatter();\n\n  @override\n  String formatValue(String value) => value;\n\n  @override\n  bool operator ==(Object other) => other is OrdinalTickFormatter;\n\n  @override\n  int get hashCode => 31;\n}\n\n/// A strategy for formatting the labels on numeric ticks using [NumberFormat].\n///\n/// The default format is [NumberFormat.decimalPattern].\nclass NumericTickFormatter extends SimpleTickFormatterBase<num> {\n  final MeasureFormatter formatter;\n\n  NumericTickFormatter._internal(this.formatter);\n\n  /// Construct a a new [NumericTickFormatter].\n  ///\n  /// [formatter] optionally specify a formatter to be used. Defaults to using\n  /// [NumberFormat.decimalPattern] if none is specified.\n  factory NumericTickFormatter({MeasureFormatter? formatter}) {\n    formatter ??= _getFormatter(NumberFormat.decimalPattern());\n    return NumericTickFormatter._internal(formatter);\n  }\n\n  /// Constructs a new [NumericTickFormatter] that formats using [numberFormat].\n  factory NumericTickFormatter.fromNumberFormat(NumberFormat numberFormat) {\n    return NumericTickFormatter._internal(_getFormatter(numberFormat));\n  }\n\n  /// Constructs a new formatter that uses [NumberFormat.compactCurrency].\n  factory NumericTickFormatter.compactSimpleCurrency() {\n    return NumericTickFormatter._internal(\n        _getFormatter(NumberFormat.compactCurrency()));\n  }\n\n  /// Returns a [MeasureFormatter] that calls format on [numberFormat].\n  static MeasureFormatter _getFormatter(NumberFormat numberFormat) {\n    return (num? value) => (value == null) ? '' : numberFormat.format(value);\n  }\n\n  @override\n  String formatValue(num value) => formatter(value);\n\n  @override\n  bool operator ==(Object other) =>\n      other is NumericTickFormatter && formatter == other.formatter;\n\n  @override\n  int get hashCode => formatter.hashCode;\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/cartesian/axis/tick_provider.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport '../../../common/graphics_factory.dart' show GraphicsFactory;\nimport '../../common/chart_context.dart' show ChartContext;\nimport 'axis.dart' show AxisOrientation;\nimport 'draw_strategy/tick_draw_strategy.dart' show TickDrawStrategy;\nimport 'scale.dart' show MutableScale;\nimport 'tick.dart' show Tick;\nimport 'tick_formatter.dart' show TickFormatter;\n\n/// A strategy for selecting values for axis ticks based on the domain values.\n///\n/// [D] is the domain type.\nabstract class TickProvider<D> {\n  /// Returns a list of ticks in value order that should be displayed.\n  ///\n  /// If no ticks are desired an empty list should be returned.\n  ///\n  /// [graphicsFactory] The graphics factory used for text measurement.\n  /// [scale] The scale of the data.\n  /// [formatter] The formatter to use for generating tick labels.\n  /// [orientation] Orientation of this axis ticks.\n  /// [tickDrawStrategy] Draw strategy for ticks.\n  /// [viewportExtensionEnabled] allow extending the viewport for 'niced' ticks.\n  /// [tickHint] tick values for provider to calculate a desired tick range.\n  List<Tick<D>> getTicks({\n    required ChartContext? context,\n    required GraphicsFactory graphicsFactory,\n    required covariant MutableScale<D> scale,\n    required TickFormatter<D> formatter,\n    required Map<D, String> formatterValueCache,\n    required TickDrawStrategy<D> tickDrawStrategy,\n    required AxisOrientation? orientation,\n    bool viewportExtensionEnabled = false,\n    TickHint<D>? tickHint,\n  });\n}\n\n/// A base tick provider.\nabstract class BaseTickProvider<D> implements TickProvider<D> {\n  const BaseTickProvider();\n\n  /// Create ticks from [domainValues].\n  List<Tick<D>> createTicks(\n    List<D> domainValues, {\n    required ChartContext? context,\n    required GraphicsFactory graphicsFactory,\n    required MutableScale<D> scale,\n    required TickFormatter<D> formatter,\n    required Map<D, String> formatterValueCache,\n    required TickDrawStrategy<D> tickDrawStrategy,\n    num? stepSize,\n  }) {\n    final ticks = <Tick<D>>[];\n    final labels =\n        formatter.format(domainValues, formatterValueCache, stepSize: stepSize);\n\n    for (var i = 0; i < domainValues.length; i++) {\n      final value = domainValues[i];\n      final tick = Tick(\n          value: value,\n          textElement: graphicsFactory.createTextElement(labels[i]),\n          locationPx: scale[value]?.toDouble());\n\n      ticks.add(tick);\n    }\n\n    // Allow draw strategy to decorate the ticks.\n    tickDrawStrategy.decorateTicks(ticks);\n\n    return ticks;\n  }\n}\n\n/// A hint for the tick provider to determine step size and tick count.\nclass TickHint<D> {\n  /// The starting hint tick value.\n  final D start;\n\n  /// The ending hint tick value.\n  final D end;\n\n  /// Number of ticks.\n  final int tickCount;\n\n  TickHint(this.start, this.end, {required this.tickCount});\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/cartesian/axis/time/auto_adjusting_date_time_tick_provider.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport '../../../../common/date_time_factory.dart' show DateTimeFactory;\nimport '../../../../common/graphics_factory.dart' show GraphicsFactory;\nimport '../../../common/chart_context.dart' show ChartContext;\nimport '../axis.dart' show AxisOrientation;\nimport '../draw_strategy/tick_draw_strategy.dart' show TickDrawStrategy;\nimport '../tick.dart' show Tick;\nimport '../tick_formatter.dart' show TickFormatter;\nimport '../tick_provider.dart' show TickProvider, TickHint;\nimport 'date_time_scale.dart' show DateTimeScale;\nimport 'day_time_stepper.dart' show DayTimeStepper;\nimport 'hour_time_stepper.dart' show HourTimeStepper;\nimport 'minute_time_stepper.dart' show MinuteTimeStepper;\nimport 'month_time_stepper.dart' show MonthTimeStepper;\nimport 'time_range_tick_provider.dart' show TimeRangeTickProvider;\nimport 'time_range_tick_provider_impl.dart' show TimeRangeTickProviderImpl;\nimport 'year_time_stepper.dart' show YearTimeStepper;\n\n/// Tick provider for date and time.\n///\n/// When determining the ticks for a given domain, the provider will use choose\n/// one of the internal tick providers appropriate to the size of the data's\n/// domain range.  It does this in an attempt to ensure there are at least 3\n/// ticks, before jumping to the next more fine grain provider.  The 3 tick\n/// minimum is not a hard rule as some of the ticks might be eliminated because\n/// of collisions, but the data was within the targeted range.\n///\n/// Once a tick provider is chosen the selection of ticks is done by the child\n/// tick provider.\nclass AutoAdjustingDateTimeTickProvider implements TickProvider<DateTime> {\n  /// List of tick providers to be selected from.\n  final List<TimeRangeTickProvider> _potentialTickProviders;\n\n  AutoAdjustingDateTimeTickProvider._internal(\n      List<TimeRangeTickProvider> tickProviders)\n      : assert(tickProviders.isNotEmpty),\n        _potentialTickProviders = tickProviders;\n\n  /// Creates a default [AutoAdjustingDateTimeTickProvider] for day and time.\n  factory AutoAdjustingDateTimeTickProvider.createDefault(\n      DateTimeFactory dateTimeFactory) {\n    return AutoAdjustingDateTimeTickProvider._internal([\n      createYearTickProvider(dateTimeFactory),\n      createMonthTickProvider(dateTimeFactory),\n      createDayTickProvider(dateTimeFactory),\n      createHourTickProvider(dateTimeFactory),\n      createMinuteTickProvider(dateTimeFactory)\n    ]);\n  }\n\n  /// Creates a default [AutoAdjustingDateTimeTickProvider] for day only.\n  factory AutoAdjustingDateTimeTickProvider.createWithoutTime(\n      DateTimeFactory dateTimeFactory) {\n    return AutoAdjustingDateTimeTickProvider._internal([\n      createYearTickProvider(dateTimeFactory),\n      createMonthTickProvider(dateTimeFactory),\n      createDayTickProvider(dateTimeFactory)\n    ]);\n  }\n\n  /// Creates [AutoAdjustingDateTimeTickProvider] with custom tick providers.\n  ///\n  /// [potentialTickProviders] must have at least one [TimeRangeTickProvider]\n  /// and this list of tick providers are used in the order they are provided.\n  factory AutoAdjustingDateTimeTickProvider.createWith(\n      List<TimeRangeTickProvider> potentialTickProviders) {\n    if (potentialTickProviders == null || potentialTickProviders.isEmpty) {\n      throw ArgumentError('At least one TimeRangeTickProvider is required');\n    }\n\n    return AutoAdjustingDateTimeTickProvider._internal(potentialTickProviders);\n  }\n\n  /// Generates a list of ticks for the given data which should not collide\n  /// unless the range is not large enough.\n  @override\n  List<Tick<DateTime>> getTicks({\n    required ChartContext? context,\n    required GraphicsFactory graphicsFactory,\n    required DateTimeScale scale,\n    required TickFormatter<DateTime> formatter,\n    required Map<DateTime, String> formatterValueCache,\n    required TickDrawStrategy<DateTime> tickDrawStrategy,\n    required AxisOrientation? orientation,\n    bool viewportExtensionEnabled = false,\n    TickHint<DateTime>? tickHint,\n  }) {\n    List<TimeRangeTickProvider> tickProviders;\n\n    /// If tick hint is provided, use the closest tick provider, otherwise\n    /// look through the tick providers for one that provides sufficient ticks\n    /// for the viewport.\n    if (tickHint != null) {\n      tickProviders = [_getClosestTickProvider(tickHint)];\n    } else {\n      tickProviders = _potentialTickProviders;\n    }\n\n    final lastTickProvider = tickProviders.last;\n\n    final viewport = scale.viewportDomain;\n    for (final tickProvider in tickProviders) {\n      final isLastProvider = tickProvider == lastTickProvider;\n      if (isLastProvider ||\n          tickProvider.providesSufficientTicksForRange(viewport)) {\n        return tickProvider.getTicks(\n          context: context,\n          graphicsFactory: graphicsFactory,\n          scale: scale,\n          formatter: formatter,\n          formatterValueCache: formatterValueCache,\n          tickDrawStrategy: tickDrawStrategy,\n          orientation: orientation,\n        );\n      }\n    }\n\n    return <Tick<DateTime>>[];\n  }\n\n  /// Find the closest tick provider based on the tick hint.\n  TimeRangeTickProvider _getClosestTickProvider(TickHint<DateTime> tickHint) {\n    final stepSize = ((tickHint.end.difference(tickHint.start).inMilliseconds) /\n            (tickHint.tickCount - 1))\n        .round();\n\n    int? minDifference;\n    late TimeRangeTickProvider closestTickProvider;\n\n    assert(_potentialTickProviders.isNotEmpty);\n    for (final tickProvider in _potentialTickProviders) {\n      final difference =\n          (stepSize - tickProvider.getClosestStepSize(stepSize)).abs();\n      if (minDifference == null || minDifference > difference) {\n        minDifference = difference;\n        closestTickProvider = tickProvider;\n      }\n    }\n    assert(minDifference != null);\n    return closestTickProvider;\n  }\n\n  static TimeRangeTickProvider createYearTickProvider(\n          DateTimeFactory dateTimeFactory) =>\n      TimeRangeTickProviderImpl(YearTimeStepper(dateTimeFactory));\n\n  static TimeRangeTickProvider createMonthTickProvider(\n          DateTimeFactory dateTimeFactory) =>\n      TimeRangeTickProviderImpl(MonthTimeStepper(dateTimeFactory));\n\n  static TimeRangeTickProvider createDayTickProvider(\n          DateTimeFactory dateTimeFactory) =>\n      TimeRangeTickProviderImpl(DayTimeStepper(dateTimeFactory));\n\n  static TimeRangeTickProvider createHourTickProvider(\n          DateTimeFactory dateTimeFactory) =>\n      TimeRangeTickProviderImpl(HourTimeStepper(dateTimeFactory));\n\n  static TimeRangeTickProvider createMinuteTickProvider(\n          DateTimeFactory dateTimeFactory) =>\n      TimeRangeTickProviderImpl(MinuteTimeStepper(dateTimeFactory));\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/cartesian/axis/time/base_time_stepper.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport '../../../../common/date_time_factory.dart';\nimport 'date_time_extents.dart' show DateTimeExtents;\nimport 'time_stepper.dart'\n    show TimeStepper, TimeStepIteratorFactory, TimeStepIterator;\n\n/// A base stepper for operating with DateTimeFactory and time range steps.\nabstract class BaseTimeStepper implements TimeStepper {\n  /// The factory to generate a DateTime object.\n  ///\n  /// This is needed because Dart's DateTime does not handle time zone.\n  /// There is a time zone aware library that we could use that implements the\n  /// DateTime interface.\n  final DateTimeFactory dateTimeFactory;\n\n  _TimeStepIteratorFactoryImpl? _stepsIterable;\n\n  BaseTimeStepper(this.dateTimeFactory) {\n    // Must have at least one increment option.\n    assert(allowedTickIncrements.isNotEmpty);\n  }\n\n  /// Get the step time before or on the given [time] from [tickIncrement].\n  DateTime getStepTimeBeforeInclusive(DateTime time, int tickIncrement);\n\n  /// Get the next step time after [time] from [tickIncrement].\n  DateTime getNextStepTime(DateTime time, int tickIncrement);\n\n  @override\n  int getStepCountBetween(DateTimeExtents timeExtent, int tickIncrement) {\n    checkTickIncrement(tickIncrement);\n    final min = timeExtent.start;\n    final max = timeExtent.end;\n    var time = getStepTimeAfterInclusive(min, tickIncrement);\n\n    var cnt = 0;\n    while (time.compareTo(max) <= 0) {\n      cnt++;\n      time = getNextStepTime(time, tickIncrement);\n    }\n    return cnt;\n  }\n\n  @override\n  TimeStepIteratorFactory getSteps(DateTimeExtents timeExtent) {\n    // Keep the steps iterable unless time extent changes, so the same iterator\n    // can be used and reset for different increments.\n    if (_stepsIterable == null || _stepsIterable!.timeExtent != timeExtent) {\n      _stepsIterable = _TimeStepIteratorFactoryImpl(timeExtent, this);\n    }\n    return _stepsIterable!;\n  }\n\n  @override\n  DateTimeExtents updateBoundingSteps(DateTimeExtents timeExtent) {\n    final stepBefore = getStepTimeBeforeInclusive(timeExtent.start, 1);\n    final stepAfter = getStepTimeAfterInclusive(timeExtent.end, 1);\n\n    return DateTimeExtents(start: stepBefore, end: stepAfter);\n  }\n\n  DateTime getStepTimeAfterInclusive(DateTime time, int tickIncrement) {\n    final boundedStart = getStepTimeBeforeInclusive(time, tickIncrement);\n    if (boundedStart.isAtSameMomentAs(time)) {\n      return boundedStart;\n    }\n    return getNextStepTime(boundedStart, tickIncrement);\n  }\n}\n\nclass _TimeStepIteratorImpl implements TimeStepIterator {\n  final DateTime extentStartTime;\n  final DateTime extentEndTime;\n  final BaseTimeStepper stepper;\n  DateTime? _current;\n  int _tickIncrement = 1;\n\n  _TimeStepIteratorImpl(\n      this.extentStartTime, this.extentEndTime, this.stepper) {\n    reset(_tickIncrement);\n  }\n\n  @override\n  bool moveNext() {\n    if (_current == null) {\n      _current =\n          stepper.getStepTimeAfterInclusive(extentStartTime, _tickIncrement);\n    } else {\n      _current = stepper.getNextStepTime(_current!, _tickIncrement);\n    }\n\n    return _current!.compareTo(extentEndTime) <= 0;\n  }\n\n  @override\n  DateTime get current => _current!;\n\n  @override\n  TimeStepIterator reset(int tickIncrement) {\n    checkTickIncrement(tickIncrement);\n    _tickIncrement = tickIncrement;\n    _current = null;\n    return this;\n  }\n}\n\nclass _TimeStepIteratorFactoryImpl extends TimeStepIteratorFactory {\n  final DateTimeExtents timeExtent;\n  final _TimeStepIteratorImpl _timeStepIterator;\n\n  _TimeStepIteratorFactoryImpl._internal(\n      _TimeStepIteratorImpl timeStepIterator, this.timeExtent)\n      : _timeStepIterator = timeStepIterator;\n\n  factory _TimeStepIteratorFactoryImpl(\n      DateTimeExtents timeExtent, BaseTimeStepper stepper) {\n    final startTime = timeExtent.start;\n    final endTime = timeExtent.end;\n    return _TimeStepIteratorFactoryImpl._internal(\n        _TimeStepIteratorImpl(startTime, endTime, stepper), timeExtent);\n  }\n\n  @override\n  TimeStepIterator get iterator => _timeStepIterator;\n}\n\nvoid checkTickIncrement(int tickIncrement) {\n  /// tickIncrement must be greater than 0\n  assert(tickIncrement > 0);\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/cartesian/axis/time/date_time_axis.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport '../../../../common/date_time_factory.dart' show DateTimeFactory;\nimport '../axis.dart' show Axis;\nimport '../tick_formatter.dart' show TickFormatter;\nimport '../tick_provider.dart' show TickProvider;\nimport 'auto_adjusting_date_time_tick_provider.dart'\n    show AutoAdjustingDateTimeTickProvider;\nimport 'date_time_extents.dart' show DateTimeExtents;\nimport 'date_time_scale.dart' show DateTimeScale;\nimport 'date_time_tick_formatter.dart' show DateTimeTickFormatter;\n\nclass DateTimeAxis extends Axis<DateTime> {\n  DateTimeAxis(DateTimeFactory dateTimeFactory,\n      {TickProvider<DateTime>? tickProvider,\n      TickFormatter<DateTime>? tickFormatter})\n      : super(\n          tickProvider: tickProvider ??\n              AutoAdjustingDateTimeTickProvider.createDefault(dateTimeFactory),\n          tickFormatter:\n              tickFormatter ?? DateTimeTickFormatter(dateTimeFactory),\n          scale: DateTimeScale(dateTimeFactory),\n        );\n\n  void setScaleViewport(DateTimeExtents viewport) {\n    autoViewport = false;\n    (mutableScale as DateTimeScale).viewportDomain = viewport;\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/cartesian/axis/time/date_time_extents.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport '../scale.dart' show Extents;\n\nclass DateTimeExtents extends Extents<DateTime> {\n  final DateTime start;\n  final DateTime end;\n\n  DateTimeExtents({required this.start, required this.end});\n\n  @override\n  bool operator ==(Object other) {\n    return other is DateTimeExtents && start == other.start && end == other.end;\n  }\n\n  @override\n  int get hashCode => start.hashCode + (end.hashCode * 37);\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/cartesian/axis/time/date_time_scale.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport '../../../../common/date_time_factory.dart' show DateTimeFactory;\nimport '../linear/linear_scale.dart' show LinearScale;\nimport '../numeric_extents.dart' show NumericExtents;\nimport '../scale.dart'\n    show MutableScale, StepSizeConfig, RangeBandConfig, ScaleOutputExtent;\nimport 'date_time_extents.dart' show DateTimeExtents;\n\n/// [DateTimeScale] is a wrapper for [LinearScale].\n/// [DateTime] values are converted to millisecondsSinceEpoch and passed to the\n/// [LinearScale].\nclass DateTimeScale extends MutableScale<DateTime> {\n  final DateTimeFactory dateTimeFactory;\n  final LinearScale _linearScale;\n\n  DateTimeScale(this.dateTimeFactory) : _linearScale = LinearScale();\n\n  DateTimeScale._copy(DateTimeScale other)\n      : dateTimeFactory = other.dateTimeFactory,\n        _linearScale = other._linearScale.copy();\n\n  @override\n  num operator [](DateTime domainValue) =>\n      _linearScale[domainValue.millisecondsSinceEpoch];\n\n  @override\n  DateTime reverse(double pixelLocation) =>\n      dateTimeFactory.createDateTimeFromMilliSecondsSinceEpoch(\n          _linearScale.reverse(pixelLocation).round());\n\n  @override\n  void resetDomain() {\n    _linearScale.resetDomain();\n  }\n\n  @override\n  set stepSizeConfig(StepSizeConfig config) {\n    _linearScale.stepSizeConfig = config;\n  }\n\n  @override\n  StepSizeConfig get stepSizeConfig => _linearScale.stepSizeConfig;\n\n  @override\n  set rangeBandConfig(RangeBandConfig barGroupWidthConfig) {\n    _linearScale.rangeBandConfig = barGroupWidthConfig;\n  }\n\n  @override\n  void setViewportSettings(double viewportScale, double viewportTranslatePx) {\n    _linearScale.setViewportSettings(viewportScale, viewportTranslatePx);\n  }\n\n  @override\n  set range(ScaleOutputExtent? extent) {\n    _linearScale.range = extent;\n  }\n\n  @override\n  void addDomain(DateTime domainValue) {\n    _linearScale.addDomain(domainValue.millisecondsSinceEpoch);\n  }\n\n  @override\n  void resetViewportSettings() {\n    _linearScale.resetViewportSettings();\n  }\n\n  DateTimeExtents get viewportDomain {\n    final extents = _linearScale.viewportDomain;\n    return DateTimeExtents(\n        start: dateTimeFactory\n            .createDateTimeFromMilliSecondsSinceEpoch(extents.min.toInt()),\n        end: dateTimeFactory\n            .createDateTimeFromMilliSecondsSinceEpoch(extents.max.toInt()));\n  }\n\n  set viewportDomain(DateTimeExtents extents) {\n    _linearScale.viewportDomain = NumericExtents(\n        extents.start.millisecondsSinceEpoch,\n        extents.end.millisecondsSinceEpoch);\n  }\n\n  @override\n  DateTimeScale copy() => DateTimeScale._copy(this);\n\n  @override\n  double get viewportTranslatePx => _linearScale.viewportTranslatePx;\n\n  @override\n  double get viewportScalingFactor => _linearScale.viewportScalingFactor;\n\n  @override\n  bool isRangeValueWithinViewport(double rangeValue) =>\n      _linearScale.isRangeValueWithinViewport(rangeValue);\n\n  @override\n  int compareDomainValueToViewport(DateTime domainValue) => _linearScale\n      .compareDomainValueToViewport(domainValue.millisecondsSinceEpoch);\n\n  @override\n  double get rangeBand => _linearScale.rangeBand;\n\n  @override\n  double get stepSize => _linearScale.stepSize;\n\n  @override\n  double get domainStepSize => _linearScale.domainStepSize;\n\n  @override\n  RangeBandConfig get rangeBandConfig => _linearScale.rangeBandConfig;\n\n  @override\n  int get rangeWidth => _linearScale.rangeWidth;\n\n  @override\n  ScaleOutputExtent? get range => _linearScale.range;\n\n  @override\n  bool canTranslate(DateTime domainValue) =>\n      _linearScale.canTranslate(domainValue.millisecondsSinceEpoch);\n\n  NumericExtents get dataExtent => _linearScale.dataExtent;\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/cartesian/axis/time/date_time_tick_formatter.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport '../../../../common/date_time_factory.dart' show DateTimeFactory;\nimport '../tick_formatter.dart' show TickFormatter;\nimport 'hour_tick_formatter.dart' show HourTickFormatter;\nimport 'time_tick_formatter.dart' show TimeTickFormatter;\nimport 'time_tick_formatter_impl.dart'\n    show CalendarField, TimeTickFormatterImpl;\n\n/// A [TickFormatter] that formats date/time values based on minimum difference\n/// between subsequent ticks.\n///\n/// This formatter assumes that the Tick values passed in are sorted in\n/// increasing order.\n///\n/// This class is setup with a list of formatters that format the input ticks at\n/// a given time resolution. The time resolution which will accurately display\n/// the difference between 2 subsequent ticks is picked. Each time resolution\n/// can be setup with a [TimeTickFormatter], which is used to format ticks as\n/// regular or transition ticks based on whether the tick has crossed the time\n/// boundary defined in the [TimeTickFormatter].\nclass DateTimeTickFormatter implements TickFormatter<DateTime> {\n  static const int SECOND = 1000;\n  static const int MINUTE = 60 * SECOND;\n  static const int HOUR = 60 * MINUTE;\n  static const int DAY = 24 * HOUR;\n\n  /// Used for the case when there is only one formatter.\n  static const int ANY = -1;\n\n  final Map<int, TimeTickFormatter> _timeFormatters;\n\n  /// Creates a [DateTimeTickFormatter] that works well with time tick provider\n  /// classes.\n  ///\n  /// The default formatter makes assumptions on border cases that time tick\n  /// providers will still provide ticks that make sense. Example: Tick provider\n  /// does not provide ticks with 23 hour intervals.  For custom tick providers\n  /// where these assumptions are not correct, please create a custom\n  /// [TickFormatter].\n  factory DateTimeTickFormatter(DateTimeFactory dateTimeFactory,\n      {Map<int, TimeTickFormatter>? overrides}) {\n    final map = <int, TimeTickFormatter>{\n      MINUTE: TimeTickFormatterImpl(\n          dateTimeFactory: dateTimeFactory,\n          simpleFormat: 'mm',\n          transitionFormat: 'h mm',\n          transitionField: CalendarField.hourOfDay),\n      HOUR: HourTickFormatter(\n          dateTimeFactory: dateTimeFactory,\n          simpleFormat: 'h',\n          transitionFormat: 'MMM d ha',\n          noonFormat: 'ha'),\n      23 * HOUR: TimeTickFormatterImpl(\n          dateTimeFactory: dateTimeFactory,\n          simpleFormat: 'd',\n          transitionFormat: 'MMM d',\n          transitionField: CalendarField.month),\n      28 * DAY: TimeTickFormatterImpl(\n          dateTimeFactory: dateTimeFactory,\n          simpleFormat: 'MMM',\n          transitionFormat: 'MMM yyyy',\n          transitionField: CalendarField.year),\n      364 * DAY: TimeTickFormatterImpl(\n          dateTimeFactory: dateTimeFactory,\n          simpleFormat: 'yyyy',\n          transitionFormat: 'yyyy',\n          transitionField: CalendarField.year),\n    };\n\n    // Allow the user to override some of the defaults.\n    if (overrides != null) {\n      map.addAll(overrides);\n    }\n\n    return DateTimeTickFormatter._internal(map);\n  }\n\n  /// Creates a [DateTimeTickFormatter] without the time component.\n  factory DateTimeTickFormatter.withoutTime(DateTimeFactory dateTimeFactory) {\n    return DateTimeTickFormatter._internal({\n      23 * HOUR: TimeTickFormatterImpl(\n          dateTimeFactory: dateTimeFactory,\n          simpleFormat: 'd',\n          transitionFormat: 'MMM d',\n          transitionField: CalendarField.month),\n      28 * DAY: TimeTickFormatterImpl(\n          dateTimeFactory: dateTimeFactory,\n          simpleFormat: 'MMM',\n          transitionFormat: 'MMM yyyy',\n          transitionField: CalendarField.year),\n      365 * DAY: TimeTickFormatterImpl(\n          dateTimeFactory: dateTimeFactory,\n          simpleFormat: 'yyyy',\n          transitionFormat: 'yyyy',\n          transitionField: CalendarField.year),\n    });\n  }\n\n  /// Creates a [DateTimeTickFormatter] that formats all ticks the same.\n  ///\n  /// Only use this formatter for data with fixed intervals, otherwise use the\n  /// default, or build from scratch.\n  ///\n  /// [formatter] The format for all ticks.\n  factory DateTimeTickFormatter.uniform(TimeTickFormatter formatter) {\n    return DateTimeTickFormatter._internal({ANY: formatter});\n  }\n\n  /// Creates a [DateTimeTickFormatter] that formats ticks with [formatters].\n  ///\n  /// The formatters are expected to be provided with keys in increasing order.\n  factory DateTimeTickFormatter.withFormatters(\n      Map<int, TimeTickFormatter> formatters) {\n    // Formatters must be non empty.\n    if (formatters == null || formatters.isEmpty) {\n      throw ArgumentError('At least one TimeTickFormatter is required.');\n    }\n\n    return DateTimeTickFormatter._internal(formatters);\n  }\n\n  DateTimeTickFormatter._internal(this._timeFormatters) {\n    // If there is only one formatter, just use this one and skip this check.\n    if (_timeFormatters.length == 1) {\n      return;\n    }\n    _checkPositiveAndSorted(_timeFormatters.keys);\n  }\n\n  @override\n  List<String> format(List<DateTime> tickValues, Map<DateTime, String> cache,\n      {num? stepSize}) {\n    final tickLabels = <String>[];\n    if (tickValues.isEmpty) {\n      return tickLabels;\n    }\n\n    // Find the formatter that is the largest interval that has enough\n    // resolution to describe the difference between ticks. If no such formatter\n    // exists pick the highest res one.\n    var formatter = _timeFormatters[_timeFormatters.keys.first]!;\n    var formatterFound = false;\n    if (_timeFormatters.keys.first == ANY) {\n      formatterFound = true;\n    } else {\n      final minTimeBetweenTicks = stepSize?.toInt() ?? 0;\n\n      // TODO: Skip the formatter if the formatter's step size is\n      // smaller than the minimum step size of the data.\n\n      var keys = _timeFormatters.keys.iterator;\n      while (keys.moveNext() && !formatterFound) {\n        if (keys.current > minTimeBetweenTicks) {\n          formatterFound = true;\n        } else {\n          formatter = _timeFormatters[keys.current]!;\n        }\n      }\n    }\n\n    // Format the ticks.\n    final tickValuesIt = tickValues.iterator;\n\n    var tickValue = (tickValuesIt..moveNext()).current;\n    var prevTickValue = tickValue;\n    tickLabels.add(formatter.formatFirstTick(tickValue));\n\n    while (tickValuesIt.moveNext()) {\n      tickValue = tickValuesIt.current;\n      if (formatter.isTransition(tickValue, prevTickValue)) {\n        tickLabels.add(formatter.formatTransitionTick(tickValue));\n      } else {\n        tickLabels.add(formatter.formatSimpleTick(tickValue));\n      }\n      prevTickValue = tickValue;\n    }\n\n    return tickLabels;\n  }\n\n  static void _checkPositiveAndSorted(Iterable<int> values) {\n    final valuesIterator = values.iterator;\n    var prev = (valuesIterator..moveNext()).current;\n    var isSorted = true;\n\n    // Only need to check the first value, because the values after are expected\n    // to be greater.\n    if (prev <= 0) {\n      throw ArgumentError('Formatter keys must be positive');\n    }\n\n    while (valuesIterator.moveNext() && isSorted) {\n      isSorted = prev < valuesIterator.current;\n      prev = valuesIterator.current;\n    }\n\n    if (!isSorted) {\n      throw ArgumentError(\n          'Formatters must be sorted with keys in increasing order');\n    }\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/cartesian/axis/time/day_time_stepper.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport '../../../../common/date_time_factory.dart' show DateTimeFactory;\nimport 'base_time_stepper.dart' show BaseTimeStepper;\n\n/// Day stepper.\nclass DayTimeStepper extends BaseTimeStepper {\n  // TODO: Remove the 14 day increment if we add week stepper.\n  static const _defaultIncrements = [1, 2, 3, 7, 14];\n  static const _hoursInDay = 24;\n\n  final List<int> _allowedTickIncrements;\n\n  DayTimeStepper._internal(\n      DateTimeFactory dateTimeFactory, List<int> increments)\n      : _allowedTickIncrements = increments,\n        super(dateTimeFactory);\n\n  factory DayTimeStepper(DateTimeFactory dateTimeFactory,\n      {List<int>? allowedTickIncrements}) {\n    // Set the default increments if null.\n    allowedTickIncrements ??= _defaultIncrements;\n\n    assert(allowedTickIncrements.every((increment) => increment > 0));\n\n    return DayTimeStepper._internal(dateTimeFactory, allowedTickIncrements);\n  }\n\n  @override\n  int get typicalStepSizeMs => _hoursInDay * 3600 * 1000;\n\n  @override\n  List<int> get allowedTickIncrements => _allowedTickIncrements;\n\n  /// Get the step time before or on the given [time] from [tickIncrement].\n  ///\n  /// Increments are based off the beginning of the month.\n  /// Ex. 5 day increments in a month is 1,6,11,16,21,26,31\n  /// Ex. Time is Aug 20, increment is 1 day. Returns Aug 20.\n  /// Ex. Time is Aug 20, increment is 2 days. Returns Aug 19 because 2 day\n  /// increments in a month is 1,3,5,7,9,11,13,15,17,19,21....\n  @override\n  DateTime getStepTimeBeforeInclusive(DateTime time, int tickIncrement) {\n    final dayRemainder = (time.day - 1) % tickIncrement;\n    // Subtract an extra hour in case stepping through a daylight saving change.\n    final dayBefore = dayRemainder > 0\n        ? time.subtract(Duration(hours: (_hoursInDay * dayRemainder) - 1))\n        : time;\n    // Explicitly leaving off hours and beyond to truncate to start of day.\n    final stepBefore = dateTimeFactory.createDateTime(\n        dayBefore.year, dayBefore.month, dayBefore.day);\n\n    return stepBefore;\n  }\n\n  @override\n  DateTime getNextStepTime(DateTime time, int tickIncrement) {\n    // Add an extra hour in case stepping through a daylight saving change.\n    final stepAfter =\n        time.add(Duration(hours: (_hoursInDay * tickIncrement) + 1));\n    // Explicitly leaving off hours and beyond to truncate to start of day.\n    return dateTimeFactory.createDateTime(\n        stepAfter.year, stepAfter.month, stepAfter.day);\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/cartesian/axis/time/hour_tick_formatter.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'package:intl/intl.dart' show DateFormat;\nimport '../../../../common/date_time_factory.dart';\nimport 'time_tick_formatter_impl.dart'\n    show CalendarField, TimeTickFormatterImpl;\n\n/// Hour specific tick formatter which will format noon differently.\nclass HourTickFormatter extends TimeTickFormatterImpl {\n  late final DateFormat _noonFormat;\n\n  HourTickFormatter(\n      {required DateTimeFactory dateTimeFactory,\n      required String? simpleFormat,\n      required String? transitionFormat,\n      required String? noonFormat})\n      : super(\n            dateTimeFactory: dateTimeFactory,\n            simpleFormat: simpleFormat,\n            transitionFormat: transitionFormat,\n            transitionField: CalendarField.date) {\n    _noonFormat = dateTimeFactory.createDateFormat(noonFormat);\n  }\n\n  @override\n  String formatSimpleTick(DateTime date) {\n    return (date.hour == 12)\n        ? _noonFormat.format(date)\n        : super.formatSimpleTick(date);\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/cartesian/axis/time/hour_time_stepper.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport '../../../../common/date_time_factory.dart' show DateTimeFactory;\nimport 'base_time_stepper.dart' show BaseTimeStepper;\n\n/// Hour stepper.\nclass HourTimeStepper extends BaseTimeStepper {\n  static const _defaultIncrements = [1, 2, 3, 4, 6, 12, 24];\n  static const _hoursInDay = 24;\n  static const _millisecondsInHour = 3600 * 1000;\n\n  final List<int> _allowedTickIncrements;\n\n  HourTimeStepper._internal(\n      DateTimeFactory dateTimeFactory, List<int> increments)\n      : _allowedTickIncrements = increments,\n        super(dateTimeFactory);\n\n  factory HourTimeStepper(DateTimeFactory dateTimeFactory,\n      {List<int>? allowedTickIncrements}) {\n    // Set the default increments if null.\n    allowedTickIncrements ??= _defaultIncrements;\n\n    assert(allowedTickIncrements\n        .every((increment) => increment >= 1 && increment <= 24));\n\n    return HourTimeStepper._internal(dateTimeFactory, allowedTickIncrements);\n  }\n\n  @override\n  int get typicalStepSizeMs => _millisecondsInHour;\n\n  @override\n  List<int> get allowedTickIncrements => _allowedTickIncrements;\n\n  /// Get the step time before or on the given [time] from [tickIncrement].\n  ///\n  /// Guarantee a step at the start of the next day.\n  /// Ex. Time is Aug 20 10 AM, increment is 1 hour. Returns 10 AM.\n  /// Ex. Time is Aug 20 6 AM, increment is 4 hours. Returns 4 AM.\n  @override\n  DateTime getStepTimeBeforeInclusive(DateTime time, int tickIncrement) {\n    final nextDay = dateTimeFactory\n        .createDateTime(time.year, time.month, time.day)\n        .add(Duration(hours: _hoursInDay + 1));\n    final nextDayStart = dateTimeFactory.createDateTime(\n        nextDay.year, nextDay.month, nextDay.day);\n\n    final hoursToNextDay =\n        ((nextDayStart.millisecondsSinceEpoch - time.millisecondsSinceEpoch) /\n                _millisecondsInHour)\n            .ceil();\n\n    final hoursRemainder = hoursToNextDay % tickIncrement;\n    final rewindHours =\n        hoursRemainder == 0 ? 0 : tickIncrement - hoursRemainder;\n    final stepBefore = dateTimeFactory.createDateTime(\n        time.year, time.month, time.day, time.hour - rewindHours);\n\n    return stepBefore;\n  }\n\n  /// Get next step time.\n  ///\n  /// [time] is expected to be a [DateTime] with the hour at start of the hour.\n  @override\n  DateTime getNextStepTime(DateTime time, int tickIncrement) {\n    return time.add(Duration(hours: tickIncrement));\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/cartesian/axis/time/minute_time_stepper.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport '../../../../common/date_time_factory.dart' show DateTimeFactory;\nimport 'base_time_stepper.dart';\n\n/// Minute stepper where ticks generated aligns with the hour.\nclass MinuteTimeStepper extends BaseTimeStepper {\n  static const _defaultIncrements = [5, 10, 15, 20, 30];\n  static const _millisecondsInMinute = 60 * 1000;\n\n  final List<int> _allowedTickIncrements;\n\n  MinuteTimeStepper._internal(\n      DateTimeFactory dateTimeFactory, List<int> increments)\n      : _allowedTickIncrements = increments,\n        super(dateTimeFactory);\n\n  factory MinuteTimeStepper(DateTimeFactory dateTimeFactory,\n      {List<int>? allowedTickIncrements}) {\n    // Set the default increments if null.\n    allowedTickIncrements ??= _defaultIncrements;\n\n    assert(allowedTickIncrements\n        .every((increment) => increment >= 1 && increment <= 60));\n\n    return MinuteTimeStepper._internal(dateTimeFactory, allowedTickIncrements);\n  }\n\n  @override\n  int get typicalStepSizeMs => _millisecondsInMinute;\n\n  @override\n  List<int> get allowedTickIncrements => _allowedTickIncrements;\n\n  /// Picks a tick start time that guarantees the start of the hour is included.\n  ///\n  /// Ex. Time is 3:46, increments is 5 minutes, step before is 3:45, because\n  /// we can guarantee a step at 4:00.\n  @override\n  DateTime getStepTimeBeforeInclusive(DateTime time, int tickIncrement) {\n    final nextHourStart = time.millisecondsSinceEpoch +\n        (60 - time.minute) * _millisecondsInMinute;\n\n    final minutesToNextHour =\n        ((nextHourStart - time.millisecondsSinceEpoch) / _millisecondsInMinute)\n            .ceil();\n\n    final minRemainder = minutesToNextHour % tickIncrement;\n    final rewindMinutes = minRemainder == 0 ? 0 : tickIncrement - minRemainder;\n\n    final stepBefore = dateTimeFactory.createDateTimeFromMilliSecondsSinceEpoch(\n        time.millisecondsSinceEpoch - rewindMinutes * _millisecondsInMinute);\n\n    return stepBefore;\n  }\n\n  @override\n  DateTime getNextStepTime(DateTime time, int tickIncrement) {\n    return time.add(Duration(minutes: tickIncrement));\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/cartesian/axis/time/month_time_stepper.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport '../../../../common/date_time_factory.dart' show DateTimeFactory;\nimport 'base_time_stepper.dart' show BaseTimeStepper;\n\n/// Month stepper.\nclass MonthTimeStepper extends BaseTimeStepper {\n  static const _defaultIncrements = [1, 2, 3, 4, 6, 12];\n\n  final List<int> _allowedTickIncrements;\n\n  MonthTimeStepper._internal(\n      DateTimeFactory dateTimeFactory, List<int> increments)\n      : _allowedTickIncrements = increments,\n        super(dateTimeFactory);\n\n  factory MonthTimeStepper(DateTimeFactory dateTimeFactory,\n      {List<int>? allowedTickIncrements}) {\n    // Set the default increments if null.\n    allowedTickIncrements ??= _defaultIncrements;\n\n    assert(allowedTickIncrements.every((increment) => increment > 0));\n\n    return MonthTimeStepper._internal(dateTimeFactory, allowedTickIncrements);\n  }\n\n  @override\n  int get typicalStepSizeMs => 30 * 24 * 3600 * 1000;\n\n  @override\n  List<int> get allowedTickIncrements => _allowedTickIncrements;\n\n  /// Guarantee a step ending in the last month of the year.\n  ///\n  /// If date is 2017 Oct and increments is 6, the step before is 2017 June.\n  @override\n  DateTime getStepTimeBeforeInclusive(DateTime time, int tickIncrement) {\n    final monthRemainder = time.month % tickIncrement;\n    var newMonth = (time.month - monthRemainder) % DateTime.monthsPerYear;\n    // Handles the last month of the year (December) edge case.\n    // Ex. When month is December and increment is 1\n    if (time.month == DateTime.monthsPerYear && newMonth == 0) {\n      newMonth = DateTime.monthsPerYear;\n    }\n    final newYear =\n        time.year - (monthRemainder / DateTime.monthsPerYear).floor();\n\n    return dateTimeFactory.createDateTime(newYear, newMonth);\n  }\n\n  @override\n  DateTime getNextStepTime(DateTime time, int tickIncrement) {\n    final incrementedMonth = time.month + tickIncrement;\n    final newMonth = incrementedMonth % DateTime.monthsPerYear;\n    final newYear =\n        time.year + (incrementedMonth / DateTime.monthsPerYear).floor();\n\n    return dateTimeFactory.createDateTime(newYear, newMonth);\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/cartesian/axis/time/simple_time_tick_formatter.dart",
    "content": "// Copyright 2019 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'time_tick_formatter.dart' show TimeTickFormatter;\n\ntypedef DateTimeFormatterFunction = String Function(DateTime datetime);\n\n/// Formatter that formats all ticks using a single [DateTimeFormatterFunction].\nclass SimpleTimeTickFormatter implements TimeTickFormatter {\n  DateTimeFormatterFunction formatter;\n\n  SimpleTimeTickFormatter({required this.formatter});\n\n  @override\n  String formatFirstTick(DateTime date) => formatter(date);\n\n  @override\n  String formatSimpleTick(DateTime date) => formatter(date);\n\n  @override\n  String formatTransitionTick(DateTime date) => formatter(date);\n\n  // Transition fields don't matter here.\n  @override\n  bool isTransition(DateTime tickValue, DateTime prevTickValue) => false;\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/cartesian/axis/time/time_range_tick_provider.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport '../tick_provider.dart' show BaseTickProvider;\nimport '../time/date_time_extents.dart' show DateTimeExtents;\n\n/// Provides ticks for a particular time unit.\n///\n/// Used by [AutoAdjustingDateTimeTickProvider].\nabstract class TimeRangeTickProvider extends BaseTickProvider<DateTime> {\n  /// Returns if this tick provider will produce a sufficient number of ticks\n  /// for [domainExtents].\n  bool providesSufficientTicksForRange(DateTimeExtents domainExtents);\n\n  /// Find the closet step size, from provided step size, in milliseconds.\n  int getClosestStepSize(int stepSize);\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/cartesian/axis/time/time_range_tick_provider_impl.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport '../../../../common/graphics_factory.dart' show GraphicsFactory;\nimport '../../../common/chart_context.dart' show ChartContext;\nimport '../axis.dart' show AxisOrientation;\nimport '../draw_strategy/tick_draw_strategy.dart' show TickDrawStrategy;\nimport '../tick.dart' show Tick;\nimport '../tick_formatter.dart' show TickFormatter;\nimport '../tick_provider.dart' show TickHint;\nimport 'date_time_extents.dart' show DateTimeExtents;\nimport 'date_time_scale.dart' show DateTimeScale;\nimport 'time_range_tick_provider.dart' show TimeRangeTickProvider;\nimport 'time_stepper.dart' show TimeStepper;\n\n// Contains all the common code for the time range tick providers.\nclass TimeRangeTickProviderImpl extends TimeRangeTickProvider {\n  final int requiredMinimumTicks;\n  final TimeStepper timeStepper;\n\n  TimeRangeTickProviderImpl(this.timeStepper, {this.requiredMinimumTicks = 3});\n\n  @override\n  bool providesSufficientTicksForRange(DateTimeExtents domainExtents) {\n    final cnt = timeStepper.getStepCountBetween(domainExtents, 1);\n    return cnt >= requiredMinimumTicks;\n  }\n\n  /// Find the closet step size, from provided step size, in milliseconds.\n  @override\n  int getClosestStepSize(int stepSize) {\n    return timeStepper.typicalStepSizeMs *\n        _getClosestIncrementFromStepSize(stepSize);\n  }\n\n  // Find the increment that is closest to the step size.\n  int _getClosestIncrementFromStepSize(int stepSize) {\n    int? minDifference;\n    late int closestIncrement;\n\n    assert(timeStepper.allowedTickIncrements.isNotEmpty);\n    for (final increment in timeStepper.allowedTickIncrements) {\n      final difference =\n          (stepSize - (timeStepper.typicalStepSizeMs * increment)).abs();\n      if (minDifference == null || minDifference > difference) {\n        minDifference = difference;\n        closestIncrement = increment;\n      }\n    }\n\n    return closestIncrement;\n  }\n\n  @override\n  List<Tick<DateTime>> getTicks({\n    required ChartContext? context,\n    required GraphicsFactory graphicsFactory,\n    required DateTimeScale scale,\n    required TickFormatter<DateTime> formatter,\n    required Map<DateTime, String> formatterValueCache,\n    required TickDrawStrategy<DateTime> tickDrawStrategy,\n    required AxisOrientation? orientation,\n    bool viewportExtensionEnabled = false,\n    TickHint<DateTime>? tickHint,\n  }) {\n    late List<Tick<DateTime>> currentTicks;\n    final tickValues = <DateTime>[];\n    final timeStepIt = timeStepper.getSteps(scale.viewportDomain).iterator;\n\n    // Try different tickIncrements and choose the first that has no collisions.\n    // If none exist use the last one which should have the fewest ticks and\n    // hope that the renderer will resolve collisions.\n    //\n    // If a tick hint was provided, use the tick hint to search for the closest\n    // increment and use that.\n    List<int> allowedTickIncrements;\n    if (tickHint != null) {\n      final stepSize = tickHint.end.difference(tickHint.start).inMilliseconds;\n      allowedTickIncrements = [_getClosestIncrementFromStepSize(stepSize)];\n    } else {\n      allowedTickIncrements = timeStepper.allowedTickIncrements;\n    }\n    assert(allowedTickIncrements.isNotEmpty);\n\n    for (final tickIncrement in allowedTickIncrements) {\n      // Create tick values with a specified increment.\n      tickValues.clear();\n      timeStepIt.reset(tickIncrement);\n      while (timeStepIt.moveNext()) {\n        tickValues.add(timeStepIt.current);\n      }\n\n      // Create ticks\n      currentTicks = createTicks(tickValues,\n          context: context,\n          graphicsFactory: graphicsFactory,\n          scale: scale,\n          formatter: formatter,\n          formatterValueCache: formatterValueCache,\n          tickDrawStrategy: tickDrawStrategy,\n          stepSize: timeStepper.typicalStepSizeMs * tickIncrement);\n\n      // Request collision check from draw strategy.\n      final collisionReport =\n          tickDrawStrategy.collides(currentTicks, orientation);\n\n      if (!collisionReport.ticksCollide) {\n        // Return the first non colliding ticks.\n        return currentTicks;\n      }\n    }\n\n    // If all ticks collide, return the last generated ticks.\n    return currentTicks;\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/cartesian/axis/time/time_stepper.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'date_time_extents.dart' show DateTimeExtents;\n\n/// Represents the step/tick information for the given time range.\nabstract class TimeStepper {\n  /// Get new bounding extents to the ticks that would contain the given\n  /// timeExtents.\n  DateTimeExtents updateBoundingSteps(DateTimeExtents timeExtents);\n\n  /// Returns the number steps/ticks are between the given extents inclusive.\n  ///\n  /// Does not extend the extents to the bounding ticks.\n  int getStepCountBetween(DateTimeExtents timeExtents, int tickIncrement);\n\n  /// Generates an Iterable for iterating over the time steps bounded by the\n  /// given timeExtents. The desired tickIncrement can be set on the returned\n  /// [TimeStepIteratorFactory].\n  TimeStepIteratorFactory getSteps(DateTimeExtents timeExtents);\n\n  /// Returns the typical stepSize for this stepper assuming increment by 1.\n  int get typicalStepSizeMs;\n\n  /// An ordered list of step increments that makes sense given the step.\n  ///\n  /// Should never be empty.\n  ///\n  /// Example: hours may increment by 1, 2, 3, 4, 6, 12.  It doesn't make sense\n  /// to increment hours by 7.\n  List<int> get allowedTickIncrements;\n}\n\n/// Iterator with a reset function that can be used multiple times to avoid\n/// object instantiation during the Android layout/draw phases.\nabstract class TimeStepIterator extends Iterator<DateTime> {\n  /// Reset the iterator and set the tickIncrement to the specified value.\n  ///\n  /// This method is provided so that the same iterator instance can be used for\n  /// different tick increments, avoiding object allocation during Android\n  /// layout/draw phases.\n  TimeStepIterator reset(int tickIncrement);\n}\n\n/// Factory that creates TimeStepIterator with the set tickIncrement value.\nabstract class TimeStepIteratorFactory extends Iterable<DateTime> {\n  /// Get iterator and optionally set the tickIncrement.\n  @override\n  TimeStepIterator get iterator;\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/cartesian/axis/time/time_tick_formatter.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n/// Formatter of [DateTime] ticks\nabstract class TimeTickFormatter {\n  /// Format for tick that is the first in a set of ticks.\n  String formatFirstTick(DateTime date);\n\n  /// Format for a 'simple' tick.\n  ///\n  /// Ex. Not a first tick or transition tick.\n  String formatSimpleTick(DateTime date);\n\n  /// Format for a transitional tick.\n  String formatTransitionTick(DateTime date);\n\n  /// Returns true if tick is a transitional tick.\n  bool isTransition(DateTime tickValue, DateTime prevTickValue);\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/cartesian/axis/time/time_tick_formatter_impl.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'package:intl/intl.dart' show DateFormat;\nimport '../../../../common/date_time_factory.dart' show DateTimeFactory;\nimport 'time_tick_formatter.dart' show TimeTickFormatter;\n\n/// Formatter that can format simple and transition time ticks differently.\nclass TimeTickFormatterImpl implements TimeTickFormatter {\n  final DateFormat _simpleFormat;\n  final DateFormat _transitionFormat;\n  final CalendarField? transitionField;\n\n  /// Create time tick formatter.\n  ///\n  /// [dateTimeFactory] factory to use to generate the [DateFormat].\n  /// [simpleFormat] format to use for most ticks.\n  /// [transitionFormat] format to use when the time unit transitions.\n  /// For example showing the month with the date for Jan 1.\n  /// [transitionField] the calendar field that indicates transition.\n  TimeTickFormatterImpl({\n    required DateTimeFactory dateTimeFactory,\n    required String? simpleFormat,\n    required String? transitionFormat,\n    this.transitionField,\n  })  : _simpleFormat = dateTimeFactory.createDateFormat(simpleFormat),\n        _transitionFormat = dateTimeFactory.createDateFormat(transitionFormat);\n\n  @override\n  String formatFirstTick(DateTime date) => _transitionFormat.format(date);\n\n  @override\n  String formatSimpleTick(DateTime date) => _simpleFormat.format(date);\n\n  @override\n  String formatTransitionTick(DateTime date) => _transitionFormat.format(date);\n\n  @override\n  bool isTransition(DateTime tickValue, DateTime prevTickValue) {\n    // Transition is always false if no transition field is specified.\n    final transitionField = this.transitionField;\n    if (transitionField == null) {\n      return false;\n    }\n    final prevTransitionFieldValue =\n        getCalendarField(prevTickValue, transitionField);\n    final transitionFieldValue = getCalendarField(tickValue, transitionField);\n    return prevTransitionFieldValue != transitionFieldValue;\n  }\n\n  /// Gets the calendar field for [dateTime].\n  int getCalendarField(DateTime dateTime, CalendarField field) {\n    switch (field) {\n      case CalendarField.year:\n        return dateTime.year;\n      case CalendarField.month:\n        return dateTime.month;\n      case CalendarField.date:\n        return dateTime.day;\n      case CalendarField.hourOfDay:\n        return dateTime.hour;\n      case CalendarField.minute:\n        return dateTime.minute;\n      case CalendarField.second:\n        return dateTime.second;\n    }\n  }\n}\n\nenum CalendarField {\n  year,\n  month,\n  date,\n  hourOfDay,\n  minute,\n  second,\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/cartesian/axis/time/year_time_stepper.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport '../../../../common/date_time_factory.dart' show DateTimeFactory;\nimport 'base_time_stepper.dart' show BaseTimeStepper;\n\n/// Year stepper.\nclass YearTimeStepper extends BaseTimeStepper {\n  static const _defaultIncrements = [1, 2, 5, 10, 50, 100, 500, 1000];\n\n  final List<int> _allowedTickIncrements;\n\n  YearTimeStepper._internal(\n      DateTimeFactory dateTimeFactory, List<int> increments)\n      : _allowedTickIncrements = increments,\n        super(dateTimeFactory);\n\n  factory YearTimeStepper(DateTimeFactory dateTimeFactory,\n      {List<int>? allowedTickIncrements}) {\n    // Set the default increments if null.\n    allowedTickIncrements ??= _defaultIncrements;\n\n    assert(allowedTickIncrements.every((increment) => increment > 0));\n\n    return YearTimeStepper._internal(dateTimeFactory, allowedTickIncrements);\n  }\n\n  @override\n  int get typicalStepSizeMs => 365 * 24 * 3600 * 1000;\n\n  @override\n  List<int> get allowedTickIncrements => _allowedTickIncrements;\n\n  /// Guarantees the increment is a factor of the tick value.\n  ///\n  /// Example: 2017, tick increment of 10, step before is 2010.\n  @override\n  DateTime getStepTimeBeforeInclusive(DateTime time, int tickIncrement) {\n    final yearRemainder = time.year % tickIncrement;\n    return dateTimeFactory.createDateTime(time.year - yearRemainder);\n  }\n\n  @override\n  DateTime getNextStepTime(DateTime time, int tickIncrement) {\n    return dateTimeFactory.createDateTime(time.year + tickIncrement);\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/cartesian/cartesian_chart.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:collection' show LinkedHashMap;\n\nimport 'package:meta/meta.dart' show protected;\n\nimport '../../common/graphics_factory.dart' show GraphicsFactory;\nimport '../../data/series.dart' show Series;\nimport '../bar/bar_renderer.dart' show BarRenderer;\nimport '../common/base_chart.dart' show BaseChart;\nimport '../common/chart_context.dart' show ChartContext;\nimport '../common/datum_details.dart' show DatumDetails;\nimport '../common/processed_series.dart' show MutableSeries;\nimport '../common/selection_model/selection_model.dart' show SelectionModelType;\nimport '../common/series_renderer.dart' show SeriesRenderer, rendererIdKey;\nimport '../layout/layout_config.dart' show LayoutConfig, MarginSpec;\nimport '../layout/layout_view.dart' show LayoutViewPaintOrder;\nimport 'axis/axis.dart'\n    show\n        Axis,\n        AxisOrientation,\n        OrdinalAxis,\n        NumericAxis,\n        domainAxisKey,\n        measureAxisIdKey,\n        measureAxisKey;\nimport 'axis/draw_strategy/gridline_draw_strategy.dart'\n    show GridlineRendererSpec;\nimport 'axis/draw_strategy/none_draw_strategy.dart' show NoneDrawStrategy;\nimport 'axis/draw_strategy/small_tick_draw_strategy.dart'\n    show SmallTickRendererSpec;\nimport 'axis/spec/axis_spec.dart' show AxisSpec;\nimport 'axis/spec/numeric_axis_spec.dart' show NumericAxisSpec;\n\nclass NumericCartesianChart extends CartesianChart<num> {\n  NumericCartesianChart(\n      {bool? vertical,\n      LayoutConfig? layoutConfig,\n      NumericAxis? primaryMeasureAxis,\n      NumericAxis? secondaryMeasureAxis,\n      LinkedHashMap<String, NumericAxis>? disjointMeasureAxes})\n      : super(\n            vertical: vertical,\n            layoutConfig: layoutConfig,\n            domainAxis: NumericAxis(),\n            primaryMeasureAxis: primaryMeasureAxis,\n            secondaryMeasureAxis: secondaryMeasureAxis,\n            disjointMeasureAxes: disjointMeasureAxes);\n\n  @protected\n  @override\n  void initDomainAxis() {\n    _domainAxis!.tickDrawStrategy = SmallTickRendererSpec<num>()\n        .createDrawStrategy(context, graphicsFactory!);\n  }\n}\n\nclass OrdinalCartesianChart extends CartesianChart<String> {\n  OrdinalCartesianChart(\n      {bool? vertical,\n      LayoutConfig? layoutConfig,\n      NumericAxis? primaryMeasureAxis,\n      NumericAxis? secondaryMeasureAxis,\n      LinkedHashMap<String, NumericAxis>? disjointMeasureAxes})\n      : super(\n            vertical: vertical,\n            layoutConfig: layoutConfig,\n            domainAxis: OrdinalAxis(),\n            primaryMeasureAxis: primaryMeasureAxis,\n            secondaryMeasureAxis: secondaryMeasureAxis,\n            disjointMeasureAxes: disjointMeasureAxes);\n\n  @protected\n  @override\n  void initDomainAxis() {\n    _domainAxis!.tickDrawStrategy = SmallTickRendererSpec<String>()\n        .createDrawStrategy(context, graphicsFactory!);\n  }\n}\n\nabstract class CartesianChart<D> extends BaseChart<D> {\n  static final _defaultLayoutConfig = LayoutConfig(\n    topSpec: MarginSpec.fromPixel(minPixel: 20),\n    bottomSpec: MarginSpec.fromPixel(minPixel: 20),\n    leftSpec: MarginSpec.fromPixel(minPixel: 20),\n    rightSpec: MarginSpec.fromPixel(minPixel: 20),\n  );\n\n  bool vertical;\n\n  /// The current domain axis for this chart.\n  Axis<D>? _domainAxis;\n\n  /// Temporarily stores the new domain axis that is passed in the constructor\n  /// and the new domain axis created when [domainAxisSpec] is set to a new\n  /// spec.\n  ///\n  /// This step is necessary because the axis cannot be fully configured until\n  /// [context] is available. [configurationChanged] is called after [context]\n  /// is available and [_newDomainAxis] will be set to [_domainAxis] and then\n  /// reset back to null.\n  Axis<D>? _newDomainAxis;\n\n  /// The current domain axis spec that was used to configure [_domainAxis].\n  ///\n  /// This is kept to check if the axis spec has changed when [domainAxisSpec]\n  /// is set.\n  AxisSpec<D>? _domainAxisSpec;\n\n  /// Temporarily stores the new domain axis spec that is passed in when\n  /// [domainAxisSpec] is set and is different from [_domainAxisSpec]. This spec\n  /// is then applied to the new domain axis when [configurationChanged] is\n  /// called.\n  AxisSpec<D>? _newDomainAxisSpec;\n\n  NumericAxisSpec? _primaryMeasureAxisSpec;\n\n  NumericAxisSpec? _newPrimaryMeasureAxisSpec;\n\n  NumericAxis _primaryMeasureAxis;\n\n  NumericAxisSpec? _secondaryMeasureAxisSpec;\n\n  NumericAxisSpec? _newSecondaryMeasureAxisSpec;\n\n  NumericAxis _secondaryMeasureAxis;\n\n  LinkedHashMap<String, NumericAxisSpec>? _disjointMeasureAxesSpec;\n\n  LinkedHashMap<String, NumericAxisSpec>? _newDisjointMeasureAxesSpec;\n\n  LinkedHashMap<String, NumericAxis> _disjointMeasureAxes;\n\n  /// If set to true, the vertical axis will render the opposite of the default\n  /// direction.\n  bool flipVerticalAxisOutput = false;\n\n  bool _usePrimaryMeasureAxis = false;\n  bool _useSecondaryMeasureAxis = false;\n\n  CartesianChart(\n      {bool? vertical,\n      LayoutConfig? layoutConfig,\n      Axis<D>? domainAxis,\n      NumericAxis? primaryMeasureAxis,\n      NumericAxis? secondaryMeasureAxis,\n      LinkedHashMap<String, NumericAxis>? disjointMeasureAxes})\n      : vertical = vertical ?? true,\n        // [domainAxis] will be set to the new axis in [configurationChanged].\n        _newDomainAxis = domainAxis,\n        _primaryMeasureAxis = primaryMeasureAxis ?? NumericAxis(),\n        _secondaryMeasureAxis = secondaryMeasureAxis ?? NumericAxis(),\n        _disjointMeasureAxes =\n            // ignore: prefer_collection_literals\n            disjointMeasureAxes ?? LinkedHashMap<String, NumericAxis>(),\n        super(layoutConfig: layoutConfig ?? _defaultLayoutConfig);\n\n  @override\n  void init(ChartContext context, GraphicsFactory graphicsFactory) {\n    super.init(context, graphicsFactory);\n\n    _primaryMeasureAxis.context = context;\n    _primaryMeasureAxis.tickDrawStrategy = GridlineRendererSpec<num>()\n        .createDrawStrategy(context, graphicsFactory);\n\n    _secondaryMeasureAxis.context = context;\n    _secondaryMeasureAxis.tickDrawStrategy = GridlineRendererSpec<num>()\n        .createDrawStrategy(context, graphicsFactory);\n\n    _disjointMeasureAxes.forEach((String axisId, NumericAxis axis) {\n      axis.context = context;\n      axis.tickDrawStrategy = NoneDrawStrategy<num>(context, graphicsFactory);\n    });\n  }\n\n  @override\n  void updateConfig(LayoutConfig? layoutConfig) {\n    super.updateConfig(layoutConfig ?? _defaultLayoutConfig);\n  }\n\n  Axis<D>? get domainAxis => _domainAxis;\n\n  /// Allows the chart to configure the domain axis when it is created.\n  @protected\n  void initDomainAxis();\n\n  /// Create a new domain axis and save the new spec to be applied during\n  /// [configurationChanged].\n  set domainAxisSpec(AxisSpec<D> axisSpec) {\n    if (_domainAxisSpec != axisSpec) {\n      _newDomainAxis = createDomainAxisFromSpec(axisSpec);\n      _newDomainAxisSpec = axisSpec;\n    }\n  }\n\n  /// Creates the domain axis from a provided axis spec.\n  @protected\n  Axis<D>? createDomainAxisFromSpec(AxisSpec<D> axisSpec) {\n    return axisSpec.createAxis();\n  }\n\n  @override\n  void configurationChanged() {\n    if (_newDomainAxis != null) {\n      markChartDirty();\n      if (_domainAxis != null) {\n        removeView(_domainAxis!);\n      }\n\n      _domainAxis = _newDomainAxis;\n      _domainAxis!\n        ..context = context\n        ..layoutPaintOrder = LayoutViewPaintOrder.domainAxis;\n\n      initDomainAxis();\n\n      addView(_domainAxis!);\n\n      _newDomainAxis = null;\n    }\n\n    if (_newDomainAxisSpec != null) {\n      markChartDirty();\n      _domainAxisSpec = _newDomainAxisSpec;\n      _newDomainAxisSpec!.configure(_domainAxis!, context, graphicsFactory!);\n      _newDomainAxisSpec = null;\n    }\n\n    if (_primaryMeasureAxisSpec != _newPrimaryMeasureAxisSpec) {\n      markChartDirty();\n      _primaryMeasureAxisSpec = _newPrimaryMeasureAxisSpec;\n      removeView(_primaryMeasureAxis);\n\n      _primaryMeasureAxis =\n          _primaryMeasureAxisSpec?.createAxis() ?? NumericAxis();\n\n      _primaryMeasureAxis.tickDrawStrategy = GridlineRendererSpec<num>()\n          .createDrawStrategy(context, graphicsFactory!);\n\n      _primaryMeasureAxisSpec?.configure(\n          _primaryMeasureAxis, context, graphicsFactory!);\n      addView(_primaryMeasureAxis);\n    }\n\n    if (_secondaryMeasureAxisSpec != _newSecondaryMeasureAxisSpec) {\n      markChartDirty();\n      _secondaryMeasureAxisSpec = _newSecondaryMeasureAxisSpec;\n      removeView(_secondaryMeasureAxis);\n\n      _secondaryMeasureAxis =\n          _secondaryMeasureAxisSpec?.createAxis() ?? NumericAxis();\n\n      _secondaryMeasureAxis.tickDrawStrategy = GridlineRendererSpec<num>()\n          .createDrawStrategy(context, graphicsFactory!);\n\n      _secondaryMeasureAxisSpec?.configure(\n          _secondaryMeasureAxis, context, graphicsFactory!);\n      addView(_secondaryMeasureAxis);\n    }\n\n    if (_disjointMeasureAxesSpec != _newDisjointMeasureAxesSpec) {\n      markChartDirty();\n      _disjointMeasureAxesSpec = _newDisjointMeasureAxesSpec;\n      _disjointMeasureAxes.forEach((String axisId, NumericAxis axis) {\n        removeView(axis);\n      });\n\n      // ignore: prefer_collection_literals, https://github.com/dart-lang/linter/issues/1649\n      _disjointMeasureAxes = LinkedHashMap<String, NumericAxis>();\n      _disjointMeasureAxesSpec?.forEach((axisId, axisSpec) {\n        _disjointMeasureAxes[axisId] = axisSpec.createAxis();\n        _disjointMeasureAxes[axisId]!.tickDrawStrategy =\n            NoneDrawStrategy<num>(context, graphicsFactory!);\n        axisSpec.configure(\n            _disjointMeasureAxes[axisId]!, context, graphicsFactory!);\n        addView(_disjointMeasureAxes[axisId]!);\n      });\n    }\n  }\n\n  /// Gets the measure axis matching the provided id.\n  ///\n  /// If none is provided, this returns the primary measure axis.\n  NumericAxis getMeasureAxis({String? axisId}) {\n    NumericAxis? axis;\n    if (axisId == Axis.secondaryMeasureAxisId) {\n      axis = _secondaryMeasureAxis;\n    } else if (axisId == Axis.primaryMeasureAxisId) {\n      axis = _primaryMeasureAxis;\n    } else if (axisId != null && _disjointMeasureAxes[axisId] != null) {\n      axis = _disjointMeasureAxes[axisId];\n    }\n\n    // If no valid axisId was provided, fall back to primary axis.\n    axis ??= _primaryMeasureAxis;\n\n    return axis;\n  }\n\n  /// Sets the primary measure axis for the chart, rendered on the start side of\n  /// the domain axis.\n  set primaryMeasureAxisSpec(NumericAxisSpec? axisSpec) {\n    _newPrimaryMeasureAxisSpec = axisSpec;\n\n    // Must set the spec to the current axis instance in the case of\n    // errant reads that expect the spec to be changed.\n    axisSpec?.configure(_primaryMeasureAxis, context, graphicsFactory!);\n  }\n\n  /// Sets the secondary measure axis for the chart, rendered on the end side of\n  /// the domain axis.\n  set secondaryMeasureAxisSpec(NumericAxisSpec? axisSpec) {\n    _newSecondaryMeasureAxisSpec = axisSpec;\n\n    // Must set the spec to the current axis instance in the case of\n    // errant reads that expect the spec to be changed.\n    axisSpec?.configure(_secondaryMeasureAxis, context, graphicsFactory!);\n  }\n\n  /// Sets a map of disjoint measure axes for the chart.\n  ///\n  /// Disjoint measure axes can be used to scale a sub-set of series on the\n  /// chart independently from the primary and secondary axes. The general use\n  /// case for this type of chart is to show differences in the trends of the\n  /// data, without comparing their absolute values.\n  ///\n  /// Disjoint axes will not render any tick or gridline elements. With\n  /// independent scales, there would be a lot of collision in labels were they\n  /// to do so.\n  ///\n  /// If any series is rendered with a disjoint axis, it is highly recommended\n  /// to render all series with disjoint axes. Otherwise, the chart may be\n  /// visually misleading.\n  ///\n  /// A [LinkedHashMap] is used to ensure consistent ordering when painting the\n  /// axes.\n  set disjointMeasureAxisSpecs(\n      LinkedHashMap<String, NumericAxisSpec>? axisSpecs) {\n    _newDisjointMeasureAxesSpec = axisSpecs;\n\n    // Must set the spec to the current axis instance in the case of\n    // errant reads that expect the spec to be changed.\n    axisSpecs?.forEach((axisId, axisSpec) {\n      if (_disjointMeasureAxes.containsKey(axisId)) {\n        axisSpec.configure(\n            _disjointMeasureAxes[axisId]!, context, graphicsFactory!);\n      }\n    });\n  }\n\n  @override\n  MutableSeries<D> makeSeries(Series<dynamic, D> series) {\n    final s = super.makeSeries(series);\n\n    s.measureOffsetFn ??= (_) => 0;\n\n    // Setup the Axes\n    s.setAttr(domainAxisKey, domainAxis);\n    s.setAttr(measureAxisKey,\n        getMeasureAxis(axisId: series.getAttribute(measureAxisIdKey)));\n\n    return s;\n  }\n\n  @override\n  SeriesRenderer<D> makeDefaultRenderer() {\n    return BarRenderer()..rendererId = SeriesRenderer.defaultRendererId;\n  }\n\n  @override\n  Map<String, List<MutableSeries<D>>> preprocessSeries(\n      List<MutableSeries<D>> seriesList) {\n    var rendererToSeriesList = super.preprocessSeries(seriesList);\n    _useSecondaryMeasureAxis = false;\n    // Check if primary or secondary measure axis is being used.\n    for (final series in seriesList) {\n      final measureAxisId = series.getAttr(measureAxisIdKey);\n      _usePrimaryMeasureAxis = _usePrimaryMeasureAxis ||\n          (measureAxisId == null || measureAxisId == Axis.primaryMeasureAxisId);\n      _useSecondaryMeasureAxis = _useSecondaryMeasureAxis ||\n          (measureAxisId == Axis.secondaryMeasureAxisId);\n    }\n\n    // Add or remove the primary axis view.\n    if (_usePrimaryMeasureAxis) {\n      addView(_primaryMeasureAxis);\n    } else {\n      removeView(_primaryMeasureAxis);\n    }\n\n    // Add or remove the secondary axis view.\n    if (_useSecondaryMeasureAxis) {\n      addView(_secondaryMeasureAxis);\n    } else {\n      removeView(_secondaryMeasureAxis);\n    }\n\n    // Add all disjoint axis views so that their range will be configured.\n    _disjointMeasureAxes.forEach((String axisId, NumericAxis axis) {\n      addView(axis);\n    });\n\n    final domainAxis = this.domainAxis!;\n\n    // Reset stale values from previous draw cycles.\n    domainAxis.resetDomains();\n    _primaryMeasureAxis.resetDomains();\n    _secondaryMeasureAxis.resetDomains();\n\n    _disjointMeasureAxes.forEach((String axisId, NumericAxis axis) {\n      axis.resetDomains();\n    });\n\n    final reverseAxisDirection = context != null && context.isRtl;\n\n    if (vertical) {\n      domainAxis\n        ..axisOrientation = AxisOrientation.bottom\n        ..reverseOutputRange = reverseAxisDirection;\n\n      _primaryMeasureAxis\n        ..axisOrientation = (reverseAxisDirection\n            ? AxisOrientation.right\n            : AxisOrientation.left)\n        ..reverseOutputRange = flipVerticalAxisOutput;\n\n      _secondaryMeasureAxis\n        ..axisOrientation = (reverseAxisDirection\n            ? AxisOrientation.left\n            : AxisOrientation.right)\n        ..reverseOutputRange = flipVerticalAxisOutput;\n\n      _disjointMeasureAxes.forEach((String axisId, NumericAxis axis) {\n        axis\n          ..axisOrientation = (reverseAxisDirection\n              ? AxisOrientation.left\n              : AxisOrientation.right)\n          ..reverseOutputRange = flipVerticalAxisOutput;\n      });\n    } else {\n      domainAxis\n        ..axisOrientation = (reverseAxisDirection\n            ? AxisOrientation.right\n            : AxisOrientation.left)\n        ..reverseOutputRange = flipVerticalAxisOutput;\n\n      _primaryMeasureAxis\n        ..axisOrientation = AxisOrientation.bottom\n        ..reverseOutputRange = reverseAxisDirection;\n\n      _secondaryMeasureAxis\n        ..axisOrientation = AxisOrientation.top\n        ..reverseOutputRange = reverseAxisDirection;\n\n      _disjointMeasureAxes.forEach((String axisId, NumericAxis axis) {\n        axis\n          ..axisOrientation = AxisOrientation.top\n          ..reverseOutputRange = reverseAxisDirection;\n      });\n    }\n\n    // Have each renderer configure the axes with their domain and measure\n    // values.\n    rendererToSeriesList\n        .forEach((String rendererId, List<MutableSeries<D>> seriesList) {\n      getSeriesRenderer(rendererId).configureDomainAxes(seriesList);\n      getSeriesRenderer(rendererId).configureMeasureAxes(seriesList);\n    });\n\n    return rendererToSeriesList;\n  }\n\n  @override\n  void onSkipLayout() {\n    // Update ticks only when skipping layout.\n    domainAxis!.updateTicks();\n\n    if (_usePrimaryMeasureAxis) {\n      _primaryMeasureAxis.updateTicks();\n    }\n\n    if (_useSecondaryMeasureAxis) {\n      _secondaryMeasureAxis.updateTicks();\n    }\n\n    _disjointMeasureAxes.forEach((String axisId, NumericAxis axis) {\n      axis.updateTicks();\n    });\n\n    super.onSkipLayout();\n  }\n\n  @override\n  void onPostLayout(Map<String, List<MutableSeries<D>>> rendererToSeriesList) {\n    fireOnAxisConfigured();\n\n    super.onPostLayout(rendererToSeriesList);\n  }\n\n  /// Returns a list of datum details from selection model of [type].\n  @override\n  List<DatumDetails<D>> getDatumDetails(SelectionModelType type) {\n    final entries = <DatumDetails<D>>[];\n\n    getSelectionModel(type).selectedDatum.forEach((seriesDatum) {\n      final series = seriesDatum.series;\n      final Object? datum = seriesDatum.datum;\n      final datumIndex = seriesDatum.index;\n\n      final domain = series.domainFn(datumIndex);\n      final domainFormatterFn = series.domainFormatterFn;\n      final measure = series.measureFn(datumIndex);\n      final measureFormatterFn = series.measureFormatterFn;\n      final measureOffset = series.measureOffsetFn!(datumIndex);\n      final rawMeasure = series.rawMeasureFn(datumIndex);\n      final color = series.colorFn!(datumIndex);\n\n      final renderer = getSeriesRenderer(series.getAttr(rendererIdKey));\n\n      final datumDetails = renderer.addPositionToDetailsForSeriesDatum(\n          DatumDetails(\n              datum: datum,\n              domain: domain,\n              domainFormatter: domainFormatterFn?.call(datumIndex),\n              index: datumIndex,\n              measure: measure,\n              measureFormatter: measureFormatterFn?.call(datumIndex),\n              measureOffset: measureOffset,\n              rawMeasure: rawMeasure,\n              series: series,\n              color: color),\n          seriesDatum);\n\n      entries.add(datumDetails);\n    });\n\n    return entries;\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/cartesian/cartesian_renderer.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'package:meta/meta.dart';\n\nimport '../../common/symbol_renderer.dart' show SymbolRenderer;\nimport '../../data/series.dart' show AccessorFn;\nimport '../common/base_chart.dart' show BaseChart;\nimport '../common/processed_series.dart' show MutableSeries;\nimport '../common/series_renderer.dart' show BaseSeriesRenderer, SeriesRenderer;\nimport 'axis/axis.dart' show Axis, domainAxisKey, measureAxisKey;\nimport 'cartesian_chart.dart' show CartesianChart;\n\nabstract class CartesianRenderer<D> extends SeriesRenderer<D> {\n  @override\n  void configureDomainAxes(List<MutableSeries<D>> seriesList);\n\n  @override\n  void configureMeasureAxes(List<MutableSeries<D>> seriesList);\n}\n\nabstract class BaseCartesianRenderer<D> extends BaseSeriesRenderer<D>\n    implements CartesianRenderer<D> {\n  BaseCartesianRenderer({\n    required String rendererId,\n    required int layoutPaintOrder,\n    SymbolRenderer? symbolRenderer,\n  }) : super(\n            rendererId: rendererId,\n            layoutPaintOrder: layoutPaintOrder,\n            symbolRenderer: symbolRenderer);\n\n  @protected\n  late CartesianChart<D> chart;\n\n  @override\n  void onAttach(BaseChart<D> chart) {\n    super.onAttach(chart);\n\n    // Save a reference to the parent chart so that we can access properties\n    // that are not set until a later state (e.g. isRtl), or that might change\n    // dynamically (e.g. vertical).\n    this.chart = chart as CartesianChart<D>;\n  }\n\n  // True when the chart should be rendered in vertical mode, false when in\n  // horizontal mode.\n  bool get renderingVertically => chart.vertical;\n\n  @override\n  void configureDomainAxes(List<MutableSeries<D>> seriesList) {\n    seriesList.forEach((MutableSeries<D> series) {\n      if (series.data.isEmpty) {\n        return;\n      }\n\n      final domainAxis = series.getAttr(domainAxisKey);\n      final domainFn = series.domainFn;\n      final domainLowerBoundFn = series.domainLowerBoundFn;\n      final domainUpperBoundFn = series.domainUpperBoundFn;\n\n      if (domainAxis == null) {\n        return;\n      }\n\n      if (renderingVertically) {\n        for (var i = 0; i < series.data.length; i++) {\n          domainAxis.addDomainValue(domainFn(i)!);\n\n          if (domainLowerBoundFn != null && domainUpperBoundFn != null) {\n            final domainLowerBound = domainLowerBoundFn(i);\n            final domainUpperBound = domainUpperBoundFn(i);\n            if (domainLowerBound != null && domainUpperBound != null) {\n              domainAxis.addDomainValue(domainLowerBound);\n              domainAxis.addDomainValue(domainUpperBound);\n            }\n          }\n        }\n      } else {\n        // When rendering horizontally, domains are displayed from top to bottom\n        // in order to match visual display in legend.\n        for (var i = series.data.length - 1; i >= 0; i--) {\n          domainAxis.addDomainValue(domainFn(i)!);\n\n          if (domainLowerBoundFn != null && domainUpperBoundFn != null) {\n            final domainLowerBound = domainLowerBoundFn(i);\n            final domainUpperBound = domainUpperBoundFn(i);\n            if (domainLowerBound != null && domainUpperBound != null) {\n              domainAxis.addDomainValue(domainLowerBound);\n              domainAxis.addDomainValue(domainUpperBound);\n            }\n          }\n        }\n      }\n    });\n  }\n\n  @override\n  void configureMeasureAxes(List<MutableSeries<D>> seriesList) {\n    seriesList.forEach((MutableSeries<D> series) {\n      if (series.data.isEmpty) {\n        return;\n      }\n\n      final domainAxis = series.getAttr(domainAxisKey) as Axis<D>?;\n      final domainFn = series.domainFn;\n\n      if (domainAxis == null) {\n        return;\n      }\n\n      final measureAxis = series.getAttr(measureAxisKey) as Axis<num>?;\n      if (measureAxis == null) {\n        return;\n      }\n\n      // Only add the measure values for datum who's domain is within the\n      // domainAxis viewport.\n      final startIndex =\n          findNearestViewportStart(domainAxis, domainFn, series.data);\n      final endIndex =\n          findNearestViewportEnd(domainAxis, domainFn, series.data);\n\n      addMeasureValuesFor(series, measureAxis, startIndex, endIndex);\n    });\n  }\n\n  void addMeasureValuesFor(\n    MutableSeries<D> series,\n    Axis<num> measureAxis,\n    int startIndex,\n    int endIndex,\n  ) {\n    final measureFn = series.measureFn;\n    final measureOffsetFn = series.measureOffsetFn!;\n    final measureLowerBoundFn = series.measureLowerBoundFn;\n    final measureUpperBoundFn = series.measureUpperBoundFn;\n\n    for (var i = startIndex; i <= endIndex; i++) {\n      final measure = measureFn(i);\n      final measureOffset = measureOffsetFn(i);\n\n      if (measure != null && measureOffset != null) {\n        measureAxis.addDomainValue(measure + measureOffset);\n\n        if (measureLowerBoundFn != null && measureUpperBoundFn != null) {\n          measureAxis\n              .addDomainValue((measureLowerBoundFn(i) ?? 0) + measureOffset);\n          measureAxis\n              .addDomainValue((measureUpperBoundFn(i) ?? 0) + measureOffset);\n        }\n      }\n    }\n  }\n\n  @visibleForTesting\n  int findNearestViewportStart(\n      Axis<D> domainAxis, AccessorFn<D> domainFn, List<Object?> data) {\n    assert(data.isNotEmpty);\n\n    // Quick optimization for full viewport (likely).\n    if (domainAxis.compareDomainValueToViewport(domainFn(0)) == 0) {\n      return 0;\n    }\n\n    var start = 1; // Index zero was already checked for above.\n    var end = data.length - 1;\n\n    // Binary search for the start of the viewport.\n    while (end >= start) {\n      final searchIndex = ((end - start) / 2).floor() + start;\n      final prevIndex = searchIndex - 1;\n\n      var comparisonValue =\n          domainAxis.compareDomainValueToViewport(domainFn(searchIndex));\n      var prevComparisonValue =\n          domainAxis.compareDomainValueToViewport(domainFn(prevIndex));\n\n      // Found start?\n      if (prevComparisonValue == -1 && comparisonValue == 0) {\n        return searchIndex;\n      }\n\n      // Straddling viewport?\n      // Return previous index as the nearest start of the viewport.\n      if (comparisonValue == 1 && prevComparisonValue == -1) {\n        return searchIndex - 1;\n      }\n\n      // Before start? Update startIndex\n      if (comparisonValue == -1) {\n        start = searchIndex + 1;\n      } else {\n        // Middle or after viewport? Update endIndex\n        end = searchIndex - 1;\n      }\n    }\n\n    // Binary search would reach this point for the edge cases where the domain\n    // specified is prior or after the domain viewport.\n    // If domain is prior to the domain viewport, return the first index as the\n    // nearest viewport start.\n    // If domain is after the domain viewport, return the last index as the\n    // nearest viewport start.\n    final lastComparison =\n        domainAxis.compareDomainValueToViewport(domainFn(data.length - 1));\n    return lastComparison == 1 ? (data.length - 1) : 0;\n  }\n\n  @visibleForTesting\n  int findNearestViewportEnd(\n      Axis<D> domainAxis, AccessorFn<D> domainFn, List<Object?> data) {\n    assert(data.isNotEmpty);\n\n    var start = 1;\n    var end = data.length - 1;\n\n    // Quick optimization for full viewport (likely).\n    if (domainAxis.compareDomainValueToViewport(domainFn(end)) == 0) {\n      return end;\n    }\n    end = end - 1; // Last index was already checked for above.\n\n    // Binary search for the start of the viewport.\n    while (end >= start) {\n      final searchIndex = ((end - start) / 2).floor() + start;\n      final prevIndex = searchIndex - 1;\n\n      final comparisonValue =\n          domainAxis.compareDomainValueToViewport(domainFn(searchIndex));\n      final prevComparisonValue =\n          domainAxis.compareDomainValueToViewport(domainFn(prevIndex));\n\n      // Found end?\n      if (prevComparisonValue == 0 && comparisonValue == 1) {\n        return prevIndex;\n      }\n\n      // Straddling viewport?\n      // Return the current index as the start of the viewport.\n      if (comparisonValue == 1 && prevComparisonValue == -1) {\n        return searchIndex;\n      }\n\n      // After end? Update endIndex\n      if (comparisonValue == 1) {\n        end = searchIndex - 1;\n      } else {\n        // Middle or before viewport? Update startIndex\n        start = searchIndex + 1;\n      }\n    }\n\n    // Binary search would reach this point for the edge cases where the domain\n    // specified is prior or after the domain viewport.\n    // If domain is prior to the domain viewport, return the first index as the\n    // nearest viewport end.\n    // If domain is after the domain viewport, return the last index as the\n    // nearest viewport end.\n    final lastComparison =\n        domainAxis.compareDomainValueToViewport(domainFn(data.length - 1));\n    return lastComparison == 1 ? (data.length - 1) : 0;\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/common/base_chart.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math' show Rectangle, Point;\n\nimport 'package:meta/meta.dart' show protected;\n\nimport '../../common/gesture_listener.dart' show GestureListener;\nimport '../../common/graphics_factory.dart' show GraphicsFactory;\nimport '../../common/proxy_gesture_listener.dart' show ProxyGestureListener;\nimport '../../data/series.dart' show Series;\nimport '../layout/layout_config.dart' show LayoutConfig;\nimport '../layout/layout_manager.dart' show LayoutManager;\nimport '../layout/layout_manager_impl.dart' show LayoutManagerImpl;\nimport '../layout/layout_view.dart' show LayoutView;\nimport 'behavior/chart_behavior.dart' show ChartBehavior;\nimport 'chart_canvas.dart' show ChartCanvas;\nimport 'chart_context.dart' show ChartContext;\nimport 'datum_details.dart' show DatumDetails;\nimport 'processed_series.dart' show MutableSeries;\nimport 'selection_model/selection_model.dart'\n    show MutableSelectionModel, SelectionModelType;\nimport 'series_datum.dart' show SeriesDatum;\nimport 'series_renderer.dart' show SeriesRenderer, rendererIdKey, rendererKey;\n\ntypedef BehaviorCreator = ChartBehavior<D> Function<D>();\n\nabstract class BaseChart<D> {\n  late ChartContext context;\n\n  /// Internal use only.\n  GraphicsFactory? graphicsFactory;\n\n  final LayoutManager _layoutManager;\n\n  int? _chartWidth;\n  int? _chartHeight;\n\n  Duration transition = const Duration(milliseconds: 300);\n\n  /// A value in the range \\[0.0, 1.0\\] that indicates the animation progress.\n  double animationPercent = 0;\n\n  bool _animationsTemporarilyDisabled = false;\n\n  /// List of series that were passed into the previous draw call.\n  ///\n  /// This list will be used when redraw is called, to reset the state of all\n  /// behaviors to the original list.\n  late List<MutableSeries<D>> _originalSeriesList;\n\n  /// List of series that are currently drawn on the chart.\n  ///\n  /// This list should be used by interactive behaviors between chart draw\n  /// cycles. It may be filtered or modified by some behaviors during the\n  /// initial draw cycle (e.g. a [Legend] may hide some series).\n  List<MutableSeries<D>>? _currentSeriesList;\n\n  Set<String> _usingRenderers = <String>{};\n  Map<String, List<MutableSeries<D>>>? _rendererToSeriesList;\n\n  final _seriesRenderers = <String, SeriesRenderer<D>>{};\n\n  /// Map of named chart behaviors attached to this chart.\n  final _behaviorRoleMap = <String, ChartBehavior<D>>{};\n  final _behaviorStack = <ChartBehavior<D>>[];\n\n  final _behaviorTappableMap = <String, ChartBehavior<D>>{};\n\n  /// Whether or not the chart will respond to tap events.\n  ///\n  /// This will generally be true if there is a behavior attached to the chart\n  /// that does something with tap events, such as \"click to select data.\"\n  bool get isTappable => _behaviorTappableMap.isNotEmpty;\n\n  final _gestureProxy = ProxyGestureListener();\n\n  final _selectionModels = <SelectionModelType, MutableSelectionModel<D>>{};\n\n  /// Whether selected data should be restricted to only have points that\n  /// cover this event location.\n  ///\n  /// When this is true, selection logic would ignore points that are close to\n  /// event location but does not cover event location.\n  bool get selectExactEventLocation => false;\n\n  /// Whether data should be selected by nearest domain distance, or by relative\n  /// distance.\n  ///\n  /// This should generally be true for chart types that are intended to be\n  /// aggregated by domain, and false for charts that plot arbitrary x,y data.\n  /// Scatter plots, for example, may have many overlapping data with the same\n  /// domain value.\n  bool get selectNearestByDomain => true;\n\n  /// Whether data should be expanded by to include all points overlapping the\n  /// selection point\n  ///\n  /// Should be true for Scatter plots.\n  bool get selectOverlappingPoints => false;\n\n  final _lifecycleListeners = <LifecycleListener<D>>[];\n\n  BaseChart({LayoutConfig? layoutConfig})\n      : _layoutManager = LayoutManagerImpl(config: layoutConfig);\n\n  void init(ChartContext context, GraphicsFactory graphicsFactory) {\n    this.context = context;\n\n    // When graphics factory is updated, update all the views.\n    if (this.graphicsFactory != graphicsFactory) {\n      this.graphicsFactory = graphicsFactory;\n\n      _layoutManager.applyToViews(\n          (LayoutView view) => view.graphicsFactory = graphicsFactory);\n    }\n\n    configurationChanged();\n  }\n\n  /// Updates the layout configuration used inside the layout manager.\n  void updateConfig(LayoutConfig layoutConfig) {\n    _layoutManager.updateConfig(layoutConfig);\n  }\n\n  bool _chartIsDirty = false;\n\n  /// If the chart configuration has changed and requires a redraw.\n  bool get chartIsDirty => _chartIsDirty;\n\n  /// Resets the chart dirty flag to `false`.\n  void resetChartDirtyFlag() {\n    _chartIsDirty = false;\n  }\n\n  /// Marks the chart as dirty.\n  ///\n  /// When a chart axis or configurable is changed and will require a redraw\n  /// next frame the chart must be marked dirty.\n  void markChartDirty() {\n    _chartIsDirty = true;\n  }\n\n  /// Finish configuring components that require context and graphics factory.\n  ///\n  /// Some components require context and graphics factory to be set again when\n  /// configuration has changed but the configuration is set prior to the\n  /// chart first calling init with the context.\n  void configurationChanged() {}\n\n  int? get chartWidth => _chartWidth;\n\n  int? get chartHeight => _chartHeight;\n\n  //\n  // Gesture proxy methods\n  //\n  ProxyGestureListener get gestureProxy => _gestureProxy;\n\n  /// Add a [GestureListener] to this chart.\n  GestureListener addGestureListener(GestureListener listener) {\n    _gestureProxy.add(listener);\n    return listener;\n  }\n\n  /// Remove a [GestureListener] from this chart.\n  void removeGestureListener(GestureListener listener) {\n    _gestureProxy.remove(listener);\n  }\n\n  LifecycleListener<D> addLifecycleListener(LifecycleListener<D> listener) {\n    _lifecycleListeners.add(listener);\n    return listener;\n  }\n\n  bool removeLifecycleListener(LifecycleListener<D> listener) =>\n      _lifecycleListeners.remove(listener);\n\n  /// Returns MutableSelectionModel for the given type. Lazy creates one upon first\n  /// request.\n  MutableSelectionModel<D> getSelectionModel(SelectionModelType type) {\n    return _selectionModels.putIfAbsent(type, () => MutableSelectionModel<D>());\n  }\n\n  /// Returns a list of datum details from selection model of [type].\n  List<DatumDetails<D>> getDatumDetails(SelectionModelType type);\n\n  //\n  // Renderer methods\n  //\n\n  set defaultRenderer(SeriesRenderer<D> renderer) {\n    renderer.rendererId = SeriesRenderer.defaultRendererId;\n    addSeriesRenderer(renderer);\n  }\n\n  SeriesRenderer<D> get defaultRenderer =>\n      getSeriesRenderer(SeriesRenderer.defaultRendererId);\n\n  void addSeriesRenderer(SeriesRenderer<D> renderer) {\n    final rendererId = renderer.rendererId;\n\n    final previousRenderer = _seriesRenderers[rendererId];\n    if (previousRenderer != null) {\n      removeView(previousRenderer);\n      previousRenderer.onDetach(this);\n    }\n\n    addView(renderer);\n    renderer.onAttach(this);\n    _seriesRenderers[rendererId] = renderer;\n  }\n\n  SeriesRenderer<D> getSeriesRenderer(String? rendererId) {\n    var renderer = _seriesRenderers[rendererId];\n\n    // Special case, if we are asking for the default and we haven't made it\n    // yet, then make it now.\n    if (renderer == null) {\n      // TODO: Throw an error if\n      // `rendererId != SeriesRenderer.defaultRendererId`?\n      renderer = makeDefaultRenderer();\n      defaultRenderer = renderer;\n    }\n\n    return renderer;\n  }\n\n  SeriesRenderer<D> makeDefaultRenderer();\n\n  bool pointWithinRenderer(Point<double> chartPosition) {\n    return _usingRenderers.any((String rendererId) =>\n        getSeriesRenderer(rendererId)\n            .componentBounds!\n            .containsPoint(chartPosition));\n  }\n\n  /// Retrieves the datum details that are nearest to the given [drawAreaPoint].\n  ///\n  /// [drawAreaPoint] represents a point in the chart, such as a point that was\n  /// clicked/tapped on by a user.\n  ///\n  /// [selectAcrossAllDrawAreaComponents] specifies whether nearest data\n  /// selection should be done across the combined draw area of all components\n  /// with series draw areas, or just the chart's primary draw area bounds.\n  List<DatumDetails<D>> getNearestDatumDetailPerSeries(\n      Point<double> drawAreaPoint, bool selectAcrossAllDrawAreaComponents) {\n    // Optionally grab the combined draw area bounds of all components. If this\n    // is disabled, then we expect each series renderer to filter out the event\n    // if [chartPoint] is located outside of its own component bounds.\n    final boundsOverride =\n        selectAcrossAllDrawAreaComponents ? drawableLayoutAreaBounds : null;\n\n    final details = <DatumDetails<D>>[];\n    _usingRenderers.forEach((String rendererId) {\n      details\n          .addAll(getSeriesRenderer(rendererId).getNearestDatumDetailPerSeries(\n        drawAreaPoint,\n        selectNearestByDomain,\n        boundsOverride,\n        selectOverlappingPoints: selectOverlappingPoints,\n        selectExactEventLocation: selectExactEventLocation,\n      ));\n    });\n\n    details.sort((DatumDetails<D> a, DatumDetails<D> b) {\n      // Sort so that the nearest one is first.\n      // Special sort, sort by domain distance first, then by measure distance.\n      if (selectNearestByDomain) {\n        final domainDiff = a.domainDistance!.compareTo(b.domainDistance!);\n        if (domainDiff == 0) {\n          return a.measureDistance!.compareTo(b.measureDistance!);\n        }\n        return domainDiff;\n      } else {\n        return a.relativeDistance!.compareTo(b.relativeDistance!);\n      }\n    });\n\n    return details;\n  }\n\n  /// Retrieves the datum details for the current chart selection.\n  ///\n  /// [selectionModelType] specifies the type of the selection model to use.\n  List<DatumDetails<D>> getSelectedDatumDetails(\n      SelectionModelType selectionModelType) {\n    final details = <DatumDetails<D>>[];\n\n    if (_currentSeriesList == null) {\n      return details;\n    }\n\n    final selectionModel = getSelectionModel(selectionModelType);\n    if (!selectionModel.hasDatumSelection) {\n      return details;\n    }\n\n    // Pass each selected datum to the appropriate series renderer to get full\n    // details appropriate to its series type.\n    for (final seriesDatum in selectionModel.selectedDatum) {\n      final rendererId = seriesDatum.series.getAttr(rendererIdKey);\n      details.add(\n          getSeriesRenderer(rendererId).getDetailsForSeriesDatum(seriesDatum));\n    }\n\n    return details;\n  }\n\n  /// Retrieves the datum details for all data on the chart.\n  List<DatumDetails<D>> getAllDatumDetails(\n      {bool includeOverlaySeries = false}) {\n    final details = <DatumDetails<D>>[];\n\n    if (_currentSeriesList == null) {\n      return details;\n    }\n\n    for (final series in _currentSeriesList!) {\n      final rendererId = series.getAttr(rendererIdKey);\n\n      if (!includeOverlaySeries && series.overlaySeries) {\n        continue;\n      }\n\n      for (dynamic datum in series.data) {\n        details.add(getSeriesRenderer(rendererId)\n            .getDetailsForSeriesDatum(SeriesDatum<D>(series, datum)));\n      }\n    }\n\n    return details;\n  }\n\n  //\n  // Behavior methods\n  //\n\n  /// Helper method to create a behavior with congruent types.\n  ///\n  /// This invokes the provides helper with type parameters that match this\n  /// chart.\n  ChartBehavior<D> createBehavior(BehaviorCreator creator) => creator<D>();\n\n  /// Attaches a behavior to the chart.\n  ///\n  /// Setting a behavior with the same role as a behavior already attached\n  /// to the chart will replace the old behavior. The old behavior's removeFrom\n  /// method will be called before we attach the behavior.\n  void addBehavior(ChartBehavior<D> behavior) {\n    final role = behavior.role;\n\n    if (role != null && _behaviorRoleMap[role] != behavior) {\n      // Remove any old behavior with the same role.\n      removeBehavior(_behaviorRoleMap[role]);\n      // Add the behavior.\n      _behaviorRoleMap[role] = behavior;\n    }\n\n    // Add the behavior if it wasn't already added.\n    if (!_behaviorStack.contains(behavior)) {\n      _behaviorStack.add(behavior);\n      behavior.attachTo(this);\n    }\n  }\n\n  /// Removes a behavior from the chart.\n  ///\n  /// Returns true if a behavior was removed, otherwise returns false.\n  bool removeBehavior(ChartBehavior<D>? behavior) {\n    if (behavior == null) {\n      return false;\n    }\n\n    final role = behavior.role;\n    if (role != null && _behaviorRoleMap[role] == behavior) {\n      _behaviorRoleMap.remove(role);\n    }\n\n    // Make sure the removed behavior is no longer registered for tap events.\n    unregisterTappable(behavior);\n\n    final wasAttached = _behaviorStack.remove(behavior);\n    behavior.removeFrom(this);\n\n    return wasAttached;\n  }\n\n  /// Tells the chart that this behavior responds to tap events.\n  ///\n  /// This should only be called after [behavior] has been attached to the chart\n  /// via [addBehavior].\n  void registerTappable(ChartBehavior<D> behavior) {\n    final role = behavior.role;\n\n    if (role != null &&\n        _behaviorRoleMap[role] == behavior &&\n        _behaviorTappableMap[role] != behavior) {\n      _behaviorTappableMap[role] = behavior;\n    }\n  }\n\n  /// Tells the chart that this behavior no longer responds to tap events.\n  void unregisterTappable(ChartBehavior<D> behavior) {\n    final role = behavior.role;\n    if (role != null && _behaviorTappableMap[role] == behavior) {\n      _behaviorTappableMap.remove(role);\n    }\n  }\n\n  /// Returns a list of behaviors that have been added.\n  List<ChartBehavior<D>> get behaviors => List.unmodifiable(_behaviorStack);\n\n  //\n  // Layout methods\n  //\n  void measure(int width, int height) {\n    if (_rendererToSeriesList != null) {\n      _layoutManager.measure(width, height);\n    }\n  }\n\n  void layout(int width, int height) {\n    if (_rendererToSeriesList != null) {\n      layoutInternal(width, height);\n\n      onPostLayout(_rendererToSeriesList!);\n    }\n  }\n\n  void layoutInternal(int width, int height) {\n    _chartWidth = width;\n    _chartHeight = height;\n    _layoutManager.layout(width, height);\n  }\n\n  void addView(LayoutView view) {\n    if (!_layoutManager.isAttached(view)) {\n      view.graphicsFactory = graphicsFactory;\n      _layoutManager.addView(view);\n    }\n  }\n\n  void removeView(LayoutView view) {\n    _layoutManager.removeView(view);\n  }\n\n  /// Returns whether or not [point] is within the draw area bounds.\n  bool withinDrawArea(Point<num> point) {\n    return _layoutManager.withinDrawArea(point);\n  }\n\n  /// Returns the bounds of the chart draw area.\n  Rectangle<int> get drawAreaBounds => _layoutManager.drawAreaBounds;\n\n  int get marginBottom => _layoutManager.marginBottom;\n\n  int get marginLeft => _layoutManager.marginLeft;\n\n  int get marginRight => _layoutManager.marginRight;\n\n  int get marginTop => _layoutManager.marginTop;\n\n  /// Returns the combined bounds of the chart draw area and all layout\n  /// components that draw series data.\n  Rectangle<int> get drawableLayoutAreaBounds =>\n      _layoutManager.drawableLayoutAreaBounds;\n\n  //\n  // Draw methods\n  //\n  void draw(List<Series<dynamic, D>> seriesList) {\n    // Clear the selection model when [seriesList] changes.\n    for (final selectionModel in _selectionModels.values) {\n      selectionModel.clearSelection(notifyListeners: false);\n    }\n\n    var processedSeriesList =\n        List.of(seriesList.map<MutableSeries<D>>(makeSeries));\n\n    // Allow listeners to manipulate the seriesList.\n    fireOnDraw(processedSeriesList);\n\n    // Set an index on the series list.\n    // This can be used by listeners of selection to determine the order of\n    // series, because the selection details are not returned in this order.\n    var seriesIndex = 0;\n    processedSeriesList.forEach((series) => series.seriesIndex = seriesIndex++);\n\n    // Initially save a reference to processedSeriesList. After drawInternal\n    // finishes, we expect _currentSeriesList to contain a new, possibly\n    // modified list.\n    _currentSeriesList = processedSeriesList;\n\n    // Store off processedSeriesList for use later during redraw calls. This\n    // list will not reflect any modifications that were made to\n    // _currentSeriesList by behaviors during the draw cycle.\n    _originalSeriesList = processedSeriesList;\n\n    drawInternal(processedSeriesList, skipAnimation: false, skipLayout: false);\n  }\n\n  /// Redraws and re-lays-out the chart using the previously rendered layout\n  /// dimensions.\n  void redraw({bool skipAnimation = false, bool skipLayout = false}) {\n    drawInternal(_originalSeriesList,\n        skipAnimation: skipAnimation, skipLayout: skipLayout);\n\n    // Trigger layout and actually redraw the chart.\n    if (!skipLayout) {\n      measure(_chartWidth!, _chartHeight!);\n      layout(_chartWidth!, _chartHeight!);\n    } else {\n      onSkipLayout();\n    }\n  }\n\n  void drawInternal(List<MutableSeries<D>> seriesList,\n      {bool? skipAnimation, bool? skipLayout}) {\n    seriesList = seriesList\n        .map((MutableSeries<D> series) => MutableSeries<D>.clone(series))\n        .toList();\n\n    // TODO: Handle exiting renderers.\n    if (skipAnimation != null) {\n      _animationsTemporarilyDisabled = skipAnimation;\n    }\n\n    configureSeries(seriesList);\n\n    // Allow listeners to manipulate the processed seriesList.\n    fireOnPreprocess(seriesList);\n\n    _rendererToSeriesList = preprocessSeries(seriesList);\n\n    // Allow listeners to manipulate the processed seriesList.\n    fireOnPostprocess(seriesList);\n\n    _currentSeriesList = seriesList;\n  }\n\n  List<MutableSeries<D>> get currentSeriesList => _currentSeriesList!;\n\n  MutableSeries<D> makeSeries(Series<dynamic, D> series) {\n    final s = MutableSeries<D>(series);\n\n    // Setup the Renderer\n    final rendererId =\n        series.getAttribute(rendererIdKey) ?? SeriesRenderer.defaultRendererId;\n    s.setAttr(rendererIdKey, rendererId);\n    s.setAttr(rendererKey, getSeriesRenderer(rendererId));\n\n    return s;\n  }\n\n  /// Preprocess series to assign missing color functions.\n  void configureSeries(List<MutableSeries<D>> seriesList) {\n    final rendererToSeriesList = <String?, List<MutableSeries<D>>>{};\n\n    // Build map of rendererIds to SeriesLists. This map can't be re-used later\n    // in the preprocessSeries call because some behaviors might alter the\n    // seriesList.\n    seriesList.forEach((MutableSeries<D> series) {\n      final rendererId = series.getAttr(rendererIdKey);\n      rendererToSeriesList.putIfAbsent(rendererId, () => []).add(series);\n    });\n\n    // Have each renderer add missing color functions to their seriesLists.\n    rendererToSeriesList\n        .forEach((String? rendererId, List<MutableSeries<D>> seriesList) {\n      getSeriesRenderer(rendererId).configureSeries(seriesList);\n    });\n  }\n\n  /// Preprocess series to allow stacking and other mutations.\n  ///\n  /// Build a map of rendererId to series.\n  Map<String, List<MutableSeries<D>>> preprocessSeries(\n      List<MutableSeries<D>> seriesList) {\n    final rendererToSeriesList = <String, List<MutableSeries<D>>>{};\n\n    var unusedRenderers = _usingRenderers;\n    _usingRenderers = <String>{};\n\n    // Build map of rendererIds to SeriesLists.\n    seriesList.forEach((MutableSeries<D> series) {\n      final rendererId = series.getAttr(rendererIdKey)!;\n      rendererToSeriesList.putIfAbsent(rendererId, () => []).add(series);\n\n      _usingRenderers.add(rendererId);\n      unusedRenderers.remove(rendererId);\n    });\n\n    // Allow unused renderers to render out content.\n    unusedRenderers\n        .forEach((rendererId) => rendererToSeriesList[rendererId] = []);\n\n    // Have each renderer preprocess their seriesLists.\n    rendererToSeriesList.forEach((rendererId, seriesList) {\n      getSeriesRenderer(rendererId).preprocessSeries(seriesList);\n    });\n\n    return rendererToSeriesList;\n  }\n\n  void onSkipLayout() {\n    onPostLayout(_rendererToSeriesList!);\n  }\n\n  void onPostLayout(Map<String, List<MutableSeries<D>>> rendererToSeriesList) {\n    // Update each renderer with\n    rendererToSeriesList\n        .forEach((String rendererId, List<MutableSeries<D>> seriesList) {\n      getSeriesRenderer(rendererId).update(seriesList, animatingThisDraw);\n    });\n\n    // Request animation\n    if (animatingThisDraw) {\n      animationPercent = 0.0;\n      context.requestAnimation(transition);\n    } else {\n      animationPercent = 1.0;\n      context.requestPaint();\n    }\n\n    _animationsTemporarilyDisabled = false;\n  }\n\n  void paint(ChartCanvas canvas) {\n    canvas.drawingView = 'BaseView';\n    _layoutManager.paintOrderedViews.forEach((LayoutView view) {\n      canvas.drawingView = view.runtimeType.toString();\n      view.paint(canvas, animatingThisDraw ? animationPercent : 1.0);\n    });\n\n    canvas.drawingView = 'PostRender';\n    fireOnPostrender(canvas);\n    canvas.drawingView = null;\n\n    if (animationPercent == 1.0) {\n      fireOnAnimationComplete();\n    }\n  }\n\n  bool get animatingThisDraw =>\n      transition != null &&\n      transition.inMilliseconds > 0 &&\n      !_animationsTemporarilyDisabled;\n\n  @protected\n  void fireOnDraw(List<MutableSeries<D>> seriesList) {\n    _lifecycleListeners.forEach((LifecycleListener<D> listener) {\n      listener.onData?.call(seriesList);\n    });\n  }\n\n  @protected\n  void fireOnPreprocess(List<MutableSeries<D>> seriesList) {\n    _lifecycleListeners.forEach((LifecycleListener<D> listener) {\n      listener.onPreprocess?.call(seriesList);\n    });\n  }\n\n  @protected\n  void fireOnPostprocess(List<MutableSeries<D>> seriesList) {\n    _lifecycleListeners.forEach((LifecycleListener<D> listener) {\n      listener.onPostprocess?.call(seriesList);\n    });\n  }\n\n  @protected\n  void fireOnAxisConfigured() {\n    _lifecycleListeners.forEach((LifecycleListener<D> listener) {\n      listener.onAxisConfigured?.call();\n    });\n  }\n\n  @protected\n  void fireOnPostrender(ChartCanvas canvas) {\n    _lifecycleListeners.forEach((LifecycleListener<D> listener) {\n      listener.onPostrender?.call(canvas);\n    });\n  }\n\n  @protected\n  void fireOnAnimationComplete() {\n    _lifecycleListeners.forEach((LifecycleListener<D> listener) {\n      listener.onAnimationComplete?.call();\n    });\n  }\n\n  /// Called to free up any resources due to chart going away.\n  void destroy() {\n    // Walk them in add order to support behaviors that remove other behaviors.\n    for (var i = 0; i < _behaviorStack.length; i++) {\n      _behaviorStack[i].removeFrom(this);\n    }\n    _behaviorStack.clear();\n    _behaviorRoleMap.clear();\n    _selectionModels.values\n        .forEach((selectionModel) => selectionModel.clearAllListeners());\n  }\n}\n\nclass LifecycleListener<D> {\n  /// Called when data is drawn to the chart (not a redraw).\n  ///\n  /// This step is good for processing the data (running averages, percentage of\n  /// first, etc). It can also be used to add Series of data (trend line) or\n  /// remove a line as mentioned above, removing Series.\n  final LifecycleSeriesListCallback<D>? onData;\n\n  /// Called for every redraw given the original SeriesList resulting from the\n  /// previous onData.\n  ///\n  /// This step is good for injecting default attributes on the Series before\n  /// the renderers process the data (ex: before stacking measures).\n  final LifecycleSeriesListCallback<D>? onPreprocess;\n\n  /// Called after the chart and renderers get a chance to process the data but\n  /// before the axes process them.\n  ///\n  /// This step is good if you need to alter the Series measure values after the\n  /// renderers have processed them (ex: after stacking measures).\n  final LifecycleSeriesListCallback<D>? onPostprocess;\n\n  /// Called after the Axes have been configured.\n  /// This step is good if you need to use the axes to get any cartesian\n  /// location information. At this point Axes should be immutable and stable.\n  final LifecycleEmptyCallback? onAxisConfigured;\n\n  /// Called after the chart is done rendering passing along the canvas allowing\n  /// a behavior or other listener to render on top of the chart.\n  ///\n  /// This is a convenience callback, however if there is any significant canvas\n  /// interaction or stacking needs, it is preferred that a AplosView/ChartView\n  /// is added to the chart instead to fully participate in the view stacking.\n  final LifecycleCanvasCallback? onPostrender;\n\n  /// Called after animation hits 100%. This allows a behavior or other listener\n  /// to chain animations to create a multiple step animation transition.\n  final LifecycleEmptyCallback? onAnimationComplete;\n\n  LifecycleListener(\n      {this.onData,\n      this.onPreprocess,\n      this.onPostprocess,\n      this.onAxisConfigured,\n      this.onPostrender,\n      this.onAnimationComplete});\n}\n\ntypedef LifecycleSeriesListCallback<D> = void Function(\n    List<MutableSeries<D>> seriesList);\ntypedef LifecycleCanvasCallback = void Function(ChartCanvas canvas);\ntypedef LifecycleEmptyCallback = void Function();\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/common/behavior/a11y/a11y_explore_behavior.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math' show Point;\nimport '../../../../common/gesture_listener.dart' show GestureListener;\nimport '../../base_chart.dart' show BaseChart;\nimport '../chart_behavior.dart' show ChartBehavior;\nimport 'a11y_node.dart' show A11yNode;\n\n/// The gesture to use for triggering explore mode.\nenum ExploreModeTrigger {\n  pressHold,\n  tap,\n}\n\n/// Chart behavior for adding A11y information.\nabstract class A11yExploreBehavior<D> implements ChartBehavior<D> {\n  /// The gesture that activates explore mode. Defaults to long press.\n  ///\n  /// Turning on explore mode asks this [A11yExploreBehavior] to generate nodes within\n  /// this chart.\n  final ExploreModeTrigger exploreModeTrigger;\n\n  /// Minimum width of the bounding box for the a11y focus.\n  ///\n  /// Must be 1 or higher because invisible semantic nodes should not be added.\n  final double minimumWidth;\n\n  /// Optionally notify the OS when explore mode is enabled.\n  final String? exploreModeEnabledAnnouncement;\n\n  /// Optionally notify the OS when explore mode is disabled.\n  final String? exploreModeDisabledAnnouncement;\n\n  BaseChart<D>? _chart;\n  late GestureListener _listener;\n  bool _exploreModeOn = false;\n\n  A11yExploreBehavior({\n    ExploreModeTrigger? exploreModeTrigger,\n    double? minimumWidth,\n    this.exploreModeEnabledAnnouncement,\n    this.exploreModeDisabledAnnouncement,\n  })  : exploreModeTrigger = exploreModeTrigger ?? ExploreModeTrigger.pressHold,\n        minimumWidth = minimumWidth ?? 1.0 {\n    assert(this.minimumWidth >= 1.0);\n\n    switch (this.exploreModeTrigger) {\n      case ExploreModeTrigger.pressHold:\n        _listener = GestureListener(onLongPress: _toggleExploreMode);\n        break;\n      case ExploreModeTrigger.tap:\n        _listener = GestureListener(onTap: _toggleExploreMode);\n        break;\n    }\n  }\n\n  bool _toggleExploreMode(Point<double> _) {\n    if (_exploreModeOn) {\n      _exploreModeOn = false;\n      // Ask native platform to turn off explore mode.\n      _chart!.context.disableA11yExploreMode(\n          announcement: exploreModeDisabledAnnouncement);\n    } else {\n      _exploreModeOn = true;\n      // Ask native platform to turn on explore mode.\n      _chart!.context.enableA11yExploreMode(createA11yNodes(),\n          announcement: exploreModeEnabledAnnouncement);\n    }\n\n    return true;\n  }\n\n  /// Returns a list of A11yNodes for this chart.\n  List<A11yNode> createA11yNodes();\n\n  @override\n  void attachTo(BaseChart<D> chart) {\n    _chart = chart;\n    chart.addGestureListener(_listener);\n  }\n\n  @override\n  void removeFrom(BaseChart<D> chart) {\n    chart.removeGestureListener(_listener);\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/common/behavior/a11y/a11y_node.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math' show Rectangle;\n\ntypedef OnFocus = void Function();\n\n/// Container for accessibility data.\nclass A11yNode {\n  /// The bounding box for this node.\n  final Rectangle<int> boundingBox;\n\n  /// The textual description of this node.\n  final String label;\n\n  /// Callback when the A11yNode is focused by the native platform\n  OnFocus? onFocus;\n\n  A11yNode(this.label, this.boundingBox, {this.onFocus});\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/common/behavior/a11y/domain_a11y_explore_behavior.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math' show Rectangle;\n\nimport '../../../cartesian/axis/axis.dart' show ImmutableAxis, domainAxisKey;\nimport '../../../cartesian/cartesian_chart.dart' show CartesianChart;\nimport '../../base_chart.dart' show BaseChart, LifecycleListener;\nimport '../../processed_series.dart' show MutableSeries;\nimport '../../selection_model/selection_model.dart' show SelectionModelType;\nimport '../../series_datum.dart' show SeriesDatum;\nimport 'a11y_explore_behavior.dart'\n    show A11yExploreBehavior, ExploreModeTrigger;\nimport 'a11y_node.dart' show A11yNode, OnFocus;\n\n/// Returns a string for a11y vocalization from a list of series datum.\ntypedef VocalizationCallback<D> = String Function(\n    List<SeriesDatum<D>> seriesDatums);\n\n/// A simple vocalization that returns the domain value to string.\nString domainVocalization<D>(List<SeriesDatum<D>> seriesDatums) {\n  final datumIndex = seriesDatums.first.index;\n  final domainFn = seriesDatums.first.series.domainFn;\n  final domain = domainFn(datumIndex);\n\n  return domain.toString();\n}\n\n/// Behavior that generates semantic nodes for each domain.\nclass DomainA11yExploreBehavior<D> extends A11yExploreBehavior<D> {\n  final VocalizationCallback<D> _vocalizationCallback;\n  late final LifecycleListener<D> _lifecycleListener;\n  late CartesianChart<D> _chart;\n  late List<MutableSeries<D>> _seriesList;\n\n  DomainA11yExploreBehavior(\n      {VocalizationCallback<D>? vocalizationCallback,\n      ExploreModeTrigger? exploreModeTrigger,\n      double? minimumWidth,\n      String? exploreModeEnabledAnnouncement,\n      String? exploreModeDisabledAnnouncement})\n      : _vocalizationCallback = vocalizationCallback ?? domainVocalization,\n        super(\n            exploreModeTrigger: exploreModeTrigger,\n            minimumWidth: minimumWidth,\n            exploreModeEnabledAnnouncement: exploreModeEnabledAnnouncement,\n            exploreModeDisabledAnnouncement: exploreModeDisabledAnnouncement) {\n    _lifecycleListener = LifecycleListener<D>(onPostprocess: _updateSeriesList);\n  }\n\n  @override\n  List<A11yNode> createA11yNodes() {\n    final nodes = <_DomainA11yNode>[];\n\n    // Update the selection model when the a11y node has focus.\n    final selectionModel = _chart.getSelectionModel(SelectionModelType.info);\n\n    final domainSeriesDatum = <D, List<SeriesDatum<D>>>{};\n\n    for (final series in _seriesList) {\n      for (var index = 0; index < series.data.length; index++) {\n        final Object? datum = series.data[index];\n        final domain = series.domainFn(index);\n\n        domainSeriesDatum[domain] ??= <SeriesDatum<D>>[];\n        domainSeriesDatum[domain]!.add(SeriesDatum<D>(series, datum));\n      }\n    }\n\n    domainSeriesDatum.forEach((D domain, List<SeriesDatum<D>> seriesDatums) {\n      final a11yDescription = _vocalizationCallback(seriesDatums);\n\n      final firstSeries = seriesDatums.first.series;\n      final domainAxis = firstSeries.getAttr(domainAxisKey) as ImmutableAxis<D>;\n      final location = domainAxis.getLocation(domain)!;\n\n      /// If the step size is smaller than the minimum width, use minimum.\n      final stepSize = (domainAxis.stepSize > minimumWidth)\n          ? domainAxis.stepSize\n          : minimumWidth;\n\n      nodes.add(_DomainA11yNode(a11yDescription,\n          location: location,\n          stepSize: stepSize,\n          chartDrawBounds: _chart.drawAreaBounds,\n          isRtl: _chart.context.isRtl,\n          renderVertically: _chart.vertical,\n          onFocus: () => selectionModel.updateSelection(seriesDatums, [])));\n    });\n\n    // The screen reader navigates the nodes based on the order it is returned.\n    // So if the chart is RTL, then the nodes should be ordered with the right\n    // most domain first.\n    //\n    // If the chart has multiple series and one series is missing the domain\n    // and it was added later, we still want the domains to be in order.\n    nodes.sort();\n\n    return nodes;\n  }\n\n  void _updateSeriesList(List<MutableSeries<D>> seriesList) {\n    _seriesList = seriesList;\n  }\n\n  @override\n  void attachTo(BaseChart<D> chart) {\n    // Domain selection behavior only works for cartesian charts.\n    assert(chart is CartesianChart<D>);\n    _chart = chart as CartesianChart<D>;\n\n    chart.addLifecycleListener(_lifecycleListener);\n\n    super.attachTo(chart);\n  }\n\n  @override\n  void removeFrom(BaseChart<D> chart) {\n    chart.removeLifecycleListener(_lifecycleListener);\n  }\n\n  @override\n  String get role => 'DomainA11yExplore-${exploreModeTrigger}';\n}\n\n/// A11yNode with domain specific information.\nclass _DomainA11yNode extends A11yNode implements Comparable<_DomainA11yNode> {\n  // Save location, RTL, and is render vertically for sorting\n  final double location;\n  final bool isRtl;\n  final bool renderVertically;\n\n  factory _DomainA11yNode(String label,\n      {required double location,\n      required double stepSize,\n      required Rectangle<int> chartDrawBounds,\n      required bool isRtl,\n      required bool renderVertically,\n      OnFocus? onFocus}) {\n    Rectangle<int> boundingBox;\n    if (renderVertically) {\n      var left = (location - stepSize / 2).round();\n      var top = chartDrawBounds.top;\n      var width = stepSize.round();\n      var height = chartDrawBounds.height;\n      boundingBox = Rectangle(left, top, width, height);\n    } else {\n      var left = chartDrawBounds.left;\n      var top = (location - stepSize / 2).round();\n      var width = chartDrawBounds.width;\n      var height = stepSize.round();\n      boundingBox = Rectangle(left, top, width, height);\n    }\n\n    return _DomainA11yNode._internal(label, boundingBox,\n        location: location,\n        isRtl: isRtl,\n        renderVertically: renderVertically,\n        onFocus: onFocus);\n  }\n\n  _DomainA11yNode._internal(String label, Rectangle<int> boundingBox,\n      {required this.location,\n      required this.isRtl,\n      required this.renderVertically,\n      OnFocus? onFocus})\n      : super(label, boundingBox, onFocus: onFocus);\n\n  @override\n  int compareTo(_DomainA11yNode other) {\n    // Ordered by smaller location first, unless rendering vertically and RTL,\n    // then flip to sort by larger location first.\n    var result = location.compareTo(other.location);\n\n    if (renderVertically && isRtl && result != 0) {\n      result = -result;\n    }\n\n    return result;\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/common/behavior/a11y/keyboard_domain_navigator.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'package:meta/meta.dart' show protected;\n\nimport '../../../cartesian/cartesian_chart.dart' show CartesianChart;\nimport '../../base_chart.dart' show BaseChart, LifecycleListener;\nimport '../../processed_series.dart' show MutableSeries;\nimport '../../selection_model/selection_model.dart' show SelectionModelType;\nimport '../../series_datum.dart' show SeriesDatum;\nimport '../chart_behavior.dart' show ChartBehavior;\n\n/// Enable keyboard navigation of the chart when focused using the directional\n/// keys.\n///\n/// This behavior enables keyboard navigation over the domains of the chart when\n/// focused using the following keys:\n/// - Arrow left/right keys will move the hover selection over the chart\n///   domains.\n/// - Escape will clear both hover and click selections.\n/// - Enter/space will update the click selection to the hover selection.\n///\n/// This behavior does not add any visual cues or accessibility text, so it is\n/// ideally used along with other behaviors that handle hover/click selections\n/// and add these types of visual and/or accessibility cues.\n///\n/// Note that using this behavior requires configuring the tabIndex of your\n/// chart component. Using the default value of 0 makes the chart focusable in\n/// the natural order of the page, but you have the option to use whatever\n/// fine-tuned order works best.\nabstract class KeyboardDomainNavigator<D> implements ChartBehavior<D> {\n  late BaseChart<D> _chart;\n  late final LifecycleListener<D> _lifecycleListener;\n\n  /// An ordered list of the available domains.\n  List<D>? _domains;\n\n  /// An ordered list of selectable domains, the domains will be selected based\n  /// on the order in this list, going back and fort with right and left keys.\n  Map<int, List<SeriesDatum<D>>>? _datumPairs;\n\n  /// Currently selected domain index.\n  int _currentIndex = NO_SELECTION;\n\n  KeyboardDomainNavigator() {\n    _lifecycleListener = LifecycleListener<D>(onData: onData);\n  }\n\n  @override\n  void attachTo(BaseChart<D> chart) {\n    _chart = chart;\n    chart.addLifecycleListener(_lifecycleListener);\n  }\n\n  @override\n  void removeFrom(BaseChart<D> chart) {\n    chart.removeLifecycleListener(_lifecycleListener);\n  }\n\n  /// Resets any hidden series data when new data is drawn on the chart.\n  @protected\n  void onData(List<MutableSeries<D>> _) {\n    _domains = null;\n    _datumPairs = null;\n    _currentIndex = NO_SELECTION;\n  }\n\n  @protected\n  bool handleEscape() {\n    _currentIndex = NO_SELECTION;\n    clearSelection();\n    return true;\n  }\n\n  @protected\n  bool handleEnter() {\n    _currentIndex = _getActiveHoverDomainIndex();\n    selectDomain(_currentIndex);\n    return true;\n  }\n\n  @protected\n  bool handlePreviousDomain() {\n    // Lazily initialize selection domains when a key is pressed after a draw.\n    if (_datumPairs == null) {\n      _generateSelectionDomains();\n    }\n\n    final domainsLength = _datumPairs!.length;\n    if (domainsLength == 0) {\n      return false;\n    }\n\n    _currentIndex = _getActiveHoverDomainIndex();\n\n    // Navigate to the last domain when current index is NO_SELECTION.\n    if (_currentIndex == NO_SELECTION) {\n      _currentIndex = domainsLength - 1;\n    } else {\n      // Navigate to the previous index, or to NO_SELECTION when it would\n      // outreach the domain index.\n      _currentIndex = _currentIndex == 0 ? NO_SELECTION : _currentIndex - 1;\n    }\n\n    _doNavigate(_currentIndex);\n\n    return true;\n  }\n\n  @protected\n  bool handleNextDomain() {\n    // Lazily initialize selection domains when a key is pressed after a draw.\n    if (_datumPairs == null) {\n      _generateSelectionDomains();\n    }\n\n    final domainsLength = _datumPairs!.length;\n    if (domainsLength == 0) {\n      return false;\n    }\n\n    _currentIndex = _getActiveHoverDomainIndex();\n\n    // Navigate to the first domain when current index is NO_SELECTION.\n    if (_currentIndex == NO_SELECTION) {\n      _currentIndex = 0;\n    } else {\n      // Set to NO_SELECTION when the next index would outreach the domains.\n      _currentIndex =\n          _currentIndex == domainsLength - 1 ? NO_SELECTION : _currentIndex + 1;\n    }\n\n    _doNavigate(_currentIndex);\n\n    return true;\n  }\n\n  /// Triggers when the left or right arrow keys are pressed.\n  void _doNavigate(int domainIndex) {\n    _selectDomainIndex(SelectionModelType.info, domainIndex);\n  }\n\n  /// Triggers when the Enter or Space key is pressed.\n  void selectDomain(int domainIndex) {\n    _selectDomainIndex(SelectionModelType.action, domainIndex);\n  }\n\n  /// Triggers when the Escape key is pressed or the chart loses focus.\n  void clearSelection() {\n    _selectDomainIndex(SelectionModelType.info, NO_SELECTION);\n  }\n\n  /// Updates the selection of the attached chart with the data at the given\n  /// domain index. If the chart doesn't support the given model, this is a\n  /// no-op.\n  @protected\n  bool _selectDomainIndex(\n      SelectionModelType selectionModelType, int domainIndex) {\n    final selectionModel = _chart.getSelectionModel(selectionModelType);\n    if (selectionModel == null) {\n      return false;\n    }\n\n    if (domainIndex == NO_SELECTION) {\n      selectionModel.clearSelection();\n    } else {\n      final datumPairs = _getDatumPairs(domainIndex);\n\n      final seriesDatumList = <SeriesDatum<D>>[];\n      final seriesList = <MutableSeries<D>>[];\n\n      for (final seriesDatum in datumPairs) {\n        seriesDatumList\n            .add(SeriesDatum<D>(seriesDatum.series, seriesDatum.datum));\n\n        if (!seriesList.contains(seriesDatum.series)) {\n          seriesList.add(seriesDatum.series as MutableSeries<D>);\n        }\n      }\n\n      selectionModel.updateSelection(seriesDatumList, seriesList);\n    }\n\n    return true;\n  }\n\n  /// Reads the current active index of the hover selection.\n  int _getActiveHoverDomainIndex() {\n    // If enter is pressed before an arrow key, we don't have any selection\n    // domains available. Bail out.\n    final _domains = this._domains;\n    if (_domains == null || _domains.isEmpty) {\n      return NO_SELECTION;\n    }\n\n    final selectionModel = _chart.getSelectionModel(SelectionModelType.info);\n\n    if (!selectionModel.hasAnySelection) {\n      return NO_SELECTION;\n    }\n\n    final details = _chart.getSelectedDatumDetails(SelectionModelType.info);\n\n    if (details.isEmpty) {\n      return NO_SELECTION;\n    }\n\n    // If the currentIndex is the same as the firstSelectedDetail we don't have\n    // to do a linear seach to find the domain.\n    final firstDomain = details.first.domain!;\n\n    if (0 <= _currentIndex &&\n        _currentIndex <= _domains.length - 1 &&\n        _domains[_currentIndex] == firstDomain) {\n      return _currentIndex;\n    }\n\n    return _domains.indexOf(firstDomain);\n  }\n\n  /// Processes chart data and generates a mapping of domain index to datum\n  /// details at that domain.\n  void _generateSelectionDomains() {\n    _domains = <D>[];\n\n    final allSeriesDatum = _chart.getAllDatumDetails();\n\n    if (_chart is CartesianChart) {\n      final localChart = _chart as CartesianChart;\n      if (localChart.vertical) {\n        allSeriesDatum.sort((a, b) {\n          if (a.chartPosition!.x == b.chartPosition!.x) {\n            return a.series!.seriesIndex.compareTo(b.series!.seriesIndex);\n          }\n          return a.chartPosition!.x!.compareTo(b.chartPosition!.x!);\n        });\n      } else {\n        allSeriesDatum.sort((a, b) {\n          if (a.chartPosition!.y == b.chartPosition!.y) {\n            return a.series!.seriesIndex.compareTo(b.series!.seriesIndex);\n          }\n          return a.chartPosition!.y!.compareTo(b.chartPosition!.y!);\n        });\n      }\n    }\n\n    final detailsByDomain = <D, List<SeriesDatum<D>>>{};\n    for (final datumDetails in allSeriesDatum) {\n      // The hovercard is closed when the closest detail has a null measure.\n      // Also, on hovercard close the current selection is cleared, so unless\n      // the details with null measure are skipped, the next domain visited\n      // after a datum with null measure will always be the first one, making\n      // all data after a datum with null measure not accessible by keyboard.\n      // LINT.IfChange\n      if (datumDetails.measure != null) {\n        final domain = datumDetails.domain!;\n\n        if (detailsByDomain[domain] == null) {\n          _domains!.add(domain);\n          detailsByDomain[domain] = [];\n        }\n\n        detailsByDomain[domain]!\n            .add(SeriesDatum<D>(datumDetails.series!, datumDetails.datum));\n      }\n      // LINT.ThenChange(//depot/google3/third_party/dart/charts_web/lib/src/common/behaviors/hovercard/hovercard.dart)\n    }\n\n    _datumPairs = <int, List<SeriesDatum<D>>>{};\n\n    var i = 0;\n    detailsByDomain.forEach((key, value) {\n      _datumPairs!.putIfAbsent(i, () => value);\n      i++;\n    });\n\n    _currentIndex = NO_SELECTION;\n  }\n\n  /// Gets the datum/series pairs for the given domainIndex.\n  List<SeriesDatum<D>> _getDatumPairs(int domainIndex) =>\n      _datumPairs![domainIndex] ?? <SeriesDatum<D>>[];\n\n  @override\n  String get role => 'keyboard-domain-navigator';\n}\n\nconst NO_SELECTION = -1;\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/common/behavior/calculation/percent_injector.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport '../../../../data/series.dart' show AttributeKey;\nimport '../../base_chart.dart' show BaseChart, LifecycleListener;\nimport '../../behavior/chart_behavior.dart' show ChartBehavior;\nimport '../../processed_series.dart' show MutableSeries;\n\nconst percentInjectedKey =\n    AttributeKey<bool>('PercentInjector.percentInjected');\n\n/// Chart behavior that can inject series or domain percentages into each datum.\n///\n/// [totalType] configures the type of total to be calculated.\n///\n/// The measure values of each datum will be replaced by the percent of the\n/// total measure value that each represents. The \"raw\" measure accessor\n/// function on [MutableSeries] can still be used to get the original values.\n///\n/// Note that the results for measureLowerBound and measureUpperBound are not\n/// currently well defined when converted into percentage values. This behavior\n/// will replace them as percents to prevent bad axis results, but no effort is\n/// made to bound them to within a \"0 to 100%\" data range.\n///\n/// Note that if the chart has a [Legend] that is capable of hiding series data,\n/// then this behavior must be added after the [Legend] to ensure that it\n/// calculates values after series have been potentially removed from the list.\nclass PercentInjector<D> implements ChartBehavior<D> {\n  late final LifecycleListener<D> _lifecycleListener;\n\n  /// The type of data total to be calculated.\n  final PercentInjectorTotalType totalType;\n\n  /// Constructs a [PercentInjector].\n  ///\n  /// [totalType] configures the type of data total to be calculated.\n  PercentInjector({this.totalType = PercentInjectorTotalType.domain}) {\n    // Set up chart draw cycle listeners.\n    _lifecycleListener =\n        LifecycleListener<D>(onPreprocess: _preProcess, onData: _onData);\n  }\n\n  @override\n  void attachTo(BaseChart<D> chart) {\n    chart.addLifecycleListener(_lifecycleListener);\n  }\n\n  @override\n  void removeFrom(BaseChart<D> chart) {\n    chart.removeLifecycleListener(_lifecycleListener);\n  }\n\n  /// Resets the state of the behavior when new data is drawn on the chart.\n  void _onData(List<MutableSeries<D>> seriesList) {\n    // Reset tracking of percentage injection for new data.\n    seriesList.forEach((series) {\n      series.setAttr(percentInjectedKey, false);\n    });\n  }\n\n  /// Injects percent of domain and/or series accessor functions into each\n  /// series.\n  ///\n  /// These are injected in the preProcess phase in case other behaviors modify\n  /// the [seriesList] between chart redraws.\n  void _preProcess(List<MutableSeries<D>> seriesList) {\n    var percentInjected = true;\n    seriesList.forEach((series) {\n      percentInjected = percentInjected && series.getAttr(percentInjectedKey)!;\n    });\n\n    if (percentInjected) {\n      return;\n    }\n\n    switch (totalType) {\n      case PercentInjectorTotalType.domain:\n      case PercentInjectorTotalType.domainBySeriesCategory:\n        final totalsByDomain = <String, num>{};\n\n        final useSeriesCategory =\n            totalType == PercentInjectorTotalType.domainBySeriesCategory;\n\n        // Walk the series and compute the domain total. Series total is\n        // automatically computed by [MutableSeries].\n        for (final series in seriesList) {\n          final seriesCategory = series.seriesCategory;\n          final rawMeasureFn = series.rawMeasureFn;\n          final domainFn = series.domainFn;\n\n          for (var index = 0; index < series.data.length; index++) {\n            final domain = domainFn(index);\n            var measure = rawMeasureFn(index) ?? 0.0;\n\n            final key =\n                useSeriesCategory ? '${seriesCategory}__$domain' : '$domain';\n\n            totalsByDomain[key] = (totalsByDomain[key] ?? 0.0) + measure;\n          }\n\n          // Add percent of domain and series accessor functions.\n          //\n          // Replace the default measure accessor with one that computes the\n          // percentage.\n          series.measureFn = (int? index) {\n            final measure = rawMeasureFn(index);\n\n            if (measure == null || measure == 0.0) {\n              return 0.0;\n            }\n\n            final domain = domainFn(index);\n\n            final key = useSeriesCategory\n                ? '${series.seriesCategory}__$domain'\n                : '$domain';\n\n            return measure / totalsByDomain[key]!;\n          };\n\n          // Replace the default measure lower bound accessor with one that\n          // computes the  percentage.\n          if (series.measureLowerBoundFn != null) {\n            series.measureLowerBoundFn = (int? index) {\n              final measureLowerBound = series.rawMeasureLowerBoundFn!(index);\n\n              if (measureLowerBound == null || measureLowerBound == 0.0) {\n                return 0.0;\n              }\n\n              final domain = domainFn(index);\n\n              final key = useSeriesCategory\n                  ? '${series.seriesCategory}__$domain'\n                  : '$domain';\n\n              return measureLowerBound / totalsByDomain[key]!;\n            };\n          }\n\n          // Replace the default measure upper bound accessor with one that\n          // computes the  percentage.\n          if (series.measureUpperBoundFn != null) {\n            series.measureUpperBoundFn = (int? index) {\n              final measureUpperBound = series.rawMeasureUpperBoundFn!(index);\n\n              if (measureUpperBound == null || measureUpperBound == 0.0) {\n                return 0.0;\n              }\n\n              final domain = domainFn(index);\n\n              final key = useSeriesCategory\n                  ? '${series.seriesCategory}__$domain'\n                  : '$domain';\n\n              return measureUpperBound / totalsByDomain[key]!;\n            };\n          }\n\n          series.setAttr(percentInjectedKey, true);\n        }\n\n        break;\n\n      case PercentInjectorTotalType.series:\n        seriesList.forEach((series) {\n          // Replace the default measure accessor with one that computes the\n          // percentage.\n          series.measureFn = (int? index) =>\n              series.rawMeasureFn(index)! / series.seriesMeasureTotal;\n\n          // Replace the default measure lower bound accessor with one that\n          // computes the  percentage.\n          if (series.measureLowerBoundFn != null) {\n            series.measureLowerBoundFn = (int? index) =>\n                (series.rawMeasureLowerBoundFn!(index) ?? 0) /\n                series.seriesMeasureTotal;\n          }\n\n          // Replace the default measure upper bound accessor with one that\n          // computes the  percentage.\n          if (series.measureUpperBoundFn != null) {\n            series.measureUpperBoundFn = (int? index) =>\n                (series.rawMeasureUpperBoundFn!(index) ?? 0) /\n                series.seriesMeasureTotal;\n          }\n\n          series.setAttr(percentInjectedKey, true);\n        });\n\n        break;\n\n      default:\n        throw ArgumentError('Unsupported totalType: ${totalType}');\n    }\n  }\n\n  @override\n  String get role => 'PercentInjector';\n}\n\n/// Describes the type of data total that will be calculated by PercentInjector.\n///\n/// [domain] calculates the percentage of each datum's measure value out of the\n/// total measure values for all data that share the same domain value.\n///\n/// [domainBySeriesCategory] calculates the percentage of each datum's measure\n/// value out of the total measure values for all data that share the same\n/// domain value and seriesCategory value. This should be enabled if the data\n/// will be rendered by a series renderer that groups data by both domain and\n/// series category, such as the \"grouped stacked\" mode of [BarRenderer].\n///\n/// [series] calculates the percentage of each datum's measure value out of the\n/// total measure values for all data in that datum's series.\nenum PercentInjectorTotalType { domain, domainBySeriesCategory, series }\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/common/behavior/chart_behavior.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport '../base_chart.dart';\n\n/// Interface for adding behavior to a chart.\n///\n/// For example pan and zoom are implemented via behavior strategies.\nabstract class ChartBehavior<D> {\n  String get role;\n\n  /// Injects the behavior into a chart.\n  void attachTo(BaseChart<D> chart);\n\n  /// Removes the behavior from a chart.\n  void removeFrom(BaseChart<D> chart);\n}\n\n/// Position of a component within the chart layout.\n///\n/// Outside positions are [top], [bottom], [start], and [end].\n///\n/// [top] component positioned at the top, with the chart positioned below the\n/// component and height reduced by the height of the component.\n/// [bottom] component positioned below the chart, and the chart's height is\n/// reduced by the height of the component.\n/// [start] component is positioned at the left of the chart (or the right if\n/// RTL), the chart's width is reduced by the width of the component.\n/// [end] component is positioned at the right of the chart (or the left if\n/// RTL), the chart's width is reduced by the width of the component.\n/// [inside] component is layered on top of the chart.\nenum BehaviorPosition {\n  top,\n  bottom,\n  start,\n  end,\n  inside,\n}\n\n/// Justification for components positioned outside [BehaviorPosition].\nenum OutsideJustification {\n  startDrawArea,\n  start,\n  middleDrawArea,\n  middle,\n  endDrawArea,\n  end,\n}\n\n/// Justification for components positioned [BehaviorPosition.inside].\nenum InsideJustification {\n  topStart,\n  topEnd,\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/common/behavior/chart_title/chart_title.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math';\n\nimport '../../../../common/graphics_factory.dart' show GraphicsFactory;\nimport '../../../../common/style/style_factory.dart' show StyleFactory;\nimport '../../../../common/text_element.dart'\n    show MaxWidthStrategy, TextDirection, TextElement;\nimport '../../../../common/text_style.dart' show TextStyle;\nimport '../../../cartesian/axis/spec/axis_spec.dart' show TextStyleSpec;\nimport '../../../layout/layout_view.dart'\n    show\n        LayoutPosition,\n        LayoutView,\n        LayoutViewConfig,\n        LayoutViewPaintOrder,\n        layoutPosition,\n        LayoutViewPositionOrder,\n        ViewMeasuredSizes;\nimport '../../base_chart.dart' show BaseChart, LifecycleListener;\nimport '../../behavior/chart_behavior.dart'\n    show BehaviorPosition, ChartBehavior, OutsideJustification;\nimport '../../chart_canvas.dart' show ChartCanvas;\n\n/// Chart behavior that adds title text to a chart. An optional second line of\n/// text may be rendered as a sub-title.\n///\n/// Titles will by default be rendered as the outermost component in the chart\n/// margin.\nclass ChartTitle<D> implements ChartBehavior<D> {\n  static const _defaultBehaviorPosition = BehaviorPosition.top;\n  static const _defaultMaxWidthStrategy = MaxWidthStrategy.ellipsize;\n  static const _defaultTitleDirection = ChartTitleDirection.auto;\n  static const _defaultTitleOutsideJustification = OutsideJustification.middle;\n  static final _defaultTitleStyle =\n      TextStyleSpec(fontSize: 18, color: StyleFactory.style.tickColor);\n  static final _defaultSubTitleStyle =\n      TextStyleSpec(fontSize: 14, color: StyleFactory.style.tickColor);\n  static const _defaultInnerPadding = 10;\n  static const _defaultTitlePadding = 18;\n  static const _defaultOuterPadding = 10;\n\n  /// Stores all of the configured properties of the behavior.\n  final _ChartTitleConfig _config;\n\n  BaseChart<D>? _chart;\n\n  _ChartTitleLayoutView<D>? _view;\n\n  late final LifecycleListener<D> _lifecycleListener;\n\n  /// Constructs a [ChartTitle].\n  ///\n  /// [title] contains the text for the chart title.\n  ChartTitle(String title,\n      {BehaviorPosition? behaviorPosition,\n      int? innerPadding,\n      int? layoutMinSize,\n      int? layoutPreferredSize,\n      int? outerPadding,\n      MaxWidthStrategy? maxWidthStrategy,\n      ChartTitleDirection? titleDirection,\n      OutsideJustification? titleOutsideJustification,\n      int? titlePadding,\n      TextStyleSpec? titleStyleSpec,\n      String? subTitle,\n      TextStyleSpec? subTitleStyleSpec})\n      : _config = _ChartTitleConfig(\n          behaviorPosition: behaviorPosition ?? _defaultBehaviorPosition,\n          innerPadding: innerPadding ?? _defaultInnerPadding,\n          layoutMinSize: layoutMinSize,\n          layoutPreferredSize: layoutPreferredSize,\n          outerPadding: outerPadding ?? _defaultOuterPadding,\n          maxWidthStrategy: maxWidthStrategy ?? _defaultMaxWidthStrategy,\n          title: title,\n          titleDirection: titleDirection ?? _defaultTitleDirection,\n          titleOutsideJustification:\n              titleOutsideJustification ?? _defaultTitleOutsideJustification,\n          titlePadding: titlePadding ?? _defaultTitlePadding,\n          titleStyleSpec: titleStyleSpec ?? _defaultTitleStyle,\n          subTitle: subTitle,\n          subTitleStyleSpec: subTitleStyleSpec ?? _defaultSubTitleStyle,\n        ) {\n    _lifecycleListener =\n        LifecycleListener<D>(onAxisConfigured: _updateViewData);\n  }\n\n  /// Layout position for the title.\n  BehaviorPosition get behaviorPosition => _config.behaviorPosition;\n\n  set behaviorPosition(BehaviorPosition behaviorPosition) {\n    _config.behaviorPosition = behaviorPosition;\n  }\n\n  /// Minimum size of the legend component. Optional.\n  ///\n  /// If the legend is positioned in the top or bottom margin, then this\n  /// configures the legend's height. If positioned in the start or end\n  /// position, this configures the legend's width.\n  int? get layoutMinSize => _config.layoutMinSize;\n\n  set layoutMinSize(int? layoutMinSize) {\n    _config.layoutMinSize = layoutMinSize;\n  }\n\n  /// Preferred size of the legend component. Defaults to 0.\n  ///\n  /// If the legend is positioned in the top or bottom margin, then this\n  /// configures the legend's height. If positioned in the start or end\n  /// position, this configures the legend's width.\n  int? get layoutPreferredSize => _config.layoutPreferredSize;\n\n  set layoutPreferredSize(int? layoutPreferredSize) {\n    _config.layoutPreferredSize = layoutPreferredSize;\n  }\n\n  /// Strategy for handling title text that is too large to fit. Defaults to\n  /// truncating the text with ellipses.\n  MaxWidthStrategy get maxWidthStrategy => _config.maxWidthStrategy;\n\n  set maxWidthStrategy(MaxWidthStrategy maxWidthStrategy) {\n    _config.maxWidthStrategy = maxWidthStrategy;\n  }\n\n  /// Primary text for the title.\n  String get title => _config.title;\n\n  set title(String title) {\n    _config.title = title;\n  }\n\n  /// Direction of the chart title text.\n  ///\n  /// This defaults to horizontal for a title in the top or bottom\n  /// [behaviorPosition], or vertical for start or end [behaviorPosition].\n  ChartTitleDirection get titleDirection => _config.titleDirection;\n\n  set titleDirection(ChartTitleDirection titleDirection) {\n    _config.titleDirection = titleDirection;\n  }\n\n  /// Justification of the title text if it is positioned outside of the draw\n  /// area.\n  OutsideJustification get titleOutsideJustification =>\n      _config.titleOutsideJustification;\n\n  set titleOutsideJustification(\n      OutsideJustification titleOutsideJustification) {\n    _config.titleOutsideJustification = titleOutsideJustification;\n  }\n\n  /// Space between the title and sub-title text, if defined.\n  ///\n  /// This padding is not used if no sub-title is provided.\n  int get titlePadding => _config.titlePadding;\n\n  set titlePadding(int titlePadding) {\n    _config.titlePadding = titlePadding;\n  }\n\n  /// Style of the [title] text.\n  TextStyleSpec get titleStyleSpec => _config.titleStyleSpec;\n\n  set titleStyleSpec(TextStyleSpec titleStyleSpec) {\n    _config.titleStyleSpec = titleStyleSpec;\n  }\n\n  /// Secondary text for the sub-title.\n  ///\n  /// [subTitle] is rendered on a second line below the [title], and may be\n  /// styled differently.\n  String? get subTitle => _config.subTitle;\n\n  set subTitle(String? subTitle) {\n    _config.subTitle = subTitle;\n  }\n\n  /// Style of the [subTitle] text.\n  TextStyleSpec get subTitleStyleSpec => _config.subTitleStyleSpec;\n\n  set subTitleStyleSpec(TextStyleSpec subTitleStyleSpec) {\n    _config.subTitleStyleSpec = subTitleStyleSpec;\n  }\n\n  /// Space between the \"inside\" of the chart, and the title behavior itself.\n  ///\n  /// This padding is applied to all the edge of the title that is in the\n  /// direction of the draw area. For a top positioned title, this is applied\n  /// to the bottom edge. [outerPadding] is applied to the top, left, and right\n  /// edges.\n  ///\n  /// If a sub-title is defined, this is the space between the sub-title text\n  /// and the inside of the chart. Otherwise, it is the space between the title\n  /// text and the inside of chart.\n  int get innerPadding => _config.innerPadding;\n\n  set innerPadding(int innerPadding) {\n    _config.innerPadding = innerPadding;\n  }\n\n  /// Space between the \"outside\" of the chart, and the title behavior itself.\n  ///\n  /// This padding is applied to all 3 edges of the title that are not in the\n  /// direction of the draw area. For a top positioned title, this is applied\n  /// to the top, left, and right edges. [innerPadding] is applied to the\n  /// bottom edge.\n  int get outerPadding => _config.outerPadding;\n\n  set outerPadding(int outerPadding) {\n    _config.outerPadding = outerPadding;\n  }\n\n  @override\n  void attachTo(BaseChart<D> chart) {\n    _chart = chart;\n\n    _view = _ChartTitleLayoutView<D>(\n        layoutPaintOrder: LayoutViewPaintOrder.chartTitle,\n        config: _config,\n        chart: _chart);\n\n    chart.addView(_view!);\n    chart.addLifecycleListener(_lifecycleListener);\n  }\n\n  @override\n  void removeFrom(BaseChart<D> chart) {\n    chart.removeView(_view!);\n    chart.removeLifecycleListener(_lifecycleListener);\n    _chart = null;\n  }\n\n  void _updateViewData() {\n    _view!.config = _config;\n  }\n\n  @override\n  String get role => 'ChartTitle-${_config.behaviorPosition}';\n\n  bool get isRtl => _chart!.context.isRtl;\n}\n\n/// Layout view component for [ChartTitle].\nclass _ChartTitleLayoutView<D> extends LayoutView {\n  late final LayoutViewConfig _layoutConfig;\n\n  @override\n  LayoutViewConfig get layoutConfig => _layoutConfig;\n\n  /// Stores all of the configured properties of the behavior.\n  _ChartTitleConfig _config;\n\n  BaseChart<D>? chart;\n\n  bool get isRtl => chart?.context.isRtl ?? false;\n\n  late Rectangle<int> _componentBounds;\n  late Rectangle<int> _drawAreaBounds;\n\n  @override\n  GraphicsFactory? graphicsFactory;\n\n  /// Cached layout element for the title text.\n  ///\n  /// This is used to prevent expensive Flutter painter layout calls on every\n  /// animation frame during the paint cycle. It should never be cached during\n  /// layout measurement.\n  TextElement? _titleTextElement;\n\n  /// Cached layout element for the sub-title text.\n  ///\n  /// This is used to prevent expensive Flutter painter layout calls on every\n  /// animation frame during the paint cycle. It should never be cached during\n  /// layout measurement.\n  TextElement? _subTitleTextElement;\n\n  _ChartTitleLayoutView(\n      {required int layoutPaintOrder,\n      required _ChartTitleConfig config,\n      required this.chart})\n      : _config = config {\n    // Set inside body to resolve [_layoutPosition].\n    _layoutConfig = LayoutViewConfig(\n        paintOrder: layoutPaintOrder,\n        position: _layoutPosition,\n        positionOrder: LayoutViewPositionOrder.chartTitle);\n  }\n\n  /// Sets the configuration for the title behavior.\n  set config(_ChartTitleConfig config) {\n    _config = config;\n    layoutConfig.position = _layoutPosition;\n  }\n\n  @override\n  ViewMeasuredSizes measure(int maxWidth, int maxHeight) {\n    int? minWidth;\n    int? minHeight;\n    var preferredWidth = 0;\n    var preferredHeight = 0;\n\n    // Always assume that we need outer padding and title padding, but only add\n    // in the sub-title padding if we have one. Title is required, but sub-title\n    // is optional.\n    final totalPadding = _config.outerPadding +\n        _config.innerPadding +\n        (_config.subTitle != null ? _config.titlePadding : 0.0);\n\n    final graphicsFactory = this.graphicsFactory!;\n\n    // Create [TextStyle] from [TextStyleSpec] to be used by all the elements.\n    // The [GraphicsFactory] is needed so it can't be created earlier.\n    final textStyle = _getTextStyle(graphicsFactory, _config.titleStyleSpec);\n\n    final textElement = graphicsFactory.createTextElement(_config.title)\n      ..maxWidthStrategy = _config.maxWidthStrategy\n      ..textStyle = textStyle;\n\n    final subTitleTextStyle =\n        _getTextStyle(graphicsFactory, _config.subTitleStyleSpec);\n\n    final subTitleTextElement = _config.subTitle == null\n        ? null\n        : (graphicsFactory.createTextElement(_config.subTitle!)\n          ..maxWidthStrategy = _config.maxWidthStrategy\n          ..textStyle = subTitleTextStyle);\n\n    final resolvedTitleDirection = _resolvedTitleDirection;\n\n    switch (_config.behaviorPosition) {\n      case BehaviorPosition.bottom:\n      case BehaviorPosition.top:\n        final textHeight =\n            (resolvedTitleDirection == ChartTitleDirection.vertical\n                    ? textElement.measurement.horizontalSliceWidth\n                    : textElement.measurement.verticalSliceWidth)\n                .round();\n\n        final subTitleTextHeight = subTitleTextElement != null\n            ? (resolvedTitleDirection == ChartTitleDirection.vertical\n                    ? subTitleTextElement.measurement.horizontalSliceWidth\n                    : subTitleTextElement.measurement.verticalSliceWidth)\n                .round()\n            : 0;\n\n        final measuredHeight =\n            (textHeight + subTitleTextHeight + totalPadding).round();\n        minHeight = _config.layoutMinSize != null\n            ? min(_config.layoutMinSize!, measuredHeight)\n            : measuredHeight;\n\n        preferredWidth = maxWidth;\n\n        preferredHeight = _config.layoutPreferredSize != null\n            ? min(_config.layoutPreferredSize!, maxHeight)\n            : measuredHeight;\n        break;\n\n      case BehaviorPosition.end:\n      case BehaviorPosition.start:\n        final textWidth =\n            (resolvedTitleDirection == ChartTitleDirection.vertical\n                    ? textElement.measurement.verticalSliceWidth\n                    : textElement.measurement.horizontalSliceWidth)\n                .round();\n\n        final subTitleTextWidth = subTitleTextElement != null\n            ? (resolvedTitleDirection == ChartTitleDirection.vertical\n                    ? subTitleTextElement.measurement.verticalSliceWidth\n                    : subTitleTextElement.measurement.horizontalSliceWidth)\n                .round()\n            : 0;\n\n        final measuredWidth =\n            (textWidth + subTitleTextWidth + totalPadding).round();\n        minWidth = _config.layoutMinSize != null\n            ? min(_config.layoutMinSize!, measuredWidth)\n            : measuredWidth;\n\n        preferredWidth = _config.layoutPreferredSize != null\n            ? min(_config.layoutPreferredSize!, maxWidth)\n            : measuredWidth;\n\n        preferredHeight = maxHeight;\n        break;\n\n      case BehaviorPosition.inside:\n        preferredWidth = _drawAreaBounds != null\n            ? min(_drawAreaBounds.width, maxWidth)\n            : maxWidth;\n\n        preferredHeight = _drawAreaBounds != null\n            ? min(_drawAreaBounds.height, maxHeight)\n            : maxHeight;\n        break;\n    }\n\n    // Reset the cached text elements used during the paint step.\n    _resetTextElementCache();\n\n    return ViewMeasuredSizes(\n        minWidth: minWidth,\n        minHeight: minHeight,\n        preferredWidth: preferredWidth,\n        preferredHeight: preferredHeight);\n  }\n\n  @override\n  void layout(Rectangle<int> componentBounds, Rectangle<int> drawAreaBounds) {\n    _componentBounds = componentBounds;\n    _drawAreaBounds = drawAreaBounds;\n\n    // Reset the cached text elements used during the paint step.\n    _resetTextElementCache();\n  }\n\n  @override\n  void paint(ChartCanvas canvas, double animationPercent) {\n    final resolvedTitleDirection = _resolvedTitleDirection;\n\n    var titleHeight = 0.0;\n    var subTitleHeight = 0.0;\n\n    // First, measure the height of the title and sub-title.\n    if (_config.title != null) {\n      // Chart titles do not animate. As an optimization for Flutter, cache the\n      // [TextElement] to avoid an expensive painter layout operation on\n      // subsequent animation frames.\n      if (_titleTextElement == null) {\n        // Create [TextStyle] from [TextStyleSpec] to be used by all the\n        // elements. The [GraphicsFactory] is needed so it can't be created\n        // earlier.\n        final textStyle =\n            _getTextStyle(graphicsFactory!, _config.titleStyleSpec);\n\n        _titleTextElement = graphicsFactory!.createTextElement(_config.title)\n          ..maxWidthStrategy = _config.maxWidthStrategy\n          ..textStyle = textStyle;\n\n        _titleTextElement!.maxWidth =\n            resolvedTitleDirection == ChartTitleDirection.horizontal\n                ? _componentBounds.width\n                : _componentBounds.height;\n      }\n\n      // Get the height of the title so that we can off-set both text elements.\n      titleHeight = _titleTextElement!.measurement.verticalSliceWidth;\n    }\n\n    if (_config.subTitle != null) {\n      // Chart titles do not animate. As an optimization for Flutter, cache the\n      // [TextElement] to avoid an expensive painter layout operation on\n      // subsequent animation frames.\n      if (_subTitleTextElement == null) {\n        // Create [TextStyle] from [TextStyleSpec] to be used by all the\n        // elements. The [GraphicsFactory] is needed so it can't be created\n        // earlier.\n        final textStyle =\n            _getTextStyle(graphicsFactory!, _config.subTitleStyleSpec);\n\n        _subTitleTextElement =\n            graphicsFactory!.createTextElement(_config.subTitle!)\n              ..maxWidthStrategy = _config.maxWidthStrategy\n              ..textStyle = textStyle;\n\n        _subTitleTextElement!.maxWidth =\n            resolvedTitleDirection == ChartTitleDirection.horizontal\n                ? _componentBounds.width\n                : _componentBounds.height;\n      }\n\n      // Get the height of the sub-title so that we can off-set both text\n      // elements.\n      subTitleHeight = _subTitleTextElement!.measurement.verticalSliceWidth;\n    }\n\n    // Draw a title if the text is not empty.\n    if (_config.title != null) {\n      final labelPoint = _getLabelPosition(\n          true,\n          _componentBounds,\n          resolvedTitleDirection,\n          _titleTextElement!,\n          titleHeight,\n          subTitleHeight);\n\n      if (labelPoint != null) {\n        final rotation = resolvedTitleDirection == ChartTitleDirection.vertical\n            ? -pi / 2\n            : 0.0;\n\n        canvas.drawText(_titleTextElement!, labelPoint.x, labelPoint.y,\n            rotation: rotation);\n      }\n    }\n\n    // Draw a sub-title if the text is not empty.\n    if (_config.subTitle != null) {\n      final labelPoint = _getLabelPosition(\n          false,\n          _componentBounds,\n          resolvedTitleDirection,\n          _subTitleTextElement!,\n          titleHeight,\n          subTitleHeight);\n\n      if (labelPoint != null) {\n        final rotation = resolvedTitleDirection == ChartTitleDirection.vertical\n            ? -pi / 2\n            : 0.0;\n\n        canvas.drawText(_subTitleTextElement!, labelPoint.x, labelPoint.y,\n            rotation: rotation);\n      }\n    }\n  }\n\n  /// Resets the cached text elements used during the paint step.\n  void _resetTextElementCache() {\n    _titleTextElement = null;\n    _subTitleTextElement = null;\n  }\n\n  /// Get the direction of the title, resolving \"auto\" position into the\n  /// appropriate direction for the position of the behavior.\n  ChartTitleDirection get _resolvedTitleDirection {\n    var resolvedTitleDirection = _config.titleDirection;\n    if (resolvedTitleDirection == ChartTitleDirection.auto) {\n      switch (_config.behaviorPosition) {\n        case BehaviorPosition.bottom:\n        case BehaviorPosition.inside:\n        case BehaviorPosition.top:\n          resolvedTitleDirection = ChartTitleDirection.horizontal;\n          break;\n        case BehaviorPosition.end:\n        case BehaviorPosition.start:\n          resolvedTitleDirection = ChartTitleDirection.vertical;\n          break;\n      }\n    }\n\n    return resolvedTitleDirection;\n  }\n\n  /// Get layout position from chart title position.\n  LayoutPosition get _layoutPosition {\n    return layoutPosition(\n        _config.behaviorPosition, _config.titleOutsideJustification, isRtl);\n  }\n\n  /// Gets the resolved location for a label element.\n  Point<int>? _getLabelPosition(\n      bool isPrimaryTitle,\n      Rectangle<num> bounds,\n      ChartTitleDirection titleDirection,\n      TextElement textElement,\n      double titleHeight,\n      double subTitleHeight) {\n    switch (_config.behaviorPosition) {\n      case BehaviorPosition.bottom:\n      case BehaviorPosition.top:\n        return _getHorizontalLabelPosition(isPrimaryTitle, bounds,\n            titleDirection, textElement, titleHeight, subTitleHeight);\n\n      case BehaviorPosition.start:\n      case BehaviorPosition.end:\n        return _getVerticalLabelPosition(isPrimaryTitle, bounds, titleDirection,\n            textElement, titleHeight, subTitleHeight);\n\n      case BehaviorPosition.inside:\n        return null;\n    }\n  }\n\n  /// Gets the resolved location for a title in the top or bottom margin.\n  Point<int> _getHorizontalLabelPosition(\n      bool isPrimaryTitle,\n      Rectangle<num> bounds,\n      ChartTitleDirection titleDirection,\n      TextElement textElement,\n      double titleHeight,\n      double subTitleHeight) {\n    var labelX = 0;\n    var labelY = 0;\n\n    switch (_config.titleOutsideJustification) {\n      case OutsideJustification.middle:\n      case OutsideJustification.middleDrawArea:\n        final textWidth =\n            (isRtl ? 1 : -1) * textElement.measurement.horizontalSliceWidth / 2;\n        labelX = (bounds.left + bounds.width / 2 + textWidth).round();\n\n        textElement.textDirection =\n            isRtl ? TextDirection.rtl : TextDirection.ltr;\n        break;\n\n      case OutsideJustification.end:\n      case OutsideJustification.endDrawArea:\n      case OutsideJustification.start:\n      case OutsideJustification.startDrawArea:\n        final alignLeft = isRtl\n            ? (_config.titleOutsideJustification == OutsideJustification.end ||\n                _config.titleOutsideJustification ==\n                    OutsideJustification.endDrawArea)\n            : (_config.titleOutsideJustification ==\n                    OutsideJustification.start ||\n                _config.titleOutsideJustification ==\n                    OutsideJustification.startDrawArea);\n\n        // Don't apply outer padding if we are aligned to the draw area.\n        final padding = (_config.titleOutsideJustification ==\n                    OutsideJustification.endDrawArea ||\n                _config.titleOutsideJustification ==\n                    OutsideJustification.startDrawArea)\n            ? 0.0\n            : _config.outerPadding;\n\n        if (alignLeft) {\n          labelX = (bounds.left + padding).round();\n          textElement.textDirection = TextDirection.ltr;\n        } else {\n          labelX = (bounds.right - padding).round();\n          textElement.textDirection = TextDirection.rtl;\n        }\n        break;\n    }\n\n    // labelY is always relative to the component bounds.\n    if (_config.behaviorPosition == BehaviorPosition.bottom) {\n      final padding = _config.innerPadding +\n          (isPrimaryTitle ? 0 : _config.titlePadding + titleHeight);\n\n      labelY = (bounds.top + padding).round();\n    } else {\n      var padding = 0.0 + _config.innerPadding;\n      if (isPrimaryTitle) {\n        padding +=\n            (subTitleHeight > 0 ? _config.titlePadding + subTitleHeight : 0) +\n                titleHeight;\n      } else {\n        padding += subTitleHeight;\n      }\n\n      labelY = (bounds.bottom - padding).round();\n    }\n\n    return Point<int>(labelX, labelY);\n  }\n\n  /// Gets the resolved location for a title in the left or right margin.\n  Point<int> _getVerticalLabelPosition(\n      bool isPrimaryTitle,\n      Rectangle<num> bounds,\n      ChartTitleDirection titleDirection,\n      TextElement textElement,\n      double titleHeight,\n      double subTitleHeight) {\n    var labelX = 0;\n    var labelY = 0;\n\n    switch (_config.titleOutsideJustification) {\n      case OutsideJustification.middle:\n      case OutsideJustification.middleDrawArea:\n        final textWidth =\n            (isRtl ? -1 : 1) * textElement.measurement.horizontalSliceWidth / 2;\n        labelY = (bounds.top + bounds.height / 2 + textWidth).round();\n\n        textElement.textDirection =\n            isRtl ? TextDirection.rtl : TextDirection.ltr;\n        break;\n\n      case OutsideJustification.end:\n      case OutsideJustification.endDrawArea:\n      case OutsideJustification.start:\n      case OutsideJustification.startDrawArea:\n        final alignLeft = isRtl\n            ? (_config.titleOutsideJustification == OutsideJustification.end ||\n                _config.titleOutsideJustification ==\n                    OutsideJustification.endDrawArea)\n            : (_config.titleOutsideJustification ==\n                    OutsideJustification.start ||\n                _config.titleOutsideJustification ==\n                    OutsideJustification.startDrawArea);\n\n        // Don't apply outer padding if we are aligned to the draw area.\n        final padding = (_config.titleOutsideJustification ==\n                    OutsideJustification.endDrawArea ||\n                _config.titleOutsideJustification ==\n                    OutsideJustification.startDrawArea)\n            ? 0.0\n            : _config.outerPadding;\n\n        if (alignLeft) {\n          labelY = (bounds.bottom - padding).round();\n          textElement.textDirection = TextDirection.ltr;\n        } else {\n          labelY = (bounds.top + padding).round();\n          textElement.textDirection = TextDirection.rtl;\n        }\n        break;\n    }\n\n    // labelX is always relative to the component bounds.\n    if (_layoutPosition == LayoutPosition.Right ||\n        _layoutPosition == LayoutPosition.FullRight) {\n      final padding = _config.outerPadding +\n          (isPrimaryTitle ? 0 : _config.titlePadding + titleHeight);\n\n      labelX = (bounds.left + padding).round();\n    } else {\n      final padding = _config.outerPadding +\n          titleHeight +\n          (isPrimaryTitle\n              ? (subTitleHeight > 0 ? _config.titlePadding + subTitleHeight : 0)\n              : 0.0);\n\n      labelX = (bounds.right - padding).round();\n    }\n\n    return Point<int>(labelX, labelY);\n  }\n\n  // Helper function that converts [TextStyleSpec] to [TextStyle].\n  TextStyle _getTextStyle(\n      GraphicsFactory graphicsFactory, TextStyleSpec labelSpec) {\n    return graphicsFactory.createTextPaint()\n      ..color = labelSpec.color ?? StyleFactory.style.tickColor\n      ..fontFamily = labelSpec.fontFamily\n      ..fontSize = labelSpec.fontSize ?? 18\n      ..lineHeight = labelSpec.lineHeight;\n  }\n\n  @override\n  Rectangle<int> get componentBounds => _drawAreaBounds;\n\n  @override\n  bool get isSeriesRenderer => false;\n}\n\n/// Configuration object for [ChartTitle].\nclass _ChartTitleConfig {\n  _ChartTitleConfig({\n    required this.behaviorPosition,\n    required this.layoutMinSize,\n    required this.layoutPreferredSize,\n    required this.maxWidthStrategy,\n    required this.title,\n    required this.titleDirection,\n    required this.titleOutsideJustification,\n    required this.titleStyleSpec,\n    required this.subTitle,\n    required this.subTitleStyleSpec,\n    required this.innerPadding,\n    required this.titlePadding,\n    required this.outerPadding,\n  });\n\n  BehaviorPosition behaviorPosition;\n\n  int? layoutMinSize;\n  int? layoutPreferredSize;\n\n  MaxWidthStrategy maxWidthStrategy;\n\n  String title;\n  ChartTitleDirection titleDirection;\n  OutsideJustification titleOutsideJustification;\n  TextStyleSpec titleStyleSpec;\n\n  String? subTitle;\n  TextStyleSpec subTitleStyleSpec;\n\n  int innerPadding;\n  int titlePadding;\n  int outerPadding;\n}\n\n/// Direction of the title text on the chart.\nenum ChartTitleDirection {\n  /// Automatically assign a direction based on the [RangeAnnotationAxisType].\n  ///\n  /// [horizontal] for measure axes, or [vertical] for domain axes.\n  auto,\n\n  /// Text flows parallel to the x axis.\n  horizontal,\n\n  /// Text flows parallel to the y axis.\n  vertical,\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/common/behavior/domain_highlighter.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport '../base_chart.dart' show BaseChart, LifecycleListener;\nimport '../processed_series.dart' show MutableSeries;\nimport '../selection_model/selection_model.dart'\n    show SelectionModel, SelectionModelType;\nimport 'chart_behavior.dart' show ChartBehavior;\n\n/// Chart behavior that monitors the specified [SelectionModel] and darkens the\n/// color for selected data.\n///\n/// This is typically used for bars and pies to highlight segments.\n///\n/// It is used in combination with SelectNearest to update the selection model\n/// and expand selection out to the domain value.\nclass DomainHighlighter<D> implements ChartBehavior<D> {\n  final SelectionModelType selectionModelType;\n\n  late BaseChart<D> _chart;\n\n  late LifecycleListener<D> _lifecycleListener;\n\n  DomainHighlighter([this.selectionModelType = SelectionModelType.info]) {\n    _lifecycleListener =\n        LifecycleListener<D>(onPostprocess: _updateColorFunctions);\n  }\n\n  void _selectionChanged(SelectionModel<D> selectionModel) {\n    _chart.redraw(skipLayout: true, skipAnimation: true);\n  }\n\n  void _updateColorFunctions(List<MutableSeries<D>> seriesList) {\n    SelectionModel<D> selectionModel =\n        _chart.getSelectionModel(selectionModelType);\n    seriesList.forEach((MutableSeries<D> series) {\n      final origColorFn = series.colorFn;\n\n      if (origColorFn != null) {\n        series.colorFn = (int? index) {\n          final origColor = origColorFn(index);\n          if (selectionModel.isDatumSelected(series, index)) {\n            return origColor.darker;\n          } else {\n            return origColor;\n          }\n        };\n      }\n    });\n  }\n\n  @override\n  void attachTo(BaseChart<D> chart) {\n    _chart = chart;\n    chart.addLifecycleListener(_lifecycleListener);\n    chart\n        .getSelectionModel(selectionModelType)\n        .addSelectionChangedListener(_selectionChanged);\n  }\n\n  @override\n  void removeFrom(BaseChart<D> chart) {\n    chart\n        .getSelectionModel(selectionModelType)\n        .removeSelectionChangedListener(_selectionChanged);\n    chart.removeLifecycleListener(_lifecycleListener);\n  }\n\n  @override\n  String get role => 'domainHighlight-$selectionModelType';\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/common/behavior/domain_outliner.dart",
    "content": "// Copyright 2019 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'package:charts_common/src/chart/common/base_chart.dart';\nimport 'package:charts_common/src/chart/common/processed_series.dart';\nimport 'package:charts_common/src/chart/common/selection_model/selection_model.dart';\n\nimport 'chart_behavior.dart' show ChartBehavior;\n\n/// Chart behavior that monitors the specified [SelectionModel] and outlines the\n/// selected data.\n///\n/// This is typically used for treemap charts to highlight nodes.\n/// For bars and pies, prefers to use [DomainHighlighter] for UX consistency.\nclass DomainOutliner<D> implements ChartBehavior<D> {\n  final SelectionModelType selectionType;\n\n  /// Default stroke width of the outline if the series has no stroke width\n  /// function.\n  ///\n  /// When no stroke width function is provided, this value will be used as\n  /// is. [strokePaddingPx] will not be added to [defaultStrokePx].\n  final double defaultStrokePx;\n\n  /// Additional stroke width added to the outline of the selected data.\n  ///\n  /// This value is only used when the series has a stroke width function\n  /// defined.\n  final double strokePaddingPx;\n\n  late BaseChart<D> _chart;\n\n  late LifecycleListener<D> _lifecycleListener;\n\n  DomainOutliner({\n    this.selectionType = SelectionModelType.info,\n    double? defaultStrokePx,\n    double? strokePaddingPx,\n  })  : defaultStrokePx = defaultStrokePx ?? 2.0,\n        strokePaddingPx = strokePaddingPx ?? 1.0 {\n    _lifecycleListener = LifecycleListener<D>(onPostprocess: _outline);\n  }\n\n  void _selectionChange(SelectionModel<D> selectionModel) {\n    _chart.redraw(skipLayout: true, skipAnimation: true);\n  }\n\n  void _outline(List<MutableSeries<D>> seriesList) {\n    final selectionModel = _chart.getSelectionModel(selectionType);\n\n    for (var series in seriesList) {\n      final strokeWidthPxFn = series.strokeWidthPxFn;\n      final colorFn = series.colorFn;\n\n      if (colorFn != null) {\n        series.colorFn = (int? index) {\n          final color = colorFn(index);\n          return selectionModel.isDatumSelected(series, index)\n              ? color.darker\n              : color;\n        };\n      }\n\n      if (strokeWidthPxFn != null) {\n        series.strokeWidthPxFn = (int? index) {\n          final strokeWidthPx = strokeWidthPxFn(index);\n          if (!selectionModel.isDatumSelected(series, index)) {\n            return strokeWidthPx;\n          }\n          return strokeWidthPx == null\n              ? defaultStrokePx\n              : strokeWidthPx + strokePaddingPx;\n        };\n      }\n    }\n  }\n\n  @override\n  void attachTo(BaseChart<D> chart) {\n    _chart = chart;\n    chart.addLifecycleListener(_lifecycleListener);\n    chart\n        .getSelectionModel(selectionType)\n        .addSelectionChangedListener(_selectionChange);\n  }\n\n  @override\n  void removeFrom(BaseChart<D> chart) {\n    chart\n        .getSelectionModel(selectionType)\n        .removeSelectionChangedListener(_selectionChange);\n    chart.removeLifecycleListener(_lifecycleListener);\n  }\n\n  @override\n  String get role => 'domainOutliner-$selectionType';\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/common/behavior/initial_selection.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport '../base_chart.dart' show BaseChart, LifecycleListener;\nimport '../processed_series.dart' show MutableSeries;\nimport '../selection_model/selection_model.dart'\n    show SelectionModel, SelectionModelType;\nimport '../series_datum.dart' show SeriesDatumConfig;\nimport 'chart_behavior.dart' show ChartBehavior;\n\n/// Behavior that sets initial selection.\nclass InitialSelection<D> implements ChartBehavior<D> {\n  final SelectionModelType selectionModelType;\n\n  /// List of series id of initially selected series.\n  final List<String>? selectedSeriesConfig;\n\n  /// List of [SeriesDatumConfig] that represents the initially selected datums.\n  final List<SeriesDatumConfig<D>>? selectedDataConfig;\n\n  BaseChart<D>? _chart;\n  late LifecycleListener<D> _lifecycleListener;\n  bool _firstDraw = true;\n\n  // TODO : When the series changes, if the user does not also\n  // change the index the wrong item could be highlighted.\n  InitialSelection(\n      {this.selectionModelType = SelectionModelType.info,\n      this.selectedDataConfig,\n      this.selectedSeriesConfig}) {\n    _lifecycleListener = LifecycleListener<D>(onData: _setInitialSelection);\n  }\n\n  void _setInitialSelection(List<MutableSeries<D>> seriesList) {\n    if (!_firstDraw) {\n      return;\n    }\n    _firstDraw = false;\n\n    final immutableModel = SelectionModel<D>.fromConfig(\n        selectedDataConfig, selectedSeriesConfig, seriesList);\n\n    _chart!.getSelectionModel(selectionModelType).updateSelection(\n        immutableModel.selectedDatum, immutableModel.selectedSeries,\n        notifyListeners: false);\n  }\n\n  @override\n  void attachTo(BaseChart<D> chart) {\n    _chart = chart;\n    chart.addLifecycleListener(_lifecycleListener);\n  }\n\n  @override\n  void removeFrom(BaseChart<D> chart) {\n    chart.removeLifecycleListener(_lifecycleListener);\n    _chart = null;\n  }\n\n  @override\n  String get role => 'InitialSelection-$selectionModelType';\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/common/behavior/legend/datum_legend.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport '../../../cartesian/axis/spec/axis_spec.dart' show TextStyleSpec;\nimport '../../datum_details.dart' show MeasureFormatter;\nimport '../../selection_model/selection_model.dart' show SelectionModelType;\nimport 'legend.dart';\nimport 'legend_entry_generator.dart';\nimport 'per_datum_legend_entry_generator.dart';\n\n/// Datum legend behavior for charts.\n///\n/// By default this behavior creates one legend entry per datum in the first\n/// series rendered on the chart.\n///\n/// TODO: Allows for hovering over a datum in legend to highlight\n/// corresponding datum in draw area.\n///\n/// TODO: Implement tap to hide individual data in the series.\nclass DatumLegend<D> extends Legend<D> {\n  /// Whether or not the series legend should show measures on datum selection.\n  late bool _showMeasures;\n\n  DatumLegend({\n    SelectionModelType? selectionModelType,\n    LegendEntryGenerator<D>? legendEntryGenerator,\n    MeasureFormatter? measureFormatter,\n    MeasureFormatter? secondaryMeasureFormatter,\n    bool? showMeasures,\n    LegendDefaultMeasure? legendDefaultMeasure,\n    TextStyleSpec? entryTextStyle,\n  }) : super(\n            selectionModelType: selectionModelType ?? SelectionModelType.info,\n            legendEntryGenerator:\n                legendEntryGenerator ?? PerDatumLegendEntryGenerator(),\n            entryTextStyle: entryTextStyle) {\n    // Calling the setters will automatically use non-null default values.\n    this.showMeasures = showMeasures;\n    this.legendDefaultMeasure = legendDefaultMeasure;\n    this.measureFormatter = measureFormatter;\n    this.secondaryMeasureFormatter = secondaryMeasureFormatter;\n  }\n\n  /// Whether or not the legend should show measures.\n  ///\n  /// By default this is false, measures are not shown. When set to true, the\n  /// default behavior is to show measure only if there is selected data.\n  /// Please set [legendDefaultMeasure] to something other than none to enable\n  /// showing measures when there is no selection.\n  ///\n  /// If [showMeasures] is set to null, it is changed to the default of false.\n  bool get showMeasures => _showMeasures;\n\n  set showMeasures(bool? showMeasures) {\n    _showMeasures = showMeasures ?? false;\n  }\n\n  /// Option to show measures when selection is null.\n  ///\n  /// By default this is set to none, so no measures are shown when there is\n  /// no selection.\n  ///\n  /// If [legendDefaultMeasure] is set to null, it is changed to the default of\n  /// none.\n  LegendDefaultMeasure get legendDefaultMeasure =>\n      legendEntryGenerator.legendDefaultMeasure;\n\n  set legendDefaultMeasure(LegendDefaultMeasure? legendDefaultMeasure) {\n    legendEntryGenerator.legendDefaultMeasure =\n        legendDefaultMeasure ?? LegendDefaultMeasure.none;\n  }\n\n  /// Formatter for measure values.\n  ///\n  /// This is optional. The default formatter formats measure values with\n  /// NumberFormat.decimalPattern. If the measure value is null, a dash is\n  /// returned.\n  set measureFormatter(MeasureFormatter? formatter) {\n    legendEntryGenerator.measureFormatter =\n        formatter ?? defaultLegendMeasureFormatter;\n  }\n\n  /// Formatter for measure values of series that uses the secondary axis.\n  ///\n  /// This is optional. The default formatter formats measure values with\n  /// NumberFormat.decimalPattern. If the measure value is null, a dash is\n  /// returned.\n  set secondaryMeasureFormatter(MeasureFormatter? formatter) {\n    legendEntryGenerator.secondaryMeasureFormatter =\n        formatter ?? defaultLegendMeasureFormatter;\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/common/behavior/legend/legend.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math' show Rectangle;\n\nimport 'package:meta/meta.dart' show protected;\nimport 'package:intl/intl.dart';\n\nimport '../../../../common/graphics_factory.dart' show GraphicsFactory;\nimport '../../../cartesian/axis/spec/axis_spec.dart' show TextStyleSpec;\nimport '../../../layout/layout_view.dart'\n    show\n        LayoutPosition,\n        LayoutView,\n        LayoutViewConfig,\n        LayoutViewPositionOrder,\n        LayoutViewPaintOrder,\n        ViewMeasuredSizes,\n        layoutPosition;\nimport '../../base_chart.dart' show BaseChart, LifecycleListener;\nimport '../../chart_canvas.dart' show ChartCanvas;\nimport '../../chart_context.dart' show ChartContext;\nimport '../../processed_series.dart' show MutableSeries;\nimport '../../selection_model/selection_model.dart'\n    show SelectionModel, SelectionModelType;\nimport '../chart_behavior.dart'\n    show\n        BehaviorPosition,\n        ChartBehavior,\n        InsideJustification,\n        OutsideJustification;\nimport 'legend_entry.dart';\nimport 'legend_entry_generator.dart';\n\n/// Legend behavior for charts.\n///\n/// Since legends are desired to be customizable, building and displaying the\n/// visual content of legends is done on the native platforms. This allows users\n/// to specify customized content for legends using the native platform (ex. for\n/// Flutter, using widgets).\nabstract class Legend<D> implements ChartBehavior<D>, LayoutView {\n  final SelectionModelType selectionModelType;\n  final legendState = LegendState<D>();\n  final LegendEntryGenerator<D> legendEntryGenerator;\n\n  /// The title text to display before legend entries.\n  late String title;\n\n  late BaseChart<D> _chart;\n  late final LifecycleListener<D> _lifecycleListener;\n\n  Rectangle<int>? _componentBounds;\n  Rectangle<int>? _drawAreaBounds;\n\n  @override\n  GraphicsFactory? graphicsFactory;\n\n  BehaviorPosition behaviorPosition = BehaviorPosition.end;\n  OutsideJustification outsideJustification =\n      OutsideJustification.startDrawArea;\n  InsideJustification insideJustification = InsideJustification.topStart;\n  LegendCellPadding? cellPadding;\n  LegendCellPadding? legendPadding;\n\n  /// Text style of the legend title text.\n  TextStyleSpec? titleTextStyle;\n\n  /// Configures the behavior of the legend when the user taps/clicks on an\n  /// entry. Defaults to no behavior.\n  ///\n  /// Tapping on a legend entry will update the data visible on the chart. For\n  /// example, when [LegendTapHandling.hide] is configured, the series or datum\n  /// associated with that entry will be removed from the chart. Tapping on that\n  /// entry a second time will make the data visible again.\n  LegendTapHandling legendTapHandling = LegendTapHandling.hide;\n\n  late List<MutableSeries<D>> _currentSeriesList;\n\n  /// List of series IDs in the order the series should appear in the legend.\n  /// Series that are not specified in the ordering will be sorted\n  /// alphabetically at the bottom.\n  List<String>? _customEntryOrder;\n\n  /// Save this in order to check if series list have changed and regenerate\n  /// the legend entries.\n  List<MutableSeries<D>>? _postProcessSeriesList;\n\n  static final _decimalPattern = NumberFormat.decimalPattern();\n\n  /// Default measure formatter for legends.\n  @protected\n  String defaultLegendMeasureFormatter(num? value) {\n    return (value == null) ? '' : _decimalPattern.format(value);\n  }\n\n  Legend({\n    required this.selectionModelType,\n    required this.legendEntryGenerator,\n    TextStyleSpec? entryTextStyle,\n  }) {\n    _lifecycleListener = LifecycleListener(\n        onPostprocess: _postProcess, onPreprocess: _preProcess, onData: onData);\n    legendEntryGenerator.entryTextStyle = entryTextStyle;\n\n    // Calling the setter will automatically use a non-null default value.\n    showOverlaySeries = null;\n  }\n\n  /// Text style of the legend entry text.\n  TextStyleSpec? get entryTextStyle => legendEntryGenerator.entryTextStyle;\n\n  set entryTextStyle(TextStyleSpec? entryTextStyle) {\n    legendEntryGenerator.entryTextStyle = entryTextStyle;\n  }\n\n  set customEntryOrder(List<String>? customEntryOrder) {\n    _customEntryOrder = customEntryOrder;\n  }\n\n  /// Whether or not the legend show overlay series.\n  ///\n  /// By default this is false, the overlay series are not shown on the legend.\n  ///\n  /// if [showOverlaySeries] is set to null, it is changed to the default of\n  /// false.\n  bool get showOverlaySeries => legendEntryGenerator.showOverlaySeries;\n\n  set showOverlaySeries(bool? showOverlaySeries) {\n    legendEntryGenerator.showOverlaySeries = showOverlaySeries ?? false;\n  }\n\n  /// Resets any hidden series data when new data is drawn on the chart.\n  @protected\n  void onData(List<MutableSeries<D>> seriesList) {}\n\n  /// Store off a copy of the series list for use when we render the legend.\n  void _preProcess(List<MutableSeries<D>> seriesList) {\n    _currentSeriesList = List.of(seriesList);\n    preProcessSeriesList(seriesList);\n  }\n\n  /// Overridable method that may be used by concrete [Legend] instances to\n  /// manipulate the series list.\n  @protected\n  void preProcessSeriesList(List<MutableSeries<D>> seriesList) {}\n\n  /// Build LegendEntries from list of series.\n  void _postProcess(List<MutableSeries<D>> seriesList) {\n    // Get the selection model directly from chart on post process.\n    //\n    // This is because if initial selection is set as a behavior, it will be\n    // handled during onData. onData is prior to this behavior's postProcess\n    // call, so the selection will have changed prior to the entries being\n    // generated.\n    final selectionModel = chart.getSelectionModel(selectionModelType);\n\n    // Update entries if the selection model is different because post\n    // process is called on each draw cycle, so this is called on each animation\n    // frame and we don't want to update and request the native platform to\n    // rebuild if nothing has changed.\n    //\n    // Also update legend entries if the series list has changed.\n    if (legendState._selectionModel != selectionModel ||\n        _postProcessSeriesList != seriesList) {\n      final _customEntryOrder = this._customEntryOrder;\n      if (_customEntryOrder != null) {\n        _currentSeriesList.sort((a, b) {\n          final a_index = _customEntryOrder.indexOf(a.id);\n          final b_index = _customEntryOrder.indexOf(b.id);\n          if (a_index == -1) {\n            if (a_index == b_index) {\n              return a.displayName!.compareTo(b.displayName!);\n            }\n            return 1;\n          } else if (b_index == -1) {\n            return -1;\n          }\n          return a_index.compareTo(b_index);\n        });\n      }\n\n      legendState._legendEntries =\n          legendEntryGenerator.getLegendEntries(_currentSeriesList);\n\n      legendState._selectionModel = selectionModel;\n      _postProcessSeriesList = seriesList;\n      _updateLegendEntries(seriesList: seriesList);\n    }\n  }\n\n  // need to handle when series data changes, selection should be reset\n\n  /// Update the legend state with [selectionModel] and request legend update.\n  void _selectionChanged(SelectionModel<D> selectionModel) {\n    legendState._selectionModel = selectionModel;\n    _updateLegendEntries();\n  }\n\n  ChartContext get chartContext => _chart.context;\n\n  /// Internally update legend entries, before calling [updateLegend] that\n  /// notifies the native platform.\n  void _updateLegendEntries({List<MutableSeries<D>>? seriesList}) {\n    legendEntryGenerator.updateLegendEntries(legendState._legendEntries,\n        legendState._selectionModel!, seriesList ?? chart.currentSeriesList);\n\n    updateLegend();\n  }\n\n  /// Requires override to show in native platform\n  void updateLegend() {}\n\n  @override\n  void attachTo(BaseChart<D> chart) {\n    _chart = chart;\n    chart.addLifecycleListener(_lifecycleListener);\n    chart\n        .getSelectionModel(selectionModelType)\n        .addSelectionChangedListener(_selectionChanged);\n\n    chart.addView(this);\n  }\n\n  @override\n  void removeFrom(BaseChart<D> chart) {\n    chart\n        .getSelectionModel(selectionModelType)\n        .removeSelectionChangedListener(_selectionChanged);\n    chart.removeLifecycleListener(_lifecycleListener);\n\n    chart.removeView(this);\n  }\n\n  @protected\n  BaseChart<D> get chart => _chart;\n\n  @override\n  String get role => 'legend-$selectionModelType';\n\n  bool get isRtl => _chart.context.chartContainerIsRtl;\n\n  bool get isAxisFlipped => _chart.context.isRtl;\n\n  @override\n  LayoutViewConfig get layoutConfig {\n    return LayoutViewConfig(\n        position: _layoutPosition,\n        positionOrder: LayoutViewPositionOrder.legend,\n        paintOrder: LayoutViewPaintOrder.legend);\n  }\n\n  /// Get layout position from legend position.\n  LayoutPosition get _layoutPosition {\n    return layoutPosition(behaviorPosition, outsideJustification, isRtl);\n  }\n\n  @override\n  ViewMeasuredSizes measure(int maxWidth, int maxHeight) {\n    // Native child classes should override this method to return real\n    // measurements.\n    return ViewMeasuredSizes(preferredWidth: 0, preferredHeight: 0);\n  }\n\n  @override\n  void layout(Rectangle<int> componentBounds, Rectangle<int> drawAreaBounds) {\n    _componentBounds = componentBounds;\n    _drawAreaBounds = drawAreaBounds;\n\n    updateLegend();\n  }\n\n  @override\n  void paint(ChartCanvas canvas, double animationPercent) {}\n\n  @override\n  Rectangle<int>? get componentBounds => _componentBounds;\n\n  @override\n  bool get isSeriesRenderer => false;\n\n  // Gets the draw area bounds for native legend content to position itself\n  // accordingly.\n  Rectangle<int>? get drawAreaBounds => _drawAreaBounds;\n}\n\n/// Stores legend data used by native legend content builder.\nclass LegendState<D> {\n  late List<LegendEntry<D>> _legendEntries;\n  SelectionModel<D>? _selectionModel;\n\n  List<LegendEntry<D>> get legendEntries => _legendEntries;\n  SelectionModel<D>? get selectionModel => _selectionModel;\n}\n\n/// Stores legend cell padding, in percents or pixels.\n///\n/// If a percent is specified, it takes precedence over a flat pixel value.\nclass LegendCellPadding {\n  final double? bottomPct;\n  final double? bottomPx;\n  final double? leftPct;\n  final double? leftPx;\n  final double? rightPct;\n  final double? rightPx;\n  final double? topPct;\n  final double? topPx;\n\n  /// Creates padding in percents from the left, top, right, and bottom.\n  const LegendCellPadding.fromLTRBPct(\n      this.leftPct, this.topPct, this.rightPct, this.bottomPct)\n      : leftPx = null,\n        topPx = null,\n        rightPx = null,\n        bottomPx = null;\n\n  /// Creates padding in pixels from the left, top, right, and bottom.\n  const LegendCellPadding.fromLTRBPx(\n      this.leftPx, this.topPx, this.rightPx, this.bottomPx)\n      : leftPct = null,\n        topPct = null,\n        rightPct = null,\n        bottomPct = null;\n\n  /// Creates padding in percents from the top, right, bottom, and left.\n  const LegendCellPadding.fromTRBLPct(\n      this.topPct, this.rightPct, this.bottomPct, this.leftPct)\n      : topPx = null,\n        rightPx = null,\n        bottomPx = null,\n        leftPx = null;\n\n  /// Creates padding in pixels from the top, right, bottom, and left.\n  const LegendCellPadding.fromTRBLPx(\n      this.topPx, this.rightPx, this.bottomPx, this.leftPx)\n      : topPct = null,\n        rightPct = null,\n        bottomPct = null,\n        leftPct = null;\n\n  /// Creates cell padding where all the offsets are `value` in percent.\n  ///\n  /// ## Sample code\n  ///\n  /// Typical eight percent margin on all sides:\n  ///\n  /// ```dart\n  /// const LegendCellPadding.allPct(8.0)\n  /// ```\n  const LegendCellPadding.allPct(double value)\n      : this.fromLTRBPct(value, value, value, value);\n\n  /// Creates cell padding where all the offsets are `value` in pixels.\n  ///\n  /// ## Sample code\n  ///\n  /// Typical eight-pixel margin on all sides:\n  ///\n  /// ```dart\n  /// const LegendCellPadding.allPx(8.0)\n  /// ```\n  const LegendCellPadding.allPx(double value)\n      : this.fromLTRBPx(value, value, value, value);\n\n  double bottom(num height) =>\n      bottomPct != null ? bottomPct! * height : bottomPx!;\n\n  double left(num width) => leftPct != null ? leftPct! * width : leftPx!;\n\n  double right(num width) => rightPct != null ? rightPct! * width : rightPx!;\n\n  double top(num height) => topPct != null ? topPct! * height : topPx!;\n}\n\n/// Options for behavior of tapping/clicking on entries in the legend.\nenum LegendTapHandling {\n  /// No associated behavior.\n  none,\n\n  /// Hide elements on the chart associated with this legend entry.\n  hide,\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/common/behavior/legend/legend_entry.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport '../../../../common/color.dart';\nimport '../../../../common/symbol_renderer.dart';\nimport '../../../cartesian/axis/spec/axis_spec.dart' show TextStyleSpec;\nimport '../../processed_series.dart' show ImmutableSeries;\nimport '../../series_renderer.dart' show rendererKey;\n\n/// The most basic possible legend entry - just a display name and positioning.\nclass LegendEntryBase {\n  final String label;\n  final TextStyleSpec? textStyle;\n\n  /// Zero based index for the row where this legend appears in the legend.\n  int? rowNumber;\n\n  /// Zero based index for the column where this legend appears in the legend.\n  int? columnNumber;\n\n  /// Total number of rows in the legend.\n  int? rowCount;\n\n  /// Total number of columns in the legend.\n  int? columnCount;\n\n  /// Indicates whether this is in the first row of a tabular layout.\n  bool? inFirstRow;\n\n  /// Indicates whether this is in the first column of a tabular layout.\n  bool? inFirstColumn;\n\n  /// Indicates whether this is in the last row of a tabular layout.\n  bool? inLastRow;\n\n  /// Indicates whether this is in the last column of a tabular layout.\n  bool? inLastColumn;\n\n  LegendEntryBase(this.label,\n      {this.textStyle,\n      this.rowNumber,\n      this.columnNumber,\n      this.rowCount,\n      this.columnCount,\n      this.inFirstRow,\n      this.inFirstColumn,\n      this.inLastRow,\n      this.inLastColumn});\n}\n\n/// When the legend groups by category it will create additional legend entries\n/// that track styling and grouping on a per category basis.\nclass LegendCategory<D> extends LegendEntryBase {\n  /// The list of entries that should be displayed within this category.\n  final List<LegendEntry<D>>? entries;\n\n  LegendCategory(\n    String label,\n    this.entries, {\n    TextStyleSpec? textStyle,\n    int? rowNumber,\n    int? columnNumber,\n    int? rowCount,\n    int? columnCount,\n    bool? inFirstRow,\n    bool? inFirstColumn,\n    bool? inLastRow,\n    bool? inLastColumn,\n  }) : super(label,\n            textStyle: textStyle,\n            rowNumber: rowNumber,\n            columnNumber: columnNumber,\n            rowCount: rowCount,\n            columnCount: columnCount,\n            inFirstRow: inFirstRow,\n            inFirstColumn: inFirstColumn,\n            inLastRow: inLastRow,\n            inLastColumn: inLastColumn);\n}\n\n/// Holder for the information used for a legend row.\n///\n/// [T] the datum class type for the series passed in.\n/// [D] the domain class type for the datum.\nclass LegendEntry<D> extends LegendEntryBase {\n  final ImmutableSeries<D> series;\n  final dynamic datum;\n  final int? datumIndex;\n  final D? domain;\n  final Color? color;\n  double? value;\n  List<int?>? selectedDataIndexes;\n  String? formattedValue;\n  bool isSelected;\n\n  // TODO: Forward the default formatters from series and allow for\n  // native legends to provide separate formatters.\n\n  LegendEntry(\n    this.series,\n    String label, {\n    this.datum,\n    this.datumIndex,\n    this.domain,\n    this.value,\n    this.selectedDataIndexes,\n    this.color,\n    this.isSelected = false,\n    TextStyleSpec? textStyle,\n    int? rowNumber,\n    int? columnNumber,\n    int? rowCount,\n    int? columnCount,\n    bool? inFirstRow,\n    bool? inFirstColumn,\n    bool? inLastRow,\n    bool? inLastColumn,\n  }) : super(label,\n            textStyle: textStyle,\n            rowNumber: rowNumber,\n            columnNumber: columnNumber,\n            rowCount: rowCount,\n            columnCount: columnCount,\n            inFirstRow: inFirstRow,\n            inFirstColumn: inFirstColumn,\n            inLastRow: inLastRow,\n            inLastColumn: inLastColumn);\n\n  /// Get the native symbol renderer stored in the series.\n  SymbolRenderer? get symbolRenderer =>\n      series.getAttr(rendererKey)!.symbolRenderer;\n\n  /// Gets the dash pattern for the symbol from the given datum and series.\n  ///\n  /// Use the dash pattern from the datum if available, otherwise fall back to\n  /// generic series dash pattern.\n  List<int>? get dashPattern => series.dashPatternFn?.call(datumIndex ?? 0);\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/common/behavior/legend/legend_entry_generator.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport '../../../cartesian/axis/spec/axis_spec.dart' show TextStyleSpec;\nimport '../../datum_details.dart' show MeasureFormatter;\nimport '../../processed_series.dart' show MutableSeries;\nimport '../../selection_model/selection_model.dart';\nimport 'legend_entry.dart';\n\n/// A strategy for generating a list of [LegendEntry] based on the series drawn.\n///\n/// [D] the domain class type for the datum.\nabstract class LegendEntryGenerator<D> {\n  /// Generates a list of legend entries based on the series drawn on the chart.\n  ///\n  /// [seriesList] Processed series list.\n  List<LegendEntry<D>> getLegendEntries(List<MutableSeries<D>> seriesList);\n\n  /// Update the list of legend entries based on the selection model.\n  ///\n  /// [legendEntries] Existing legend entries to update.\n  /// [selectionModel] Selection model to query selected state.\n  /// [seriesList] Processed series list.\n  void updateLegendEntries(List<LegendEntry<D>> legendEntries,\n      SelectionModel<D> selectionModel, List<MutableSeries<D>> seriesList);\n\n  MeasureFormatter? get measureFormatter;\n\n  set measureFormatter(MeasureFormatter? formatter);\n\n  MeasureFormatter? get secondaryMeasureFormatter;\n\n  set secondaryMeasureFormatter(MeasureFormatter? formatter);\n\n  LegendDefaultMeasure get legendDefaultMeasure;\n\n  set legendDefaultMeasure(LegendDefaultMeasure noSelectionMeasure);\n\n  TextStyleSpec? get entryTextStyle;\n\n  set entryTextStyle(TextStyleSpec? entryTextStyle);\n\n  bool get showOverlaySeries;\n\n  set showOverlaySeries(bool showOverlaySeries);\n}\n\n/// Options for calculating what measures are shown when there is no selection.\nenum LegendDefaultMeasure {\n  // No measures are shown where there is no selection.\n  none,\n  // Sum of all measure values for the series.\n  sum,\n  // Average of all measure values for the series.\n  average,\n  // The first measure value of the series.\n  firstValue,\n  // The last measure value of the series.\n  lastValue,\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/common/behavior/legend/per_datum_legend_entry_generator.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n//import 'dart:collection' show HashSet;\nimport '../../../cartesian/axis/axis.dart' show Axis, measureAxisIdKey;\nimport '../../../cartesian/axis/spec/axis_spec.dart' show TextStyleSpec;\nimport '../../datum_details.dart' show MeasureFormatter;\nimport '../../processed_series.dart' show ImmutableSeries, MutableSeries;\nimport '../../selection_model/selection_model.dart';\nimport 'legend_entry.dart';\nimport 'legend_entry_generator.dart';\n\n/// A strategy for generating a list of [LegendEntry] per series data drawn.\n///\n/// [D] the domain class type for the datum.\nclass PerDatumLegendEntryGenerator<D> implements LegendEntryGenerator<D> {\n  @override\n  TextStyleSpec? entryTextStyle;\n\n  @override\n  MeasureFormatter? measureFormatter;\n\n  @override\n  MeasureFormatter? secondaryMeasureFormatter;\n\n  @override\n  late bool showOverlaySeries;\n\n  /// Option for showing measures when there is no selection.\n  @override\n  late LegendDefaultMeasure legendDefaultMeasure;\n\n  @override\n  List<LegendEntry<D>> getLegendEntries(List<MutableSeries<D>> seriesList) {\n    final legendEntries = <LegendEntry<D>>[];\n\n    final series = seriesList[0];\n    for (var i = 0; i < series.data.length; i++) {\n      legendEntries.add(LegendEntry<D>(series, series.domainFn(i).toString(),\n          color: series.colorFn!(i),\n          datum: series.data[i],\n          datumIndex: i,\n          textStyle: entryTextStyle));\n    }\n\n    // Update with measures only if showing measure on no selection.\n    if (legendDefaultMeasure != LegendDefaultMeasure.none) {\n      _updateEntries(legendEntries);\n    }\n\n    return legendEntries;\n  }\n\n  @override\n  void updateLegendEntries(List<LegendEntry<D>> legendEntries,\n      SelectionModel<D> selectionModel, List<MutableSeries<D>> seriesList) {\n    if (selectionModel.hasAnySelection) {\n      _updateFromSelection(legendEntries, selectionModel);\n    } else {\n      // Update with measures only if showing measure on no selection.\n      if (legendDefaultMeasure != LegendDefaultMeasure.none) {\n        _updateEntries(legendEntries);\n      } else {\n        _resetLegendEntryMeasures(legendEntries);\n      }\n    }\n  }\n\n  /// Update legend entries with measures of the selected datum\n  void _updateFromSelection(\n      List<LegendEntry<D>> legendEntries, SelectionModel<D> selectionModel) {\n    // Given that each legend entry only has one datum associated with it, any\n    // option for [legendDefaultMeasure] essentially boils down to just showing\n    // the measure value.\n    if (legendDefaultMeasure != LegendDefaultMeasure.none) {\n      for (var entry in legendEntries) {\n        final series = entry.series;\n        final measure = series.measureFn(entry.datumIndex);\n        entry.value = measure!.toDouble();\n        entry.formattedValue = _getFormattedMeasureValue(series, measure);\n\n        entry.isSelected = selectionModel.selectedSeries\n            .any((selectedSeries) => series.id == selectedSeries.id);\n      }\n    }\n  }\n\n  void _resetLegendEntryMeasures(List<LegendEntry<D>> legendEntries) {\n    for (final entry in legendEntries) {\n      entry.value = null;\n      entry.formattedValue = null;\n      entry.isSelected = false;\n    }\n  }\n\n  /// Update each legend entry by calculating measure values for its series.\n  ///\n  /// This method calculates the legend's measure value to show when there is no\n  /// selection. The type of calculation is based on the [legendDefaultMeasure]\n  /// value.\n  void _updateEntries(List<LegendEntry<D>> legendEntries) {\n    // Given that each legend entry only has one datum associated with it, any\n    // option for [legendDefaultMeasure] essentially boils down to just showing\n    // the measure value.\n    if (legendDefaultMeasure != LegendDefaultMeasure.none) {\n      for (var entry in legendEntries) {\n        final series = entry.series;\n        final measure = series.measureFn(entry.datumIndex);\n        entry.value = measure!.toDouble();\n        entry.formattedValue = _getFormattedMeasureValue(series, measure);\n        entry.isSelected = false;\n      }\n    }\n  }\n\n  /// Formats the measure value using the appropriate measure formatter\n  /// function for the series.\n  String _getFormattedMeasureValue(ImmutableSeries<D> series, num measure) {\n    return (series.getAttr(measureAxisIdKey) == Axis.secondaryMeasureAxisId)\n        ? secondaryMeasureFormatter!(measure)\n        : measureFormatter!(measure);\n  }\n\n  @override\n  bool operator ==(Object other) {\n    return other is PerDatumLegendEntryGenerator &&\n        measureFormatter == other.measureFormatter &&\n        secondaryMeasureFormatter == other.secondaryMeasureFormatter &&\n        legendDefaultMeasure == other.legendDefaultMeasure &&\n        entryTextStyle == other.entryTextStyle;\n  }\n\n  @override\n  int get hashCode {\n    var hashcode = measureFormatter.hashCode;\n    hashcode = (hashcode * 37) + secondaryMeasureFormatter.hashCode;\n    hashcode = (hashcode * 37) + legendDefaultMeasure.hashCode;\n    hashcode = (hashcode * 37) + entryTextStyle.hashCode;\n    return hashcode;\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/common/behavior/legend/per_series_legend_entry_generator.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:collection' show HashSet;\n\nimport '../../../cartesian/axis/axis.dart' show Axis, measureAxisIdKey;\nimport '../../../cartesian/axis/spec/axis_spec.dart' show TextStyleSpec;\nimport '../../datum_details.dart' show MeasureFormatter;\nimport '../../processed_series.dart' show MutableSeries;\nimport '../../selection_model/selection_model.dart';\nimport 'legend_entry.dart';\nimport 'legend_entry_generator.dart';\n\n/// A strategy for generating a list of [LegendEntry] per series drawn.\n///\n/// [D] the domain class type for the datum.\nclass PerSeriesLegendEntryGenerator<D> implements LegendEntryGenerator<D> {\n  @override\n  TextStyleSpec? entryTextStyle;\n\n  @override\n  MeasureFormatter? measureFormatter;\n\n  @override\n  MeasureFormatter? secondaryMeasureFormatter;\n\n  @override\n  bool showOverlaySeries = false;\n\n  /// Option for showing measures when there is no selection.\n  @override\n  late LegendDefaultMeasure legendDefaultMeasure;\n\n  @override\n  List<LegendEntry<D>> getLegendEntries(List<MutableSeries<D>> seriesList) {\n    final legendEntries = seriesList\n        .where((series) => showOverlaySeries || !series.overlaySeries)\n        .map((series) => LegendEntry<D>(\n              series,\n              series.displayName!,\n              // TODO: Should this use series.colorFn if seriesColor is null?\n              color: series.seriesColor!,\n              textStyle: entryTextStyle,\n            ))\n        .toList();\n\n    // Update with measures only if showing measure on no selection.\n    if (legendDefaultMeasure != LegendDefaultMeasure.none) {\n      _updateFromSeriesList(legendEntries, seriesList);\n    }\n\n    return legendEntries;\n  }\n\n  @override\n  void updateLegendEntries(List<LegendEntry<D>> legendEntries,\n      SelectionModel<D> selectionModel, List<MutableSeries<D>> seriesList) {\n    if (selectionModel.hasAnySelection) {\n      _updateFromSelection(legendEntries, selectionModel);\n    } else {\n      // Update with measures only if showing measure on no selection.\n      if (legendDefaultMeasure != LegendDefaultMeasure.none) {\n        _updateFromSeriesList(legendEntries, seriesList);\n      } else {\n        _resetLegendEntryMeasures(legendEntries);\n      }\n    }\n  }\n\n  /// Update legend entries with measures of the selected datum\n  void _updateFromSelection(\n      List<LegendEntry<D>> legendEntries, SelectionModel<D> selectionModel) {\n    // Map of series ID to the total selected measure value for that series.\n    final seriesAndMeasure = <String, num>{};\n\n    // Hash set of series ID's that use the secondary measure axis\n    final secondaryAxisSeriesIDs = HashSet<String>();\n\n    for (final selectedDatum in selectionModel.selectedDatum) {\n      final series = selectedDatum.series;\n      final seriesId = series.id;\n      final measure = series.measureFn(selectedDatum.index) ?? 0;\n\n      seriesAndMeasure[seriesId] = (seriesAndMeasure[seriesId] ?? 0) + measure;\n\n      if (series.getAttr(measureAxisIdKey) == Axis.secondaryMeasureAxisId) {\n        secondaryAxisSeriesIDs.add(seriesId);\n      }\n    }\n\n    for (var entry in legendEntries) {\n      final seriesId = entry.series.id;\n      final measureValue = seriesAndMeasure[seriesId]?.toDouble();\n      final formattedValue = secondaryAxisSeriesIDs.contains(seriesId)\n          ? secondaryMeasureFormatter!(measureValue)\n          : measureFormatter!(measureValue);\n\n      entry.value = measureValue;\n      entry.formattedValue = formattedValue;\n      entry.isSelected = selectionModel.selectedSeries\n          .any((selectedSeries) => entry.series.id == selectedSeries.id);\n\n      // Set the current selected model index for legend entry.\n      entry.selectedDataIndexes =\n          selectionModel.selectedDatum.map((datum) => datum.index).toList();\n    }\n  }\n\n  void _resetLegendEntryMeasures(List<LegendEntry<D>> legendEntries) {\n    for (final entry in legendEntries) {\n      entry.value = null;\n      entry.formattedValue = null;\n      entry.isSelected = false;\n    }\n  }\n\n  /// Update each legend entry by calculating measure values in [seriesList].\n  ///\n  /// This method calculates the legend's measure value to show when there is no\n  /// selection. The type of calculation is based on the [legendDefaultMeasure]\n  /// value.\n  void _updateFromSeriesList(\n      List<LegendEntry<D>> legendEntries, List<MutableSeries<D>> seriesList) {\n    // Helper function to sum up the measure values\n    num getMeasureTotal(MutableSeries<D> series) {\n      var measureTotal = 0.0;\n      for (var i = 0; i < series.data.length; i++) {\n        measureTotal += series.measureFn(i) ?? 0.0;\n      }\n      return measureTotal;\n    }\n\n    // Map of series ID to the calculated measure for that series.\n    final seriesAndMeasure = <String, double?>{};\n    // Map of series ID and the formatted measure for that series.\n    final seriesAndFormattedMeasure = <String, String>{};\n\n    for (final series in seriesList) {\n      final seriesId = series.id;\n      num? calculatedMeasure;\n\n      switch (legendDefaultMeasure) {\n        case LegendDefaultMeasure.sum:\n          calculatedMeasure = getMeasureTotal(series);\n          break;\n        case LegendDefaultMeasure.average:\n          calculatedMeasure = getMeasureTotal(series) / series.data.length;\n          break;\n        case LegendDefaultMeasure.firstValue:\n          calculatedMeasure = series.measureFn(0);\n          break;\n        case LegendDefaultMeasure.lastValue:\n          calculatedMeasure = series.measureFn(series.data.length - 1);\n          break;\n        case LegendDefaultMeasure.none:\n          // [calculatedMeasure] intentionally left null, since we do not want\n          // to show any measures.\n          break;\n      }\n\n      seriesAndMeasure[seriesId] = calculatedMeasure?.toDouble();\n      seriesAndFormattedMeasure[seriesId] =\n          (series.getAttr(measureAxisIdKey) == Axis.secondaryMeasureAxisId)\n              ? secondaryMeasureFormatter!(calculatedMeasure)\n              : measureFormatter!(calculatedMeasure);\n    }\n\n    for (var entry in legendEntries) {\n      final seriesId = entry.series.id;\n\n      entry.value = seriesAndMeasure[seriesId];\n      entry.formattedValue = seriesAndFormattedMeasure[seriesId];\n      entry.isSelected = false;\n    }\n  }\n\n  @override\n  bool operator ==(Object other) {\n    return other is PerSeriesLegendEntryGenerator &&\n        measureFormatter == other.measureFormatter &&\n        secondaryMeasureFormatter == other.secondaryMeasureFormatter &&\n        legendDefaultMeasure == other.legendDefaultMeasure &&\n        entryTextStyle == other.entryTextStyle;\n  }\n\n  @override\n  int get hashCode {\n    var hashcode = measureFormatter.hashCode;\n    hashcode = (hashcode * 37) + secondaryMeasureFormatter.hashCode;\n    hashcode = (hashcode * 37) + legendDefaultMeasure.hashCode;\n    hashcode = (hashcode * 37) + entryTextStyle.hashCode;\n    return hashcode;\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/common/behavior/legend/series_legend.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'package:meta/meta.dart' show protected;\n\nimport '../../../cartesian/axis/spec/axis_spec.dart' show TextStyleSpec;\nimport '../../datum_details.dart' show MeasureFormatter;\nimport '../../processed_series.dart' show MutableSeries;\nimport '../../selection_model/selection_model.dart' show SelectionModelType;\nimport 'legend.dart';\nimport 'legend_entry_generator.dart';\nimport 'per_series_legend_entry_generator.dart';\n\n// TODO: Allows for hovering over a series in legend to highlight\n// corresponding series in draw area.\n\n/// Series legend behavior for charts.\n///\n/// By default this behavior creates a legend entry per series.\nclass SeriesLegend<D> extends Legend<D> {\n  /// List of currently hidden series, by ID.\n  final _hiddenSeriesList = <String>{};\n\n  /// List of series IDs that should be hidden by default.\n  List<String>? _defaultHiddenSeries;\n\n  /// List of series IDs that should not be hideable.\n  List<String>? _alwaysVisibleSeries;\n\n  /// Whether or not the series legend should show measures on datum selection.\n  late bool _showMeasures;\n\n  SeriesLegend({\n    SelectionModelType? selectionModelType,\n    LegendEntryGenerator<D>? legendEntryGenerator,\n    MeasureFormatter? measureFormatter,\n    MeasureFormatter? secondaryMeasureFormatter,\n    bool? showMeasures,\n    LegendDefaultMeasure? legendDefaultMeasure,\n    TextStyleSpec? entryTextStyle,\n  }) : super(\n            selectionModelType: selectionModelType ?? SelectionModelType.info,\n            legendEntryGenerator:\n                legendEntryGenerator ?? PerSeriesLegendEntryGenerator(),\n            entryTextStyle: entryTextStyle) {\n    // Calling the setters will automatically use non-null default values.\n    this.showMeasures = showMeasures;\n    this.legendDefaultMeasure = legendDefaultMeasure;\n    this.measureFormatter = measureFormatter;\n    this.secondaryMeasureFormatter = secondaryMeasureFormatter;\n  }\n\n  /// Sets a list of series IDs that should be hidden by default on first chart\n  /// draw.\n  ///\n  /// This will also reset the current list of hidden series, filling it in with\n  /// the new default list.\n  set defaultHiddenSeries(List<String>? defaultHiddenSeries) {\n    _defaultHiddenSeries = defaultHiddenSeries;\n\n    _hiddenSeriesList.clear();\n\n    _defaultHiddenSeries?.forEach(hideSeries);\n  }\n\n  /// Gets a list of series IDs that should be hidden by default on first chart\n  /// draw.\n  List<String>? get defaultHiddenSeries => _defaultHiddenSeries;\n\n  /// Sets a list of series IDs that should always be visible and therefore\n  /// cannot be hidden.\n  ///\n  /// This also shows any series that should always be visible in case\n  /// it was previously hidden.\n  set alwaysVisibleSeries(List<String>? alwaysVisibleSeries) {\n    _alwaysVisibleSeries = alwaysVisibleSeries;\n    _alwaysVisibleSeries?.forEach(showSeries);\n  }\n\n  /// Gets a list of series IDs that should always be visible.\n  List<String>? get alwaysVisibleSeries => _alwaysVisibleSeries;\n\n  /// Whether or not the legend should show measures.\n  ///\n  /// By default this is false, measures are not shown. When set to true, the\n  /// default behavior is to show measure only if there is selected data.\n  /// Please set [legendDefaultMeasure] to something other than none to enable\n  /// showing measures when there is no selection.\n  ///\n  /// If [showMeasures] is set to null, it is changed to the default of false.\n  bool get showMeasures => _showMeasures;\n\n  set showMeasures(bool? showMeasures) {\n    _showMeasures = showMeasures ?? false;\n  }\n\n  /// Option to show measures when selection is null.\n  ///\n  /// By default this is set to none, so no measures are shown when there is\n  /// no selection.\n  ///\n  /// If [legendDefaultMeasure] is set to null, it is changed to the default of\n  /// none.\n  LegendDefaultMeasure get legendDefaultMeasure =>\n      legendEntryGenerator.legendDefaultMeasure;\n\n  set legendDefaultMeasure(LegendDefaultMeasure? legendDefaultMeasure) {\n    legendEntryGenerator.legendDefaultMeasure =\n        legendDefaultMeasure ?? LegendDefaultMeasure.none;\n  }\n\n  /// Formatter for measure values.\n  ///\n  /// This is optional. The default formatter formats measure values with\n  /// NumberFormat.decimalPattern. If the measure value is null, a dash is\n  /// returned.\n  set measureFormatter(MeasureFormatter? formatter) {\n    legendEntryGenerator.measureFormatter =\n        formatter ?? defaultLegendMeasureFormatter;\n  }\n\n  /// Formatter for measure values of series that uses the secondary axis.\n  ///\n  /// This is optional. The default formatter formats measure values with\n  /// NumberFormat.decimalPattern. If the measure value is null, a dash is\n  /// returned.\n  set secondaryMeasureFormatter(MeasureFormatter? formatter) {\n    legendEntryGenerator.secondaryMeasureFormatter =\n        formatter ?? defaultLegendMeasureFormatter;\n  }\n\n  /// Remove series IDs from the currently hidden list if those series have been\n  /// removed from the chart data. The goal is to allow any metric that is\n  /// removed from a chart, and later re-added to it, to be visible to the user.\n  @override\n  void onData(List<MutableSeries<D>> seriesList) {\n    // If a series was removed from the chart, remove it from our current list\n    // of hidden series.\n    final seriesIds = seriesList.map((MutableSeries<D> series) => series.id);\n\n    _hiddenSeriesList.removeWhere((String id) => !seriesIds.contains(id));\n  }\n\n  @override\n  void preProcessSeriesList(List<MutableSeries<D>> seriesList) {\n    seriesList.removeWhere((MutableSeries<D> series) {\n      return _hiddenSeriesList.contains(series.id);\n    });\n  }\n\n  /// Hides the data for a series on the chart by [seriesId].\n  ///\n  /// The entry in the legend for this series will be grayed out to indicate\n  /// that it is hidden.\n  @protected\n  void hideSeries(String seriesId) {\n    if (!isSeriesAlwaysVisible(seriesId)) {\n      _hiddenSeriesList.add(seriesId);\n    }\n  }\n\n  /// Shows the data for a series on the chart by [seriesId].\n  ///\n  /// The entry in the legend for this series will be returned to its normal\n  /// color if it was previously hidden.\n  @protected\n  void showSeries(String seriesId) {\n    _hiddenSeriesList.removeWhere((String id) => id == seriesId);\n  }\n\n  /// Returns whether or not a given series [seriesId] is currently hidden.\n  bool isSeriesHidden(String seriesId) {\n    return _hiddenSeriesList.contains(seriesId);\n  }\n\n  /// Returns whether or not a given series is always visible.\n  bool isSeriesAlwaysVisible(String seriesId) {\n    return _alwaysVisibleSeries != null &&\n        _alwaysVisibleSeries!.contains(seriesId);\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/common/behavior/line_point_highlighter.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:collection' show LinkedHashMap;\nimport 'dart:math' show max, min, Point, Rectangle;\n\nimport 'package:meta/meta.dart';\n\nimport '../../../common/color.dart' show Color;\nimport '../../../common/graphics_factory.dart' show GraphicsFactory;\nimport '../../../common/math.dart' show NullablePoint;\nimport '../../../common/style/style_factory.dart' show StyleFactory;\nimport '../../../common/symbol_renderer.dart'\n    show CircleSymbolRenderer, SymbolRenderer;\nimport '../../cartesian/axis/axis.dart'\n    show ImmutableAxis, domainAxisKey, measureAxisKey;\nimport '../../cartesian/cartesian_chart.dart' show CartesianChart;\nimport '../../layout/layout_view.dart'\n    show\n        LayoutPosition,\n        LayoutView,\n        LayoutViewConfig,\n        LayoutViewPaintOrder,\n        ViewMeasuredSizes;\nimport '../base_chart.dart' show BaseChart, LifecycleListener;\nimport '../chart_canvas.dart' show ChartCanvas, getAnimatedColor;\nimport '../processed_series.dart' show ImmutableSeries;\nimport '../selection_model/selection_model.dart'\n    show SelectionModel, SelectionModelType;\nimport 'chart_behavior.dart' show ChartBehavior;\n\n/// Chart behavior that monitors the specified [SelectionModel] and renders a\n/// dot for selected data.\n///\n/// Vertical or horizontal follow lines can optionally be drawn underneath the\n/// rendered dots. Follow lines will be drawn in the combined area of the chart\n/// draw area, and the draw area for any layout components that provide a\n/// series draw area (e.g. [SymbolAnnotationRenderer]).\n///\n/// This is typically used for line charts to highlight segments.\n///\n/// It is used in combination with SelectNearest to update the selection model\n/// and expand selection out to the domain value.\nclass LinePointHighlighter<D> implements ChartBehavior<D> {\n  final SelectionModelType selectionModelType;\n\n  /// Default radius of the dots if the series has no radius mapping function.\n  ///\n  /// When no radius mapping function is provided, this value will be used as\n  /// is. [radiusPaddingPx] will not be added to [defaultRadiusPx].\n  final double defaultRadiusPx;\n\n  /// Additional radius value added to the radius of the selected data.\n  ///\n  /// This value is only used when the series has a radius mapping function\n  /// defined.\n  final double radiusPaddingPx;\n\n  /// Whether or not to draw horizontal follow lines through the selected\n  /// points.\n  ///\n  /// Defaults to drawing no horizontal follow lines.\n  final LinePointHighlighterFollowLineType showHorizontalFollowLine;\n\n  /// Whether or not to draw vertical follow lines through the selected points.\n  ///\n  /// Defaults to drawing a vertical follow line only for the nearest datum.\n  final LinePointHighlighterFollowLineType showVerticalFollowLine;\n\n  /// The dash pattern to be used for drawing the line.\n  ///\n  /// To disable dash pattern (to draw a solid line), pass in an empty list.\n  /// This is because if dashPattern is null or not set, it defaults to [1,3].\n  final List<int>? dashPattern;\n\n  /// Whether or not follow lines should be drawn across the entire chart draw\n  /// area, or just from the axis to the point.\n  ///\n  /// When disabled, measure follow lines will be drawn from the primary measure\n  /// axis to the point. In RTL mode, this means from the right-hand axis. In\n  /// LTR mode, from the left-hand axis.\n  final bool drawFollowLinesAcrossChart;\n\n  /// Renderer used to draw the highlighted points.\n  final SymbolRenderer symbolRenderer;\n\n  late BaseChart<D> _chart;\n\n  late _LinePointLayoutView<D> _view;\n\n  late LifecycleListener<D> _lifecycleListener;\n\n  /// Store a map of data drawn on the chart, mapped by series name.\n  ///\n  /// [LinkedHashMap] is used to render the series on the canvas in the same\n  /// order as the data was provided by the selection model.\n  // ignore: prefer_collection_literals, https://github.com/dart-lang/linter/issues/1649\n  var _seriesPointMap = LinkedHashMap<String, _AnimatedPoint<D>>();\n\n  // Store a list of points that exist in the series data.\n  //\n  // This list will be used to remove any [_AnimatedPoint] that were rendered in\n  // previous draw cycles, but no longer have a corresponding datum in the new\n  // data.\n  final _currentKeys = <String>[];\n\n  LinePointHighlighter(\n      {SelectionModelType? selectionModelType,\n      double? defaultRadiusPx,\n      double? radiusPaddingPx,\n      LinePointHighlighterFollowLineType? showHorizontalFollowLine,\n      LinePointHighlighterFollowLineType? showVerticalFollowLine,\n      List<int>? dashPattern,\n      bool? drawFollowLinesAcrossChart,\n      SymbolRenderer? symbolRenderer})\n      : selectionModelType = selectionModelType ?? SelectionModelType.info,\n        defaultRadiusPx = defaultRadiusPx ?? 4.0,\n        radiusPaddingPx = radiusPaddingPx ?? 2.0,\n        showHorizontalFollowLine =\n            showHorizontalFollowLine ?? LinePointHighlighterFollowLineType.none,\n        showVerticalFollowLine = showVerticalFollowLine ??\n            LinePointHighlighterFollowLineType.nearest,\n        dashPattern = dashPattern ?? [1, 3],\n        drawFollowLinesAcrossChart = drawFollowLinesAcrossChart ?? true,\n        symbolRenderer = symbolRenderer ?? CircleSymbolRenderer() {\n    _lifecycleListener =\n        LifecycleListener<D>(onAxisConfigured: _updateViewData);\n  }\n\n  @override\n  void attachTo(BaseChart<D> chart) {\n    _chart = chart;\n\n    _view = _LinePointLayoutView<D>(\n        chart: chart,\n        layoutPaintOrder: LayoutViewPaintOrder.linePointHighlighter,\n        showHorizontalFollowLine: showHorizontalFollowLine,\n        showVerticalFollowLine: showVerticalFollowLine,\n        dashPattern: dashPattern,\n        drawFollowLinesAcrossChart: drawFollowLinesAcrossChart,\n        symbolRenderer: symbolRenderer);\n\n    if (chart is CartesianChart) {\n      // Only vertical rendering is supported by this behavior.\n      assert((chart as CartesianChart).vertical);\n    }\n\n    chart.addView(_view);\n\n    chart.addLifecycleListener(_lifecycleListener);\n    chart\n        .getSelectionModel(selectionModelType)\n        .addSelectionChangedListener(_selectionChanged);\n  }\n\n  @override\n  void removeFrom(BaseChart<D> chart) {\n    chart.removeView(_view);\n    chart\n        .getSelectionModel(selectionModelType)\n        .removeSelectionChangedListener(_selectionChanged);\n    chart.removeLifecycleListener(_lifecycleListener);\n  }\n\n  void _selectionChanged(SelectionModel<D> selectionModel) {\n    _chart.redraw(skipLayout: true, skipAnimation: true);\n  }\n\n  void _updateViewData() {\n    _currentKeys.clear();\n\n    final selectedDatumDetails =\n        _chart.getSelectedDatumDetails(selectionModelType);\n\n    // Create a new map each time to ensure that we have it sorted in the\n    // selection model order. This preserves the \"nearestDetail\" ordering, so\n    // that we render follow lines in the proper place.\n    // ignore: prefer_collection_literals\n    final newSeriesMap = LinkedHashMap<String, _AnimatedPoint<D>>();\n\n    for (final detail in selectedDatumDetails) {\n      if (detail == null) {\n        continue;\n      }\n\n      final series = detail.series!;\n      final Object? datum = detail.datum;\n\n      final domainAxis = series.getAttr(domainAxisKey) as ImmutableAxis<D>;\n      final measureAxis = series.getAttr(measureAxisKey) as ImmutableAxis<num>;\n\n      final lineKey = series.id;\n\n      final radiusPx = (detail.radiusPx != null)\n          ? detail.radiusPx!.toDouble() + radiusPaddingPx\n          : defaultRadiusPx;\n\n      final pointKey = '${lineKey}::${detail.domain}::${detail.measure}';\n\n      // If we already have a point for that key, use it.\n      _AnimatedPoint<D> animatingPoint;\n      if (_seriesPointMap.containsKey(pointKey)) {\n        animatingPoint = _seriesPointMap[pointKey]!;\n      } else {\n        // Create a new point and have it animate in from axis.\n        final point = _DatumPoint<D>(\n            datum: datum,\n            domain: detail.domain,\n            series: series,\n            x: domainAxis.getLocation(detail.domain),\n            y: measureAxis.getLocation(0.0));\n\n        animatingPoint = _AnimatedPoint<D>(\n            key: pointKey, overlaySeries: series.overlaySeries)\n          ..setNewTarget(_PointRendererElement<D>(\n            point: point,\n            color: detail.color,\n            fillColor: detail.fillColor,\n            radiusPx: radiusPx,\n            measureAxisPosition: measureAxis.getLocation(0.0),\n            strokeWidthPx: detail.strokeWidthPx,\n            symbolRenderer: detail.symbolRenderer,\n          ));\n      }\n\n      newSeriesMap[pointKey] = animatingPoint;\n\n      // Create a new line using the final point locations.\n      final point = _DatumPoint<D>(\n          datum: datum,\n          domain: detail.domain,\n          series: series,\n          x: detail.chartPosition!.x,\n          y: detail.chartPosition!.y);\n\n      // Update the set of points that still exist in the series data.\n      _currentKeys.add(pointKey);\n\n      // Get the point element we are going to setup.\n      final pointElement = _PointRendererElement<D>(\n        point: point,\n        color: detail.color,\n        fillColor: detail.fillColor,\n        radiusPx: radiusPx,\n        measureAxisPosition: measureAxis.getLocation(0.0),\n        strokeWidthPx: detail.strokeWidthPx,\n        symbolRenderer: detail.symbolRenderer,\n      );\n\n      animatingPoint.setNewTarget(pointElement);\n    }\n\n    // Animate out points that don't exist anymore.\n    _seriesPointMap.forEach((String key, _AnimatedPoint<D> point) {\n      if (_currentKeys.contains(point.key) != true) {\n        point.animateOut();\n        newSeriesMap[point.key] = point;\n      }\n    });\n\n    _seriesPointMap = newSeriesMap;\n    _view.seriesPointMap = _seriesPointMap;\n  }\n\n  @override\n  String get role => 'LinePointHighlighter-$selectionModelType';\n}\n\nclass _LinePointLayoutView<D> extends LayoutView {\n  @override\n  final LayoutViewConfig layoutConfig;\n\n  final LinePointHighlighterFollowLineType showHorizontalFollowLine;\n\n  final LinePointHighlighterFollowLineType showVerticalFollowLine;\n\n  final BaseChart<D> chart;\n\n  final List<int>? dashPattern;\n\n  late Rectangle<int> _drawAreaBounds;\n\n  Rectangle<int> get drawBounds => _drawAreaBounds;\n\n  final bool drawFollowLinesAcrossChart;\n\n  final SymbolRenderer symbolRenderer;\n\n  @override\n  GraphicsFactory? graphicsFactory;\n\n  /// Store a map of series drawn on the chart, mapped by series name.\n  ///\n  /// [LinkedHashMap] is used to render the series on the canvas in the same\n  /// order as the data was given to the chart.\n  LinkedHashMap<String, _AnimatedPoint<D>>? _seriesPointMap;\n\n  _LinePointLayoutView({\n    required this.chart,\n    required int layoutPaintOrder,\n    required this.showHorizontalFollowLine,\n    required this.showVerticalFollowLine,\n    required this.symbolRenderer,\n    required this.dashPattern,\n    required this.drawFollowLinesAcrossChart,\n  }) : layoutConfig = LayoutViewConfig(\n            paintOrder: LayoutViewPaintOrder.linePointHighlighter,\n            position: LayoutPosition.DrawArea,\n            positionOrder: layoutPaintOrder);\n\n  set seriesPointMap(LinkedHashMap<String, _AnimatedPoint<D>>? value) {\n    _seriesPointMap = value;\n  }\n\n  @override\n  ViewMeasuredSizes? measure(int maxWidth, int maxHeight) {\n    return null;\n  }\n\n  @override\n  void layout(Rectangle<int> componentBounds, Rectangle<int> drawAreaBounds) {\n    _drawAreaBounds = drawAreaBounds;\n  }\n\n  @override\n  void paint(ChartCanvas canvas, double animationPercent) {\n    final _seriesPointMap = this._seriesPointMap;\n    if (_seriesPointMap == null) {\n      return;\n    }\n\n    // Clean up the lines that no longer exist.\n    if (animationPercent == 1.0) {\n      final keysToRemove = <String>[];\n\n      _seriesPointMap.forEach((String key, _AnimatedPoint<D> point) {\n        if (point.animatingOut) {\n          keysToRemove.add(key);\n        }\n      });\n\n      keysToRemove.forEach(_seriesPointMap.remove);\n    }\n\n    final points = <_PointRendererElement<D>>[];\n    _seriesPointMap.forEach((String key, _AnimatedPoint<D> point) {\n      points.add(point.getCurrentPoint(animationPercent));\n    });\n\n    // Build maps of the position where the follow lines should stop for each\n    // selected data point.\n    final endPointPerValueVertical = <int, int>{};\n    final endPointPerValueHorizontal = <int, int>{};\n\n    for (final pointElement in points) {\n      if (pointElement.point.x == null || pointElement.point.y == null) {\n        continue;\n      }\n      final point = pointElement.point.toPoint();\n\n      final roundedX = point.x.round();\n      final roundedY = point.y.round();\n\n      // Get the Y value closest to the top of the chart for this X position.\n      if (endPointPerValueVertical[roundedX] == null) {\n        endPointPerValueVertical[roundedX] = roundedY;\n      } else {\n        // In the nearest case, we rely on the selected data always starting\n        // with the nearest point. In this case, we don't care about the rest of\n        // the selected data positions.\n        if (showVerticalFollowLine !=\n            LinePointHighlighterFollowLineType.nearest) {\n          endPointPerValueVertical[roundedX] =\n              min(endPointPerValueVertical[roundedX]!, roundedY);\n        }\n      }\n\n      // Get the X value closest to the \"end\" side of the chart for this Y\n      // position.\n      if (endPointPerValueHorizontal[roundedY] == null) {\n        endPointPerValueHorizontal[roundedY] = roundedX;\n      } else {\n        // In the nearest case, we rely on the selected data always starting\n        // with the nearest point. In this case, we don't care about the rest of\n        // the selected data positions.\n        if (showHorizontalFollowLine !=\n            LinePointHighlighterFollowLineType.nearest) {\n          endPointPerValueHorizontal[roundedY] =\n              max(endPointPerValueHorizontal[roundedY]!, roundedX);\n        }\n      }\n    }\n\n    var shouldShowHorizontalFollowLine = showHorizontalFollowLine ==\n            LinePointHighlighterFollowLineType.all ||\n        showHorizontalFollowLine == LinePointHighlighterFollowLineType.nearest;\n\n    var shouldShowVerticalFollowLine = showVerticalFollowLine ==\n            LinePointHighlighterFollowLineType.all ||\n        showVerticalFollowLine == LinePointHighlighterFollowLineType.nearest;\n\n    // Keep track of points for which we've already drawn lines.\n    final paintedHorizontalLinePositions = <num>[];\n    final paintedVerticalLinePositions = <num>[];\n\n    final drawBounds = chart.drawableLayoutAreaBounds;\n\n    final rtl = chart.context.isRtl;\n\n    // Draw the follow lines first, below all of the highlight shapes.\n    for (final pointElement in points) {\n      if (pointElement.point.x == null || pointElement.point.y == null) {\n        continue;\n      }\n      final point = pointElement.point.toPoint();\n\n      final roundedX = point.x.round();\n      final roundedY = point.y.round();\n\n      // Draw the horizontal follow line.\n      if (shouldShowHorizontalFollowLine &&\n          !paintedHorizontalLinePositions.contains(roundedY)) {\n        int leftBound;\n        int rightBound;\n\n        if (drawFollowLinesAcrossChart) {\n          // RTL and LTR both go across the whole draw area.\n          leftBound = drawBounds.left;\n          rightBound = drawBounds.left + drawBounds.width;\n        } else {\n          final x = endPointPerValueHorizontal[roundedY]!;\n\n          // RTL goes from the point to the right edge. LTR goes from the left\n          // edge to the point.\n          leftBound = rtl ? x : drawBounds.left;\n          rightBound = rtl ? drawBounds.left + drawBounds.width : x;\n        }\n\n        canvas.drawLine(\n            points: [\n              Point<num>(leftBound, point.y),\n              Point<num>(rightBound, point.y),\n            ],\n            stroke: StyleFactory.style.linePointHighlighterColor,\n            strokeWidthPx: 1.0,\n            dashPattern: dashPattern);\n\n        if (showHorizontalFollowLine ==\n            LinePointHighlighterFollowLineType.nearest) {\n          shouldShowHorizontalFollowLine = false;\n        }\n\n        paintedHorizontalLinePositions.add(roundedY);\n      }\n\n      // Draw the vertical follow line.\n      if (shouldShowVerticalFollowLine &&\n          !paintedVerticalLinePositions.contains(roundedX)) {\n        final topBound = drawFollowLinesAcrossChart\n            ? drawBounds.top\n            : endPointPerValueVertical[roundedX]!;\n\n        canvas.drawLine(\n            points: [\n              Point<num>(point.x, topBound),\n              Point<num>(point.x, drawBounds.top + drawBounds.height),\n            ],\n            stroke: StyleFactory.style.linePointHighlighterColor,\n            strokeWidthPx: 1.0,\n            dashPattern: dashPattern);\n\n        if (showVerticalFollowLine ==\n            LinePointHighlighterFollowLineType.nearest) {\n          shouldShowVerticalFollowLine = false;\n        }\n\n        paintedVerticalLinePositions.add(roundedX);\n      }\n\n      if (!shouldShowHorizontalFollowLine && !shouldShowVerticalFollowLine) {\n        break;\n      }\n    }\n\n    // Draw the highlight shapes on top of all follow lines.\n    for (final pointElement in points) {\n      if (pointElement.point.x == null || pointElement.point.y == null) {\n        continue;\n      }\n      final point = pointElement.point.toPoint();\n\n      final bounds = Rectangle<double>(\n          point.x - pointElement.radiusPx,\n          point.y - pointElement.radiusPx,\n          pointElement.radiusPx * 2,\n          pointElement.radiusPx * 2);\n\n      // Draw the highlight dot. Use the [SymbolRenderer] from the datum if one\n      // is defined.\n      (pointElement.symbolRenderer ?? symbolRenderer).paint(canvas, bounds,\n          fillColor: pointElement.fillColor,\n          strokeColor: pointElement.color,\n          strokeWidthPx: pointElement.strokeWidthPx);\n    }\n  }\n\n  @override\n  Rectangle<int> get componentBounds => _drawAreaBounds;\n\n  @override\n  bool get isSeriesRenderer => false;\n}\n\nclass _DatumPoint<D> extends NullablePoint {\n  final dynamic datum;\n  final D? domain;\n  final ImmutableSeries<D>? series;\n\n  _DatumPoint({\n    this.datum,\n    this.domain,\n    this.series,\n    double? x,\n    double? y,\n  }) : super(x, y);\n\n  factory _DatumPoint.from(_DatumPoint<D> other, [double? x, double? y]) {\n    return _DatumPoint<D>(\n        datum: other.datum,\n        domain: other.domain,\n        series: other.series,\n        x: x ?? other.x,\n        y: y ?? other.y);\n  }\n}\n\nclass _PointRendererElement<D> {\n  _DatumPoint<D> point;\n  Color? color;\n  Color? fillColor;\n  double radiusPx;\n  double? measureAxisPosition;\n  double? strokeWidthPx;\n  SymbolRenderer? symbolRenderer;\n\n  _PointRendererElement({\n    required this.point,\n    required this.color,\n    required this.fillColor,\n    required this.radiusPx,\n    required this.measureAxisPosition,\n    required this.strokeWidthPx,\n    required this.symbolRenderer,\n  });\n\n  _PointRendererElement<D> clone() {\n    return _PointRendererElement<D>(\n      point: point,\n      color: color,\n      fillColor: fillColor,\n      measureAxisPosition: measureAxisPosition,\n      radiusPx: radiusPx,\n      strokeWidthPx: strokeWidthPx,\n      symbolRenderer: symbolRenderer,\n    );\n  }\n\n  void updateAnimationPercent(_PointRendererElement<D> previous,\n      _PointRendererElement<D> target, double animationPercent) {\n    final targetPoint = target.point;\n    final previousPoint = previous.point;\n\n    final x = _lerpDouble(previousPoint.x, targetPoint.x, animationPercent);\n\n    final y = _lerpDouble(previousPoint.y, targetPoint.y, animationPercent);\n\n    point = _DatumPoint<D>.from(targetPoint, x, y);\n\n    color = getAnimatedColor(previous.color!, target.color!, animationPercent);\n\n    fillColor = getAnimatedColor(\n        previous.fillColor!, target.fillColor!, animationPercent);\n\n    radiusPx =\n        _lerpDouble(previous.radiusPx, target.radiusPx, animationPercent)!;\n\n    final targetStrokeWidthPx = target.strokeWidthPx;\n    final previousStrokeWidthPx = previous.strokeWidthPx;\n    if (targetStrokeWidthPx != null && previousStrokeWidthPx != null) {\n      strokeWidthPx =\n          ((targetStrokeWidthPx - previousStrokeWidthPx) * animationPercent) +\n              previousStrokeWidthPx;\n    } else {\n      strokeWidthPx = null;\n    }\n  }\n\n  /// Linear interpolation for doubles.\n  ///\n  /// If either [a] or [b] is null, return null.\n  /// This is different than Flutter's lerpDouble method, we want to return null\n  /// instead of assuming it is 0.0.\n  double? _lerpDouble(double? a, double? b, double t) {\n    if (a == null || b == null) return null;\n    return a + (b - a) * t;\n  }\n}\n\nclass _AnimatedPoint<D> {\n  final String key;\n  final bool overlaySeries;\n\n  _PointRendererElement<D>? _previousPoint;\n  late _PointRendererElement<D> _targetPoint;\n  _PointRendererElement<D>? _currentPoint;\n\n  // Flag indicating whether this point is being animated out of the chart.\n  bool animatingOut = false;\n\n  _AnimatedPoint({required this.key, required this.overlaySeries});\n\n  /// Animates a point that was removed from the series out of the view.\n  ///\n  /// This should be called in place of \"setNewTarget\" for points that represent\n  /// data that has been removed from the series.\n  ///\n  /// Animates the height of the point down to the measure axis position\n  /// (position of 0).\n  void animateOut() {\n    final newTarget = _currentPoint!.clone();\n\n    // Set the target measure value to the axis position for all points.\n    final targetPoint = newTarget.point;\n\n    final newPoint = _DatumPoint<D>.from(targetPoint, targetPoint.x,\n        newTarget.measureAxisPosition!.roundToDouble());\n\n    newTarget.point = newPoint;\n\n    // Animate the radius to 0 so that we don't get a lingering point after\n    // animation is done.\n    newTarget.radiusPx = 0.0;\n\n    setNewTarget(newTarget);\n    animatingOut = true;\n  }\n\n  void setNewTarget(_PointRendererElement<D> newTarget) {\n    animatingOut = false;\n    _currentPoint ??= newTarget.clone();\n    _previousPoint = _currentPoint!.clone();\n    _targetPoint = newTarget;\n  }\n\n  _PointRendererElement<D> getCurrentPoint(double animationPercent) {\n    if (animationPercent == 1.0 || _previousPoint == null) {\n      _currentPoint = _targetPoint;\n      _previousPoint = _targetPoint;\n      return _currentPoint!;\n    }\n\n    _currentPoint!.updateAnimationPercent(\n        _previousPoint!, _targetPoint, animationPercent);\n\n    return _currentPoint!;\n  }\n}\n\n/// Type of follow line(s) to draw.\nenum LinePointHighlighterFollowLineType {\n  /// Draw a follow line for only the nearest point in the selection.\n  nearest,\n\n  /// Draw no follow lines.\n  none,\n\n  /// Draw a follow line for every point in the selection.\n  all,\n}\n\n/// Helper class that exposes fewer private internal properties for unit tests.\n@visibleForTesting\nclass LinePointHighlighterTester<D> {\n  final LinePointHighlighter<D> behavior;\n\n  LinePointHighlighterTester(this.behavior);\n\n  int getSelectionLength() => behavior._seriesPointMap.length;\n\n  bool isDatumSelected(D datum) => behavior._seriesPointMap.values\n      .any((point) => point._currentPoint!.point.datum == datum);\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/common/behavior/range_annotation.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:collection' show LinkedHashMap;\nimport 'dart:math' show pi, Point, Rectangle;\n\nimport 'package:meta/meta.dart';\n\nimport '../../../common/color.dart' show Color;\nimport '../../../common/graphics_factory.dart' show GraphicsFactory;\nimport '../../../common/style/style_factory.dart' show StyleFactory;\nimport '../../../common/text_element.dart'\n    show MaxWidthStrategy, TextDirection, TextElement;\nimport '../../../common/text_style.dart' show TextStyle;\nimport '../../cartesian/axis/axis.dart' show Axis;\nimport '../../cartesian/axis/spec/axis_spec.dart' show TextStyleSpec;\nimport '../../cartesian/cartesian_chart.dart' show CartesianChart;\nimport '../../layout/layout_view.dart'\n    show\n        LayoutPosition,\n        LayoutView,\n        LayoutViewConfig,\n        LayoutViewPaintOrder,\n        LayoutViewPositionOrder,\n        ViewMeasuredSizes;\nimport '../base_chart.dart' show BaseChart, LifecycleListener;\nimport '../chart_canvas.dart' show ChartCanvas, getAnimatedColor;\nimport '../processed_series.dart' show MutableSeries;\nimport 'chart_behavior.dart' show ChartBehavior;\n\nconst _defaultStrokeWidthPx = 2.0;\n\n/// Chart behavior that annotates domain ranges with a solid fill color.\n///\n/// The annotations will be drawn underneath series data and chart axes.\n///\n/// This is typically used for line charts to call out sections of the data\n/// range.\n///\n/// TODO: Support labels.\nclass RangeAnnotation<D> implements ChartBehavior<D> {\n  static const _defaultLabelAnchor = AnnotationLabelAnchor.end;\n  static const _defaultLabelDirection = AnnotationLabelDirection.auto;\n  static const _defaultLabelPosition = AnnotationLabelPosition.auto;\n  static const _defaultLabelPadding = 5;\n  static final _defaultLabelStyle =\n      TextStyleSpec(fontSize: 12, color: Color.black);\n\n  /// List of annotations to render on the chart.\n  final List<AnnotationSegment<Object>> annotations;\n\n  /// Default color for annotations.\n  final Color defaultColor;\n\n  /// Configures where to anchor annotation label text.\n  final AnnotationLabelAnchor defaultLabelAnchor;\n\n  /// Direction of label text on the annotations.\n  final AnnotationLabelDirection defaultLabelDirection;\n\n  /// Configures where to place labels relative to the annotation.\n  final AnnotationLabelPosition defaultLabelPosition;\n\n  /// Configures the style of label text.\n  final TextStyleSpec defaultLabelStyleSpec;\n\n  /// Configures the stroke width for line annotations.\n  final double defaultStrokeWidthPx;\n\n  /// Whether or not the range of the axis should be extended to include the\n  /// annotation start and end values.\n  final bool extendAxis;\n\n  /// Space before and after label text.\n  final int labelPadding;\n\n  /// Configures the order in which the behavior should be painted.\n  /// This value should be relative to LayoutPaintViewOrder.rangeAnnotation.\n  /// (e.g. LayoutViewPaintOrder.rangeAnnotation + 1)\n  final int layoutPaintOrder;\n\n  late CartesianChart<D> _chart;\n\n  late _RangeAnnotationLayoutView<D> _view;\n\n  late LifecycleListener<D> _lifecycleListener;\n\n  /// Store a map of data drawn on the chart, mapped by series name.\n  ///\n  /// [LinkedHashMap] is used to render the series on the canvas in the same\n  /// order as the data was given to the chart.\n  // ignore: prefer_collection_literals, https://github.com/dart-lang/linter/issues/1649\n  final _annotationMap = LinkedHashMap<String, _AnimatedAnnotation<D>>();\n\n  // Store a list of annotations that exist in the current annotation list.\n  //\n  // This list will be used to remove any [_AnimatedAnnotation] that were\n  // rendered in previous draw cycles, but no longer have a corresponding datum\n  // in the new data.\n  final _currentKeys = <String>[];\n\n  RangeAnnotation(this.annotations,\n      {Color? defaultColor,\n      AnnotationLabelAnchor? defaultLabelAnchor,\n      AnnotationLabelDirection? defaultLabelDirection,\n      AnnotationLabelPosition? defaultLabelPosition,\n      TextStyleSpec? defaultLabelStyleSpec,\n      bool? extendAxis,\n      int? labelPadding,\n      double? defaultStrokeWidthPx,\n      int? layoutPaintOrder})\n      : defaultColor = StyleFactory.style.rangeAnnotationColor,\n        defaultLabelAnchor = defaultLabelAnchor ?? _defaultLabelAnchor,\n        defaultLabelDirection = defaultLabelDirection ?? _defaultLabelDirection,\n        defaultLabelPosition = defaultLabelPosition ?? _defaultLabelPosition,\n        defaultLabelStyleSpec = defaultLabelStyleSpec ?? _defaultLabelStyle,\n        extendAxis = extendAxis ?? true,\n        labelPadding = labelPadding ?? _defaultLabelPadding,\n        defaultStrokeWidthPx = defaultStrokeWidthPx ?? _defaultStrokeWidthPx,\n        layoutPaintOrder =\n            layoutPaintOrder ?? LayoutViewPaintOrder.rangeAnnotation {\n    _lifecycleListener = LifecycleListener<D>(\n        onPostprocess: _updateAxisRange, onAxisConfigured: _updateViewData);\n  }\n\n  @override\n  void attachTo(BaseChart<D> chart) {\n    if (chart is! CartesianChart<D>) {\n      throw ArgumentError(\n          'RangeAnnotation can only be attached to a CartesianChart<D>');\n    }\n\n    _chart = chart;\n\n    _view = _RangeAnnotationLayoutView<D>(\n        defaultColor: defaultColor,\n        labelPadding: labelPadding,\n        chart: _chart,\n        rangeAnnotation: this,\n        layoutPaintOrder: layoutPaintOrder);\n\n    chart.addView(_view);\n\n    chart.addLifecycleListener(_lifecycleListener);\n  }\n\n  @override\n  void removeFrom(BaseChart<D> chart) {\n    chart.removeView(_view);\n    chart.removeLifecycleListener(_lifecycleListener);\n\n    _view.chart = null;\n  }\n\n  /// Sub-classes can override this method to control label visibility.\n  @protected\n  bool shouldShowLabels(AnnotationSegment<Object> annotation) => true;\n\n  void _updateAxisRange(List<MutableSeries<D>> seriesList) {\n    // Extend the axis range if enabled.\n    if (extendAxis) {\n      for (final annotation in annotations) {\n        // Either an Axis<D> and Axis<num>.\n        Axis<Object?> axis;\n\n        switch (annotation.axisType) {\n          case RangeAnnotationAxisType.domain:\n            axis = _chart.domainAxis!;\n            break;\n\n          case RangeAnnotationAxisType.measure:\n            // We expect an empty axisId to get us the primary measure axis.\n            axis = _chart.getMeasureAxis(axisId: annotation.axisId);\n            break;\n        }\n\n        if (annotation is RangeAnnotationSegment<Object>) {\n          axis.addDomainValue(annotation.startValue);\n          axis.addDomainValue(annotation.endValue);\n        } else if (annotation is LineAnnotationSegment<Object>) {\n          axis.addDomainValue(annotation.value);\n        }\n      }\n    }\n  }\n\n  void _updateViewData() {\n    _currentKeys.clear();\n\n    // The values (T) can match the data type of the domain (D) or measure axis\n    // (num).\n    void updateAnnotation<T>(\n      Axis<T> axis,\n      AnnotationSegment<Object> annotation,\n    ) {\n      final key = annotation.key;\n\n      final color = annotation.color ?? defaultColor;\n\n      final startLabel = annotation.startLabel;\n      final endLabel = annotation.endLabel;\n      final middleLabel = annotation.middleLabel;\n      final labelAnchor = annotation.labelAnchor ?? defaultLabelAnchor;\n      var labelDirection = annotation.labelDirection ?? defaultLabelDirection;\n\n      if (labelDirection == AnnotationLabelDirection.auto) {\n        switch (annotation.axisType) {\n          case RangeAnnotationAxisType.domain:\n            labelDirection = AnnotationLabelDirection.vertical;\n            break;\n\n          case RangeAnnotationAxisType.measure:\n            labelDirection = AnnotationLabelDirection.horizontal;\n            break;\n        }\n      }\n\n      final labelPosition = annotation.labelPosition ?? defaultLabelPosition;\n      final labelStyleSpec = annotation.labelStyleSpec ?? defaultLabelStyleSpec;\n\n      // Add line annotation settings.\n      final dashPattern = annotation is LineAnnotationSegment<Object>\n          ? annotation.dashPattern\n          : null;\n      final strokeWidthPx = annotation is LineAnnotationSegment<Object>\n          ? annotation.strokeWidthPx\n          : 0.0;\n\n      final isRange = annotation is RangeAnnotationSegment;\n\n      final T startValue;\n      final T endValue;\n\n      // We unfortunately can't check for `RangeAnnotationSegment<T>` nor\n      // `LineAnnotationSegment<T>` here because the `AnnotationSegment` object\n      // might not have been parameterized on `T` when it was initially\n      // constructed.\n      if (annotation is RangeAnnotationSegment<Object>) {\n        startValue = annotation.startValue as T;\n        endValue = annotation.endValue as T;\n      } else if (annotation is LineAnnotationSegment<Object>) {\n        startValue = endValue = annotation.value as T;\n      } else {\n        throw UnsupportedError(\n            'Unrecognized annotation type: ${annotation.runtimeType}');\n      }\n\n      final annotationDatum =\n          _getAnnotationDatum(startValue, endValue, axis, annotation.axisType);\n\n      // If we already have a animatingAnnotation for that index, use it.\n      var animatingAnnotation = _annotationMap[key];\n      if (animatingAnnotation == null) {\n        // Create a new annotation, positioned at the start and end values.\n        animatingAnnotation = _AnimatedAnnotation<D>(key: key)\n          ..setNewTarget(_AnnotationElement<D>(\n            annotation: annotationDatum,\n            annotationSegment: annotation,\n            color: color,\n            dashPattern: dashPattern,\n            startLabel: startLabel,\n            endLabel: endLabel,\n            middleLabel: middleLabel,\n            isRange: isRange,\n            labelAnchor: labelAnchor,\n            labelDirection: labelDirection,\n            labelPosition: labelPosition,\n            labelStyleSpec: labelStyleSpec,\n            strokeWidthPx: strokeWidthPx,\n          ));\n\n        _annotationMap[key] = animatingAnnotation;\n      }\n\n      // Update the set of annotations that still exist in the series data.\n      _currentKeys.add(key);\n\n      // Get the annotation element we are going to setup.\n      final annotationElement = _AnnotationElement<D>(\n        annotation: annotationDatum,\n        annotationSegment: annotation,\n        color: color,\n        dashPattern: dashPattern,\n        startLabel: startLabel,\n        endLabel: endLabel,\n        middleLabel: middleLabel,\n        isRange: isRange,\n        labelAnchor: labelAnchor,\n        labelDirection: labelDirection,\n        labelPosition: labelPosition,\n        labelStyleSpec: labelStyleSpec,\n        strokeWidthPx: strokeWidthPx,\n      );\n\n      animatingAnnotation.setNewTarget(annotationElement);\n    }\n\n    for (final annotation in annotations) {\n      switch (annotation.axisType) {\n        case RangeAnnotationAxisType.domain:\n          updateAnnotation(_chart.domainAxis!, annotation);\n          break;\n\n        case RangeAnnotationAxisType.measure:\n          // We expect an empty axisId to get us the primary measure axis.\n          updateAnnotation(\n              _chart.getMeasureAxis(axisId: annotation.axisId), annotation);\n          break;\n      }\n    }\n\n    // Animate out annotations that don't exist anymore.\n    _annotationMap.forEach((String key, _AnimatedAnnotation<D> annotation) {\n      if (!_currentKeys.contains(annotation.key)) {\n        annotation.animateOut();\n      }\n    });\n\n    _view.annotationMap = _annotationMap;\n  }\n\n  /// Generates a datum that describes an annotation.\n  ///\n  /// [startValue] and [endValue] are dynamic because they can be different data\n  /// types for domain and measure axes, e.g. DateTime and num for a TimeSeries\n  /// chart.\n  _DatumAnnotation _getAnnotationDatum<T>(T startValue, T endValue,\n      Axis<T> axis, RangeAnnotationAxisType axisType) {\n    // Remove floating point rounding errors by rounding to 2 decimal places of\n    // precision. The difference in the canvas is negligible.\n    final startPosition = (axis.getLocation(startValue)! * 100).round() / 100;\n    final endPosition = (axis.getLocation(endValue)! * 100).round() / 100;\n\n    return _DatumAnnotation(\n        startPosition: startPosition,\n        endPosition: endPosition,\n        axisType: axisType);\n  }\n\n  @override\n  String get role => 'RangeAnnotation';\n}\n\nclass _RangeAnnotationLayoutView<D> extends LayoutView {\n  @override\n  final LayoutViewConfig layoutConfig;\n\n  final Color defaultColor;\n\n  final int labelPadding;\n\n  final RangeAnnotation<D> rangeAnnotation;\n\n  final int layoutPaintOrder;\n\n  CartesianChart<D>? chart;\n\n  bool get isRtl => chart!.context.isRtl;\n\n  late Rectangle<int> _drawAreaBounds;\n\n  Rectangle<int> get drawBounds => _drawAreaBounds;\n\n  @override\n  GraphicsFactory? graphicsFactory;\n\n  /// Store a map of series drawn on the chart, mapped by series name.\n  ///\n  /// [LinkedHashMap] is used to render the series on the canvas in the same\n  /// order as the data was given to the chart.\n  LinkedHashMap<String, _AnimatedAnnotation<D>>? _annotationMap;\n\n  _RangeAnnotationLayoutView(\n      {required this.defaultColor,\n      required this.labelPadding,\n      required this.chart,\n      required this.rangeAnnotation,\n      required this.layoutPaintOrder})\n      : layoutConfig = LayoutViewConfig(\n            paintOrder: layoutPaintOrder,\n            position: LayoutPosition.DrawArea,\n            positionOrder: LayoutViewPositionOrder.drawArea);\n\n  set annotationMap(LinkedHashMap<String, _AnimatedAnnotation<D>> value) {\n    _annotationMap = value;\n  }\n\n  @override\n  ViewMeasuredSizes? measure(int maxWidth, int maxHeight) {\n    return null;\n  }\n\n  @override\n  void layout(Rectangle<int> componentBounds, Rectangle<int> drawAreaBounds) {\n    _drawAreaBounds = drawAreaBounds;\n  }\n\n  @override\n  void paint(ChartCanvas canvas, double animationPercent) {\n    final _annotationMap = this._annotationMap;\n    if (_annotationMap == null) {\n      return;\n    }\n\n    // Clean up the annotations that no longer exist.\n    if (animationPercent == 1.0) {\n      final keysToRemove = <String>[];\n\n      _annotationMap.forEach((String key, _AnimatedAnnotation<D> annotation) {\n        if (annotation.animatingOut) {\n          keysToRemove.add(key);\n        }\n      });\n\n      keysToRemove.forEach(_annotationMap.remove);\n    }\n\n    _annotationMap.forEach((String key, _AnimatedAnnotation<D> annotation) {\n      final annotationElement =\n          annotation.getCurrentAnnotation(animationPercent);\n\n      // Calculate the bounds of a range annotation.\n      //\n      // This will still be used for line annotations to compute the position of\n      // labels. We always expect those to end up outside, since the bounds will\n      // have zero width or  height.\n      final bounds = _getAnnotationBounds(annotationElement);\n\n      if (annotationElement.isRange) {\n        // Draw the annotation.\n        canvas.drawRect(bounds, fill: annotationElement.color);\n      } else {\n        // Calculate the points for a line annotation.\n        final points = _getLineAnnotationPoints(annotationElement);\n\n        // Draw the annotation.\n        canvas.drawLine(\n            dashPattern: annotationElement.dashPattern,\n            points: points,\n            stroke: annotationElement.color,\n            strokeWidthPx: annotationElement.strokeWidthPx);\n      }\n\n      // Create [TextStyle] from [TextStyleSpec] to be used by all the elements.\n      // The [GraphicsFactory] is needed so it can't be created earlier.\n      final labelStyle =\n          _getTextStyle(graphicsFactory!, annotationElement.labelStyleSpec);\n\n      final rotation =\n          annotationElement.labelDirection == AnnotationLabelDirection.vertical\n              ? -pi / 2\n              : 0.0;\n\n      if (rangeAnnotation\n          .shouldShowLabels(annotationElement.annotationSegment)) {\n        final labels = {\n          if (annotationElement.startLabel != null)\n            _AnnotationLabelType.start: annotationElement.startLabel,\n          if (annotationElement.endLabel != null)\n            _AnnotationLabelType.end: annotationElement.endLabel,\n          if (annotationElement.middleLabel != null)\n            _AnnotationLabelType.middle: annotationElement.middleLabel,\n        };\n\n        // Draw labels that have been defined.\n        labels.forEach((labelType, label) {\n          final labelElement = graphicsFactory!.createTextElement(label!)\n            ..maxWidthStrategy = MaxWidthStrategy.ellipsize\n            ..textStyle = labelStyle;\n\n          // Measure the label max width once if either type of label is defined.\n          labelElement.maxWidth =\n              _getLabelMaxWidth(bounds, annotationElement, labelElement);\n\n          final labelPoint = _getLabelPosition(\n              labelType, bounds, annotationElement, labelElement);\n\n          if (labelPoint != null) {\n            canvas.drawText(labelElement, labelPoint.x, labelPoint.y,\n                rotation: rotation);\n          }\n        });\n      }\n    });\n  }\n\n  /// Calculates the bounds of the annotation.\n  Rectangle<num> _getAnnotationBounds(_AnnotationElement<D> annotationElement) {\n    Rectangle<num> bounds;\n\n    switch (annotationElement.annotation.axisType) {\n      case RangeAnnotationAxisType.domain:\n        bounds = Rectangle<num>(\n            annotationElement.annotation.startPosition,\n            _drawAreaBounds.top,\n            annotationElement.annotation.endPosition -\n                annotationElement.annotation.startPosition,\n            _drawAreaBounds.height);\n        break;\n\n      case RangeAnnotationAxisType.measure:\n        bounds = Rectangle<num>(\n            _drawAreaBounds.left,\n            annotationElement.annotation.endPosition,\n            _drawAreaBounds.width,\n            annotationElement.annotation.startPosition -\n                annotationElement.annotation.endPosition);\n        break;\n    }\n\n    return bounds;\n  }\n\n  /// Calculates the bounds of the annotation.\n  List<Point> _getLineAnnotationPoints(\n      _AnnotationElement<D> annotationElement) {\n    final points = <Point>[];\n\n    switch (annotationElement.annotation.axisType) {\n      case RangeAnnotationAxisType.domain:\n        points.add(Point<num>(\n            annotationElement.annotation.startPosition, _drawAreaBounds.top));\n        points.add(Point<num>(\n            annotationElement.annotation.endPosition, _drawAreaBounds.bottom));\n        break;\n\n      case RangeAnnotationAxisType.measure:\n        points.add(Point<num>(\n            _drawAreaBounds.left, annotationElement.annotation.startPosition));\n        points.add(Point<num>(\n            _drawAreaBounds.right, annotationElement.annotation.endPosition));\n        break;\n    }\n\n    return points;\n  }\n\n  /// Measures the max label width of the annotation.\n  int _getLabelMaxWidth(Rectangle<num> bounds,\n      _AnnotationElement<D> annotationElement, TextElement labelElement) {\n    num maxWidth = 0;\n\n    final calculatedLabelPosition =\n        _resolveAutoLabelPosition(bounds, annotationElement, labelElement);\n\n    if (annotationElement.labelPosition == AnnotationLabelPosition.margin &&\n        annotationElement.annotation.axisType ==\n            RangeAnnotationAxisType.measure) {\n      switch (annotationElement.annotation.axisType) {\n        case RangeAnnotationAxisType.domain:\n          break;\n\n        case RangeAnnotationAxisType.measure:\n          switch (annotationElement.labelAnchor) {\n            case AnnotationLabelAnchor.start:\n              maxWidth = chart!.marginLeft - labelPadding;\n              break;\n\n            case AnnotationLabelAnchor.end:\n              maxWidth = chart!.marginRight - labelPadding;\n              break;\n\n            case AnnotationLabelAnchor.middle:\n              break;\n          }\n          break;\n      }\n    } else {\n      if (calculatedLabelPosition == AnnotationLabelPosition.outside) {\n        maxWidth = annotationElement.labelDirection ==\n                AnnotationLabelDirection.horizontal\n            ? drawBounds.width\n            : drawBounds.height;\n      } else {\n        maxWidth = annotationElement.labelDirection ==\n                AnnotationLabelDirection.horizontal\n            ? bounds.width\n            : bounds.height;\n      }\n    }\n\n    return maxWidth.round();\n  }\n\n  /// Gets the resolved location for a label element.\n  Point<int>? _getLabelPosition(\n      _AnnotationLabelType labelType,\n      Rectangle<num> bounds,\n      _AnnotationElement<D> annotationElement,\n      TextElement labelElement) {\n    switch (annotationElement.annotation.axisType) {\n      case RangeAnnotationAxisType.domain:\n        return _getDomainLabelPosition(\n            labelType, bounds, annotationElement, labelElement);\n\n      case RangeAnnotationAxisType.measure:\n        return _getMeasureLabelPosition(\n            labelType, bounds, annotationElement, labelElement);\n    }\n  }\n\n  /// Gets the resolved location for a domain annotation label element.\n  Point<int> _getDomainLabelPosition(\n      _AnnotationLabelType labelType,\n      Rectangle<num> bounds,\n      _AnnotationElement<D> annotationElement,\n      TextElement labelElement) {\n    if (annotationElement.labelDirection == AnnotationLabelDirection.vertical) {\n      return _getDomainLabelPositionVertical(\n          labelType, bounds, annotationElement, labelElement);\n    } else {\n      return _getDomainLabelPositionHorizontal(\n          labelType, bounds, annotationElement, labelElement);\n    }\n  }\n\n  /// Gets the resolved location for a horizontal domain annotation label\n  /// element.\n  Point<int> _getDomainLabelPositionHorizontal(\n      _AnnotationLabelType labelType,\n      Rectangle<num> bounds,\n      _AnnotationElement<D> annotationElement,\n      TextElement labelElement) {\n    num labelX = 0;\n    num labelY = 0;\n\n    final calculatedLabelPosition =\n        _resolveAutoLabelPosition(bounds, annotationElement, labelElement);\n\n    switch (annotationElement.labelAnchor) {\n      case AnnotationLabelAnchor.middle:\n        labelY = bounds.top +\n            bounds.height / 2 -\n            labelElement.measurement.verticalSliceWidth / 2 -\n            labelPadding;\n        break;\n\n      case AnnotationLabelAnchor.end:\n        if (annotationElement.labelPosition == AnnotationLabelPosition.margin) {\n          labelY = bounds.top -\n              labelElement.measurement.verticalSliceWidth -\n              labelPadding;\n        } else {\n          labelY = bounds.top + labelPadding;\n        }\n        break;\n\n      case AnnotationLabelAnchor.start:\n        if (annotationElement.labelPosition == AnnotationLabelPosition.margin) {\n          labelY = bounds.bottom + labelPadding;\n        } else {\n          labelY = bounds.bottom -\n              labelElement.measurement.verticalSliceWidth -\n              labelPadding;\n        }\n        break;\n    }\n\n    switch (calculatedLabelPosition) {\n      case AnnotationLabelPosition.margin:\n      case AnnotationLabelPosition.auto:\n        throw ArgumentError(_unresolvedAutoMessage);\n\n      case AnnotationLabelPosition.outside:\n        switch (labelType) {\n          case _AnnotationLabelType.start:\n            labelX = bounds.left -\n                labelElement.measurement.horizontalSliceWidth -\n                labelPadding;\n            break;\n          case _AnnotationLabelType.end:\n            labelX = bounds.right + labelPadding;\n            break;\n          case _AnnotationLabelType.middle:\n            labelX = bounds.left +\n                (bounds.width - labelElement.measurement.horizontalSliceWidth) /\n                    2;\n            break;\n        }\n\n        labelElement.textDirection =\n            isRtl ? TextDirection.rtl : TextDirection.ltr;\n        break;\n\n      case AnnotationLabelPosition.inside:\n        switch (labelType) {\n          case _AnnotationLabelType.start:\n            labelX = bounds.left + labelPadding;\n            break;\n          case _AnnotationLabelType.end:\n            labelX = bounds.right -\n                labelElement.measurement.horizontalSliceWidth -\n                labelPadding;\n            break;\n          case _AnnotationLabelType.middle:\n            labelX = bounds.left +\n                (bounds.width - labelElement.measurement.horizontalSliceWidth) /\n                    2;\n            break;\n        }\n\n        labelElement.textDirection =\n            isRtl ? TextDirection.rtl : TextDirection.ltr;\n        break;\n    }\n\n    return Point<int>(labelX.round(), labelY.round());\n  }\n\n  /// Gets the resolved location for a vertical domain annotation label element.\n  Point<int> _getDomainLabelPositionVertical(\n      _AnnotationLabelType labelType,\n      Rectangle<num> bounds,\n      _AnnotationElement<D> annotationElement,\n      TextElement labelElement) {\n    num labelX = 0;\n    num labelY = 0;\n\n    final calculatedLabelPosition =\n        _resolveAutoLabelPosition(bounds, annotationElement, labelElement);\n\n    switch (annotationElement.labelAnchor) {\n      case AnnotationLabelAnchor.middle:\n        labelY = bounds.top +\n            bounds.height / 2 +\n            labelElement.measurement.horizontalSliceWidth / 2 +\n            labelPadding;\n        break;\n\n      case AnnotationLabelAnchor.end:\n        if (annotationElement.labelPosition == AnnotationLabelPosition.margin) {\n          labelY = bounds.top +\n              labelElement.measurement.horizontalSliceWidth +\n              labelPadding;\n        } else {\n          labelY = bounds.top +\n              labelElement.measurement.horizontalSliceWidth +\n              labelPadding;\n        }\n        break;\n\n      case AnnotationLabelAnchor.start:\n        if (annotationElement.labelPosition == AnnotationLabelPosition.margin) {\n          labelY = bounds.bottom + labelPadding;\n        } else {\n          labelY = bounds.bottom -\n              labelElement.measurement.horizontalSliceWidth -\n              labelPadding;\n        }\n        break;\n    }\n\n    switch (calculatedLabelPosition) {\n      case AnnotationLabelPosition.margin:\n      case AnnotationLabelPosition.auto:\n        throw ArgumentError(_unresolvedAutoMessage);\n\n      case AnnotationLabelPosition.outside:\n        switch (labelType) {\n          case _AnnotationLabelType.start:\n            labelX = bounds.left -\n                labelElement.measurement.verticalSliceWidth -\n                labelPadding;\n            break;\n          case _AnnotationLabelType.end:\n            labelX = bounds.right + labelPadding;\n            break;\n          case _AnnotationLabelType.middle:\n            labelX = bounds.left +\n                (bounds.width - labelElement.measurement.verticalSliceWidth) /\n                    2;\n            break;\n        }\n\n        labelElement.textDirection =\n            isRtl ? TextDirection.rtl : TextDirection.ltr;\n        break;\n\n      case AnnotationLabelPosition.inside:\n        switch (labelType) {\n          case _AnnotationLabelType.start:\n            labelX = bounds.left + labelPadding;\n            break;\n          case _AnnotationLabelType.end:\n            labelX = bounds.right -\n                labelElement.measurement.verticalSliceWidth -\n                labelPadding;\n            break;\n          case _AnnotationLabelType.middle:\n            labelX = bounds.left +\n                (bounds.width - labelElement.measurement.verticalSliceWidth) /\n                    2;\n            break;\n        }\n\n        labelElement.textDirection =\n            isRtl ? TextDirection.rtl : TextDirection.ltr;\n        break;\n    }\n\n    return Point<int>(labelX.round(), labelY.round());\n  }\n\n  /// Gets the resolved location for a measure annotation label element.\n  Point<int> _getMeasureLabelPosition(\n      _AnnotationLabelType labelType,\n      Rectangle<num> bounds,\n      _AnnotationElement<D> annotationElement,\n      TextElement labelElement) {\n    if (annotationElement.labelDirection == AnnotationLabelDirection.vertical) {\n      return _getMeasureLabelPositionVertical(\n          labelType, bounds, annotationElement, labelElement);\n    } else {\n      return _getMeasureLabelPositionHorizontal(\n          labelType, bounds, annotationElement, labelElement);\n    }\n  }\n\n  /// Gets the resolved location for a horizontal measure annotation label\n  /// element.\n  Point<int> _getMeasureLabelPositionHorizontal(\n      _AnnotationLabelType labelType,\n      Rectangle<num> bounds,\n      _AnnotationElement<D> annotationElement,\n      TextElement labelElement) {\n    num labelX = 0;\n    num labelY = 0;\n\n    final calculatedLabelPosition =\n        _resolveAutoLabelPosition(bounds, annotationElement, labelElement);\n\n    switch (annotationElement.labelAnchor) {\n      case AnnotationLabelAnchor.middle:\n        labelX = bounds.left +\n            bounds.width / 2 -\n            labelElement.measurement.horizontalSliceWidth / 2;\n        labelElement.textDirection =\n            isRtl ? TextDirection.rtl : TextDirection.ltr;\n        break;\n\n      case AnnotationLabelAnchor.end:\n      case AnnotationLabelAnchor.start:\n        if (annotationElement.labelPosition == AnnotationLabelPosition.margin) {\n          final alignLeft = isRtl\n              ? (annotationElement.labelAnchor == AnnotationLabelAnchor.end)\n              : (annotationElement.labelAnchor == AnnotationLabelAnchor.start);\n\n          if (alignLeft) {\n            labelX = bounds.left - labelPadding;\n            labelElement.textDirection = TextDirection.rtl;\n          } else {\n            labelX = bounds.right + labelPadding;\n            labelElement.textDirection = TextDirection.ltr;\n          }\n        } else {\n          final alignLeft = isRtl\n              ? (annotationElement.labelAnchor == AnnotationLabelAnchor.end)\n              : (annotationElement.labelAnchor == AnnotationLabelAnchor.start);\n\n          if (alignLeft) {\n            labelX = bounds.left + labelPadding;\n            labelElement.textDirection = TextDirection.ltr;\n          } else {\n            labelX = bounds.right - labelPadding;\n            labelElement.textDirection = TextDirection.rtl;\n          }\n        }\n        break;\n    }\n\n    switch (calculatedLabelPosition) {\n      case AnnotationLabelPosition.margin:\n      case AnnotationLabelPosition.auto:\n        throw ArgumentError(_unresolvedAutoMessage);\n\n      case AnnotationLabelPosition.outside:\n        switch (labelType) {\n          case _AnnotationLabelType.start:\n            labelY = bounds.bottom + labelPadding;\n            break;\n          case _AnnotationLabelType.end:\n            labelY = bounds.top -\n                labelElement.measurement.verticalSliceWidth -\n                labelPadding;\n            break;\n          case _AnnotationLabelType.middle:\n            labelY = bounds.top +\n                (bounds.height - labelElement.measurement.verticalSliceWidth) /\n                    2;\n            break;\n        }\n        break;\n\n      case AnnotationLabelPosition.inside:\n        switch (labelType) {\n          case _AnnotationLabelType.start:\n            labelY = bounds.bottom -\n                labelElement.measurement.verticalSliceWidth -\n                labelPadding;\n            break;\n          case _AnnotationLabelType.end:\n            labelY = bounds.top + labelPadding;\n            break;\n          case _AnnotationLabelType.middle:\n            labelY = bounds.top +\n                (bounds.height - labelElement.measurement.verticalSliceWidth) /\n                    2;\n            break;\n        }\n        break;\n    }\n\n    return Point<int>(labelX.round(), labelY.round());\n  }\n\n  /// Gets the resolved location for a vertical measure annotation label\n  /// element.\n  Point<int> _getMeasureLabelPositionVertical(\n      _AnnotationLabelType labelType,\n      Rectangle<num> bounds,\n      _AnnotationElement<D> annotationElement,\n      TextElement labelElement) {\n    num labelX = 0;\n    num labelY = 0;\n\n    final calculatedLabelPosition =\n        _resolveAutoLabelPosition(bounds, annotationElement, labelElement);\n\n    switch (annotationElement.labelAnchor) {\n      case AnnotationLabelAnchor.middle:\n        labelX = bounds.left +\n            bounds.width / 2 -\n            labelElement.measurement.verticalSliceWidth / 2;\n        labelElement.textDirection =\n            isRtl ? TextDirection.rtl : TextDirection.ltr;\n        break;\n\n      case AnnotationLabelAnchor.end:\n      case AnnotationLabelAnchor.start:\n        if (annotationElement.labelPosition == AnnotationLabelPosition.margin) {\n          final alignLeft = isRtl\n              ? (annotationElement.labelAnchor == AnnotationLabelAnchor.end)\n              : (annotationElement.labelAnchor == AnnotationLabelAnchor.start);\n\n          if (alignLeft) {\n            labelX = bounds.left -\n                labelElement.measurement.verticalSliceWidth -\n                labelPadding;\n            labelElement.textDirection = TextDirection.ltr;\n          } else {\n            labelX = bounds.right + labelPadding;\n            labelElement.textDirection = TextDirection.ltr;\n          }\n        } else {\n          final alignLeft = isRtl\n              ? (annotationElement.labelAnchor == AnnotationLabelAnchor.end)\n              : (annotationElement.labelAnchor == AnnotationLabelAnchor.start);\n\n          if (alignLeft) {\n            labelX = bounds.left + labelPadding;\n            labelElement.textDirection = TextDirection.ltr;\n          } else {\n            labelX = bounds.right -\n                labelElement.measurement.verticalSliceWidth -\n                labelPadding;\n            labelElement.textDirection = TextDirection.ltr;\n          }\n        }\n        break;\n    }\n\n    switch (calculatedLabelPosition) {\n      case AnnotationLabelPosition.margin:\n      case AnnotationLabelPosition.auto:\n        throw ArgumentError(_unresolvedAutoMessage);\n\n      case AnnotationLabelPosition.outside:\n        switch (labelType) {\n          case _AnnotationLabelType.start:\n            labelY = bounds.bottom +\n                labelElement.measurement.horizontalSliceWidth +\n                labelPadding;\n            break;\n          case _AnnotationLabelType.end:\n            labelY = bounds.top - labelPadding;\n            break;\n          case _AnnotationLabelType.middle:\n            labelY = bounds.bottom +\n                (labelElement.measurement.horizontalSliceWidth -\n                        bounds.height) /\n                    2;\n            break;\n        }\n        break;\n\n      case AnnotationLabelPosition.inside:\n        switch (labelType) {\n          case _AnnotationLabelType.start:\n            labelY = bounds.bottom - labelPadding;\n            break;\n          case _AnnotationLabelType.end:\n            labelY = bounds.top +\n                labelElement.measurement.horizontalSliceWidth +\n                labelPadding;\n            break;\n          case _AnnotationLabelType.middle:\n            labelY = bounds.bottom +\n                (labelElement.measurement.horizontalSliceWidth -\n                        bounds.height) /\n                    2;\n            break;\n        }\n        break;\n    }\n\n    return Point<int>(labelX.round(), labelY.round());\n  }\n\n  /// Resolves [AnnotationLabelPosition.auto] configuration for an annotation\n  /// into an inside or outside position, depending on the size of the\n  /// annotation and the chart draw area.\n  AnnotationLabelPosition _resolveAutoLabelPosition(Rectangle<num> bounds,\n      _AnnotationElement<D> annotationElement, TextElement labelElement) {\n    var calculatedLabelPosition = annotationElement.labelPosition;\n    if (calculatedLabelPosition == AnnotationLabelPosition.auto ||\n        calculatedLabelPosition == AnnotationLabelPosition.margin) {\n      final isDomain = annotationElement.annotation.axisType ==\n          RangeAnnotationAxisType.domain;\n\n      final annotationBoundsSize = isDomain ? bounds.width : bounds.height;\n\n      final drawBoundsSize = isDomain ? drawBounds.width : drawBounds.height;\n\n      final isVertical =\n          annotationElement.labelDirection == AnnotationLabelDirection.vertical;\n\n      final labelSize = isDomain && isVertical || !isDomain && !isVertical\n          ? labelElement.measurement.verticalSliceWidth\n          : labelElement.measurement.horizontalSliceWidth;\n\n      // Get space available inside and outside the annotation.\n      final totalPadding = labelPadding * 2;\n      final insideBarWidth = annotationBoundsSize - totalPadding;\n      final outsideBarWidth =\n          drawBoundsSize - annotationBoundsSize - totalPadding;\n\n      // A label fits if the space inside the annotation is >= outside\n      // annotation or if the length of the text fits and the space. This is\n      // because if the annotation has more space than the outside, it makes\n      // more sense to place the label inside the annotation, even if the\n      // entire label does not fit.\n      calculatedLabelPosition =\n          (insideBarWidth >= outsideBarWidth || labelSize < insideBarWidth)\n              ? AnnotationLabelPosition.inside\n              : AnnotationLabelPosition.outside;\n    }\n\n    return calculatedLabelPosition;\n  }\n\n  @override\n  Rectangle<int> get componentBounds => _drawAreaBounds;\n\n  @override\n  bool get isSeriesRenderer => false;\n\n  // Helper function that converts [TextStyleSpec] to [TextStyle].\n  TextStyle _getTextStyle(\n      GraphicsFactory graphicsFactory, TextStyleSpec labelSpec) {\n    return graphicsFactory.createTextPaint()\n      ..color = labelSpec.color ?? Color.black\n      ..fontFamily = labelSpec.fontFamily\n      ..fontSize = labelSpec.fontSize ?? 12\n      ..lineHeight = labelSpec.lineHeight;\n  }\n}\n\nclass _DatumAnnotation {\n  final double startPosition;\n  final double endPosition;\n  final RangeAnnotationAxisType axisType;\n\n  _DatumAnnotation({\n    required this.startPosition,\n    required this.endPosition,\n    required this.axisType,\n  });\n\n  factory _DatumAnnotation.from(_DatumAnnotation other,\n      [double? startPosition, double? endPosition]) {\n    return _DatumAnnotation(\n        startPosition: startPosition ?? other.startPosition,\n        endPosition: endPosition ?? other.endPosition,\n        axisType: other.axisType);\n  }\n}\n\nclass _AnnotationElement<D> {\n  _DatumAnnotation annotation;\n  final AnnotationSegment<Object> annotationSegment;\n  Color? color;\n  final String? startLabel;\n  final String? endLabel;\n  final String? middleLabel;\n  final bool isRange;\n  final AnnotationLabelAnchor labelAnchor;\n  final AnnotationLabelDirection labelDirection;\n  final AnnotationLabelPosition labelPosition;\n  final TextStyleSpec labelStyleSpec;\n  final List<int>? dashPattern;\n  double strokeWidthPx;\n\n  _AnnotationElement({\n    required this.annotation,\n    required this.annotationSegment,\n    required this.color,\n    required this.startLabel,\n    required this.endLabel,\n    required this.middleLabel,\n    required this.isRange,\n    required this.labelAnchor,\n    required this.labelDirection,\n    required this.labelPosition,\n    required this.labelStyleSpec,\n    required this.dashPattern,\n    required this.strokeWidthPx,\n  });\n\n  _AnnotationElement<D> clone() {\n    return _AnnotationElement<D>(\n      annotation: _DatumAnnotation.from(annotation),\n      annotationSegment: annotationSegment,\n      color: color != null ? Color.fromOther(color: color!) : null,\n      startLabel: startLabel,\n      endLabel: endLabel,\n      middleLabel: middleLabel,\n      isRange: isRange,\n      labelAnchor: labelAnchor,\n      labelDirection: labelDirection,\n      labelPosition: labelPosition,\n      labelStyleSpec: labelStyleSpec,\n      dashPattern: dashPattern,\n      strokeWidthPx: strokeWidthPx,\n    );\n  }\n\n  void updateAnimationPercent(\n    _AnnotationElement<D> previous,\n    _AnnotationElement<D> target,\n    double animationPercent,\n  ) {\n    final targetAnnotation = target.annotation;\n    final previousAnnotation = previous.annotation;\n\n    final startPosition =\n        ((targetAnnotation.startPosition - previousAnnotation.startPosition) *\n                animationPercent) +\n            previousAnnotation.startPosition;\n\n    final endPosition =\n        ((targetAnnotation.endPosition - previousAnnotation.endPosition) *\n                animationPercent) +\n            previousAnnotation.endPosition;\n\n    annotation =\n        _DatumAnnotation.from(targetAnnotation, startPosition, endPosition);\n\n    color = getAnimatedColor(previous.color!, target.color!, animationPercent);\n\n    strokeWidthPx =\n        ((target.strokeWidthPx - previous.strokeWidthPx) * animationPercent) +\n            previous.strokeWidthPx;\n  }\n}\n\nenum _AnnotationLabelType {\n  start,\n  end,\n  middle,\n}\n\nclass _AnimatedAnnotation<D> {\n  final String key;\n\n  _AnnotationElement<D>? _previousAnnotation;\n  late _AnnotationElement<D> _targetAnnotation;\n  _AnnotationElement<D>? _currentAnnotation;\n\n  // Flag indicating whether this annotation is being animated out of the chart.\n  bool animatingOut = false;\n\n  _AnimatedAnnotation({required this.key});\n\n  /// Animates an annotation that was removed from the list out of the view.\n  ///\n  /// This should be called in place of \"setNewTarget\" for annotations have been\n  /// removed from the list.\n  /// TODO: Needed?\n  void animateOut() {\n    final newTarget = _currentAnnotation!.clone();\n\n    setNewTarget(newTarget);\n    animatingOut = true;\n  }\n\n  void setNewTarget(_AnnotationElement<D> newTarget) {\n    animatingOut = false;\n    _currentAnnotation ??= newTarget.clone();\n    _previousAnnotation = _currentAnnotation!.clone();\n    _targetAnnotation = newTarget;\n  }\n\n  _AnnotationElement<D> getCurrentAnnotation(double animationPercent) {\n    if (animationPercent == 1.0 || _previousAnnotation == null) {\n      _currentAnnotation = _targetAnnotation;\n      _previousAnnotation = _targetAnnotation;\n      return _currentAnnotation!;\n    }\n\n    _currentAnnotation!.updateAnimationPercent(\n        _previousAnnotation!, _targetAnnotation, animationPercent);\n\n    return _currentAnnotation!;\n  }\n}\n\n/// Helper class that exposes fewer private internal properties for unit tests.\n@visibleForTesting\nclass RangeAnnotationTester<D> {\n  final RangeAnnotation<D> behavior;\n\n  RangeAnnotationTester(this.behavior);\n\n  set graphicsFactory(GraphicsFactory value) {\n    behavior._view.graphicsFactory = value;\n  }\n\n  void mockLayout(Rectangle<int> bounds) {\n    behavior._view.layout(bounds, bounds);\n  }\n\n  /// Checks if an annotation exists with the given position and color.\n  bool doesAnnotationExist(\n      {num? startPosition,\n      num? endPosition,\n      Color? color,\n      List<int>? dashPattern,\n      String? startLabel,\n      String? endLabel,\n      String? middleLabel,\n      AnnotationLabelAnchor? labelAnchor,\n      AnnotationLabelDirection? labelDirection,\n      AnnotationLabelPosition? labelPosition}) {\n    for (final a in behavior._annotationMap.values) {\n      final currentAnnotation = a._currentAnnotation!;\n      final annotation = currentAnnotation.annotation;\n\n      if (annotation.startPosition == startPosition &&\n          annotation.endPosition == endPosition &&\n          currentAnnotation.color == color &&\n          currentAnnotation.startLabel == startLabel &&\n          currentAnnotation.endLabel == endLabel &&\n          currentAnnotation.middleLabel == middleLabel &&\n          currentAnnotation.labelAnchor == labelAnchor &&\n          currentAnnotation.labelDirection == labelDirection &&\n          currentAnnotation.labelPosition == labelPosition &&\n          (currentAnnotation is! LineAnnotationSegment ||\n              currentAnnotation.dashPattern == dashPattern)) {\n        return true;\n      }\n    }\n\n    return false;\n  }\n}\n\n/// Base class for chart annotations.\nabstract class AnnotationSegment<D> {\n  final RangeAnnotationAxisType axisType;\n  final String? axisId;\n  final Color? color;\n  final String? startLabel;\n  final String? endLabel;\n  final String? middleLabel;\n  final AnnotationLabelAnchor? labelAnchor;\n  final AnnotationLabelDirection? labelDirection;\n  final AnnotationLabelPosition? labelPosition;\n  final TextStyleSpec? labelStyleSpec;\n\n  String get key;\n\n  AnnotationSegment(this.axisType,\n      {this.axisId,\n      this.color,\n      this.startLabel,\n      this.endLabel,\n      this.middleLabel,\n      this.labelAnchor,\n      this.labelDirection,\n      this.labelPosition,\n      this.labelStyleSpec});\n}\n\n/// Data for a chart range annotation.\nclass RangeAnnotationSegment<D> extends AnnotationSegment<D> {\n  final D startValue;\n  final D endValue;\n\n  RangeAnnotationSegment(\n      this.startValue, this.endValue, RangeAnnotationAxisType axisType,\n      {String? axisId,\n      Color? color,\n      String? startLabel,\n      String? endLabel,\n      String? middleLabel,\n      AnnotationLabelAnchor? labelAnchor,\n      AnnotationLabelDirection? labelDirection,\n      AnnotationLabelPosition? labelPosition,\n      TextStyleSpec? labelStyleSpec})\n      : super(axisType,\n            axisId: axisId,\n            color: color,\n            startLabel: startLabel,\n            endLabel: endLabel,\n            middleLabel: middleLabel,\n            labelAnchor: labelAnchor,\n            labelDirection: labelDirection,\n            labelPosition: labelPosition,\n            labelStyleSpec: labelStyleSpec);\n\n  @override\n  String get key => 'r::${axisType}::${axisId}::${startValue}::${endValue}';\n}\n\n/// Data for a chart line annotation.\nclass LineAnnotationSegment<D> extends AnnotationSegment<D> {\n  final D value;\n  final List<int>? dashPattern;\n  final double strokeWidthPx;\n\n  LineAnnotationSegment(this.value, RangeAnnotationAxisType axisType,\n      {String? axisId,\n      Color? color,\n      String? startLabel,\n      String? endLabel,\n      String? middleLabel,\n      AnnotationLabelAnchor? labelAnchor,\n      AnnotationLabelDirection? labelDirection,\n      AnnotationLabelPosition? labelPosition,\n      TextStyleSpec? labelStyleSpec,\n      this.dashPattern,\n      this.strokeWidthPx = _defaultStrokeWidthPx})\n      : super(axisType,\n            axisId: axisId,\n            color: color,\n            startLabel: startLabel,\n            endLabel: endLabel,\n            middleLabel: middleLabel,\n            labelAnchor: labelAnchor,\n            labelDirection: labelDirection,\n            labelPosition: labelPosition,\n            labelStyleSpec: labelStyleSpec);\n\n  @override\n  String get key => 'l::${axisType}::${axisId}::${value}';\n}\n\n/// Axis type for an annotation.\nenum RangeAnnotationAxisType {\n  domain,\n  measure,\n}\n\n/// Configures where to anchor the label.\nenum AnnotationLabelAnchor {\n  /// Anchor to the starting side of the annotation range.\n  start,\n\n  /// Anchor to the middle of the annotation range.\n  middle,\n\n  /// Anchor to the ending side of the annotation range.\n  end,\n}\n\n/// Direction of the label text on the chart.\nenum AnnotationLabelDirection {\n  /// Automatically assign a direction based on the [RangeAnnotationAxisType].\n  ///\n  /// [horizontal] for measure axes, or [vertical] for domain axes.\n  auto,\n\n  /// Text flows parallel to the x axis.\n  horizontal,\n\n  /// Text flows parallel to the y axis.\n  /// TODO[b/112553019]: Implement vertical text rendering of labels.\n  vertical,\n}\n\n/// Configures where to place the label relative to the annotation.\nenum AnnotationLabelPosition {\n  /// Automatically try to place the label inside the bar first and place it on\n  /// the outside of the space available outside the bar is greater than space\n  /// available inside the bar.\n  auto,\n\n  /// Always place label on the outside.\n  outside,\n\n  /// Always place label on the inside.\n  inside,\n\n  /// Place the label outside of the draw area, in the chart margin.\n  ///\n  /// Labels will be rendered on the opposite side of the chart from the primary\n  /// axis. For measure annotations, this means the \"end\" side, opposite from\n  /// the \"start\" side where the primary measure axis is located.\n  ///\n  /// This should not be used for measure annotations if the chart has a\n  /// secondary measure axis. The annotation behaviors do not perform collision\n  /// detection with tick labels.\n  margin,\n}\n\nconst String _unresolvedAutoMessage = 'Unresolved AnnotationLabelPosition.auto';\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/common/behavior/selection/lock_selection.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math';\n\nimport '../../../../common/gesture_listener.dart' show GestureListener;\nimport '../../base_chart.dart' show BaseChart;\nimport '../../behavior/chart_behavior.dart' show ChartBehavior;\nimport '../../selection_model/selection_model.dart' show SelectionModelType;\nimport 'selection_trigger.dart' show SelectionTrigger;\n\n/// Chart behavior that listens to tap event trigges and locks the specified\n/// [SelectionModel]. This is used to prevent further updates to the selection\n/// model, until it is unlocked again.\n///\n/// SelectionModels that can be updated:\n///   info - To view the details of the selected items (ie: hover for web).\n///   action - To select an item as an input, drill, or other selection.\n///\n/// You can add one LockSelection for each model type that you are updating.\n/// Any previous LockSelection behavior for that selection model will be\n/// removed.\nclass LockSelection<D> implements ChartBehavior<D> {\n  late GestureListener _listener;\n\n  /// Type of selection model that should be updated by input events.\n  final SelectionModelType selectionModelType;\n\n  /// Type of input event that should trigger selection.\n  final SelectionTrigger eventTrigger = SelectionTrigger.tap;\n\n  BaseChart<D>? _chart;\n\n  LockSelection({this.selectionModelType = SelectionModelType.info}) {\n    // Setup the appropriate gesture listening.\n    switch (eventTrigger) {\n      case SelectionTrigger.tap:\n        _listener = GestureListener(onTapTest: _onTapTest, onTap: _onSelect);\n        break;\n      default:\n        throw ArgumentError('LockSelection does not support the event '\n            'trigger \"$eventTrigger\"');\n    }\n  }\n\n  bool _onTapTest(Point<double> chartPoint) {\n    // If the tap is within the drawArea, then claim the event from others.\n    return _chart!.pointWithinRenderer(chartPoint);\n  }\n\n  bool _onSelect(Point<double> chartPoint, [double? ignored]) {\n    // Skip events that occur outside the drawArea for any series renderer.\n    if (!_chart!.pointWithinRenderer(chartPoint)) {\n      return false;\n    }\n\n    final selectionModel = _chart!.getSelectionModel(selectionModelType);\n\n    // Do nothing if the chart has no selection model.\n    if (selectionModel == null) {\n      return false;\n    }\n\n    // Do not lock the selection model if there is no selection. Locking nothing\n    // would result in a very confusing user interface as the user tries to\n    // interact with content on the chart.\n    if (!selectionModel.locked && !selectionModel.hasAnySelection) {\n      return false;\n    }\n\n    // Toggle the lock state.\n    selectionModel.locked = !selectionModel.locked;\n\n    // If the model was just unlocked, clear the selection to dismiss any stale\n    // behavior elements. A new hovercard/etc. will appear after the user\n    // triggers a new gesture.\n    if (!selectionModel.locked) {\n      selectionModel.clearSelection();\n    }\n\n    return false;\n  }\n\n  @override\n  void attachTo(BaseChart<D> chart) {\n    _chart = chart;\n    chart.addGestureListener(_listener);\n\n    // TODO: Update this dynamically based on tappable location.\n    switch (eventTrigger) {\n      case SelectionTrigger.tap:\n      case SelectionTrigger.tapAndDrag:\n      case SelectionTrigger.pressHold:\n      case SelectionTrigger.longPressHold:\n        chart.registerTappable(this);\n        break;\n      case SelectionTrigger.hover:\n      default:\n        chart.unregisterTappable(this);\n        break;\n    }\n  }\n\n  @override\n  void removeFrom(BaseChart<D> chart) {\n    chart.removeGestureListener(_listener);\n    chart.unregisterTappable(this);\n    _chart = null;\n  }\n\n  @override\n  String get role => 'LockSelection-$selectionModelType';\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/common/behavior/selection/select_nearest.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math';\n\nimport '../../../../common/gesture_listener.dart' show GestureListener;\nimport '../../../../common/rate_limit_utils.dart' show throttle;\nimport '../../base_chart.dart' show BaseChart;\nimport '../../behavior/chart_behavior.dart' show ChartBehavior;\nimport '../../datum_details.dart' show DatumDetails;\nimport '../../processed_series.dart' show ImmutableSeries;\nimport '../../selection_model/selection_model.dart' show SelectionModelType;\nimport '../../series_datum.dart' show SeriesDatum;\nimport 'selection_trigger.dart' show SelectionTrigger;\n\n/// Chart behavior that listens to the given eventTrigger and updates the\n/// specified [SelectionModel]. This is used to pair input events to behaviors\n/// that listen to selection changes.\n///\n/// Input event types:\n///   hover (default) - Mouse over/near data.\n///   tap - Mouse/Touch on/near data.\n///   pressHold - Mouse/Touch and drag across the data instead of panning.\n///   longPressHold - Mouse/Touch for a while in one place then drag across the\n///       data.\n///\n/// SelectionModels that can be updated:\n///   info - To view the details of the selected items (ie: hover for web).\n///   action - To select an item as an input, drill, or other selection.\n///\n/// Other options available\n///   [selectionMode] - Optional mode for expanding the selection beyond the\n///       nearest datum. Defaults to selecting just the nearest datum.\n///\n///   [selectAcrossAllSeriesRendererComponents] - Events in any component that\n///       draw Series data will propagate to other components that draw Series\n///       data to get a union of points that match across all series renderer\n///       components. This is useful when components in the margins draw series\n///       data and a selection is supposed to bridge the two adjacent\n///       components. (Default: true)\n///   [selectClosestSeries] - If true, the closest Series itself will be marked\n///       as selected in addition to the datum. This is useful for features like\n///       highlighting the closest Series. (Default: true)\n///\n/// You can add one SelectNearest for each model type that you are updating.\n/// Any previous SelectNearest behavior for that selection model will be\n/// removed.\nclass SelectNearest<D> implements ChartBehavior<D> {\n  late GestureListener _listener;\n\n  /// Type of selection model that should be updated by input events.\n  final SelectionModelType selectionModelType;\n\n  /// Type of input event that should trigger selection.\n  final SelectionTrigger eventTrigger;\n\n  /// Optional mode for expanding the selection beyond the nearest datum.\n  /// Defaults to selecting just the nearest datum.\n  final SelectionMode selectionMode;\n\n  /// Whether or not events in any component that draw Series data will\n  /// propagate to other components that draw Series data to get a union of\n  /// points that match across all series renderer components.\n  ///\n  /// This is useful when components in the margins draw series data and a\n  /// selection is supposed to bridge the two adjacent components.\n  final bool selectAcrossAllSeriesRendererComponents;\n\n  /// Whether or not the closest Series itself will be marked as selected in\n  /// addition to the datum.\n  final bool selectClosestSeries;\n\n  /// The farthest away a domain value can be from the mouse position on the\n  /// domain axis before we'll ignore the datum.\n  ///\n  /// This allows sparse data to not get selected until the mouse is some\n  /// reasonable distance. Defaults to no maximum distance.\n  final int? maximumDomainDistancePx;\n\n  /// Wait time in milliseconds for when the next event can be called.\n  final int? hoverEventDelay;\n\n  BaseChart<D>? _chart;\n\n  bool _delaySelect = false;\n\n  SelectNearest(\n      {this.selectionModelType = SelectionModelType.info,\n      this.selectionMode = SelectionMode.expandToDomain,\n      this.selectAcrossAllSeriesRendererComponents = true,\n      this.selectClosestSeries = true,\n      this.eventTrigger = SelectionTrigger.hover,\n      this.maximumDomainDistancePx,\n      this.hoverEventDelay}) {\n    // Setup the appropriate gesture listening.\n    switch (eventTrigger) {\n      case SelectionTrigger.tap:\n        _listener = GestureListener(onTapTest: _onTapTest, onTap: _onSelect);\n        break;\n      case SelectionTrigger.tapAndDrag:\n        _listener = GestureListener(\n          onTapTest: _onTapTest,\n          onTap: _onSelect,\n          onDragStart: _onSelect,\n          onDragUpdate: _onSelect,\n        );\n        break;\n      case SelectionTrigger.pressHold:\n        _listener = GestureListener(\n            onTapTest: _onTapTest,\n            onLongPress: _onSelect,\n            onDragStart: _onSelect,\n            onDragUpdate: _onSelect,\n            onDragEnd: _onDeselectAll);\n        break;\n      case SelectionTrigger.longPressHold:\n        _listener = GestureListener(\n            onTapTest: _onTapTest,\n            onLongPress: _onLongPressSelect,\n            onDragStart: _onSelect,\n            onDragUpdate: _onSelect,\n            onDragEnd: _onDeselectAll);\n        break;\n      case SelectionTrigger.hover:\n      default:\n        _listener = GestureListener(\n            onHover: hoverEventDelay == null\n                ? _onSelect\n                : throttle<Point<double>, bool>(_onSelect,\n                    delay: Duration(milliseconds: hoverEventDelay!),\n                    defaultReturn: false));\n        break;\n    }\n  }\n\n  bool _onTapTest(Point<double> chartPoint) {\n    // If the tap is within the drawArea, then claim the event from others.\n    _delaySelect = eventTrigger == SelectionTrigger.longPressHold;\n    return _chart!.pointWithinRenderer(chartPoint);\n  }\n\n  bool _onLongPressSelect(Point<double> chartPoint) {\n    _delaySelect = false;\n    return _onSelect(chartPoint);\n  }\n\n  bool _onSelect(Point<double> chartPoint, [double? ignored]) {\n    // If _chart has not yet been attached, then quit.\n    if (_chart == null) return false;\n\n    // If the selection is delayed (waiting for long press), then quit early.\n    if (_delaySelect) return false;\n\n    var details = _chart!.getNearestDatumDetailPerSeries(\n        chartPoint, selectAcrossAllSeriesRendererComponents);\n\n    final seriesList = <ImmutableSeries<D>>[];\n    var seriesDatumList = <SeriesDatum<D>>[];\n\n    if (details != null && details.isNotEmpty) {\n      details.sort((a, b) => a.domainDistance!.compareTo(b.domainDistance!));\n\n      if (maximumDomainDistancePx == null ||\n          details[0].domainDistance! <= maximumDomainDistancePx!) {\n        seriesDatumList = _extractSeriesFromNearestSelection(details);\n\n        // Filter out points from overlay series.\n        seriesDatumList\n            .removeWhere((SeriesDatum<D> datum) => datum.series.overlaySeries);\n\n        if (selectClosestSeries && seriesList.isEmpty) {\n          if (details.first.series!.overlaySeries) {\n            // If the closest \"details\" was from an overlay series, grab the\n            // closest remaining series instead. In this case, we need to sort a\n            // copy of the list by domain distance because we do not want to\n            // re-order the actual return values here.\n            final sortedSeriesDatumList =\n                List<SeriesDatum<D>>.from(seriesDatumList);\n            sortedSeriesDatumList.sort((a, b) {\n              final detailsA = a.datum as DatumDetails<D>;\n              final detailsB = b.datum as DatumDetails<D>;\n              return detailsA.domainDistance!\n                  .compareTo(detailsB.domainDistance!);\n            });\n            seriesList.add(sortedSeriesDatumList.first.series);\n          } else {\n            seriesList.add(details.first.series!);\n          }\n        }\n      }\n    }\n\n    return _chart!\n        .getSelectionModel(selectionModelType)\n        .updateSelection(seriesDatumList, seriesList);\n  }\n\n  List<SeriesDatum<D>> _extractSeriesFromNearestSelection(\n      List<DatumDetails<D>> details) {\n    switch (selectionMode) {\n      case SelectionMode.expandToDomain:\n        return _expandToDomain(details.first);\n      case SelectionMode.selectOverlapping:\n        return details\n            .map((datumDetails) =>\n                SeriesDatum<D>(datumDetails.series!, datumDetails.datum))\n            .toList();\n      case SelectionMode.single:\n        return [SeriesDatum<D>(details.first.series!, details.first.datum)];\n    }\n  }\n\n  bool _onDeselectAll(Point<double> _, double __, double ___) {\n    // If the selection is delayed (waiting for long press), then quit early.\n    if (_delaySelect) {\n      return false;\n    }\n\n    _chart!\n        .getSelectionModel(selectionModelType)\n        .updateSelection(<SeriesDatum<D>>[], <ImmutableSeries<D>>[]);\n    return false;\n  }\n\n  List<SeriesDatum<D>> _expandToDomain(DatumDetails<D> nearestDetails) {\n    // Make sure that the \"nearest\" datum is at the top of the list.\n    final data = <SeriesDatum<D>>[\n      SeriesDatum(nearestDetails.series!, nearestDetails.datum)\n    ];\n    final nearestDomain = nearestDetails.domain;\n\n    for (ImmutableSeries<D> series in _chart!.currentSeriesList) {\n      final domainFn = series.domainFn;\n      final domainLowerBoundFn = series.domainLowerBoundFn;\n      final domainUpperBoundFn = series.domainUpperBoundFn;\n      final testBounds =\n          domainLowerBoundFn != null && domainUpperBoundFn != null;\n\n      for (var i = 0; i < series.data.length; i++) {\n        final Object? datum = series.data[i];\n        final domain = domainFn(i);\n\n        // Don't re-add the nearest details.\n        if (nearestDetails.series == series && nearestDetails.datum == datum) {\n          continue;\n        }\n\n        if (domain == nearestDomain) {\n          data.add(SeriesDatum(series, datum));\n        } else if (testBounds) {\n          final domainLowerBound = domainLowerBoundFn!(i);\n          final domainUpperBound = domainUpperBoundFn!(i);\n\n          var addDatum = false;\n          if (domainLowerBound != null && domainUpperBound != null) {\n            if (domain is int) {\n              addDatum = (domainLowerBound as int) <= (nearestDomain as int) &&\n                  (nearestDomain as int) <= (domainUpperBound as int);\n            } else if (domain is double) {\n              addDatum =\n                  (domainLowerBound as double) <= (nearestDomain as double) &&\n                      (nearestDomain as double) <= (domainUpperBound as double);\n            } else if (domain is DateTime) {\n              addDatum = domainLowerBound == nearestDomain ||\n                  domainUpperBound == nearestDomain ||\n                  ((domainLowerBound as DateTime)\n                          .isBefore(nearestDomain as DateTime) &&\n                      (nearestDomain as DateTime)\n                          .isBefore(domainUpperBound as DateTime));\n            }\n          }\n\n          if (addDatum) {\n            data.add(SeriesDatum(series, datum));\n          }\n        }\n      }\n    }\n\n    return data;\n  }\n\n  @override\n  void attachTo(BaseChart<D> chart) {\n    _chart = chart;\n    chart.addGestureListener(_listener);\n\n    // TODO: Update this dynamically based on tappable location.\n    switch (eventTrigger) {\n      case SelectionTrigger.tap:\n      case SelectionTrigger.tapAndDrag:\n      case SelectionTrigger.pressHold:\n      case SelectionTrigger.longPressHold:\n        chart.registerTappable(this);\n        break;\n      case SelectionTrigger.hover:\n      default:\n        chart.unregisterTappable(this);\n        break;\n    }\n  }\n\n  @override\n  void removeFrom(BaseChart<D> chart) {\n    chart.removeGestureListener(_listener);\n    chart.unregisterTappable(this);\n    _chart = null;\n  }\n\n  @override\n  String get role => 'SelectNearest-$selectionModelType';\n}\n\n/// Mode for expanding the selection beyond just the nearest datum.\nenum SelectionMode {\n  /// All data sharing the same domain value as the nearest datum will be\n  /// selected (in charts that have a concept of domain).\n  expandToDomain,\n\n  /// All data for overlapping points in a series will be selected.\n  selectOverlapping,\n\n  /// Select only the nearest datum selected by the chart. This is the default\n  /// mode.\n  single,\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/common/behavior/selection/selection_trigger.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nenum SelectionTrigger {\n  hover,\n  tap,\n  tapAndDrag,\n  pressHold,\n  longPressHold,\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/common/behavior/slider/slider.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math';\n\nimport 'package:meta/meta.dart';\n\nimport '../../../../common/color.dart' show Color;\nimport '../../../../common/gesture_listener.dart' show GestureListener;\nimport '../../../../common/graphics_factory.dart' show GraphicsFactory;\nimport '../../../../common/math.dart' show clamp;\nimport '../../../../common/style/style_factory.dart' show StyleFactory;\nimport '../../../../common/symbol_renderer.dart'\n    show RectSymbolRenderer, SymbolRenderer;\nimport '../../../cartesian/cartesian_chart.dart' show CartesianChart;\nimport '../../../layout/layout_view.dart'\n    show\n        LayoutPosition,\n        LayoutView,\n        LayoutViewConfig,\n        LayoutViewPaintOrder,\n        LayoutViewPositionOrder,\n        ViewMeasuredSizes;\nimport '../../base_chart.dart' show BaseChart, LifecycleListener;\nimport '../../behavior/chart_behavior.dart' show ChartBehavior;\nimport '../../processed_series.dart' show MutableSeries;\nimport '../../chart_canvas.dart' show ChartCanvas, getAnimatedColor;\nimport '../selection/selection_trigger.dart' show SelectionTrigger;\n\n/// Chart behavior that adds a slider widget to a chart. When the slider is\n/// dropped after drag, it will report its domain position and nearest datum\n/// value. This behavior only supports charts that use continuous scales.\n///\n/// Input event types:\n///   tapAndDrag - Mouse/Touch on the handle and drag across the chart.\n///   pressHold - Mouse/Touch on the handle and drag across the chart instead of\n///       panning.\n///   longPressHold - Mouse/Touch for a while on the handle, then drag across\n///       the data.\nclass Slider<D> implements ChartBehavior<D> {\n  late _SliderLayoutView<D> _view;\n\n  late GestureListener _gestureListener;\n\n  late LifecycleListener<D> _lifecycleListener;\n\n  late SliderEventListener<D> _sliderEventListener;\n\n  /// The order to paint slider on the canvas.\n  ///\n  /// The smaller number is drawn first.  This value should be relative to\n  /// LayoutPaintViewOrder.slider (e.g. LayoutViewPaintOrder.slider + 1).\n  int layoutPaintOrder;\n\n  /// Type of input event for the slider.\n  ///\n  /// Input event types:\n  ///   tapAndDrag - Mouse/Touch on the handle and drag across the chart.\n  ///   pressHold - Mouse/Touch on the handle and drag across the chart instead\n  ///       of panning.\n  ///   longPressHold - Mouse/Touch for a while on the handle, then drag across\n  ///       the data.\n  final SelectionTrigger eventTrigger;\n\n  /// Renderer for the handle. Defaults to a rectangle.\n  final SymbolRenderer _handleRenderer;\n\n  /// Custom role ID for this slider\n  final String _roleId;\n\n  /// Whether or not the slider will snap onto the nearest datum (by domain\n  /// distance) when dragged.\n  final bool snapToDatum;\n\n  /// Color and size styles for the slider.\n  final SliderStyle _style;\n\n  CartesianChart<D>? _chart;\n\n  /// Rendering data for the slider line and handle.\n  _AnimatedSlider<D>? _sliderHandle;\n\n  bool _delaySelect = false;\n\n  bool _handleDrag = false;\n\n  /// Current location of the slider line.\n  Point<int>? _domainCenterPoint;\n\n  /// Previous location of the slider line.\n  ///\n  /// This is used to track changes in the position of the slider caused by new\n  /// data being drawn on the chart.\n  Point<int>? _previousDomainCenterPoint;\n\n  /// Bounding box for the slider drag handle.\n  Rectangle<int>? _handleBounds;\n\n  /// Domain value of the current slider position.\n  ///\n  /// This is saved in terms of domain instead of chart position so that we can\n  /// adjust the slider automatically when the chart is resized.\n  D? _domainValue;\n\n  /// Event to fire during the chart's onPostrender event.\n  ///\n  /// This should be set any time the state of the slider has changed.\n  SliderListenerDragState? _dragStateToFireOnPostRender;\n\n  /// Constructs a [Slider].\n  ///\n  /// [eventTrigger] sets the type of gesture handled by the slider.\n  ///\n  /// [handleRenderer] draws a handle for the slider. Defaults to a rectangle.\n  ///\n  /// [initialDomainValue] sets the initial position of the slider in domain\n  /// units. The default is the center of the chart.\n  ///\n  /// [onChangeCallback] will be called when the position of the slider\n  /// changes during a drag event.\n  ///\n  /// [roleId] optional custom role ID for the slider. This can be used to allow\n  /// multiple [Slider] behaviors on the same chart. Normally, there can only be\n  /// one slider (per event trigger type) on a chart. This setting allows for\n  /// configuring multiple independent sliders.\n  ///\n  /// [snapToDatum] configures the slider to snap snap onto the nearest datum\n  /// (by domain distance) when dragged. By default, the slider can be\n  /// positioned anywhere along the domain axis.\n  ///\n  /// [style] configures the color and sizing of the slider line and handle.\n  ///\n  /// [layoutPaintOrder] configures the order in which the behavior should be\n  /// painted. This value should be relative to LayoutPaintViewOrder.slider.\n  /// (e.g. LayoutViewPaintOrder.slider + 1).\n  Slider(\n      {this.eventTrigger = SelectionTrigger.tapAndDrag,\n      SymbolRenderer? handleRenderer,\n      D? initialDomainValue,\n      SliderListenerCallback<D>? onChangeCallback,\n      String? roleId,\n      this.snapToDatum = false,\n      SliderStyle? style,\n      this.layoutPaintOrder = LayoutViewPaintOrder.slider})\n      : _handleRenderer = handleRenderer ?? RectSymbolRenderer(),\n        _roleId = roleId ?? '',\n        _style = style ?? SliderStyle(),\n        _domainValue = initialDomainValue {\n    if (_domainValue != null) {\n      _dragStateToFireOnPostRender = SliderListenerDragState.initial;\n    }\n\n    // Setup the appropriate gesture listening.\n    switch (eventTrigger) {\n      case SelectionTrigger.tapAndDrag:\n        _gestureListener = GestureListener(\n            onTapTest: _onTapTest,\n            onTap: _onSelect,\n            onDragStart: _onSelect,\n            onDragUpdate: _onSelect,\n            onDragEnd: _onDragEnd);\n        break;\n      case SelectionTrigger.pressHold:\n        _gestureListener = GestureListener(\n            onTapTest: _onTapTest,\n            onLongPress: _onSelect,\n            onDragStart: _onSelect,\n            onDragUpdate: _onSelect,\n            onDragEnd: _onDragEnd);\n        break;\n      case SelectionTrigger.longPressHold:\n        _gestureListener = GestureListener(\n            onTapTest: _onTapTest,\n            onLongPress: _onLongPressSelect,\n            onDragStart: _onSelect,\n            onDragUpdate: _onSelect,\n            onDragEnd: _onDragEnd);\n        break;\n      default:\n        throw ArgumentError('Slider does not support the event trigger '\n            '\"$eventTrigger\"');\n    }\n\n    // Set up chart draw cycle listeners.\n    _lifecycleListener = LifecycleListener<D>(\n      onData: _setInitialDragState,\n      onAxisConfigured: _updateViewData,\n      onPostrender: _fireChangeEvent,\n    );\n\n    // Set up slider event listeners.\n    _sliderEventListener = SliderEventListener<D>(onChange: onChangeCallback);\n  }\n\n  bool _onTapTest(Point<double> chartPoint) {\n    _delaySelect = eventTrigger == SelectionTrigger.longPressHold;\n    _handleDrag = _sliderContainsPoint(chartPoint);\n    return _handleDrag;\n  }\n\n  bool _onLongPressSelect(Point<double> chartPoint) {\n    _delaySelect = false;\n    return _onSelect(chartPoint);\n  }\n\n  bool _onSelect(Point<double> chartPoint, [double? ignored]) {\n    // Skip events that occur outside the drawArea for any series renderer.\n    // If the selection is delayed (waiting for long press), then quit early.\n    if (!_handleDrag || _delaySelect) {\n      return false;\n    }\n\n    // Move the slider line along the domain axis, without adjusting the measure\n    // position.\n    final positionChanged = _moveSliderToPoint(chartPoint);\n\n    if (positionChanged) {\n      _dragStateToFireOnPostRender = SliderListenerDragState.drag;\n\n      _chart!.redraw(skipAnimation: true, skipLayout: true);\n    }\n\n    return true;\n  }\n\n  bool _onDragEnd(Point<double> chartPoint, double __, double ___) {\n    // If the selection is delayed (waiting for long press), then quit early.\n    if (_delaySelect) {\n      return false;\n    }\n\n    _handleDrag = false;\n\n    // If snapToDatum is enabled, use the x position of the nearest datum\n    // instead of the mouse point.\n    if (snapToDatum) {\n      final details = _chart!.getNearestDatumDetailPerSeries(chartPoint, true);\n      if (details.isNotEmpty && details[0].chartPosition!.x != null) {\n        // Only trigger an animating draw cycle if we need to move the slider.\n        if (_domainValue != details[0].domain) {\n          _moveSliderToDomain(details[0].domain);\n\n          // Always fire the end event to notify listeners that the gesture is\n          // over.\n          _dragStateToFireOnPostRender = SliderListenerDragState.end;\n\n          _chart!.redraw(skipAnimation: false, skipLayout: true);\n        }\n      }\n    } else {\n      // Move the slider line along the domain axis, without adjusting the\n      // measure position.\n      _moveSliderToPoint(chartPoint);\n\n      // Always fire the end event to notify listeners that the gesture is\n      // over.\n      _dragStateToFireOnPostRender = SliderListenerDragState.end;\n\n      _chart!.redraw(skipAnimation: true, skipLayout: true);\n    }\n\n    return false;\n  }\n\n  bool _sliderContainsPoint(Point<double> chartPoint) {\n    return _handleBounds!.containsPoint(chartPoint);\n  }\n\n  /// Sets the drag state to \"initial\" when new data is drawn on the chart.\n  void _setInitialDragState(List<MutableSeries<D>> _) {\n    _dragStateToFireOnPostRender = SliderListenerDragState.initial;\n  }\n\n  void _updateViewData() {\n    _sliderHandle ??= _AnimatedSlider<D>();\n\n    // If not set in the constructor, initial position for the handle is the\n    // center of the draw area.\n    if (_domainValue == null) {\n      final newDomainValue = _chart!.domainAxis!\n          .getDomain(_view.drawBounds.left + _view.drawBounds.width / 2);\n      _domainValue = (newDomainValue is double)\n          ? (newDomainValue.round().toDouble() as D)\n          : newDomainValue;\n    }\n\n    // Possibly move the slider, if the axis values have changed since the last\n    // chart draw.\n    _moveSliderToDomain(_domainValue);\n\n    // Move the handle to the current event position.\n    final _handleBounds = this._handleBounds!;\n    final _domainCenterPoint = this._domainCenterPoint!;\n    final element = _SliderElement<D>(\n      domainCenterPoint: Point<int>(_domainCenterPoint.x, _domainCenterPoint.y),\n      buttonBounds: Rectangle<int>(_handleBounds.left, _handleBounds.top,\n          _handleBounds.width, _handleBounds.height),\n      fill: _style.fillColor,\n      stroke: _style.strokeColor,\n      strokeWidthPx: _style.strokeWidthPx,\n    );\n\n    _sliderHandle!.setNewTarget(element);\n\n    _view.sliderHandle = _sliderHandle!;\n  }\n\n  /// Fires a [SliderListenerDragState] change event if needed.\n  void _fireChangeEvent(ChartCanvas _) {\n    if (SliderListenerDragState == null ||\n        _sliderEventListener.onChange == null) {\n      return;\n    }\n\n    var dragState = _dragStateToFireOnPostRender;\n\n    // Initial drag state event should only be fired if the slider has moved\n    // since the last draw. We always set the initial drag state event when new\n    // data was drawn on the chart, since we might need to move the slider if\n    // the axis range changed.\n    if (dragState == SliderListenerDragState.initial &&\n        _previousDomainCenterPoint == _domainCenterPoint) {\n      dragState = null;\n    }\n\n    // Reset state.\n    _dragStateToFireOnPostRender = null;\n    _previousDomainCenterPoint = _domainCenterPoint;\n\n    // Bail out if the event was cancelled.\n    if (dragState == null) {\n      return;\n    }\n\n    // Fire the event.\n    _sliderEventListener.onChange!(\n        Point<int>(_domainCenterPoint!.x, _domainCenterPoint!.y),\n        _domainValue,\n        _roleId,\n        dragState);\n  }\n\n  /// Moves the slider along the domain axis (and primary measure axis if\n  /// [_style.handlePosition] is set to [SliderHandlePosition.manual]) to [point\n  /// ].\n  ///\n  /// If [point] exists beyond either edge of the draw area, it will be bound to\n  /// the nearest edge.\n  ///\n  /// Updates [_domainValue] with the domain value located at [point]. For\n  /// ordinal axes, this might technically result in a domain value whose center\n  /// point lies slightly outside the draw area.\n  ///\n  /// Updates [_domainCenterPoint] and [_handleBounds] with the new position of\n  /// the slider.\n  ///\n  /// Returns whether or not the position actually changed. This will generally\n  /// be false if the mouse was dragged outside of the domain axis viewport.\n  bool _moveSliderToPoint(Point<double> point) {\n    var positionChanged = false;\n\n    if (_chart != null) {\n      final viewBounds = _view.componentBounds;\n\n      // Clamp the position to the edge of the viewport.\n      final positionX = clamp(point.x, viewBounds.left, viewBounds.right);\n\n      final previousYPosition = _handleBounds == null\n          ? 0.0\n          : _handleBounds!.top +\n              _style.handleSize.height / 2 -\n              _style.handleOffset.y;\n\n      var positionY = point.y;\n      if (point.y == 0) {\n        if (_handleBounds == null) {\n          positionY = viewBounds.bottom.toDouble();\n        } else {\n          positionY = previousYPosition;\n        }\n      }\n\n      // Clamp the position to the edge of the viewport.\n      positionY =\n          clamp(positionY, viewBounds.top, viewBounds.bottom).toDouble();\n\n      final positionXChanged = _previousDomainCenterPoint != null &&\n          positionX != _previousDomainCenterPoint!.x;\n\n      final positionYChanged =\n          _style.handlePosition == SliderHandlePosition.manual &&\n              _handleBounds != null &&\n              positionY != previousYPosition;\n\n      positionChanged = positionXChanged || positionYChanged;\n\n      // Reset the domain value if the position was outside of the chart.\n      _domainValue = _chart!.domainAxis!.getDomain(positionX.toDouble());\n\n      if (_domainCenterPoint != null) {\n        _domainCenterPoint =\n            Point<int>(positionX.round(), _domainCenterPoint!.y);\n      } else {\n        _domainCenterPoint = Point<int>(positionX.round(),\n            (viewBounds.top + viewBounds.height / 2).round());\n      }\n\n      num handleReferenceY;\n      switch (_style.handlePosition) {\n        case SliderHandlePosition.middle:\n          handleReferenceY = _domainCenterPoint!.y;\n          break;\n        case SliderHandlePosition.top:\n          handleReferenceY = viewBounds.top;\n          break;\n        case SliderHandlePosition.manual:\n          handleReferenceY = positionY;\n          break;\n        default:\n          throw ArgumentError('Slider does not support the handle position '\n              '\"${_style.handlePosition}\"');\n      }\n\n      // Move the slider handle along the domain axis.\n      _handleBounds = Rectangle<int>(\n          (_domainCenterPoint!.x -\n                  _style.handleSize.width / 2 +\n                  _style.handleOffset.x)\n              .round(),\n          (handleReferenceY -\n                  _style.handleSize.height / 2 +\n                  _style.handleOffset.y)\n              .round(),\n          _style.handleSize.width,\n          _style.handleSize.height);\n    }\n\n    return positionChanged;\n  }\n\n  /// Moves the slider along the domain axis to the location of [domain] and iff\n  /// [measure] is set moves it also to location of [measure] along the primary\n  /// measure axis.\n  ///\n  /// If [domain] or [measure] exists beyond either edge of the draw area, the position will\n  /// be bound to the nearest edge.\n  ///\n  /// Updates [_domainValue] with the location of [domain]. For ordinal axes,\n  /// this might result in a different domain value if the range band of\n  /// [domain] is completely outside of the viewport.\n  ///\n  /// Updates [_domainCenterPoint] and [_handleBounds] with the new position of\n  /// the slider.\n  ///\n  /// Returns whether or not the position actually changed. This will generally\n  /// be false if the mouse was dragged outside of the domain axis viewport.\n  bool _moveSliderToDomain(D? domain, {num? measure}) {\n    final x = _chart!.domainAxis!.getLocation(domain)!;\n    final y =\n        measure != null ? _chart!.getMeasureAxis().getLocation(measure)! : 0.0;\n\n    return _moveSliderToPoint(Point<double>(x, y));\n  }\n\n  /// Programmatically moves the slider to the location of [domain] on the\n  /// domain axis and iff [measure] is set moves it also to its position along\n  /// the primary measure axis.\n  ///\n  /// If [domain] exists beyond either edge of the draw area, the position will\n  /// be bound to the nearest edge of the chart. The slider's current domain\n  /// value state will reflect the domain value at the edge of the chart. For\n  /// ordinal axes, this might result in a domain value whose range band is\n  /// partially located beyond the edge of the chart.\n  ///\n  /// This does nothing if the domain matches the current domain location.\n  ///\n  /// [SliderEventListener] callbacks will be fired to indicate that the slider\n  /// has moved.\n  ///\n  /// [skipAnimation] controls whether or not the slider will animate. Animation\n  /// is disabled by default.\n  ///\n  /// [measure] controls the vertical position of the handle on the measure\n  /// axis, can only be set if the SliderHandlePosition is set to 'manual'. If\n  /// measure exists beyond the edges of the draw area, the position will be\n  /// bound to the nearest edge of the chart.\n  void moveSliderToDomain(D domain, {num? measure, bool skipAnimation = true}) {\n    // Nothing to do if we are unattached to a chart or asked to move to the\n    // current location.\n    if (_chart == null || domain == _domainValue) {\n      return;\n    }\n\n    final positionChanged = _moveSliderToDomain(domain, measure: measure);\n\n    if (positionChanged) {\n      _dragStateToFireOnPostRender = SliderListenerDragState.end;\n\n      _chart!.redraw(skipAnimation: skipAnimation, skipLayout: true);\n    }\n  }\n\n  @override\n  void attachTo(BaseChart<D> chart) {\n    if (chart is! CartesianChart<D>) {\n      throw ArgumentError('Slider can only be attached to a cartesian chart.');\n    }\n\n    _chart = chart;\n\n    // Only vertical rendering is supported by this behavior.\n    assert(chart.vertical);\n\n    _view = _SliderLayoutView<D>(\n        layoutPaintOrder: layoutPaintOrder, handleRenderer: _handleRenderer);\n\n    chart.addView(_view);\n    chart.addGestureListener(_gestureListener);\n    chart.addLifecycleListener(_lifecycleListener);\n  }\n\n  @override\n  void removeFrom(BaseChart<D> chart) {\n    chart.removeView(_view);\n    chart.removeGestureListener(_gestureListener);\n    chart.removeLifecycleListener(_lifecycleListener);\n    _chart = null;\n  }\n\n  @override\n  String get role => 'Slider-$eventTrigger-$_roleId';\n}\n\n/// Style configuration for a [Slider] behavior.\nclass SliderStyle {\n  /// Fill color of the handle of the slider.\n  Color fillColor;\n\n  /// Allows users to specify both x-position and y-position offset values that\n  /// determines where the slider handle will be rendered. The offset will be\n  /// calculated relative to its default position at the vertical and horizontal\n  /// center of the slider line.\n  Point<double> handleOffset;\n\n  /// The vertical position for the slider handle.\n  SliderHandlePosition handlePosition;\n\n  /// Specifies the size of the slider handle.\n  Rectangle<int> handleSize;\n\n  /// Stroke width of the slider line and the slider handle.\n  double strokeWidthPx;\n\n  /// Stroke color of the slider line and hte slider handle\n  Color strokeColor = StyleFactory.style.sliderStrokeColor;\n\n  SliderStyle(\n      {Color? fillColor,\n      this.handleOffset = const Point<double>(0.0, 0.0),\n      this.handleSize = const Rectangle<int>(0, 0, 10, 20),\n      Color? strokeColor,\n      this.handlePosition = SliderHandlePosition.middle,\n      this.strokeWidthPx = 2.0})\n      : fillColor = fillColor ?? StyleFactory.style.sliderFillColor,\n        strokeColor = strokeColor ?? StyleFactory.style.sliderStrokeColor;\n\n  @override\n  bool operator ==(Object other) {\n    return other is SliderStyle &&\n        fillColor == other.fillColor &&\n        handleOffset == other.handleOffset &&\n        handleSize == other.handleSize &&\n        strokeWidthPx == other.strokeWidthPx &&\n        strokeColor == other.strokeColor;\n  }\n\n  @override\n  int get hashCode {\n    var hashcode = fillColor.hashCode;\n    hashcode = (hashcode * 37) + handleOffset.hashCode;\n    hashcode = (hashcode * 37) + handleSize.hashCode;\n    hashcode = (hashcode * 37) + strokeWidthPx.hashCode;\n    hashcode = (hashcode * 37) + strokeColor.hashCode;\n    hashcode = (hashcode * 37) + handlePosition.hashCode;\n    return hashcode;\n  }\n}\n\n/// Describes the vertical position of the slider handle on the slider.\n///\n/// [middle] indicates the handle should be half-way between the top and bottom\n/// of the chart in the middle of the slider line.\n///\n/// [top] indicates the slider should be rendered relative to the top of the\n/// chart.\n///\n/// [manual] indicates that the slider vertical position can be set every\n/// time the slider moves by calling moveSliderToDomain.\nenum SliderHandlePosition { middle, top, manual }\n\n/// Layout view component for [Slider].\nclass _SliderLayoutView<D> extends LayoutView {\n  @override\n  final LayoutViewConfig layoutConfig;\n\n  late Rectangle<int> _drawAreaBounds;\n\n  Rectangle<int> get drawBounds => _drawAreaBounds;\n\n  @override\n  GraphicsFactory? graphicsFactory;\n\n  /// Renderer for the handle. Defaults to a rectangle.\n  final SymbolRenderer _handleRenderer;\n\n  /// Rendering data for the slider line and handle.\n  _AnimatedSlider<D>? _sliderHandle;\n\n  _SliderLayoutView(\n      {required int layoutPaintOrder, required SymbolRenderer handleRenderer})\n      : layoutConfig = LayoutViewConfig(\n            paintOrder: layoutPaintOrder,\n            position: LayoutPosition.DrawArea,\n            positionOrder: LayoutViewPositionOrder.drawArea),\n        _handleRenderer = handleRenderer;\n\n  set sliderHandle(_AnimatedSlider<D> value) {\n    _sliderHandle = value;\n  }\n\n  @override\n  ViewMeasuredSizes? measure(int maxWidth, int maxHeight) {\n    return null;\n  }\n\n  @override\n  void layout(Rectangle<int> componentBounds, Rectangle<int> drawAreaBounds) {\n    _drawAreaBounds = drawAreaBounds;\n  }\n\n  @override\n  void paint(ChartCanvas canvas, double animationPercent) {\n    final sliderElement = _sliderHandle!.getCurrentSlider(animationPercent);\n\n    canvas.drawLine(\n        points: [\n          Point<num>(sliderElement.domainCenterPoint.x, _drawAreaBounds.top),\n          Point<num>(sliderElement.domainCenterPoint.x, _drawAreaBounds.bottom),\n        ],\n        stroke: sliderElement.stroke,\n        strokeWidthPx: sliderElement.strokeWidthPx);\n\n    _handleRenderer.paint(canvas, sliderElement.buttonBounds,\n        fillColor: sliderElement.fill,\n        strokeColor: sliderElement.stroke,\n        strokeWidthPx: sliderElement.strokeWidthPx);\n  }\n\n  @override\n  Rectangle<int> get componentBounds => _drawAreaBounds;\n\n  @override\n  bool get isSeriesRenderer => false;\n}\n\n/// Rendering information for a slider control element.\nclass _SliderElement<D> {\n  Point<int> domainCenterPoint;\n  Rectangle<int> buttonBounds;\n  Color fill;\n  Color stroke;\n  double strokeWidthPx;\n\n  _SliderElement({\n    required this.domainCenterPoint,\n    required this.buttonBounds,\n    required this.fill,\n    required this.stroke,\n    required this.strokeWidthPx,\n  });\n\n  _SliderElement<D> clone() {\n    return _SliderElement<D>(\n      domainCenterPoint: domainCenterPoint,\n      buttonBounds: buttonBounds,\n      fill: fill,\n      stroke: stroke,\n      strokeWidthPx: strokeWidthPx,\n    );\n  }\n\n  void updateAnimationPercent(_SliderElement<D> previous,\n      _SliderElement<D> target, double animationPercent) {\n    final previousPoint = previous.domainCenterPoint;\n    final targetPoint = target.domainCenterPoint;\n\n    final x = ((targetPoint.x - previousPoint.x) * animationPercent) +\n        previousPoint.x;\n\n    final y = ((targetPoint.y - previousPoint.y) * animationPercent) +\n        previousPoint.y;\n\n    domainCenterPoint = Point<int>(x.round(), y.round());\n\n    final previousBounds = previous.buttonBounds;\n    final targetBounds = target.buttonBounds;\n\n    final top = ((targetBounds.top - previousBounds.top) * animationPercent) +\n        previousBounds.top;\n    final right =\n        ((targetBounds.right - previousBounds.right) * animationPercent) +\n            previousBounds.right;\n    final bottom =\n        ((targetBounds.bottom - previousBounds.bottom) * animationPercent) +\n            previousBounds.bottom;\n    final left =\n        ((targetBounds.left - previousBounds.left) * animationPercent) +\n            previousBounds.left;\n\n    buttonBounds = Rectangle<int>(left.round(), top.round(),\n        (right - left).round(), (bottom - top).round());\n\n    fill = getAnimatedColor(previous.fill, target.fill, animationPercent);\n\n    stroke = getAnimatedColor(previous.stroke, target.stroke, animationPercent);\n\n    strokeWidthPx =\n        ((target.strokeWidthPx - previous.strokeWidthPx) * animationPercent) +\n            previous.strokeWidthPx;\n  }\n}\n\n/// Animates the slider control element of the behavior between different\n/// states.\nclass _AnimatedSlider<D> {\n  _SliderElement<D>? _previousSlider;\n  late _SliderElement<D> _targetSlider;\n  _SliderElement<D>? _currentSlider;\n\n  // Flag indicating whether this point is being animated out of the chart.\n  bool animatingOut = false;\n\n  _AnimatedSlider();\n\n  /// Animates a point that was removed from the series out of the view.\n  ///\n  /// This should be called in place of \"setNewTarget\" for points that represent\n  /// data that has been removed from the series.\n  ///\n  /// Animates the width of the slider down to 0.\n  void animateOut() {\n    final newTarget = _currentSlider!.clone();\n\n    // Animate the button bounds inwards horizontally towards a 0 width box.\n    final targetBounds = newTarget.buttonBounds;\n    final top = targetBounds.top;\n    final right = targetBounds.left + targetBounds.width / 2;\n    final bottom = targetBounds.bottom;\n    final left = right;\n\n    newTarget.buttonBounds = Rectangle<int>(left.round(), top.round(),\n        (right - left).round(), (bottom - top).round());\n\n    // Animate the stroke width to 0 so that we don't get a lingering line after\n    // animation is done.\n    newTarget.strokeWidthPx = 0.0;\n\n    setNewTarget(newTarget);\n    animatingOut = true;\n  }\n\n  void setNewTarget(_SliderElement<D> newTarget) {\n    animatingOut = false;\n    _currentSlider ??= newTarget.clone();\n    _previousSlider = _currentSlider!.clone();\n    _targetSlider = newTarget;\n  }\n\n  _SliderElement<D> getCurrentSlider(double animationPercent) {\n    if (animationPercent == 1.0 || _previousSlider == null) {\n      _currentSlider = _targetSlider;\n      _previousSlider = _targetSlider;\n      return _currentSlider!;\n    }\n\n    _currentSlider!.updateAnimationPercent(\n        _previousSlider!, _targetSlider, animationPercent);\n\n    return _currentSlider!;\n  }\n}\n\n/// Event handler for slider events.\nclass SliderEventListener<D> {\n  /// Called when the position of the slider has changed during a drag event.\n  final SliderListenerCallback<D>? onChange;\n\n  SliderEventListener({this.onChange});\n}\n\n/// Callback function for [Slider] drag events.\n///\n/// [point] is the current position of the slider line. [point.x] is the domain\n/// position, and [point.y] is the position of the center of the line on the\n/// measure axis.\n///\n/// [domain] is the domain value at the slider position.\n///\n/// [dragState] indicates the current state of a drag event.\ntypedef SliderListenerCallback<D> = void Function(Point<int> point, D? domain,\n    String roleId, SliderListenerDragState dragState);\n\n/// Describes the current state of a slider change as a result of a drag event.\n///\n/// [initial] indicates that the slider was set to an initial position when new\n/// data was drawn on a chart. This will be fired if an initialDomainValue is\n/// passed to [Slider]. It will also be fired if the position of the slider\n/// changes as a result of new data being drawn on the chart.\n///\n/// [drag] indicates that the slider is being moved as a result of drag events.\n/// When this is passed, the drag event is still active. Once the drag event is\n/// completed, an [end] event will be fired.\n///\n/// [end] indicates that a drag event has been completed. This usually occurs\n/// after one or more [drag] events. An [end] event will also be fired if\n/// [Slider.moveSliderToDomain] is called, but there will be no preceding [drag]\n/// events in this case.\nenum SliderListenerDragState { initial, drag, end }\n\n/// Helper class that exposes fewer private internal properties for unit tests.\n@visibleForTesting\nclass SliderTester<D> {\n  final Slider<D> behavior;\n\n  SliderTester(this.behavior);\n\n  Point<int>? get domainCenterPoint => behavior._domainCenterPoint;\n\n  D? get domainValue => behavior._domainValue;\n\n  Rectangle<int>? get handleBounds => behavior._handleBounds;\n\n  void layout(Rectangle<int> componentBounds, Rectangle<int> drawAreaBounds) {\n    behavior._view.layout(componentBounds, drawAreaBounds);\n  }\n\n  _SliderLayoutView<D> get view => behavior._view;\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/common/behavior/sliding_viewport.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport '../../cartesian/cartesian_chart.dart' show CartesianChart;\nimport '../base_chart.dart' show BaseChart;\nimport '../selection_model/selection_model.dart'\n    show SelectionModel, SelectionModelType;\nimport 'chart_behavior.dart' show ChartBehavior;\n\n/// Chart behavior that centers the viewport on the selected domain.\n///\n/// It is used in combination with SelectNearest to update the selection model\n/// and notify this behavior to update the viewport on selection change.\n///\n/// This behavior can only be used on [CartesianChart].\nclass SlidingViewport<D> implements ChartBehavior<D> {\n  final SelectionModelType selectionModelType;\n\n  late CartesianChart<D> _chart;\n\n  SlidingViewport([this.selectionModelType = SelectionModelType.info]);\n\n  void _selectionChanged(SelectionModel<D> selectionModel) {\n    if (selectionModel.hasAnySelection == false) {\n      return;\n    }\n\n    // Calculate current viewport center and determine the translate pixels\n    // needed based on the selected domain value's location and existing amount\n    // of translate pixels.\n    final domainAxis = _chart.domainAxis!;\n    final selectedDatum = selectionModel.selectedDatum.first;\n    final domainLocation = domainAxis\n        .getLocation(selectedDatum.series.domainFn(selectedDatum.index))!;\n    final viewportCenter =\n        domainAxis.range!.start + (domainAxis.range!.width / 2);\n    final translatePx =\n        domainAxis.viewportTranslatePx + (viewportCenter - domainLocation);\n    domainAxis.setViewportSettings(\n        domainAxis.viewportScalingFactor, translatePx);\n\n    _chart.redraw();\n  }\n\n  @override\n  void attachTo(BaseChart<D> chart) {\n    assert(chart is CartesianChart);\n    _chart = chart as CartesianChart<D>;\n    chart\n        .getSelectionModel(selectionModelType)\n        .addSelectionChangedListener(_selectionChanged);\n  }\n\n  @override\n  void removeFrom(BaseChart<D> chart) {\n    chart\n        .getSelectionModel(selectionModelType)\n        .removeSelectionChangedListener(_selectionChanged);\n  }\n\n  @override\n  String get role => 'slidingViewport-$selectionModelType';\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/common/behavior/sunburst_ring_expander.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport '../base_chart.dart' show BaseChart;\nimport '../selection_model/selection_model.dart'\n    show SelectionModel, SelectionModelType;\nimport '../../sunburst/sunburst_chart.dart' show SunburstChart;\nimport 'chart_behavior.dart' show ChartBehavior;\n\n/// Expands the initially displayed outer ring to show subset of data in one\n/// final ring.\nclass SunburstRingExpander<D> implements ChartBehavior<D> {\n  final SelectionModelType selectionModelType;\n\n  late SunburstChart<D> _chart;\n\n  SunburstRingExpander([this.selectionModelType = SelectionModelType.action]);\n\n  void _selectionChanged(SelectionModel<D> selectionModel) {\n    if (selectionModel.selectedDatum.isNotEmpty) {\n      _chart.expandNode(selectionModel.selectedDatum.first.datum);\n      _chart.redraw(skipLayout: true, skipAnimation: true);\n    }\n  }\n\n  @override\n  void attachTo(BaseChart<D> chart) {\n    if (!(chart is SunburstChart)) {\n      throw ArgumentError(\n          'SunburstRingExpander can only be attached to a Sunburst chart');\n    }\n    _chart = chart as SunburstChart<D>;\n    chart\n        .getSelectionModel(selectionModelType)\n        .addSelectionUpdatedListener(_selectionChanged);\n  }\n\n  @override\n  void removeFrom(BaseChart<D> chart) {\n    chart\n        .getSelectionModel(selectionModelType)\n        .addSelectionUpdatedListener(_selectionChanged);\n  }\n\n  @override\n  String get role => 'sunburstRingExpander-$selectionModelType';\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/common/behavior/zoom/initial_hint_behavior.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math' show Point;\n\nimport 'package:meta/meta.dart' show protected;\n\nimport '../../../../common/gesture_listener.dart' show GestureListener;\nimport '../../../cartesian/axis/axis.dart' show Axis;\nimport '../../../cartesian/cartesian_chart.dart' show CartesianChart;\nimport '../../base_chart.dart' show BaseChart, LifecycleListener;\nimport '../chart_behavior.dart' show ChartBehavior;\n\n/// Adds initial hint behavior for [CartesianChart].\n///\n/// This behavior animates to the final viewport from an initial translate and\n/// or scale factor.\nabstract class InitialHintBehavior<D> implements ChartBehavior<D> {\n  /// Listens for drag gestures.\n  late GestureListener _listener;\n\n  /// Chart lifecycle listener to setup hint animation.\n  late LifecycleListener<D> _lifecycleListener;\n\n  @override\n  String get role => 'InitialHint';\n\n  /// The chart to which the behavior is attached.\n  CartesianChart<D>? _chart;\n\n  @protected\n  CartesianChart<D>? get chart => _chart;\n\n  Duration _hintDuration = Duration(milliseconds: 3000);\n\n  /// The amount of time to animate to the desired viewport.\n  ///\n  /// If no duration is passed in, the default of 3000 ms is used.\n  @protected\n  Duration get hintDuration => _hintDuration;\n\n  set hintDuration(Duration duration) {\n    _hintDuration = duration;\n  }\n\n  double _maxHintTranslate = 0.0;\n\n  // TODO: Translation animation only works for ordinal axis.\n  /// The maximum amount ordinal values to shift the viewport for the the hint\n  /// animation.\n  ///\n  /// Positive numbers shift the viewport to the right and negative to the left.\n  /// The default is no translation.\n  @protected\n  double get maxHintTranslate => _maxHintTranslate;\n\n  set maxHintTranslate(double maxHintTranslate) {\n    _maxHintTranslate = maxHintTranslate;\n  }\n\n  double? _maxHintScaleFactor;\n\n  /// The amount the domain axis will be scaled for the start of the hint.\n  ///\n  /// A value of 1.0 means the viewport is completely zoomed out (all domains\n  /// are in the viewport). If a value is provided, it cannot be less than 1.0.\n  ///\n  /// By default maxHintScaleFactor is not set.\n  @protected\n  double? get maxHintScaleFactor => _maxHintScaleFactor;\n\n  set maxHintScaleFactor(double? maxHintScaleFactor) {\n    assert(maxHintScaleFactor != null && maxHintScaleFactor >= 1.0);\n\n    _maxHintScaleFactor = maxHintScaleFactor;\n  }\n\n  /// Flag to indicate that hint animation controller has already been set up.\n  ///\n  /// This is to ensure that the hint is only set up on the first draw.\n  bool _hintSetupCompleted = false;\n\n  /// Flag to indicate that the first call to axis configured is completed.\n  ///\n  /// This is to ensure that the initial and target viewport translate and scale\n  /// factor is only calculated on the first axis configuration.\n  bool _firstAxisConfigured = false;\n\n  double? _initialViewportTranslatePx;\n  double? _initialViewportScalingFactor;\n  late double _targetViewportTranslatePx;\n  late double _targetViewportScalingFactor;\n\n  InitialHintBehavior() {\n    _listener = GestureListener(onTapTest: onTapTest);\n\n    _lifecycleListener = LifecycleListener<D>(\n        onAxisConfigured: _onAxisConfigured,\n        onAnimationComplete: _onAnimationComplete);\n  }\n\n  @override\n  void attachTo(BaseChart<D> chart) {\n    if (chart is! CartesianChart<D>) {\n      throw ArgumentError(\n          'InitialHintBehavior can only be attached to a CartesianChart<D>');\n    }\n\n    _chart = chart;\n\n    chart.addGestureListener(_listener);\n    chart.addLifecycleListener(_lifecycleListener);\n  }\n\n  @override\n  void removeFrom(BaseChart<D> chart) {\n    if (chart is! CartesianChart) {\n      throw ArgumentError(\n          'InitialHintBehavior can only be removed from a CartesianChart<D>');\n    }\n\n    stopHintAnimation();\n\n    _chart = chart as CartesianChart<D>;\n    chart.removeGestureListener(_listener);\n    chart.removeLifecycleListener(_lifecycleListener);\n\n    _chart = null;\n  }\n\n  @protected\n  bool onTapTest(Point<double> localPosition) {\n    if (_chart == null) {\n      return false;\n    }\n\n    // If the user taps the chart, stop the hint animation immediately.\n    stopHintAnimation();\n\n    return _chart!.withinDrawArea(localPosition);\n  }\n\n  /// Calculate the animation's initial and target viewport and scale factor\n  /// and shift the viewport to the start.\n  void _onAxisConfigured() {\n    if (!_firstAxisConfigured) {\n      _firstAxisConfigured = true;\n\n      final domainAxis = chart!.domainAxis!;\n\n      // TODO: Translation animation only works for axis with a\n      // rangeband type that returns a non zero step size. If two rows have\n      // the same domain value, step size could also equal 0.\n      assert(domainAxis.stepSize != 0.0);\n\n      // Save the target viewport and scale factor from axis, because the\n      // viewport can be set by the user using AxisSpec.\n      _targetViewportTranslatePx = domainAxis.viewportTranslatePx;\n      _targetViewportScalingFactor = domainAxis.viewportScalingFactor;\n\n      // Calculate the amount to translate from the target viewport.\n      final translateAmount = domainAxis.stepSize * maxHintTranslate;\n\n      _initialViewportTranslatePx =\n          _targetViewportTranslatePx - translateAmount;\n\n      _initialViewportScalingFactor =\n          maxHintScaleFactor ?? _targetViewportScalingFactor;\n\n      assert(_initialViewportScalingFactor != null);\n      domainAxis.setViewportSettings(\n          _initialViewportScalingFactor!, _initialViewportTranslatePx!);\n      chart!.redraw(skipAnimation: true, skipLayout: false);\n    }\n  }\n\n  /// Start the hint animation, only start the animation on the very first draw.\n  void _onAnimationComplete() {\n    if (!_hintSetupCompleted) {\n      _hintSetupCompleted = true;\n\n      startHintAnimation();\n    }\n  }\n\n  /// Setup and start the hint animation.\n  ///\n  /// Animation controller to be handled by the native platform.\n  @protected\n  void startHintAnimation() {\n    // When panning starts, measure tick provider should not update ticks.\n    // This is still needed because axis internally updates the tick location\n    // after the tick provider generates the ticks. If we do not tell the axis\n    // not to update the location of the measure axes, the measure axis will\n    // change during the hint animation and make values jump back and forth.\n    _chart!.getMeasureAxis().lockAxis = true;\n    _chart!.getMeasureAxis(axisId: Axis.secondaryMeasureAxisId).lockAxis = true;\n  }\n\n  /// Stop hint animation\n  @protected\n  void stopHintAnimation() {\n    // When panning is completed, unlock the measure axis.\n    _chart!.getMeasureAxis().lockAxis = false;\n    _chart!.getMeasureAxis(axisId: Axis.secondaryMeasureAxisId).lockAxis =\n        false;\n  }\n\n  /// Animation hint percent, to be returned by the native platform.\n  @protected\n  double get hintAnimationPercent;\n\n  /// Shift domain viewport on hint animation ticks.\n  @protected\n  void onHintTick() {\n    final percent = hintAnimationPercent;\n\n    final scaleFactor = _lerpDouble(\n        _initialViewportScalingFactor, _targetViewportScalingFactor, percent);\n\n    var translatePx = _lerpDouble(\n        _initialViewportTranslatePx, _targetViewportTranslatePx, percent);\n\n    // If there is a scale factor animation, need to scale the translatePx so\n    // the animation appears to be zooming in on the viewport when there is no\n    // [maxHintTranslate] provided.\n    //\n    // If there is a translate hint, the animation will still first zoom in\n    // and then translate the [maxHintTranslate] amount.\n    if (_initialViewportScalingFactor != _targetViewportScalingFactor) {\n      translatePx = translatePx * percent;\n    }\n\n    final chart = this.chart!;\n    final domainAxis = chart.domainAxis!;\n    domainAxis.setViewportSettings(scaleFactor, translatePx,\n        drawAreaWidth: chart.drawAreaBounds.width);\n\n    if (percent >= 1.0) {\n      stopHintAnimation();\n      chart.redraw();\n    } else {\n      chart.redraw(skipAnimation: true, skipLayout: true);\n    }\n  }\n\n  /// Linear interpolation for doubles.\n  double _lerpDouble(double? a, double? b, double t) {\n    a ??= 0.0;\n    b ??= 0.0;\n    return a + (b - a) * t;\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/common/behavior/zoom/pan_and_zoom_behavior.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math' show min, max, Point;\n\nimport 'package:meta/meta.dart' show protected;\n\nimport 'pan_behavior.dart';\nimport 'panning_tick_provider.dart' show PanningTickProviderMode;\n\n/// Adds domain axis panning and zooming support to the chart.\n///\n/// Zooming is supported for the web by mouse wheel events. Scrolling up zooms\n/// the chart in, and scrolling down zooms the chart out. The chart can never be\n/// zoomed out past the domain axis range.\n///\n/// Zooming is supported by pinch gestures for mobile devices.\n///\n/// Panning is supported by clicking and dragging the mouse for web, or tapping\n/// and dragging on the chart for mobile devices.\nclass PanAndZoomBehavior<D> extends PanBehavior<D> {\n  @override\n  String get role => 'PanAndZoom';\n\n  /// Flag which is enabled to indicate that the user is \"zooming\" the chart.\n  bool _isZooming = false;\n\n  @protected\n  bool get isZooming => _isZooming;\n\n  /// Current zoom scaling factor for the behavior.\n  double _scalingFactor = 1.0;\n\n  /// Minimum scalingFactor to prevent zooming out beyond the data range.\n  final _minScalingFactor = 1.0;\n\n  /// Maximum scalingFactor to prevent zooming in so far that no data is\n  /// visible.\n  ///\n  /// TODO: Dynamic max based on data range?\n  final _maxScalingFactor = 5.0;\n\n  @override\n  bool onDragStart(Point<double> localPosition) {\n    if (chart == null) {\n      return false;\n    }\n\n    super.onDragStart(localPosition);\n\n    // Save the current scaling factor to make zoom events relative.\n    _scalingFactor = chart!.domainAxis!.viewportScalingFactor;\n    _isZooming = true;\n\n    return true;\n  }\n\n  @override\n  bool onDragUpdate(Point<double> localPosition, double scale) {\n    // Swipe gestures should be handled by the [PanBehavior].\n    if (scale == 1.0) {\n      _isZooming = false;\n      return super.onDragUpdate(localPosition, scale);\n    }\n\n    // No further events in this chain should be handled by [PanBehavior].\n    cancelPanning();\n\n    final chart = this.chart;\n    if (!_isZooming || lastPosition == null || chart == null) {\n      return false;\n    }\n\n    // Update the domain axis's viewport scale factor to zoom the chart.\n    final domainAxis = chart.domainAxis;\n\n    if (domainAxis == null) {\n      return false;\n    }\n\n    // This is set during onDragUpdate and NOT onDragStart because we don't yet\n    // know during onDragStart whether pan/zoom behavior is panning or zooming.\n    // During zoom in / zoom out, domain tick provider set to return existing\n    // cached ticks.\n    domainAxisTickProvider.mode = PanningTickProviderMode.useCachedTicks;\n\n    // Clamp the scale to prevent zooming out beyond the range of the data, or\n    // zooming in so far that we show nothing useful.\n    final newScalingFactor =\n        min(max(_scalingFactor * scale, _minScalingFactor), _maxScalingFactor);\n\n    domainAxis.setViewportSettings(\n        newScalingFactor, domainAxis.viewportTranslatePx,\n        drawAreaWidth: chart.drawAreaBounds.width,\n        drawAreaHeight: chart.drawAreaBounds.height);\n\n    chart.redraw(skipAnimation: true, skipLayout: true);\n\n    return true;\n  }\n\n  @override\n  bool onDragEnd(\n      Point<double> localPosition, double scale, double pixelsPerSec) {\n    _isZooming = false;\n\n    return super.onDragEnd(localPosition, scale, pixelsPerSec);\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/common/behavior/zoom/pan_behavior.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math' show Point;\n\nimport 'package:meta/meta.dart' show protected;\n\nimport '../../../../common/gesture_listener.dart' show GestureListener;\nimport '../../../cartesian/axis/axis.dart' show Axis;\nimport '../../../cartesian/cartesian_chart.dart' show CartesianChart;\nimport '../../base_chart.dart' show BaseChart;\nimport '../chart_behavior.dart' show ChartBehavior;\nimport 'panning_tick_provider.dart';\n\n/// Adds domain axis panning support to a chart.\n///\n/// Panning is supported by clicking and dragging the mouse for web, or tapping\n/// and dragging on the chart for mobile devices.\nclass PanBehavior<D> implements ChartBehavior<D> {\n  /// Listens for drag gestures.\n  late GestureListener _listener;\n\n  /// Wrapped domain tick provider for pan and zoom behavior.\n  late PanningTickProvider<D> _domainAxisTickProvider;\n\n  @protected\n  PanningTickProvider<D> get domainAxisTickProvider => _domainAxisTickProvider;\n\n  @override\n  String get role => 'Pan';\n\n  /// The chart to which the behavior is attached.\n  CartesianChart<D>? _chart;\n\n  @protected\n  CartesianChart<D>? get chart => _chart;\n\n  /// Flag which is enabled to indicate that the user is \"panning\" the chart.\n  bool _isPanning = false;\n\n  @protected\n  bool get isPanning => _isPanning;\n\n  /// Last position of the mouse/tap that was used to adjust the scale translate\n  /// factor.\n  Point<double>? _lastPosition;\n\n  @protected\n  Point<double>? get lastPosition => _lastPosition;\n\n  /// Optional callback that is invoked at the end of panning ([onPanEnd]).\n  PanningCompletedCallback? _panningCompletedCallback;\n\n  set panningCompletedCallback(PanningCompletedCallback? callback) {\n    _panningCompletedCallback = callback;\n  }\n\n  PanBehavior() {\n    _listener = GestureListener(\n        onTapTest: onTapTest,\n        onDragStart: onDragStart,\n        onDragUpdate: onDragUpdate,\n        onDragEnd: onDragEnd);\n  }\n\n  /// Injects the behavior into a chart.\n  @override\n  void attachTo(BaseChart<D> chart) {\n    if (chart is! CartesianChart<D>) {\n      throw ArgumentError(\n          'PanBehavior can only be attached to a CartesianChart<D>');\n    }\n\n    _chart = chart;\n    chart.addGestureListener(_listener);\n\n    // Disable the autoViewport feature to enable panning.\n    chart.domainAxis!.autoViewport = false;\n\n    // Wrap domain axis tick provider with the panning behavior one.\n    _domainAxisTickProvider =\n        PanningTickProvider<D>(chart.domainAxis!.tickProvider!);\n    chart.domainAxis!.tickProvider = _domainAxisTickProvider;\n  }\n\n  /// Removes the behavior from a chart.\n  @override\n  void removeFrom(BaseChart<D> chart) {\n    if (chart is! CartesianChart<D>) {\n      throw ArgumentError(\n          'PanBehavior can only be attached to a CartesianChart<D>');\n    }\n\n    _chart = chart;\n    chart.removeGestureListener(_listener);\n\n    // Restore the default autoViewport state.\n    chart.domainAxis!.autoViewport = true;\n\n    // Restore the original tick providers\n    chart.domainAxis!.tickProvider = _domainAxisTickProvider.tickProvider;\n\n    _chart = null;\n  }\n\n  @protected\n  bool onTapTest(Point<double> localPosition) {\n    if (_chart == null) {\n      return false;\n    }\n\n    return _chart!.withinDrawArea(localPosition);\n  }\n\n  @protected\n  bool onDragStart(Point<double> localPosition) {\n    if (_chart == null) {\n      return false;\n    }\n\n    onPanStart();\n\n    _lastPosition = localPosition;\n    _isPanning = true;\n    return true;\n  }\n\n  @protected\n  bool onDragUpdate(Point<double> localPosition, double scale) {\n    if (!_isPanning || _lastPosition == null || _chart == null) {\n      return false;\n    }\n\n    // Pinch gestures should be handled by the [PanAndZoomBehavior].\n    if (scale != 1.0) {\n      _isPanning = false;\n      return false;\n    }\n\n    // Update the domain axis's viewport translate to pan the chart.\n    final domainAxis = _chart!.domainAxis;\n\n    if (domainAxis == null) {\n      return false;\n    }\n\n    // This is set during onDragUpdate and NOT onDragStart because we don't yet\n    // know during onDragStart whether pan/zoom behavior is panning or zooming.\n    // During panning, domain tick provider set to generate ticks with locked\n    // steps.\n    _domainAxisTickProvider.mode = PanningTickProviderMode.stepSizeLocked;\n\n    final domainScalingFactor = domainAxis.viewportScalingFactor;\n\n    var domainChange = 0.0;\n    if (domainAxis.isVertical) {\n      domainChange =\n          domainAxis.viewportTranslatePx + localPosition.y - _lastPosition!.y;\n    } else {\n      domainChange =\n          domainAxis.viewportTranslatePx + localPosition.x - _lastPosition!.x;\n    }\n\n    final chart = this.chart!;\n    domainAxis.setViewportSettings(domainScalingFactor, domainChange,\n        drawAreaWidth: chart.drawAreaBounds.width,\n        drawAreaHeight: chart.drawAreaBounds.height);\n\n    _lastPosition = localPosition;\n\n    chart.redraw(skipAnimation: true, skipLayout: true);\n    return true;\n  }\n\n  @protected\n  bool onDragEnd(\n      Point<double> localPosition, double scale, double pixelsPerSec) {\n    onPanEnd();\n    return true;\n  }\n\n  @protected\n  void onPanStart() {\n    // When panning starts, measure tick provider should not update ticks.\n    // This is still needed because axis internally updates the tick location\n    // after the tick provider generates the ticks. If we do not tell the axis\n    // not to update the location of the measure axes, we get a jittery effect\n    // as the measure axes location changes ever so slightly during pan/zoom.\n    _chart!.getMeasureAxis().lockAxis = true;\n    _chart!.getMeasureAxis(axisId: Axis.secondaryMeasureAxisId).lockAxis = true;\n  }\n\n  @protected\n  void onPanEnd() {\n    cancelPanning();\n\n    // When panning stops, allow tick provider to update ticks, and then\n    // request redraw.\n    _domainAxisTickProvider.mode = PanningTickProviderMode.passThrough;\n\n    final _chart = this._chart!;\n    _chart.getMeasureAxis().lockAxis = false;\n    _chart.getMeasureAxis(axisId: Axis.secondaryMeasureAxisId).lockAxis = false;\n    _chart.redraw();\n\n    _panningCompletedCallback?.call();\n  }\n\n  /// Cancels the handling of any current panning event.\n  void cancelPanning() {\n    _isPanning = false;\n  }\n}\n\n/// Callback for when panning is completed.\ntypedef PanningCompletedCallback = void Function();\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/common/behavior/zoom/panning_tick_provider.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport '../../../../common/graphics_factory.dart' show GraphicsFactory;\nimport '../../../cartesian/axis/axis.dart' show AxisOrientation;\nimport '../../../cartesian/axis/draw_strategy/tick_draw_strategy.dart'\n    show TickDrawStrategy;\nimport '../../../cartesian/axis/scale.dart' show MutableScale;\nimport '../../../cartesian/axis/tick.dart' show Tick;\nimport '../../../cartesian/axis/tick_formatter.dart' show TickFormatter;\nimport '../../../cartesian/axis/tick_provider.dart' show TickProvider, TickHint;\nimport '../../../common/chart_context.dart' show ChartContext;\n\nenum PanningTickProviderMode {\n  /// Return cached ticks.\n  useCachedTicks,\n\n  /// Request ticks with [TickHint] calculated from cached ticks.\n  stepSizeLocked,\n\n  /// Request ticks directly from tick provider.\n  passThrough,\n}\n\n/// Wraps an existing tick provider to be able to return cached ticks during\n/// zoom in/out, return ticks calculated with locked step size during panning,\n/// or just pass through to the existing tick provider.\nclass PanningTickProvider<D> implements TickProvider<D> {\n  final TickProvider<D> tickProvider;\n\n  PanningTickProviderMode _mode = PanningTickProviderMode.passThrough;\n\n  late List<Tick<D>> _ticks;\n\n  PanningTickProvider(this.tickProvider);\n\n  set mode(PanningTickProviderMode mode) {\n    _mode = mode;\n  }\n\n  @override\n  List<Tick<D>> getTicks({\n    required ChartContext? context,\n    required GraphicsFactory graphicsFactory,\n    required MutableScale<D> scale,\n    required TickFormatter<D> formatter,\n    required Map<D, String> formatterValueCache,\n    required TickDrawStrategy<D> tickDrawStrategy,\n    required AxisOrientation? orientation,\n    bool viewportExtensionEnabled = false,\n    TickHint<D>? tickHint,\n  }) {\n    if (_mode == PanningTickProviderMode.stepSizeLocked) {\n      tickHint = TickHint(\n        _ticks.first.value,\n        _ticks.last.value,\n        tickCount: _ticks.length,\n      );\n    }\n\n    if (_mode != PanningTickProviderMode.useCachedTicks) {\n      _ticks = tickProvider.getTicks(\n        context: context,\n        graphicsFactory: graphicsFactory,\n        scale: scale,\n        formatter: formatter,\n        formatterValueCache: formatterValueCache,\n        tickDrawStrategy: tickDrawStrategy,\n        orientation: orientation,\n        viewportExtensionEnabled: viewportExtensionEnabled,\n        tickHint: tickHint,\n      );\n    }\n\n    return _ticks;\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/common/canvas_shapes.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math' show Rectangle, min, max, Point;\n\nimport '../../common/color.dart' show Color;\nimport 'chart_canvas.dart' show FillPatternType;\n\n/// A rectangle to be painted by [ChartCanvas].\nclass CanvasRect {\n  final Rectangle<int> bounds;\n  final List<int>? dashPattern;\n  final Color? fill;\n  final FillPatternType? pattern;\n  final Color? stroke;\n  final double? strokeWidthPx;\n\n  CanvasRect(this.bounds,\n      {this.dashPattern,\n      this.fill,\n      this.pattern,\n      this.stroke,\n      this.strokeWidthPx});\n}\n\n/// A stack of [CanvasRect] to be painted by [ChartCanvas].\nclass CanvasBarStack {\n  final List<CanvasRect> segments;\n  final int? radius;\n  final int stackedBarPadding;\n  final bool roundTopLeft;\n  final bool roundTopRight;\n  final bool roundBottomLeft;\n  final bool roundBottomRight;\n  final Rectangle<int> fullStackRect;\n\n  factory CanvasBarStack(\n    List<CanvasRect> segments, {\n    int? radius,\n    int stackedBarPadding = 1,\n    bool roundTopLeft = false,\n    bool roundTopRight = false,\n    bool roundBottomLeft = false,\n    bool roundBottomRight = false,\n  }) {\n    final firstBarBounds = segments.first.bounds;\n\n    // Find the rectangle that would represent the full stack of bars.\n    var left = firstBarBounds.left;\n    var top = firstBarBounds.top;\n    var right = firstBarBounds.right;\n    var bottom = firstBarBounds.bottom;\n\n    for (var barIndex = 1; barIndex < segments.length; barIndex++) {\n      final bounds = segments[barIndex].bounds;\n\n      left = min(left, bounds.left);\n      top = min(top, bounds.top);\n      right = max(right, bounds.right);\n      bottom = max(bottom, bounds.bottom);\n    }\n\n    final width = right - left;\n    final height = bottom - top;\n    final fullStackRect = Rectangle(left, top, width, height);\n\n    return CanvasBarStack._internal(\n      segments,\n      radius: radius,\n      stackedBarPadding: stackedBarPadding,\n      roundTopLeft: roundTopLeft,\n      roundTopRight: roundTopRight,\n      roundBottomLeft: roundBottomLeft,\n      roundBottomRight: roundBottomRight,\n      fullStackRect: fullStackRect,\n    );\n  }\n\n  CanvasBarStack._internal(\n    this.segments, {\n    required this.radius,\n    required this.stackedBarPadding,\n    required this.roundTopLeft,\n    required this.roundTopRight,\n    required this.roundBottomLeft,\n    required this.roundBottomRight,\n    required this.fullStackRect,\n  });\n}\n\n/// A list of [CanvasPieSlice]s to be painted by [ChartCanvas].\nclass CanvasPie {\n  final List<CanvasPieSlice> slices;\n  Point center;\n  double radius;\n  double innerRadius;\n\n  /// Color of separator lines between arcs.\n  final Color? stroke;\n\n  /// Stroke width of separator lines between arcs.\n  double strokeWidthPx;\n\n  CanvasPie(this.slices, this.center, this.radius, this.innerRadius,\n      {this.stroke, this.strokeWidthPx = 0.0});\n}\n\n/// A circle sector to be painted by [ChartCanvas].\nclass CanvasPieSlice {\n  double startAngle;\n  double endAngle;\n  Color? fill;\n\n  CanvasPieSlice(this.startAngle, this.endAngle, {this.fill});\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/common/chart_canvas.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math' show Point, Rectangle;\n\nimport '../../common/color.dart' show Color;\nimport '../../common/graphics_factory.dart' show GraphicsFactory;\nimport '../../common/text_element.dart' show TextElement;\nimport 'canvas_shapes.dart' show CanvasBarStack, CanvasPie;\n\nabstract class ChartCanvas {\n  /// Get [GraphicsFactory] for creating native graphics elements.\n  GraphicsFactory get graphicsFactory;\n\n  /// Set the name of the view doing the rendering for debugging purposes,\n  /// or null when we believe rendering is complete.\n  set drawingView(String? viewName);\n\n  /// Renders a sector of a circle, with an optional hole in the center.\n  ///\n  /// [center] The x, y coordinates of the circle's center.\n  /// [radius] The radius of the circle.\n  /// [innerRadius] Optional radius of a hole in the center of the circle that\n  ///     should not be filled in as part of the sector.\n  /// [startAngle] The angle at which the arc starts, measured clockwise from\n  ///     the positive x axis and expressed in radians\n  /// [endAngle] The angle at which the arc ends, measured clockwise from the\n  ///     positive x axis and expressed in radians.\n  /// [fill] Fill color for the sector.\n  /// [stroke] Stroke color of the arc and radius lines.\n  /// [strokeWidthPx] Stroke width of the arc and radius lines.\n  void drawCircleSector(Point center, double radius, double innerRadius,\n      double startAngle, double endAngle,\n      {Color? fill, Color? stroke, double? strokeWidthPx});\n\n  /// Renders a simple line.\n  ///\n  /// [dashPattern] controls the pattern of dashes and gaps in a line. It is a\n  /// list of lengths of alternating dashes and gaps. The rendering is similar\n  /// to stroke-dasharray in SVG path elements. An odd number of values in the\n  /// pattern will be repeated to derive an even number of values. \"1,2,3\" is\n  /// equivalent to \"1,2,3,1,2,3.\"\n  void drawLine(\n      {required List<Point> points,\n      Rectangle<num>? clipBounds,\n      Color? fill,\n      Color? stroke,\n      bool? roundEndCaps,\n      double? strokeWidthPx,\n      List<int>? dashPattern});\n\n  /// Renders a pie, with an optional hole in the center.\n  void drawPie(CanvasPie canvasPie);\n\n  /// Renders a simple point.\n  ///\n  /// [point] The x, y coordinates of the point.\n  ///\n  /// [radius] The radius of the point.\n  ///\n  /// [fill] Fill color for the point.\n  ///\n  /// [stroke] and [strokeWidthPx] configure the color and thickness of the\n  /// outer edge of the point. Both must be provided together for a line to\n  /// appear.\n  ///\n  /// [blendMode] Blend mode to be used when drawing this point on canvas.\n  void drawPoint(\n      {required Point point,\n      required double radius,\n      Color? fill,\n      Color? stroke,\n      double? strokeWidthPx,\n      BlendMode? blendMode});\n\n  /// Renders a polygon shape described by a set of points.\n  ///\n  /// [points] describes the vertices of the polygon. The last point will always\n  /// be connected to the first point to close the shape.\n  ///\n  /// [fill] configures the color inside the polygon. The shape will be\n  /// transparent if this is not provided.\n  ///\n  /// [stroke] and [strokeWidthPx] configure the color and thickness of the\n  /// edges of the polygon. Both must be provided together for a line to appear.\n  void drawPolygon(\n      {required List<Point> points,\n      Rectangle<num>? clipBounds,\n      Color? fill,\n      Color? stroke,\n      double? strokeWidthPx});\n\n  /// Renders a simple rectangle.\n  ///\n  /// [drawAreaBounds] if specified and if the bounds of the rectangle exceed\n  /// the draw area bounds on the top, the first x pixels (decided by the native\n  /// platform) exceeding the draw area will apply a gradient to transparent\n  /// with anything exceeding the x pixels to be transparent.\n  void drawRect(Rectangle<num> bounds,\n      {Color? fill,\n      Color? stroke,\n      double? strokeWidthPx,\n      Rectangle<num>? drawAreaBounds});\n\n  /// Renders a rounded rectangle.\n  void drawRRect(Rectangle<num> bounds,\n      {Color? fill,\n      Color? stroke,\n      Color? patternColor,\n      FillPatternType? fillPattern,\n      double? patternStrokeWidthPx,\n      double? strokeWidthPx,\n      num? radius,\n      bool roundTopLeft = false,\n      bool roundTopRight = false,\n      bool roundBottomLeft = false,\n      bool roundBottomRight = false});\n\n  /// Renders a stack of bars, rounding the last bar in the stack.\n  ///\n  /// The first bar of the stack is expected to be the \"base\" bar. This would\n  /// be the bottom most bar for a vertically rendered bar.\n  ///\n  /// [drawAreaBounds] if specified and if the bounds of the rectangle exceed\n  /// the draw area bounds on the top, the first x pixels (decided by the native\n  /// platform) exceeding the draw area will apply a gradient to transparent\n  /// with anything exceeding the x pixels to be transparent.\n  void drawBarStack(CanvasBarStack canvasBarStack,\n      {Rectangle<num>? drawAreaBounds});\n\n  void drawText(TextElement textElement, int offsetX, int offsetY,\n      {double rotation = 0.0});\n\n  /// Request the canvas to clip to [clipBounds].\n  ///\n  /// Applies to all operations until [restClipBounds] is called.\n  void setClipBounds(Rectangle<int> clipBounds);\n\n  /// Restore\n  void resetClipBounds();\n}\n\nColor getAnimatedColor(Color previous, Color target, double animationPercent) {\n  var r = (((target.r - previous.r) * animationPercent) + previous.r).round();\n  var g = (((target.g - previous.g) * animationPercent) + previous.g).round();\n  var b = (((target.b - previous.b) * animationPercent) + previous.b).round();\n  var a = (((target.a - previous.a) * animationPercent) + previous.a).round();\n\n  return Color(a: a, r: r, g: g, b: b);\n}\n\n/// Defines the pattern for a color fill.\n///\n/// * [forwardHatch] defines a pattern of white lines angled up and to the right\n///   on top of a bar filled with the fill color.\n/// * [solid] defines a simple bar filled with the fill color. This is the\n///   default pattern for bars.\nenum FillPatternType { forwardHatch, solid }\n\n/// Defines the blend modes to use for drawing on canvas.\nenum BlendMode {\n  color,\n  colorBurn,\n  colorDodge,\n  darken,\n  defaultMode,\n  difference,\n  exclusion,\n  hardLight,\n  hue,\n  lighten,\n  luminosity,\n  multiply,\n  overlay,\n  saturation,\n  screen,\n  softLight,\n  copy,\n  destinationAtop,\n  destinationIn,\n  destinationOut,\n  destinationOver,\n  lighter,\n  sourceAtop,\n  sourceIn,\n  sourceOut,\n  sourceOver,\n  xor\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/common/chart_context.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport '../../common/date_time_factory.dart';\nimport '../../common/rtl_spec.dart' show RTLSpec;\nimport '../common/behavior/a11y/a11y_node.dart' show A11yNode;\n\nabstract class ChartContext {\n  /// Flag indicating whether or not the chart's container was configured in\n  /// right to left mode.\n  ///\n  /// This should be set when the chart is created (or if its container ever\n  /// gets configured to the other direction setting).\n  ///\n  /// Any chart component that needs to know whether the chart axes should be\n  /// rendered right to left should read [isRtl].\n  bool get chartContainerIsRtl;\n\n  /// Configures the behavior of the chart when [chartContainerIsRtl] is true.\n  RTLSpec? get rtlSpec;\n\n  /// Gets whether or not the chart axes should be rendered in right to left\n  /// mode.\n  ///\n  /// This will only be true if the container for the chart component was\n  /// configured with the rtl direction setting ([chartContainerIsRtl] == true), and the chart's\n  /// [RTLSpec] is set to reverse the axis direction in rtl mode.\n  bool get isRtl;\n\n  /// Whether or not the chart will respond to tap events.\n  ///\n  /// This will generally be true if there is a behavior attached to the chart\n  /// that does something with tap events, such as \"click to select data.\"\n  bool get isTappable;\n\n  double get pixelsPerDp;\n\n  DateTimeFactory get dateTimeFactory;\n\n  void requestRedraw();\n\n  void requestAnimation(Duration transition);\n\n  void requestPaint();\n\n  void enableA11yExploreMode(List<A11yNode> nodes, {String? announcement});\n\n  void disableA11yExploreMode({String? announcement});\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/common/datum_details.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math';\n\nimport '../../common/color.dart' show Color;\nimport '../../common/math.dart' show NullablePoint;\nimport '../../common/symbol_renderer.dart' show SymbolRenderer;\nimport 'chart_canvas.dart' show FillPatternType;\nimport 'processed_series.dart' show ImmutableSeries;\n\ntypedef DomainFormatter<D> = String Function(D domain);\ntypedef MeasureFormatter = String Function(num? measure);\n\n/// Represents processed rendering details for a data point from a series.\nclass DatumDetails<D> {\n  final dynamic datum;\n\n  /// The index of the datum in the series.\n  final int? index;\n\n  /// Domain value of [datum].\n  final D? domain;\n\n  /// Domain lower bound value of [datum]. This may represent an error bound, or\n  /// a previous domain value.\n  final D? domainLowerBound;\n\n  /// Domain upper bound value of [datum]. This may represent an error bound, or\n  /// a target domain value.\n  final D? domainUpperBound;\n\n  /// Measure value of [datum].\n  final num? measure;\n\n  /// Measure lower bound value of [datum]. This may represent an error bound,\n  /// or a previous value.\n  final num? measureLowerBound;\n\n  /// Measure upper bound value of [datum]. This may represent an error bound,\n  /// or a target measure value.\n  final num? measureUpperBound;\n\n  /// Measure offset value of [datum].\n  final num? measureOffset;\n\n  /// Original measure value of [datum]. This may differ from [measure] if a\n  /// behavior attached to a chart automatically adjusts measure values.\n  final num? rawMeasure;\n\n  /// Original measure lower bound value of [datum]. This may differ from\n  /// [measureLowerBound] if a behavior attached to a chart automatically\n  /// adjusts measure values.\n  final num? rawMeasureLowerBound;\n\n  /// Original measure upper bound value of [datum]. This may differ from\n  /// [measureUpperBound] if a behavior attached to a chart automatically\n  /// adjusts measure values.\n  final num? rawMeasureUpperBound;\n\n  /// The series the [datum] is from.\n  final ImmutableSeries<D>? series;\n\n  /// The color of this [datum].\n  final Color? color;\n\n  /// Optional fill color of this [datum].\n  ///\n  /// If this is defined, then [color] will be used as a stroke color.\n  /// Otherwise, [color] will be used for the fill color.\n  final Color? fillColor;\n\n  /// Optional fill pattern of this [datum].\n  final FillPatternType? fillPattern;\n\n  /// Optional area color of this [datum].\n  ///\n  /// This color is used for supplemental information on the series, such as\n  /// confidence intervals or area skirts. If not provided, then some variation\n  /// of the main [color] will be used (e.g. 10% opacity).\n  final Color? areaColor;\n\n  /// Optional dash pattern of this [datum].\n  final List<int>? dashPattern;\n\n  /// The chart position of the (domain, measure) for the [datum] from a\n  /// renderer.\n  final NullablePoint? chartPosition;\n\n  /// The chart position of the (domainLowerBound, measureLowerBound) for the\n  /// [datum] from a renderer.\n  final NullablePoint? chartPositionLower;\n\n  /// The chart position of the (domainUpperBound, measureUpperBound) for the\n  /// [datum] from a renderer.\n  final NullablePoint? chartPositionUpper;\n\n  /// The bounding box for the chart space occupied by this datum.\n  ///\n  /// This is currently only populated by the bar series renderer.\n  ///\n  /// TODO: Fill this in for other series renderers.\n  final Rectangle<int>? bounds;\n\n  /// Distance of [domain] from a given (x, y) coordinate.\n  final double? domainDistance;\n\n  /// Distance of [measure] from a given (x, y) coordinate.\n  final double? measureDistance;\n\n  /// Relative Cartesian distance of ([domain], [measure]) from a given (x, y)\n  /// coordinate.\n  final double? relativeDistance;\n\n  /// The radius of this [datum].\n  final double? radiusPx;\n\n  /// Renderer used to draw the shape of this datum.\n  ///\n  /// This is primarily used for point shapes on line and scatter plot charts.\n  final SymbolRenderer? symbolRenderer;\n\n  /// The stroke width of this [datum].\n  final double? strokeWidthPx;\n\n  /// Optional formatter for [domain].\n  DomainFormatter<D>? domainFormatter;\n\n  /// Optional formatter for [measure].\n  MeasureFormatter? measureFormatter;\n\n  DatumDetails(\n      {this.datum,\n      this.index,\n      this.domain,\n      this.domainFormatter,\n      this.domainLowerBound,\n      this.domainUpperBound,\n      this.measure,\n      this.measureFormatter,\n      this.measureLowerBound,\n      this.measureUpperBound,\n      this.measureOffset,\n      this.rawMeasure,\n      this.rawMeasureLowerBound,\n      this.rawMeasureUpperBound,\n      this.series,\n      this.color,\n      this.fillColor,\n      this.fillPattern,\n      this.areaColor,\n      this.dashPattern,\n      this.chartPosition,\n      this.chartPositionLower,\n      this.chartPositionUpper,\n      this.bounds,\n      this.domainDistance,\n      this.measureDistance,\n      this.relativeDistance,\n      this.radiusPx,\n      this.symbolRenderer,\n      this.strokeWidthPx});\n\n  factory DatumDetails.from(DatumDetails<D> other,\n      {D? datum,\n      int? index,\n      D? domain,\n      D? domainLowerBound,\n      D? domainUpperBound,\n      num? measure,\n      MeasureFormatter? measureFormatter,\n      num? measureLowerBound,\n      num? measureUpperBound,\n      num? measureOffset,\n      num? rawMeasure,\n      num? rawMeasureLowerBound,\n      num? rawMeasureUpperBound,\n      ImmutableSeries<D>? series,\n      Color? color,\n      Color? fillColor,\n      FillPatternType? fillPattern,\n      Color? areaColor,\n      List<int>? dashPattern,\n      NullablePoint? chartPosition,\n      NullablePoint? chartPositionLower,\n      NullablePoint? chartPositionUpper,\n      Rectangle<int>? bounds,\n      DomainFormatter<D>? domainFormatter,\n      double? domainDistance,\n      double? measureDistance,\n      double? radiusPx,\n      SymbolRenderer? symbolRenderer,\n      double? strokeWidthPx}) {\n    return DatumDetails<D>(\n        datum: datum ?? other.datum,\n        index: index ?? other.index,\n        domain: domain ?? other.domain,\n        domainFormatter: domainFormatter ?? other.domainFormatter,\n        domainLowerBound: domainLowerBound ?? other.domainLowerBound,\n        domainUpperBound: domainUpperBound ?? other.domainUpperBound,\n        measure: measure ?? other.measure,\n        measureFormatter: measureFormatter ?? other.measureFormatter,\n        measureLowerBound: measureLowerBound ?? other.measureLowerBound,\n        measureUpperBound: measureUpperBound ?? other.measureUpperBound,\n        measureOffset: measureOffset ?? other.measureOffset,\n        rawMeasure: rawMeasure ?? other.rawMeasure,\n        rawMeasureLowerBound:\n            rawMeasureLowerBound ?? other.rawMeasureLowerBound,\n        rawMeasureUpperBound:\n            rawMeasureUpperBound ?? other.rawMeasureUpperBound,\n        series: series ?? other.series,\n        color: color ?? other.color,\n        fillColor: fillColor ?? other.fillColor,\n        fillPattern: fillPattern ?? other.fillPattern,\n        areaColor: areaColor ?? other.areaColor,\n        dashPattern: dashPattern ?? other.dashPattern,\n        chartPosition: chartPosition ?? other.chartPosition,\n        chartPositionLower: chartPositionLower ?? other.chartPositionLower,\n        chartPositionUpper: chartPositionUpper ?? other.chartPositionUpper,\n        bounds: bounds ?? other.bounds,\n        domainDistance: domainDistance ?? other.domainDistance,\n        measureDistance: measureDistance ?? other.measureDistance,\n        radiusPx: radiusPx ?? other.radiusPx,\n        symbolRenderer: symbolRenderer ?? other.symbolRenderer,\n        strokeWidthPx: radiusPx ?? other.strokeWidthPx);\n  }\n\n  String get formattedDomain =>\n      (domainFormatter != null) ? domainFormatter!(domain!) : domain.toString();\n\n  String get formattedMeasure => (measureFormatter != null)\n      ? measureFormatter!(measure)\n      : measure.toString();\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/common/processed_series.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport '../../common/color.dart' show Color;\nimport 'datum_details.dart' show DomainFormatter, MeasureFormatter;\nimport '../../data/series.dart'\n    show AccessorFn, Series, SeriesAttributes, AttributeKey;\nimport '../cartesian/axis/axis.dart' show Axis;\nimport '../cartesian/axis/spec/axis_spec.dart' show TextStyleSpec;\nimport '../common/chart_canvas.dart' show FillPatternType;\n\nclass MutableSeries<D> extends ImmutableSeries<D> {\n  @override\n  final String id;\n\n  @override\n  String? displayName;\n\n  @override\n  bool overlaySeries;\n\n  @override\n  String? seriesCategory;\n\n  @override\n  Color? seriesColor;\n\n  @override\n  late int seriesIndex;\n\n  /// Sum of the measure values for the series.\n  @override\n  late num seriesMeasureTotal;\n\n  @override\n  List<dynamic> data;\n\n  @override\n  AccessorFn<String>? keyFn;\n\n  @override\n  AccessorFn<D> domainFn;\n\n  @override\n  AccessorFn<DomainFormatter<D>>? domainFormatterFn;\n\n  @override\n  AccessorFn<D?>? domainLowerBoundFn;\n\n  @override\n  AccessorFn<D?>? domainUpperBoundFn;\n\n  @override\n  AccessorFn<num?> measureFn;\n\n  @override\n  AccessorFn<MeasureFormatter>? measureFormatterFn;\n\n  @override\n  AccessorFn<num?>? measureLowerBoundFn;\n\n  @override\n  AccessorFn<num?>? measureUpperBoundFn;\n\n  @override\n  AccessorFn<num?>? measureOffsetFn;\n\n  @override\n  AccessorFn<num?> rawMeasureFn;\n\n  @override\n  AccessorFn<num?>? rawMeasureLowerBoundFn;\n\n  @override\n  AccessorFn<num?>? rawMeasureUpperBoundFn;\n\n  @override\n  AccessorFn<Color?>? areaColorFn;\n\n  @override\n  AccessorFn<Color>? colorFn;\n\n  @override\n  AccessorFn<List<int>?>? dashPatternFn;\n\n  @override\n  AccessorFn<Color?>? fillColorFn;\n\n  @override\n  AccessorFn<FillPatternType?>? fillPatternFn;\n\n  @override\n  AccessorFn<Color?>? patternColorFn;\n\n  @override\n  AccessorFn<num?>? radiusPxFn;\n  @override\n  AccessorFn<num?>? strokeWidthPxFn;\n  @override\n  AccessorFn<String>? labelAccessorFn;\n\n  @override\n  AccessorFn<TextStyleSpec>? insideLabelStyleAccessorFn;\n\n  @override\n  AccessorFn<TextStyleSpec>? outsideLabelStyleAccessorFn;\n\n  final _attrs = SeriesAttributes();\n\n  Axis<num>? measureAxis;\n  Axis<D>? domainAxis;\n\n  MutableSeries(Series<dynamic, D> series)\n      : id = series.id,\n        displayName = series.displayName ?? series.id,\n        overlaySeries = series.overlaySeries,\n        seriesCategory = series.seriesCategory,\n        seriesColor = series.seriesColor,\n        data = series.data,\n        keyFn = series.keyFn,\n        domainFn = series.domainFn,\n        domainFormatterFn = series.domainFormatterFn,\n        domainLowerBoundFn = series.domainLowerBoundFn,\n        domainUpperBoundFn = series.domainUpperBoundFn,\n        measureFn = series.measureFn,\n        measureFormatterFn = series.measureFormatterFn,\n        measureLowerBoundFn = series.measureLowerBoundFn,\n        measureUpperBoundFn = series.measureUpperBoundFn,\n        measureOffsetFn = series.measureOffsetFn,\n\n        // Save the original measure functions in case they get replaced later.\n        rawMeasureFn = series.measureFn,\n        rawMeasureLowerBoundFn = series.measureLowerBoundFn,\n        rawMeasureUpperBoundFn = series.measureUpperBoundFn,\n        areaColorFn = series.areaColorFn,\n        colorFn = series.colorFn,\n        dashPatternFn = series.dashPatternFn,\n        fillColorFn = series.fillColorFn,\n        fillPatternFn = series.fillPatternFn,\n        patternColorFn = series.patternColorFn,\n        insideLabelStyleAccessorFn = series.insideLabelStyleAccessorFn,\n        outsideLabelStyleAccessorFn = series.outsideLabelStyleAccessorFn,\n        radiusPxFn = series.radiusPxFn,\n        strokeWidthPxFn = series.strokeWidthPxFn {\n    // Pre-compute the sum of the measure values to make it available on demand.\n    seriesMeasureTotal = 0;\n    for (var i = 0; i < data.length; i++) {\n      final measure = measureFn(i);\n      if (measure != null) {\n        seriesMeasureTotal += measure;\n      }\n    }\n\n    labelAccessorFn = series.labelAccessorFn ?? (i) => domainFn(i).toString();\n\n    _attrs.mergeFrom(series.attributes);\n  }\n\n  MutableSeries.clone(MutableSeries<D> other)\n      : id = other.id,\n        displayName = other.displayName,\n        overlaySeries = other.overlaySeries,\n        seriesCategory = other.seriesCategory,\n        seriesColor = other.seriesColor,\n        seriesIndex = other.seriesIndex,\n        data = other.data,\n        keyFn = other.keyFn,\n        domainFn = other.domainFn,\n        domainFormatterFn = other.domainFormatterFn,\n        domainLowerBoundFn = other.domainLowerBoundFn,\n        domainUpperBoundFn = other.domainUpperBoundFn,\n        measureFn = other.measureFn,\n        measureFormatterFn = other.measureFormatterFn,\n        measureLowerBoundFn = other.measureLowerBoundFn,\n        measureUpperBoundFn = other.measureUpperBoundFn,\n        measureOffsetFn = other.measureOffsetFn,\n        rawMeasureFn = other.rawMeasureFn,\n        rawMeasureLowerBoundFn = other.rawMeasureLowerBoundFn,\n        rawMeasureUpperBoundFn = other.rawMeasureUpperBoundFn,\n        seriesMeasureTotal = other.seriesMeasureTotal,\n        areaColorFn = other.areaColorFn,\n        colorFn = other.colorFn,\n        dashPatternFn = other.dashPatternFn,\n        fillColorFn = other.fillColorFn,\n        fillPatternFn = other.fillPatternFn,\n        patternColorFn = other.patternColorFn,\n        labelAccessorFn = other.labelAccessorFn,\n        insideLabelStyleAccessorFn = other.insideLabelStyleAccessorFn,\n        outsideLabelStyleAccessorFn = other.outsideLabelStyleAccessorFn,\n        radiusPxFn = other.radiusPxFn,\n        strokeWidthPxFn = other.strokeWidthPxFn,\n        measureAxis = other.measureAxis,\n        domainAxis = other.domainAxis {\n    _attrs.mergeFrom(other._attrs);\n  }\n\n  @override\n  void setAttr<R>(AttributeKey<R> key, R value) => _attrs.setAttr(key, value);\n\n  @override\n  R? getAttr<R>(AttributeKey<R> key) => _attrs.getAttr(key);\n\n  @override\n  bool operator ==(Object other) =>\n      other is MutableSeries && data == other.data && id == other.id;\n\n  @override\n  int get hashCode => data.hashCode * 31 + id.hashCode;\n}\n\nabstract class ImmutableSeries<D> {\n  String get id;\n\n  String? get displayName;\n\n  /// Overlay series provided supplemental information on a chart, but are not\n  /// considered to be primary data. They should not be selectable by user\n  /// interaction.\n  bool get overlaySeries;\n\n  String? get seriesCategory;\n\n  /// Color which represents the entire series in legends.\n  ///\n  /// If this is not provided in the original series object, it will be inferred\n  /// from the color of the first datum in the series.\n  ///\n  /// If this is provided, but no [colorFn] is provided, then it will be treated\n  /// as the color for each datum in the series.\n  ///\n  /// If neither are provided, then the chart will insert colors for each series\n  /// on the chart using a mapping function.\n  Color? get seriesColor;\n\n  int get seriesIndex;\n\n  /// Sum of the measure values for the series.\n  num get seriesMeasureTotal;\n\n  // Uses `dynamic` for convenience to callers.\n  List<dynamic> get data;\n\n  /// [keyFn] defines a globally unique identifier for each datum.\n  ///\n  /// The key for each datum is used during chart animation to smoothly\n  /// transition data still in the series to its new state.\n  ///\n  /// Note: This is currently an optional function that is not fully used by all\n  /// series renderers yet.\n  AccessorFn<String>? keyFn;\n\n  AccessorFn<D> get domainFn;\n\n  AccessorFn<DomainFormatter<D>>? get domainFormatterFn;\n\n  AccessorFn<D?>? get domainLowerBoundFn;\n\n  AccessorFn<D?>? get domainUpperBoundFn;\n\n  AccessorFn<num?> get measureFn;\n\n  AccessorFn<MeasureFormatter>? get measureFormatterFn;\n\n  AccessorFn<num?>? get measureLowerBoundFn;\n\n  AccessorFn<num?>? get measureUpperBoundFn;\n\n  AccessorFn<num?>? get measureOffsetFn;\n\n  AccessorFn<num?> get rawMeasureFn;\n\n  AccessorFn<num?>? get rawMeasureLowerBoundFn;\n\n  AccessorFn<num?>? get rawMeasureUpperBoundFn;\n\n  AccessorFn<Color?>? get areaColorFn;\n\n  AccessorFn<Color?>? get colorFn;\n\n  AccessorFn<List<int>?>? get dashPatternFn;\n\n  AccessorFn<Color?>? get fillColorFn;\n\n  AccessorFn<Color?>? get patternColorFn;\n\n  AccessorFn<FillPatternType?>? get fillPatternFn;\n\n  AccessorFn<String>? get labelAccessorFn;\n\n  AccessorFn<TextStyleSpec>? insideLabelStyleAccessorFn;\n  AccessorFn<TextStyleSpec>? outsideLabelStyleAccessorFn;\n\n  AccessorFn<num?>? get radiusPxFn;\n\n  AccessorFn<num?>? get strokeWidthPxFn;\n\n  void setAttr<R>(AttributeKey<R> key, R value);\n\n  R? getAttr<R>(AttributeKey<R> key);\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/common/selection_model/selection_model.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'package:collection/collection.dart' show ListEquality;\n\nimport '../processed_series.dart' show ImmutableSeries;\nimport '../series_datum.dart' show SeriesDatum, SeriesDatumConfig;\n\n/// Holds the state of interaction or selection for the chart to coordinate\n/// between various event sources and things that wish to act upon the selection\n/// state (highlight, drill, etc).\n///\n/// There is one instance per interaction type (ex: info, action) with each\n/// maintaining their own state. Info is typically used to update a hover/touch\n/// card while action is used in case of a secondary selection/action.\n///\n/// The series selection state is kept separate from datum selection state to\n/// allow more complex highlighting. For example: a Hovercard that shows entries\n/// for each datum for a given domain/time, but highlights the closest entry to\n/// match up with highlighting/bolding of the line and legend.\nclass SelectionModel<D> {\n  var _selectedDatum = <SeriesDatum<D>>[];\n  var _selectedSeries = <ImmutableSeries<D>>[];\n\n  /// Create selection model with the desired selection.\n  SelectionModel(\n      {List<SeriesDatum<D>>? selectedData,\n      List<ImmutableSeries<D>>? selectedSeries}) {\n    if (selectedData != null) {\n      _selectedDatum = selectedData;\n    }\n    if (selectedSeries != null) {\n      _selectedSeries = selectedSeries;\n    }\n  }\n\n  /// Create a deep copy of the selection model.\n  SelectionModel.fromOther(SelectionModel<D> other) {\n    _selectedDatum = List.of(other._selectedDatum);\n    _selectedSeries = List.of(other._selectedSeries);\n  }\n\n  /// Create selection model from configuration.\n  SelectionModel.fromConfig(List<SeriesDatumConfig<D>>? selectedDataConfig,\n      List<String>? selectedSeriesConfig, List<ImmutableSeries<D>> seriesList) {\n    final selectedDataMap = <String, List<D>>{};\n\n    if (selectedDataConfig != null) {\n      for (final config in selectedDataConfig) {\n        selectedDataMap[config.seriesId] ??= <D>[];\n        selectedDataMap[config.seriesId]!.add(config.domainValue as D);\n      }\n\n      // Add to list of selected series.\n      _selectedSeries.addAll(seriesList.where((ImmutableSeries<D> series) =>\n          selectedDataMap.keys.contains(series.id)));\n\n      // Add to list of selected data.\n      for (final series in seriesList) {\n        if (selectedDataMap.containsKey(series.id)) {\n          final domainFn = series.domainFn;\n\n          for (var i = 0; i < series.data.length; i++) {\n            final Object? datum = series.data[i];\n\n            if (selectedDataMap[series.id]!.contains(domainFn(i))) {\n              _selectedDatum.add(SeriesDatum(series, datum));\n            }\n          }\n        }\n      }\n    }\n\n    // Add to list of selected series, if it does not already exist.\n    if (selectedSeriesConfig != null) {\n      final existingSeriesIds = {\n        for (final series in _selectedSeries) series.id,\n      };\n\n      final remainingSeriesToAdd = selectedSeriesConfig\n          .where((String seriesId) => !existingSeriesIds.contains(seriesId))\n          .toSet();\n\n      _selectedSeries.addAll(seriesList.where((ImmutableSeries<D> series) =>\n          remainingSeriesToAdd.contains(series.id)));\n    }\n  }\n\n  /// Returns true if this [SelectionModel] has a selected datum.\n  bool get hasDatumSelection => _selectedDatum.isNotEmpty;\n\n  bool isDatumSelected(ImmutableSeries<D> series, int? index) {\n    final Object? datum = index == null ? null : series.data[index];\n    return _selectedDatum.contains(SeriesDatum(series, datum));\n  }\n\n  /// Returns the selected [SeriesDatum] for this [SelectionModel].\n  ///\n  /// This is empty by default.\n  List<SeriesDatum<D>> get selectedDatum => List.unmodifiable(_selectedDatum);\n\n  /// Returns true if this [SelectionModel] has a selected series.\n  bool get hasSeriesSelection => _selectedSeries.isNotEmpty;\n\n  /// Returns the selected [ImmutableSeries] for this [SelectionModel].\n  ///\n  /// This is empty by default.\n  List<ImmutableSeries<D>> get selectedSeries =>\n      List.unmodifiable(_selectedSeries);\n\n  /// Returns true if this [SelectionModel] has a selected datum or series.\n  bool get hasAnySelection =>\n      _selectedDatum.isNotEmpty || selectedSeries.isNotEmpty;\n\n  @override\n  bool operator ==(Object other) {\n    return other is SelectionModel<D> &&\n        ListEquality<SeriesDatum<D>>()\n            .equals(_selectedDatum, other.selectedDatum) &&\n        ListEquality<ImmutableSeries<D>>()\n            .equals(_selectedSeries, other.selectedSeries);\n  }\n\n  @override\n  int get hashCode {\n    var hashcode = ListEquality<SeriesDatum<D>>().hash(_selectedDatum);\n    hashcode = hashcode * 37 +\n        ListEquality<ImmutableSeries<D>>().hash(_selectedSeries);\n    return hashcode;\n  }\n}\n\n/// A [SelectionModel] that can be updated.\n///\n/// This model will notify listeners subscribed to this model when the selection\n/// is modified.\nclass MutableSelectionModel<D> extends SelectionModel<D> {\n  final _changedListeners = <SelectionModelListener<D>>[];\n  final _updatedListeners = <SelectionModelListener<D>>[];\n  final _lockChangedListeners = <SelectionModelListener<D>>[];\n\n  bool _locked = false;\n\n  /// When set to true, prevents the model from being updated.\n  set locked(bool locked) {\n    _locked = locked;\n    _lockChangedListeners\n        .forEach((listener) => listener(SelectionModel.fromOther(this)));\n  }\n\n  bool get locked => _locked;\n\n  /// Clears the selection state.\n  bool clearSelection({bool notifyListeners = true}) {\n    return updateSelection([], [], notifyListeners: notifyListeners);\n  }\n\n  /// Updates the selection state. If mouse driven, [datumSelection] should be\n  /// ordered by distance from mouse, closest first.\n  bool updateSelection(\n      List<SeriesDatum<D>> datumSelection, List<ImmutableSeries<D>> seriesList,\n      {bool notifyListeners = true}) {\n    if (_locked) return false;\n\n    final origSelectedDatum = _selectedDatum;\n    final origSelectedSeries = _selectedSeries;\n\n    _selectedDatum = datumSelection;\n    _selectedSeries = seriesList;\n\n    // Provide a copy, so listeners get an immutable model.\n    final copyOfSelectionModel = SelectionModel.fromOther(this);\n    _updatedListeners.forEach((listener) => listener(copyOfSelectionModel));\n\n    final changed = !ListEquality<SeriesDatum<D>>()\n            .equals(origSelectedDatum, _selectedDatum) ||\n        !ListEquality<ImmutableSeries<D>>()\n            .equals(origSelectedSeries, _selectedSeries);\n    if (notifyListeners && changed) {\n      _changedListeners.forEach((listener) => listener(copyOfSelectionModel));\n    }\n    return changed;\n  }\n\n  /// Add a listener to be notified when this [SelectionModel] changes.\n  ///\n  /// Note: the listener will not be triggered if [updateSelection] is called\n  /// resulting in the same selection state.\n  void addSelectionChangedListener(SelectionModelListener<D> listener) {\n    _changedListeners.add(listener);\n  }\n\n  /// Remove listener from being notified when this [SelectionModel] changes.\n  void removeSelectionChangedListener(SelectionModelListener<D> listener) {\n    _changedListeners.remove(listener);\n  }\n\n  /// Add a listener to be notified when [updateSelection] is called, even if\n  /// the selection state is the same.\n  ///\n  /// This is necessary in order to support programmatic selections in Flutter.\n  /// Due to the way widgets are constructed in Flutter, there currently isn't\n  /// a way for users to programmatically specify the selection. In order to\n  /// provide this support, the users who subscribe to the selection updated\n  /// event can keep a copy of the selection model and also decide if it should\n  /// be overwritten.\n  void addSelectionUpdatedListener(SelectionModelListener<D> listener) {\n    _updatedListeners.add(listener);\n  }\n\n  /// Remove listener from being notified when [updateSelection] is called.\n  void removeSelectionUpdatedListener(SelectionModelListener<D> listener) {\n    _updatedListeners.remove(listener);\n  }\n\n  /// Add a listener to be notified when this [SelectionModel] is locked.\n  void addSelectionLockChangedListener(SelectionModelListener<D> listener) {\n    _lockChangedListeners.add(listener);\n  }\n\n  /// Remove listener from being notified when this [SelectionModel]  is locked.\n  void removeSelectionLockChangedListener(SelectionModelListener<D> listener) {\n    _lockChangedListeners.remove(listener);\n  }\n\n  /// Remove all listeners.\n  void clearAllListeners() {\n    _changedListeners.clear();\n    _updatedListeners.clear();\n    _lockChangedListeners.clear();\n  }\n}\n\n/// Callback for SelectionModel. It is triggered when the selection state\n/// changes.\ntypedef SelectionModelListener<D> = void Function(SelectionModel<D> model);\n\nenum SelectionModelType {\n  /// Typical Hover or Details event for viewing the details of the selected\n  /// items.\n  info,\n\n  /// Typical Selection, Drill or Input event likely updating some external\n  /// content.\n  action,\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/common/series_datum.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'processed_series.dart' show ImmutableSeries;\n\n/// Stores datum and the series the datum originated.\nclass SeriesDatum<D> {\n  final ImmutableSeries<D> series;\n  final dynamic datum;\n\n  /// This is set after [index] getter is called. So accessing this directly is\n  /// considered unsafe. Always uses [index] getter instead.\n  int? _index;\n\n  SeriesDatum(this.series, this.datum);\n\n  /// Returns null if-and-only if [datum] is null.\n  int? get index {\n    if (datum == null) return null;\n    _index ??= series.data.indexOf(datum);\n    return _index;\n  }\n\n  @override\n  bool operator ==(Object other) =>\n      other is SeriesDatum && other.series == series && other.datum == datum;\n\n  @override\n  int get hashCode => series.hashCode * 31 + datum.hashCode;\n}\n\n/// Represents a series datum based on series id and datum index.\nclass SeriesDatumConfig<D> {\n  final String seriesId;\n  final D domainValue;\n\n  SeriesDatumConfig(this.seriesId, this.domainValue);\n\n  @override\n  bool operator ==(Object other) {\n    return other is SeriesDatumConfig &&\n        seriesId == other.seriesId &&\n        domainValue == other.domainValue;\n  }\n\n  @override\n  int get hashCode {\n    var hashcode = seriesId.hashCode;\n    hashcode = hashcode * 37 + domainValue.hashCode;\n    return hashcode;\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/common/series_renderer.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math' show Point, Rectangle, max;\n\nimport 'package:meta/meta.dart';\n\nimport '../../common/color.dart' show Color;\nimport '../../common/graphics_factory.dart' show GraphicsFactory;\nimport '../../common/style/style_factory.dart' show StyleFactory;\nimport '../../common/symbol_renderer.dart' show SymbolRenderer;\nimport '../../data/series.dart' show AttributeKey;\nimport '../layout/layout_view.dart'\n    show\n        LayoutPosition,\n        LayoutView,\n        LayoutViewConfig,\n        LayoutViewPositionOrder,\n        ViewMeasuredSizes;\nimport 'base_chart.dart' show BaseChart;\nimport 'chart_canvas.dart' show ChartCanvas;\nimport 'datum_details.dart' show DatumDetails;\nimport 'processed_series.dart' show ImmutableSeries, MutableSeries;\nimport 'series_datum.dart' show SeriesDatum;\n\n/// Unique identifier used to associate custom series renderers on a chart with\n/// one or more series of data.\n///\n/// [rendererIdKey] can be added as an attribute to user-defined [Series]\n/// objects.\nconst rendererIdKey = AttributeKey<String>('SeriesRenderer.rendererId');\n\nconst rendererKey =\n    AttributeKey<SeriesRenderer<Object>>('SeriesRenderer.renderer');\n\n/// A series renderer draws one or more series of data onto a chart canvas.\nabstract class SeriesRenderer<D> extends LayoutView {\n  static const defaultRendererId = 'default';\n\n  /// Symbol renderer for this renderer.\n  ///\n  /// The default is set natively by the platform. This is because in Flutter,\n  /// the [SymbolRenderer] has to be a Flutter wrapped version to support\n  /// building widget based symbols.\n  SymbolRenderer? get symbolRenderer;\n\n  set symbolRenderer(SymbolRenderer? symbolRenderer);\n\n  /// Unique identifier for this renderer. Any [Series] on a chart with a\n  /// matching  [rendererIdKey] will be drawn by this renderer.\n  String get rendererId;\n\n  set rendererId(String rendererId);\n\n  /// Handles any setup of the renderer that needs to be deferred until it is\n  /// attached to a chart.\n  void onAttach(BaseChart<D> chart);\n\n  /// Handles any clean-up of the renderer that needs to be performed when it is\n  /// detached from a chart.\n  void onDetach(BaseChart<D> chart);\n\n  /// Performs basic configuration for the series, before it is pre-processed.\n  ///\n  /// Typically, a series renderer should assign color mapping functions to\n  /// series that do not have them.\n  void configureSeries(List<MutableSeries<D>> seriesList);\n\n  /// Pre-calculates some details for the series that will be needed later\n  /// during the drawing phase.\n  void preprocessSeries(List<MutableSeries<D>> seriesList);\n\n  /// Adds the domain values for the given series to the chart's domain axis.\n  void configureDomainAxes(List<MutableSeries<D>> seriesList);\n\n  /// Adds the measure values for the given series to the chart's measure axes.\n  void configureMeasureAxes(List<MutableSeries<D>> seriesList);\n\n  /// Generates rendering data needed to paint the data on the chart.\n  ///\n  /// This is called during the post layout phase of the chart draw cycle.\n  void update(List<ImmutableSeries<D>> seriesList, bool isAnimating);\n\n  /// Renders the series data on the canvas, using the data generated during the\n  /// [update] call.\n  @override\n  void paint(ChartCanvas canvas, double animationPercent);\n\n  /// Gets a list of the data from each series that is closest to a given point.\n  ///\n  /// [chartPoint] represents a point in the chart, such as a point that was\n  /// clicked/tapped on by a user.\n  ///\n  /// [selectOverlappingPoints] specifies whether to include all points that\n  /// overlap the tapped position in the result. If specified, the method will\n  /// return either the closest point or all the overlapping points with the\n  /// tapped position.\n  ///\n  /// [byDomain] specifies whether the nearest data should be defined by domain\n  /// distance, or relative Cartesian distance.\n  ///\n  /// [boundsOverride] optionally specifies a bounding box for the selection\n  /// event. If specified, then no data should be returned if [chartPoint] lies\n  /// outside the box. If not specified, then each series renderer on the chart\n  /// will use its own component bounds for filtering out selection events\n  /// (usually the chart draw area).\n  List<DatumDetails<D>> getNearestDatumDetailPerSeries(\n    Point<double> chartPoint,\n    bool byDomain,\n    Rectangle<int>? boundsOverride, {\n    bool selectOverlappingPoints = false,\n    bool selectExactEventLocation = false,\n  });\n\n  /// Get an expanded set of processed [DatumDetails] for a given [SeriesDatum].\n  ///\n  /// This is typically called by chart behaviors that need to get full details\n  /// on selected data.\n  DatumDetails<D> getDetailsForSeriesDatum(SeriesDatum<D> seriesDatum);\n\n  /// Adds chart position data to [details].\n  ///\n  /// This is a helper function intended to be called from\n  /// [getDetailsForSeriesDatum]. Every concrete [SeriesRenderer] needs to\n  /// implement custom logic for setting location data.\n  DatumDetails<D> addPositionToDetailsForSeriesDatum(\n      DatumDetails<D> details, SeriesDatum<D> seriesDatum);\n}\n\n/// Concrete base class for [SeriesRenderer]s that implements common\n/// functionality.\nabstract class BaseSeriesRenderer<D> implements SeriesRenderer<D> {\n  @override\n  final LayoutViewConfig layoutConfig;\n\n  @override\n  String rendererId;\n\n  @override\n  SymbolRenderer? symbolRenderer;\n\n  Rectangle<int>? _drawAreaBounds;\n\n  Rectangle<int>? get drawBounds => _drawAreaBounds;\n\n  @override\n  GraphicsFactory? graphicsFactory;\n\n  BaseSeriesRenderer({\n    required this.rendererId,\n    required int layoutPaintOrder,\n    this.symbolRenderer,\n  }) : layoutConfig = LayoutViewConfig(\n            paintOrder: layoutPaintOrder,\n            position: LayoutPosition.DrawArea,\n            positionOrder: LayoutViewPositionOrder.drawArea);\n\n  @override\n  void onAttach(BaseChart<D> chart) {}\n\n  @override\n  void onDetach(BaseChart<D> chart) {}\n\n  /// Assigns colors to series that are missing their colorFn.\n  ///\n  /// [emptyCategoryUsesSinglePalette] Flag indicating whether having all\n  ///     series with no categories will use the same or separate palettes.\n  ///     Setting it to true uses various Blues for each series.\n  ///     Setting it to false used different palettes (ie: s1 uses Blue500,\n  ///     s2 uses Red500),\n  @protected\n  void assignMissingColors(Iterable<MutableSeries<D>> seriesList,\n      {required bool emptyCategoryUsesSinglePalette}) {\n    const defaultCategory = '__default__';\n\n    // Count up the number of missing series per category, keeping a max across\n    // categories.\n    final missingColorCountPerCategory = <String, int>{};\n    var maxMissing = 0;\n    var hasSpecifiedCategory = false;\n\n    seriesList.forEach((MutableSeries<D> series) {\n      // Assign the seriesColor as the color of every datum if no colorFn was\n      // provided.\n      if (series.colorFn == null && series.seriesColor != null) {\n        series.colorFn = (_) => series.seriesColor!;\n      }\n\n      // This series was missing both seriesColor and a colorFn. Add it to the\n      // \"missing\" set.\n      if (series.colorFn == null) {\n        // If there is no category, give it a default category to match logic.\n        var category = series.seriesCategory;\n        if (category == null) {\n          category = defaultCategory;\n        } else {\n          hasSpecifiedCategory = true;\n        }\n\n        // Increment the missing counts for the category.\n        final missingCnt = (missingColorCountPerCategory[category] ?? 0) + 1;\n        missingColorCountPerCategory[category] = missingCnt;\n        maxMissing = max(maxMissing, missingCnt);\n      }\n    });\n\n    if (maxMissing > 0) {\n      // Special handling of only series with empty categories when we want\n      // to use different palettes.\n      if (!emptyCategoryUsesSinglePalette && !hasSpecifiedCategory) {\n        final palettes = StyleFactory.style.getOrderedPalettes(maxMissing);\n        var index = 0;\n        seriesList.forEach((series) {\n          if (series.colorFn == null) {\n            final color = palettes[index % palettes.length].shadeDefault;\n            index++;\n            series.colorFn = (_) => color;\n            series.seriesColor ??= color;\n          } else {\n            // Fill in missing seriesColor values with the color of the first\n            // datum in the series. Note that [Series.colorFn] should always\n            // return a color.\n            if (series.seriesColor == null) {\n              try {\n                series.seriesColor = series.colorFn!(0);\n              } catch (exception) {\n                series.seriesColor = StyleFactory.style.defaultSeriesColor;\n              }\n            }\n          }\n        });\n        return;\n      }\n\n      // Get a list of palettes to use given the number of categories we've\n      // seen. One palette per category (but might need to repeat).\n      final colorPalettes = StyleFactory.style\n          .getOrderedPalettes(missingColorCountPerCategory.length);\n\n      // Create a map of Color palettes for each category. Each Palette uses\n      // the max for any category to ensure that the gradients look appropriate.\n      final colorsByCategory = <String, List<Color>>{};\n      var index = 0;\n      missingColorCountPerCategory.keys.forEach((String category) {\n        colorsByCategory[category] =\n            colorPalettes[index % colorPalettes.length].makeShades(maxMissing);\n        index++;\n\n        // Reset the count so we can use it to count as we set the colorFn.\n        missingColorCountPerCategory[category] = 0;\n      });\n\n      seriesList.forEach((series) {\n        if (series.colorFn == null) {\n          final category = series.seriesCategory ?? defaultCategory;\n\n          // Get the current index into the color list.\n          final colorIndex = missingColorCountPerCategory[category]!;\n          missingColorCountPerCategory[category] = colorIndex + 1;\n\n          final color = colorsByCategory[category]![colorIndex];\n          series.colorFn = (_) => color;\n        }\n\n        // Fill color defaults to the series color if no accessor is provided.\n        series.fillColorFn ??= (int? index) => series.colorFn!(index);\n      });\n    } else {\n      seriesList.forEach((series) {\n        // Fill color defaults to the series color if no accessor is provided.\n        series.fillColorFn ??= (int? index) => series.colorFn!(index);\n      });\n    }\n\n    // Fill in any missing seriesColor values with the color of the first datum\n    // in the series. Note that [Series.colorFn] should always return a color.\n    seriesList.forEach((series) {\n      if (series.seriesColor == null) {\n        try {\n          series.seriesColor = series.colorFn!(0);\n        } catch (exception) {\n          series.seriesColor = StyleFactory.style.defaultSeriesColor;\n        }\n      }\n    });\n  }\n\n  @override\n  ViewMeasuredSizes? measure(int maxWidth, int maxHeight) {\n    return null;\n  }\n\n  @override\n  void layout(Rectangle<int> componentBounds, Rectangle<int> drawAreaBounds) {\n    _drawAreaBounds = drawAreaBounds;\n  }\n\n  @override\n  Rectangle<int>? get componentBounds => _drawAreaBounds;\n\n  @override\n  bool get isSeriesRenderer => true;\n\n  @override\n  void configureSeries(List<MutableSeries<D>> seriesList) {}\n\n  @override\n  void preprocessSeries(List<MutableSeries<D>> seriesList) {}\n\n  @override\n  void configureDomainAxes(List<MutableSeries<D>> seriesList) {}\n\n  @override\n  void configureMeasureAxes(List<MutableSeries<D>> seriesList) {}\n\n  @override\n  DatumDetails<D> getDetailsForSeriesDatum(SeriesDatum<D> seriesDatum) {\n    // Generate details relevant to every type of series renderer. Position\n    // details are left as an exercise for every renderer that extends this\n    // class.\n    final series = seriesDatum.series;\n    final index = seriesDatum.index;\n    final domainFn = series.domainFn;\n    final domainLowerBoundFn = series.domainLowerBoundFn;\n    final domainUpperBoundFn = series.domainUpperBoundFn;\n    final measureFn = series.measureFn;\n    final measureLowerBoundFn = series.measureLowerBoundFn;\n    final measureUpperBoundFn = series.measureUpperBoundFn;\n    final measureOffsetFn = series.measureOffsetFn;\n    final rawMeasureFn = series.rawMeasureFn;\n    final rawMeasureLowerBoundFn = series.rawMeasureLowerBoundFn;\n    final rawMeasureUpperBoundFn = series.rawMeasureUpperBoundFn;\n    final colorFn = series.colorFn;\n    final areaColorFn = series.areaColorFn ?? colorFn;\n    final fillColorFn = series.fillColorFn ?? colorFn;\n    final radiusPxFn = series.radiusPxFn;\n    final strokeWidthPxFn = series.strokeWidthPxFn;\n\n    final domainValue = domainFn(index);\n    final domainLowerBoundValue = domainLowerBoundFn?.call(index);\n    final domainUpperBoundValue = domainUpperBoundFn?.call(index);\n\n    final measureValue = measureFn(index);\n    final measureLowerBoundValue = measureLowerBoundFn?.call(index);\n    final measureUpperBoundValue = measureUpperBoundFn?.call(index);\n    final measureOffsetValue = measureOffsetFn?.call(index);\n\n    final rawMeasureValue = rawMeasureFn(index);\n    final rawMeasureLowerBoundValue = rawMeasureLowerBoundFn?.call(index);\n    final rawMeasureUpperBoundValue = rawMeasureUpperBoundFn?.call(index);\n\n    final color = colorFn!(index);\n\n    // Fill color is an optional override for color. Make sure we get a value if\n    // the series doesn't define anything specific.\n    var fillColor = fillColorFn!(index);\n    fillColor ??= color;\n\n    // Area color is entirely optional.\n    final areaColor = areaColorFn!(index);\n\n    var radiusPx = radiusPxFn?.call(index)?.toDouble();\n    radiusPx = radiusPx?.toDouble();\n\n    var strokeWidthPx = strokeWidthPxFn?.call(index)?.toDouble();\n    strokeWidthPx = strokeWidthPx?.toDouble();\n\n    final details = DatumDetails<D>(\n        datum: seriesDatum.datum,\n        index: seriesDatum.index,\n        domain: domainValue,\n        domainLowerBound: domainLowerBoundValue,\n        domainUpperBound: domainUpperBoundValue,\n        measure: measureValue,\n        measureLowerBound: measureLowerBoundValue,\n        measureUpperBound: measureUpperBoundValue,\n        measureOffset: measureOffsetValue,\n        rawMeasure: rawMeasureValue,\n        rawMeasureLowerBound: rawMeasureLowerBoundValue,\n        rawMeasureUpperBound: rawMeasureUpperBoundValue,\n        series: series,\n        color: color,\n        fillColor: fillColor,\n        areaColor: areaColor,\n        radiusPx: radiusPx,\n        strokeWidthPx: strokeWidthPx);\n\n    // chartPosition depends on the shape of the rendered elements, and must be\n    // added by concrete [SeriesRenderer] classes.\n    return addPositionToDetailsForSeriesDatum(details, seriesDatum);\n  }\n\n  /// Returns true of [chartPoint] is within the component bounds for this\n  /// renderer.\n  ///\n  /// [chartPoint] a point to test.\n  ///\n  /// [bounds] optional override for component bounds. If this is passed, then\n  /// we will check whether the point is within these bounds instead of the\n  /// component bounds.\n  bool isPointWithinBounds(Point<double> chartPoint, Rectangle<int>? bounds) {\n    // Was it even in the drawArea?\n    if (bounds != null) {\n      if (!bounds.containsPoint(chartPoint)) {\n        return false;\n      }\n    } else if (componentBounds == null ||\n        !componentBounds!.containsPoint(chartPoint)) {\n      return false;\n    }\n\n    return true;\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/common/series_renderer_config.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport '../../common/symbol_renderer.dart';\nimport '../../common/typed_registry.dart';\nimport 'series_renderer.dart' show SeriesRenderer;\n\n/// Interface for series renderer configuration.\nabstract class SeriesRendererConfig<D> {\n  /// Stores typed renderer attributes\n  ///\n  /// This is useful for storing attributes that is used on the native platform.\n  /// Such as the SymbolRenderer that is associated with each renderer but is\n  /// a native builder since legend is built natively.\n  RendererAttributes get rendererAttributes;\n\n  String? get customRendererId;\n\n  SymbolRenderer? get symbolRenderer;\n\n  SeriesRenderer<D> build();\n}\n\nclass RendererAttributeKey<R> extends TypedKey<R> {\n  const RendererAttributeKey(String uniqueKey) : super(uniqueKey);\n}\n\nclass RendererAttributes extends TypedRegistry {}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/common/unitconverter/identity_converter.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'unit_converter.dart' show UnitConverter;\n\n/// A No op unit converter.\nclass IdentityConverter<U extends num> implements UnitConverter<U, U> {\n  const IdentityConverter();\n\n  @override\n  U convert(U value) => value;\n\n  @override\n  U invert(U value) => value;\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/common/unitconverter/unit_converter.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n/// Converts a num value in the 'from' unit to a num value in the 'to' unit.\n///\n/// [F] Type of the value in the 'from' units.\n/// [T] Type of the value in 'to' units.\nabstract class UnitConverter<F extends num, T extends num> {\n  /// Converts 'from' unit value to the 'to' unit value.\n  T convert(F value);\n\n  /// Converts 'to' unit value back to the 'from' unit value.\n  F invert(T value);\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/layout/layout_config.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n/// Collection of configurations that apply to the [LayoutManager].\nclass LayoutConfig {\n  final MarginSpec leftSpec;\n  final MarginSpec rightSpec;\n  final MarginSpec topSpec;\n  final MarginSpec bottomSpec;\n\n  /// Create a new [LayoutConfig] used by [DynamicLayoutManager].\n  LayoutConfig({\n    MarginSpec? leftSpec,\n    MarginSpec? rightSpec,\n    MarginSpec? topSpec,\n    MarginSpec? bottomSpec,\n  })  : leftSpec = leftSpec ?? MarginSpec.defaultSpec,\n        rightSpec = rightSpec ?? MarginSpec.defaultSpec,\n        topSpec = topSpec ?? MarginSpec.defaultSpec,\n        bottomSpec = bottomSpec ?? MarginSpec.defaultSpec;\n}\n\n/// Specs that applies to one margin.\nclass MarginSpec {\n  /// [MarginSpec] that has max of 50 percent.\n  static const defaultSpec = MarginSpec._internal(null, null, null, 50);\n\n  final int? _minPixel;\n  final int? _maxPixel;\n  final int? _minPercent;\n  final int? _maxPercent;\n\n  const MarginSpec._internal(\n      int? minPixel, int? maxPixel, int? minPercent, int? maxPercent)\n      : _minPixel = minPixel,\n        _maxPixel = maxPixel,\n        _minPercent = minPercent,\n        _maxPercent = maxPercent;\n\n  /// Create [MarginSpec] that specifies min/max pixels.\n  ///\n  /// [minPixel] if set must be greater than or equal to 0 and less than max if\n  /// it is also set.\n  /// [maxPixel] if set must be greater than or equal to 0.\n  factory MarginSpec.fromPixel({int? minPixel, int? maxPixel}) {\n    // Require zero or higher settings if set\n    assert(minPixel == null || minPixel >= 0);\n    assert(maxPixel == null || maxPixel >= 0);\n    // Min must be less than or equal to max.\n    // Can be equal to enforce strict pixel size.\n    if (minPixel != null && maxPixel != null) {\n      assert(minPixel <= maxPixel);\n    }\n\n    return MarginSpec._internal(minPixel, maxPixel, null, null);\n  }\n\n  /// Create [MarginSpec] with a fixed pixel size [pixels].\n  ///\n  /// [pixels] if set must be greater than or equal to 0.\n  factory MarginSpec.fixedPixel(int? pixels) {\n    // Require require or higher setting if set\n    assert(pixels == null || pixels >= 0);\n\n    return MarginSpec._internal(pixels, pixels, null, null);\n  }\n\n  /// Create [MarginSpec] that specifies min/max percentage.\n  ///\n  /// [minPercent] if set must be between 0 and 100 inclusive. If [maxPercent]\n  /// is also set, then must be less than [maxPercent].\n  /// [maxPercent] if set must be between 0 and 100 inclusive.\n  factory MarginSpec.fromPercent({int? minPercent, int? maxPercent}) {\n    // Percent must be within 0 to 100\n    assert(minPercent == null || (minPercent >= 0 && minPercent <= 100));\n    assert(maxPercent == null || (maxPercent >= 0 && maxPercent <= 100));\n    // Min must be less than or equal to max.\n    // Can be equal to enforce strict percentage.\n    if (minPercent != null && maxPercent != null) {\n      assert(minPercent <= maxPercent);\n    }\n\n    return MarginSpec._internal(null, null, minPercent, maxPercent);\n  }\n\n  /// Get the min pixels, given the [totalPixels].\n  int getMinPixels(int totalPixels) {\n    final _minPixel = this._minPixel;\n    final _minPercent = this._minPercent;\n    if (_minPixel != null) {\n      assert(_minPixel < totalPixels);\n      return _minPixel;\n    } else if (_minPercent != null) {\n      return (totalPixels * (_minPercent / 100)).round();\n    } else {\n      return 0;\n    }\n  }\n\n  /// Get the max pixels, given the [totalPixels].\n  int getMaxPixels(int totalPixels) {\n    final _maxPixel = this._maxPixel;\n    final _maxPercent = this._maxPercent;\n    if (_maxPixel != null) {\n      assert(_maxPixel < totalPixels);\n      return _maxPixel;\n    } else if (_maxPercent != null) {\n      return (totalPixels * (_maxPercent / 100)).round();\n    } else {\n      return totalPixels;\n    }\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/layout/layout_manager.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math' show Point, Rectangle;\n\nimport '../layout/layout_config.dart' show LayoutConfig;\nimport 'layout_view.dart' show LayoutView;\n\nabstract class LayoutManager {\n  /// Adds a view to be managed by the LayoutManager.\n  void addView(LayoutView view);\n\n  /// Removes a view previously added to the LayoutManager.\n  /// No-op if it wasn't there to begin with.\n  void removeView(LayoutView view);\n\n  /// Returns true if view is already attached.\n  bool isAttached(LayoutView view);\n\n  /// Walk through the child views and determine their desired sizes storing\n  /// off the information for layout.\n  void measure(int width, int height);\n\n  /// Walk through the child views and set their bounds from the perspective\n  /// of the canvas origin.\n  void layout(int width, int height);\n\n  /// Updates the layout configuration.\n  void updateConfig(LayoutConfig layoutConfig);\n\n  /// Returns the bounds of the drawArea. Must be called after layout().\n  Rectangle<int> get drawAreaBounds;\n\n  /// Returns the combined bounds of the drawArea, and all components that\n  /// function as series draw areas. Must be called after layout().\n  Rectangle<int> get drawableLayoutAreaBounds;\n\n  /// Gets the measured size of the bottom margin, available after layout.\n  int get marginBottom;\n\n  /// Gets the measured size of the left margin, available after layout.\n  int get marginLeft;\n\n  /// Gets the measured size of the right margin, available after layout.\n  int get marginRight;\n\n  /// Gets the measured size of the top margin, available after layout.\n  int get marginTop;\n\n  /// Returns whether or not [point] is within the draw area bounds.\n  bool withinDrawArea(Point<num> point);\n\n  /// Walk through the child views and apply the function passed in.\n  void applyToViews(void Function(LayoutView view) apply);\n\n  /// Return the child views in the order that they should be drawn.\n  List<LayoutView> get paintOrderedViews;\n\n  /// Return the child views in the order that they should be positioned within\n  /// chart margins.\n  List<LayoutView> get positionOrderedViews;\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/layout/layout_manager_impl.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math' show Point, Rectangle, max;\n\nimport 'layout_config.dart' show LayoutConfig;\nimport 'layout_manager.dart';\nimport 'layout_margin_strategy.dart';\nimport 'layout_view.dart' show LayoutView, LayoutPosition;\n\n/// Default Layout manager for [LayoutView]s.\nclass LayoutManagerImpl implements LayoutManager {\n  static const _minDrawWidth = 20;\n  static const _minDrawHeight = 20;\n\n  // Allow [Layoutconfig] to be mutable so it can be modified without requiring\n  // a new copy of [DefaultLayoutManager] to be created.\n  LayoutConfig config;\n\n  /// Unordered list of views in the layout.\n  final _views = <LayoutView>[];\n\n  /// List of views in the order they should be drawn on the canvas.\n  ///\n  /// First element is painted first.\n  late List<LayoutView> _paintOrderedViews;\n\n  /// List of vies in the order they should be positioned in a chart margin.\n  ///\n  /// First element is closest to the draw area.\n  late List<LayoutView> _positionOrderedViews;\n\n  late _MeasuredSizes _measurements;\n\n  late Rectangle<int> _drawAreaBounds;\n  bool _drawAreaBoundsOutdated = true;\n  bool _viewsNeedPaintSort = true;\n  bool _viewsNeedPositionSort = true;\n\n  /// Create a new [LayoutManager].\n  LayoutManagerImpl({LayoutConfig? config}) : config = config ?? LayoutConfig();\n\n  /// Add one [LayoutView].\n  @override\n  void addView(LayoutView view) {\n    _views.add(view);\n    _drawAreaBoundsOutdated = true;\n    _viewsNeedPositionSort = true;\n    _viewsNeedPaintSort = true;\n  }\n\n  /// Remove one [LayoutView].\n  @override\n  void removeView(LayoutView view) {\n    if (_views.remove(view)) {\n      _drawAreaBoundsOutdated = true;\n      _viewsNeedPositionSort = true;\n      _viewsNeedPaintSort = true;\n    }\n  }\n\n  /// Returns true if [view] is already attached.\n  @override\n  bool isAttached(LayoutView view) => _views.contains(view);\n\n  @override\n  void updateConfig(LayoutConfig layoutConfig) {\n    config = layoutConfig;\n  }\n\n  /// Get all layout components in the order to be drawn.\n  @override\n  List<LayoutView> get paintOrderedViews {\n    if (_viewsNeedPaintSort) {\n      _paintOrderedViews = List.of(_views);\n\n      _paintOrderedViews.sort((LayoutView v1, LayoutView v2) =>\n          v1.layoutConfig.paintOrder!.compareTo(v2.layoutConfig.paintOrder!));\n\n      _viewsNeedPaintSort = false;\n    }\n    return _paintOrderedViews;\n  }\n\n  /// Get all layout components in the order to be visited.\n  @override\n  List<LayoutView> get positionOrderedViews {\n    if (_viewsNeedPositionSort) {\n      _positionOrderedViews = List.of(_views);\n\n      _positionOrderedViews.sort((LayoutView v1, LayoutView v2) => v1\n          .layoutConfig.positionOrder!\n          .compareTo(v2.layoutConfig.positionOrder!));\n\n      _viewsNeedPositionSort = false;\n    }\n    return _positionOrderedViews;\n  }\n\n  @override\n  Rectangle<int> get drawAreaBounds {\n    assert(_drawAreaBoundsOutdated == false);\n    return _drawAreaBounds;\n  }\n\n  @override\n  Rectangle<int> get drawableLayoutAreaBounds {\n    assert(_drawAreaBoundsOutdated == false);\n\n    final drawableViews =\n        _views.where((LayoutView view) => view.isSeriesRenderer);\n\n    var componentBounds = drawableViews.first.componentBounds;\n\n    if (componentBounds != null) {\n      for (final view in drawableViews.skip(1)) {\n        if (view.componentBounds != null) {\n          // See https://github.com/dart-lang/language/issues/1308 for why\n          // `componentBounds` isn't promoted to be non-nullable.\n          componentBounds = componentBounds!.boundingBox(view.componentBounds!);\n        }\n      }\n    } else {\n      componentBounds = Rectangle(0, 0, 0, 0);\n    }\n\n    return componentBounds!;\n  }\n\n  @override\n  int get marginBottom {\n    assert(_drawAreaBoundsOutdated == false);\n    return _measurements.bottomHeight;\n  }\n\n  @override\n  int get marginLeft {\n    assert(_drawAreaBoundsOutdated == false);\n    return _measurements.leftWidth;\n  }\n\n  @override\n  int get marginRight {\n    assert(_drawAreaBoundsOutdated == false);\n    return _measurements.rightWidth;\n  }\n\n  @override\n  int get marginTop {\n    assert(_drawAreaBoundsOutdated == false);\n    return _measurements.topHeight;\n  }\n\n  @override\n  bool withinDrawArea(Point<num> point) {\n    return _drawAreaBounds.containsPoint(point);\n  }\n\n  /// Measure and layout with given [width] and [height].\n  @override\n  void measure(int width, int height) {\n    var topViews =\n        _viewsForPositions(LayoutPosition.Top, LayoutPosition.FullTop);\n    var rightViews =\n        _viewsForPositions(LayoutPosition.Right, LayoutPosition.FullRight);\n    var bottomViews =\n        _viewsForPositions(LayoutPosition.Bottom, LayoutPosition.FullBottom);\n    var leftViews =\n        _viewsForPositions(LayoutPosition.Left, LayoutPosition.FullLeft);\n\n    // Assume the full width and height of the chart is available when measuring\n    // for the first time but adjust the maximum if margin spec is set.\n    var measurements = _measure(width, height,\n        topViews: topViews,\n        rightViews: rightViews,\n        bottomViews: bottomViews,\n        leftViews: leftViews,\n        useMax: true);\n\n    // Measure a second time but pass in the preferred width and height from\n    // the first measure cycle.\n    // Allow views to report a different size than the previously measured max.\n    final secondMeasurements = _measure(width, height,\n        topViews: topViews,\n        rightViews: rightViews,\n        bottomViews: bottomViews,\n        leftViews: leftViews,\n        previousMeasurements: measurements,\n        useMax: true);\n\n    // If views need more space with the 2nd pass, perform a third pass.\n    if (measurements.leftWidth != secondMeasurements.leftWidth ||\n        measurements.rightWidth != secondMeasurements.rightWidth ||\n        measurements.topHeight != secondMeasurements.topHeight ||\n        measurements.bottomHeight != secondMeasurements.bottomHeight) {\n      final thirdMeasurements = _measure(width, height,\n          topViews: topViews,\n          rightViews: rightViews,\n          bottomViews: bottomViews,\n          leftViews: leftViews,\n          previousMeasurements: secondMeasurements,\n          useMax: false);\n\n      measurements = thirdMeasurements;\n    } else {\n      measurements = secondMeasurements;\n    }\n\n    _measurements = measurements;\n\n    // Draw area size.\n    // Set to a minimum size if there is not enough space for the draw area.\n    // Prevents the app from crashing by rendering overlapping content instead.\n    final drawAreaWidth = max(\n      _minDrawWidth,\n      width - measurements.leftWidth - measurements.rightWidth,\n    );\n    final drawAreaHeight = max(\n      _minDrawHeight,\n      height - measurements.bottomHeight - measurements.topHeight,\n    );\n\n    // Bounds for the draw area.\n    _drawAreaBounds = Rectangle(measurements.leftWidth, measurements.topHeight,\n        drawAreaWidth, drawAreaHeight);\n    _drawAreaBoundsOutdated = false;\n  }\n\n  @override\n  void layout(int width, int height) {\n    var topViews =\n        _viewsForPositions(LayoutPosition.Top, LayoutPosition.FullTop);\n    var rightViews =\n        _viewsForPositions(LayoutPosition.Right, LayoutPosition.FullRight);\n    var bottomViews =\n        _viewsForPositions(LayoutPosition.Bottom, LayoutPosition.FullBottom);\n    var leftViews =\n        _viewsForPositions(LayoutPosition.Left, LayoutPosition.FullLeft);\n    var drawAreaViews = _viewsForPositions(LayoutPosition.DrawArea);\n\n    final fullBounds = Rectangle(0, 0, width, height);\n\n    // Layout the margins.\n    LeftMarginLayoutStrategy()\n        .layout(leftViews, _measurements.leftSizes, fullBounds, drawAreaBounds);\n    RightMarginLayoutStrategy().layout(\n        rightViews, _measurements.rightSizes, fullBounds, drawAreaBounds);\n    BottomMarginLayoutStrategy().layout(\n        bottomViews, _measurements.bottomSizes, fullBounds, drawAreaBounds);\n    TopMarginLayoutStrategy()\n        .layout(topViews, _measurements.topSizes, fullBounds, drawAreaBounds);\n\n    // Layout the drawArea.\n    drawAreaViews.forEach(\n        (LayoutView view) => view.layout(_drawAreaBounds, _drawAreaBounds));\n  }\n\n  Iterable<LayoutView> _viewsForPositions(LayoutPosition p1,\n      [LayoutPosition? p2]) {\n    return positionOrderedViews.where((LayoutView view) =>\n        view.layoutConfig.position == p1 ||\n        (p2 != null && view.layoutConfig.position == p2));\n  }\n\n  /// Measure and return size measurements.\n  /// [width] full width of chart\n  /// [height] full height of chart\n  _MeasuredSizes _measure(\n    int width,\n    int height, {\n    required Iterable<LayoutView> topViews,\n    required Iterable<LayoutView> rightViews,\n    required Iterable<LayoutView> bottomViews,\n    required Iterable<LayoutView> leftViews,\n    _MeasuredSizes? previousMeasurements,\n    required bool useMax,\n  }) {\n    final maxLeftWidth = config.leftSpec.getMaxPixels(width);\n    final maxRightWidth = config.rightSpec.getMaxPixels(width);\n    final maxBottomHeight = config.bottomSpec.getMaxPixels(height);\n    final maxTopHeight = config.topSpec.getMaxPixels(height);\n\n    // Assume the full width and height of the chart is available when measuring\n    // for the first time but adjust the maximum if margin spec is set.\n    var leftWidth = previousMeasurements?.leftWidth ?? maxLeftWidth;\n    var rightWidth = previousMeasurements?.rightWidth ?? maxRightWidth;\n    var bottomHeight = previousMeasurements?.bottomHeight ?? maxBottomHeight;\n    var topHeight = previousMeasurements?.topHeight ?? maxTopHeight;\n\n    // Only adjust the height if we have previous measurements.\n    final adjustedHeight = (previousMeasurements != null)\n        ? height - bottomHeight - topHeight\n        : height;\n\n    var leftSizes = LeftMarginLayoutStrategy().measure(leftViews,\n        maxWidth: useMax ? maxLeftWidth : leftWidth,\n        height: adjustedHeight,\n        fullHeight: height);\n\n    leftWidth = max(leftSizes.total, config.leftSpec.getMinPixels(width));\n\n    var rightSizes = RightMarginLayoutStrategy().measure(rightViews,\n        maxWidth: useMax ? maxRightWidth : rightWidth,\n        height: adjustedHeight,\n        fullHeight: height);\n    rightWidth = max(rightSizes.total, config.rightSpec.getMinPixels(width));\n\n    final adjustedWidth = width - leftWidth - rightWidth;\n\n    var bottomSizes = BottomMarginLayoutStrategy().measure(bottomViews,\n        maxHeight: useMax ? maxBottomHeight : bottomHeight,\n        width: adjustedWidth,\n        fullWidth: width);\n    bottomHeight =\n        max(bottomSizes.total, config.bottomSpec.getMinPixels(height));\n\n    var topSizes = TopMarginLayoutStrategy().measure(topViews,\n        maxHeight: useMax ? maxTopHeight : topHeight,\n        width: adjustedWidth,\n        fullWidth: width);\n    topHeight = max(topSizes.total, config.topSpec.getMinPixels(height));\n\n    return _MeasuredSizes(\n        leftWidth: leftWidth,\n        leftSizes: leftSizes,\n        rightWidth: rightWidth,\n        rightSizes: rightSizes,\n        topHeight: topHeight,\n        topSizes: topSizes,\n        bottomHeight: bottomHeight,\n        bottomSizes: bottomSizes);\n  }\n\n  @override\n  void applyToViews(void Function(LayoutView view) apply) {\n    _views.forEach(apply);\n  }\n}\n\n/// Helper class that stores measured width and height during measure cycles.\nclass _MeasuredSizes {\n  final int leftWidth;\n  final SizeList leftSizes;\n\n  final int rightWidth;\n  final SizeList rightSizes;\n\n  final int topHeight;\n  final SizeList topSizes;\n\n  final int bottomHeight;\n  final SizeList bottomSizes;\n\n  _MeasuredSizes({\n    required this.leftWidth,\n    required this.leftSizes,\n    required this.rightWidth,\n    required this.rightSizes,\n    required this.topHeight,\n    required this.topSizes,\n    required this.bottomHeight,\n    required this.bottomSizes,\n  });\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/layout/layout_margin_strategy.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math' show Rectangle;\nimport 'layout_view.dart';\n\nclass SizeList {\n  final _sizes = <int>[];\n  int _total = 0;\n\n  int operator [](int i) => _sizes[i];\n\n  int get total => _total;\n\n  int get length => _sizes.length;\n\n  void add(int size) {\n    _sizes.add(size);\n    _total += size;\n  }\n\n  void adjust(int index, int amount) {\n    _sizes[index] += amount;\n    _total += amount;\n  }\n}\n\nclass _DesiredViewSizes {\n  final preferredSizes = SizeList();\n  final minimumSizes = SizeList();\n\n  void add(int preferred, int minimum) {\n    preferredSizes.add(preferred);\n    minimumSizes.add(minimum);\n  }\n\n  void adjustedTo(int maxSize) {\n    if (maxSize < preferredSizes.total) {\n      var delta = preferredSizes.total - maxSize;\n      for (var i = preferredSizes.length - 1; i >= 0; i--) {\n        final viewAvailablePx = preferredSizes[i] - minimumSizes[i];\n\n        if (viewAvailablePx < delta) {\n          // We need even more than this one view can give up, so assign the\n          // minimum to the view and adjust totals.\n          preferredSizes.adjust(i, -viewAvailablePx);\n          delta -= viewAvailablePx;\n        } else {\n          // We can adjust this view to account for the delta.\n          preferredSizes.adjust(i, -delta);\n          return;\n        }\n      }\n    }\n  }\n}\n\n/// A strategy for calculating size of vertical margins (RIGHT & LEFT).\nabstract class VerticalMarginStrategy {\n  SizeList measure(Iterable<LayoutView> views,\n      {required int maxWidth, required int height, required int fullHeight}) {\n    final measuredWidths = _DesiredViewSizes();\n    var remainingWidth = maxWidth;\n\n    views.forEach((LayoutView view) {\n      final params = view.layoutConfig;\n      final viewMargin = params.viewMargin;\n\n      final availableHeight =\n          (params.isFullPosition ? fullHeight : height) - viewMargin.height;\n\n      // Measure with all available space, minus the buffer.\n      remainingWidth = remainingWidth - viewMargin.width;\n      maxWidth -= viewMargin.width;\n\n      var size = ViewMeasuredSizes.zero;\n      // Don't ask component to measure if both measurements are 0.\n      //\n      // Measure still needs to be called even when one dimension has a size of\n      // zero because if the component is an axis, the axis needs to still\n      // recalculate ticks even if it is not to be shown.\n      if (remainingWidth > 0 || availableHeight > 0) {\n        size = view.measure(remainingWidth, availableHeight)!;\n        remainingWidth -= size.preferredWidth;\n      }\n\n      measuredWidths.add(size.preferredWidth, size.minWidth);\n    });\n\n    measuredWidths.adjustedTo(maxWidth);\n    return measuredWidths.preferredSizes;\n  }\n\n  void layout(List<LayoutView> views, SizeList measuredSizes,\n      Rectangle<int> fullBounds, Rectangle<int> drawAreaBounds);\n}\n\n/// A strategy for calculating size and bounds of left margins.\nclass LeftMarginLayoutStrategy extends VerticalMarginStrategy {\n  @override\n  void layout(Iterable<LayoutView> views, SizeList measuredSizes,\n      Rectangle<int> fullBounds, Rectangle<int> drawAreaBounds) {\n    var prevBoundsRight = drawAreaBounds.left;\n\n    var i = 0;\n    views.forEach((LayoutView view) {\n      final params = view.layoutConfig;\n\n      final width = measuredSizes[i];\n      final left = prevBoundsRight - params.viewMargin.rightPx - width;\n      final height =\n          (params.isFullPosition ? fullBounds.height : drawAreaBounds.height) -\n              params.viewMargin.height;\n      final top = params.viewMargin.topPx +\n          (params.isFullPosition ? fullBounds.top : drawAreaBounds.top);\n\n      // Update the remaining bounds.\n      prevBoundsRight = left - params.viewMargin.leftPx;\n\n      // Layout this component.\n      view.layout(Rectangle(left, top, width, height), drawAreaBounds);\n\n      i++;\n    });\n  }\n}\n\n/// A strategy for calculating size and bounds of right margins.\nclass RightMarginLayoutStrategy extends VerticalMarginStrategy {\n  @override\n  void layout(Iterable<LayoutView> views, SizeList measuredSizes,\n      Rectangle<int> fullBounds, Rectangle<int> drawAreaBounds) {\n    var prevBoundsLeft = drawAreaBounds.right;\n\n    var i = 0;\n    views.forEach((view) {\n      final params = view.layoutConfig;\n\n      final width = measuredSizes[i];\n      final left = prevBoundsLeft + params.viewMargin.leftPx;\n      final height =\n          (params.isFullPosition ? fullBounds.height : drawAreaBounds.height) -\n              params.viewMargin.height;\n      final top = params.viewMargin.topPx +\n          (params.isFullPosition ? fullBounds.top : drawAreaBounds.top);\n\n      // Update the remaining bounds.\n      prevBoundsLeft = left + width + params.viewMargin.rightPx;\n\n      // Layout this component.\n      view.layout(Rectangle(left, top, width, height), drawAreaBounds);\n\n      i++;\n    });\n  }\n}\n\n/// A strategy for calculating size of horizontal margins (TOP & BOTTOM).\nabstract class HorizontalMarginStrategy {\n  SizeList measure(Iterable<LayoutView> views,\n      {required int maxHeight, required int width, required int fullWidth}) {\n    final measuredHeights = _DesiredViewSizes();\n    var remainingHeight = maxHeight;\n\n    views.forEach((LayoutView view) {\n      final params = view.layoutConfig;\n      final viewMargin = params.viewMargin;\n\n      final availableWidth =\n          (params.isFullPosition ? fullWidth : width) - viewMargin.width;\n\n      // Measure with all available space, minus the buffer.\n      remainingHeight = remainingHeight - viewMargin.height;\n      maxHeight -= viewMargin.height;\n\n      var size = ViewMeasuredSizes.zero;\n      // Don't ask component to measure if both measurements are 0.\n      //\n      // Measure still needs to be called even when one dimension has a size of\n      // zero because if the component is an axis, the axis needs to still\n      // recalculate ticks even if it is not to be shown.\n      if (remainingHeight > 0 || availableWidth > 0) {\n        size = view.measure(availableWidth, remainingHeight)!;\n        remainingHeight -= size.preferredHeight;\n      }\n\n      measuredHeights.add(size.preferredHeight, size.minHeight);\n    });\n\n    measuredHeights.adjustedTo(maxHeight);\n    return measuredHeights.preferredSizes;\n  }\n\n  void layout(Iterable<LayoutView> views, SizeList measuredSizes,\n      Rectangle<int> fullBounds, Rectangle<int> drawAreaBounds);\n}\n\n/// A strategy for calculating size and bounds of top margins.\nclass TopMarginLayoutStrategy extends HorizontalMarginStrategy {\n  @override\n  void layout(Iterable<LayoutView> views, SizeList measuredSizes,\n      Rectangle<int> fullBounds, Rectangle<int> drawAreaBounds) {\n    var prevBoundsBottom = drawAreaBounds.top;\n\n    var i = 0;\n    views.forEach((LayoutView view) {\n      final params = view.layoutConfig;\n\n      final height = measuredSizes[i];\n      final top = prevBoundsBottom - height - params.viewMargin.bottomPx;\n\n      final width =\n          (params.isFullPosition ? fullBounds.width : drawAreaBounds.width) -\n              params.viewMargin.width;\n      final left = params.viewMargin.leftPx +\n          (params.isFullPosition ? fullBounds.left : drawAreaBounds.left);\n\n      // Update the remaining bounds.\n      prevBoundsBottom = top - params.viewMargin.topPx;\n\n      // Layout this component.\n      view.layout(Rectangle(left, top, width, height), drawAreaBounds);\n\n      i++;\n    });\n  }\n}\n\n/// A strategy for calculating size and bounds of bottom margins.\nclass BottomMarginLayoutStrategy extends HorizontalMarginStrategy {\n  @override\n  void layout(Iterable<LayoutView> views, SizeList measuredSizes,\n      Rectangle<int> fullBounds, Rectangle<int> drawAreaBounds) {\n    var prevBoundsTop = drawAreaBounds.bottom;\n\n    var i = 0;\n    views.forEach((view) {\n      final params = view.layoutConfig;\n\n      final height = measuredSizes[i];\n      final top = prevBoundsTop + params.viewMargin.topPx;\n\n      final width =\n          (params.isFullPosition ? fullBounds.width : drawAreaBounds.width) -\n              params.viewMargin.width;\n      final left = params.viewMargin.leftPx +\n          (params.isFullPosition ? fullBounds.left : drawAreaBounds.left);\n\n      // Update the remaining bounds.\n      prevBoundsTop = top + height + params.viewMargin.bottomPx;\n\n      // Layout this component.\n      view.layout(Rectangle(left, top, width, height), drawAreaBounds);\n\n      i++;\n    });\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/layout/layout_view.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math' show Rectangle;\n\nimport '../common/behavior/chart_behavior.dart'\n    show BehaviorPosition, OutsideJustification;\nimport '../../common/graphics_factory.dart' show GraphicsFactory;\nimport '../common/chart_canvas.dart' show ChartCanvas;\n\n/// Position of a [LayoutView].\nenum LayoutPosition {\n  Bottom,\n  FullBottom,\n\n  Top,\n  FullTop,\n\n  Left,\n  FullLeft,\n\n  Right,\n  FullRight,\n\n  DrawArea,\n}\n\n/// Standard layout paint orders for all internal components.\n///\n/// Custom component layers should define their paintOrder by taking the nearest\n/// layer from this list, and adding or subtracting 1. This will help reduce the\n/// chance of custom behaviors, renderers, etc. from breaking if we need to\n/// re-order these components internally.\nclass LayoutViewPaintOrder {\n  // Draw range annotations beneath axis grid lines.\n  static const rangeAnnotation = -10;\n  // Axis elements form the \"base layer\" of all components on the chart. Domain\n  // axes are drawn on top of measure axes to ensure that the domain axis line\n  // appears on top of any measure axis grid lines.\n  static const measureAxis = 0;\n  static const domainAxis = 5;\n  // Draw series data on top of axis elements.\n  static const arc = 10;\n  static const bar = 10;\n  static const treeMap = 10;\n  static const barTargetLine = 15;\n  static const line = 20;\n  static const point = 25;\n  // Draw most behaviors on top of series data.\n  static const legend = 100;\n  static const linePointHighlighter = 110;\n  static const slider = 150;\n  static const chartTitle = 160;\n}\n\n/// Standard layout position orders for all internal components.\n///\n/// Custom component layers should define their positionOrder by taking the\n/// nearest component from this list, and adding or subtracting 1. This will\n/// help reduce the chance of custom behaviors, renderers, etc. from breaking if\n/// we need to re-order these components internally.\nclass LayoutViewPositionOrder {\n  static const drawArea = 0;\n  static const symbolAnnotation = 10;\n  static const axis = 20;\n  static const legend = 30;\n  static const chartTitle = 40;\n}\n\n/// A configuration for margin (empty space) around a layout child view.\nclass ViewMargin {\n  /// A [ViewMargin] with all zero px.\n  static const empty = ViewMargin(topPx: 0, bottomPx: 0, rightPx: 0, leftPx: 0);\n\n  final int topPx;\n  final int bottomPx;\n  final int rightPx;\n  final int leftPx;\n\n  const ViewMargin({int? topPx, int? bottomPx, int? rightPx, int? leftPx})\n      : topPx = topPx ?? 0,\n        bottomPx = bottomPx ?? 0,\n        rightPx = rightPx ?? 0,\n        leftPx = leftPx ?? 0;\n\n  /// Total width.\n  int get width => leftPx + rightPx;\n\n  /// Total height.\n  int get height => topPx + bottomPx;\n}\n\n/// Configuration of a [LayoutView].\nclass LayoutViewConfig {\n  /// Unique identifier for the [LayoutView].\n  String? id;\n\n  /// The order to paint a [LayoutView] on the canvas.\n  ///\n  /// The smaller number is drawn first.\n  int? paintOrder;\n\n  /// The position of a [LayoutView] defining where to place the view.\n  LayoutPosition? position;\n\n  /// The order to place the [LayoutView] within a chart margin.\n  ///\n  /// The smaller number is closer to the draw area. Elements positioned closer\n  /// to the draw area will be given extra layout space first, before those\n  /// further away.\n  ///\n  /// Note that all views positioned in the draw area are given the entire draw\n  /// area bounds as their component bounds.\n  int? positionOrder;\n\n  /// Defines the space around a layout component.\n  ViewMargin viewMargin;\n\n  /// Creates new [LayoutParams].\n  ///\n  /// [paintOrder] the order that this component will be drawn.\n  /// [position] the [ComponentPosition] of this component.\n  /// [positionOrder] the order of this component in a chart margin.\n  LayoutViewConfig({\n    this.paintOrder,\n    this.position,\n    this.positionOrder,\n    ViewMargin? viewMargin,\n  }) : viewMargin = viewMargin ?? ViewMargin.empty;\n\n  /// Returns true if it is a full position.\n  bool get isFullPosition =>\n      position == LayoutPosition.FullBottom ||\n      position == LayoutPosition.FullTop ||\n      position == LayoutPosition.FullRight ||\n      position == LayoutPosition.FullLeft;\n}\n\n/// Size measurements of one component.\n///\n/// The measurement is tight to the component, without adding [ComponentBuffer].\nclass ViewMeasuredSizes {\n  /// All zeroes component size.\n  static const zero = ViewMeasuredSizes(\n      preferredWidth: 0, preferredHeight: 0, minWidth: 0, minHeight: 0);\n\n  final int preferredWidth;\n  final int preferredHeight;\n  final int minWidth;\n  final int minHeight;\n\n  /// Create a new [ViewSizes].\n  ///\n  /// [preferredWidth] the component's preferred width.\n  /// [preferredHeight] the component's preferred width.\n  /// [minWidth] the component's minimum width. If not set, default to 0.\n  /// [minHeight] the component's minimum height. If not set, default to 0.\n  const ViewMeasuredSizes(\n      {required this.preferredWidth,\n      required this.preferredHeight,\n      int? minWidth,\n      int? minHeight})\n      : minWidth = minWidth ?? 0,\n        minHeight = minHeight ?? 0;\n}\n\n/// A component that measures its size and accepts bounds to complete layout.\nabstract class LayoutView {\n  GraphicsFactory? get graphicsFactory;\n\n  set graphicsFactory(GraphicsFactory? value);\n\n  /// Layout params for this component.\n  LayoutViewConfig get layoutConfig;\n\n  /// Measure and return the size of this component.\n  ///\n  /// This measurement is without the [ComponentBuffer], which is added by the\n  /// layout manager.\n  ViewMeasuredSizes? measure(int maxWidth, int maxHeight);\n\n  /// Layout this component.\n  void layout(Rectangle<int> componentBounds, Rectangle<int> drawAreaBounds);\n\n  /// Draw this component on the canvas.\n  void paint(ChartCanvas canvas, double animationPercent);\n\n  /// Bounding box for drawing this component.\n  Rectangle<int>? get componentBounds;\n\n  /// Whether or not this component is a series renderer that draws series\n  /// data.\n  ///\n  /// This component may either render into the chart's draw area, or into a\n  /// separate area bounded by the component bounds.\n  bool get isSeriesRenderer;\n}\n\n/// Translates a component's [BehaviorPosition] and [OutsideJustification] into\n/// a [LayoutPosition] that a [LayoutManager] can use to place components on the\n/// chart.\nLayoutPosition layoutPosition(BehaviorPosition behaviorPosition,\n    OutsideJustification outsideJustification, bool isRtl) {\n  LayoutPosition position;\n  switch (behaviorPosition) {\n    case BehaviorPosition.bottom:\n      position = LayoutPosition.Bottom;\n      break;\n    case BehaviorPosition.end:\n      position = isRtl ? LayoutPosition.Left : LayoutPosition.Right;\n      break;\n    case BehaviorPosition.inside:\n      position = LayoutPosition.DrawArea;\n      break;\n    case BehaviorPosition.start:\n      position = isRtl ? LayoutPosition.Right : LayoutPosition.Left;\n      break;\n    case BehaviorPosition.top:\n      position = LayoutPosition.Top;\n      break;\n  }\n\n  // If we have a \"full\" [OutsideJustification], convert the layout position\n  // to the \"full\" form.\n  if (outsideJustification == OutsideJustification.start ||\n      outsideJustification == OutsideJustification.middle ||\n      outsideJustification == OutsideJustification.end) {\n    switch (position) {\n      case LayoutPosition.Bottom:\n        position = LayoutPosition.FullBottom;\n        break;\n      case LayoutPosition.Left:\n        position = LayoutPosition.FullLeft;\n        break;\n      case LayoutPosition.Top:\n        position = LayoutPosition.FullTop;\n        break;\n      case LayoutPosition.Right:\n        position = LayoutPosition.FullRight;\n        break;\n\n      // Ignore other positions, like DrawArea.\n      default:\n        break;\n    }\n  }\n\n  return position;\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/line/line_chart.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:collection' show LinkedHashMap;\n\nimport '../cartesian/axis/axis.dart' show NumericAxis;\nimport '../cartesian/cartesian_chart.dart' show NumericCartesianChart;\nimport '../common/series_renderer.dart' show SeriesRenderer;\nimport '../layout/layout_config.dart' show LayoutConfig;\nimport '../line/line_renderer.dart' show LineRenderer;\n\nclass LineChart extends NumericCartesianChart {\n  LineChart(\n      {bool? vertical,\n      LayoutConfig? layoutConfig,\n      NumericAxis? primaryMeasureAxis,\n      NumericAxis? secondaryMeasureAxis,\n      LinkedHashMap<String, NumericAxis>? disjointMeasureAxes})\n      : super(\n            vertical: vertical,\n            layoutConfig: layoutConfig,\n            primaryMeasureAxis: primaryMeasureAxis,\n            secondaryMeasureAxis: secondaryMeasureAxis,\n            disjointMeasureAxes: disjointMeasureAxes);\n\n  @override\n  SeriesRenderer<num> makeDefaultRenderer() {\n    return LineRenderer<num>()..rendererId = SeriesRenderer.defaultRendererId;\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/line/line_renderer.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:collection' show LinkedHashMap;\nimport 'dart:math' show Rectangle, Point;\n\nimport 'package:collection/collection.dart' show IterableExtension;\nimport 'package:meta/meta.dart' show visibleForTesting;\n\nimport '../../common/color.dart' show Color;\nimport '../../common/math.dart';\nimport '../../data/series.dart' show AttributeKey, AccessorFn;\nimport '../cartesian/axis/axis.dart'\n    show ImmutableAxis, OrdinalAxis, domainAxisKey, measureAxisKey;\nimport '../cartesian/cartesian_renderer.dart' show BaseCartesianRenderer;\nimport '../common/base_chart.dart' show BaseChart;\nimport '../common/chart_canvas.dart' show ChartCanvas, getAnimatedColor;\nimport '../common/datum_details.dart' show DatumDetails;\nimport '../common/processed_series.dart' show ImmutableSeries, MutableSeries;\nimport '../common/series_datum.dart' show SeriesDatum;\nimport '../scatter_plot/point_renderer.dart' show PointRenderer;\nimport '../scatter_plot/point_renderer_config.dart' show PointRendererConfig;\nimport 'line_renderer_config.dart' show LineRendererConfig;\n\nconst styleSegmentsKey = AttributeKey<List<_LineRendererElement<Object>>>(\n    'LineRenderer.styleSegments');\n\nconst lineStackIndexKey = AttributeKey<int>('LineRenderer.lineStackIndex');\n\nclass LineRenderer<D> extends BaseCartesianRenderer<D> {\n  // Configuration used to extend the clipping area to extend the draw bounds.\n  static const drawBoundTopExtensionPx = 5;\n  static const drawBoundBottomExtensionPx = 5;\n\n  final LineRendererConfig<D> config;\n\n  late PointRenderer<D> _pointRenderer;\n\n  BaseChart<D>? _chart;\n\n  /// True if any series has a measureUpperBoundFn and measureLowerBoundFn.\n  ///\n  /// Used to enable drawing confidence interval areas segments.\n  late bool _hasMeasureBounds;\n\n  /// Store a map of series drawn on the chart, mapped by series name.\n  ///\n  /// [LinkedHashMap] is used to render the series on the canvas in the same\n  /// order as the data was given to the chart.\n  final _seriesLineMap = <String, List<_AnimatedElements<D>>>{};\n\n  // Store a list of lines that exist in the series data.\n  //\n  // This list will be used to remove any [_AnimatedLine] that were rendered in\n  // previous draw cycles, but no longer have a corresponding datum in the new\n  // data.\n  final _currentKeys = <String>[];\n\n  factory LineRenderer({String? rendererId, LineRendererConfig<D>? config}) {\n    return LineRenderer._internal(\n        rendererId: rendererId ?? 'line',\n        config: config ?? LineRendererConfig<D>());\n  }\n\n  LineRenderer._internal({required String rendererId, required this.config})\n      : _pointRenderer = PointRenderer<D>(\n            config: PointRendererConfig<D>(radiusPx: config.radiusPx)),\n        super(\n            rendererId: rendererId,\n            layoutPaintOrder: config.layoutPaintOrder,\n            symbolRenderer: config.symbolRenderer);\n\n  @override\n  void layout(Rectangle<int> componentBounds, Rectangle<int> drawAreaBounds) {\n    super.layout(componentBounds, drawAreaBounds);\n\n    if (config.includePoints) {\n      _pointRenderer.layout(componentBounds, drawAreaBounds);\n    }\n  }\n\n  @override\n  void configureSeries(List<MutableSeries<D>> seriesList) {\n    assignMissingColors(seriesList, emptyCategoryUsesSinglePalette: false);\n\n    seriesList.forEach((series) {\n      // Add a default area color function which applies the configured\n      // areaOpacity value to the datum's current color.\n      series.areaColorFn ??= (int? index) {\n        final color = series.colorFn?.call(index);\n        if (color == null) {\n          return null;\n        }\n\n        return Color(\n            r: color.r,\n            g: color.g,\n            b: color.b,\n            a: (color.a * config.areaOpacity).round());\n      };\n    });\n\n    if (config.includePoints) {\n      _pointRenderer.configureSeries(seriesList);\n    }\n  }\n\n  @override\n  void preprocessSeries(List<MutableSeries<D>> seriesList) {\n    var stackIndex = 0;\n\n    _hasMeasureBounds = seriesList.any((series) =>\n        series.measureUpperBoundFn != null &&\n        series.measureLowerBoundFn != null);\n\n    seriesList.forEach((MutableSeries<D> series) {\n      final colorFn = series.colorFn;\n      final areaColorFn = series.areaColorFn;\n      final domainFn = series.domainFn;\n      final measureFn = series.measureFn;\n      final strokeWidthPxFn = series.strokeWidthPxFn;\n\n      series.dashPatternFn ??= (_) => config.dashPattern;\n      final dashPatternFn = series.dashPatternFn!;\n\n      final styleSegments = <_LineRendererElement<D>>[];\n      var styleSegmentsIndex = 0;\n\n      final usedKeys = <String>{};\n\n      // Configure style segments for each series.\n      String? previousSegmentKey;\n      _LineRendererElement<D>? currentDetails;\n\n      for (var index = 0; index < series.data.length; index++) {\n        final domain = domainFn(index);\n        final measure = measureFn(index);\n\n        if (domain == null || measure == null) {\n          continue;\n        }\n\n        final color = colorFn!(index);\n        final areaColor = areaColorFn!(index);\n        final dashPattern = dashPatternFn(index);\n        final strokeWidthPx =\n            strokeWidthPxFn?.call(index)?.toDouble() ?? config.strokeWidthPx;\n\n        // Create a style key for this datum, and then compare it to the\n        // previous datum.\n        //\n        // Compare strokeWidthPx to 2 decimals of precision. Any less and you\n        // can't see any difference in the canvas anyways.\n        final strokeWidthPxRounded = (strokeWidthPx * 100).round() / 100;\n        var styleKey = '${series.id}__${styleSegmentsIndex}__${color}'\n            '__${dashPattern}__${strokeWidthPxRounded}';\n\n        if (styleKey != previousSegmentKey) {\n          // If we have a repeated style segment, update the repeat index and\n          // create a new key.\n          // TODO: Paint repeated styles with multiple clip regions.\n          if (usedKeys.isNotEmpty && usedKeys.contains(styleKey)) {\n            styleSegmentsIndex++;\n\n            styleKey = '${series.id}__${styleSegmentsIndex}__${color}'\n                '__${dashPattern}__${strokeWidthPxRounded}';\n          }\n\n          // Make sure that the previous style segment extends to the current\n          // domain value. This will ensure that the style of the line changes\n          // right at the point of the datum that changes the style.\n          if (currentDetails != null) {\n            currentDetails.domainExtent.includePoint(domain);\n          }\n\n          // Create a new style segment.\n          currentDetails = _LineRendererElement<D>(\n            color: color,\n            areaColor: areaColor,\n            dashPattern: dashPattern,\n            domainExtent: _Range<D>(domain, domain),\n            strokeWidthPx: strokeWidthPx,\n            styleKey: styleKey,\n            roundEndCaps: config.roundEndCaps,\n          );\n\n          styleSegments.add(currentDetails);\n          usedKeys.add(styleKey);\n\n          previousSegmentKey = styleKey;\n        } else {\n          // Extend the range of the current segment to include the current\n          // domain value.\n          currentDetails!.domainExtent.includePoint(domain);\n        }\n      }\n\n      series.setAttr(styleSegmentsKey, styleSegments);\n      series.setAttr(lineStackIndexKey, stackIndex);\n\n      if (config.stacked) {\n        stackIndex++;\n      }\n    });\n\n    if (config.includePoints) {\n      _pointRenderer.preprocessSeries(seriesList);\n    }\n\n    // If we are stacking, generate new stacking measure offset functions for\n    // each series. Each datum should have a measure offset consisting of the\n    // sum of the measure and measure offsets of each datum with the same domain\n    // value in series below it in the stack. The first series will be treated\n    // as the bottom of the stack.\n    if (config.stacked && seriesList.isNotEmpty) {\n      var curOffsets = _createInitialOffsetMap(seriesList[0]);\n      var nextOffsets = <D, num>{};\n\n      for (var i = 0; i < seriesList.length; i++) {\n        final series = seriesList[i];\n        final measureOffsetFn = _createStackedMeasureOffsetFunction(\n            series, curOffsets, nextOffsets);\n\n        if (i > 0) {\n          series.measureOffsetFn = measureOffsetFn;\n        }\n\n        curOffsets = nextOffsets;\n        nextOffsets = <D, num>{};\n      }\n    }\n  }\n\n  /// Creates the initial offsets for the series given the measureOffset values.\n  Map<D, num?> _createInitialOffsetMap(MutableSeries<D> series) {\n    final domainFn = series.domainFn;\n    final measureOffsetFn = series.measureOffsetFn!;\n    final initialOffsets = <D, num?>{};\n\n    for (var index = 0; index < series.data.length; index++) {\n      initialOffsets[domainFn(index)] = measureOffsetFn(index);\n    }\n\n    return initialOffsets;\n  }\n\n  /// Function needed to create a closure preserving the previous series\n  /// information. y0 for this series is just y + y0 for previous series as long\n  /// as both y and y0 are not null. If they are null propagate up the\n  /// missing/null data.\n  AccessorFn<num?> _createStackedMeasureOffsetFunction(MutableSeries<D> series,\n      Map<D, num?> curOffsets, Map<D, num> nextOffsets) {\n    final domainFn = series.domainFn;\n    final measureFn = series.measureFn;\n\n    for (var index = 0; index < series.data.length; index++) {\n      final domainValue = domainFn(index);\n      final measure = measureFn(index);\n      final prevOffset = curOffsets[domainValue];\n\n      if (measure != null && prevOffset != null) {\n        nextOffsets[domainValue] = measure + prevOffset;\n      }\n    }\n\n    return (int? i) => curOffsets[domainFn(i)];\n  }\n\n  /// Merge the line map and the new series so that the new elements are mixed\n  /// with the previous ones.\n  ///\n  /// This is to deal with the issue that every new series added after the fact\n  /// would be be rendered on top of the old ones, no matter the order of the\n  /// new series list.\n  void _mergeIntoSeriesMap(List<ImmutableSeries<D>> seriesList) {\n    final newLineMap = <MapEntry<String, List<_AnimatedElements<D>>>>[];\n\n    seriesList.forEach((ImmutableSeries<D> series) {\n      final key = series.id;\n\n      // First, add all the series from the old map that have been removed from\n      // the new seriesList in the same order they appear, stopping at the first\n      // series that is still in the list. We need to maintain them in the same\n      // order animate them out smoothly.\n      var checkNext = true;\n      while (checkNext && _seriesLineMap.isNotEmpty) {\n        final firstKey = _seriesLineMap.keys.first;\n        if (!seriesList.any((s) => s.id == firstKey)) {\n          newLineMap.add(MapEntry(firstKey, _seriesLineMap.remove(firstKey)!));\n          checkNext = true;\n        } else {\n          checkNext = false;\n        }\n      }\n\n      // If it's a new key, we add it and move to the next one. If not, we\n      // remove it from the current list and add it to the new one.\n      if (!_seriesLineMap.containsKey(key)) {\n        newLineMap.add(MapEntry(key, []));\n      } else {\n        newLineMap.add(MapEntry(key, _seriesLineMap.remove(key)!));\n      }\n    });\n\n    // Now whatever is left is stuff that has been removed. We still add it to\n    // the end and removed them as the map is modified in place.\n    newLineMap.addAll(_seriesLineMap.entries);\n    _seriesLineMap.clear();\n\n    _seriesLineMap.addEntries(newLineMap);\n  }\n\n  @override\n  void update(List<ImmutableSeries<D>> seriesList, bool isAnimatingThisDraw) {\n    _currentKeys.clear();\n\n    // List of final points for the previous line in a stack.\n    final previousPointList = <List<_DatumPoint<D>>>[];\n\n    // List of initial points for the previous line in a stack, animated in from\n    // the measure axis.\n    final previousInitialPointList = <List<_DatumPoint<D>>>[];\n\n    _mergeIntoSeriesMap(seriesList);\n\n    seriesList.forEach((ImmutableSeries<D> series) {\n      final domainAxis = series.getAttr(domainAxisKey) as ImmutableAxis<D>;\n      final lineKey = series.id;\n      final stackIndex = series.getAttr(lineStackIndexKey)!;\n\n      previousPointList.add([]);\n      previousInitialPointList.add([]);\n\n      final elementsList = _seriesLineMap[lineKey]!;\n\n      final styleSegments = series.getAttr(styleSegmentsKey)!;\n\n      // Include the end points of the domain axis range in the first and last\n      // style segments to avoid clipping everything when the domain range of\n      // the data is very small. Doing this after [preProcess] handles invalid\n      // data (e.g. null measure) at the ends of the series data.\n      //\n      // TODO: Handle ordinal axes by looking at the next domains.\n      if (styleSegments.isNotEmpty && !(domainAxis is OrdinalAxis)) {\n        final drawBounds = this.drawBounds!;\n        final startPx = (isRtl ? drawBounds.right : drawBounds.left).toDouble();\n        final endPx = (isRtl ? drawBounds.left : drawBounds.right).toDouble();\n\n        final startDomain = domainAxis.getDomain(startPx);\n        final endDomain = domainAxis.getDomain(endPx);\n\n        styleSegments.first.domainExtent.includePoint(startDomain);\n        styleSegments.last.domainExtent.includePoint(endDomain);\n      }\n\n      // Create a set of animated line and area elements for each style segment.\n      //\n      // If the series contains null measure values, then multiple animated line\n      // and area objects will be created to represent the isolated sections of\n      // the series.\n      //\n      // The full set of line and area elements will be rendered on the canvas\n      // for each style segment, with a clip region added in the [paint] process\n      // later to display only the relevant parts of data. This ensures that\n      // styles that visually depend on the start location, such as dash\n      // patterns, are not disrupted by other changes in style.\n      styleSegments.forEach((styleSegment) {\n        final styleKey = styleSegment.styleKey;\n\n        // If we already have an AnimatingPoint for that index, use it.\n        var animatingElements = elementsList\n            .firstWhereOrNull((elements) => elements.styleKey == styleKey);\n\n        if (animatingElements != null) {\n          previousInitialPointList[stackIndex] = animatingElements.allPoints;\n        } else {\n          // Create a new line and have it animate in from axis.\n          final lineAndArea = _createLineAndAreaElements(\n              series,\n              styleSegment as _LineRendererElement<D>,\n              stackIndex > 0 ? previousInitialPointList[stackIndex - 1] : null,\n              true);\n          final lineElementList =\n              lineAndArea[0] as List<_LineRendererElement<D>>;\n          final areaElementList =\n              lineAndArea[1] as List<_AreaRendererElement<D>>;\n          final allPointList = lineAndArea[2] as List<_DatumPoint<D>>;\n          final boundsElementList =\n              lineAndArea[3] as List<_AreaRendererElement<D>>;\n\n          // Create the line elements.\n          final animatingLines = <_AnimatedLine<D>>[];\n\n          for (var index = 0; index < lineElementList.length; index++) {\n            animatingLines.add(_AnimatedLine<D>(\n                key: lineElementList[index].styleKey,\n                overlaySeries: series.overlaySeries)\n              ..setNewTarget(lineElementList[index]));\n          }\n\n          // Create the area elements.\n          List<_AnimatedArea<D>>? animatingAreas;\n          if (config.includeArea) {\n            animatingAreas = <_AnimatedArea<D>>[];\n\n            for (var index = 0; index < areaElementList.length; index++) {\n              animatingAreas.add(_AnimatedArea<D>(\n                  key: areaElementList[index].styleKey,\n                  overlaySeries: series.overlaySeries)\n                ..setNewTarget(areaElementList[index]));\n            }\n          }\n\n          // Create the bound elements separately from area elements, because\n          // it needs to be rendered on top of the area elements.\n          List<_AnimatedArea<D>>? animatingBounds;\n          if (_hasMeasureBounds) {\n            animatingBounds ??= <_AnimatedArea<D>>[];\n\n            for (var index = 0; index < boundsElementList.length; index++) {\n              animatingBounds.add(_AnimatedArea<D>(\n                  key: boundsElementList[index].styleKey,\n                  overlaySeries: series.overlaySeries)\n                ..setNewTarget(boundsElementList[index]));\n            }\n          }\n\n          animatingElements = _AnimatedElements<D>(\n            styleKey: styleSegment.styleKey,\n            allPoints: allPointList,\n            lines: animatingLines,\n            areas: animatingAreas,\n            bounds: animatingBounds,\n          );\n\n          elementsList.add(animatingElements);\n\n          previousInitialPointList[stackIndex] = allPointList;\n        }\n\n        // Create a new line using the final point locations.\n        final lineAndArea = _createLineAndAreaElements(\n            series,\n            styleSegment as _LineRendererElement<D>,\n            stackIndex > 0 ? previousPointList[stackIndex - 1] : null,\n            false);\n        final lineElementList = lineAndArea[0] as List<_LineRendererElement<D>>;\n        final areaElementList = lineAndArea[1] as List<_AreaRendererElement<D>>;\n        final allPointList = lineAndArea[2] as List<_DatumPoint<D>>;\n        final boundsElementList =\n            lineAndArea[3] as List<_AreaRendererElement<D>>;\n\n        for (var index = 0; index < lineElementList.length; index++) {\n          final lineElement = lineElementList[index];\n\n          // Add a new animated line if we have more segments in this draw cycle\n          // than we did in the previous chart draw cycle.\n          // TODO: Nicer animations for incoming segments.\n          if (index >= animatingElements.lines.length) {\n            animatingElements.lines.add(_AnimatedLine<D>(\n                key: lineElement.styleKey,\n                overlaySeries: series.overlaySeries));\n          }\n          animatingElements.lines[index].setNewTarget(lineElement);\n        }\n\n        if (config.includeArea) {\n          for (var index = 0; index < areaElementList.length; index++) {\n            final areaElement = areaElementList[index];\n\n            // Add a new animated area if we have more segments in this draw\n            // cycle than we did in the previous chart draw cycle.\n            // TODO: Nicer animations for incoming segments.\n            if (index >= animatingElements.areas!.length) {\n              animatingElements.areas!.add(_AnimatedArea<D>(\n                  key: areaElement.styleKey,\n                  overlaySeries: series.overlaySeries));\n            }\n            animatingElements.areas![index].setNewTarget(areaElement);\n          }\n        }\n\n        if (_hasMeasureBounds) {\n          for (var index = 0; index < boundsElementList.length; index++) {\n            final boundElement = boundsElementList[index];\n\n            // Add a new animated bound if we have more segments in this draw\n            // cycle than we did in the previous chart draw cycle.\n            // TODO: Nicer animations for incoming segments.\n            if (index >= animatingElements.bounds!.length) {\n              animatingElements.bounds!.add(_AnimatedArea<D>(\n                  key: boundElement.styleKey,\n                  overlaySeries: series.overlaySeries));\n            }\n            animatingElements.bounds![index].setNewTarget(boundElement);\n          }\n        }\n\n        animatingElements.allPoints = allPointList;\n\n        // Save the line points for the current series so that we can use them\n        // in the area skirt for the next stacked series.\n        previousPointList[stackIndex] = allPointList;\n      });\n    });\n\n    // Animate out lines that don't exist anymore.\n    _seriesLineMap.forEach((String key, List<_AnimatedElements<D>> elements) {\n      for (var element in elements) {\n        if (element.lines != null) {\n          for (var line in element.lines) {\n            if (!_currentKeys.contains(line.key)) {\n              line.animateOut();\n            }\n          }\n        }\n        if (element.areas != null) {\n          for (var area in element.areas!) {\n            if (!_currentKeys.contains(area.key)) {\n              area.animateOut();\n            }\n          }\n        }\n        if (element.bounds != null) {\n          for (var bound in element.bounds!) {\n            if (!_currentKeys.contains(bound.key)) {\n              bound.animateOut();\n            }\n          }\n        }\n      }\n    });\n\n    if (config.includePoints) {\n      _pointRenderer.update(seriesList, isAnimatingThisDraw);\n    }\n  }\n\n  /// Creates a tuple of lists of [_LineRendererElement]s,\n  /// [_AreaRendererElement]s, [_DatumPoint]s for a given style segment of a\n  /// series.\n  ///\n  /// The first element in the returned array is a list of line elements, broken\n  /// apart by null data.\n  ///\n  /// The second element in the returned array is a list of area elements,\n  /// broken apart by null data.\n  ///\n  /// The third element in the returned array is a list of all of the points for\n  /// the entire series. This is intended to be used as the [previousPointList]\n  /// for the next series.\n  ///\n  /// [series] the series that this line represents.\n  ///\n  /// [styleSegment] represents the rendering style for a subset of the series\n  /// data, bounded by its domainExtent.\n  ///\n  /// [previousPointList] contains the points for the line below this series in\n  /// the stack, if stacking is enabled. It forms the bottom edges for the area\n  /// skirt.\n  ///\n  /// [initializeFromZero] controls whether we generate elements with measure\n  /// values of 0, or using series data. This should be true when calculating\n  /// point positions to animate in from the measure axis.\n  List<Object> _createLineAndAreaElements(\n      ImmutableSeries<D> series,\n      _LineRendererElement<D> styleSegment,\n      List<_DatumPoint<D>>? previousPointList,\n      bool initializeFromZero) {\n    final measureAxis = series.getAttr(measureAxisKey) as ImmutableAxis<num>;\n\n    final color = styleSegment.color;\n    final areaColor = styleSegment.areaColor;\n    final dashPattern = styleSegment.dashPattern;\n    final domainExtent = styleSegment.domainExtent;\n    final strokeWidthPx = styleSegment.strokeWidthPx;\n    final styleKey = styleSegment.styleKey;\n    final roundEndCaps = styleSegment.roundEndCaps;\n\n    // Get a list of all positioned points for this series.\n    final pointList = _createPointListForSeries(series, initializeFromZero);\n\n    // Break pointList up into sets of line and area segments, divided by null\n    // measure values in the series data.\n    final segmentsList = _createLineAndAreaSegmentsForSeries(\n        pointList, previousPointList, series, initializeFromZero);\n    final lineSegments = segmentsList[0];\n    final areaSegments = segmentsList[1];\n    final boundsSegment = segmentsList[2];\n\n    _currentKeys.add(styleKey);\n\n    final positionExtent = _createPositionExtent(series, styleSegment);\n\n    // Get the line elements we are going to to set up.\n    final lineElements = <_LineRendererElement<D>>[];\n    for (var index = 0; index < lineSegments.length; index++) {\n      final linePointList = lineSegments[index];\n\n      // Update the set of areas that still exist in the series data.\n      final lineStyleKey = '${styleKey}__line__${index}';\n      _currentKeys.add(lineStyleKey);\n\n      lineElements.add(_LineRendererElement<D>(\n        points: linePointList,\n        color: color,\n        areaColor: areaColor,\n        dashPattern: dashPattern,\n        domainExtent: domainExtent,\n        measureAxisPosition: measureAxis.getLocation(0.0),\n        positionExtent: positionExtent,\n        strokeWidthPx: strokeWidthPx,\n        styleKey: lineStyleKey,\n        roundEndCaps: roundEndCaps,\n      ));\n    }\n\n    // Get the area elements we are going to set up.\n    final areaElements = <_AreaRendererElement<D>>[];\n    if (config.includeArea) {\n      for (var index = 0; index < areaSegments.length; index++) {\n        final areaPointList = areaSegments[index];\n\n        // Update the set of areas that still exist in the series data.\n        final areaStyleKey = '${styleKey}__area_${index}';\n        _currentKeys.add(areaStyleKey);\n\n        areaElements.add(_AreaRendererElement<D>(\n          points: areaPointList,\n          color: color,\n          areaColor: areaColor,\n          domainExtent: domainExtent,\n          measureAxisPosition: measureAxis.getLocation(0.0)!,\n          positionExtent: positionExtent,\n          styleKey: areaStyleKey,\n        ));\n      }\n    }\n\n    // Create the bounds element\n    final boundsElements = <_AreaRendererElement<D>>[];\n    if (_hasMeasureBounds) {\n      // Update the set of bounds that still exist in the series data.\n      for (var index = 0; index < boundsSegment.length; index++) {\n        final boundsPointList = boundsSegment[index];\n\n        final boundsStyleKey = '${styleKey}__bounds_${index}';\n        _currentKeys.add(boundsStyleKey);\n\n        boundsElements.add(_AreaRendererElement<D>(\n          points: boundsPointList,\n          color: color,\n          areaColor: areaColor,\n          domainExtent: domainExtent,\n          measureAxisPosition: measureAxis.getLocation(0.0)!,\n          positionExtent: positionExtent,\n          styleKey: boundsStyleKey,\n        ));\n      }\n    }\n\n    return [lineElements, areaElements, pointList, boundsElements];\n  }\n\n  /// Builds a list of data points for the entire series.\n  ///\n  /// [series] the series that this line represents.\n  ///\n  /// [initializeFromZero] controls whether we generate elements with measure\n  /// values of 0, or using series data. This should be true when calculating\n  /// point positions to animate in from the measure axis.\n  List<_DatumPoint<D>> _createPointListForSeries(\n      ImmutableSeries<D> series, bool initializeFromZero) {\n    final domainAxis = series.getAttr(domainAxisKey) as ImmutableAxis<D>;\n    final domainFn = series.domainFn;\n    final measureAxis = series.getAttr(measureAxisKey) as ImmutableAxis<num>;\n    final measureFn = series.measureFn;\n    final measureOffsetFn = series.measureOffsetFn!;\n\n    final pointList = <_DatumPoint<D>>[];\n\n    // Generate [_DatumPoints]s for the series data.\n    for (var index = 0; index < series.data.length; index++) {\n      final Object? datum = series.data[index];\n\n      // TODO: Animate from the nearest lines in the stack.\n      var measure = measureFn(index);\n      if (measure != null && initializeFromZero) {\n        measure = 0.0;\n      }\n\n      var measureOffset = measureOffsetFn(index);\n      if (measureOffset != null && initializeFromZero) {\n        measureOffset = 0.0;\n      }\n\n      pointList.add(_getPoint(datum, domainFn(index), series, domainAxis,\n          measure, measureOffset, measureAxis,\n          index: index));\n    }\n\n    return pointList;\n  }\n\n  /// Builds a list of line and area segments for a series.\n  ///\n  /// This method returns a list of two elements. The first is a list of line\n  /// segments, and the second is a list of area segments. Both sets of segments\n  /// are broken up by null measure values in the series data.\n  ///\n  /// [pointList] list of all points in the line.\n  ///\n  /// [previousPointList] list of all points in the line below this one in the\n  /// stack.\n  ///\n  /// [series] the series that this line represents.\n  List<List<List<_DatumPoint<D>>>> _createLineAndAreaSegmentsForSeries(\n      List<_DatumPoint<D>> pointList,\n      List<_DatumPoint<D>>? previousPointList,\n      ImmutableSeries<D> series,\n      bool initializeFromZero) {\n    final lineSegments = <List<_DatumPoint<D>>>[];\n    final areaSegments = <List<_DatumPoint<D>>>[];\n    final boundsSegments = <List<_DatumPoint<D>>>[];\n\n    int? startPointIndex;\n    int? endPointIndex;\n\n    // Only build bound segments for this series if it has bounds functions.\n    final seriesHasMeasureBounds = series.measureUpperBoundFn != null &&\n        series.measureLowerBoundFn != null;\n\n    for (var index = 0; index < pointList.length; index++) {\n      final point = pointList[index];\n\n      if (point.y == null) {\n        if (startPointIndex == null) {\n          continue;\n        }\n        assert(endPointIndex != null);\n\n        lineSegments.add(\n            _createLineSegment(startPointIndex, endPointIndex!, pointList));\n\n        // Isolated data points are handled by the line painter. Do not add an\n        // area segment for them.\n        if (startPointIndex != endPointIndex) {\n          if (config.includeArea) {\n            areaSegments.add(_createAreaSegment(startPointIndex, endPointIndex,\n                pointList, previousPointList, series, initializeFromZero));\n          }\n          if (seriesHasMeasureBounds) {\n            boundsSegments.add(_createBoundsSegment(\n                pointList.sublist(startPointIndex, endPointIndex + 1),\n                series,\n                initializeFromZero));\n          }\n        }\n\n        startPointIndex = null;\n        endPointIndex = null;\n        continue;\n      }\n\n      startPointIndex ??= index;\n      endPointIndex = index;\n    }\n\n    // Create an area point list for the final segment. This will be the only\n    // segment if no null measure values were found in the series.\n    if (startPointIndex != null && endPointIndex != null) {\n      lineSegments\n          .add(_createLineSegment(startPointIndex, endPointIndex, pointList));\n\n      // Isolated data points are handled by the line painter. Do not add an\n      // area segment for them.\n      if (startPointIndex != endPointIndex) {\n        if (config.includeArea) {\n          areaSegments.add(_createAreaSegment(startPointIndex, endPointIndex,\n              pointList, previousPointList, series, initializeFromZero));\n        }\n\n        if (seriesHasMeasureBounds) {\n          boundsSegments.add(_createBoundsSegment(\n              pointList.sublist(startPointIndex, endPointIndex + 1),\n              series,\n              initializeFromZero));\n        }\n      }\n    }\n\n    return [lineSegments, areaSegments, boundsSegments];\n  }\n\n  /// Builds a list of data points for a line segment.\n  ///\n  /// For a line, this is effectively just a sub list of [pointList].\n  ///\n  /// [start] index of the first point in the segment.\n  ///\n  /// [end] index of the last point in the segment.\n  ///\n  /// [pointList] list of all points in the line.\n  List<_DatumPoint<D>> _createLineSegment(\n          int start, int end, List<_DatumPoint<D>> pointList) =>\n      pointList.sublist(start, end + 1);\n\n  /// Builds a list of data points for an area segment.\n  ///\n  /// The list of points will include a baseline at the domain axis if there was\n  /// no previous line in the stack. Otherwise, the bottom of the shape will\n  /// consist of the points from the previous series that line up with the\n  /// current series.\n  ///\n  /// [start] index of the first point in the segment.\n  ///\n  /// [end] index of the last point in the segment.\n  ///\n  /// [pointList] list of all points in the line.\n  ///\n  /// [previousPointList] list of all points in the line below this one in the\n  /// stack.\n  ///\n  /// [series] the series that this line represents.\n  List<_DatumPoint<D>> _createAreaSegment(\n      int start,\n      int end,\n      List<_DatumPoint<D>> pointList,\n      List<_DatumPoint<D>>? previousPointList,\n      ImmutableSeries<D> series,\n      bool initializeFromZero) {\n    final domainAxis = series.getAttr(domainAxisKey) as ImmutableAxis<D>;\n    final domainFn = series.domainFn;\n    final measureAxis = series.getAttr(measureAxisKey) as ImmutableAxis<num>;\n\n    final areaPointList = <_DatumPoint<D>>[];\n\n    if (!config.stacked || previousPointList == null) {\n      // Start area segments at the bottom of a stack by adding a bottom line\n      // segment along the measure axis.\n      areaPointList.add(_getPoint(\n          null, domainFn(end), series, domainAxis, 0.0, 0.0, measureAxis));\n\n      areaPointList.add(_getPoint(\n          null, domainFn(start), series, domainAxis, 0.0, 0.0, measureAxis));\n    } else {\n      // Start subsequent area segments in a stack by adding the previous\n      // points in reverse order, so that we can get a properly closed\n      // polygon.\n      areaPointList.addAll(previousPointList.sublist(start, end + 1).reversed);\n    }\n\n    areaPointList.addAll(pointList.sublist(start, end + 1));\n\n    return areaPointList;\n  }\n\n  List<_DatumPoint<D>> _createBoundsSegment(List<_DatumPoint<D>> pointList,\n      ImmutableSeries<D> series, bool initializeFromZero) {\n    final measureAxis = series.getAttr(measureAxisKey) as ImmutableAxis<num>;\n    final areaPointList = <_DatumPoint<D>>[];\n\n    // Add all points for upper bounds.\n    areaPointList.addAll(pointList.map((datumPoint) => _DatumPoint.from(\n        datumPoint,\n        datumPoint.x,\n        initializeFromZero\n            ? datumPoint.y\n            : measureAxis.getLocation(\n                (series.measureUpperBoundFn!(datumPoint.index) ?? 0) +\n                    series.measureOffsetFn!(datumPoint.index)!))));\n\n    // Add all points for lower bounds, in reverse order.\n    areaPointList.addAll(pointList.reversed.map((datumPoint) =>\n        _DatumPoint.from(\n            datumPoint,\n            datumPoint.x,\n            initializeFromZero\n                ? datumPoint.y\n                : measureAxis.getLocation(\n                    (series.measureLowerBoundFn!(datumPoint.index) ?? 0) +\n                        series.measureOffsetFn!(datumPoint.index)!))));\n\n    return areaPointList;\n  }\n\n  /// Converts the domain value extent for the series into axis positions,\n  /// clamped to the edges of the draw area.\n  ///\n  /// [series] the series that this line represents.\n  ///\n  /// [details] represents the element details for a line segment.\n  _Range<num> _createPositionExtent(\n      ImmutableSeries<D> series, _LineRendererElement<D> details) {\n    final domainAxis = series.getAttr(domainAxisKey) as ImmutableAxis<D>;\n\n    // Convert the domain extent into axis positions.\n    // Clamp start position to the beginning of the draw area if it is outside\n    // the domain viewport range.\n    final startPosition = domainAxis.getLocation(details.domainExtent.start) ??\n        drawBounds!.left.toDouble();\n\n    // Clamp end position to the end of the draw area if it is outside the\n    // domain viewport range.\n    final endPosition = domainAxis.getLocation(details.domainExtent.end) ??\n        drawBounds!.right.toDouble();\n\n    return _Range<num>(startPosition, endPosition);\n  }\n\n  @override\n  void onAttach(BaseChart<D> chart) {\n    super.onAttach(chart);\n    // We only need the chart.context.isRtl setting, but context is not yet\n    // available when the default renderer is attached to the chart on chart\n    // creation time, since chart onInit is called after the chart is created.\n    _chart = chart;\n  }\n\n  @override\n  void paint(ChartCanvas canvas, double animationPercent) {\n    // Clean up the lines that no longer exist.\n    if (animationPercent == 1.0) {\n      final keysToRemove = <String>[];\n\n      _seriesLineMap.forEach((String key, List<_AnimatedElements<D>> elements) {\n        elements.removeWhere(\n            (_AnimatedElements<D> element) => element.animatingOut);\n\n        if (elements.isEmpty) {\n          keysToRemove.add(key);\n        }\n      });\n\n      keysToRemove.forEach(_seriesLineMap.remove);\n    }\n\n    _seriesLineMap.forEach((String key, List<_AnimatedElements<D>> elements) {\n      if (config.includeArea) {\n        elements\n            .map<List<_AnimatedArea<D>>>(\n                (_AnimatedElements<D> animatingElement) =>\n                    animatingElement.areas!)\n            .expand<_AnimatedArea<D>>((List<_AnimatedArea<D>> areas) => areas)\n            .map<_AreaRendererElement<D>>((_AnimatedArea<D> animatingArea) =>\n                animatingArea.getCurrentArea(animationPercent))\n            .forEach((area) {\n          if (area != null) {\n            canvas.drawPolygon(\n                clipBounds: _getClipBoundsForExtent(area.positionExtent),\n                fill: area.areaColor ?? area.color,\n                points: area.points.toPoints());\n          }\n        });\n      }\n\n      if (_hasMeasureBounds) {\n        elements\n            .map<List<_AnimatedArea<D>>>(\n                (_AnimatedElements<D> animatingElement) =>\n                    animatingElement.bounds!)\n            .expand<_AnimatedArea<D>>((List<_AnimatedArea<D>> bounds) => bounds)\n            .map<_AreaRendererElement<D>>((_AnimatedArea<D> animatingBounds) =>\n                animatingBounds.getCurrentArea(animationPercent))\n            .forEach((bound) {\n          if (bound != null) {\n            canvas.drawPolygon(\n                clipBounds: _getClipBoundsForExtent(bound.positionExtent),\n                fill: bound.areaColor ?? bound.color,\n                points: bound.points.toPoints());\n          }\n        });\n      }\n\n      if (config.includeLine) {\n        elements\n            .map<List<_AnimatedLine<D>>>(\n                (_AnimatedElements<D> animatingElement) =>\n                    animatingElement.lines)\n            .expand<_AnimatedLine<D>>((List<_AnimatedLine<D>> lines) => lines)\n            .map<_LineRendererElement<D>>((_AnimatedLine<D> animatingLine) =>\n                animatingLine.getCurrentLine(animationPercent))\n            .forEach((line) {\n          if (line != null) {\n            canvas.drawLine(\n                clipBounds: _getClipBoundsForExtent(line.positionExtent!),\n                dashPattern: line.dashPattern,\n                points: line.points!.toPoints(),\n                stroke: line.color,\n                strokeWidthPx: line.strokeWidthPx,\n                roundEndCaps: line.roundEndCaps);\n          }\n        });\n      }\n    });\n\n    if (config.includePoints) {\n      _pointRenderer.paint(canvas, animationPercent);\n    }\n  }\n\n  /// Builds a clip region bounding box within the component [drawBounds] for a\n  /// given domain range [extent].\n  Rectangle<num> _getClipBoundsForExtent(_Range<num> extent) {\n    // In RTL mode, the domain range extent has start on the right side of the\n    // chart. Adjust the calculated positions to define a regular left-anchored\n    // [Rectangle]. Clamp both ends to be within the draw area.\n    final drawBounds = this.drawBounds!;\n    final left = isRtl\n        ? clamp(extent.end, drawBounds.left, drawBounds.right)\n        : clamp(extent.start, drawBounds.left, drawBounds.right);\n\n    final right = isRtl\n        ? clamp(extent.start, drawBounds.left, drawBounds.right)\n        : clamp(extent.end, drawBounds.left, drawBounds.right);\n\n    return Rectangle<num>(\n        left,\n        drawBounds.top - drawBoundTopExtensionPx,\n        right - left,\n        drawBounds.height +\n            drawBoundTopExtensionPx +\n            drawBoundBottomExtensionPx);\n  }\n\n  bool get isRtl => _chart?.context.isRtl ?? false;\n\n  _DatumPoint<D> _getPoint(\n      dynamic datum,\n      D? domainValue,\n      ImmutableSeries<D> series,\n      ImmutableAxis<D> domainAxis,\n      num? measureValue,\n      num? measureOffsetValue,\n      ImmutableAxis<num> measureAxis,\n      {int? index}) {\n    final domainPosition = domainAxis.getLocation(domainValue);\n\n    final measurePosition = measureValue != null && measureOffsetValue != null\n        ? measureAxis.getLocation(measureValue + measureOffsetValue)\n        : null;\n\n    return _DatumPoint<D>(\n        datum: datum,\n        domain: domainValue,\n        series: series,\n        x: domainPosition,\n        y: measurePosition,\n        index: index);\n  }\n\n  @override\n  List<DatumDetails<D>> getNearestDatumDetailPerSeries(\n    Point<double> chartPoint,\n    bool byDomain,\n    Rectangle<int>? boundsOverride, {\n    bool selectOverlappingPoints = false,\n    bool selectExactEventLocation = false,\n  }) {\n    final nearest = <DatumDetails<D>>[];\n\n    // Was it even in the component bounds?\n    if (!isPointWithinBounds(chartPoint, boundsOverride)) {\n      return nearest;\n    }\n\n    for (final seriesSegments in _seriesLineMap.values) {\n      _DatumPoint<D>? nearestPoint;\n      var nearestDomainDistance = 10000.0;\n      var nearestMeasureDistance = 10000.0;\n      var nearestRelativeDistance = 10000.0;\n\n      for (final segment in seriesSegments) {\n        if (segment.overlaySeries) {\n          continue;\n        }\n\n        for (final p in segment.allPoints) {\n          // Don't look at points not in the drawArea.\n          if (p.x! < componentBounds!.left || p.x! > componentBounds!.right) {\n            continue;\n          }\n\n          double measureDistance;\n          double relativeDistance;\n          double domainDistance;\n\n          if (p.y != null) {\n            measureDistance = (p.y! - chartPoint.y).abs();\n            domainDistance = (p.x! - chartPoint.x).abs();\n            relativeDistance = chartPoint.distanceTo(p.toPoint());\n          } else {\n            // Null measures have no real position, so make them the farthest\n            // away by real distance.\n            measureDistance = double.infinity;\n            domainDistance = double.infinity;\n            relativeDistance = byDomain ? domainDistance : double.infinity;\n          }\n\n          if (byDomain) {\n            if ((domainDistance < nearestDomainDistance) ||\n                ((domainDistance == nearestDomainDistance) &&\n                    (measureDistance < nearestMeasureDistance))) {\n              nearestPoint = p;\n              nearestDomainDistance = domainDistance;\n              nearestMeasureDistance = measureDistance;\n              nearestRelativeDistance = relativeDistance;\n            }\n          } else {\n            if (relativeDistance < nearestRelativeDistance) {\n              nearestPoint = p;\n              nearestDomainDistance = domainDistance;\n              nearestMeasureDistance = measureDistance;\n              nearestRelativeDistance = relativeDistance;\n            }\n          }\n        }\n      }\n\n      // Found a point, add it to the list.\n      if (nearestPoint != null) {\n        nearest.add(DatumDetails<D>(\n            chartPosition: NullablePoint(nearestPoint.x, nearestPoint.y),\n            datum: nearestPoint.datum,\n            domain: nearestPoint.domain,\n            series: nearestPoint.series,\n            domainDistance: nearestDomainDistance,\n            measureDistance: nearestMeasureDistance,\n            relativeDistance: nearestRelativeDistance));\n      }\n    }\n\n    // Note: the details are already sorted by domain & measure distance in\n    // base chart.\n\n    return nearest;\n  }\n\n  @override\n  DatumDetails<D> addPositionToDetailsForSeriesDatum(\n      DatumDetails<D> details, SeriesDatum<D> seriesDatum) {\n    final series = details.series!;\n\n    final domainAxis = series.getAttr(domainAxisKey) as ImmutableAxis<D>;\n    final measureAxis = series.getAttr(measureAxisKey) as ImmutableAxis<num>;\n\n    final point = _getPoint(seriesDatum.datum, details.domain, series,\n        domainAxis, details.measure, details.measureOffset, measureAxis);\n    final chartPosition = NullablePoint(point.x, point.y);\n\n    return DatumDetails.from(details, chartPosition: chartPosition);\n  }\n}\n\nclass _DatumPoint<D> extends NullablePoint {\n  final dynamic datum;\n  final D? domain;\n  final ImmutableSeries<D>? series;\n  final int? index;\n\n  _DatumPoint({\n    this.datum,\n    this.domain,\n    this.series,\n    this.index,\n    double? x,\n    double? y,\n  }) : super(x, y);\n\n  factory _DatumPoint.from(_DatumPoint<D> other, [double? x, double? y]) {\n    return _DatumPoint<D>(\n        datum: other.datum,\n        domain: other.domain,\n        series: other.series,\n        index: other.index,\n        x: x ?? other.x,\n        y: y ?? other.y);\n  }\n}\n\n/// Rendering information for the line portion of a series.\nclass _LineRendererElement<D> {\n  List<_DatumPoint<D>>? points;\n  Color? color;\n  Color? areaColor;\n  List<int>? dashPattern;\n  _Range<D> domainExtent;\n  double? measureAxisPosition;\n  _Range<num>? positionExtent;\n  double strokeWidthPx;\n  String styleKey;\n  bool roundEndCaps;\n\n  _LineRendererElement({\n    this.points,\n    required this.color,\n    required this.areaColor,\n    required this.dashPattern,\n    required this.domainExtent,\n    this.measureAxisPosition,\n    this.positionExtent,\n    required this.strokeWidthPx,\n    required this.styleKey,\n    required this.roundEndCaps,\n  });\n\n  _LineRendererElement<D> clone() {\n    return _LineRendererElement<D>(\n      points: points != null ? List.of(points!) : null,\n      color: color != null ? Color.fromOther(color: color!) : null,\n      areaColor: areaColor != null ? Color.fromOther(color: areaColor!) : null,\n      dashPattern: dashPattern != null ? List.of(dashPattern!) : null,\n      domainExtent: domainExtent,\n      measureAxisPosition: measureAxisPosition,\n      positionExtent: positionExtent,\n      strokeWidthPx: strokeWidthPx,\n      styleKey: styleKey,\n      roundEndCaps: roundEndCaps,\n    );\n  }\n\n  void updateAnimationPercent(_LineRendererElement<D> previous,\n      _LineRendererElement<D> target, double animationPercent) {\n    final points = this.points!;\n\n    late _DatumPoint<D> lastPoint;\n\n    int pointIndex;\n    for (pointIndex = 0; pointIndex < target.points!.length; pointIndex++) {\n      final targetPoint = target.points![pointIndex];\n\n      // If we have more points than the previous line, animate in the new point\n      // by starting its measure position at the last known official point.\n      // TODO: Can this be done in setNewTarget instead?\n      _DatumPoint<D> previousPoint;\n      if (previous.points!.length - 1 >= pointIndex) {\n        previousPoint = previous.points![pointIndex];\n        lastPoint = previousPoint;\n      } else {\n        previousPoint =\n            _DatumPoint<D>.from(targetPoint, targetPoint.x, lastPoint.y);\n      }\n\n      final x = ((targetPoint.x! - previousPoint.x!) * animationPercent) +\n          previousPoint.x!;\n\n      double? y;\n      if (targetPoint.y != null && previousPoint.y != null) {\n        y = ((targetPoint.y! - previousPoint.y!) * animationPercent) +\n            previousPoint.y!;\n      } else if (targetPoint.y != null) {\n        y = targetPoint.y;\n      } else {\n        y = null;\n      }\n\n      if (points.length - 1 >= pointIndex) {\n        points[pointIndex] = _DatumPoint<D>.from(targetPoint, x, y);\n      } else {\n        points.add(_DatumPoint<D>.from(targetPoint, x, y));\n      }\n    }\n\n    // Removing extra points that don't exist anymore.\n    if (pointIndex < points.length) {\n      points.removeRange(pointIndex, points.length);\n    }\n\n    color = getAnimatedColor(previous.color!, target.color!, animationPercent);\n\n    if (areaColor != null) {\n      areaColor = getAnimatedColor(\n          previous.areaColor!, target.areaColor!, animationPercent);\n    }\n\n    strokeWidthPx =\n        ((target.strokeWidthPx - previous.strokeWidthPx) * animationPercent) +\n            previous.strokeWidthPx;\n  }\n}\n\n/// Animates the line element of a series between different states.\nclass _AnimatedLine<D> {\n  final String key;\n  final bool overlaySeries;\n\n  _LineRendererElement<D>? _previousLine;\n  late _LineRendererElement<D> _targetLine;\n  _LineRendererElement<D>? _currentLine;\n\n  // Flag indicating whether this line is being animated out of the chart.\n  bool animatingOut = false;\n\n  _AnimatedLine({required this.key, required this.overlaySeries});\n\n  /// Animates a line that was removed from the series out of the view.\n  ///\n  /// This should be called in place of \"setNewTarget\" for lines that represent\n  /// data that has been removed from the series.\n  ///\n  /// Animates the height of the line down to the measure axis position\n  /// (position of 0).\n  void animateOut() {\n    var newTarget = _currentLine!.clone();\n\n    // Set the target measure value to the axis position for all points.\n    // TODO: Animate to the nearest lines in the stack.\n    var newPoints = <_DatumPoint<D>>[];\n    for (var index = 0; index < newTarget.points!.length; index++) {\n      var targetPoint = newTarget.points![index];\n\n      newPoints.add(_DatumPoint<D>.from(targetPoint, targetPoint.x,\n          newTarget.measureAxisPosition!.roundToDouble()));\n    }\n\n    newTarget.points = newPoints;\n\n    // Animate the stroke width to 0 so that we don't get a lingering line after\n    // animation is done.\n    newTarget.strokeWidthPx = 0.0;\n\n    setNewTarget(newTarget);\n    animatingOut = true;\n  }\n\n  void setNewTarget(_LineRendererElement<D> newTarget) {\n    animatingOut = false;\n    _currentLine ??= newTarget.clone();\n    _previousLine = _currentLine!.clone();\n    _targetLine = newTarget;\n  }\n\n  _LineRendererElement<D> getCurrentLine(double animationPercent) {\n    if (animationPercent == 1.0 || _previousLine == null) {\n      _currentLine = _targetLine;\n      _previousLine = _targetLine;\n      return _currentLine!;\n    }\n\n    _currentLine!\n        .updateAnimationPercent(_previousLine!, _targetLine, animationPercent);\n\n    return _currentLine!;\n  }\n\n  /// Returns the [points] of the current target element, without updating\n  /// animation state.\n  List<_DatumPoint<D>>? get currentPoints => _currentLine?.points;\n}\n\n/// Rendering information for the area skirt portion of a series.\nclass _AreaRendererElement<D> {\n  List<_DatumPoint<D>> points;\n  Color? color;\n  Color? areaColor;\n  _Range<D> domainExtent;\n  double measureAxisPosition;\n  _Range<num> positionExtent;\n  String styleKey;\n\n  _AreaRendererElement({\n    required this.points,\n    required this.color,\n    required this.areaColor,\n    required this.domainExtent,\n    required this.measureAxisPosition,\n    required this.positionExtent,\n    required this.styleKey,\n  });\n\n  _AreaRendererElement<D> clone() {\n    return _AreaRendererElement<D>(\n      points: List.of(points),\n      color: color != null ? Color.fromOther(color: color!) : null,\n      areaColor: areaColor != null ? Color.fromOther(color: areaColor!) : null,\n      domainExtent: domainExtent,\n      measureAxisPosition: measureAxisPosition,\n      positionExtent: positionExtent,\n      styleKey: styleKey,\n    );\n  }\n\n  void updateAnimationPercent(_AreaRendererElement<D> previous,\n      _AreaRendererElement<D> target, double animationPercent) {\n    late _DatumPoint<D> lastPoint;\n\n    int pointIndex;\n    for (pointIndex = 0; pointIndex < target.points.length; pointIndex++) {\n      var targetPoint = target.points[pointIndex];\n\n      // If we have more points than the previous line, animate in the new point\n      // by starting its measure position at the last known official point.\n      // TODO: Can this be done in setNewTarget instead?\n      _DatumPoint<D> previousPoint;\n      if (previous.points.length - 1 >= pointIndex) {\n        previousPoint = previous.points[pointIndex];\n        lastPoint = previousPoint;\n      } else {\n        previousPoint =\n            _DatumPoint<D>.from(targetPoint, targetPoint.x, lastPoint.y);\n      }\n\n      final x = ((targetPoint.x! - previousPoint.x!) * animationPercent) +\n          previousPoint.x!;\n\n      double? y;\n      if (targetPoint.y != null && previousPoint.y != null) {\n        y = ((targetPoint.y! - previousPoint.y!) * animationPercent) +\n            previousPoint.y!;\n      } else if (targetPoint.y != null) {\n        y = targetPoint.y;\n      } else {\n        y = null;\n      }\n\n      if (points.length - 1 >= pointIndex) {\n        points[pointIndex] = _DatumPoint<D>.from(targetPoint, x, y);\n      } else {\n        points.add(_DatumPoint<D>.from(targetPoint, x, y));\n      }\n    }\n\n    // Removing extra points that don't exist anymore.\n    if (pointIndex < points.length) {\n      points.removeRange(pointIndex, points.length);\n    }\n\n    color = getAnimatedColor(previous.color!, target.color!, animationPercent);\n\n    if (areaColor != null) {\n      areaColor = getAnimatedColor(\n          previous.areaColor!, target.areaColor!, animationPercent);\n    }\n  }\n}\n\n/// Animates the area element of a series between different states.\nclass _AnimatedArea<D> {\n  final String key;\n  final bool overlaySeries;\n\n  _AreaRendererElement<D>? _previousArea;\n  late _AreaRendererElement<D> _targetArea;\n  _AreaRendererElement<D>? _currentArea;\n\n  // Flag indicating whether this line is being animated out of the chart.\n  bool animatingOut = false;\n\n  _AnimatedArea({required this.key, required this.overlaySeries});\n\n  /// Animates a line that was removed from the series out of the view.\n  ///\n  /// This should be called in place of \"setNewTarget\" for lines that represent\n  /// data that has been removed from the series.\n  ///\n  /// Animates the height of the line down to the measure axis position\n  /// (position of 0).\n  void animateOut() {\n    var newTarget = _currentArea!.clone();\n\n    // Set the target measure value to the axis position for all points.\n    // TODO: Animate to the nearest areas in the stack.\n    var newPoints = <_DatumPoint<D>>[];\n    for (var index = 0; index < newTarget.points.length; index++) {\n      var targetPoint = newTarget.points[index];\n\n      newPoints.add(_DatumPoint<D>.from(targetPoint, targetPoint.x,\n          newTarget.measureAxisPosition.roundToDouble()));\n    }\n\n    newTarget.points = newPoints;\n\n    setNewTarget(newTarget);\n    animatingOut = true;\n  }\n\n  void setNewTarget(_AreaRendererElement<D> newTarget) {\n    animatingOut = false;\n    _currentArea ??= newTarget.clone();\n    _previousArea = _currentArea!.clone();\n    _targetArea = newTarget;\n  }\n\n  _AreaRendererElement<D> getCurrentArea(double animationPercent) {\n    if (animationPercent == 1.0 || _previousArea == null) {\n      _currentArea = _targetArea;\n      _previousArea = _targetArea;\n      return _currentArea!;\n    }\n\n    _currentArea!\n        .updateAnimationPercent(_previousArea!, _targetArea, animationPercent);\n\n    return _currentArea!;\n  }\n}\n\nclass _AnimatedElements<D> {\n  List<_DatumPoint<D>> allPoints;\n  List<_AnimatedArea<D>>? areas;\n  List<_AnimatedLine<D>> lines;\n  List<_AnimatedArea<D>>? bounds;\n  String styleKey;\n\n  _AnimatedElements({\n    required this.allPoints,\n    required this.areas,\n    required this.lines,\n    required this.bounds,\n    required this.styleKey,\n  });\n\n  bool get animatingOut {\n    var areasAnimatingOut = true;\n    if (areas != null) {\n      for (final area in areas!) {\n        areasAnimatingOut = areasAnimatingOut && area.animatingOut;\n      }\n    }\n\n    var linesAnimatingOut = true;\n    if (lines != null) {\n      for (final line in lines) {\n        linesAnimatingOut = linesAnimatingOut && line.animatingOut;\n      }\n    }\n\n    var boundsAnimatingOut = true;\n    if (bounds != null) {\n      for (final bound in bounds!) {\n        boundsAnimatingOut = boundsAnimatingOut && bound.animatingOut;\n      }\n    }\n\n    return areasAnimatingOut && linesAnimatingOut && boundsAnimatingOut;\n  }\n\n  bool get overlaySeries {\n    var areasOverlaySeries = true;\n    if (areas != null) {\n      for (final area in areas!) {\n        areasOverlaySeries = areasOverlaySeries && area.overlaySeries;\n      }\n    }\n\n    var linesOverlaySeries = true;\n    if (lines != null) {\n      for (final line in lines) {\n        linesOverlaySeries = linesOverlaySeries && line.overlaySeries;\n      }\n    }\n\n    var boundsOverlaySeries = true;\n    if (bounds != null) {\n      for (final bound in bounds!) {\n        boundsOverlaySeries = boundsOverlaySeries && bound.overlaySeries;\n      }\n    }\n\n    return areasOverlaySeries && linesOverlaySeries && boundsOverlaySeries;\n  }\n}\n\n/// Describes a numeric range with a start and end value.\n///\n/// [start] must always be less than [end].\nclass _Range<D> {\n  D _start;\n  D _end;\n\n  _Range(D start, D end)\n      : _start = start,\n        _end = end;\n\n  /// Gets the start of the range.\n  D get start => _start;\n\n  /// Gets the end of the range.\n  D get end => _end;\n\n  /// Extends the range to include [value].\n  void includePoint(D? value) {\n    if (value == null) {\n      return;\n    } else if (value is num) {\n      _includePointAsNum(value);\n    } else if (value is DateTime) {\n      _includePointAsDateTime(value);\n    } else if (value is String) {\n      _includePointAsString(value);\n    } else {\n      throw ArgumentError(\n          'Unsupported object type for LineRenderer domain value: '\n          '${value.runtimeType}');\n    }\n  }\n\n  /// Extends the range to include value by casting as numbers.\n  void _includePointAsNum(D value) {\n    value as num;\n    if (value < (_start as num)) {\n      _start = value;\n    } else if (value > (_end as num)) {\n      _end = value;\n    }\n  }\n\n  /// Extends the range to include value by casting as DateTime objects.\n  void _includePointAsDateTime(D value) {\n    value as DateTime;\n    if (value.isBefore(_start as DateTime)) {\n      _start = value;\n    } else if (value.isAfter(_end as DateTime)) {\n      _end = value;\n    }\n  }\n\n  /// Extends the range to include value by casting as String objects.\n  ///\n  /// In this case, we assume that the data is ordered in the same order as the\n  /// axis.\n  void _includePointAsString(D value) {\n    _end = value;\n  }\n}\n\n@visibleForTesting\nclass LineRendererTester<D> {\n  final LineRenderer<D> renderer;\n\n  LineRendererTester(this.renderer);\n\n  Iterable<String> get seriesKeys => renderer._seriesLineMap.keys;\n\n  void setSeriesKeys(List<String> keys) {\n    renderer._seriesLineMap.addEntries(keys.map((key) => MapEntry(key, [])));\n  }\n\n  void merge(List<ImmutableSeries<D>> series) {\n    renderer._mergeIntoSeriesMap(series);\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/line/line_renderer_config.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport '../../common/symbol_renderer.dart';\nimport '../common/series_renderer_config.dart'\n    show RendererAttributes, SeriesRendererConfig;\nimport '../layout/layout_view.dart' show LayoutViewConfig, LayoutViewPaintOrder;\nimport 'line_renderer.dart' show LineRenderer;\n\n/// Configuration for a line renderer.\nclass LineRendererConfig<D> extends LayoutViewConfig\n    implements SeriesRendererConfig<D> {\n  @override\n  final String? customRendererId;\n\n  @override\n  final SymbolRenderer symbolRenderer;\n\n  @override\n  final rendererAttributes = RendererAttributes();\n\n  /// Radius of points on the line, if [includePoints] is enabled.\n  final double radiusPx;\n\n  /// Whether or not series should be rendered in a stack.\n  ///\n  /// This is typically enabled when including area skirts.\n  final bool stacked;\n\n  /// Stroke width of the line.\n  final double strokeWidthPx;\n\n  /// Dash pattern for the line.\n  final List<int>? dashPattern;\n\n  /// Configures whether a line representing the data will be drawn.\n  final bool includeLine;\n\n  /// Configures whether points representing the data will be drawn.\n  final bool includePoints;\n\n  /// Configures whether an area skirt representing the data will be drawn.\n  ///\n  /// An area skirt will be drawn from the line for each series, down to the\n  /// domain axis. It will be layered underneath the primary line on the chart.\n  ///\n  /// The area skirt color will be a semi-transparent version of the series\n  /// color, using [areaOpacity] as the opacity.\n  ///\n  /// When stacking is enabled, the bottom of each area skirt will instead be\n  /// the previous line in the stack. The bottom area will be drawn down to the\n  /// domain axis.\n  final bool includeArea;\n\n  /// The order to paint this renderer on the canvas.\n  final int layoutPaintOrder;\n\n  /// Configures the opacity of the area skirt on the chart.\n  final double areaOpacity;\n\n  /// Whether lines should have round end caps, or square if false.\n  final bool roundEndCaps;\n\n  LineRendererConfig(\n      {this.customRendererId,\n      this.radiusPx = 3.5,\n      this.stacked = false,\n      this.strokeWidthPx = 2.0,\n      this.dashPattern,\n      this.includeLine = true,\n      this.includePoints = false,\n      this.includeArea = false,\n      this.layoutPaintOrder = LayoutViewPaintOrder.line,\n      this.areaOpacity = 0.1,\n      this.roundEndCaps = false,\n      SymbolRenderer? symbolRenderer})\n      : symbolRenderer = symbolRenderer ?? LineSymbolRenderer();\n\n  @override\n  LineRenderer<D> build() {\n    return LineRenderer<D>(config: this, rendererId: customRendererId);\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/pie/arc_label_decorator.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math' show cos, min, sin, pi, Point, Rectangle;\n\nimport 'package:meta/meta.dart' show immutable, protected;\n\nimport '../../common/color.dart' show Color;\nimport '../../common/graphics_factory.dart' show GraphicsFactory;\nimport '../../common/style/style_factory.dart' show StyleFactory;\nimport '../../common/text_element.dart'\n    show MaxWidthStrategy, TextDirection, TextElement;\nimport '../../common/text_style.dart' show TextStyle;\nimport '../../data/series.dart' show AccessorFn;\nimport '../cartesian/axis/spec/axis_spec.dart' show TextStyleSpec;\nimport '../common/chart_canvas.dart' show ChartCanvas;\nimport 'arc_renderer_element.dart'\n    show ArcRendererElement, ArcRendererElementList;\nimport 'arc_renderer_decorator.dart' show ArcRendererDecorator;\n\n/// Renders labels for arc renderers.\n///\n/// This decorator performs very basic label collision detection. If the y\n/// position of a label positioned outside collides with the previously drawn\n/// label (on the same side of the chart), then that label will be skipped.\nclass ArcLabelDecorator<D> extends ArcRendererDecorator<D> {\n  // Default configuration\n  static const _defaultLabelPosition = ArcLabelPosition.auto;\n  static const _defaultLabelPadding = 5;\n  static final _defaultInsideLabelStyle =\n      TextStyleSpec(fontSize: 12, color: Color.white);\n  static final _defaultOutsideLabelStyle =\n      TextStyleSpec(fontSize: 12, color: Color.black);\n  static final _defaultLeaderLineStyle = ArcLabelLeaderLineStyleSpec(\n      length: 20.0,\n      thickness: 1.0,\n      color: StyleFactory.style.arcLabelOutsideLeaderLine);\n  static const _defaultShowLeaderLines = true;\n\n  /// Configures [TextStyleSpec] for labels placed inside the arcs.\n  final TextStyleSpec insideLabelStyleSpec;\n\n  /// Configures [TextStyleSpec] for labels placed outside the arcs.\n  final TextStyleSpec outsideLabelStyleSpec;\n\n  /// Configures [ArcLabelLeaderLineStyleSpec] for leader lines for labels\n  /// placed outside the arcs.\n  final ArcLabelLeaderLineStyleSpec leaderLineStyleSpec;\n\n  /// Configures where to place the label relative to the arcs.\n  final ArcLabelPosition labelPosition;\n\n  /// Space before and after the label text.\n  final int labelPadding;\n\n  /// Whether or not to draw leader lines for labels placed outside the arcs.\n  final bool showLeaderLines;\n\n  /// Render the labels on top of series data.\n  @override\n  final bool renderAbove = true;\n\n  ArcLabelDecorator(\n      {TextStyleSpec? insideLabelStyleSpec,\n      TextStyleSpec? outsideLabelStyleSpec,\n      ArcLabelLeaderLineStyleSpec? leaderLineStyleSpec,\n      this.labelPosition = _defaultLabelPosition,\n      this.labelPadding = _defaultLabelPadding,\n      this.showLeaderLines = _defaultShowLeaderLines,\n      Color? leaderLineColor})\n      : insideLabelStyleSpec = insideLabelStyleSpec ?? _defaultInsideLabelStyle,\n        outsideLabelStyleSpec =\n            outsideLabelStyleSpec ?? _defaultOutsideLabelStyle,\n        leaderLineStyleSpec = leaderLineStyleSpec ?? _defaultLeaderLineStyle;\n\n  @override\n  void decorate(ArcRendererElementList<D> arcElements, ChartCanvas canvas,\n      GraphicsFactory graphicsFactory,\n      {required Rectangle drawBounds,\n      required double animationPercent,\n      bool rtl = false}) {\n    // Only decorate the arcs when animation is at 100%.\n    if (animationPercent != 1.0) {\n      return;\n    }\n\n    // Create [TextStyle] from [TextStyleSpec] to be used by all the elements.\n    // The [GraphicsFactory] is needed so it can't be created earlier.\n    final insideLabelStyle =\n        _getTextStyle(graphicsFactory, insideLabelStyleSpec);\n    final outsideLabelStyle =\n        _getTextStyle(graphicsFactory, outsideLabelStyleSpec);\n\n    // Track the Y position of the previous outside label for collision\n    // detection purposes.\n    num? previousOutsideLabelY;\n    bool? previousLabelLeftOfChart;\n\n    for (var element in arcElements.arcs) {\n      final labelFn = element.series.labelAccessorFn;\n      final datumIndex = element.index;\n      final label = (labelFn != null) ? labelFn(datumIndex) : null;\n\n      // If there are custom styles, use that instead of the default or the\n      // style defined for the entire decorator.\n      final datumInsideLabelStyle = _getDatumStyle(\n          element.series.insideLabelStyleAccessorFn,\n          datumIndex,\n          graphicsFactory,\n          defaultStyle: insideLabelStyle);\n      final datumOutsideLabelStyle = _getDatumStyle(\n          element.series.outsideLabelStyleAccessorFn,\n          datumIndex,\n          graphicsFactory,\n          defaultStyle: outsideLabelStyle);\n\n      // Skip calculation and drawing for this element if no label.\n      if (label == null || label.isEmpty) {\n        continue;\n      }\n\n      final arcAngle = element.endAngle - element.startAngle;\n\n      final centerAngle = element.startAngle + (arcAngle / 2);\n\n      final centerRadius = arcElements.innerRadius +\n          ((arcElements.radius - arcElements.innerRadius) / 2);\n\n      final innerPoint = Point<double>(\n          arcElements.center.x + arcElements.innerRadius * cos(centerAngle),\n          arcElements.center.y + arcElements.innerRadius * sin(centerAngle));\n\n      final outerPoint = Point<double>(\n          arcElements.center.x + arcElements.radius * cos(centerAngle),\n          arcElements.center.y + arcElements.radius * sin(centerAngle));\n\n      //final bounds = element.bounds;\n      final bounds = Rectangle<double>.fromPoints(innerPoint, outerPoint);\n\n      // Get space available inside and outside the arc.\n      final totalPadding = labelPadding * 2;\n      final insideArcWidth = min(\n              (((arcAngle * 180 / pi) / 360) * (2 * pi * centerRadius)).round(),\n              (arcElements.radius - arcElements.innerRadius) - labelPadding)\n          .round();\n\n      final leaderLineLength = showLeaderLines ? leaderLineStyleSpec.length : 0;\n\n      final outsideArcWidth = ((drawBounds.width / 2) -\n              bounds.width -\n              totalPadding -\n              leaderLineLength)\n          .round();\n\n      final labelElement = graphicsFactory.createTextElement(label)\n        ..maxWidthStrategy = MaxWidthStrategy.ellipsize;\n\n      var calculatedLabelPosition = calculateLabelPosition(\n          labelElement,\n          datumInsideLabelStyle,\n          insideArcWidth,\n          outsideArcWidth,\n          element,\n          labelPosition);\n\n      // Set the max width and text style.\n      if (calculatedLabelPosition == ArcLabelPosition.inside) {\n        labelElement.textStyle = datumInsideLabelStyle;\n        labelElement.maxWidth = insideArcWidth;\n      } else {\n        // calculatedLabelPosition == LabelPosition.outside\n        labelElement.textStyle = datumOutsideLabelStyle;\n        labelElement.maxWidth = outsideArcWidth;\n      }\n\n      // Only calculate and draw label if there's actually space for the label.\n      if (labelElement.maxWidth! > 0) {\n        // Calculate the start position of label based on [labelAnchor].\n        if (calculatedLabelPosition == ArcLabelPosition.inside) {\n          _drawInsideLabel(canvas, arcElements, labelElement, centerAngle);\n        } else {\n          final l = _drawOutsideLabel(\n              canvas,\n              drawBounds,\n              arcElements,\n              labelElement,\n              centerAngle,\n              previousOutsideLabelY,\n              previousLabelLeftOfChart);\n\n          // List destructuring.\n          if (l != null) {\n            previousLabelLeftOfChart = l[0] as bool;\n            previousOutsideLabelY = l[1] as int;\n          }\n        }\n      }\n    }\n  }\n\n  @protected\n  ArcLabelPosition calculateLabelPosition(\n      TextElement labelElement,\n      TextStyle labelStyle,\n      int insideArcWidth,\n      int outsideArcWidth,\n      ArcRendererElement arcRendererelement,\n      ArcLabelPosition labelPosition) {\n    if (labelPosition == ArcLabelPosition.auto) {\n      // For auto, first try to fit the text inside the arc.\n      labelElement.textStyle = labelStyle;\n\n      // A label fits if the space inside the arc is >= outside arc or if the\n      // length of the text fits and the space. This is because if the arc has\n      // more space than the outside, it makes more sense to place the label\n      // inside the arc, even if the entire label does not fit.\n      return (insideArcWidth >= outsideArcWidth ||\n              labelElement.measurement.horizontalSliceWidth < insideArcWidth)\n          ? ArcLabelPosition.inside\n          : ArcLabelPosition.outside;\n    } else {\n      return labelPosition;\n    }\n  }\n\n  /// Helper function that converts [TextStyleSpec] to [TextStyle].\n  TextStyle _getTextStyle(\n      GraphicsFactory graphicsFactory, TextStyleSpec labelSpec) {\n    return graphicsFactory.createTextPaint()\n      ..color = labelSpec.color ?? Color.black\n      ..fontFamily = labelSpec.fontFamily\n      ..fontSize = labelSpec.fontSize ?? 12\n      ..lineHeight = labelSpec.lineHeight;\n  }\n\n  /// Helper function to get datum specific style\n  TextStyle _getDatumStyle(AccessorFn<TextStyleSpec>? labelFn, int? datumIndex,\n      GraphicsFactory graphicsFactory,\n      {required TextStyle defaultStyle}) {\n    final styleSpec = (labelFn != null) ? labelFn(datumIndex) : null;\n    return (styleSpec != null)\n        ? _getTextStyle(graphicsFactory, styleSpec)\n        : defaultStyle;\n  }\n\n  /// Draws a label inside of an arc.\n  void _drawInsideLabel(\n      ChartCanvas canvas,\n      ArcRendererElementList<D> arcElements,\n      TextElement labelElement,\n      double centerAngle) {\n    // Center the label inside the arc.\n    final labelRadius = arcElements.innerRadius +\n        (arcElements.radius - arcElements.innerRadius) / 2;\n\n    final labelX =\n        (arcElements.center.x + labelRadius * cos(centerAngle)).round();\n\n    final labelY = (arcElements.center.y +\n            labelRadius * sin(centerAngle) -\n            insideLabelStyleSpec.fontSize! / 2)\n        .round();\n\n    labelElement.textDirection = TextDirection.center;\n\n    canvas.drawText(labelElement, labelX, labelY);\n  }\n\n  /// Draws a label outside of an arc.\n  List<Object>? _drawOutsideLabel(\n      ChartCanvas canvas,\n      Rectangle drawBounds,\n      ArcRendererElementList<D> arcElements,\n      TextElement labelElement,\n      double centerAngle,\n      num? previousOutsideLabelY,\n      bool? previousLabelLeftOfChart) {\n    final labelRadius = arcElements.radius + leaderLineStyleSpec.length / 2;\n\n    final labelPoint = Point<double>(\n        arcElements.center.x + labelRadius * cos(centerAngle),\n        arcElements.center.y + labelRadius * sin(centerAngle));\n\n    // Use the label's chart quandrant to determine whether it's rendered to the\n    // right or left.\n    final centerAbs = centerAngle.abs() % (2 * pi);\n    final labelLeftOfChart = pi / 2 < centerAbs && centerAbs < pi * 3 / 2;\n\n    // Shift the label horizontally away from the center of the chart.\n    var labelX = labelLeftOfChart\n        ? (labelPoint.x - labelPadding).round()\n        : (labelPoint.x + labelPadding).round();\n\n    // Shift the label up by the size of the font.\n    final labelY = (labelPoint.y - outsideLabelStyleSpec.fontSize! / 2).round();\n\n    // Outside labels should flow away from the center of the chart\n    labelElement.textDirection =\n        labelLeftOfChart ? TextDirection.rtl : TextDirection.ltr;\n\n    // Skip this label if it collides with the previously drawn label.\n    if (_detectOutsideLabelCollision(labelY, labelLeftOfChart,\n        previousOutsideLabelY, previousLabelLeftOfChart)) {\n      return null;\n    }\n\n    if (showLeaderLines) {\n      final tailX = _drawLeaderLine(canvas, labelLeftOfChart, labelPoint,\n          arcElements.radius, arcElements.center, centerAngle);\n\n      // Shift the label horizontally by the length of the leader line.\n      labelX = (labelX + tailX).round();\n\n      labelElement.maxWidth = (labelElement.maxWidth! - tailX).round();\n    }\n\n    canvas.drawText(labelElement, labelX, labelY);\n\n    // Return a structured list of values.\n    return [labelLeftOfChart, labelY];\n  }\n\n  /// Detects whether the current outside label collides with the previous label.\n  bool _detectOutsideLabelCollision(num labelY, bool labelLeftOfChart,\n      num? previousOutsideLabelY, bool? previousLabelLeftOfChart) {\n    var collides = false;\n\n    // Given that labels are vertically centered, we can assume they will\n    // collide if the current label's Y coordinate +/- the font size\n    // crosses past the Y coordinate of the previous label drawn on the\n    // same side of the chart.\n    if (previousOutsideLabelY != null &&\n        labelLeftOfChart == previousLabelLeftOfChart) {\n      if (labelY > previousOutsideLabelY) {\n        if (labelY - outsideLabelStyleSpec.fontSize! <= previousOutsideLabelY) {\n          collides = true;\n        }\n      } else {\n        if (labelY + outsideLabelStyleSpec.fontSize! >= previousOutsideLabelY) {\n          collides = true;\n        }\n      }\n    }\n\n    return collides;\n  }\n\n  /// Draws a leader line for the current arc.\n  double _drawLeaderLine(\n      ChartCanvas canvas,\n      bool labelLeftOfChart,\n      Point<double> labelPoint,\n      double radius,\n      Point<double> arcCenterPoint,\n      double centerAngle) {\n    final tailX = (labelLeftOfChart ? -1 : 1) * leaderLineStyleSpec.length;\n\n    final leaderLineTailPoint =\n        Point<double>(labelPoint.x + tailX, labelPoint.y);\n\n    final centerRadius = radius - leaderLineStyleSpec.length / 2;\n    final leaderLineStartPoint = Point<double>(\n        arcCenterPoint.x + centerRadius * cos(centerAngle),\n        arcCenterPoint.y + centerRadius * sin(centerAngle));\n\n    canvas.drawLine(\n        points: [\n          leaderLineStartPoint,\n          labelPoint,\n          leaderLineTailPoint,\n        ],\n        stroke: leaderLineStyleSpec.color,\n        strokeWidthPx: leaderLineStyleSpec.thickness);\n\n    return tailX;\n  }\n}\n\n/// Configures where to place the label relative to the arcs.\nenum ArcLabelPosition {\n  /// Automatically try to place the label inside the arc first and place it on\n  /// the outside of the space available outside the arc is greater than space\n  /// available inside the arc.\n  auto,\n\n  /// Always place label on the outside.\n  outside,\n\n  /// Always place label on the inside.\n  inside\n}\n\n/// Style configuration for leader lines.\n@immutable\nclass ArcLabelLeaderLineStyleSpec {\n  final Color color;\n  final double length;\n  final double thickness;\n\n  ArcLabelLeaderLineStyleSpec({\n    required this.color,\n    required this.length,\n    required this.thickness,\n  });\n\n  @override\n  bool operator ==(Object other) {\n    return other is ArcLabelLeaderLineStyleSpec &&\n        color == other.color &&\n        thickness == other.thickness &&\n        length == other.length;\n  }\n\n  @override\n  int get hashCode {\n    var hashcode = color.hashCode;\n    hashcode = (hashcode * 37) + thickness.hashCode;\n    hashcode = (hashcode * 37) + length.hashCode;\n    return hashcode;\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/pie/arc_renderer.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:collection' show LinkedHashMap;\nimport 'dart:math' show max, pi, Point;\n\nimport 'package:collection/collection.dart' show IterableExtension;\n\nimport '../../common/style/style_factory.dart' show StyleFactory;\nimport '../../data/series.dart' show AttributeKey;\nimport '../common/chart_canvas.dart' show ChartCanvas;\nimport '../common/processed_series.dart' show ImmutableSeries, MutableSeries;\nimport 'arc_renderer_config.dart' show ArcRendererConfig;\nimport 'arc_renderer_decorator.dart' show ArcRendererDecorator;\nimport 'arc_renderer_element.dart'\n    show ArcRendererElement, AnimatedArcList, AnimatedArc;\nimport 'base_arc_renderer.dart';\n\nconst arcElementsKey =\n    AttributeKey<List<ArcRendererElement<Object>>>('ArcRenderer.elements');\n\nclass ArcRenderer<D> extends BaseArcRenderer<D> {\n  final ArcRendererConfig<D> config;\n\n  final List<ArcRendererDecorator<D>> arcRendererDecorators;\n\n  /// Store a map of series drawn on the chart, mapped by series name.\n  ///\n  /// [LinkedHashMap] is used to render the series on the canvas in the same\n  /// order as the data was given to the chart.\n  // ignore: prefer_collection_literals, https://github.com/dart-lang/linter/issues/1649\n  final _seriesArcMap = LinkedHashMap<String, AnimatedArcList<D>>();\n\n  // Store a list of arcs that exist in the series data.\n  //\n  // This list will be used to remove any [AnimatedArc] that were rendered in\n  // previous draw cycles, but no longer have a corresponding datum in the new\n  // data.\n  final _currentKeys = <String>[];\n\n  factory ArcRenderer({String? rendererId, ArcRendererConfig<D>? config}) {\n    return ArcRenderer._internal(\n        rendererId: rendererId ?? 'line',\n        config: config ?? ArcRendererConfig());\n  }\n\n  ArcRenderer._internal({required String rendererId, required this.config})\n      : arcRendererDecorators = config.arcRendererDecorators,\n        super(config: config, rendererId: rendererId);\n\n  @override\n  void preprocessSeries(List<MutableSeries<D>> seriesList) {\n    seriesList.forEach((MutableSeries<D> series) {\n      var elements = <ArcRendererElement<D>>[];\n\n      var domainFn = series.domainFn;\n      var measureFn = series.measureFn;\n\n      final seriesMeasureTotal = series.seriesMeasureTotal;\n\n      // On the canvas, arc measurements are defined as angles from the positive\n      // x axis. Start our first slice at the positive y axis instead.\n      var startAngle = config.startAngle;\n      var arcLength = config.arcLength;\n\n      var totalAngle = 0.0;\n\n      var measures = <num?>[];\n\n      if (series.data.isEmpty) {\n        // If the series has no data, generate an empty arc element that\n        // occupies the entire chart.\n        //\n        // Use a tiny epsilon difference to ensure that the canvas renders a\n        // \"full\" circle, in the correct direction.\n        var angle = arcLength == 2 * pi ? arcLength * .999999 : arcLength;\n        var endAngle = startAngle + angle;\n\n        var details = ArcRendererElement<D>(\n          startAngle: startAngle,\n          endAngle: endAngle,\n          index: 0,\n          key: 0,\n          series: series,\n        );\n\n        elements.add(details);\n      } else {\n        // Otherwise, generate an arc element per datum.\n        for (var arcIndex = 0; arcIndex < series.data.length; arcIndex++) {\n          var domain = domainFn(arcIndex);\n          var measure = measureFn(arcIndex);\n          measures.add(measure);\n          if (measure == null) {\n            continue;\n          }\n\n          final percentOfSeries = measure / seriesMeasureTotal;\n          var angle = arcLength * percentOfSeries;\n          var endAngle = startAngle + angle;\n\n          var details = ArcRendererElement<D>(\n            startAngle: startAngle,\n            endAngle: endAngle,\n            index: arcIndex,\n            key: arcIndex,\n            domain: domain,\n            series: series,\n          );\n\n          elements.add(details);\n\n          // Update the starting angle for the next datum in the series.\n          startAngle = endAngle;\n\n          totalAngle = totalAngle + angle;\n        }\n      }\n\n      series.setAttr(arcElementsKey, elements);\n    });\n  }\n\n  @override\n  void update(List<ImmutableSeries<D>> seriesList, bool isAnimatingThisDraw) {\n    _currentKeys.clear();\n\n    final bounds = chart!.drawAreaBounds;\n\n    final center = Point<double>((bounds.left + bounds.width / 2).toDouble(),\n        (bounds.top + bounds.height / 2).toDouble());\n\n    final radius = bounds.height < bounds.width\n        ? (bounds.height / 2).toDouble()\n        : (bounds.width / 2).toDouble();\n\n    if (config.arcRatio != null &&\n        (config.arcRatio! < 0 || config.arcRatio! > 1)) {\n      throw ArgumentError('arcRatio must be between 0 and 1');\n    }\n\n    final innerRadius = _calculateInnerRadius(radius);\n\n    seriesList.forEach((ImmutableSeries<D> series) {\n      var colorFn = series.colorFn;\n      var arcListKey = series.id;\n\n      var arcList =\n          _seriesArcMap.putIfAbsent(arcListKey, () => AnimatedArcList());\n\n      var elementsList =\n          series.getAttr(arcElementsKey) as List<ArcRendererElement<D>>;\n\n      if (series.data.isEmpty) {\n        // If the series is empty, set up the \"no data\" arc element. This should\n        // occupy the entire chart, and use the chart style's no data color.\n        final details = elementsList[0];\n\n        var arcKey = '__no_data__';\n\n        // If we already have an AnimatingArc for that index, use it.\n        var animatingArc =\n            arcList.arcs.firstWhereOrNull((arc) => arc.key == arcKey);\n\n        arcList.center = center;\n        arcList.radius = radius;\n        arcList.innerRadius = innerRadius;\n        arcList.series = series;\n        arcList.stroke = config.noDataColor;\n        arcList.strokeWidthPx = 0.0;\n\n        // If we don't have any existing arc element, create a new arc. Unlike\n        // real arcs, we should not animate the no data state in from 0.\n        if (animatingArc == null) {\n          animatingArc = AnimatedArc<D>(arcKey, null, null);\n          arcList.arcs.add(animatingArc);\n        } else {\n          animatingArc.datum = null;\n          animatingArc.domain = null;\n        }\n\n        // Update the set of arcs that still exist in the series data.\n        _currentKeys.add(arcKey);\n\n        // Get the arcElement we are going to setup.\n        // Optimization to prevent allocation in non-animating case.\n        final arcElement = ArcRendererElement<D>(\n          color: config.noDataColor,\n          startAngle: details.startAngle,\n          endAngle: details.endAngle,\n          series: series,\n        );\n\n        animatingArc.setNewTarget(arcElement);\n      } else {\n        var previousEndAngle = config.startAngle;\n\n        for (var arcIndex = 0; arcIndex < series.data.length; arcIndex++) {\n          final Object? datum = series.data[arcIndex];\n          final details = elementsList[arcIndex];\n          final domainValue = details.domain;\n\n          var arcKey = '${series.id}__$domainValue';\n\n          // If we already have an AnimatingArc for that index, use it.\n          var animatingArc =\n              arcList.arcs.firstWhereOrNull((arc) => arc.key == arcKey);\n\n          arcList.center = center;\n          arcList.radius = radius;\n          arcList.innerRadius = innerRadius;\n          arcList.series = series;\n          arcList.stroke = config.stroke;\n          arcList.strokeWidthPx = config.strokeWidthPx;\n\n          // If we don't have any existing arc element, create a new arc and\n          // have it animate in from the position of the previous arc's end\n          // angle. If there were no previous arcs, then animate everything in\n          // from 0.\n          if (animatingArc == null) {\n            animatingArc = AnimatedArc<D>(arcKey, datum, domainValue)\n              ..setNewTarget(ArcRendererElement<D>(\n                color: colorFn!(arcIndex),\n                startAngle: previousEndAngle,\n                endAngle: previousEndAngle,\n                index: arcIndex,\n                series: series,\n              ));\n\n            arcList.arcs.add(animatingArc);\n          } else {\n            animatingArc.datum = datum;\n\n            previousEndAngle = animatingArc.previousArcEndAngle ?? 0.0;\n          }\n\n          animatingArc.domain = domainValue;\n\n          // Update the set of arcs that still exist in the series data.\n          _currentKeys.add(arcKey);\n\n          // Get the arcElement we are going to setup.\n          // Optimization to prevent allocation in non-animating case.\n          final arcElement = ArcRendererElement<D>(\n            color: colorFn!(arcIndex),\n            startAngle: details.startAngle,\n            endAngle: details.endAngle,\n            index: arcIndex,\n            series: series,\n          );\n\n          animatingArc.setNewTarget(arcElement);\n        }\n      }\n    });\n\n    // Animate out arcs that don't exist anymore.\n    _seriesArcMap.forEach((String key, AnimatedArcList<D> arcList) {\n      for (var arcIndex = 0; arcIndex < arcList.arcs.length; arcIndex++) {\n        final arc = arcList.arcs[arcIndex];\n        final arcStartAngle = arc.previousArcStartAngle;\n\n        if (_currentKeys.contains(arc.key) != true) {\n          // Default to animating out to the top of the chart, clockwise, if\n          // there are no arcs that start past this arc.\n          var targetArcAngle = (2 * pi) + config.startAngle;\n\n          // Find the nearest start angle of the next arc that still exists in\n          // the data.\n          for (final nextArc\n              in arcList.arcs.where((arc) => _currentKeys.contains(arc.key))) {\n            final nextArcStartAngle = nextArc.newTargetArcStartAngle;\n\n            if (arcStartAngle! < nextArcStartAngle! &&\n                nextArcStartAngle < targetArcAngle) {\n              targetArcAngle = nextArcStartAngle;\n            }\n          }\n\n          arc.animateOut(targetArcAngle);\n        }\n      }\n    });\n  }\n\n  @override\n  void paint(ChartCanvas canvas, double animationPercent) {\n    // Clean up the arcs that no longer exist.\n    if (animationPercent == 1.0) {\n      final keysToRemove = <String>[];\n\n      _seriesArcMap.forEach((String key, AnimatedArcList<D> arcList) {\n        arcList.arcs.removeWhere((AnimatedArc<D> arc) => arc.animatingOut);\n\n        if (arcList.arcs.isEmpty) {\n          keysToRemove.add(key);\n        }\n      });\n\n      keysToRemove.forEach(_seriesArcMap.remove);\n    }\n    super.paint(canvas, animationPercent);\n  }\n\n  /// Assigns colors to series that are missing their colorFn.\n  @override\n  void assignMissingColors(Iterable<MutableSeries<D>> seriesList,\n      {required bool emptyCategoryUsesSinglePalette}) {\n    var maxMissing = 0;\n\n    seriesList.forEach((series) {\n      if (series.colorFn == null) {\n        maxMissing = max(maxMissing, series.data.length);\n      }\n    });\n\n    if (maxMissing > 0) {\n      final colorPalettes = StyleFactory.style.getOrderedPalettes(1);\n      final colorPalette = colorPalettes[0].makeShades(maxMissing);\n\n      seriesList.forEach((series) {\n        series.colorFn ??= (index) => colorPalette[index!];\n      });\n    }\n  }\n\n  /// Calculates the size of the inner pie radius given the outer radius.\n  double _calculateInnerRadius(double radius) {\n    // arcRatio trumps arcWidth. If neither is defined, then inner radius is 0.\n    if (config.arcRatio != null) {\n      return max(radius - radius * config.arcRatio!, 0.0).toDouble();\n    } else if (config.arcWidth != null) {\n      return max(radius - config.arcWidth!, 0.0).toDouble();\n    } else {\n      return 0.0;\n    }\n  }\n\n  @override\n  List<AnimatedArcList<D>> getArcLists({String? seriesId}) {\n    if (seriesId == null) {\n      return _seriesArcMap.values.toList();\n    }\n    final arcList = _seriesArcMap[seriesId];\n\n    if (arcList == null) return <AnimatedArcList<D>>[];\n    return [arcList];\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/pie/arc_renderer_config.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math' show pi;\n\nimport '../../common/symbol_renderer.dart';\nimport '../layout/layout_view.dart' show LayoutViewPaintOrder;\nimport 'arc_renderer.dart' show ArcRenderer;\nimport 'arc_renderer_decorator.dart' show ArcRendererDecorator;\nimport 'base_arc_renderer_config.dart' show BaseArcRendererConfig;\n\n/// Configuration for an [ArcRenderer].\nclass ArcRendererConfig<D> extends BaseArcRendererConfig<D> {\n  ArcRendererConfig(\n      {String? customRendererId,\n      double arcLength = 2 * pi,\n      List<ArcRendererDecorator<D>> arcRendererDecorators = const [],\n      double? arcRatio,\n      int? arcWidth,\n      int layoutPaintOrder = LayoutViewPaintOrder.arc,\n      int minHoleWidthForCenterContent = 30,\n      double startAngle = -pi / 2,\n      double strokeWidthPx = 2.0,\n      SymbolRenderer? symbolRenderer})\n      : super(\n            customRendererId: customRendererId,\n            arcLength: arcLength,\n            arcRatio: arcRatio,\n            arcWidth: arcWidth,\n            layoutPaintOrder: layoutPaintOrder,\n            minHoleWidthForCenterContent: minHoleWidthForCenterContent,\n            startAngle: startAngle,\n            strokeWidthPx: strokeWidthPx,\n            arcRendererDecorators: arcRendererDecorators);\n\n  @override\n  ArcRenderer<D> build() {\n    return ArcRenderer<D>(config: this, rendererId: customRendererId);\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/pie/arc_renderer_decorator.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math' show Rectangle;\n\nimport '../../common/graphics_factory.dart' show GraphicsFactory;\nimport '../common/chart_canvas.dart' show ChartCanvas;\nimport 'arc_renderer_element.dart' show ArcRendererElementList;\n\n/// Decorates arcs after the arcs have already been painted.\nabstract class ArcRendererDecorator<D> {\n  const ArcRendererDecorator();\n\n  /// Configures whether the decorator should be rendered on top of or below\n  /// series data elements.\n  bool get renderAbove;\n\n  void decorate(ArcRendererElementList<D> arcElements, ChartCanvas canvas,\n      GraphicsFactory graphicsFactory,\n      {required Rectangle drawBounds,\n      required double animationPercent,\n      bool rtl = false});\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/pie/arc_renderer_element.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'package:meta/meta.dart' show protected;\n\nimport 'dart:math' show Point;\nimport '../../common/color.dart' show Color;\nimport '../common/processed_series.dart' show ImmutableSeries;\nimport '../common/chart_canvas.dart' show getAnimatedColor;\n\nclass ArcRendererElementList<D> {\n  final List<ArcRendererElement<D>> arcs;\n  final Point<double> center;\n  final double innerRadius;\n  final double radius;\n  final double startAngle;\n\n  /// Color of separator lines between arcs.\n  final Color? stroke;\n\n  /// Stroke width of separator lines between arcs.\n  final double? strokeWidthPx;\n\n  ArcRendererElementList({\n    required this.arcs,\n    required this.center,\n    required this.innerRadius,\n    required this.radius,\n    required this.startAngle,\n    this.stroke,\n    this.strokeWidthPx,\n  });\n}\n\nclass ArcRendererElement<D> {\n  double startAngle;\n  double endAngle;\n  Color? color;\n  int? index;\n  num? key;\n  D? domain;\n  ImmutableSeries<D> series;\n\n  ArcRendererElement({\n    required this.startAngle,\n    required this.endAngle,\n    this.color,\n    this.index,\n    this.key,\n    this.domain,\n    required this.series,\n  });\n\n  ArcRendererElement<D> clone() {\n    return ArcRendererElement<D>(\n      startAngle: startAngle,\n      endAngle: endAngle,\n      color: color == null ? null : Color.fromOther(color: color!),\n      index: index,\n      key: key,\n      series: series,\n    );\n  }\n\n  void updateAnimationPercent(ArcRendererElement<D> previous,\n      ArcRendererElement<D> target, double animationPercent) {\n    startAngle =\n        ((target.startAngle - previous.startAngle) * animationPercent) +\n            previous.startAngle;\n\n    endAngle = ((target.endAngle - previous.endAngle) * animationPercent) +\n        previous.endAngle;\n\n    color = getAnimatedColor(previous.color!, target.color!, animationPercent);\n  }\n}\n\n@protected\nclass AnimatedArcList<D> {\n  final arcs = <AnimatedArc<D>>[];\n  Point<double>? center;\n  double? innerRadius;\n  double? radius;\n  ImmutableSeries<D>? series;\n\n  /// Color of separator lines between arcs.\n  Color? stroke;\n\n  /// Stroke width of separator lines between arcs.\n  double? strokeWidthPx;\n}\n\n@protected\nclass AnimatedArc<D> {\n  final String key;\n  Object? datum;\n  D? domain;\n\n  ArcRendererElement<D>? _previousArc;\n  late ArcRendererElement<D> _targetArc;\n  ArcRendererElement<D>? _currentArc;\n\n  // Flag indicating whether this arc is being animated out of the chart.\n  bool animatingOut = false;\n\n  AnimatedArc(this.key, this.datum, this.domain);\n\n  /// Animates a arc that was removed from the series out of the view.\n  ///\n  /// This should be called in place of \"setNewTarget\" for arcs that represent\n  /// data that has been removed from the series.\n  ///\n  /// Animates the angle of the arc to [endAngle], in radians.\n  void animateOut(double endAngle) {\n    var newTarget = _currentArc!.clone();\n\n    // Animate the arc out by setting the angles to 0.\n    newTarget.startAngle = endAngle;\n    newTarget.endAngle = endAngle;\n\n    setNewTarget(newTarget);\n    animatingOut = true;\n  }\n\n  void setNewTarget(ArcRendererElement<D> newTarget) {\n    animatingOut = false;\n    _currentArc ??= newTarget.clone();\n    _previousArc = _currentArc!.clone();\n    _targetArc = newTarget;\n  }\n\n  ArcRendererElement<D> getCurrentArc(double animationPercent) {\n    if (animationPercent == 1.0 || _previousArc == null) {\n      _currentArc = _targetArc;\n      _previousArc = _targetArc;\n      return _currentArc!;\n    }\n\n    _currentArc!\n        .updateAnimationPercent(_previousArc!, _targetArc, animationPercent);\n\n    return _currentArc!;\n  }\n\n  /// Returns the [startAngle] of the new target element, without updating\n  /// animation state.\n  double? get newTargetArcStartAngle => _targetArc.startAngle;\n\n  /// Returns the [endAngle] of the new target element, without updating\n  /// animation state.\n  double? get currentArcEndAngle => _currentArc?.endAngle;\n\n  /// Returns the [startAngle] of the currently rendered element, without\n  /// updating animation state.\n  double? get currentArcStartAngle => _currentArc?.startAngle;\n\n  /// Returns the [endAngle] of the new target element, without updating\n  /// animation state.\n  double? get previousArcEndAngle => _previousArc?.endAngle;\n\n  /// Returns the [startAngle] of the previously rendered element, without\n  /// updating animation state.\n  double? get previousArcStartAngle => _previousArc?.startAngle;\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/pie/base_arc_renderer.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math' show atan2, cos, sin, pi, Point, Rectangle;\n\nimport 'package:meta/meta.dart' show protected;\n\nimport '../../common/math.dart' show NullablePoint;\nimport '../../data/series.dart' show AttributeKey;\nimport '../common/base_chart.dart' show BaseChart;\nimport '../common/canvas_shapes.dart' show CanvasPieSlice, CanvasPie;\nimport '../common/chart_canvas.dart' show ChartCanvas;\nimport '../common/datum_details.dart' show DatumDetails;\nimport '../common/processed_series.dart' show MutableSeries;\nimport '../common/series_datum.dart' show SeriesDatum;\nimport '../common/series_renderer.dart' show BaseSeriesRenderer;\nimport 'arc_renderer_config.dart' show ArcRendererConfig;\nimport 'arc_renderer_decorator.dart' show ArcRendererDecorator;\nimport 'arc_renderer_element.dart'\n    show\n        ArcRendererElement,\n        ArcRendererElementList,\n        AnimatedArcList,\n        AnimatedArc;\nimport 'base_arc_renderer_config.dart' show BaseArcRendererConfig;\n\nconst arcElementsKey =\n    AttributeKey<List<ArcRendererElement<Object>>>('ArcRenderer.elements');\n\nabstract class BaseArcRenderer<D> extends BaseSeriesRenderer<D> {\n  // Constant used in the calculation of [centerContentBounds], calculated\n  // once to save runtime cost.\n  static final _cosPIOver4 = cos(pi / 4);\n\n  final BaseArcRendererConfig<D> config;\n\n  final List<ArcRendererDecorator<D>> arcRendererDecorators;\n\n  @protected\n  BaseChart<D>? chart;\n\n  BaseArcRenderer({required this.config, required String rendererId})\n      : arcRendererDecorators = config.arcRendererDecorators,\n        super(\n            rendererId: rendererId,\n            layoutPaintOrder: config.layoutPaintOrder,\n            symbolRenderer: config.symbolRenderer);\n\n  @override\n  void onAttach(BaseChart<D> chart) {\n    super.onAttach(chart);\n    this.chart = chart;\n  }\n\n  @override\n  void configureSeries(List<MutableSeries<D>> seriesList) {\n    assignMissingColors(seriesList, emptyCategoryUsesSinglePalette: false);\n  }\n\n  bool get isRtl => chart?.context.isRtl ?? false;\n\n  /// Gets a bounding box for the largest center content card that can fit\n  /// inside the hole of the chart.\n  ///\n  /// If the inner radius of the arcs is smaller than\n  /// [ArcRendererConfig.minHoleWidthForCenterContent], this will return a\n  /// rectangle of 0 width and height to indicate that no card can fit inside\n  /// the chart.\n  Rectangle<int> get centerContentBounds {\n    // Grab the first arcList from the animated set.\n    var arcLists = getArcLists();\n    var arcList = arcLists.isNotEmpty ? arcLists.first : null;\n\n    // No card should be visible if the hole in the chart is too small.\n    if (arcList == null ||\n        arcList.innerRadius! < config.minHoleWidthForCenterContent) {\n      // Return default bounds of 0 size.\n      final bounds = chart!.drawAreaBounds;\n      return Rectangle<int>((bounds.left + bounds.width / 2).round(),\n          (bounds.top + bounds.height / 2).round(), 0, 0);\n    }\n\n    // Fix the height and width of the center content div to the maximum box\n    // size that will fit within the pie's inner radius.\n    final width = (_cosPIOver4 * arcList.innerRadius!).floor();\n\n    return Rectangle<int>((arcList.center!.x - width).round(),\n        (arcList.center!.y - width).round(), width * 2, width * 2);\n  }\n\n  /// Returns an expanded [DatumDetails] object that contains location data.\n  DatumDetails<D> getExpandedDatumDetails(SeriesDatum<D> seriesDatum) {\n    final series = seriesDatum.series;\n    final Object? datum = seriesDatum.datum;\n    final datumIndex = seriesDatum.index;\n\n    final domain = series.domainFn(datumIndex);\n    final measure = series.measureFn(datumIndex);\n    final color = series.colorFn!(datumIndex);\n\n    final chartPosition = _getChartPosition(series.id, '${series.id}__$domain');\n\n    return DatumDetails(\n        datum: datum,\n        domain: domain,\n        measure: measure,\n        series: series,\n        color: color,\n        chartPosition: NullablePoint.from(chartPosition));\n  }\n\n  /// Returns the List of AnimatedArcList associated with the renderer. The Pie\n  /// Chart has one AnimatedArcList and the Sunburst chart usually has multiple\n  /// elements.\n  @protected\n  List<AnimatedArcList<D>> getArcLists({String? seriesId});\n\n  /// Returns the chart position for a given datum by series ID and domain\n  /// value.\n  ///\n  /// [seriesId] the series ID.\n  ///\n  /// [key] the key in the current animated arc list.\n  Point<double>? _getChartPosition(String seriesId, String key) {\n    Point<double>? chartPosition;\n\n    final arcLists = getArcLists(seriesId: seriesId);\n\n    if (arcLists.isEmpty) {\n      return chartPosition;\n    }\n\n    for (var arcList in arcLists) {\n      for (final arc in arcList.arcs) {\n        if (arc.key == key) {\n          // Now that we have found the matching arc, calculate the center\n          // point halfway between the inner and outer radius, and the start\n          // and end angles.\n          final centerAngle = arc.currentArcStartAngle! +\n              (arc.currentArcEndAngle! - arc.currentArcStartAngle!) / 2;\n\n          final centerPointRadius = arcList.innerRadius! +\n              (arcList.radius! - arcList.innerRadius!) / 2;\n\n          chartPosition = Point<double>(\n              centerPointRadius * cos(centerAngle) + arcList.center!.x,\n              centerPointRadius * sin(centerAngle) + arcList.center!.y);\n\n          break;\n        }\n      }\n    }\n\n    return chartPosition;\n  }\n\n  @override\n  void paint(ChartCanvas canvas, double animationPercent) {\n    final arcLists = getArcLists();\n    var arcListToElementsList = {};\n    for (var arcList in arcLists) {\n      final elementsList = ArcRendererElementList<D>(\n        arcs: <ArcRendererElement<D>>[],\n        center: arcList.center!,\n        innerRadius: arcList.innerRadius!,\n        radius: arcList.radius!,\n        startAngle: config.startAngle,\n        stroke: arcList.stroke,\n        strokeWidthPx: arcList.strokeWidthPx,\n      );\n\n      // Decorate the arcs with decorators that should appear below the main\n      // series data.\n      arcRendererDecorators\n          .where((decorator) => !decorator.renderAbove)\n          .forEach((decorator) {\n        decorator.decorate(elementsList, canvas, graphicsFactory!,\n            drawBounds: drawBounds!,\n            animationPercent: animationPercent,\n            rtl: isRtl);\n      });\n      arcListToElementsList[arcList] = elementsList;\n    }\n\n    for (var arcList in arcLists) {\n      final circleSectors = <CanvasPieSlice>[];\n\n      arcList.arcs\n          .map<ArcRendererElement<D>>((AnimatedArc<D> animatingArc) =>\n              animatingArc.getCurrentArc(animationPercent))\n          .forEach((arc) {\n        circleSectors\n            .add(CanvasPieSlice(arc.startAngle, arc.endAngle, fill: arc.color));\n\n        arcListToElementsList[arcList].arcs.add(arc);\n      });\n\n      // Draw the arcs.\n      canvas.drawPie(CanvasPie(\n          circleSectors, arcList.center!, arcList.radius!, arcList.innerRadius!,\n          stroke: arcList.stroke, strokeWidthPx: arcList.strokeWidthPx ?? 0));\n    }\n\n    // Decorate the arcs with decorators that should appear above the main\n    // series data. This is the typical place for labels.\n    for (var arcList in arcLists) {\n      arcRendererDecorators\n          .where((decorator) => decorator.renderAbove)\n          .forEach((decorator) {\n        decorator.decorate(\n            arcListToElementsList[arcList], canvas, graphicsFactory!,\n            drawBounds: drawBounds!,\n            animationPercent: animationPercent,\n            rtl: isRtl);\n      });\n    }\n  }\n\n  @override\n  List<DatumDetails<D>> getNearestDatumDetailPerSeries(\n    Point<double> chartPoint,\n    bool byDomain,\n    Rectangle<int>? boundsOverride, {\n    bool selectOverlappingPoints = false,\n    bool selectExactEventLocation = false,\n  }) {\n    final nearest = <DatumDetails<D>>[];\n\n    // Was it even in the component bounds?\n    if (!isPointWithinBounds(chartPoint, boundsOverride)) {\n      return nearest;\n    }\n\n    final arcLists = getArcLists();\n\n    for (var arcList in arcLists) {\n      if (arcList.series!.overlaySeries) {\n        return nearest;\n      }\n\n      final center = arcList.center!;\n      final innerRadius = arcList.innerRadius!;\n      final radius = arcList.radius!;\n\n      final distance = center.distanceTo(chartPoint);\n\n      // Calculate the angle of [chartPoint] from the center of the arcs.\n      var chartPointAngle =\n          atan2(chartPoint.y - center.y, chartPoint.x - center.x);\n\n      // atan2 returns NaN if we are at the exact center of the circle.\n      if (chartPointAngle.isNaN) {\n        chartPointAngle = config.startAngle;\n      }\n\n      // atan2 returns an angle in the range -PI..PI, from the positive x-axis.\n      // Our arcs start at the positive y-axis, in the range -PI/2..3PI/2. Thus,\n      // if angle is in the -x, +y section of the circle, we need to adjust the\n      // angle into our range.\n      if (chartPointAngle < config.startAngle && chartPointAngle < 0) {\n        chartPointAngle = 2 * pi + chartPointAngle;\n      }\n\n      arcList.arcs.forEach((AnimatedArc<D> arc) {\n        if (innerRadius <= distance &&\n            distance <= radius &&\n            arc.currentArcStartAngle! <= chartPointAngle &&\n            chartPointAngle <= arc.currentArcEndAngle!) {\n          nearest.add(DatumDetails<D>(\n            series: arcList.series,\n            datum: arc.datum,\n            domain: arc.domain,\n            domainDistance: 0.0,\n            measureDistance: 0.0,\n          ));\n        }\n      });\n    }\n\n    return nearest;\n  }\n\n  @override\n  DatumDetails<D> addPositionToDetailsForSeriesDatum(\n      DatumDetails<D> details, SeriesDatum<D> seriesDatum) {\n    final chartPosition =\n        _getChartPosition(details.series!.id, details.domain.toString());\n\n    return DatumDetails.from(details,\n        chartPosition: NullablePoint.from(chartPosition));\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/pie/base_arc_renderer_config.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math' show pi;\n\nimport '../../common/color.dart' show Color;\nimport '../../common/style/style_factory.dart' show StyleFactory;\nimport '../../common/symbol_renderer.dart';\nimport '../common/series_renderer_config.dart'\n    show RendererAttributes, SeriesRendererConfig;\nimport '../layout/layout_view.dart' show LayoutViewConfig, LayoutViewPaintOrder;\nimport 'arc_renderer_decorator.dart' show ArcRendererDecorator;\n\n/// The base renderer config for arc renderer and sunburst arc renderer.\nabstract class BaseArcRendererConfig<D> extends LayoutViewConfig\n    implements SeriesRendererConfig<D> {\n  @override\n  final String? customRendererId;\n\n  /// List of decorators applied to rendered arcs.\n  final List<ArcRendererDecorator<D>> arcRendererDecorators;\n\n  @override\n  final SymbolRenderer symbolRenderer;\n\n  @override\n  final rendererAttributes = RendererAttributes();\n\n  /// Total arc length, in radians.\n  ///\n  /// The default arcLength is 2π.\n  final double arcLength;\n\n  /// If set, configures the arcWidth to be a percentage of the radius.\n  final double? arcRatio;\n\n  /// Fixed width of the arc within the radius.\n  ///\n  /// If arcRatio is set, this value will be ignored.\n  final int? arcWidth;\n\n  /// The order to paint this renderer on the canvas.\n  final int layoutPaintOrder;\n\n  /// Minimum radius in pixels of the hole in a donut chart for center content\n  /// to appear.\n  final int minHoleWidthForCenterContent;\n\n  /// Start angle for pie slices, in radians.\n  ///\n  /// Angles are defined from the positive x axis in Cartesian space. The\n  /// default startAngle is -π/2.\n  final double startAngle;\n\n  /// Stroke width of the border of the arcs.\n  final double strokeWidthPx;\n\n  /// Stroke color of the border of the arcs.\n  final Color stroke;\n\n  /// Color of the \"no data\" state for the chart, used when an empty series is\n  /// drawn.\n  final Color noDataColor;\n\n  BaseArcRendererConfig(\n      {this.customRendererId,\n      this.arcLength = 2 * pi,\n      this.arcRendererDecorators = const [],\n      this.arcRatio,\n      this.arcWidth,\n      this.layoutPaintOrder = LayoutViewPaintOrder.arc,\n      this.minHoleWidthForCenterContent = 30,\n      this.startAngle = -pi / 2,\n      this.strokeWidthPx = 2.0,\n      SymbolRenderer? symbolRenderer})\n      : noDataColor = StyleFactory.style.noDataColor,\n        stroke = StyleFactory.style.arcStrokeColor,\n        symbolRenderer = symbolRenderer ?? CircleSymbolRenderer();\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/pie/pie_chart.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math' show Rectangle;\n\nimport '../common/base_chart.dart' show BaseChart;\nimport '../common/datum_details.dart' show DatumDetails;\nimport '../common/processed_series.dart' show MutableSeries;\nimport '../common/selection_model/selection_model.dart' show SelectionModelType;\nimport '../common/series_renderer.dart' show rendererIdKey, SeriesRenderer;\nimport '../layout/layout_config.dart' show LayoutConfig, MarginSpec;\nimport 'arc_renderer.dart' show ArcRenderer;\n\nclass PieChart<D> extends BaseChart<D> {\n  static final _defaultLayoutConfig = LayoutConfig(\n    topSpec: MarginSpec.fromPixel(minPixel: 20),\n    bottomSpec: MarginSpec.fromPixel(minPixel: 20),\n    leftSpec: MarginSpec.fromPixel(minPixel: 20),\n    rightSpec: MarginSpec.fromPixel(minPixel: 20),\n  );\n\n  PieChart({LayoutConfig? layoutConfig})\n      : super(layoutConfig: layoutConfig ?? _defaultLayoutConfig);\n\n  @override\n  void drawInternal(List<MutableSeries<D>> seriesList,\n      {bool? skipAnimation, bool? skipLayout}) {\n    if (seriesList.length > 1) {\n      throw ArgumentError('PieChart can only render a single series');\n    }\n    super.drawInternal(seriesList,\n        skipAnimation: skipAnimation, skipLayout: skipLayout);\n  }\n\n  @override\n  void updateConfig(LayoutConfig? layoutConfig) {\n    super.updateConfig(layoutConfig ?? _defaultLayoutConfig);\n  }\n\n  @override\n  SeriesRenderer<D> makeDefaultRenderer() {\n    return ArcRenderer<D>()..rendererId = SeriesRenderer.defaultRendererId;\n  }\n\n  /// Returns a list of datum details from selection model of [type].\n  @override\n  List<DatumDetails<D>> getDatumDetails(SelectionModelType type) {\n    final entries = <DatumDetails<D>>[];\n\n    for (final seriesDatum in getSelectionModel(type).selectedDatum) {\n      final rendererId = seriesDatum.series.getAttr(rendererIdKey);\n      final renderer = getSeriesRenderer(rendererId);\n\n      // This should never happen.\n      if (renderer is! ArcRenderer<D>) {\n        continue;\n      }\n\n      final details = renderer.getExpandedDatumDetails(seriesDatum);\n\n      if (details != null) {\n        entries.add(details);\n      }\n    }\n\n    return entries;\n  }\n\n  Rectangle<int>? get centerContentBounds {\n    final defaultRenderer = this.defaultRenderer;\n    if (defaultRenderer is ArcRenderer<D>) {\n      return defaultRenderer.centerContentBounds;\n    } else {\n      return null;\n    }\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/scatter_plot/comparison_points_decorator.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math' show Point, Rectangle;\n\nimport 'package:meta/meta.dart' show protected;\n\nimport '../../common/graphics_factory.dart' show GraphicsFactory;\nimport '../../common/symbol_renderer.dart';\nimport '../common/chart_canvas.dart' show ChartCanvas;\nimport 'point_renderer.dart' show PointRendererElement;\nimport 'point_renderer_decorator.dart' show PointRendererDecorator;\n\n/// Decorates a point chart by drawing a shape connecting the domain and measure\n/// data bounds.\n///\n/// The line will connect the point (domainLowerBound, measureLowerBound) to the\n/// point  (domainUpperBound, measureUpperBound).\nclass ComparisonPointsDecorator<D> extends PointRendererDecorator<D> {\n  /// Renderer used to draw the points. Defaults to a line with circular end\n  /// caps.\n  final PointSymbolRenderer symbolRenderer;\n\n  /// Render the bounds shape underneath series data.\n  @override\n  final bool renderAbove = false;\n\n  ComparisonPointsDecorator({PointSymbolRenderer? symbolRenderer})\n      : symbolRenderer = symbolRenderer ?? CylinderSymbolRenderer();\n\n  @override\n  void decorate(PointRendererElement<D> pointElement, ChartCanvas canvas,\n      GraphicsFactory graphicsFactory,\n      {required Rectangle drawBounds,\n      required double animationPercent,\n      bool rtl = false}) {\n    final points = computeBoundedPointsForElement(pointElement, drawBounds);\n\n    if (points == null) {\n      return;\n    }\n\n    final color = pointElement.color!.lighter;\n\n    symbolRenderer.paint(canvas, points[0], pointElement.boundsLineRadiusPx,\n        fillColor: color, strokeColor: color, p2: points[1]);\n  }\n\n  /// Computes end points for the [pointElement]'s lower and upper data bounds.\n  ///\n  /// This will compute two points representing the end points of the symbol,\n  /// from (xLower, yLower) to (xUpper, yUpper). The end points will be clamped\n  /// along the line so that it is fully contained within [drawBounds].\n  ///\n  /// Returns null if [pointElement] is missing any of the data bounds, or if\n  /// the line connecting them is located entirely outside of [drawBounds].\n  @protected\n  List<Point<double>>? computeBoundedPointsForElement(\n      PointRendererElement<D> pointElement, Rectangle drawBounds) {\n    // All bounds points must be defined for a valid comparison point to be\n    // drawn.\n    final point = pointElement.point!;\n    if (point.xLower == null ||\n        point.xUpper == null ||\n        point.yLower == null ||\n        point.yUpper == null) {\n      return null;\n    }\n\n    // Construct the points that describe our line p1p2.\n    var p1 = Point<double>(point.xLower!, point.yLower!);\n    var p2 = Point<double>(point.xUpper!, point.yUpper!);\n\n    // First check to see if there is no intersection at all between the line\n    // p1p2 and [drawBounds].\n    final dataBoundsRect = Rectangle<num>.fromPoints(p1, p2);\n    if (!drawBounds.intersects(dataBoundsRect)) {\n      return null;\n    }\n\n    // Line with end points [p1] and [p2].\n    final p1p2 = _Line.fromPoints(p1, p2);\n\n    // Next, slide p1 along the line p1p2 towards the edge of the draw area if\n    // the point is located outside of it.\n    if (!drawBounds.containsPoint(p1)) {\n      final p = _clampPointAlongLineToBoundingBox(p1, p1p2, drawBounds);\n      if (p != null) {\n        p1 = p;\n      }\n    }\n\n    // Next, slide p2 along the line p1p2 towards the edge of the draw area if\n    // the point is located outside of it.\n    if (!drawBounds.containsPoint(p2)) {\n      final p = _clampPointAlongLineToBoundingBox(p2, p1p2, drawBounds);\n      if (p != null) {\n        p2 = p;\n      }\n    }\n\n    return [p1, p2];\n  }\n\n  /// Slide the given point [p1] along the line [line], such that it intersects\n  /// the nearest edge of [bounds].\n  ///\n  /// This method assumes that we have already verified that the [line]\n  /// intercepts the [bounds] somewhere.\n  Point<double>? _clampPointAlongLineToBoundingBox(\n      Point<double> p1, _Line line, Rectangle<num> bounds) {\n    // The top and bottom edges of the bounds box describe two horizontal lines,\n    // with equations y = bounds.top and y = bounds.bottom. We can pass these\n    // into a standard line interception method to find our point.\n    if (p1.y < bounds.top) {\n      final p = line.intersection(_Line(0.0, bounds.top.toDouble()));\n      if (p != null && bounds.containsPoint(p)) {\n        return p;\n      }\n    }\n\n    if (p1.y > bounds.bottom) {\n      final p = line.intersection(_Line(0.0, bounds.bottom.toDouble()));\n      if (p != null && bounds.containsPoint(p)) {\n        return p;\n      }\n    }\n\n    // The left and right edges of the bounds box describe two vertical lines,\n    // with equations x = bounds.right and x = bounds.left. To find the\n    // intersection, we just need to solve for y in our line described by\n    // [slope] and [yIntercept]:\n    //\n    // y = slope * x + yIntercept\n    if (p1.x < bounds.left) {\n      final p = line.intersection(_Line.fromVertical(bounds.left.toDouble()));\n      if (p != null && bounds.containsPoint(p)) {\n        return p;\n      }\n    }\n\n    if (p1.x > bounds.right) {\n      final p = line.intersection(_Line.fromVertical(bounds.right.toDouble()));\n      if (p != null && bounds.containsPoint(p)) {\n        return p;\n      }\n    }\n\n    return null;\n  }\n}\n\n/// Describes a simple line with the equation y = slope * x + yIntercept.\nclass _Line {\n  /// Slope of the line.\n  double? slope;\n\n  /// y-intercept of the line (i.e. the y value of the point where the line\n  /// intercepts the y axis).\n  double? yIntercept;\n\n  /// x-intercept of the line (i.e. the x value of the point where the line\n  /// intercepts the x axis). This is normally only needed for vertical lines,\n  /// which have no slope.\n  double? xIntercept;\n\n  /// True if this line is a vertical line, of the form x = [xIntercept].\n  bool get vertical => slope == null && xIntercept != null;\n\n  _Line(this.slope, this.yIntercept, [this.xIntercept]);\n\n  /// Creates a line with end points [p1] and [p2].\n  factory _Line.fromPoints(Point<num> p1, Point<num> p2) {\n    // Handle vertical lines.\n    if (p1.x == p2.x) {\n      return _Line.fromVertical(p1.x);\n    }\n\n    // Slope of the line p1p2.\n    final m = ((p2.y - p1.y) / (p2.x - p1.x)).toDouble();\n\n    // y-intercept of the line p1p2.\n    final b = (p1.y - (m * p1.x)).toDouble();\n\n    return _Line(m, b);\n  }\n\n  /// Creates a vertical line, with the question x = [xIntercept].\n  factory _Line.fromVertical(num xIntercept) {\n    return _Line(null, null, xIntercept.toDouble());\n  }\n\n  /// Computes the intersection of `this` and [other].\n  ///\n  /// Returns the intersection of this and `other`, or `null` if they don't\n  /// intersect.\n  Point<double>? intersection(_Line other) {\n    // Parallel lines have no intersection.\n    if (slope == other.slope || (vertical && other.vertical)) {\n      return null;\n    }\n\n    // If the other line is a vertical line (has undefined slope), then we can\n    // just plug its xIntercept value into the line equation as x and solve for\n    // y.\n    if (other.vertical) {\n      return Point<double>(\n          other.xIntercept!, slope! * other.xIntercept! + yIntercept!);\n    }\n\n    // If this line is a vertical line (has undefined slope), then we can just\n    // plug its xIntercept value into the line equation as x and solve for y.\n    if (vertical) {\n      return Point<double>(\n          xIntercept!, other.slope! * xIntercept! + other.yIntercept!);\n    }\n\n    // Now that we know that we have intersecting, non-vertical lines, compute\n    // the intersection.\n    final x = (other.yIntercept! - yIntercept!) / (slope! - other.slope!);\n\n    final y =\n        slope! * (other.yIntercept! - yIntercept!) / (slope! - other.slope!) +\n            yIntercept!;\n\n    return Point<double>(x, y);\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/scatter_plot/point_renderer.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:collection' show LinkedHashMap;\nimport 'dart:math' show min, Point, Rectangle;\n\nimport 'package:collection/collection.dart' show IterableExtension;\nimport 'package:meta/meta.dart' show protected;\nimport 'package:vector_math/vector_math.dart' show Vector2;\n\nimport '../../common/color.dart' show Color;\nimport '../../common/math.dart'\n    show distanceBetweenPointAndLineSegment, NullablePoint;\nimport '../../common/symbol_renderer.dart'\n    show CircleSymbolRenderer, SymbolRenderer;\nimport '../../data/series.dart' show AccessorFn, AttributeKey, TypedAccessorFn;\nimport '../cartesian/axis/axis.dart'\n    show ImmutableAxis, domainAxisKey, measureAxisKey;\nimport '../cartesian/cartesian_renderer.dart' show BaseCartesianRenderer;\nimport '../common/base_chart.dart' show BaseChart;\nimport '../common/chart_canvas.dart' show ChartCanvas, getAnimatedColor;\nimport '../common/datum_details.dart' show DatumDetails;\nimport '../common/processed_series.dart' show ImmutableSeries, MutableSeries;\nimport '../common/series_datum.dart' show SeriesDatum;\nimport '../layout/layout_view.dart' show LayoutViewPaintOrder;\nimport 'comparison_points_decorator.dart' show ComparisonPointsDecorator;\nimport 'point_renderer_config.dart' show PointRendererConfig;\nimport 'point_renderer_decorator.dart' show PointRendererDecorator;\n\nconst pointElementsKey =\n    AttributeKey<List<PointRendererElement<Object>>>('PointRenderer.elements');\n\nconst pointSymbolRendererFnKey =\n    AttributeKey<AccessorFn<String>>('PointRenderer.symbolRendererFn');\n\nconst pointSymbolRendererIdKey =\n    AttributeKey<String>('PointRenderer.symbolRendererId');\n\n/// Defines a fixed radius for data bounds lines (typically drawn by attaching a\n/// [ComparisonPointsDecorator] to the renderer.\nconst boundsLineRadiusPxKey =\n    AttributeKey<double>('SymbolAnnotationRenderer.boundsLineRadiusPx');\n\n/// Defines an [AccessorFn] for the radius for data bounds lines (typically\n/// drawn by attaching a [ComparisonPointsDecorator] to the renderer.\nconst boundsLineRadiusPxFnKey = AttributeKey<AccessorFn<double?>>(\n    'SymbolAnnotationRenderer.boundsLineRadiusPxFn');\n\nconst defaultSymbolRendererId = '__default__';\n\n/// Large number used as a starting sentinel for data distance comparisons.\n///\n/// This is generally larger than the distance from any datum to the mouse.\nconst _maxInitialDistance = 10000.0;\n\nclass PointRenderer<D> extends BaseCartesianRenderer<D> {\n  final PointRendererConfig<D> config;\n\n  final List<PointRendererDecorator<D>> pointRendererDecorators;\n\n  BaseChart<D>? _chart;\n\n  /// Store a map of series drawn on the chart, mapped by series name.\n  ///\n  /// [LinkedHashMap] is used to render the series on the canvas in the same\n  /// order as the data was given to the chart.\n  @protected\n  // ignore: prefer_collection_literals, https://github.com/dart-lang/linter/issues/1649\n  var seriesPointMap = LinkedHashMap<String, List<AnimatedPoint<D>>>();\n\n  // Store a list of lines that exist in the series data.\n  //\n  // This list will be used to remove any [_AnimatedPoint] that were rendered in\n  // previous draw cycles, but no longer have a corresponding datum in the new\n  // data.\n  final _currentKeys = <String>[];\n\n  PointRenderer({String? rendererId, PointRendererConfig<D>? config})\n      : config = config ?? PointRendererConfig<D>(),\n        pointRendererDecorators = config?.pointRendererDecorators ?? [],\n        super(\n            rendererId: rendererId ?? 'point',\n            layoutPaintOrder:\n                config?.layoutPaintOrder ?? LayoutViewPaintOrder.point,\n            symbolRenderer: config?.symbolRenderer ?? CircleSymbolRenderer());\n\n  @override\n  void configureSeries(List<MutableSeries<D>> seriesList) {\n    assignMissingColors(seriesList, emptyCategoryUsesSinglePalette: false);\n  }\n\n  @override\n  void preprocessSeries(List<MutableSeries<D>> seriesList) {\n    seriesList.forEach((MutableSeries<D> series) {\n      final elements = <PointRendererElement<D>>[];\n\n      // Default to the configured radius if none was defined by the series.\n      series.radiusPxFn ??= (_) => config.radiusPx;\n\n      // Create an accessor function for the bounds line radius, if needed. If\n      // the series doesn't define an accessor function, then each datum's\n      // boundsLineRadiusPx value will be filled in by using the following\n      // values, in order of what is defined:\n      //\n      // 1) boundsLineRadiusPx defined on the series.\n      // 2) boundsLineRadiusPx defined on the renderer config.\n      // 3) Final fallback is to use the point radiusPx for this datum.\n      var boundsLineRadiusPxFn = series.getAttr(boundsLineRadiusPxFnKey);\n\n      if (boundsLineRadiusPxFn == null) {\n        var boundsLineRadiusPx = series.getAttr(boundsLineRadiusPxKey);\n        boundsLineRadiusPx ??= config.boundsLineRadiusPx;\n        if (boundsLineRadiusPx != null) {\n          boundsLineRadiusPxFn = (_) => boundsLineRadiusPx!.toDouble();\n          series.setAttr(boundsLineRadiusPxFnKey, boundsLineRadiusPxFn);\n        }\n      }\n\n      final symbolRendererFn = series.getAttr(pointSymbolRendererFnKey);\n\n      // Add a key function to help animate points moved in position in the\n      // series data between chart draw cycles. Ideally we should require the\n      // user to provide a key function, but this at least provides some\n      // smoothing when adding/removing data.\n      series.keyFn ??=\n          (int? index) => '${series.id}__${series.domainFn(index)}__'\n              '${series.measureFn(index)}';\n\n      for (var index = 0; index < series.data.length; index++) {\n        // Default to the configured radius if none was returned by the\n        // accessor function.\n        var radiusPx = series.radiusPxFn!(index);\n        radiusPx ??= config.radiusPx;\n\n        num? boundsLineRadiusPx;\n        if (boundsLineRadiusPxFn != null) {\n          boundsLineRadiusPx = (boundsLineRadiusPxFn is TypedAccessorFn)\n              ? (boundsLineRadiusPxFn as TypedAccessorFn<dynamic, int>)(\n                  series.data[index], index)\n              : boundsLineRadiusPxFn(index);\n        }\n        boundsLineRadiusPx ??= config.boundsLineRadiusPx;\n        boundsLineRadiusPx ??= radiusPx;\n\n        // Default to the configured stroke width if none was returned by the\n        // accessor function.\n        var strokeWidthPx = series.strokeWidthPxFn != null\n            ? series.strokeWidthPxFn!(index)\n            : null;\n        strokeWidthPx ??= config.strokeWidthPx;\n\n        // Get the ID of the [SymbolRenderer] for this point. An ID may be\n        // specified on the datum, or on the series. If neither is specified,\n        // fall back to the default.\n        String? symbolRendererId;\n        if (symbolRendererFn != null) {\n          symbolRendererId = symbolRendererFn(index);\n        }\n        symbolRendererId ??= series.getAttr(pointSymbolRendererIdKey);\n        symbolRendererId ??= defaultSymbolRendererId;\n\n        // Get the colors. If no fill color is provided, default it to the\n        // primary data color.\n        final colorFn = series.colorFn;\n        final fillColorFn = series.fillColorFn ?? colorFn;\n\n        final color = colorFn!(index);\n\n        // Fill color is an optional override for color. Make sure we get a\n        // value if the series doesn't define anything specific.\n        var fillColor = fillColorFn!(index);\n        fillColor ??= color;\n\n        final details = PointRendererElement<D>(\n          index: index,\n          color: color,\n          fillColor: fillColor,\n          radiusPx: radiusPx.toDouble(),\n          boundsLineRadiusPx: boundsLineRadiusPx.toDouble(),\n          strokeWidthPx: strokeWidthPx.toDouble(),\n          symbolRendererId: symbolRendererId,\n        );\n\n        elements.add(details);\n      }\n\n      series.setAttr(pointElementsKey, elements);\n    });\n  }\n\n  @override\n  void update(List<ImmutableSeries<D>> seriesList, bool isAnimatingThisDraw) {\n    _currentKeys.clear();\n\n    // Build a list of sorted series IDs as we iterate through the list, used\n    // later for sorting.\n    final sortedSeriesIds = <String>[];\n\n    seriesList.forEach((ImmutableSeries<D> series) {\n      sortedSeriesIds.add(series.id);\n\n      final domainAxis = series.getAttr(domainAxisKey) as ImmutableAxis<D>;\n      final domainFn = series.domainFn;\n      final domainLowerBoundFn = series.domainLowerBoundFn;\n      final domainUpperBoundFn = series.domainUpperBoundFn;\n      final measureAxis = series.getAttr(measureAxisKey) as ImmutableAxis<num>;\n      final measureFn = series.measureFn;\n      final measureLowerBoundFn = series.measureLowerBoundFn;\n      final measureUpperBoundFn = series.measureUpperBoundFn;\n      final measureOffsetFn = series.measureOffsetFn;\n      final seriesKey = series.id;\n      final keyFn = series.keyFn!;\n\n      var pointList = seriesPointMap.putIfAbsent(seriesKey, () => []);\n\n      var elementsList = series.getAttr(pointElementsKey);\n\n      for (var index = 0; index < series.data.length; index++) {\n        final Object? datum = series.data[index];\n        final details = elementsList![index];\n\n        final domainValue = domainFn(index);\n        final domainLowerBoundValue = domainLowerBoundFn?.call(index);\n        final domainUpperBoundValue = domainUpperBoundFn?.call(index);\n\n        final measureValue = measureFn(index);\n        final measureLowerBoundValue = measureLowerBoundFn?.call(index);\n        final measureUpperBoundValue = measureUpperBoundFn?.call(index);\n        final measureOffsetValue = measureOffsetFn!(index);\n\n        // Create a new point using the final location.\n        final point = getPoint(\n            datum,\n            domainValue,\n            domainLowerBoundValue,\n            domainUpperBoundValue,\n            series,\n            domainAxis,\n            measureValue,\n            measureLowerBoundValue,\n            measureUpperBoundValue,\n            measureOffsetValue,\n            measureAxis);\n\n        final pointKey = keyFn(index);\n\n        // If we already have an AnimatingPoint for that index, use it.\n        var animatingPoint =\n            pointList.firstWhereOrNull((point) => point.key == pointKey);\n\n        // If we don't have any existing arc element, create a new arc and\n        // have it animate in from the position of the previous arc's end\n        // angle. If there were no previous arcs, then animate everything in\n        // from 0.\n        if (animatingPoint == null) {\n          // Create a new point and have it animate in from axis.\n          final point = getPoint(\n              datum,\n              domainValue,\n              domainLowerBoundValue,\n              domainUpperBoundValue,\n              series,\n              domainAxis,\n              0.0,\n              0.0,\n              0.0,\n              0.0,\n              measureAxis);\n\n          animatingPoint = AnimatedPoint<D>(\n              key: pointKey, overlaySeries: series.overlaySeries)\n            ..setNewTarget(PointRendererElement<D>(\n              index: details.index,\n              color: details.color,\n              fillColor: details.fillColor,\n              measureAxisPosition: measureAxis.getLocation(0.0),\n              point: point,\n              radiusPx: details.radiusPx,\n              boundsLineRadiusPx: details.boundsLineRadiusPx,\n              strokeWidthPx: details.strokeWidthPx,\n              symbolRendererId: details.symbolRendererId,\n            ));\n\n          pointList.add(animatingPoint);\n        }\n\n        // Update the set of arcs that still exist in the series data.\n        _currentKeys.add(pointKey);\n\n        // Get the pointElement we are going to setup.\n        final pointElement = PointRendererElement<D>(\n          index: index,\n          color: details.color,\n          fillColor: details.fillColor,\n          measureAxisPosition: measureAxis.getLocation(0.0),\n          point: point,\n          radiusPx: details.radiusPx,\n          boundsLineRadiusPx: details.boundsLineRadiusPx,\n          strokeWidthPx: details.strokeWidthPx,\n          symbolRendererId: details.symbolRendererId,\n        );\n\n        animatingPoint.setNewTarget(pointElement);\n      }\n    });\n\n    // Sort the renderer elements to be in the same order as the series list.\n    // They may get disordered between chart draw cycles if a behavior adds or\n    // removes series from the list (e.g. click to hide on legends).\n    seriesPointMap = LinkedHashMap<String, List<AnimatedPoint<D>>>.fromIterable(\n        sortedSeriesIds,\n        key: (dynamic k) => k as String,\n        value: (dynamic k) => seriesPointMap[k]!);\n\n    // Animate out points that don't exist anymore.\n    seriesPointMap.forEach((String key, List<AnimatedPoint<D>> points) {\n      for (var point in points) {\n        if (_currentKeys.contains(point.key) != true) {\n          point.animateOut();\n        }\n      }\n    });\n  }\n\n  @override\n  void onAttach(BaseChart<D> chart) {\n    super.onAttach(chart);\n    // We only need the chart.context.isRtl setting, but context is not yet\n    // available when the default renderer is attached to the chart on chart\n    // creation time, since chart onInit is called after the chart is created.\n    _chart = chart;\n  }\n\n  @override\n  void paint(ChartCanvas canvas, double animationPercent) {\n    // Clean up the points that no longer exist.\n    if (animationPercent == 1.0) {\n      final keysToRemove = <String>[];\n\n      seriesPointMap.forEach((String key, List<AnimatedPoint<D>> points) {\n        points.removeWhere((AnimatedPoint<D> point) => point.animatingOut);\n\n        if (points.isEmpty) {\n          keysToRemove.add(key);\n        }\n      });\n\n      keysToRemove.forEach(seriesPointMap.remove);\n    }\n\n    seriesPointMap.forEach((String key, List<AnimatedPoint<D>> points) {\n      points\n          .map<PointRendererElement<D>>((AnimatedPoint<D> animatingPoint) =>\n              animatingPoint.getCurrentPoint(animationPercent))\n          .forEach((point) {\n        // Decorate the points with decorators that should appear below the main\n        // series data.\n        pointRendererDecorators\n            .where((decorator) => !decorator.renderAbove)\n            .forEach((decorator) {\n          decorator.decorate(point, canvas, graphicsFactory!,\n              drawBounds: componentBounds!,\n              animationPercent: animationPercent,\n              rtl: isRtl);\n        });\n\n        // Skip points whose center lies outside the draw bounds. Those that lie\n        // near the edge will be allowed to render partially outside. This\n        // prevents harshly clipping off half of the shape.\n        if (point.point!.y != null &&\n            componentBounds!.containsPoint(point.point!.toPoint())) {\n          final bounds = Rectangle<double>(\n              point.point!.x! - point.radiusPx,\n              point.point!.y! - point.radiusPx,\n              point.radiusPx * 2,\n              point.radiusPx * 2);\n\n          if (point.symbolRendererId == defaultSymbolRendererId) {\n            symbolRenderer!.paint(canvas, bounds,\n                fillColor: point.fillColor,\n                strokeColor: point.color,\n                strokeWidthPx: point.strokeWidthPx);\n          } else {\n            final id = point.symbolRendererId;\n            if (!config.customSymbolRenderers!.containsKey(id)) {\n              throw ArgumentError('Invalid custom symbol renderer id \"${id}\"');\n            }\n\n            final customRenderer = config.customSymbolRenderers![id]!;\n            customRenderer.paint(canvas, bounds,\n                fillColor: point.fillColor,\n                strokeColor: point.color,\n                strokeWidthPx: point.strokeWidthPx);\n          }\n        }\n\n        // Decorate the points with decorators that should appear above the main\n        // series data. This is the typical place for labels.\n        pointRendererDecorators\n            .where((decorator) => decorator.renderAbove)\n            .forEach((decorator) {\n          decorator.decorate(point, canvas, graphicsFactory!,\n              drawBounds: componentBounds!,\n              animationPercent: animationPercent,\n              rtl: isRtl);\n        });\n      });\n    });\n  }\n\n  bool get isRtl => _chart?.context.isRtl ?? false;\n\n  @protected\n  DatumPoint<D> getPoint(\n      Object? datum,\n      D? domainValue,\n      D? domainLowerBoundValue,\n      D? domainUpperBoundValue,\n      ImmutableSeries<D> series,\n      ImmutableAxis<D> domainAxis,\n      num? measureValue,\n      num? measureLowerBoundValue,\n      num? measureUpperBoundValue,\n      num? measureOffsetValue,\n      ImmutableAxis<num> measureAxis) {\n    final domainPosition = domainAxis.getLocation(domainValue);\n\n    final domainLowerBoundPosition = domainLowerBoundValue != null\n        ? domainAxis.getLocation(domainLowerBoundValue)\n        : null;\n\n    final domainUpperBoundPosition = domainUpperBoundValue != null\n        ? domainAxis.getLocation(domainUpperBoundValue)\n        : null;\n\n    final measurePosition = measureValue != null && measureOffsetValue != null\n        ? measureAxis.getLocation(measureValue + measureOffsetValue)\n        : null;\n\n    final measureLowerBoundPosition = measureLowerBoundValue != null\n        ? measureAxis.getLocation(measureLowerBoundValue + measureOffsetValue!)\n        : null;\n\n    final measureUpperBoundPosition = measureUpperBoundValue != null\n        ? measureAxis.getLocation(measureUpperBoundValue + measureOffsetValue!)\n        : null;\n\n    return DatumPoint<D>(\n        datum: datum,\n        domain: domainValue,\n        series: series,\n        x: domainPosition,\n        xLower: domainLowerBoundPosition,\n        xUpper: domainUpperBoundPosition,\n        y: measurePosition,\n        yLower: measureLowerBoundPosition,\n        yUpper: measureUpperBoundPosition);\n  }\n\n  @override\n  List<DatumDetails<D>> getNearestDatumDetailPerSeries(\n    Point<double> chartPoint,\n    bool byDomain,\n    Rectangle<int>? boundsOverride, {\n    bool selectOverlappingPoints = false,\n    bool selectExactEventLocation = false,\n  }) {\n    final nearest = <DatumDetails<D>>[];\n    final inside = <DatumDetails<D>>[];\n\n    // Was it even in the component bounds?\n    if (!isPointWithinBounds(chartPoint, boundsOverride)) {\n      return nearest;\n    }\n\n    seriesPointMap.values.forEach((List<AnimatedPoint<D>> points) {\n      PointRendererElement<D>? nearestPoint;\n\n      var nearestDistances = _Distances(\n          domainDistance: _maxInitialDistance,\n          measureDistance: _maxInitialDistance,\n          relativeDistance: _maxInitialDistance);\n\n      points.forEach((point) {\n        if (point.overlaySeries) {\n          return;\n        }\n\n        final p = point._currentPoint!.point!;\n\n        // Don't look at points not in the drawArea.\n        if (p.x! < componentBounds!.left || p.x! > componentBounds!.right) {\n          return;\n        }\n\n        final distances = _getDatumDistance(point, chartPoint);\n\n        if (selectOverlappingPoints) {\n          if (distances.insidePoint!) {\n            inside.add(_createDatumDetails(point._currentPoint!, distances));\n          }\n        }\n\n        // If any point was added to the inside list on previous iterations,\n        // we don't need to go through calculating nearest points because we\n        // only return inside list as a result in that case.\n        if (inside.isEmpty) {\n          // Do not consider the points outside event location when\n          // selectExactEventLocation flag is set.\n          if (!selectExactEventLocation || distances.insidePoint!) {\n            if (byDomain) {\n              if ((distances.domainDistance <\n                      nearestDistances.domainDistance) ||\n                  (distances.domainDistance ==\n                          nearestDistances.domainDistance &&\n                      distances.measureDistance <\n                          nearestDistances.measureDistance)) {\n                nearestPoint = point._currentPoint;\n                nearestDistances = distances;\n              }\n            } else {\n              if (distances.relativeDistance <\n                  nearestDistances.relativeDistance) {\n                nearestPoint = point._currentPoint;\n                nearestDistances = distances;\n              }\n            }\n          }\n        }\n      });\n\n      // Found a point, add it to the list.\n      if (nearestPoint != null) {\n        nearest.add(_createDatumDetails(nearestPoint!, nearestDistances));\n      }\n    });\n\n    // Note: the details are already sorted by domain & measure distance in\n    // base chart. If asking for all overlapping points, return the list of\n    // inside points - only if there was overlap.\n    return (selectOverlappingPoints && inside.isNotEmpty) ? inside : nearest;\n  }\n\n  DatumDetails<D> _createDatumDetails(\n      PointRendererElement<D> point, _Distances distances) {\n    SymbolRenderer? pointSymbolRenderer;\n    if (point.symbolRendererId == defaultSymbolRendererId) {\n      pointSymbolRenderer = symbolRenderer;\n    } else {\n      final id = point.symbolRendererId;\n      if (!config.customSymbolRenderers!.containsKey(id)) {\n        throw ArgumentError('Invalid custom symbol renderer id \"${id}\"');\n      }\n      pointSymbolRenderer = config.customSymbolRenderers![id];\n    }\n    return DatumDetails<D>(\n        datum: point.point!.datum,\n        domain: point.point!.domain,\n        series: point.point!.series,\n        domainDistance: distances.domainDistance,\n        measureDistance: distances.measureDistance,\n        relativeDistance: distances.relativeDistance,\n        symbolRenderer: pointSymbolRenderer);\n  }\n\n  /// Returns a struct containing domain, measure, and relative distance between\n  /// a datum and a point within the chart.\n  _Distances _getDatumDistance(\n      AnimatedPoint<D> point, Point<double> chartPoint) {\n    final datumPoint = point._currentPoint!.point!;\n    final radiusPx = point._currentPoint!.radiusPx;\n    final boundsLineRadiusPx = point._currentPoint!.boundsLineRadiusPx;\n\n    // Compute distances from [chartPoint] to the primary point of the datum.\n    final domainDistance = (chartPoint.x - datumPoint.x!).abs();\n\n    final measureDistance = datumPoint.y != null\n        ? (chartPoint.y - datumPoint.y!).abs()\n        : _maxInitialDistance;\n\n    var relativeDistance = datumPoint.y != null\n        ? chartPoint.distanceTo(datumPoint.toPoint())\n        : _maxInitialDistance;\n\n    var insidePoint = false;\n\n    if (datumPoint.xLower != null &&\n        datumPoint.xUpper != null &&\n        datumPoint.yLower != null &&\n        datumPoint.yUpper != null) {\n      // If we have data bounds, compute the relative distance between\n      // [chartPoint] and the nearest point of the data bounds element. We will\n      // use the smaller of this distance and the distance from the primary\n      // point as the relativeDistance from this datum.\n      final relativeDistanceBounds = distanceBetweenPointAndLineSegment(\n          Vector2(chartPoint.x, chartPoint.y),\n          Vector2(datumPoint.xLower!, datumPoint.yLower!),\n          Vector2(datumPoint.xUpper!, datumPoint.yUpper!));\n\n      insidePoint = (relativeDistance < radiusPx) ||\n          (boundsLineRadiusPx != null &&\n              // This may be inaccurate if the symbol is drawn without end caps.\n              relativeDistanceBounds < boundsLineRadiusPx);\n\n      // Keep the smaller relative distance after we have determined whether\n      // [chartPoint] is located inside the datum.\n      relativeDistance = min(relativeDistance, relativeDistanceBounds);\n    } else {\n      insidePoint = relativeDistance < radiusPx;\n    }\n\n    return _Distances(\n      domainDistance: domainDistance,\n      measureDistance: measureDistance,\n      relativeDistance: relativeDistance,\n      insidePoint: insidePoint,\n    );\n  }\n\n  @override\n  DatumDetails<D> addPositionToDetailsForSeriesDatum(\n      DatumDetails<D> details, SeriesDatum<D> seriesDatum) {\n    final series = details.series!;\n\n    final domainAxis = series.getAttr(domainAxisKey) as ImmutableAxis<D>;\n    final measureAxis = series.getAttr(measureAxisKey) as ImmutableAxis<num>;\n\n    final point = getPoint(\n        seriesDatum.datum,\n        details.domain,\n        details.domainLowerBound,\n        details.domainUpperBound,\n        series,\n        domainAxis,\n        details.measure,\n        details.measureLowerBound,\n        details.measureUpperBound,\n        details.measureOffset,\n        measureAxis);\n\n    final symbolRendererFn = series.getAttr(pointSymbolRendererFnKey);\n\n    // Get the ID of the [SymbolRenderer] for this point. An ID may be\n    // specified on the datum, or on the series. If neither is specified,\n    // fall back to the default.\n    String? symbolRendererId;\n    if (symbolRendererFn != null) {\n      symbolRendererId = symbolRendererFn(details.index);\n    }\n    symbolRendererId ??= series.getAttr(pointSymbolRendererIdKey);\n    symbolRendererId ??= defaultSymbolRendererId;\n\n    // Now that we have the ID, get the configured [SymbolRenderer].\n    SymbolRenderer? nearestSymbolRenderer;\n    if (symbolRendererId == defaultSymbolRendererId) {\n      nearestSymbolRenderer = symbolRenderer;\n    } else {\n      final id = symbolRendererId;\n      if (!config.customSymbolRenderers!.containsKey(id)) {\n        throw ArgumentError('Invalid custom symbol renderer id \"${id}\"');\n      }\n\n      nearestSymbolRenderer = config.customSymbolRenderers![id];\n    }\n\n    return DatumDetails.from(details,\n        chartPosition: NullablePoint(point.x, point.y),\n        chartPositionLower: NullablePoint(point.xLower, point.yLower),\n        chartPositionUpper: NullablePoint(point.xUpper, point.yUpper),\n        symbolRenderer: nearestSymbolRenderer);\n  }\n}\n\nclass DatumPoint<D> extends NullablePoint {\n  final Object? datum;\n  final D? domain;\n  final ImmutableSeries<D>? series;\n\n  // Coordinates for domain bounds.\n  final double? xLower;\n  final double? xUpper;\n\n  // Coordinates for measure bounds.\n  final double? yLower;\n  final double? yUpper;\n\n  DatumPoint({\n    this.datum,\n    this.domain,\n    this.series,\n    required double? x,\n    required this.xLower,\n    required this.xUpper,\n    required double? y,\n    required this.yLower,\n    required this.yUpper,\n  }) : super(x, y);\n\n  factory DatumPoint.from(DatumPoint<D> other,\n      {double? x,\n      double? xLower,\n      double? xUpper,\n      double? y,\n      double? yLower,\n      double? yUpper}) {\n    return DatumPoint<D>(\n        datum: other.datum,\n        domain: other.domain,\n        series: other.series,\n        x: x ?? other.x,\n        xLower: xLower ?? other.xLower,\n        xUpper: xUpper ?? other.xUpper,\n        y: y ?? other.y,\n        yLower: yLower ?? other.yLower,\n        yUpper: yUpper ?? other.yUpper);\n  }\n}\n\nclass PointRendererElement<D> {\n  DatumPoint<D>? point;\n  int? index;\n  Color? color;\n  Color? fillColor;\n  double? measureAxisPosition;\n  double radiusPx;\n  double boundsLineRadiusPx;\n  double strokeWidthPx;\n  String? symbolRendererId;\n\n  PointRendererElement({\n    this.point,\n    this.index,\n    this.color,\n    this.fillColor,\n    this.measureAxisPosition,\n    required this.radiusPx,\n    required this.boundsLineRadiusPx,\n    required this.strokeWidthPx,\n    this.symbolRendererId,\n  });\n\n  PointRendererElement<D> clone() {\n    return PointRendererElement<D>(\n      point: point != null ? DatumPoint<D>.from(point!) : null,\n      index: index,\n      color: color != null ? Color.fromOther(color: color!) : null,\n      fillColor: fillColor != null ? Color.fromOther(color: fillColor!) : null,\n      measureAxisPosition: measureAxisPosition,\n      radiusPx: radiusPx,\n      boundsLineRadiusPx: boundsLineRadiusPx,\n      strokeWidthPx: strokeWidthPx,\n      symbolRendererId: symbolRendererId,\n    );\n  }\n\n  void updateAnimationPercent(PointRendererElement<D> previous,\n      PointRendererElement<D> target, double animationPercent) {\n    final targetPoint = target.point!;\n    final previousPoint = previous.point!;\n\n    final x = ((targetPoint.x! - previousPoint.x!) * animationPercent) +\n        previousPoint.x!;\n\n    final xLower = targetPoint.xLower != null && previousPoint.xLower != null\n        ? ((targetPoint.xLower! - previousPoint.xLower!) * animationPercent) +\n            previousPoint.xLower!\n        : null;\n\n    final xUpper = targetPoint.xUpper != null && previousPoint.xUpper != null\n        ? ((targetPoint.xUpper! - previousPoint.xUpper!) * animationPercent) +\n            previousPoint.xUpper!\n        : null;\n\n    double? y;\n    if (targetPoint.y != null && previousPoint.y != null) {\n      y = ((targetPoint.y! - previousPoint.y!) * animationPercent) +\n          previousPoint.y!;\n    } else if (targetPoint.y != null) {\n      y = targetPoint.y;\n    } else {\n      y = null;\n    }\n\n    final yLower = targetPoint.yLower != null && previousPoint.yLower != null\n        ? ((targetPoint.yLower! - previousPoint.yLower!) * animationPercent) +\n            previousPoint.yLower!\n        : null;\n\n    final yUpper = targetPoint.yUpper != null && previousPoint.yUpper != null\n        ? ((targetPoint.yUpper! - previousPoint.yUpper!) * animationPercent) +\n            previousPoint.yUpper!\n        : null;\n\n    point = DatumPoint<D>.from(targetPoint,\n        x: x,\n        xLower: xLower,\n        xUpper: xUpper,\n        y: y,\n        yLower: yLower,\n        yUpper: yUpper);\n\n    color = getAnimatedColor(previous.color!, target.color!, animationPercent);\n\n    fillColor = getAnimatedColor(\n        previous.fillColor!, target.fillColor!, animationPercent);\n\n    radiusPx = (target.radiusPx - previous.radiusPx) * animationPercent +\n        previous.radiusPx;\n\n    boundsLineRadiusPx =\n        ((target.boundsLineRadiusPx - previous.boundsLineRadiusPx) *\n                animationPercent) +\n            previous.boundsLineRadiusPx;\n\n    strokeWidthPx =\n        ((target.strokeWidthPx - previous.strokeWidthPx) * animationPercent) +\n            previous.strokeWidthPx;\n  }\n}\n\nclass AnimatedPoint<D> {\n  final String key;\n  final bool overlaySeries;\n\n  PointRendererElement<D>? _previousPoint;\n  late PointRendererElement<D> _targetPoint;\n  PointRendererElement<D>? _currentPoint;\n\n  // Flag indicating whether this point is being animated out of the chart.\n  bool animatingOut = false;\n\n  AnimatedPoint({required this.key, required this.overlaySeries});\n\n  /// Animates a point that was removed from the series out of the view.\n  ///\n  /// This should be called in place of \"setNewTarget\" for points that represent\n  /// data that has been removed from the series.\n  ///\n  /// Animates the height of the point down to the measure axis position\n  /// (position of 0).\n  void animateOut() {\n    var newTarget = _currentPoint!.clone();\n\n    // Set the target measure value to the axis position.\n    var targetPoint = newTarget.point!;\n    var y = newTarget.measureAxisPosition!.roundToDouble();\n    newTarget.point = DatumPoint<D>.from(\n      targetPoint,\n      x: targetPoint.x,\n      y: y,\n      yLower: y,\n      yUpper: y,\n    );\n\n    // Animate the radius and stroke width to 0 so that we don't get a lingering\n    // point after animation is done.\n    newTarget.radiusPx = 0.0;\n    newTarget.strokeWidthPx = 0.0;\n\n    setNewTarget(newTarget);\n    animatingOut = true;\n  }\n\n  void setNewTarget(PointRendererElement<D> newTarget) {\n    animatingOut = false;\n    _currentPoint ??= newTarget.clone();\n    _previousPoint = _currentPoint!.clone();\n    _targetPoint = newTarget;\n  }\n\n  PointRendererElement<D> getCurrentPoint(double animationPercent) {\n    if (animationPercent == 1.0 || _previousPoint == null) {\n      _currentPoint = _targetPoint;\n      _previousPoint = _targetPoint;\n      return _currentPoint!;\n    }\n\n    _currentPoint!.updateAnimationPercent(\n        _previousPoint!, _targetPoint, animationPercent);\n\n    return _currentPoint!;\n  }\n}\n\n/// Struct of distances between a datum and a point in the chart.\nclass _Distances {\n  /// Distance between two points along the domain axis.\n  final double domainDistance;\n\n  /// Distance between two points along the measure axis.\n  final double measureDistance;\n\n  /// Cartesian distance between the two points.\n  final double relativeDistance;\n\n  /// Whether or not the point was located inside the datum.\n  final bool? insidePoint;\n\n  _Distances({\n    required this.domainDistance,\n    required this.measureDistance,\n    required this.relativeDistance,\n    this.insidePoint,\n  });\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/scatter_plot/point_renderer_config.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport '../../common/symbol_renderer.dart';\nimport '../common/series_renderer_config.dart'\n    show RendererAttributes, SeriesRendererConfig;\nimport '../layout/layout_view.dart' show LayoutViewConfig, LayoutViewPaintOrder;\nimport 'point_renderer.dart' show PointRenderer, pointSymbolRendererIdKey;\nimport 'point_renderer_decorator.dart' show PointRendererDecorator;\n\n/// Configuration for a line renderer.\nclass PointRendererConfig<D> extends LayoutViewConfig\n    implements SeriesRendererConfig<D> {\n  @override\n  final String? customRendererId;\n\n  /// The order to paint this renderer on the canvas.\n  final int layoutPaintOrder;\n\n  /// List of decorators applied to rendered points.\n  final List<PointRendererDecorator<D>> pointRendererDecorators;\n\n  /// Renderer used to draw the points. Defaults to a circle.\n  @override\n  final SymbolRenderer? symbolRenderer;\n\n  /// Map of custom symbol renderers used to draw points.\n  ///\n  /// Each series or point can be associated with a custom renderer by\n  /// specifying a [pointSymbolRendererIdKey] matching a key in the map. Any\n  /// point that doesn't define one will fall back to the default\n  /// [symbolRenderer].\n  final Map<String, SymbolRenderer>? customSymbolRenderers;\n\n  @override\n  final rendererAttributes = RendererAttributes();\n\n  /// Default radius of the points, used if a series does not define a radiusPx\n  /// accessor function.\n  final double radiusPx;\n\n  /// Stroke width of the target line.\n  final double strokeWidthPx;\n\n  /// Optional default radius of data bounds lines, used if a series does not\n  /// define a boundsLineRadiusPx accessor function.\n  ///\n  /// If the series does not define a boundsLineRadiusPx accessor function, then\n  /// each datum's boundsLineRadiusPx value will be filled in by using the\n  /// following values, in order of what is defined:\n  ///\n  /// 1) boundsLineRadiusPx property defined on the series.\n  /// 2) boundsLineRadiusPx property defined on this renderer config.\n  /// 3) Final fallback is to use the point radiusPx for the datum.\n  final double? boundsLineRadiusPx;\n\n  PointRendererConfig(\n      {this.customRendererId,\n      this.layoutPaintOrder = LayoutViewPaintOrder.point,\n      this.pointRendererDecorators = const [],\n      this.radiusPx = 3.5,\n      this.boundsLineRadiusPx,\n      this.strokeWidthPx = 0.0,\n      this.symbolRenderer,\n      this.customSymbolRenderers});\n\n  @override\n  PointRenderer<D> build() {\n    return PointRenderer<D>(config: this, rendererId: customRendererId);\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/scatter_plot/point_renderer_decorator.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math' show Rectangle;\n\nimport '../../common/graphics_factory.dart' show GraphicsFactory;\nimport '../common/chart_canvas.dart' show ChartCanvas;\nimport 'point_renderer.dart' show PointRendererElement;\n\n/// Decorates points after the points have already been painted.\nabstract class PointRendererDecorator<D> {\n  const PointRendererDecorator();\n\n  /// Configures whether the decorator should be rendered on top of or below\n  /// series data elements.\n  bool get renderAbove;\n\n  void decorate(PointRendererElement<D> pointElement, ChartCanvas canvas,\n      GraphicsFactory graphicsFactory,\n      {required Rectangle drawBounds,\n      required double animationPercent,\n      bool rtl = false});\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/scatter_plot/scatter_plot_chart.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:collection' show LinkedHashMap;\n\nimport '../cartesian/axis/axis.dart' show NumericAxis;\nimport '../cartesian/axis/draw_strategy/gridline_draw_strategy.dart'\n    show GridlineRendererSpec;\nimport '../cartesian/cartesian_chart.dart' show NumericCartesianChart;\nimport '../common/series_renderer.dart' show SeriesRenderer;\nimport '../layout/layout_config.dart' show LayoutConfig;\nimport 'point_renderer.dart' show PointRenderer;\n\n/// A scatter plot draws series data as a collection of points in a two\n/// dimensional Cartesian space, plotting two variables from each datum at a\n/// point represented by (domain, measure).\n///\n/// A third and fourth metric can be represented by configuring the color and\n/// radius of each datum.\n///\n/// Scatter plots render grid lines along both the domain and measure axes by\n/// default.\nclass ScatterPlotChart extends NumericCartesianChart {\n  /// Select data by relative Cartesian distance. Scatter plots draw potentially\n  /// overlapping data in an arbitrary (x, y) space, and do not consider the\n  /// domain axis to be more or  less important for data selection than the\n  /// measure axis.\n  @override\n  bool get selectNearestByDomain => false;\n\n  /// On scatter plots, overlapping points that contain the click/tap location\n  /// are all added to the selection.\n  @override\n  bool get selectOverlappingPoints => true;\n\n  ScatterPlotChart(\n      {bool? vertical,\n      LayoutConfig? layoutConfig,\n      NumericAxis? primaryMeasureAxis,\n      NumericAxis? secondaryMeasureAxis,\n      LinkedHashMap<String, NumericAxis>? disjointMeasureAxes})\n      : super(\n            vertical: vertical,\n            layoutConfig: layoutConfig,\n            primaryMeasureAxis: primaryMeasureAxis,\n            secondaryMeasureAxis: secondaryMeasureAxis,\n            disjointMeasureAxes: disjointMeasureAxes);\n\n  @override\n  SeriesRenderer<num> makeDefaultRenderer() {\n    return PointRenderer<num>()..rendererId = SeriesRenderer.defaultRendererId;\n  }\n\n  @override\n  void initDomainAxis() {\n    domainAxis!.tickDrawStrategy = GridlineRendererSpec<num>()\n        .createDrawStrategy(context, graphicsFactory!);\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/scatter_plot/symbol_annotation_renderer.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:collection' show LinkedHashMap;\nimport 'dart:math' show max, Rectangle;\n\nimport '../../common/graphics_factory.dart' show GraphicsFactory;\nimport '../cartesian/axis/axis.dart' show ImmutableAxis;\nimport '../cartesian/cartesian_chart.dart' show CartesianChart;\nimport '../common/base_chart.dart' show BaseChart;\nimport '../common/chart_canvas.dart' show ChartCanvas;\nimport '../common/processed_series.dart' show ImmutableSeries, MutableSeries;\nimport '../layout/layout_view.dart'\n    show\n        LayoutPosition,\n        LayoutView,\n        LayoutViewConfig,\n        LayoutViewPaintOrder,\n        LayoutViewPositionOrder,\n        ViewMeasuredSizes;\nimport 'point_renderer.dart' show AnimatedPoint, DatumPoint, PointRenderer;\nimport 'symbol_annotation_renderer_config.dart'\n    show SymbolAnnotationRendererConfig;\n\n/// Series renderer which draws a row of symbols for each series below the\n/// drawArea but above the bottom axis.\n///\n/// This renderer can draw point annotations and range annotations. Point\n/// annotations are drawn at the location of the domain along the chart's domain\n/// axis, in the row for its series. Range annotations are drawn as a range\n/// shape between the domainLowerBound and domainUpperBound positions along the\n/// chart's domain axis. Point annotations are drawn on top of range\n/// annotations.\n///\n/// Limitations:\n/// Does not handle horizontal bars.\nclass SymbolAnnotationRenderer<D> extends PointRenderer<D>\n    implements LayoutView {\n  late Rectangle<int> _componentBounds;\n\n  @override\n  GraphicsFactory? graphicsFactory;\n\n  late CartesianChart<D> _chart;\n\n  var _currentHeight = 0;\n\n  // ignore: prefer_collection_literals, https://github.com/dart-lang/linter/issues/1649\n  final _seriesInfo = LinkedHashMap<String, _SeriesInfo<D>>();\n\n  SymbolAnnotationRenderer(\n      {String? rendererId, SymbolAnnotationRendererConfig<D>? config})\n      : super(rendererId: rendererId ?? 'symbolAnnotation', config: config);\n\n  //\n  // Renderer methods\n  //\n  /// Symbol annotations do not use any measure axes, or draw anything in the\n  /// main draw area associated with them.\n  @override\n  void configureMeasureAxes(List<MutableSeries<D>> seriesList) {}\n\n  @override\n  void preprocessSeries(List<MutableSeries<D>> seriesList) {\n    var localConfig = config as SymbolAnnotationRendererConfig;\n\n    _seriesInfo.clear();\n\n    var offset = 0.0;\n\n    seriesList.forEach((series) {\n      final seriesKey = series.id;\n\n      // Default to the configured radius if none was defined by the series.\n      series.radiusPxFn ??= (_) => config.radiusPx;\n\n      var maxRadius = 0.0;\n      for (var index = 0; index < series.data.length; index++) {\n        // Default to the configured radius if none was returned by the\n        // accessor function.\n        var radiusPx = series.radiusPxFn?.call(index)?.toDouble();\n        radiusPx ??= config.radiusPx;\n\n        maxRadius = max(maxRadius, radiusPx);\n      }\n\n      final rowInnerHeight = maxRadius * 2;\n\n      final rowHeight = localConfig.verticalSymbolBottomPaddingPx +\n          localConfig.verticalSymbolTopPaddingPx +\n          rowInnerHeight;\n\n      final symbolCenter = offset +\n          localConfig.verticalSymbolTopPaddingPx +\n          (rowInnerHeight / 2);\n\n      series.measureFn = (index) => 0;\n      series.measureOffsetFn = (index) => 0;\n\n      // Override the key function to allow for range annotations that start at\n      // the same point. This is a necessary hack because every annotation has a\n      // measure value of 0, so the key generated in [PointRenderer] is not\n      // unique enough.\n      series.keyFn ??= (index) => '${series.id}__${series.domainFn(index)}__'\n          '${series.domainLowerBoundFn!(index)}__'\n          '${series.domainUpperBoundFn!(index)}';\n\n      _seriesInfo[seriesKey] = _SeriesInfo<D>(\n        rowHeight: rowHeight,\n        rowStart: offset,\n        symbolCenter: symbolCenter,\n      );\n\n      offset += rowHeight;\n    });\n\n    _currentHeight = offset.ceil();\n\n    super.preprocessSeries(seriesList);\n  }\n\n  @override\n  DatumPoint<D> getPoint(\n      Object? datum,\n      D? domainValue,\n      D? domainLowerBoundValue,\n      D? domainUpperBoundValue,\n      ImmutableSeries<D> series,\n      ImmutableAxis<D> domainAxis,\n      num? measureValue,\n      num? measureLowerBoundValue,\n      num? measureUpperBoundValue,\n      num? measureOffsetValue,\n      ImmutableAxis<num> measureAxis) {\n    final domainPosition = domainAxis.getLocation(domainValue);\n\n    final domainLowerBoundPosition = domainLowerBoundValue != null\n        ? domainAxis.getLocation(domainLowerBoundValue)\n        : null;\n\n    final domainUpperBoundPosition = domainUpperBoundValue != null\n        ? domainAxis.getLocation(domainUpperBoundValue)\n        : null;\n\n    final seriesKey = series.id;\n    final seriesInfo = _seriesInfo[seriesKey]!;\n\n    final measurePosition = _componentBounds.top + seriesInfo.symbolCenter;\n\n    final measureLowerBoundPosition =\n        domainLowerBoundPosition != null ? measurePosition : null;\n\n    final measureUpperBoundPosition =\n        domainUpperBoundPosition != null ? measurePosition : null;\n\n    return DatumPoint<D>(\n        datum: datum,\n        domain: domainValue,\n        series: series,\n        x: domainPosition,\n        xLower: domainLowerBoundPosition,\n        xUpper: domainUpperBoundPosition,\n        y: measurePosition,\n        yLower: measureLowerBoundPosition,\n        yUpper: measureUpperBoundPosition);\n  }\n\n  @override\n  void onAttach(BaseChart<D> chart) {\n    if (chart is! CartesianChart<D>) {\n      throw ArgumentError(\n          'SymbolAnnotationRenderer can only be attached to a CartesianChart<D>');\n    }\n\n    _chart = chart;\n\n    // Only vertical rendering is supported by this behavior.\n    assert(_chart.vertical);\n\n    super.onAttach(chart);\n    _chart.addView(this);\n  }\n\n  @override\n  void onDetach(BaseChart<D> chart) {\n    chart.removeView(this);\n  }\n\n  @override\n  void paint(ChartCanvas canvas, double animationPercent) {\n    super.paint(canvas, animationPercent);\n\n    // Use the domain axis of the attached chart to render the separator lines\n    // to keep the same overall style.\n    if ((config as SymbolAnnotationRendererConfig).showSeparatorLines) {\n      seriesPointMap.forEach((String key, List<AnimatedPoint<D>> points) {\n        final seriesInfo = _seriesInfo[key]!;\n\n        final y = componentBounds.top + seriesInfo.rowStart;\n\n        final domainAxis = _chart.domainAxis!;\n        final bounds = Rectangle<int>(\n            componentBounds.left, y.round(), componentBounds.width, 0);\n        domainAxis.tickDrawStrategy!\n            .drawAxisLine(canvas, domainAxis.axisOrientation!, bounds);\n      });\n    }\n  }\n\n  //\n  // Layout methods\n  //\n\n  @override\n  LayoutViewConfig get layoutConfig {\n    return LayoutViewConfig(\n        paintOrder: LayoutViewPaintOrder.point,\n        position: LayoutPosition.Bottom,\n        positionOrder: LayoutViewPositionOrder.symbolAnnotation);\n  }\n\n  @override\n  ViewMeasuredSizes measure(int maxWidth, int maxHeight) {\n    // The sizing of component is not flexible. It's height is always a multiple\n    // of the number of series rendered, even if that ends up taking all of the\n    // available margin space.\n    return ViewMeasuredSizes(\n        preferredWidth: maxWidth, preferredHeight: _currentHeight);\n  }\n\n  @override\n  void layout(Rectangle<int> componentBounds, Rectangle<int> drawAreaBounds) {\n    _componentBounds = componentBounds;\n\n    super.layout(componentBounds, drawAreaBounds);\n  }\n\n  @override\n  Rectangle<int> get componentBounds => _componentBounds;\n}\n\nclass _SeriesInfo<D> {\n  double rowHeight;\n  double rowStart;\n  double symbolCenter;\n\n  _SeriesInfo(\n      {required this.rowHeight,\n      required this.rowStart,\n      required this.symbolCenter});\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/scatter_plot/symbol_annotation_renderer_config.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport '../../common/symbol_renderer.dart';\nimport 'comparison_points_decorator.dart' show ComparisonPointsDecorator;\nimport 'point_renderer_config.dart' show PointRendererConfig;\nimport 'point_renderer_decorator.dart' show PointRendererDecorator;\nimport 'symbol_annotation_renderer.dart' show SymbolAnnotationRenderer;\n\n/// Configuration for [SymbolAnnotationRenderer].\n///\n/// This renderer is configured with a [ComparisonPointsDecorator] by default,\n/// used to draw domain ranges. This decorator will draw a rectangular shape\n/// between the points (domainLowerBound, measureLowerBound) and\n/// (domainUpperBound, measureUpperBound), beneath the primary point for each\n/// series.\nclass SymbolAnnotationRendererConfig<D> extends PointRendererConfig<D> {\n  /// Whether a separator line should be drawn between the bottom row of\n  /// rendered symbols and the axis ticks/labels.\n  final bool showBottomSeparatorLine;\n\n  /// Whether or not separator lines will be rendered between rows of rendered\n  /// symbols.\n  final bool showSeparatorLines;\n\n  /// Space reserved at the bottom of each row where the symbol should not\n  /// render into.\n  final double verticalSymbolBottomPaddingPx;\n\n  /// Space reserved at the top of each row where the symbol should not render\n  /// into.\n  final double verticalSymbolTopPaddingPx;\n\n  SymbolAnnotationRendererConfig(\n      {String? customRendererId,\n      List<PointRendererDecorator<D>>? pointRendererDecorators,\n      double radiusPx = 5.0,\n      SymbolRenderer? symbolRenderer,\n      Map<String, SymbolRenderer>? customSymbolRenderers,\n      this.showBottomSeparatorLine = false,\n      this.showSeparatorLines = true,\n      this.verticalSymbolBottomPaddingPx = 5.0,\n      this.verticalSymbolTopPaddingPx = 5.0})\n      : super(\n            customRendererId: customRendererId,\n            pointRendererDecorators: pointRendererDecorators ??\n                [\n                  ComparisonPointsDecorator<D>(\n                      symbolRenderer: RectangleRangeSymbolRenderer())\n                ],\n            radiusPx: radiusPx,\n            symbolRenderer: symbolRenderer,\n            customSymbolRenderers: customSymbolRenderers);\n\n  @override\n  SymbolAnnotationRenderer<D> build() {\n    return SymbolAnnotationRenderer<D>(\n        config: this, rendererId: customRendererId);\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/sunburst/sunburst_arc_label_decorator.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math' show Rectangle;\n\nimport '../../common/color.dart' show Color;\nimport '../../common/graphics_factory.dart' show GraphicsFactory;\nimport '../../common/text_element.dart' show TextElement;\nimport '../../common/text_style.dart' show TextStyle;\nimport '../cartesian/axis/spec/axis_spec.dart' show TextStyleSpec;\nimport '../common/chart_canvas.dart' show ChartCanvas;\nimport '../pie/arc_renderer_element.dart'\n    show ArcRendererElement, ArcRendererElementList;\nimport '../pie/arc_label_decorator.dart';\nimport 'sunburst_arc_renderer.dart' show SunburstArcRendererElement;\n\n/// Renders labels for sunburst arc renderers. Configures label based on arc's\n/// position via innerRingArcLabelPosition, innerRingLeafArcLabelPosition, and\n/// outerRingArcLabelPosition. Currently label for non-leaf arcs in the inner\n/// ring may only be drawn inside until there's better collision detection for\n/// inner arcs' label versus the outer arcs.\n///\n/// TODO: Improve label handling for sunburst chart.\nclass SunburstArcLabelDecorator<D> extends ArcLabelDecorator<D> {\n  /// Configures the [ArcLabelPosition] for the non-leaf arcs in the inner ring.\n  /// Label can only be rendered inside, If set to ArcLabelPosition.outside,\n  /// label will not be rendered.\n  final ArcLabelPosition innerRingArcLabelPosition;\n\n  /// Configures the [ArcLabelPosition] for the leaf arcs in the inner ring.\n  final ArcLabelPosition innerRingLeafArcLabelPosition;\n\n  /// Configures the [ArcLabelPosition] for the arcs in the outer most ring.\n  final ArcLabelPosition outerRingArcLabelPosition;\n\n  SunburstArcLabelDecorator(\n      {TextStyleSpec? insideLabelStyleSpec,\n      TextStyleSpec? outsideLabelStyleSpec,\n      ArcLabelLeaderLineStyleSpec? leaderLineStyleSpec,\n      int labelPadding = 5,\n      bool showLeaderLines = true,\n      Color? leaderLineColor,\n      // TODO: Change to auto when we can detect collision of inner\n      // arcs' label with outer arcs.\n      this.innerRingArcLabelPosition = ArcLabelPosition.inside,\n      // TODO: Change to auto when we can detect collision of inner\n      // arcs' label with outer arcs.\n      this.innerRingLeafArcLabelPosition = ArcLabelPosition.inside,\n      this.outerRingArcLabelPosition = ArcLabelPosition.auto})\n      : super(\n            insideLabelStyleSpec: insideLabelStyleSpec,\n            outsideLabelStyleSpec: outsideLabelStyleSpec,\n            leaderLineStyleSpec: leaderLineStyleSpec,\n            labelPosition: ArcLabelPosition.auto,\n            labelPadding: labelPadding,\n            showLeaderLines: showLeaderLines,\n            leaderLineColor: leaderLineColor);\n\n  @override\n  void decorate(ArcRendererElementList<D> arcElements, ChartCanvas canvas,\n      GraphicsFactory graphicsFactory,\n      {required Rectangle drawBounds,\n      required double animationPercent,\n      bool rtl = false}) {\n    /// TODO: Improve label handling for sunburst chart. When a\n    /// more sophisticated collision detection is in place, we can draw the\n    /// label for inner arc outside when it doesn't collide with outer arcs.\n\n    // Do not draw label for arcs on the inner ring if positioned outside.\n    if (innerRingArcLabelPosition == ArcLabelPosition.outside) {\n      arcElements.arcs\n          .retainWhere((e) => (e as SunburstArcRendererElement).isLeaf == true);\n    }\n    super.decorate(arcElements, canvas, graphicsFactory,\n        drawBounds: drawBounds, animationPercent: animationPercent, rtl: rtl);\n  }\n\n  @override\n  ArcLabelPosition calculateLabelPosition(\n      TextElement labelElement,\n      TextStyle labelStyle,\n      int insideArcWidth,\n      int outsideArcWidth,\n      ArcRendererElement arcRendererElement,\n      ArcLabelPosition labelPosition) {\n    assert(arcRendererElement is SunburstArcRendererElement);\n\n    if ((arcRendererElement as SunburstArcRendererElement).isOuterMostRing ==\n        true) {\n      return super.calculateLabelPosition(\n          labelElement,\n          labelStyle,\n          insideArcWidth,\n          outsideArcWidth,\n          arcRendererElement,\n          outerRingArcLabelPosition);\n    } else if ((arcRendererElement as SunburstArcRendererElement).isLeaf ==\n        true) {\n      return super.calculateLabelPosition(\n          labelElement,\n          labelStyle,\n          insideArcWidth,\n          outsideArcWidth,\n          arcRendererElement,\n          innerRingLeafArcLabelPosition);\n    } else {\n      /// TODO: Improve label handling for sunburst chart. When a\n      /// more sophisticated collision detection is in place, we can draw the\n      /// label for inner arc outside when it doesn't collide with outer arcs.\n\n      // Force label for arc on the inner ring inside.\n      return ArcLabelPosition.inside;\n    }\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/sunburst/sunburst_arc_renderer.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:collection' show LinkedHashMap, HashSet;\nimport 'dart:math' show max, min, pi, Point;\n\nimport 'package:collection/collection.dart' show IterableExtension;\n\nimport '../../common/color.dart' show Color;\nimport '../../common/style/style_factory.dart' show StyleFactory;\nimport '../../data/series.dart' show AttributeKey;\nimport '../../data/tree.dart' show TreeNode;\nimport '../common/chart_canvas.dart' show ChartCanvas;\nimport '../common/processed_series.dart' show ImmutableSeries, MutableSeries;\nimport '../pie/arc_renderer_decorator.dart' show ArcRendererDecorator;\nimport '../pie/arc_renderer_element.dart'\n    show ArcRendererElement, AnimatedArcList, AnimatedArc;\nimport '../pie/base_arc_renderer.dart';\nimport 'sunburst_arc_renderer_config.dart'\n    show SunburstArcRendererConfig, SunburstColorStrategy;\n\nconst arcElementsKey = AttributeKey<List<SunburstArcRendererElement<Object>>>(\n    'SunburstArcRenderer.elements');\n\n/// ArcRenderer for the Sunburst chart using Tree based data.\nclass SunburstArcRenderer<D> extends BaseArcRenderer<D> {\n  final SunburstArcRendererConfig<D> config;\n\n  final List<ArcRendererDecorator<D>> arcRendererDecorators;\n\n  /// Store a map of series drawn on the chart, mapped by series name.\n  ///\n  /// [LinkedHashMap] is used to render the series on the canvas in the same\n  /// order as the data was given to the chart.\n  // ignore: prefer_collection_literals, https://github.com/dart-lang/linter/issues/1649\n  final _seriesArcMap = LinkedHashMap<String, List<AnimatedArcList<D>>>();\n\n  final _nodeToArcRenderElementMap =\n      LinkedHashMap<TreeNode<D>, SunburstArcRendererElement>();\n\n  // Store a list of arcs that exist in the series data.\n  //\n  // This list will be used to remove any [AnimatedArc] that were rendered in\n  // previous draw cycles, but no longer have a corresponding datum in the new\n  // data.\n  final _currentKeys = <String>[];\n\n  final _nodeToExpand = HashSet<TreeNode<dynamic>>();\n\n  factory SunburstArcRenderer(\n      {String? rendererId, SunburstArcRendererConfig<D>? config}) {\n    return SunburstArcRenderer._internal(\n        rendererId: rendererId ?? 'sunburst',\n        config: config ?? SunburstArcRendererConfig());\n  }\n\n  SunburstArcRenderer._internal(\n      {required String rendererId, required this.config})\n      : arcRendererDecorators = config.arcRendererDecorators,\n        super(rendererId: rendererId, config: config);\n\n  @override\n  void preprocessSeries(List<MutableSeries<D>> seriesList) {\n    _nodeToArcRenderElementMap.clear();\n    seriesList.forEach((MutableSeries<D> series) {\n      var elements = <SunburstArcRendererElement<D>>[];\n\n      var domainFn = series.domainFn;\n      var measureFn = series.measureFn;\n\n      // The seriesMeasureTotal needs to be computed from currently displayed\n      // top level.\n      var seriesMeasureTotal = 0.0;\n      for (var i = 0; i < series.data.length; i++) {\n        final node = series.data[i] as TreeNode<Object>;\n        final measure = measureFn(i);\n        if (node.depth == 1 && measure != null) {\n          seriesMeasureTotal += measure;\n        }\n      }\n\n      // On the canvas, arc measurements are defined as angles from the positive\n      // x axis. Start our first slice at the positive y axis instead.\n      var startAngle = config.startAngle;\n      var arcLength = config.arcLength;\n\n      var totalAngle = 0.0;\n\n      var measures = <num>[];\n\n      // No data processing is same as the regular arc renderer.\n      if (series.data.isEmpty) {\n        // If the series has no data, generate an empty arc element that\n        // occupies the entire chart.\n        //\n        // Use a tiny epsilon difference to ensure that the canvas renders a\n        // \"full\" circle, in the correct direction.\n        var angle = arcLength == 2 * pi ? arcLength * .999999 : arcLength;\n        var endAngle = startAngle + angle;\n\n        var details = SunburstArcRendererElement<D>(\n            startAngle: startAngle,\n            endAngle: endAngle,\n            index: 0,\n            key: 0,\n            series: series);\n\n        elements.add(details);\n      } else {\n        // Create SunburstArcRendererElement for each item in the tree,\n        // excluding the root node.\n        var root = series.data.first as TreeNode<D>;\n        root.visit((node) {\n          elements.addAll(_createArcRenderElementForNode(series, node));\n        });\n      }\n\n      series.setAttr(arcElementsKey, elements);\n    });\n  }\n\n  // Create SunburstArcRendererElement for children of the node.\n  List<SunburstArcRendererElement<D>> _createArcRenderElementForNode(\n      MutableSeries<D> series, TreeNode<D> node) {\n    var elements = <SunburstArcRendererElement<D>>[];\n    final children = node.children;\n    if (children.isNotEmpty) {\n      var childrenMeasureTotal = 0.0;\n\n      // Compute the measure total for the node's children.\n      for (var i = 0; i < children.length; i++) {\n        final child = children.elementAt(i);\n        final measure = series.measureFn(series.data.indexOf(child));\n        if (measure != null) {\n          childrenMeasureTotal += measure;\n        }\n      }\n\n      // Create ArcRenderElement for the node's children. Computing arc angles\n      // based on parent arc’s arcLength and the nodes measure versus the\n      // sibling nodes.\n      var startAngle = _getParentStartAngle(node);\n      for (var i = 0; i < children.length; i++) {\n        final child = children.elementAt(i);\n        final arcIndex = series.data.indexOf(child);\n        final measure = series.measureFn(arcIndex);\n        final domain = series.domainFn(arcIndex);\n        if (measure == null) {\n          continue;\n        }\n\n        final percentOfLevel = measure / childrenMeasureTotal;\n        var angle = _getParentArcLength(node) * percentOfLevel;\n        var endAngle = startAngle + angle;\n\n        var details = SunburstArcRendererElement<D>(\n            arcLength: angle,\n            startAngle: startAngle,\n            endAngle: endAngle,\n            index: arcIndex,\n            key: arcIndex,\n            domain: domain,\n            series: series);\n\n        _nodeToArcRenderElementMap[child] = details;\n        elements.add(details);\n\n        // Update the starting angle for the next datum in the series.\n        startAngle = endAngle;\n      }\n    }\n    return elements;\n  }\n\n  double _getParentArcLength(TreeNode<D> parent) =>\n      _nodeToArcRenderElementMap[parent]?.arcLength != null\n          ? _nodeToArcRenderElementMap[parent]!.arcLength!\n          : config.arcLength;\n\n  double _getParentStartAngle(TreeNode<D> parent) =>\n      _nodeToArcRenderElementMap[parent] != null\n          ? _nodeToArcRenderElementMap[parent]!.startAngle\n          : config.startAngle;\n\n  @override\n  void update(List<ImmutableSeries<D>> seriesList, bool isAnimatingThisDraw) {\n    _currentKeys.clear();\n\n    final bounds = chart!.drawAreaBounds;\n\n    final center = Point<double>((bounds.left + bounds.width / 2).toDouble(),\n        (bounds.top + bounds.height / 2).toDouble());\n\n    final radius = bounds.height < bounds.width\n        ? (bounds.height / 2).toDouble()\n        : (bounds.width / 2).toDouble();\n\n    if (config.arcRatio != null) {\n      if (config.arcRatio! < 0 || config.arcRatio! > 1) {\n        throw ArgumentError('arcRatio must be between 0 and 1');\n      }\n    }\n\n    seriesList.forEach((ImmutableSeries<D> series) {\n      var colorFn = series.colorFn;\n      var arcListKey = series.id;\n      var elementsList =\n          series.getAttr(arcElementsKey) as List<SunburstArcRendererElement<D>>;\n\n      var arcLists =\n          _seriesArcMap.putIfAbsent(arcListKey, () => <AnimatedArcList<D>>[]);\n      if (series.data.isEmpty) {\n        var arcList = AnimatedArcList<D>();\n        _seriesArcMap.putIfAbsent(arcListKey, () => [arcList]);\n        final innerRadius = _calculateRadii(radius).first;\n\n        // If the series is empty, set up the \"no data\" arc element. This should\n        // occupy the entire chart, and use the chart style's no data color.\n        final details = elementsList[0];\n\n        var arcKey = '__no_data__';\n\n        // If we already have an AnimatingArc for that index, use it.\n        var animatingArc =\n            arcList.arcs.firstWhereOrNull((arc) => arc.key == arcKey);\n\n        arcList.center = center;\n        arcList.radius = radius;\n        arcList.innerRadius = innerRadius;\n        arcList.series = series;\n        arcList.stroke = config.noDataColor;\n        arcList.strokeWidthPx = 0.0;\n\n        // If we don't have any existing arc element, create a new arc. Unlike\n        // real arcs, we should not animate the no data state in from 0.\n        if (animatingArc == null) {\n          animatingArc = AnimatedArc<D>(arcKey, null, null);\n          arcList.arcs.add(animatingArc);\n        } else {\n          animatingArc.datum = null;\n          animatingArc.domain = null;\n        }\n\n        // Update the set of arcs that still exist in the series data.\n        _currentKeys.add(arcKey);\n\n        // Get the arcElement we are going to setup.\n        // Optimization to prevent allocation in non-animating case.\n        final arcElement = SunburstArcRendererElement<D>(\n            startAngle: details.startAngle,\n            endAngle: details.endAngle,\n            color: config.noDataColor,\n            series: series);\n\n        animatingArc.setNewTarget(arcElement);\n\n        arcLists.add(arcList);\n      } else {\n        var previousEndAngle = config.startAngle;\n\n        // Create Arc and add to arcList for each of the node with depth\n        // within config.maxDisplayLevel\n        var root = series.data.first as TreeNode<Object>;\n        var maxDepth = 0;\n        root.visit((node) {\n          maxDepth = max(maxDepth, node.depth);\n        });\n\n        // Create arcLists up to min(maxDepth, config.maxDisplayLevel).\n        final maxDisplayLevel = min(maxDepth, config.maxDisplayLevel);\n        final displayLevel = min(maxDepth, config.initialDisplayLevel);\n        for (var i = 0; i < maxDisplayLevel; i++) {\n          var arcList =\n              arcLists.length > i ? arcLists[i] : AnimatedArcList<D>();\n\n          // Create arc for node that’s within the initial display level or\n          // selected nodes and its children up to the maxDisplayLevel.\n          for (var node in _nodeToArcRenderElementMap.keys.where((e) =>\n              e.depth == i + 1 &&\n              (e.depth <= displayLevel || _nodeToExpand.contains(e)))) {\n            final radii = _calculateRadii(radius, maxDisplayLevel, i + 1);\n            final innerRadius = radii.first;\n            final outerRadius = radii.last;\n\n            final arcIndex = series.data.indexOf(node);\n            final Object datum = series.data[arcIndex];\n            final details = _nodeToArcRenderElementMap[node];\n            final domainValue = details!.domain;\n            final isLeaf = !node.hasChildren ||\n                ((node.depth == displayLevel || _nodeToExpand.contains(node)) &&\n                    !_nodeToExpand.any((e) => node.children.contains(e)));\n            final isOuterMostRing = node.depth == maxDisplayLevel;\n\n            var arcKey = '${series.id}__${domainValue.toString()}';\n\n            // If we already have an AnimatingArc for that index, use it.\n            var animatingArc =\n                arcList.arcs.firstWhereOrNull((arc) => arc.key == arcKey);\n\n            arcList.center = center;\n            arcList.radius = outerRadius;\n            arcList.innerRadius = innerRadius;\n            arcList.series = series;\n            arcList.stroke = config.stroke;\n            arcList.strokeWidthPx = config.strokeWidthPx;\n\n            // If we don't have any existing arc element, create a new arc and\n            // have it animate in from the position of the previous arc's end\n            // angle. If there were no previous arcs, then animate everything in\n            // from 0.\n            if (animatingArc == null) {\n              animatingArc = AnimatedArc<D>(arcKey, datum, domainValue)\n                ..setNewTarget(SunburstArcRendererElement<D>(\n                    color: colorFn!(arcIndex),\n                    startAngle: previousEndAngle,\n                    endAngle: previousEndAngle,\n                    index: arcIndex,\n                    series: series,\n                    isLeaf: isLeaf,\n                    isOuterMostRing: isOuterMostRing));\n\n              arcList.arcs.add(animatingArc);\n            } else {\n              animatingArc.datum = datum;\n\n              previousEndAngle = animatingArc.previousArcEndAngle ?? 0.0;\n            }\n\n            animatingArc.domain = domainValue;\n\n            // Update the set of arcs that still exist in the series data.\n            _currentKeys.add(arcKey);\n\n            // Get the arcElement we are going to setup.\n            // Optimization to prevent allocation in non-animating case.\n            final arcElement = SunburstArcRendererElement<D>(\n                color: colorFn!(arcIndex),\n                startAngle: details.startAngle,\n                endAngle: details.endAngle,\n                index: arcIndex,\n                series: series,\n                isLeaf: isLeaf,\n                isOuterMostRing: isOuterMostRing);\n\n            animatingArc.setNewTarget(arcElement);\n          }\n          if (arcLists.length <= i && arcList.arcs.isNotEmpty) {\n            arcLists.add(arcList);\n          }\n        }\n      }\n    });\n\n    // Animate out arcs that don't exist anymore.\n    _seriesArcMap.forEach((String key, List<AnimatedArcList<D>> arcLists) {\n      for (var arcList in arcLists) {\n        for (var arcIndex = 0; arcIndex < arcList.arcs.length; arcIndex++) {\n          final arc = arcList.arcs[arcIndex];\n          final arcStartAngle = arc.previousArcStartAngle;\n\n          if (_currentKeys.contains(arc.key) != true) {\n            // Default to animating out to the top of the chart, clockwise, if\n            // there are no arcs that start past this arc.\n            var targetArcAngle = (2 * pi) + config.startAngle;\n\n            // Find the nearest start angle of the next arc that still exists in\n            // the data.\n            for (final nextArc in arcList.arcs\n                .where((arc) => _currentKeys.contains(arc.key))) {\n              final nextArcStartAngle = nextArc.newTargetArcStartAngle;\n\n              if (arcStartAngle! < nextArcStartAngle! &&\n                  nextArcStartAngle < targetArcAngle) {\n                targetArcAngle = nextArcStartAngle;\n              }\n            }\n\n            arc.animateOut(targetArcAngle);\n          }\n        }\n      }\n    });\n  }\n\n  @override\n  void paint(ChartCanvas canvas, double animationPercent) {\n    // Clean up the arcs that no longer exist.\n    if (animationPercent == 1.0) {\n      final keysToRemove = <String>[];\n\n      _seriesArcMap.forEach((String key, List<AnimatedArcList<D>> arcLists) {\n        final arcListToRemove = <AnimatedArcList<D>>[];\n        for (var arcList in arcLists) {\n          arcList.arcs.removeWhere((AnimatedArc<D> arc) => arc.animatingOut);\n\n          if (arcList.arcs.isEmpty) {\n            arcListToRemove.add(arcList);\n          }\n        }\n\n        arcListToRemove.forEach(arcLists.remove);\n        if (arcLists.isEmpty) {\n          keysToRemove.add(key);\n        }\n      });\n\n      keysToRemove.forEach(_seriesArcMap.remove);\n    }\n\n    super.paint(canvas, animationPercent);\n  }\n\n  bool _isNodeDisplayed(TreeNode<D>? node) {\n    return node != null &&\n        (node.depth <= config.initialDisplayLevel ||\n            _nodeToExpand.contains(node));\n  }\n\n  // Records the nodes to expand beyond initial display level.\n  void expandNode(TreeNode<D> node) {\n    if (node == null) {\n      _nodeToExpand.clear();\n    } else if (node.hasChildren) {\n      // Collapse rings up to the clicked expanded node.\n      if (node.children.any((e) => _nodeToExpand.contains(e))) {\n        node.visit((e) {\n          if (node != e) {\n            _nodeToExpand.remove(e);\n          }\n        });\n      } else {\n        // Expand clicked node by one level.\n        _nodeToExpand.add(node);\n        _nodeToExpand.addAll(node.children);\n      }\n    }\n  }\n\n  /// Assigns one color pallet for each subtree from the children of the root\n  /// node, and one shade for each node of the subtree to series that are\n  /// missing their colorFn.\n  @override\n  void assignMissingColors(Iterable<MutableSeries<D>> seriesList,\n      {required bool emptyCategoryUsesSinglePalette}) {\n    seriesList.forEach((series) {\n      if (series.colorFn == null) {\n        final root = series.data.first as TreeNode<D>;\n        final firstLevelChildren = (series.data.first as TreeNode<D>).children;\n\n        // Create number of palettes based on the first level children of root.\n        final colorPalettes =\n            StyleFactory.style.getOrderedPalettes(root.children.length);\n        final nodeToColorMap = {};\n\n        // Create shades base on number of Nodes in the subtree\n        if (config.colorAssignmentStrategy ==\n            SunburstColorStrategy.newShadePerArc) {\n          for (var i = 0; i < firstLevelChildren.length; i++) {\n            var numOfNodeInSubTree = 0;\n            firstLevelChildren.elementAt(i).visit((node) {\n              numOfNodeInSubTree++;\n            });\n\n            final colorList = colorPalettes[i].makeShades(numOfNodeInSubTree);\n\n            // Fill in node to color map to be used in the colorFn\n            numOfNodeInSubTree = 0;\n            firstLevelChildren.elementAt(i).visit((node) {\n              nodeToColorMap[node] = colorList[numOfNodeInSubTree];\n              numOfNodeInSubTree++;\n            });\n          }\n        } else {\n          // Create number of shades based on the full depth of the tree instead\n          // of each subtree, so the shades of each branch looks more aligned\n          // at each level.\n          var depthOfTree = 0;\n          root.visit((node) {\n            depthOfTree = max(depthOfTree, node.depth);\n          });\n\n          for (var i = 0; i < firstLevelChildren.length; i++) {\n            final colorList = colorPalettes[i].makeShades(depthOfTree);\n\n            // Fill in node to color map to be used in the colorFn\n            firstLevelChildren.elementAt(i).visit((node) {\n              nodeToColorMap[node] = colorList[node.depth - 1];\n            });\n          }\n        }\n        series.colorFn ??=\n            (index) => nodeToColorMap[series.data[index!]] ?? Color.black;\n      }\n    });\n  }\n\n  /// Calculate the inner and outer radius of the current level based on config.\n  List<double> _calculateRadii(double radius,\n      [int maxDisplayLevel = 1, int currentLevel = 1]) {\n    // arcRatio trumps arcWidth for determining the inner radius. If neither is\n    // defined, then inner radius is 0.\n    final baseInnerRadius;\n    if (config.arcRatio != null) {\n      baseInnerRadius = max(radius - radius * config.arcRatio!, 0.0).toDouble();\n    } else if (config.arcWidth != null) {\n      baseInnerRadius = max(radius - config.arcWidth!, 0.0).toDouble();\n    } else {\n      baseInnerRadius = 0.0;\n    }\n\n    if (config.arcWidths != null && config.arcWidths!.isNotEmpty) {\n      // Check if arcWidths provided covers maxDisplayLevel, if not, copy the\n      // last value for each level not provided.\n      List<int> arcWidths = _ensureConfigLengthCoversMaxDisplayLevel(\n          config.arcWidths!, maxDisplayLevel);\n      final sumOfPreviousLevelRadii = currentLevel > 1\n          ? arcWidths.take(currentLevel - 1).reduce((a, b) => a + b)\n          : 0;\n      final innerRadius = baseInnerRadius + sumOfPreviousLevelRadii;\n      return [\n        innerRadius,\n        innerRadius + arcWidths[currentLevel - 1] - config.strokeWidthPx\n      ];\n    } else {\n      final totalRadius = radius - baseInnerRadius;\n      final radiusDenom;\n      final sumOfPreviousLevelRadiiFactor;\n      final currentLevelRadiusFactor;\n      // If arcRatios is defined, calculate inner and outer radius based on it.\n      if (config.arcRatios != null && config.arcRatios!.isNotEmpty) {\n        List<int> arcRatios = _ensureConfigLengthCoversMaxDisplayLevel(\n            config.arcRatios!, maxDisplayLevel);\n        radiusDenom = arcRatios.reduce((a, b) => a + b);\n        sumOfPreviousLevelRadiiFactor = currentLevel > 1\n            ? arcRatios.take(currentLevel - 1).reduce((a, b) => a + b)\n            : 0;\n        currentLevelRadiusFactor = arcRatios[currentLevel - 1];\n      } else {\n        // Else distribute the chart area to rings evenly.\n        radiusDenom = maxDisplayLevel;\n        sumOfPreviousLevelRadiiFactor = (currentLevel - 1);\n        currentLevelRadiusFactor = 1;\n      }\n\n      // InnerRadius is baseInnerRadius + sum of radii of previous levels.\n      final innerRadius = baseInnerRadius +\n          totalRadius * sumOfPreviousLevelRadiiFactor / radiusDenom;\n\n      // OuterRadius is baseInnerRadius + sum of radii of previous levels +\n      // radius of currentLevel. Subtract config.strokeWidth from outerRadius to\n      // create the separation of slice between levels.\n      final outerRadius = baseInnerRadius +\n          totalRadius *\n              (sumOfPreviousLevelRadiiFactor + currentLevelRadiusFactor) /\n              radiusDenom -\n          config.strokeWidthPx;\n      return [innerRadius, outerRadius];\n    }\n  }\n\n  @override\n  List<AnimatedArcList<D>> getArcLists({String? seriesId}) {\n    if (seriesId == null) {\n      return _seriesArcMap.values.first;\n    }\n    final arcList = _seriesArcMap[seriesId];\n\n    if (arcList == null) return <AnimatedArcList<D>>[];\n    return arcList;\n  }\n\n  List<int> _ensureConfigLengthCoversMaxDisplayLevel(\n      List<int> configParam, int maxDisplayLevel) {\n    // Check if config param provided covers maxDisplayLevel, if not, copy the\n    // last value for each level not provided.\n    List<int> arcWidths;\n    if (configParam.length < maxDisplayLevel) {\n      // Repeat last value in the config param to match length of\n      // maxDisplayLevel.\n      arcWidths = List<int>.generate(maxDisplayLevel,\n          (i) => (configParam.length > i) ? configParam[i] : configParam.last);\n    } else {\n      arcWidths = List<int>.from(configParam);\n    }\n    return arcWidths;\n  }\n}\n\nclass SunburstArcRendererElement<D> extends ArcRendererElement<D> {\n  /// Records the arcLength of a particular node, so its children can use it\n  /// to compute the start and end angles.\n  double? arcLength;\n\n  /// Whether the SunburstArcRendererElement is currently displayed as the outer\n  /// most arc of the branch.\n  bool? isLeaf;\n\n  /// Whether the SunburstArcRendererElement is on the outer most ring of the\n  /// sunburst.\n  bool? isOuterMostRing;\n\n  SunburstArcRendererElement(\n      {required double startAngle,\n      required double endAngle,\n      required ImmutableSeries<D> series,\n      Color? color,\n      int? index,\n      num? key,\n      D? domain,\n      this.arcLength,\n      this.isLeaf,\n      this.isOuterMostRing})\n      : super(\n          startAngle: startAngle,\n          endAngle: endAngle,\n          series: series,\n          color: color,\n          index: index,\n          key: key,\n          domain: domain,\n        );\n\n  SunburstArcRendererElement<D> clone() {\n    return SunburstArcRendererElement<D>(\n        arcLength: arcLength,\n        startAngle: startAngle,\n        endAngle: endAngle,\n        color: color == null ? null : Color.fromOther(color: color!),\n        index: index,\n        key: key,\n        series: series,\n        isLeaf: isLeaf,\n        isOuterMostRing: isOuterMostRing);\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/sunburst/sunburst_arc_renderer_config.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math' show pi;\n\nimport '../../common/symbol_renderer.dart' show SymbolRenderer;\nimport '../layout/layout_view.dart' show LayoutViewPaintOrder;\nimport '../pie/arc_renderer.dart' show ArcRenderer;\nimport '../pie/arc_renderer_decorator.dart' show ArcRendererDecorator;\nimport 'sunburst_arc_renderer.dart' show SunburstArcRenderer;\nimport '../pie/base_arc_renderer_config.dart' show BaseArcRendererConfig;\nimport '../../data/tree.dart' show TreeNode;\n\n/// Given the selected node and a list of currently expanded node, returns the\n/// new set of node to be expanded (shown beyond the initialDisplayLevel).\ntypedef List<TreeNode<dynamic>> ExpandNodeCallback(\n    TreeNode<dynamic> node, List<TreeNode<dynamic>> expandedNode);\n\n/// Configuration for an [ArcRenderer].\nclass SunburstArcRendererConfig<D> extends BaseArcRendererConfig<D> {\n  static const _maxInt32Value = 1 << 31;\n\n  /// Ratio of the arc widths for each of the ring drawn in the sunburst. The\n  /// arc ratio of each ring will be normalized based on the actual render area\n  /// of the chart. If the maxDisplayLevel to be rendered is greater than the\n  /// arcRatios provided, the last value of the arcRatios will be used to fill\n  /// the rest of the levels. If neither arcRatios nor arcWidths is provided,\n  /// space will be distributed evenly between levels.\n  final List<int>? arcRatios;\n\n  /// Fixed width of the arcs for each of the ring drawn in the sunburst. The\n  /// arcs will be drawn exactly as the defined width, any part exceeding the\n  /// chart area will not be drawn. If the maxDisplayLevel to be rendered is\n  /// greater than the arcWidths provided, the last value of the arcWidths will\n  /// be used to fill the rest of the levels. arcWidths has more precedence than\n  /// arcRatios. If neither arcRatios nor arcWidths is provided, space will be\n  /// distributed evenly between levels.\n  final List<int>? arcWidths;\n\n  /// Configures how missing colors are assigned for the Sunburst.\n  final SunburstColorStrategy colorAssignmentStrategy;\n\n  /// The initial display level of rings to render in the sunburst. Children\n  /// of hovered/selected node may expand up to the maxDisplayLevel. If unset,\n  /// defaults to maxDisplayLevel.\n  final int initialDisplayLevel;\n\n  /// The max level of rings to render in the sunburst. If unset, display all\n  /// data.\n  final int maxDisplayLevel;\n\n  SunburstArcRendererConfig(\n      {String? customRendererId,\n      double arcLength = 2 * pi,\n      List<ArcRendererDecorator<D>> arcRendererDecorators = const [],\n      double? arcRatio,\n      this.arcRatios,\n      int? arcWidth,\n      this.arcWidths,\n      this.colorAssignmentStrategy = SunburstColorStrategy.newShadePerLevel,\n      int layoutPaintOrder = LayoutViewPaintOrder.arc,\n      int? maxDisplayLevel,\n      int? initialDisplayLevel,\n      int minHoleWidthForCenterContent = 30,\n      double startAngle = -pi / 2,\n      double strokeWidthPx = 2.0,\n      SymbolRenderer? symbolRenderer})\n      : this.maxDisplayLevel = maxDisplayLevel ?? _maxInt32Value,\n        this.initialDisplayLevel =\n            initialDisplayLevel ?? maxDisplayLevel ?? _maxInt32Value,\n        super(\n            customRendererId: customRendererId,\n            arcLength: arcLength,\n            arcRatio: arcRatio,\n            arcWidth: arcWidth,\n            layoutPaintOrder: layoutPaintOrder,\n            minHoleWidthForCenterContent: minHoleWidthForCenterContent,\n            startAngle: startAngle,\n            strokeWidthPx: strokeWidthPx,\n            arcRendererDecorators: arcRendererDecorators);\n\n  @override\n  SunburstArcRenderer<D> build() {\n    return SunburstArcRenderer<D>(config: this, rendererId: customRendererId);\n  }\n}\n\n/// Strategies for assinging color to the arcs if colorFn is not provided for\n/// Series.\nenum SunburstColorStrategy {\n  /// Assign a new shade to each of the arcs.\n  newShadePerArc,\n\n  /// Assign a new shade to each ring of the sunburst.\n  newShadePerLevel,\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/sunburst/sunburst_chart.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math' show Rectangle;\n\nimport '../common/base_chart.dart' show BaseChart;\nimport '../common/datum_details.dart' show DatumDetails;\nimport '../common/selection_model/selection_model.dart' show SelectionModelType;\nimport '../common/series_renderer.dart' show rendererIdKey, SeriesRenderer;\nimport '../layout/layout_config.dart' show LayoutConfig;\nimport '../../data/tree.dart' show TreeNode;\nimport 'sunburst_arc_renderer.dart' show SunburstArcRenderer;\n\nclass SunburstChart<D> extends BaseChart<D> {\n  SunburstChart({LayoutConfig? layoutConfig})\n      : super(layoutConfig: layoutConfig);\n\n  @override\n  SeriesRenderer<D> makeDefaultRenderer() {\n    return SunburstArcRenderer<D>()\n      ..rendererId = SeriesRenderer.defaultRendererId;\n  }\n\n  /// Returns a list of datum details from selection model of [type].\n  @override\n  List<DatumDetails<D>> getDatumDetails(SelectionModelType type) {\n    final entries = <DatumDetails<D>>[];\n\n    for (final seriesDatum in getSelectionModel(type).selectedDatum) {\n      final rendererId = seriesDatum.series.getAttr(rendererIdKey);\n      final renderer = getSeriesRenderer(rendererId);\n\n      assert(renderer is SunburstArcRenderer<D>);\n\n      final details = (renderer as SunburstArcRenderer<D>)\n          .getExpandedDatumDetails(seriesDatum);\n\n      if (details != null) {\n        entries.add(details);\n      }\n    }\n\n    return entries;\n  }\n\n  Rectangle<int>? get centerContentBounds {\n    assert(defaultRenderer is SunburstArcRenderer<D>);\n    return (defaultRenderer as SunburstArcRenderer<D>).centerContentBounds;\n  }\n\n  void expandNode(TreeNode<D> node) {\n    assert(defaultRenderer is SunburstArcRenderer<D>);\n    (defaultRenderer as SunburstArcRenderer<D>).expandNode(node);\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/time_series/time_series_chart.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:collection' show LinkedHashMap;\n\nimport '../../common/date_time_factory.dart'\n    show DateTimeFactory, LocalDateTimeFactory;\nimport '../cartesian/axis/axis.dart' show Axis, NumericAxis;\nimport '../cartesian/axis/draw_strategy/small_tick_draw_strategy.dart'\n    show SmallTickRendererSpec;\nimport '../cartesian/axis/spec/axis_spec.dart' show AxisSpec;\nimport '../cartesian/axis/spec/date_time_axis_spec.dart' show DateTimeAxisSpec;\nimport '../cartesian/axis/time/date_time_axis.dart' show DateTimeAxis;\nimport '../cartesian/cartesian_chart.dart' show CartesianChart;\nimport '../common/series_renderer.dart' show SeriesRenderer;\nimport '../layout/layout_config.dart' show LayoutConfig;\nimport '../line/line_renderer.dart' show LineRenderer;\n\nclass TimeSeriesChart extends CartesianChart<DateTime> {\n  final DateTimeFactory dateTimeFactory;\n\n  TimeSeriesChart(\n      {bool? vertical,\n      LayoutConfig? layoutConfig,\n      NumericAxis? primaryMeasureAxis,\n      NumericAxis? secondaryMeasureAxis,\n      LinkedHashMap<String, NumericAxis>? disjointMeasureAxes,\n      this.dateTimeFactory = const LocalDateTimeFactory()})\n      : super(\n            vertical: vertical,\n            layoutConfig: layoutConfig,\n            domainAxis: DateTimeAxis(dateTimeFactory),\n            primaryMeasureAxis: primaryMeasureAxis,\n            secondaryMeasureAxis: secondaryMeasureAxis,\n            disjointMeasureAxes: disjointMeasureAxes);\n\n  @override\n  void initDomainAxis() {\n    domainAxis!.tickDrawStrategy = SmallTickRendererSpec<DateTime>()\n        .createDrawStrategy(context, graphicsFactory!);\n  }\n\n  @override\n  SeriesRenderer<DateTime> makeDefaultRenderer() {\n    return LineRenderer<DateTime>()\n      ..rendererId = SeriesRenderer.defaultRendererId;\n  }\n\n  @override\n  Axis<DateTime> createDomainAxisFromSpec(AxisSpec<DateTime> axisSpec) {\n    return (axisSpec as DateTimeAxisSpec).createDateTimeAxis(dateTimeFactory);\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/treemap/base_treemap_renderer.dart",
    "content": "// Copyright 2019 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:collection' show Queue;\nimport 'dart:math' show MutableRectangle, Point, Rectangle, min;\n\nimport 'package:charts_common/src/chart/common/base_chart.dart';\nimport 'package:charts_common/src/chart/common/chart_canvas.dart';\nimport 'package:charts_common/src/chart/common/datum_details.dart';\nimport 'package:charts_common/src/chart/common/processed_series.dart';\nimport 'package:charts_common/src/chart/common/series_datum.dart';\nimport 'package:charts_common/src/chart/common/series_renderer.dart';\nimport 'package:charts_common/src/common/math.dart' show NullablePoint;\nimport 'package:charts_common/src/common/style/style_factory.dart';\nimport 'package:charts_common/src/data/series.dart';\nimport 'package:charts_common/src/data/tree.dart';\nimport 'package:meta/meta.dart';\n\nimport 'treemap_label_decorator.dart';\nimport 'treemap_renderer_config.dart';\nimport 'treemap_renderer_element.dart';\n\n/// Key for storing a list of treemap renderer elements.\n///\n/// Each element contains a bounding rectangle for rendering.\nconst treeMapElementsKey =\n    AttributeKey<Iterable<TreeMapRendererElement<Object>>>(\n        'TreeMapRenderer.elements');\n\nabstract class BaseTreeMapRenderer<D> extends BaseSeriesRenderer<D> {\n  /// Default renderer ID for treemap.\n  static const defaultRendererId = 'treemap';\n\n  /// A hash map that allows accessing the renderer element drawn on the chart\n  /// from a treemap node.\n  final _treeNodeToRendererElement =\n      <TreeNode<Object>, TreeMapRendererElement<D>>{};\n\n  /// An ordered map of [_AnimatedTreeMapRect] that will get drawn on the\n  /// canvas.\n  final _animatedTreeMapRects = <D, _AnimatedTreeMapRect<D>>{};\n\n  /// Renderer configuration.\n  final TreeMapRendererConfig<D> config;\n\n  /// Decorator for rendering treemap node label.\n  final TreeMapLabelDecorator<D>? labelDecorator;\n\n  BaseChart<D>? _chart;\n\n  BaseTreeMapRenderer({required this.config, String? rendererId})\n      : labelDecorator = config.labelDecorator,\n        super(\n          rendererId: rendererId ?? defaultRendererId,\n          layoutPaintOrder: config.layoutPaintOrder,\n          symbolRenderer: config.symbolRenderer,\n        );\n\n  @override\n  void onAttach(BaseChart<D> chart) {\n    super.onAttach(chart);\n    _chart = chart;\n  }\n\n  /// Rtl direction setting from chart context.\n  bool get isRtl => _chart?.context.isRtl ?? false;\n\n  @override\n  void configureSeries(List<MutableSeries<D>> seriesList) {\n    assignMissingColors(seriesList, emptyCategoryUsesSinglePalette: true);\n    assignMissingStrokeWidths(seriesList);\n  }\n\n  @override\n  void preprocessSeries(List<MutableSeries<D>> seriesList) {\n    _ensureSingleTree(seriesList);\n\n    // Clears [_treeNodeToRendererElement] map when a new seriesList is passed\n    // in for preprocessing. The order in this map matters because the first\n    // entry is expected to be the root.\n    _treeNodeToRendererElement.clear();\n\n    for (final series in seriesList) {\n      final count = series.data.length;\n\n      // Populates [treeNodeToRendererElement] map entries.\n      for (var i = 0; i < count; i++) {\n        final node = series.data[i] as TreeNode<Object>;\n        _treeNodeToRendererElement[node] =\n            _createRendererElement(series, i, isLeaf: !node.hasChildren);\n      }\n      series.setAttr(treeMapElementsKey, _treeNodeToRendererElement.values);\n    }\n  }\n\n  /// Tiling algorithm for dividing a region into subregions of specified areas.\n  void tile(TreeNode<Object> node);\n\n  @override\n  void update(List<ImmutableSeries<D>> seriesList, bool isAnimating) {\n    // _visibleTreeMapRectKeys is used to remove any [_AnimatedTreeMapRect]s\n    // that were rendered in the previous draw cycles, but no longer have a\n    // corresponding datum in the new series data.\n    final _visibleTreeMapRectKeys = <D>{};\n\n    for (final series in seriesList) {\n      if (series.data.isNotEmpty) {\n        final root = series.data.first as TreeNode<Object>;\n        // Configures the renderer element for root node.\n        _configureRootRendererElement(root);\n\n        // Applies tiling algorithm to each node.\n        for (final datum in series.data) {\n          final node = datum as TreeNode<Object>;\n          tile(node);\n          final element = _getRendererElement(node)..refreshPaintProperties();\n          final rect = _createAnimatedTreeMapRect(element);\n          _visibleTreeMapRectKeys.add(rect.key);\n        }\n      }\n    }\n\n    _animatedTreeMapRects.forEach((_, rect) {\n      if (!_visibleTreeMapRectKeys.contains(rect.key)) {\n        rect.animateOut();\n      }\n    });\n  }\n\n  @override\n  void paint(ChartCanvas canvas, double animationPercent) {\n    if (animationPercent == 1.0) {\n      _animatedTreeMapRects.removeWhere((_, rect) => rect.animatingOut);\n    }\n\n    _animatedTreeMapRects.forEach((_, animatedRect) {\n      final element = animatedRect.getCurrentRect(animationPercent);\n      final rect = element.boundingRect;\n\n      // canvas.drawRRect is used instead of canvas.drawRect because drawRRect\n      // supports FillPatternType.forwardHatch.\n      canvas.drawRRect(\n        rect,\n        fill: element.fillColor,\n        fillPattern: element.fillPattern,\n        patternStrokeWidthPx: config.patternStrokeWidthPx,\n        patternColor: element.patternColor,\n        stroke: element.strokeColor,\n        strokeWidthPx: element.strokeWidthPx!.toDouble(),\n        radius: 0,\n        roundTopLeft: false,\n        roundTopRight: false,\n        roundBottomLeft: false,\n        roundBottomRight: false,\n      );\n\n      // Paint label.\n      labelDecorator?.decorate(element, canvas, graphicsFactory!,\n          drawBounds: drawBounds!,\n          animationPercent: animationPercent,\n          rtl: isRtl,\n          // only leaf node could possibly render label vertically.\n          renderVertically: element.isLeaf && rect.width < rect.height,\n          renderMultiline: element.isLeaf);\n    });\n  }\n\n  /// Datum details of nearest rectangles in the treemap.\n  @override\n  List<DatumDetails<D>> getNearestDatumDetailPerSeries(\n    Point<double> chartPoint,\n    bool byDomain,\n    Rectangle<int>? boundsOverride, {\n    bool selectOverlappingPoints = false,\n    bool selectExactEventLocation = false,\n  }) {\n    final nearest = <DatumDetails<D>>[];\n\n    // Checks if the [chartPoint] is within bounds.\n    if (!isPointWithinBounds(chartPoint, boundsOverride)) return nearest;\n\n    final root = _treeNodeToRendererElement.entries.first.key;\n    final queue = Queue<TreeNode<Object>>()..add(root);\n\n    while (queue.isNotEmpty) {\n      final node = queue.removeFirst();\n      final element = _getRendererElement(node);\n\n      if (element.boundingRect.containsPoint(chartPoint)) {\n        nearest.add(DatumDetails<D>(\n          index: element.index,\n          series: element.series,\n          datum: node,\n          domain: element.domain,\n          measure: element.measure,\n          domainDistance: 0.0,\n          measureDistance: 0.0,\n        ));\n        // No need to verify remaining siblings.\n        queue.clear();\n\n        // Only processes nodes whose parents contain the [chartPoint].\n        // This reduces the number of nodes to verify.\n        queue.addAll(node.children);\n      }\n    }\n\n    // Prioritizes nodes with larger depth;\n    nearest.sort((a, b) {\n      final nodeA = a.datum as TreeNode<Object>;\n      final nodeB = b.datum as TreeNode<Object>;\n      return nodeB.depth.compareTo(nodeA.depth);\n    });\n    return nearest;\n  }\n\n  @override\n  DatumDetails<D> addPositionToDetailsForSeriesDatum(\n      DatumDetails<D> details, SeriesDatum<D> seriesDatum) {\n    final bounds =\n        _getRendererElement(seriesDatum.datum as TreeNode<Object>).boundingRect;\n    final chartPosition = Point<double>(\n        (isRtl ? bounds.left : bounds.right).toDouble(),\n        (bounds.top + (bounds.height / 2)).toDouble());\n    return DatumDetails.from(details,\n        chartPosition: NullablePoint.from(chartPosition));\n  }\n\n  /// Assigns missing colors in case when color accessor functions are not set.\n  ///\n  /// Assigned color is based on the depth of each node.\n  @override\n  void assignMissingColors(Iterable<MutableSeries<D>> seriesList,\n      {required bool emptyCategoryUsesSinglePalette}) {\n    for (final series in seriesList) {\n      final colorPalettes =\n          StyleFactory.style.getOrderedPalettes(series.data.length);\n      final count = colorPalettes.length;\n\n      series.fillColorFn ??= (int? index) {\n        var node = series.data[index!] as TreeNode<Object>;\n        return colorPalettes[node.depth % count].shadeDefault;\n      };\n\n      // Pattern color and stroke color defaults to the default config stroke\n      // color if no accessor is provided.\n      series.colorFn ??= (index) => config.strokeColor;\n      series.patternColorFn ??= (index) => config.strokeColor;\n    }\n  }\n\n  /// Assigns missing stroke widths in case when strokeWidthPx accessor\n  /// functions are not set.\n  @protected\n  void assignMissingStrokeWidths(Iterable<MutableSeries<D>> seriesList) {\n    for (final series in seriesList) {\n      series.strokeWidthPxFn ??= (_) => config.strokeWidthPx;\n    }\n  }\n\n  /// Available bounding rectangle that can be used to lay out the child\n  /// renderer elements.\n  ///\n  /// Available bounding rectangle is computed after padding is applied.\n  @protected\n  MutableRectangle availableLayoutBoundingRect(TreeNode<Object> node) {\n    final element = _getRendererElement(node);\n    final rect = element.boundingRect;\n    final padding = config.rectPaddingPx;\n\n    var top = rect.top + padding.topPx;\n    var left = rect.left + padding.leftPx;\n    var width = rect.width - padding.leftPx - padding.rightPx;\n    var height = rect.height - padding.topPx - padding.bottomPx;\n\n    // Handles an edge case when width or height is negative.\n    if (width < 0) {\n      left += width / 2;\n      width = 0;\n    }\n    if (height < 0) {\n      top += height / 2;\n      height = 0;\n    }\n    return MutableRectangle(left, top, width, height);\n  }\n\n  /// Scales the area of each renderer element in [children] by a [scaleFactor].\n  ///\n  /// [scaleFactor] should be calculated based on the available layout area and\n  /// the measure which the available layout area represents.\n  @protected\n  void scaleArea(Iterable<TreeNode<Object>> children, num scaleFactor) {\n    for (final child in children) {\n      final element = _getRendererElement(child);\n      final area = element.measure * (scaleFactor < 0 ? 0 : scaleFactor);\n      element.area = area <= 0 ? 0 : area;\n    }\n  }\n\n  /// Gets the measure for a tree [node].\n  @protected\n  num measureForTreeNode(TreeNode<Object> node) =>\n      _getRendererElement(node).measure;\n\n  /// Gets the area of a [Rectangle].\n  @protected\n  num areaForRectangle(Rectangle rect) => rect.height * rect.width;\n\n  /// Gets the area for a tree [node].\n  @protected\n  num areaForTreeNode(TreeNode<Object> node) => _getRendererElement(node).area;\n\n  /// Positions each renderer element in [nodes] within the [boundingRect].\n  ///\n  /// [side] is defined as the smallest side of the [layoutArea].\n  ///\n  /// Consider the following boundingRect:\n  /// ```\n  /// boundingRect:\n  ///          ------------------\n  ///         |************|     |\n  ///  (side) |*layoutArea*|     | height\n  ///         |************|     |\n  ///          ------------------\n  ///                 width\n  /// ```\n  @protected\n  void position(Iterable<TreeNode<Object>> nodes, MutableRectangle boundingRect,\n      num side, num layoutArea) {\n    var top = boundingRect.top;\n    var left = boundingRect.left;\n    var length = side > 0 ? (layoutArea / side) : 0;\n\n    // [side] is equal to the height of the boundingRect, so stacks rectangles\n    // vertically. [length] is the width of the stacking rectangles.\n    if (side == boundingRect.height) {\n      // Truncates the length since it is out of bounds.\n      if (length > boundingRect.width) length = boundingRect.width.toInt();\n      for (final node in nodes) {\n        final element = _getRendererElement(node);\n        final height = min(boundingRect.top + boundingRect.height - top,\n            length > 0 ? (element.area / length) : 0);\n        element.boundingRect = Rectangle(left, top, length, height);\n        top += height;\n      }\n      boundingRect.left += length;\n      boundingRect.width -= length;\n    } else {\n      // Positions rectangles horizontally.\n      if (length > boundingRect.height) length = boundingRect.height.toInt();\n      for (final node in nodes) {\n        final element = _getRendererElement(node);\n        final width = min(boundingRect.left + boundingRect.width - left,\n            length > 0 ? (element.area / length) : 0);\n        element.boundingRect = Rectangle(left, top, width, length);\n        left += width;\n      }\n      boundingRect.top += length;\n      boundingRect.height -= length;\n    }\n  }\n\n  void _configureRootRendererElement(TreeNode<Object> root) {\n    // Root should take up the entire [drawBounds] area.\n    final drawBounds = this.drawBounds!;\n    _getRendererElement(root)\n      ..boundingRect = drawBounds\n      ..area = areaForRectangle(drawBounds);\n  }\n\n  /// Creates an [_AnimatedTreeMapRect].\n  ///\n  /// This object contains previous, current, and target animation state of\n  /// treemap renderer [element].\n  _AnimatedTreeMapRect<D> _createAnimatedTreeMapRect(\n      TreeMapRendererElement<D> element) {\n    final key = element.domain;\n    // Creates a new _AnimatedTreeMapRect if not exists. Otherwise, moves the\n    // existing one to the end of the list so that the iteration order of\n    // _AnimatedTreeMapRects is preserved. This is important because the order\n    // of rects in _animatedTreeMapRects determines the painting order.\n    final rect = _animatedTreeMapRects.containsKey(key)\n        ? _animatedTreeMapRects.remove(key)!\n        : _AnimatedTreeMapRect<D>(key: key);\n\n    _animatedTreeMapRects[key] = rect;\n    return rect..setNewTarget(element);\n  }\n\n  /// Creates a basic [TreeMapRendererElement].\n  ///\n  /// `boundingRect` and `area` are set after tile function is applied.\n  TreeMapRendererElement<D> _createRendererElement(\n    MutableSeries<D> series,\n    int index, {\n    required bool isLeaf,\n  }) =>\n      TreeMapRendererElement<D>(\n        domain: series.domainFn(index),\n        measure: series.measureFn(index)!,\n        isLeaf: isLeaf,\n        index: index,\n        series: series,\n      );\n\n  TreeMapRendererElement<D> _getRendererElement(TreeNode<Object> node) {\n    final element = _treeNodeToRendererElement[node];\n    assert(\n        element != null, 'There is no associated renderer element for $node.');\n    return element!;\n  }\n\n  void _ensureSingleTree(List<ImmutableSeries<D>> seriesList) {\n    assert(seriesList.length <= 1,\n        'TreeMapRenderer only supports a single series at most.');\n  }\n}\n\n/// A representation of the animation state of [TreeMapRendererElement].\nclass _AnimatedTreeMapRect<D> {\n  final D key;\n\n  /// A previous [TreeMapRendererElement] before animation.\n  TreeMapRendererElement<D>? _previousRect;\n\n  /// A target [TreeMapRendererElement] after animation is performed.\n  late TreeMapRendererElement<D> _targetRect;\n\n  /// Current [TreeMapRendererElement] at a given animation percent time.\n  TreeMapRendererElement<D>? _currentRect;\n\n  // Flag indicating whether this rect is being animated out of the chart.\n  bool animatingOut = false;\n\n  _AnimatedTreeMapRect({required this.key});\n\n  /// Animates a rect that was removed from the tree out of the view.\n  ///\n  /// Animates the height and width of the rect down to zero, centered in the\n  /// middle of the original rect.\n  void animateOut() {\n    final newTarget = _currentRect!.clone();\n    final rect = newTarget.boundingRect;\n    newTarget.boundingRect = Rectangle(\n        rect.left + (rect.width / 2), rect.top + (rect.height / 2), 0, 0);\n    newTarget.strokeWidthPx = 0.0;\n\n    setNewTarget(newTarget);\n    animatingOut = true;\n  }\n\n  void setNewTarget(TreeMapRendererElement<D> newTarget) {\n    animatingOut = false;\n    // Only when [currentRect] is null, [currentRect] should be [newTarget].\n    _currentRect ??= newTarget.clone();\n    _previousRect = _currentRect!.clone();\n    _targetRect = newTarget;\n  }\n\n  /// Current [TreeMapRendererElement] at a given animation percent time.\n  TreeMapRendererElement<D> getCurrentRect(double animationPercent) {\n    if (animationPercent == 1.0 || _previousRect == null) {\n      _currentRect = _targetRect;\n      _previousRect = _targetRect;\n      return _currentRect!;\n    }\n\n    _currentRect!\n        .updateAnimationPercent(_previousRect!, _targetRect, animationPercent);\n    return _currentRect!;\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/treemap/dice_treemap_renderer.dart",
    "content": "// Copyright 2019 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'package:charts_common/src/data/tree.dart';\n\nimport 'base_treemap_renderer.dart';\nimport 'treemap_renderer_config.dart';\n\n/// A treemap renderer that renders a treemap with dice layout.\nclass DiceTreeMapRenderer<D> extends BaseTreeMapRenderer<D> {\n  DiceTreeMapRenderer({String? rendererId, TreeMapRendererConfig<D>? config})\n      : super(\n            config:\n                config ?? TreeMapRendererConfig(tileType: TreeMapTileType.dice),\n            rendererId: rendererId ?? BaseTreeMapRenderer.defaultRendererId);\n\n  /// Uses dicing as the tiling algorithm for this tree map.\n  @override\n  void tile(TreeNode<Object> node) {\n    final children = node.children;\n    if (children.isNotEmpty) {\n      final rect = availableLayoutBoundingRect(node);\n      final measure = measureForTreeNode(node);\n      final scaleFactor = measure == 0 ? 0 : areaForRectangle(rect) / measure;\n      scaleArea(children, scaleFactor);\n      position(children, rect, rect.height, areaForRectangle(rect));\n    }\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/treemap/slice_dice_treemap_renderer.dart",
    "content": "// Copyright 2019 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'package:charts_common/src/data/tree.dart';\n\nimport 'base_treemap_renderer.dart';\nimport 'treemap_renderer_config.dart';\n\n/// A treemap renderer that renders a treemap with slice-and-dice layout.\nclass SliceDiceTreeMapRenderer<D> extends BaseTreeMapRenderer<D> {\n  SliceDiceTreeMapRenderer(\n      {String? rendererId, TreeMapRendererConfig<D>? config})\n      : super(\n            config: config ??\n                TreeMapRendererConfig(tileType: TreeMapTileType.sliceDice),\n            rendererId: rendererId ?? BaseTreeMapRenderer.defaultRendererId);\n\n  /// Uses slice-and-dice as the tiling algorithm for this tree map.\n  @override\n  void tile(TreeNode<Object> node) {\n    final children = node.children;\n    if (children.isNotEmpty) {\n      final rect = availableLayoutBoundingRect(node);\n      final measure = measureForTreeNode(node);\n      final scaleFactor = measure == 0 ? 0 : areaForRectangle(rect) / measure;\n      scaleArea(children, scaleFactor);\n      position(children, rect, node.depth & 1 == 1 ? rect.height : rect.width,\n          areaForRectangle(rect));\n    }\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/treemap/slice_treemap_renderer.dart",
    "content": "// Copyright 2019 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'package:charts_common/src/data/tree.dart';\n\nimport 'base_treemap_renderer.dart';\nimport 'treemap_renderer_config.dart';\n\n/// A treemap renderer that renders a treemap with slice layout.\nclass SliceTreeMapRenderer<D> extends BaseTreeMapRenderer<D> {\n  SliceTreeMapRenderer({String? rendererId, TreeMapRendererConfig<D>? config})\n      : super(\n            config: config ??\n                TreeMapRendererConfig(tileType: TreeMapTileType.slice),\n            rendererId: rendererId ?? BaseTreeMapRenderer.defaultRendererId);\n\n  /// Uses slicing as the tiling algorithm for this tree map.\n  @override\n  void tile(TreeNode<Object> node) {\n    final children = node.children;\n    if (children.isNotEmpty) {\n      final rect = availableLayoutBoundingRect(node);\n      final measure = measureForTreeNode(node);\n      final scaleFactor = measure == 0 ? 0 : areaForRectangle(rect) / measure;\n      scaleArea(children, scaleFactor);\n      position(children, rect, rect.width, areaForRectangle(rect));\n    }\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/treemap/squarified_treemap_renderer.dart",
    "content": "// Copyright 2019 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:collection' show Queue;\nimport 'dart:math' as math;\n\nimport 'package:charts_common/src/data/tree.dart';\n\nimport 'base_treemap_renderer.dart';\nimport 'treemap_renderer_config.dart';\n\n/// A treemap renderer that renders a squarified treemap.\nclass SquarifiedTreeMapRenderer<D> extends BaseTreeMapRenderer<D> {\n  /// Golden ratio.\n  final _ratio = .5 * (1 + math.sqrt(5));\n\n  SquarifiedTreeMapRenderer(\n      {String? rendererId, TreeMapRendererConfig<D>? config})\n      : super(\n            config: config ??\n                TreeMapRendererConfig(tileType: TreeMapTileType.squarified),\n            rendererId: rendererId ?? BaseTreeMapRenderer.defaultRendererId);\n\n  /// Uses squarification as the tiling algorithm for this tree map.\n  ///\n  /// The idea is to present treemap layouts in which the rectangles approximate\n  /// squares.\n  ///\n  /// For more information about squarify technique, see:\n  /// Squarified Treemaps:\n  /// https://www.win.tue.nl/~vanwijk/stm.pdf\n  /// Squarify algorithm from Charted:\n  /// https://cs.corp.google.com/piper///depot/google3/third_party/dart/charted/lib/layout/src/treemap_layout.dart?l=158\n  @override\n  void tile(TreeNode<Object> node) {\n    final children = node.children;\n    if (children.isNotEmpty) {\n      final remainingNodes = Queue.of(children);\n      final rect = availableLayoutBoundingRect(node);\n      final analyzer = _SquarifyRatioAnalyzer(_ratio, areaForTreeNode);\n\n      var bestScore = double.infinity;\n      var width = math.min(rect.width, rect.height);\n      final measure = measureForTreeNode(node);\n      final scaleFactor = measure == 0 ? 0 : areaForRectangle(rect) / measure;\n      scaleArea(children, scaleFactor);\n\n      while (remainingNodes.isNotEmpty) {\n        final child = remainingNodes.first;\n        analyzer.addNode(child);\n        final score = analyzer.worst(width).toDouble();\n\n        // Adding a new child rectangle improves score for the aspect ratio .\n        if (score <= bestScore) {\n          remainingNodes.removeFirst();\n          bestScore = score;\n        } else {\n          analyzer.removeLast();\n          position(analyzer.nodes, rect, width, analyzer.layoutArea);\n          width = math.min(rect.width, rect.height);\n          analyzer.reset();\n          bestScore = double.infinity;\n        }\n      }\n      if (analyzer.nodes.isNotEmpty) {\n        position(analyzer.nodes, rect, width, analyzer.layoutArea);\n        analyzer.reset();\n      }\n    }\n  }\n}\n\n/// An analyzer that computes whether adding a node to a layout can improve the\n/// aspect ratio of the layout.\nclass _SquarifyRatioAnalyzer {\n  /// A accessor function that returns area of a [TreeNode].\n  final AreaFn _areaFn;\n\n  /// Target aspect ratio.\n  final num _ratio;\n\n  /// List of processing nodes.\n  final nodes = <TreeNode<Object>>[];\n\n  var _layoutArea = 0.0;\n\n  _SquarifyRatioAnalyzer(this._ratio, this._areaFn);\n\n  /// Adds a node for processing.\n  void addNode(TreeNode<Object> node) {\n    nodes.add(node);\n    _layoutArea += _areaFn(node);\n  }\n\n  /// Removes the last node added for processing.\n  void removeLast() {\n    _layoutArea -= _areaFn(nodes.removeLast());\n  }\n\n  /// Allocated area for laying out processing [nodes].\n  num get layoutArea => _layoutArea;\n\n  /// Aspect-ratio score for the list of processing [nodes] in a given [width].\n  ///\n  /// [width] is defined as the smallest side of a rectangle.\n  ///\n  /// Underlying equation:\n  ///   max(w^2 * r_max * ratio / (r_layout^2),\n  ///     r_layout^2 / (w^2 * r_min * ratio)).\n  num worst(num width) {\n    var rMin = double.infinity;\n    var rMax = 0.0;\n\n    // Finds rMin (i.e minimum area) and rMax (i.e maximum area) in [nodes].\n    for (final node in nodes) {\n      final area = _areaFn(node).toDouble();\n      if (area <= 0) continue;\n      if (area < rMin) rMin = area;\n      if (area > rMax) rMax = area;\n    }\n    final sqWidth = _square(width);\n    final sqArea = _square(_layoutArea);\n    return sqArea > 0\n        ? math.max(sqWidth * rMax * _ratio / sqArea,\n            sqArea / (sqWidth * rMin * _ratio))\n        : double.infinity;\n  }\n\n  void reset() {\n    nodes.clear();\n    _layoutArea = 0.0;\n  }\n\n  /// Calculates the square of a number [n].\n  num _square(num n) => n * n;\n}\n\n/// A function type that returns area for a tree [node].\ntypedef AreaFn = num Function(TreeNode<Object> node);\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/treemap/treemap_chart.dart",
    "content": "// Copyright 2019 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'package:charts_common/src/chart/common/base_chart.dart';\nimport 'package:charts_common/src/chart/common/datum_details.dart';\nimport 'package:charts_common/src/chart/common/processed_series.dart';\nimport 'package:charts_common/src/chart/common/selection_model/selection_model.dart';\nimport 'package:charts_common/src/chart/common/series_renderer.dart';\nimport 'package:charts_common/src/chart/layout/layout_config.dart';\n\nimport 'squarified_treemap_renderer.dart';\n\nclass TreeMapChart<D> extends BaseChart<D> {\n  TreeMapChart({LayoutConfig? layoutConfig})\n      : super(layoutConfig: layoutConfig ?? LayoutConfig());\n\n  @override\n  void drawInternal(List<MutableSeries<D>> seriesList,\n      {bool? skipAnimation, bool? skipLayout}) {\n    if (seriesList.length > 1) {\n      throw ArgumentError('TreeMapChart can only render a single tree.');\n    }\n    super.drawInternal(seriesList,\n        skipAnimation: skipAnimation, skipLayout: skipLayout);\n  }\n\n  /// Squarified treemap is used as default renderer.\n  @override\n  SeriesRenderer<D> makeDefaultRenderer() {\n    return SquarifiedTreeMapRenderer<D>()\n      ..rendererId = SeriesRenderer.defaultRendererId;\n  }\n\n  /// Returns a list of datum details from the selection model of [type].\n  @override\n  List<DatumDetails<D>> getDatumDetails(SelectionModelType type) {\n    final details = <DatumDetails<D>>[];\n    final treeMapSelection = getSelectionModel(type);\n\n    for (final seriesDatum in treeMapSelection.selectedDatum) {\n      final series = seriesDatum.series;\n      final datumIndex = seriesDatum.index;\n      final renderer = getSeriesRenderer(series.getAttr(rendererIdKey));\n\n      final datumDetails = renderer.addPositionToDetailsForSeriesDatum(\n          DatumDetails(\n              datum: seriesDatum.datum,\n              domain: series.domainFn(datumIndex),\n              measure: series.measureFn(datumIndex),\n              series: seriesDatum.series,\n              color: series.colorFn!(datumIndex)),\n          seriesDatum);\n      details.add(datumDetails);\n    }\n    return details;\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/treemap/treemap_label_decorator.dart",
    "content": "// Copyright 2019 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math' show Rectangle, pi;\n\nimport 'package:charts_common/src/chart/cartesian/axis/spec/axis_spec.dart';\nimport 'package:charts_common/src/chart/common/chart_canvas.dart';\nimport 'package:charts_common/src/common/color.dart';\nimport 'package:charts_common/src/common/graphics_factory.dart';\nimport 'package:charts_common/src/common/text_element.dart';\nimport 'package:charts_common/src/common/text_style.dart';\nimport 'package:charts_common/src/common/text_utils.dart';\nimport 'package:charts_common/src/data/series.dart';\n\nimport 'treemap_renderer_decorator.dart';\nimport 'treemap_renderer_element.dart';\n\n/// Decorator that renders label for treemap renderer element.\nclass TreeMapLabelDecorator<D> extends TreeMapRendererDecorator<D> {\n  // Default configuration\n  static const _defaultLabelPadding = 4;\n  static const _defaultFontSize = 12;\n  static final _defaultLabelStyle =\n      TextStyleSpec(fontSize: _defaultFontSize, color: Color.black);\n\n  /// Rotation value of 90 degrees clockwise.\n  static const _90DegreeClockwise = pi / 2;\n\n  /// Text style spec for labels.\n  final TextStyleSpec labelStyleSpec;\n\n  /// Padding of the label text.\n  final int labelPadding;\n\n  /// Whether or not to allow labels to draw outside of their bounding box.\n  final bool allowLabelOverflow;\n\n  /// Whether or not drawing a label in multiple lines if there is enough\n  /// space.\n  final bool enableMultiline;\n\n  TreeMapLabelDecorator(\n      {TextStyleSpec? labelStyleSpec,\n      this.labelPadding = _defaultLabelPadding,\n      this.allowLabelOverflow = true,\n      this.enableMultiline = false})\n      : labelStyleSpec = labelStyleSpec ?? _defaultLabelStyle;\n\n  @override\n  void decorate(TreeMapRendererElement<D> rendererElement, ChartCanvas canvas,\n      GraphicsFactory graphicsFactory,\n      {required Rectangle drawBounds,\n      required double animationPercent,\n      bool rtl = false,\n      bool renderVertically = false,\n      bool renderMultiline = false}) {\n    // Decorates the renderer elements when animation is completed.\n    if (animationPercent != 1.0) return;\n\n    // Creates [TextStyle] from [TextStyleSpec] to be used by all the elements.\n    // The [GraphicsFactory] is needed since it cannot be created earlier.\n    final labelStyle = _asTextStyle(graphicsFactory, labelStyleSpec);\n\n    final labelFn = rendererElement.series.labelAccessorFn;\n    final datumIndex = rendererElement.index;\n    final label = labelFn != null ? labelFn(datumIndex) : null;\n\n    // Skips if this element has no label.\n    if (label == null || label.isEmpty) return;\n\n    // Uses datum specific label style if provided.\n    final datumLabelStyle = _datumStyle(\n        rendererElement.series.insideLabelStyleAccessorFn,\n        datumIndex,\n        graphicsFactory,\n        defaultStyle: labelStyle);\n    final rect = rendererElement.boundingRect;\n    final labelElement = graphicsFactory.createTextElement(label)\n      ..textStyle = datumLabelStyle\n      ..textDirection = rtl ? TextDirection.rtl : TextDirection.ltr;\n    final labelHeight = labelElement.measurement.verticalSliceWidth;\n    final maxLabelHeight =\n        (renderVertically ? rect.width : rect.height) - (labelPadding * 2);\n    final maxLabelWidth =\n        (renderVertically ? rect.height : rect.width) - (labelPadding * 2);\n    final multiline = enableMultiline && renderMultiline;\n    final parts = wrapLabelLines(\n        labelElement, graphicsFactory, maxLabelWidth, maxLabelHeight,\n        allowLabelOverflow: allowLabelOverflow, multiline: multiline);\n\n    for (var index = 0; index < parts.length; index++) {\n      final segment = _createLabelSegment(\n          rect, labelHeight, parts[index], index,\n          rtl: rtl, rotate: renderVertically);\n\n      // Draws a label inside of a treemap renderer element.\n      canvas.drawText(segment.text, segment.xOffet, segment.yOffset,\n          rotation: segment.rotationAngle);\n    }\n  }\n\n  /// Converts [TextStyleSpec] to [TextStyle].\n  TextStyle _asTextStyle(\n          GraphicsFactory graphicsFactory, TextStyleSpec labelSpec) =>\n      graphicsFactory.createTextPaint()\n        ..color = labelSpec.color ?? Color.black\n        ..fontFamily = labelSpec.fontFamily\n        ..fontSize = labelSpec.fontSize ?? _defaultFontSize\n        ..lineHeight = labelSpec.lineHeight;\n\n  /// Gets datum specific style.\n  TextStyle _datumStyle(AccessorFn<TextStyleSpec>? labelStyleFn, int datumIndex,\n      GraphicsFactory graphicsFactory,\n      {required TextStyle defaultStyle}) {\n    final styleSpec = labelStyleFn?.call(datumIndex);\n    return (styleSpec != null)\n        ? _asTextStyle(graphicsFactory, styleSpec)\n        : defaultStyle;\n  }\n\n  _TreeMapLabelSegment _createLabelSegment(Rectangle elementBoundingRect,\n      num labelHeight, TextElement labelElement, int position,\n      {bool rtl = false, bool rotate = false}) {\n    num xOffset;\n    num yOffset;\n\n    // Set x offset for each line.\n    if (rotate) {\n      xOffset = elementBoundingRect.right -\n          labelPadding -\n          2 * labelElement.textStyle!.fontSize! -\n          labelHeight * position;\n    } else if (rtl) {\n      xOffset = elementBoundingRect.right - labelPadding;\n    } else {\n      xOffset = elementBoundingRect.left + labelPadding;\n    }\n\n    // Set y offset for each line.\n    if (!rotate) {\n      yOffset =\n          elementBoundingRect.top + labelPadding + (labelHeight * position);\n    } else if (rtl) {\n      yOffset = elementBoundingRect.bottom - labelPadding;\n    } else {\n      yOffset = elementBoundingRect.top + labelPadding;\n    }\n\n    return _TreeMapLabelSegment(labelElement, xOffset.toInt(), yOffset.toInt(),\n        rotate ? _90DegreeClockwise : 0.0);\n  }\n}\n\n/// Represents a segment of a label that will be drawn in a single line.\nclass _TreeMapLabelSegment {\n  /// Text to be drawn on the canvas.\n  final TextElement text;\n\n  /// x-coordinate offset for [text].\n  final int xOffet;\n\n  /// y-coordinate offset for [text].\n  final int yOffset;\n\n  /// Rotation angle for drawing [text].\n  final double rotationAngle;\n\n  _TreeMapLabelSegment(\n      this.text, this.xOffet, this.yOffset, this.rotationAngle);\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/treemap/treemap_renderer_config.dart",
    "content": "// Copyright 2019 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'package:charts_common/src/chart/common/series_renderer_config.dart';\nimport 'package:charts_common/src/chart/layout/layout_view.dart';\nimport 'package:charts_common/src/common/color.dart';\nimport 'package:charts_common/src/common/style/style_factory.dart';\nimport 'package:charts_common/src/common/symbol_renderer.dart';\n\nimport 'base_treemap_renderer.dart';\nimport 'dice_treemap_renderer.dart';\nimport 'slice_dice_treemap_renderer.dart';\nimport 'slice_treemap_renderer.dart';\nimport 'squarified_treemap_renderer.dart';\nimport 'treemap_label_decorator.dart';\n\n/// Configuration for a [BaseTreeMapRenderer].\nclass TreeMapRendererConfig<D> extends LayoutViewConfig\n    implements SeriesRendererConfig<D> {\n  /// Default padding of a treemap rectangle.\n  static const _defaultRectPadding =\n      ViewMargin(topPx: 26, leftPx: 4, rightPx: 4, bottomPx: 4);\n\n  @override\n  final String? customRendererId;\n\n  @override\n  final SymbolRenderer symbolRenderer;\n\n  @override\n  final rendererAttributes = RendererAttributes();\n\n  /// Tiling algorithm, which is the way to divide a region into sub-regions of\n  /// specified areas, in the treemap.\n  final TreeMapTileType tileType;\n\n  /// The order to paint this renderer on the canvas.\n  final int layoutPaintOrder;\n\n  /// Padding of the treemap rectangle.\n  final ViewMargin rectPaddingPx;\n\n  /// Stroke width of the border of the treemap rectangle.\n  final double strokeWidthPx;\n\n  /// Stroke color of the border of the treemap rectangle.\n  final Color strokeColor;\n\n  /// Pattern stroke width of the treemap rectangle.\n  final double patternStrokeWidthPx;\n\n  /// Decorator for optionally decorating treemap rectangle label.\n  final TreeMapLabelDecorator<D>? labelDecorator;\n\n  TreeMapRendererConfig(\n      {this.customRendererId,\n      this.patternStrokeWidthPx = 1.0,\n      this.strokeWidthPx = 1.0,\n      this.layoutPaintOrder = LayoutViewPaintOrder.treeMap,\n      this.rectPaddingPx = _defaultRectPadding,\n      this.tileType = TreeMapTileType.squarified,\n      this.labelDecorator,\n      Color? strokeColor,\n      SymbolRenderer? symbolRenderer})\n      : strokeColor = strokeColor ?? StyleFactory.style.black,\n        symbolRenderer = symbolRenderer ?? RectSymbolRenderer();\n\n  @override\n  BaseTreeMapRenderer<D> build() {\n    switch (tileType) {\n      case TreeMapTileType.dice:\n        return DiceTreeMapRenderer<D>(\n            config: this, rendererId: customRendererId);\n      case TreeMapTileType.slice:\n        return SliceTreeMapRenderer<D>(\n            config: this, rendererId: customRendererId);\n      case TreeMapTileType.sliceDice:\n        return SliceDiceTreeMapRenderer<D>(\n            config: this, rendererId: customRendererId);\n      default:\n        return SquarifiedTreeMapRenderer<D>(\n            config: this, rendererId: customRendererId);\n    }\n  }\n}\n\n/// Tiling algorithm, which is the way to divide a region into subregions of\n/// specified areas, in a treemap.\n///\n/// * [dice] - Renders rectangles in dice layout.\n/// * [slice] - Renders rectangles in slice layout.\n/// * [sliceDice] - Renders rectangles in slice-and-dice layout.\n/// * [squarified] - Renders rectangles such that their aspect-ratios approach\n/// one as close as possible.\nenum TreeMapTileType { dice, slice, sliceDice, squarified }\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/treemap/treemap_renderer_decorator.dart",
    "content": "// Copyright 2019 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math' show Rectangle;\n\nimport 'package:charts_common/src/chart/common/chart_canvas.dart';\nimport 'package:charts_common/src/common/graphics_factory.dart';\n\nimport 'treemap_renderer_element.dart';\n\n/// Decorator that gets rendered after [TreeMapRendererElement]s are rendered.\nabstract class TreeMapRendererDecorator<D> {\n  const TreeMapRendererDecorator();\n\n  /// Paints decorator on top of [rendererElement].\n  void decorate(TreeMapRendererElement<D> rendererElement, ChartCanvas canvas,\n      GraphicsFactory graphicsFactory,\n      {required Rectangle drawBounds,\n      required double animationPercent,\n      bool rtl = false,\n      bool renderVertically = false,\n      bool renderMultiline = false});\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/chart/treemap/treemap_renderer_element.dart",
    "content": "// Copyright 2019 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math' show Rectangle;\n\nimport 'package:charts_common/src/chart/common/chart_canvas.dart';\nimport 'package:charts_common/src/chart/common/processed_series.dart';\nimport 'package:charts_common/src/common/color.dart';\n\n/// A renderer element that represents a TreeNode.\nclass TreeMapRendererElement<D> {\n  /// Bounding rectangle of this element.\n  Rectangle<num> get boundingRect => _boundingRect!;\n  set boundingRect(Rectangle<num> value) => _boundingRect = value;\n  Rectangle<num>? _boundingRect;\n\n  /// Occupied area of this element in pixel.\n  num get area => _area!;\n  set area(num value) => _area = value;\n  num? _area;\n\n  /// Fill color of this element.\n  Color? fillColor;\n\n  /// Fill pattern of the background of the treemap rectangle.\n  FillPatternType? fillPattern;\n\n  /// Pattern color of this element.\n  Color? patternColor;\n\n  /// Stroke color of this element.\n  Color? strokeColor;\n\n  /// Whether this element is a leaf in the treemap.\n  bool isLeaf;\n\n  /// Stroke width of this element.\n  num? strokeWidthPx;\n\n  /// Associated index in the [series].\n  int index;\n\n  /// Original series.\n  ImmutableSeries<D> series;\n\n  /// Domain of this element.\n  D domain;\n\n  /// Measure of this element.\n  num measure;\n\n  TreeMapRendererElement({\n    Rectangle<num>? boundingRect,\n    num? area,\n    this.fillColor,\n    this.fillPattern,\n    this.patternColor,\n    this.strokeColor,\n    required this.isLeaf,\n    this.strokeWidthPx,\n    required this.index,\n    required this.series,\n    required this.domain,\n    required this.measure,\n  })   : _boundingRect = boundingRect,\n        _area = area;\n\n  /// Clones a new renderer element with the same properties.\n  TreeMapRendererElement<D> clone() => TreeMapRendererElement(\n        boundingRect: _boundingRect == null\n            ? null\n            : Rectangle.fromPoints(\n                boundingRect.topLeft, boundingRect.bottomRight),\n        area: area,\n        fillPattern: fillPattern,\n        fillColor:\n            fillColor == null ? null : Color.fromOther(color: fillColor!),\n        patternColor:\n            patternColor == null ? null : Color.fromOther(color: patternColor!),\n        strokeColor:\n            strokeColor == null ? null : Color.fromOther(color: strokeColor!),\n        strokeWidthPx: strokeWidthPx,\n        isLeaf: isLeaf,\n        index: index,\n        series: series,\n        domain: domain,\n        measure: measure,\n      );\n\n  /// Refreshes paint properties by invoking series accessor functions again.\n  ///\n  /// This is useful when series accessor functions are updated by behaviors\n  /// and redraw of this element is triggered.\n  void refreshPaintProperties() {\n    strokeColor = series.colorFn!(index);\n    strokeWidthPx = series.strokeWidthPxFn!(index);\n    fillColor = series.fillColorFn!(index);\n    fillPattern = series.fillPatternFn == null\n        ? FillPatternType.solid\n        : series.fillPatternFn!(index);\n    patternColor = series.patternColorFn!(index);\n  }\n\n  /// Updates properties of this element based on [animationPercent].\n  ///\n  /// Used when animation is in progress.\n  void updateAnimationPercent(TreeMapRendererElement<D> previous,\n      TreeMapRendererElement<D> target, double animationPercent) {\n    // TODO: Implements animation based on animationPercent.\n    boundingRect = target.boundingRect;\n    area = target.area;\n  }\n\n  @override\n  String toString() =>\n      '$runtimeType' +\n      {\n        'boundingRect': boundingRect,\n        'area': area,\n        'strokeColor': strokeColor,\n        'strokeWidthPx': strokeWidthPx,\n        'fillColor': fillColor,\n        'fillPattern': fillPattern,\n        'patternColor': patternColor,\n        'isLeaf': isLeaf,\n        'index': index,\n        'domain': domain,\n        'measure': measure,\n      }.toString();\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/common/color.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'package:meta/meta.dart' show immutable;\n\n@immutable\nclass Color {\n  static const black = Color(r: 0, g: 0, b: 0);\n  static const white = Color(r: 255, g: 255, b: 255);\n  static const transparent = Color(r: 0, g: 0, b: 0, a: 0);\n\n  static const _darkerPercentOfOrig = 0.7;\n  static const _lighterPercentOfOrig = 0.1;\n\n  final int r;\n  final int g;\n  final int b;\n  final int a;\n\n  final Color? _darker;\n  final Color? _lighter;\n\n  const Color({\n    required this.r,\n    required this.g,\n    required this.b,\n    this.a = 255,\n    Color? darker,\n    Color? lighter,\n  })  : _darker = darker,\n        _lighter = lighter;\n\n  Color.fromOther({required Color color, Color? darker, Color? lighter})\n      : r = color.r,\n        g = color.g,\n        b = color.b,\n        a = color.a,\n        _darker = darker ?? color._darker,\n        _lighter = lighter ?? color._lighter;\n\n  /// Construct the color from a hex code string, of the format #RRGGBB.\n  factory Color.fromHex({required String code}) {\n    var str = code.substring(1, 7);\n    var bigint = int.parse(str, radix: 16);\n    final r = (bigint >> 16) & 255;\n    final g = (bigint >> 8) & 255;\n    final b = bigint & 255;\n    final a = 255;\n    return Color(r: r, g: g, b: b, a: a);\n  }\n\n  Color get darker =>\n      _darker ??\n      Color(\n          r: (r * _darkerPercentOfOrig).round(),\n          g: (g * _darkerPercentOfOrig).round(),\n          b: (b * _darkerPercentOfOrig).round(),\n          a: a);\n\n  Color get lighter =>\n      _lighter ??\n      Color(\n          r: r + ((255 - r) * _lighterPercentOfOrig).round(),\n          g: g + ((255 - g) * _lighterPercentOfOrig).round(),\n          b: b + ((255 - b) * _lighterPercentOfOrig).round(),\n          a: a);\n\n  @override\n  bool operator ==(Object other) =>\n      other is Color &&\n      other.r == r &&\n      other.g == g &&\n      other.b == b &&\n      other.a == a;\n\n  @override\n  int get hashCode {\n    var hashcode = r.hashCode;\n    hashcode = hashcode * 37 + g.hashCode;\n    hashcode = hashcode * 37 + b.hashCode;\n    hashcode = hashcode * 37 + a.hashCode;\n    return hashcode;\n  }\n\n  @override\n  String toString() => rgbaHexString;\n\n  /// Converts the character into a #RGBA hex string.\n  String get rgbaHexString => '#${_get2CharHex(r)}${_get2CharHex(g)}'\n      '${_get2CharHex(b)}${_get2CharHex(a)}';\n\n  /// Converts the character into a #RGB hex string.\n  String get hexString {\n    // Alpha is not included in the hex string.\n    assert(a == 255);\n    return '#${_get2CharHex(r)}${_get2CharHex(g)}${_get2CharHex(b)}';\n  }\n\n  String _get2CharHex(int num) {\n    var str = num.toRadixString(16);\n    while (str.length < 2) {\n      str = '0' + str;\n    }\n    return str;\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/common/date_time_factory.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'package:intl/intl.dart' show DateFormat;\n\n/// Interface for factory that creates [DateTime] and [DateFormat].\n///\n/// This allows for creating of locale specific date time and date format.\nabstract class DateTimeFactory {\n  // TODO: Per cbraun@, we need to allow setting the timezone that\n  // is used globally (along with other settings like which day the week starts\n  // on. Use DateTimeFactory - either return a local DateTime or a UTC date time\n  // based on the setting.\n\n  // TODO: We need to incorporate the time zoned calendar here\n  // because Dart DateTime doesn't do this. TZDateTime implements DateTime, so\n  // we can use DateTime as the interface.\n  DateTime createDateTimeFromMilliSecondsSinceEpoch(int millisecondsSinceEpoch);\n\n  DateTime createDateTime(int year,\n      [int month = 1,\n      int day = 1,\n      int hour = 0,\n      int minute = 0,\n      int second = 0,\n      int millisecond = 0,\n      int microsecond = 0]);\n\n  /// Returns a [DateFormat].\n  DateFormat createDateFormat(String? pattern);\n}\n\n/// A local time [DateTimeFactory].\nclass LocalDateTimeFactory implements DateTimeFactory {\n  const LocalDateTimeFactory();\n\n  @override\n  DateTime createDateTimeFromMilliSecondsSinceEpoch(\n      int millisecondsSinceEpoch) {\n    return DateTime.fromMillisecondsSinceEpoch(millisecondsSinceEpoch);\n  }\n\n  @override\n  DateTime createDateTime(int year,\n      [int month = 1,\n      int day = 1,\n      int hour = 0,\n      int minute = 0,\n      int second = 0,\n      int millisecond = 0,\n      int microsecond = 0]) {\n    return DateTime(\n        year, month, day, hour, minute, second, millisecond, microsecond);\n  }\n\n  /// Returns a [DateFormat].\n  @override\n  DateFormat createDateFormat(String? pattern) => DateFormat(pattern);\n}\n\n/// An UTC time [DateTimeFactory].\nclass UTCDateTimeFactory implements DateTimeFactory {\n  const UTCDateTimeFactory();\n\n  @override\n  DateTime createDateTimeFromMilliSecondsSinceEpoch(\n      int millisecondsSinceEpoch) {\n    return DateTime.fromMillisecondsSinceEpoch(millisecondsSinceEpoch,\n        isUtc: true);\n  }\n\n  @override\n  DateTime createDateTime(int year,\n      [int month = 1,\n      int day = 1,\n      int hour = 0,\n      int minute = 0,\n      int second = 0,\n      int millisecond = 0,\n      int microsecond = 0]) {\n    return DateTime.utc(\n        year, month, day, hour, minute, second, millisecond, microsecond);\n  }\n\n  /// Returns a [DateFormat].\n  @override\n  DateFormat createDateFormat(String? pattern) => DateFormat(pattern);\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/common/gesture_listener.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math' show Point;\n\n/// Listener to touch gestures.\n///\n/// [GestureListeners] can override only the gestures it is interested in.\n///\n/// Each gesture returns true if the event is consumed or false if it should\n/// continue to alert other listeners.\nclass GestureListener {\n  static final GestureCancelCallback defaultTapCancel = () {};\n  static final GestureSinglePointCallback defaultTapTest = (_) => false;\n\n  /// Called before all gestures (except onHover) as a preliminary test to\n  /// see who is interested in an event.\n  ///\n  /// All listeners that return true will get the next gesture event.\n  ///\n  /// Any listener that returns false will only get the next gesture event if\n  /// no one returned true.\n  ///\n  /// This is useful for figuring out who is claiming a gesture event.\n  /// Example: SelectNearest returns true for onTapTest if the point is within\n  /// the drawArea. SeriesLegend returns true for onTapTest if the point is\n  /// within the legend. If the tap occurs in either of those places the\n  /// corresponding listener. If the tap occurs outside of both targets, then\n  /// both will be given the event so they can deselect everything in the\n  /// selection model.\n  ///\n  /// Defaults to function that returns false allowing other listeners to preempt.\n  final GestureSinglePointCallback onTapTest;\n\n  /// Called if onTapTest was previously called, but listener is being preempted.\n  final GestureCancelCallback onTapCancel;\n\n  /// Called after the tap event has been going on for a period of time (500ms)\n  /// without moving much (20px).\n  /// The onTap or onDragStart gestures can still trigger after this gesture.\n  final GestureSinglePointCallback? onLongPress;\n\n  /// Called on tap up if not dragging.\n  final GestureSinglePointCallback? onTap;\n\n  /// Called when a mouse hovers over the chart. (No tap event).\n  final GestureSinglePointCallback? onHover;\n\n  /// Called when the chart is focused.\n  final GestureCallback? onFocus;\n\n  /// Called when the chart is blured.\n  final GestureCallback? onBlur;\n\n  /// Called when the tap event has moved beyond a threshold indicating that\n  /// the user is dragging.\n  ///\n  /// This will only be called once per drag gesture independent of how many\n  /// touches are going on until the last touch is complete. onDragUpdate is\n  /// called as touches move updating the scale as determined by the first\n  /// two points. onDragEnd is called when the last touch event lifts and the\n  /// velocity is calculated from the final movement.\n  ///\n  /// onDragStart, onDragUpdate, and onDragEnd are also called for mouse wheel\n  /// with the scale and point updated given the WheelEvent (deltaY updates the\n  /// scale, deltaX updates the event point/pans).\n  ///\n  /// TODO: Add a \"discrete\" flag that tells drag listeners whether\n  /// they should be expecting a series of continuous updates, or one large\n  /// update. This will mostly be used to control whether we animate the chart\n  /// between onDragUpdate calls.\n  ///\n  /// TODO: Investigate low performance of chart rendering from\n  /// flutter when animation is enabled and we pinch to zoom on the chart.\n  final GestureDragStartCallback? onDragStart;\n  final GestureDragUpdateCallback? onDragUpdate;\n  final GestureDragEndCallback? onDragEnd;\n\n  GestureListener({\n    GestureSinglePointCallback? onTapTest,\n    GestureCancelCallback? onTapCancel,\n    this.onLongPress,\n    this.onTap,\n    this.onHover,\n    this.onDragStart,\n    this.onDragUpdate,\n    this.onDragEnd,\n    this.onFocus,\n    this.onBlur,\n  })  : onTapTest = onTapTest ?? defaultTapTest,\n        onTapCancel = onTapCancel ?? defaultTapCancel;\n}\n\ntypedef GestureCancelCallback = void Function();\ntypedef GestureCallback = bool Function();\ntypedef GestureSinglePointCallback = bool Function(Point<double> localPosition);\n\ntypedef GestureDragStartCallback = bool Function(Point<double> localPosition);\ntypedef GestureDragUpdateCallback = bool Function(\n    Point<double> localPosition, double scale);\ntypedef GestureDragEndCallback = bool Function(\n    Point<double> localPosition, double scale, double pixelsPerSec);\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/common/graphics_factory.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'line_style.dart' show LineStyle;\nimport 'text_element.dart' show TextElement;\nimport 'text_style.dart' show TextStyle;\n\n/// Interface to native platform graphics functions.\nabstract class GraphicsFactory {\n  LineStyle createLinePaint();\n\n  /// Returns a [TextStyle] object.\n  TextStyle createTextPaint();\n\n  /// Returns a text element from [text].\n  TextElement createTextElement(String text);\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/common/line_style.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'paint_style.dart' show PaintStyle;\n\nabstract class LineStyle extends PaintStyle {\n  List<int>? get dashPattern;\n  set dashPattern(List<int>? dashPattern);\n\n  int get strokeWidth;\n  set strokeWidth(int strokeWidth);\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/common/material_palette.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'color.dart' show Color;\nimport 'palette.dart' show Palette;\n\n/// A canonical palette of colors from material.io.\n///\n/// @link https://material.io/guidelines/style/color.html#color-color-palette\nclass MaterialPalette {\n  static const black = Color(r: 0, g: 0, b: 0);\n  static const transparent = Color(r: 0, g: 0, b: 0, a: 0);\n  static const white = Color(r: 255, g: 255, b: 255);\n\n  static Palette get blue => const MaterialBlue();\n  static Palette get red => const MaterialRed();\n  static Palette get yellow => const MaterialYellow();\n  static Palette get green => const MaterialGreen();\n  static Palette get purple => const MaterialPurple();\n  static Palette get cyan => const MaterialCyan();\n  static Palette get deepOrange => const MaterialDeepOrange();\n  static Palette get lime => const MaterialLime();\n  static Palette get indigo => const MaterialIndigo();\n  static Palette get pink => const MaterialPink();\n  static Palette get teal => const MaterialTeal();\n  static MaterialGray get gray => const MaterialGray();\n\n  // Lazily-instantiated iterable, to avoid allocating colors that are not used.\n  static final Iterable<Palette> _orderedPalettes = [\n    () => blue,\n    () => red,\n    () => yellow,\n    () => green,\n    () => purple,\n    () => cyan,\n    () => deepOrange,\n    () => lime,\n    () => indigo,\n    () => pink,\n    () => teal\n  ].map((f) => f());\n\n  static List<Palette> getOrderedPalettes(int count) {\n    return _orderedPalettes.take(count).toList();\n  }\n}\n\nclass MaterialBlue extends Palette {\n  static const _shade200 = Color(r: 0x90, g: 0xCA, b: 0xF9); //#90CAF9\n  static const _shade500 =\n      Color(r: 0x21, g: 0x96, b: 0xF3, darker: _shade700, lighter: _shade200);\n  static const _shade700 = Color(r: 0x19, g: 0x76, b: 0xD2); //#1976D2\n\n  const MaterialBlue();\n\n  @override\n  Color get shadeDefault => _shade500;\n}\n\nclass MaterialRed extends Palette {\n  static const _shade200 = Color(r: 0xEF, g: 0x9A, b: 0x9A); //#EF9A9A\n  static const _shade700 = Color(r: 0xD3, g: 0x2F, b: 0x2F); //#D32F2F\n  static const _shade500 =\n      Color(r: 0xF4, g: 0x43, b: 0x36, darker: _shade700, lighter: _shade200);\n\n  const MaterialRed();\n\n  @override\n  Color get shadeDefault => _shade500;\n}\n\nclass MaterialYellow extends Palette {\n  static const _shade200 = Color(r: 0xFF, g: 0xF5, b: 0x9D); //#FFF59D\n  static const _shade700 = Color(r: 0xFB, g: 0xC0, b: 0x2D); //#FBC02D\n  static const _shade500 =\n      Color(r: 0xFF, g: 0xEB, b: 0x3B, darker: _shade700, lighter: _shade200);\n\n  const MaterialYellow();\n\n  @override\n  Color get shadeDefault => _shade500;\n}\n\nclass MaterialGreen extends Palette {\n  static const _shade200 = Color(r: 0xA5, g: 0xD6, b: 0xA7); //#A5D6A7\n  static const _shade700 = Color(r: 0x38, g: 0x8E, b: 0x3C); //#388E3C;\n  static const _shade500 =\n      Color(r: 0x4C, g: 0xAF, b: 0x50, darker: _shade700, lighter: _shade200);\n\n  const MaterialGreen();\n\n  @override\n  Color get shadeDefault => _shade500;\n}\n\nclass MaterialPurple extends Palette {\n  static const _shade200 = Color(r: 0xCE, g: 0x93, b: 0xD8); //#CE93D8\n  static const _shade700 = Color(r: 0x7B, g: 0x1F, b: 0xA2); //#7B1FA2\n  static const _shade500 =\n      Color(r: 0x9C, g: 0x27, b: 0xB0, darker: _shade700, lighter: _shade200);\n\n  const MaterialPurple();\n\n  @override\n  Color get shadeDefault => _shade500;\n}\n\nclass MaterialCyan extends Palette {\n  static const _shade200 = Color(r: 0x80, g: 0xDE, b: 0xEA); //#80DEEA\n  static const _shade700 = Color(r: 0x00, g: 0x97, b: 0xA7); //#0097A7\n  static const _shade500 =\n      Color(r: 0x00, g: 0xBC, b: 0xD4, darker: _shade700, lighter: _shade200);\n\n  const MaterialCyan();\n\n  @override\n  Color get shadeDefault => _shade500;\n}\n\nclass MaterialDeepOrange extends Palette {\n  static const _shade200 = Color(r: 0xFF, g: 0xAB, b: 0x91); //#FFAB91\n  static const _shade700 = Color(r: 0xE6, g: 0x4A, b: 0x19); //#E64A19\n  static const _shade500 =\n      Color(r: 0xFF, g: 0x57, b: 0x22, darker: _shade700, lighter: _shade200);\n\n  const MaterialDeepOrange();\n\n  @override\n  Color get shadeDefault => _shade500;\n}\n\nclass MaterialLime extends Palette {\n  static const _shade200 = Color(r: 0xE6, g: 0xEE, b: 0x9C); //#E6EE9C\n  static const _shade700 = Color(r: 0xAF, g: 0xB4, b: 0x2B); //#AFB42B\n  static const _shade500 =\n      Color(r: 0xCD, g: 0xDC, b: 0x39, darker: _shade700, lighter: _shade200);\n\n  const MaterialLime();\n\n  @override\n  Color get shadeDefault => _shade500;\n}\n\nclass MaterialIndigo extends Palette {\n  static const _shade200 = Color(r: 0x9F, g: 0xA8, b: 0xDA); //#9FA8DA\n  static const _shade700 = Color(r: 0x30, g: 0x3F, b: 0x9F); //#303F9F\n  static const _shade500 =\n      Color(r: 0x3F, g: 0x51, b: 0xB5, darker: _shade700, lighter: _shade200);\n\n  const MaterialIndigo();\n\n  @override\n  Color get shadeDefault => _shade500;\n}\n\nclass MaterialPink extends Palette {\n  static const _shade200 = Color(r: 0xF4, g: 0x8F, b: 0xB1); //#F48FB1\n  static const _shade700 = Color(r: 0xC2, g: 0x18, b: 0x5B); //#C2185B\n  static const _shade500 =\n      Color(r: 0xE9, g: 0x1E, b: 0x63, darker: _shade700, lighter: _shade200);\n\n  const MaterialPink();\n\n  @override\n  Color get shadeDefault => _shade500;\n}\n\nclass MaterialTeal extends Palette {\n  static const _shade200 = Color(r: 0x80, g: 0xCB, b: 0xC4); //#80CBC4\n  static const _shade700 = Color(r: 0x00, g: 0x79, b: 0x6B); //#00796B\n  static const _shade500 =\n      Color(r: 0x00, g: 0x96, b: 0x88, darker: _shade700, lighter: _shade200);\n\n  const MaterialTeal();\n\n  @override\n  Color get shadeDefault => _shade500;\n}\n\nclass MaterialGray extends Palette {\n  static const _shade200 = Color(r: 0xEE, g: 0xEE, b: 0xEE); //#EEEEEE\n  static const _shade700 = Color(r: 0x61, g: 0x61, b: 0x61); //#616161\n  static const _shade500 =\n      Color(r: 0x9E, g: 0x9E, b: 0x9E, darker: _shade700, lighter: _shade200);\n\n  const MaterialGray();\n\n  @override\n  Color get shadeDefault => _shade500;\n\n  Color get shade50 => Color(r: 0xFA, g: 0xFA, b: 0xFA); //#FAFAFA\n  Color get shade100 => Color(r: 0xF5, g: 0xF5, b: 0xF5); //#F5F5F5\n  Color get shade200 => _shade200;\n  Color get shade300 => Color(r: 0xE0, g: 0xE0, b: 0xE0); //#E0E0E0\n  Color get shade400 => Color(r: 0xBD, g: 0xBD, b: 0xBD); //#BDBDBD\n  Color get shade500 => _shade500;\n  Color get shade600 => Color(r: 0x75, g: 0x75, b: 0x75); //#757575\n  Color get shade700 => _shade700;\n  Color get shade800 => Color(r: 0x42, g: 0x42, b: 0x42); //#424242\n  Color get shade900 => Color(r: 0x21, g: 0x21, b: 0x21); //#212121\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/common/math.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math' show max, min, sqrt, Point;\nimport 'package:vector_math/vector_math.dart' show Vector2;\n\nconst _defaultEpsilon = 2e-10;\n\n/// Takes a value along with an upper and lower bound and returns whether or not\n/// the value falls inclusively within the bounds.\n///\n/// [value] The input number.\n/// [lowerBound] The lower bound.\n/// [upperBound] The upper bound.\n/// [epsilon] Maximum valid difference between [value] and the bounds. Defaults\n/// to 2e-10.\nbool withinBounds(num value, num lowerBound, num upperBound,\n    {double epsilon = _defaultEpsilon}) {\n  return value + epsilon >= lowerBound && value - epsilon <= upperBound;\n}\n\n/// Takes a number and clamps it to within the provided bounds.\n///\n/// Returns the input number if it is within bounds, or the nearest number\n/// within the bounds.\n///\n/// [value] The input number.\n/// [minValue] The minimum value to return.\n/// [maxValue] The maximum value to return.\nnum clamp(num value, num minValue, num maxValue) {\n  return min(max(value, minValue), maxValue);\n}\n\n/// Returns the minimum distance between point p and the line segment vw.\n///\n/// [p] The point.\n/// [v] Start point for the line segment.\n/// [w] End point for the line segment.\ndouble distanceBetweenPointAndLineSegment(Vector2 p, Vector2 v, Vector2 w) {\n  return sqrt(distanceBetweenPointAndLineSegmentSquared(p, v, w));\n}\n\n/// Returns the squared minimum distance between point p and the line segment\n/// vw.\n///\n/// [p] The point.\n/// [v] Start point for the line segment.\n/// [w] End point for the line segment.\ndouble distanceBetweenPointAndLineSegmentSquared(\n    Vector2 p, Vector2 v, Vector2 w) {\n  final lineLength = v.distanceToSquared(w);\n\n  if (lineLength == 0) {\n    return p.distanceToSquared(v);\n  }\n\n  var t0 = (p - v).dot(w - v) / lineLength;\n  t0 = max(0.0, min(1.0, t0));\n\n  final projection = v + ((w - v) * t0);\n\n  return p.distanceToSquared(projection);\n}\n\n/// A two-dimensional cartesian coordinate pair with potentially null coordinate\n/// values.\nclass NullablePoint {\n  final double? x;\n  final double? y;\n\n  /// Creates a point with the provided [x] and [y] coordinates.\n  const NullablePoint(this.x, this.y);\n\n  /// Creates a [NullablePoint] from a [Point].\n  NullablePoint.from(Point<double>? point) : this(point?.x, point?.y);\n\n  @override\n  String toString() => 'NullablePoint($x, $y)';\n\n  /// Whether [other] is a point with the same coordinates as this point.\n  ///\n  /// Returns `true` if [other] is a [NullablePoint] with [x] and [y]\n  /// coordinates equal to the corresponding coordinates of this point,\n  /// and `false` otherwise.\n  @override\n  bool operator ==(Object other) =>\n      other is NullablePoint && x == other.x && y == other.y;\n\n  @override\n  int get hashCode => x.hashCode * 37 + y.hashCode;\n\n  /// Converts this to a [Point].\n  ///\n  /// Throws if [x] or [y] is null.\n  Point<double> toPoint() {\n    assert(x != null);\n    assert(y != null);\n    return Point<double>(x!, y!);\n  }\n}\n\nextension NullablePointsToPoints on Iterable<NullablePoint> {\n  /// Converts an [Iterable] of [NullablePoint]s to a [List] of [Point]s.\n  ///\n  /// Any [NullablePoint]s that have null values will be filtered out.\n  List<Point<double>> toPoints() {\n    return [\n      for (final nullablePoint in this)\n        if (nullablePoint.x != null && nullablePoint.y != null)\n          nullablePoint.toPoint(),\n    ];\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/common/paint_style.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'color.dart';\n\n/// Style properties of a paintable object.\nabstract class PaintStyle {\n  Color? get color;\n\n  set color(Color? value);\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/common/palette.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'color.dart' show Color;\n\n/// A color palette.\nabstract class Palette {\n  const Palette();\n\n  /// The default shade.\n  Color get shadeDefault;\n\n  /// Returns a list of colors for this color palette.\n  List<Color> makeShades(int colorCnt) {\n    final colors = <Color>[shadeDefault];\n\n    // If we need more than 2 colors, then [unselected] collides with one of the\n    // generated colors. Otherwise divide the space between the top color\n    // and white in half.\n    final lighterColor = colorCnt < 3\n        ? shadeDefault.lighter\n        : _getSteppedColor(shadeDefault, (colorCnt * 2) - 1, colorCnt * 2);\n\n    // Divide the space between 255 and c500 evenly according to the colorCnt.\n    for (var i = 1; i < colorCnt; i++) {\n      colors.add(_getSteppedColor(shadeDefault, i, colorCnt,\n          darker: shadeDefault.darker, lighter: lighterColor));\n    }\n\n    colors.add(Color.fromOther(color: shadeDefault, lighter: lighterColor));\n    return colors;\n  }\n\n  Color _getSteppedColor(Color color, int index, int steps,\n      {Color? darker, Color? lighter}) {\n    final fraction = index / steps;\n    return Color(\n      r: color.r + ((255 - color.r) * fraction).round(),\n      g: color.g + ((255 - color.g) * fraction).round(),\n      b: color.b + ((255 - color.b) * fraction).round(),\n      a: color.a + ((255 - color.a) * fraction).round(),\n      darker: darker,\n      lighter: lighter,\n    );\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/common/performance.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\ntypedef PerformanceCallback = void Function(String tag);\n\nclass Performance {\n  static PerformanceCallback time = (_) {};\n  static PerformanceCallback timeEnd = (_) {};\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/common/proxy_gesture_listener.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math' show Point;\n\nimport 'package:collection/collection.dart' show IterableExtension;\n\nimport 'gesture_listener.dart' show GestureListener;\n\n/// Listens to all gestures and proxies to child listeners.\nclass ProxyGestureListener {\n  final _listeners = <GestureListener>[];\n  var _activeListeners = <GestureListener>[];\n\n  void add(GestureListener listener) {\n    _listeners.add(listener);\n    _activeListeners.clear();\n  }\n\n  void remove(GestureListener listener) {\n    _listeners.remove(listener);\n    _activeListeners.clear();\n  }\n\n  bool onTapTest(Point<double> localPosition) {\n    _activeListeners.clear();\n    return _populateActiveListeners(localPosition);\n  }\n\n  bool onLongPress(Point<double> localPosition) {\n    // Walk through listeners stopping at the first handled listener.\n    final claimingListener = _activeListeners.firstWhereOrNull(\n        (GestureListener listener) =>\n            listener.onLongPress?.call(localPosition) ?? false);\n\n    // If someone claims the long press, then cancel everyone else.\n    if (claimingListener != null) {\n      _activeListeners =\n          _cancel(all: _activeListeners, keep: [claimingListener]);\n      return true;\n    }\n    return false;\n  }\n\n  bool onTap(Point<double> localPosition) {\n    // Walk through listeners stopping at the first handled listener.\n    final claimingListener = _activeListeners.firstWhereOrNull(\n        (GestureListener listener) =>\n            listener.onTap?.call(localPosition) ?? false);\n\n    // If someone claims the tap, then cancel everyone else.\n    // This should hopefully be rare, like for drilling.\n    if (claimingListener != null) {\n      _activeListeners =\n          _cancel(all: _activeListeners, keep: [claimingListener]);\n      return true;\n    }\n    return false;\n  }\n\n  bool onHover(Point<double> localPosition) {\n    // Cancel any previously active long lived gestures.\n    _activeListeners = <GestureListener>[];\n\n    // Walk through listeners stopping at the first handled listener.\n    return _listeners.any((GestureListener listener) =>\n        listener.onHover?.call(localPosition) ?? false);\n  }\n\n  bool onDragStart(Point<double> localPosition) {\n    // In Flutter, a tap test may not be triggered because a tap down event\n    // may not be registered if the the drag gesture happens without any pause.\n    if (_activeListeners.isEmpty) {\n      _populateActiveListeners(localPosition);\n    }\n\n    // Walk through listeners stopping at the first handled listener.\n    final claimingListener = _activeListeners.firstWhereOrNull(\n        (GestureListener listener) =>\n            listener.onDragStart?.call(localPosition) ?? false);\n\n    if (claimingListener != null) {\n      _activeListeners =\n          _cancel(all: _activeListeners, keep: [claimingListener]);\n      return true;\n    }\n    return false;\n  }\n\n  bool onDragUpdate(Point<double> localPosition, double scale) {\n    return _activeListeners.any((GestureListener listener) =>\n        listener.onDragUpdate?.call(localPosition, scale) ?? false);\n  }\n\n  bool onDragEnd(\n      Point<double> localPosition, double scale, double pixelsPerSecond) {\n    return _activeListeners.any((GestureListener listener) =>\n        listener.onDragEnd?.call(localPosition, scale, pixelsPerSecond) ??\n        false);\n  }\n\n  bool onFocus() {\n    return _listeners\n        .any((GestureListener listener) => listener.onFocus?.call() ?? false);\n  }\n\n  bool onBlur() {\n    return _listeners\n        .any((GestureListener listener) => listener.onBlur?.call() ?? false);\n  }\n\n  List<GestureListener> _cancel({\n    required List<GestureListener> all,\n    required List<GestureListener> keep,\n  }) {\n    all.forEach((GestureListener listener) {\n      if (!keep.contains(listener)) {\n        listener.onTapCancel();\n      }\n    });\n    return keep;\n  }\n\n  bool _populateActiveListeners(Point<double> localPosition) {\n    var localListeners = List.of(_listeners);\n\n    var previouslyClaimed = false;\n    localListeners.forEach((GestureListener listener) {\n      var claimed = listener.onTapTest(localPosition);\n      if (claimed && !previouslyClaimed) {\n        // Cancel any already added non-claiming listeners now that someone is\n        // claiming it.\n        _activeListeners = _cancel(all: _activeListeners, keep: [listener]);\n        previouslyClaimed = true;\n      } else if (claimed || !previouslyClaimed) {\n        _activeListeners.add(listener);\n      }\n    });\n\n    return previouslyClaimed;\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/common/rate_limit_utils.dart",
    "content": "// Copyright 2019 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:async';\n\n/// Function that accepts only one argument of type [T] with return type [R].\ntypedef UnaryFunction<T, R> = R Function(T argument);\n\n/// A wrapper function that enforces the maximum number of times [callback] can\n/// be called over a period of time.\n///\n/// [delay] specifies the amount of time to wait until [callback] can be called\n/// again.\n/// [defaultReturn] is used as the return value when throttle event occurs.\nUnaryFunction<T, R> throttle<T, R>(UnaryFunction<T, R> callback,\n    {Duration delay = Duration.zero, required R defaultReturn}) {\n  Timer? timer;\n  Stopwatch? stopwatch;\n\n  return (T argument) {\n    stopwatch ??= Stopwatch()..start();\n\n    // This event happened too soon. Do not call the [callback] function yet,\n    // unless it turns out to be the very last event. [delay]s for a period of\n    // time before calling the [callback] function again.\n    if (stopwatch!.elapsedMilliseconds < delay.inMilliseconds) {\n      timer?.cancel();\n      timer = Timer(delay, () {\n        callback(argument);\n        timer = null;\n        stopwatch = null;\n      });\n      return defaultReturn;\n    }\n\n    stopwatch = null;\n\n    // This is a non-throttled event, go ahead and clear away the last throttled\n    // event callback so that we do not move the hover point back in time.\n    timer?.cancel();\n    return callback(argument);\n  };\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/common/rtl_spec.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n/// Defines the behavior of the chart if it is RTL.\nclass RTLSpec {\n  /// Creates [RTLSpec]. If no parameters are specified, the defaults are used.\n  const RTLSpec({\n    this.axisDirection = AxisDirection.reversed,\n  });\n\n  /// Direction of the domain axis when the chart container is configured for\n  /// RTL mode.\n  final AxisDirection axisDirection;\n}\n\n/// Direction of the domain axis when the chart container is configured for\n/// RTL mode.\n///\n/// [normal] Vertically rendered charts will have the primary measure axis on\n/// the left and secondary measure axis on the right. Domain axis is on the left\n/// and the domain output range starts from the left and grows to the right.\n/// Horizontally rendered charts will have the primary measure axis on the\n/// bottom and secondary measure axis on the right. Measure output range starts\n/// from the left and grows to the right.\n///\n/// [reversed] Vertically rendered charts will have the primary measure axis on\n/// the right and secondary measure axis on the left. Domain axis is on the\n/// right and domain values grows from the right to the left. Horizontally\n/// rendered charts will have the primary measure axis on the top and secondary\n/// measure axis on the left. Measure output range is flipped and grows from the\n/// right to the left.\nenum AxisDirection {\n  normal,\n  reversed,\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/common/style/material_style.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport '../../chart/cartesian/axis/spec/axis_spec.dart' show LineStyleSpec;\nimport '../color.dart' show Color;\nimport '../graphics_factory.dart' show GraphicsFactory;\nimport '../line_style.dart' show LineStyle;\nimport '../material_palette.dart' show MaterialPalette;\nimport '../palette.dart' show Palette;\nimport 'style.dart' show Style;\n\nclass MaterialStyle implements Style {\n  const MaterialStyle();\n\n  @override\n  Color get black => MaterialPalette.black;\n\n  @override\n  Color get transparent => MaterialPalette.transparent;\n\n  @override\n  Color get white => MaterialPalette.white;\n\n  @override\n  List<Palette> getOrderedPalettes(int count) =>\n      MaterialPalette.getOrderedPalettes(count);\n\n  @override\n  LineStyle createAxisLineStyle(\n      GraphicsFactory graphicsFactory, LineStyleSpec? spec) {\n    return graphicsFactory.createLinePaint()\n      ..color = spec?.color ?? MaterialPalette.gray.shadeDefault\n      ..dashPattern = spec?.dashPattern\n      ..strokeWidth = spec?.thickness ?? 1;\n  }\n\n  @override\n  LineStyle createTickLineStyle(\n      GraphicsFactory graphicsFactory, LineStyleSpec? spec) {\n    return graphicsFactory.createLinePaint()\n      ..color = spec?.color ?? MaterialPalette.gray.shadeDefault\n      ..dashPattern = spec?.dashPattern\n      ..strokeWidth = spec?.thickness ?? 1;\n  }\n\n  @override\n  int get tickLength => 3;\n\n  @override\n  Color get tickColor => MaterialPalette.gray.shade800;\n\n  @override\n  LineStyle createGridlineStyle(\n      GraphicsFactory graphicsFactory, LineStyleSpec? spec) {\n    return graphicsFactory.createLinePaint()\n      ..color = spec?.color ?? MaterialPalette.gray.shade300\n      ..dashPattern = spec?.dashPattern\n      ..strokeWidth = spec?.thickness ?? 1;\n  }\n\n  @override\n  Color get arcLabelOutsideLeaderLine => MaterialPalette.gray.shade600;\n\n  @override\n  Color get defaultSeriesColor => MaterialPalette.gray.shadeDefault;\n\n  @override\n  Color get arcStrokeColor => MaterialPalette.white;\n\n  @override\n  Color get legendEntryTextColor => MaterialPalette.gray.shade800;\n\n  @override\n  Color get legendTitleTextColor => MaterialPalette.gray.shade800;\n\n  @override\n  Color get linePointHighlighterColor => MaterialPalette.gray.shade600;\n\n  @override\n  Color get noDataColor => MaterialPalette.gray.shade200;\n\n  @override\n  Color get rangeAnnotationColor => MaterialPalette.gray.shade100;\n\n  @override\n  Color get sliderFillColor => MaterialPalette.white;\n\n  @override\n  Color get sliderStrokeColor => MaterialPalette.gray.shade600;\n\n  @override\n  Color get chartBackgroundColor => MaterialPalette.white;\n\n  @override\n  double get rangeBandSize => 0.65;\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/common/style/style.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport '../../chart/cartesian/axis/spec/axis_spec.dart' show LineStyleSpec;\nimport '../color.dart' show Color;\nimport '../graphics_factory.dart' show GraphicsFactory;\nimport '../line_style.dart' show LineStyle;\nimport '../palette.dart';\n\n// TODO: Implementation of style will change drastically, see bug\n// for more details. This is an intermediate step in order to allow overriding\n// the default style using style factory.\n\n/// A set of styling rules that determines the default look and feel of charts.\n///\n/// Get or set the [Style] that is used for the app using [StyleFactory.style].\nabstract class Style {\n  Color get black;\n\n  Color get transparent;\n\n  Color get white;\n\n  /// Gets list with [count] of palettes.\n  List<Palette> getOrderedPalettes(int count);\n\n  /// Creates [LineStyleSpec] for axis line from spec.\n  ///\n  /// Fill missing value(s) with default.\n  LineStyle createAxisLineStyle(\n      GraphicsFactory graphicsFactory, LineStyleSpec? spec);\n\n  /// Creates [LineStyleSpec] for tick lines from spec.\n  ///\n  /// Fill missing value(s) with default.\n  LineStyle createTickLineStyle(\n      GraphicsFactory graphicsFactory, LineStyleSpec? spec);\n\n  /// Default tick length.\n  int get tickLength;\n\n  /// Default tick color.\n  Color get tickColor;\n\n  ///\n  /// Creates [LineStyle] for axis gridlines from spec.\n  ///\n  /// Fill missing value(s) with default.\n  LineStyle createGridlineStyle(\n      GraphicsFactory graphicsFactory, LineStyleSpec? spec);\n\n  /// Default color for outside label leader lines for [ArcLabelDecorator].\n  Color get arcLabelOutsideLeaderLine;\n\n  /// Default series color for legends, used as a fallback when a series has no\n  /// data.\n  Color get defaultSeriesColor;\n\n  /// Default color for strokes for [ArcRendererConfig].\n  Color get arcStrokeColor;\n\n  /// Default color for entry text for [Legend].\n  Color get legendEntryTextColor;\n\n  /// Default color for title text for [Legend].\n  Color get legendTitleTextColor;\n\n  /// Default color for [LinePointHighlighter].\n  Color get linePointHighlighterColor;\n\n  /// Default color for \"no data\" states on charts.\n  Color get noDataColor;\n\n  /// Default color for [RangeAnnotation].\n  Color get rangeAnnotationColor;\n\n  /// Default fill color for [Slider].\n  Color get sliderFillColor;\n\n  /// Default stroke color for [Slider].\n  Color get sliderStrokeColor;\n\n  /// Default background color for the chart.\n  Color get chartBackgroundColor;\n\n  /// The width of the band specified as fraction of step.\n  double get rangeBandSize;\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/common/style/style_factory.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'material_style.dart' show MaterialStyle;\nimport 'style.dart' show Style;\n\nclass StyleFactory {\n  static final StyleFactory _styleFactory = StyleFactory._internal();\n\n  Style _style = const MaterialStyle();\n\n  /// The [Style] that is used for all the charts in this application.\n  static Style get style => _styleFactory._style;\n\n  static set style(Style value) {\n    _styleFactory._style = value;\n  }\n\n  StyleFactory._internal();\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/common/symbol_renderer.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math' show Rectangle, Point, min, sqrt;\n\nimport 'package:meta/meta.dart' show protected;\n\nimport '../chart/common/chart_canvas.dart' show ChartCanvas, FillPatternType;\nimport 'color.dart' show Color;\nimport 'style/style_factory.dart' show StyleFactory;\n\n/// Strategy for rendering a symbol.\nabstract class BaseSymbolRenderer {\n  bool shouldRepaint(covariant BaseSymbolRenderer oldRenderer);\n}\n\n/// Strategy for rendering a symbol bounded within a box.\nabstract class SymbolRenderer extends BaseSymbolRenderer {\n  /// Whether the symbol should be rendered as a solid shape, or a hollow shape.\n  ///\n  /// If this is true, then fillColor and strokeColor will be used to fill in\n  /// the shape, and draw a border, respectively. The stroke (border) will only\n  /// be visible if a non-zero strokeWidthPx is configured.\n  ///\n  /// If this is false, then the shape will be filled in with a white color\n  /// (overriding fillColor). strokeWidthPx will default to 2 if none was\n  /// configured.\n  final bool isSolid;\n\n  SymbolRenderer({required this.isSolid});\n\n  void paint(ChartCanvas canvas, Rectangle<num> bounds,\n      {List<int>? dashPattern,\n      Color? fillColor,\n      FillPatternType? fillPattern,\n      Color? strokeColor,\n      double? strokeWidthPx});\n\n  @protected\n  double? getSolidStrokeWidthPx(double? strokeWidthPx) {\n    return isSolid ? strokeWidthPx : (strokeWidthPx ?? 2.0);\n  }\n\n  @protected\n  Color? getSolidFillColor(Color? fillColor) {\n    return isSolid ? fillColor : StyleFactory.style.white;\n  }\n\n  @override\n  bool operator ==(Object other) {\n    return other is SymbolRenderer && other.isSolid == isSolid;\n  }\n\n  @override\n  int get hashCode => isSolid.hashCode;\n}\n\n/// Strategy for rendering a symbol centered around a point.\n///\n/// An optional second point can describe an extended symbol.\nabstract class PointSymbolRenderer extends BaseSymbolRenderer {\n  void paint(ChartCanvas canvas, Point<double> p1, double radius,\n      {required Point<double> p2, Color? fillColor, Color? strokeColor});\n}\n\n/// Rounded rectangular symbol with corners having [radius].\nclass RoundedRectSymbolRenderer extends SymbolRenderer {\n  final double radius;\n\n  RoundedRectSymbolRenderer({bool isSolid = true, double? radius})\n      : radius = radius ?? 1.0,\n        super(isSolid: isSolid);\n\n  @override\n  void paint(ChartCanvas canvas, Rectangle<num> bounds,\n      {List<int>? dashPattern,\n      Color? fillColor,\n      FillPatternType? fillPattern,\n      Color? strokeColor,\n      double? strokeWidthPx}) {\n    canvas.drawRRect(bounds,\n        fill: getSolidFillColor(fillColor),\n        fillPattern: fillPattern,\n        stroke: strokeColor,\n        radius: radius,\n        roundTopLeft: true,\n        roundTopRight: true,\n        roundBottomRight: true,\n        roundBottomLeft: true);\n  }\n\n  @override\n  bool shouldRepaint(RoundedRectSymbolRenderer oldRenderer) {\n    return this != oldRenderer;\n  }\n\n  @override\n  bool operator ==(Object other) {\n    return other is RoundedRectSymbolRenderer &&\n        other.radius == radius &&\n        super == other;\n  }\n\n  @override\n  int get hashCode {\n    var hashcode = super.hashCode;\n    hashcode = (hashcode * 37) + radius.hashCode;\n    return hashcode;\n  }\n}\n\n/// Line symbol renderer.\nclass LineSymbolRenderer extends SymbolRenderer {\n  static const roundEndCapsPixels = 2;\n  static const minLengthToRoundCaps = (roundEndCapsPixels * 2) + 1;\n  static const strokeWidthForRoundEndCaps = 4.0;\n  static const strokeWidthForNonRoundedEndCaps = 2.0;\n\n  /// Thickness of the line stroke.\n  final double strokeWidth;\n\n  /// Dash pattern for the line.\n  final List<int>? _dashPattern;\n\n  LineSymbolRenderer(\n      {List<int>? dashPattern, bool isSolid = true, double? strokeWidth})\n      : strokeWidth = strokeWidth ?? strokeWidthForRoundEndCaps,\n        _dashPattern = dashPattern,\n        super(isSolid: isSolid);\n\n  @override\n  void paint(ChartCanvas canvas, Rectangle<num> bounds,\n      {List<int>? dashPattern,\n      Color? fillColor,\n      FillPatternType? fillPattern,\n      Color? strokeColor,\n      double? strokeWidthPx}) {\n    final centerHeight = (bounds.bottom - bounds.top) / 2;\n\n    // If we have a dash pattern, do not round the end caps, and set\n    // strokeWidthPx to a smaller value. Using round end caps makes smaller\n    // patterns blurry.\n    final localDashPattern = dashPattern ?? _dashPattern;\n    final roundEndCaps = localDashPattern == null;\n\n    // If we have a dash pattern, the normal stroke width makes them look\n    // strangely tall.\n    final localStrokeWidthPx = localDashPattern == null\n        ? getSolidStrokeWidthPx(strokeWidthPx ?? strokeWidth)\n        : strokeWidthForNonRoundedEndCaps;\n\n    // Adjust the length so the total width includes the rounded pixels.\n    // Otherwise the cap is drawn past the bounds and appears to be cut off.\n    // If bounds is not long enough to accommodate the line, do not adjust.\n    var left = bounds.left;\n    var right = bounds.right;\n\n    if (roundEndCaps && bounds.width >= minLengthToRoundCaps) {\n      left += roundEndCapsPixels;\n      right -= roundEndCapsPixels;\n    }\n\n    // TODO: Pass in strokeWidth, roundEndCaps, and dashPattern from\n    // line renderer config.\n    canvas.drawLine(\n      points: [Point(left, centerHeight), Point(right, centerHeight)],\n      dashPattern: localDashPattern,\n      fill: getSolidFillColor(fillColor),\n      roundEndCaps: roundEndCaps,\n      stroke: strokeColor,\n      strokeWidthPx: localStrokeWidthPx,\n    );\n  }\n\n  @override\n  bool shouldRepaint(LineSymbolRenderer oldRenderer) {\n    return this != oldRenderer;\n  }\n\n  @override\n  bool operator ==(Object other) {\n    return other is LineSymbolRenderer &&\n        other.strokeWidth == strokeWidth &&\n        super == other;\n  }\n\n  @override\n  int get hashCode {\n    var hashcode = super.hashCode;\n    hashcode = (hashcode * 37) + strokeWidth.hashCode;\n    return hashcode;\n  }\n}\n\n/// Circle symbol renderer.\nclass CircleSymbolRenderer extends SymbolRenderer {\n  CircleSymbolRenderer({bool isSolid = true}) : super(isSolid: isSolid);\n\n  @override\n  void paint(ChartCanvas canvas, Rectangle<num> bounds,\n      {List<int>? dashPattern,\n      Color? fillColor,\n      FillPatternType? fillPattern,\n      Color? strokeColor,\n      double? strokeWidthPx}) {\n    final center = Point(\n      bounds.left + (bounds.width / 2),\n      bounds.top + (bounds.height / 2),\n    );\n    final radius = min(bounds.width, bounds.height) / 2;\n    canvas.drawPoint(\n        point: center,\n        radius: radius,\n        fill: getSolidFillColor(fillColor),\n        stroke: strokeColor,\n        strokeWidthPx: getSolidStrokeWidthPx(strokeWidthPx));\n  }\n\n  @override\n  bool shouldRepaint(CircleSymbolRenderer oldRenderer) {\n    return this != oldRenderer;\n  }\n\n  @override\n  bool operator ==(Object other) =>\n      other is CircleSymbolRenderer && super == other;\n\n  @override\n  int get hashCode {\n    var hashcode = super.hashCode;\n    hashcode = (hashcode * 37) + runtimeType.hashCode;\n    return hashcode;\n  }\n}\n\n/// Rectangle symbol renderer.\nclass RectSymbolRenderer extends SymbolRenderer {\n  RectSymbolRenderer({bool isSolid = true}) : super(isSolid: isSolid);\n\n  @override\n  void paint(ChartCanvas canvas, Rectangle<num> bounds,\n      {List<int>? dashPattern,\n      Color? fillColor,\n      FillPatternType? fillPattern,\n      Color? strokeColor,\n      double? strokeWidthPx}) {\n    canvas.drawRect(bounds,\n        fill: getSolidFillColor(fillColor),\n        stroke: strokeColor,\n        strokeWidthPx: getSolidStrokeWidthPx(strokeWidthPx));\n  }\n\n  @override\n  bool shouldRepaint(RectSymbolRenderer oldRenderer) {\n    return this != oldRenderer;\n  }\n\n  @override\n  bool operator ==(Object other) =>\n      other is RectSymbolRenderer && super == other;\n\n  @override\n  int get hashCode {\n    var hashcode = super.hashCode;\n    hashcode = (hashcode * 37) + runtimeType.hashCode;\n    return hashcode;\n  }\n}\n\n/// This [SymbolRenderer] renders an upward pointing equilateral triangle.\nclass TriangleSymbolRenderer extends SymbolRenderer {\n  TriangleSymbolRenderer({bool isSolid = true}) : super(isSolid: isSolid);\n\n  @override\n  void paint(ChartCanvas canvas, Rectangle<num> bounds,\n      {List<int>? dashPattern,\n      Color? fillColor,\n      FillPatternType? fillPattern,\n      Color? strokeColor,\n      double? strokeWidthPx}) {\n    // To maximize the size of the triangle in the available space, we can use\n    // the width as the length of each size. Set the bottom edge to be the full\n    // width, and then calculate the height based on the 30/60/90 degree right\n    // triangle whose tall side is the height of our equilateral triangle.\n    final dy = sqrt(3) / 2 * bounds.width;\n    final centerX = (bounds.left + bounds.right) / 2;\n    canvas.drawPolygon(\n        points: [\n          Point(bounds.left, bounds.top + dy),\n          Point(bounds.right, bounds.top + dy),\n          Point(centerX, bounds.top),\n        ],\n        fill: getSolidFillColor(fillColor),\n        stroke: strokeColor,\n        strokeWidthPx: getSolidStrokeWidthPx(strokeWidthPx));\n  }\n\n  @override\n  bool shouldRepaint(TriangleSymbolRenderer oldRenderer) {\n    return this != oldRenderer;\n  }\n\n  @override\n  // ignore: hash_and_equals\n  bool operator ==(Object other) =>\n      other is TriangleSymbolRenderer && super == other;\n}\n\n/// Draws a cylindrical shape connecting two points.\nclass CylinderSymbolRenderer extends PointSymbolRenderer {\n  CylinderSymbolRenderer();\n\n  @override\n  void paint(ChartCanvas canvas, Point<double> p1, double radius,\n      {required Point<double> p2,\n      Color? fillColor,\n      Color? strokeColor,\n      double? strokeWidthPx}) {\n    if (p1 == null) {\n      throw ArgumentError('Invalid point p1 \"${p1}\"');\n    }\n\n    if (p2 == null) {\n      throw ArgumentError('Invalid point p2 \"${p2}\"');\n    }\n\n    final adjustedP1 = Point<double>(p1.x, p1.y);\n    final adjustedP2 = Point<double>(p2.x, p2.y);\n\n    canvas.drawLine(\n        points: [adjustedP1, adjustedP2],\n        stroke: strokeColor,\n        roundEndCaps: true,\n        strokeWidthPx: radius * 2);\n  }\n\n  @override\n  bool shouldRepaint(CylinderSymbolRenderer oldRenderer) {\n    return this != oldRenderer;\n  }\n\n  @override\n  bool operator ==(Object other) => other is CylinderSymbolRenderer;\n\n  @override\n  int get hashCode => runtimeType.hashCode;\n}\n\n/// Draws a rectangular shape connecting two points.\nclass RectangleRangeSymbolRenderer extends PointSymbolRenderer {\n  RectangleRangeSymbolRenderer();\n\n  @override\n  void paint(ChartCanvas canvas, Point<double> p1, double radius,\n      {required Point<double> p2,\n      Color? fillColor,\n      Color? strokeColor,\n      double? strokeWidthPx}) {\n    if (p1 == null) {\n      throw ArgumentError('Invalid point p1 \"${p1}\"');\n    }\n\n    if (p2 == null) {\n      throw ArgumentError('Invalid point p2 \"${p2}\"');\n    }\n\n    final adjustedP1 = Point<double>(p1.x, p1.y);\n    final adjustedP2 = Point<double>(p2.x, p2.y);\n\n    canvas.drawLine(\n        points: [adjustedP1, adjustedP2],\n        stroke: strokeColor,\n        roundEndCaps: false,\n        strokeWidthPx: radius * 2);\n  }\n\n  @override\n  bool shouldRepaint(RectangleRangeSymbolRenderer oldRenderer) {\n    return this != oldRenderer;\n  }\n\n  @override\n  bool operator ==(Object other) => other is RectangleRangeSymbolRenderer;\n\n  @override\n  int get hashCode => runtimeType.hashCode;\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/common/text_element.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'text_measurement.dart' show TextMeasurement;\nimport 'text_style.dart' show TextStyle;\n\n/// Interface for accessing text measurement and painter.\nabstract class TextElement {\n  /// The [TextStyle] of this [TextElement].\n  TextStyle? get textStyle;\n\n  set textStyle(TextStyle? value);\n\n  /// The max width of this [TextElement] during measure and layout.\n  ///\n  /// If the text exceeds maxWidth, the [maxWidthStrategy] is used.\n  int? get maxWidth;\n\n  set maxWidth(int? value);\n\n  /// The strategy to use if this [TextElement] exceeds the [maxWidth].\n  MaxWidthStrategy? get maxWidthStrategy;\n\n  set maxWidthStrategy(MaxWidthStrategy? maxWidthStrategy);\n\n  /// The opacity of this element, in addition to the alpha set on the color\n  /// of this element.\n  set opacity(double? opacity);\n\n  // The text of this [TextElement].\n  String get text;\n\n  /// The [TextMeasurement] of this [TextElement] as an approximate of what\n  /// is actually printed.\n  ///\n  /// Will return the [maxWidth] if set and the actual text width is larger.\n  TextMeasurement get measurement;\n\n  /// The direction to render the text relative to the coordinate.\n  TextDirection get textDirection;\n  set textDirection(TextDirection direction);\n\n  /// Return true if settings are all the same.\n  ///\n  /// Purposely excludes measurement because the measurement will request the\n  /// native [TextElement] to layout, which is expensive. We want to avoid the\n  /// layout by comparing with another [TextElement] to see if they have the\n  /// same settings.\n  static bool elementSettingsSame(TextElement a, TextElement b) {\n    return a.textStyle == b.textStyle &&\n        a.maxWidth == b.maxWidth &&\n        a.maxWidthStrategy == b.maxWidthStrategy &&\n        a.text == b.text &&\n        a.textDirection == b.textDirection;\n  }\n}\n\nenum TextDirection {\n  ltr,\n  rtl,\n  center,\n}\n\n/// The strategy to use if a [TextElement] exceeds the [maxWidth].\nenum MaxWidthStrategy {\n  truncate,\n  ellipsize,\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/common/text_measurement.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n/// A measurement result for rendering text.\nclass TextMeasurement {\n  /// Rendered width of the text.\n  final double horizontalSliceWidth;\n\n  /// Vertical slice is likely based off the rendered text.\n  ///\n  /// This means that 'mo' and 'My' will have different heights so do not use\n  /// this for centering vertical text.\n  final double verticalSliceWidth;\n\n  /// Baseline of the text for text vertical alignment.\n  final double? baseline;\n\n  TextMeasurement({\n    required this.horizontalSliceWidth,\n    required this.verticalSliceWidth,\n    this.baseline,\n  });\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/common/text_style.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'paint_style.dart' show PaintStyle;\n\n/// Paint properties of a text.\nabstract class TextStyle extends PaintStyle {\n  int? get fontSize;\n  set fontSize(int? value);\n\n  String? get fontFamily;\n  set fontFamily(String? fontFamily);\n\n  double? get lineHeight;\n  set lineHeight(double? value);\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/common/text_utils.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:collection';\n\nimport 'package:charts_common/src/common/graphics_factory.dart';\nimport 'package:charts_common/src/common/text_element.dart';\n\n/// This function breaks original [labelElement] into multiple\n/// [TextElement] when [multiline] is true and the width of\n/// [labelElement] is larger than [maxWidth], maximum height is\n/// limited by [maxHeight]. Otherwise, ellipsize [labelElement] by\n/// [maxWidth]\n///\n/// Returns a list of [TextElement] with given [textStyle].\nconst _defaultlabelDelimiter = ' ';\n\nList<TextElement> wrapLabelLines(TextElement labelElement,\n    GraphicsFactory graphicsFactory, num maxWidth, num maxHeight,\n    {required bool allowLabelOverflow,\n    required bool multiline,\n    String labelDelimiter = _defaultlabelDelimiter}) {\n  final textStyle = labelElement.textStyle;\n  final textDirection = labelElement.textDirection;\n  final labelLineHeight = labelElement.measurement.verticalSliceWidth;\n  final maxLines = (maxHeight / labelLineHeight).floor();\n  final maxWidthStrategy =\n      labelElement.maxWidthStrategy ?? MaxWidthStrategy.ellipsize;\n\n  if (maxWidth.toInt() <= 0 || maxLines <= 0) return <TextElement>[];\n\n  final createTextElement =\n      (String text) => graphicsFactory.createTextElement(text)\n        ..textStyle = textStyle\n        ..textDirection = textDirection;\n\n  if (!multiline) {\n    labelElement\n      ..maxWidthStrategy = maxWidthStrategy\n      ..maxWidth = maxWidth.toInt();\n\n    final labelFits = _doesLabelFit(\n        allowLabelOverflow, labelElement, maxWidth, createTextElement);\n\n    return [\n      if (labelFits) labelElement,\n    ];\n  }\n\n  final delimiterElement = createTextElement(labelDelimiter);\n\n  final delimiterElementWidth =\n      delimiterElement.measurement.horizontalSliceWidth;\n\n  final labelPartElements = Queue<TextElement>()\n    ..addAll(labelElement.text.split(labelDelimiter).map(createTextElement));\n\n  final labelElements = <TextElement>[];\n  var currentLineElements = <TextElement>[];\n  var currentLineNumber = 0;\n  var currentWidth = 0.0;\n\n  while (labelPartElements.isNotEmpty && currentLineNumber < maxLines) {\n    final currentElement = labelPartElements.removeFirst();\n    var width = currentElement.measurement.horizontalSliceWidth +\n        (currentLineElements.isEmpty\n            ? 0\n            : currentWidth + delimiterElementWidth);\n\n    // If the new word can fit in the left space of the line.\n    if (width < maxWidth) {\n      currentWidth = width;\n      if (currentLineElements.isNotEmpty) {\n        currentLineElements.add(delimiterElement);\n      }\n      currentLineElements.add(currentElement);\n    } else {\n      // If the new word can not fit in the left space of the line.\n      var currentLineString =\n          currentLineElements.map((element) => element.text).join();\n      currentLineNumber++;\n      currentLineElements = [];\n      currentWidth = 0;\n\n      // If this is the last line, ellipsize the string of current line and\n      // new word.\n      if (currentLineNumber == maxLines) {\n        if (currentLineString != '') currentLineString += labelDelimiter;\n        currentLineString += currentElement.text;\n        final truncatedLabelElement = createTextElement(currentLineString)\n          ..maxWidthStrategy = maxWidthStrategy\n          ..maxWidth = maxWidth.toInt();\n\n        if (_doesLabelFit(allowLabelOverflow, truncatedLabelElement, maxWidth,\n            createTextElement)) {\n          labelElements.add(truncatedLabelElement);\n        }\n        break;\n      } else {\n        // This is not the last line.\n        if (currentLineString == '') {\n          // When currentElement cannot fit in a whole line.\n          final results =\n              _splitLabel(currentElement.text, createTextElement, maxWidth);\n          labelPartElements.addFirst(results[1]);\n          labelElements.add(results[0]);\n        } else {\n          // Starts a new line.\n          final currentLineTextElement = createTextElement(currentLineString);\n          labelElements.add(currentLineTextElement);\n          labelPartElements.addFirst(currentElement);\n        }\n      }\n    }\n  }\n\n  if (currentLineElements.isNotEmpty) {\n    final currentLineString =\n        currentLineElements.map((element) => element.text).join();\n\n    final labelElement = createTextElement(currentLineString);\n    labelElements.add(labelElement);\n  }\n  return labelElements;\n}\n\n/// Split label into two pieces, the first part should exactly fit into a\n/// single line.\n///\n/// Returns a list of [TextElement] with length of 2.\nList<TextElement> _splitLabel(\n    String text, TextElement Function(String) createTextElement, num maxWidth) {\n  var l = 0;\n  var r = text.length - 1;\n  var m = ((l + r) / 2).floor();\n\n  while (l < r - 1) {\n    final labelElement = createTextElement(text.substring(0, m));\n    if (labelElement.measurement.horizontalSliceWidth < maxWidth) {\n      l = m;\n      m = ((l + r) / 2).floor();\n    } else if (labelElement.measurement.horizontalSliceWidth == maxWidth) {\n      l = m;\n      break;\n    } else {\n      r = m;\n      m = ((l + r) / 2).floor();\n    }\n  }\n\n  return <TextElement>[\n    createTextElement(text.substring(0, l)),\n    createTextElement(text.substring(l, text.length))\n  ];\n}\n\n/// Tests whether or not a given text element fits in the available space.\nbool _doesLabelFit(bool allowLabelOverflow, TextElement textElement,\n    num maxWidth, TextElement Function(String) createTextElement) {\n  if (textElement.maxWidthStrategy != MaxWidthStrategy.ellipsize ||\n      allowLabelOverflow) {\n    return true;\n  }\n\n  // When allowLabelOverflow is disabled and maxWidthStrategy is ellipsize,\n  // compares [textElement] width with [maxWidth].\n  final ellipsizedText = textElement.text;\n  final ellipsizedElementWidth = (createTextElement(ellipsizedText)\n        ..textStyle = textElement.textStyle)\n      .measurement\n      .horizontalSliceWidth;\n\n  return ellipsizedElementWidth <= maxWidth;\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/common/typed_registry.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nclass TypedRegistry {\n  final _registry = <TypedKey<Object?>, Object?>{};\n\n  R? getAttr<R>(TypedKey<R> key) {\n    return _registry[key] as R?;\n  }\n\n  void setAttr<R>(TypedKey<R> key, R value) {\n    _registry[key] = value;\n  }\n\n  void mergeFrom(TypedRegistry other) {\n    _registry.addAll(other._registry);\n  }\n}\n\nclass TypedKey<R> {\n  final String uniqueKey;\n  const TypedKey(this.uniqueKey);\n\n  @override\n  int get hashCode => uniqueKey.hashCode;\n\n  @override\n  bool operator ==(Object other) =>\n      other is TypedKey && uniqueKey == other.uniqueKey;\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/data/series.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport '../chart/cartesian/axis/spec/axis_spec.dart' show TextStyleSpec;\nimport '../chart/common/chart_canvas.dart' show FillPatternType;\nimport '../chart/common/datum_details.dart'\n    show DomainFormatter, MeasureFormatter;\nimport '../common/color.dart' show Color;\nimport '../common/typed_registry.dart' show TypedRegistry, TypedKey;\n\nclass Series<T, D> {\n  final String id;\n  final String? displayName;\n\n  /// Overlay series provided supplemental information on a chart, but are not\n  /// considered to be primary data. They should not be selectable by user\n  /// interaction.\n  final bool overlaySeries;\n\n  final String? seriesCategory;\n\n  /// Color which represents the entire series in legends.\n  ///\n  /// If this is not provided in the original series object, it will be inferred\n  /// from the color of the first datum in the series.\n  ///\n  /// If this is provided, but no [colorFn] is provided, then it will be treated\n  /// as the color for each datum in the series.\n  ///\n  /// If neither are provided, then the chart will insert colors for each series\n  /// on the chart using a mapping function.\n  final Color? seriesColor;\n\n  final List<T> data;\n\n  /// [keyFn] defines a globally unique identifier for each datum.\n  ///\n  /// The key for each datum is used during chart animation to smoothly\n  /// transition data still in the series to its new state.\n  ///\n  /// Note: This is currently an optional function that is not fully used by all\n  /// series renderers yet.\n  final AccessorFn<String>? keyFn;\n\n  final AccessorFn<D> domainFn;\n  final AccessorFn<DomainFormatter<D>>? domainFormatterFn;\n  final AccessorFn<D?>? domainLowerBoundFn;\n  final AccessorFn<D?>? domainUpperBoundFn;\n  final AccessorFn<num?> measureFn;\n  final AccessorFn<MeasureFormatter>? measureFormatterFn;\n  final AccessorFn<num?>? measureLowerBoundFn;\n  final AccessorFn<num?>? measureUpperBoundFn;\n  final AccessorFn<num>? measureOffsetFn;\n\n  /// [areaColorFn] returns the area color for a given data value. If not\n  /// provided, then some variation of the main [colorFn] will be used (e.g.\n  /// 10% opacity).\n  ///\n  /// This color is used for supplemental information on the series, such as\n  /// confidence intervals or area skirts.\n  final AccessorFn<Color>? areaColorFn;\n\n  /// [colorFn] returns the rendered stroke color for a given data value.\n  ///\n  /// If this is not provided, then [seriesColor] will be used for every datum.\n  ///\n  /// If neither are provided, then the chart will insert colors for each series\n  /// on the chart using a mapping function.\n  final AccessorFn<Color>? colorFn;\n\n  /// [dashPatternFn] returns the dash pattern for a given data value.\n  final AccessorFn<List<int>?>? dashPatternFn;\n\n  /// [fillColorFn] returns the rendered fill color for a given data value. If\n  /// not provided, then [colorFn] will be used as a fallback.\n  final AccessorFn<Color?>? fillColorFn;\n\n  /// [patternColorFn] returns the background color of tile when a\n  /// [FillPatternType] beside `solid` is used. If not provided, then\n  /// background color is used.\n  final AccessorFn<Color>? patternColorFn;\n\n  final AccessorFn<FillPatternType>? fillPatternFn;\n  final AccessorFn<num>? radiusPxFn;\n  final AccessorFn<num?>? strokeWidthPxFn;\n  final AccessorFn<String>? labelAccessorFn;\n  final AccessorFn<TextStyleSpec>? insideLabelStyleAccessorFn;\n  final AccessorFn<TextStyleSpec>? outsideLabelStyleAccessorFn;\n\n  // TODO: should this be immutable as well? If not, should any of\n  // the non-required ones be final?\n  final SeriesAttributes attributes = SeriesAttributes();\n\n  factory Series(\n      {required String id,\n      required List<T> data,\n      required TypedAccessorFn<T, D> domainFn,\n      required TypedAccessorFn<T, num?> measureFn,\n      String? displayName,\n      Color? seriesColor,\n      TypedAccessorFn<T, Color>? areaColorFn,\n      TypedAccessorFn<T, Color>? colorFn,\n      TypedAccessorFn<T, List<int>?>? dashPatternFn,\n      TypedAccessorFn<T, DomainFormatter<D>>? domainFormatterFn,\n      TypedAccessorFn<T, D?>? domainLowerBoundFn,\n      TypedAccessorFn<T, D?>? domainUpperBoundFn,\n      TypedAccessorFn<T, Color?>? fillColorFn,\n      TypedAccessorFn<T, Color>? patternColorFn,\n      TypedAccessorFn<T, FillPatternType>? fillPatternFn,\n      TypedAccessorFn<T, String>? keyFn,\n      TypedAccessorFn<T, String>? labelAccessorFn,\n      TypedAccessorFn<T, TextStyleSpec>? insideLabelStyleAccessorFn,\n      TypedAccessorFn<T, TextStyleSpec>? outsideLabelStyleAccessorFn,\n      TypedAccessorFn<T, MeasureFormatter>? measureFormatterFn,\n      TypedAccessorFn<T, num?>? measureLowerBoundFn,\n      TypedAccessorFn<T, num?>? measureUpperBoundFn,\n      TypedAccessorFn<T, num>? measureOffsetFn,\n      bool overlaySeries = false,\n      TypedAccessorFn<T, num>? radiusPxFn,\n      String? seriesCategory,\n      TypedAccessorFn<T, num?>? strokeWidthPxFn}) {\n    // Wrap typed accessors.\n    final _domainFn = (int? index) => domainFn(data[index!], index);\n    final _measureFn = (int? index) => measureFn(data[index!], index);\n    final _areaColorFn = areaColorFn == null\n        ? null\n        : (int? index) => areaColorFn(data[index!], index);\n    final _colorFn =\n        colorFn == null ? null : (int? index) => colorFn(data[index!], index);\n    final _dashPatternFn = dashPatternFn == null\n        ? null\n        : (int? index) => dashPatternFn(data[index!], index);\n    final _domainFormatterFn = domainFormatterFn == null\n        ? null\n        : (int? index) => domainFormatterFn(data[index!], index);\n    final _domainLowerBoundFn = domainLowerBoundFn == null\n        ? null\n        : (int? index) => domainLowerBoundFn(data[index!], index);\n    final _domainUpperBoundFn = domainUpperBoundFn == null\n        ? null\n        : (int? index) => domainUpperBoundFn(data[index!], index);\n    final _fillColorFn = fillColorFn == null\n        ? null\n        : (int? index) => fillColorFn(data[index!], index);\n    final _patternColorFn = patternColorFn == null\n        ? null\n        : (int? index) => patternColorFn(data[index!], index);\n    final _fillPatternFn = fillPatternFn == null\n        ? null\n        : (int? index) => fillPatternFn(data[index!], index);\n    final _labelAccessorFn = labelAccessorFn == null\n        ? null\n        : (int? index) => labelAccessorFn(data[index!], index);\n    final _insideLabelStyleAccessorFn = insideLabelStyleAccessorFn == null\n        ? null\n        : (int? index) => insideLabelStyleAccessorFn(data[index!], index);\n    final _outsideLabelStyleAccessorFn = outsideLabelStyleAccessorFn == null\n        ? null\n        : (int? index) => outsideLabelStyleAccessorFn(data[index!], index);\n    final _measureFormatterFn = measureFormatterFn == null\n        ? null\n        : (int? index) => measureFormatterFn(data[index!], index);\n    final _measureLowerBoundFn = measureLowerBoundFn == null\n        ? null\n        : (int? index) => measureLowerBoundFn(data[index!], index);\n    final _measureUpperBoundFn = measureUpperBoundFn == null\n        ? null\n        : (int? index) => measureUpperBoundFn(data[index!], index);\n    final _measureOffsetFn = measureOffsetFn == null\n        ? null\n        : (int? index) => measureOffsetFn(data[index!], index);\n    final _radiusPxFn = radiusPxFn == null\n        ? null\n        : (int? index) => radiusPxFn(data[index!], index);\n    final _strokeWidthPxFn = strokeWidthPxFn == null\n        ? null\n        : (int? index) => strokeWidthPxFn(data[index!], index);\n    final _keyFn =\n        keyFn == null ? null : (int? index) => keyFn(data[index!], index);\n\n    return Series._internal(\n      id: id,\n      data: data,\n      domainFn: _domainFn,\n      measureFn: _measureFn,\n      displayName: displayName,\n      areaColorFn: _areaColorFn,\n      colorFn: _colorFn,\n      dashPatternFn: _dashPatternFn,\n      domainFormatterFn: _domainFormatterFn,\n      domainLowerBoundFn: _domainLowerBoundFn,\n      domainUpperBoundFn: _domainUpperBoundFn,\n      fillColorFn: _fillColorFn,\n      fillPatternFn: _fillPatternFn,\n      keyFn: _keyFn,\n      patternColorFn: _patternColorFn,\n      labelAccessorFn: _labelAccessorFn,\n      insideLabelStyleAccessorFn: _insideLabelStyleAccessorFn,\n      outsideLabelStyleAccessorFn: _outsideLabelStyleAccessorFn,\n      measureFormatterFn: _measureFormatterFn,\n      measureLowerBoundFn: _measureLowerBoundFn,\n      measureUpperBoundFn: _measureUpperBoundFn,\n      measureOffsetFn: _measureOffsetFn,\n      overlaySeries: overlaySeries,\n      radiusPxFn: _radiusPxFn,\n      seriesCategory: seriesCategory,\n      seriesColor: seriesColor,\n      strokeWidthPxFn: _strokeWidthPxFn,\n    );\n  }\n\n  Series._internal({\n    required this.id,\n    required this.data,\n    required this.domainFn,\n    required this.measureFn,\n    required this.displayName,\n    required this.areaColorFn,\n    required this.colorFn,\n    required this.dashPatternFn,\n    required this.domainFormatterFn,\n    required this.domainLowerBoundFn,\n    required this.domainUpperBoundFn,\n    required this.fillColorFn,\n    required this.fillPatternFn,\n    required this.patternColorFn,\n    required this.keyFn,\n    required this.labelAccessorFn,\n    required this.insideLabelStyleAccessorFn,\n    required this.outsideLabelStyleAccessorFn,\n    required this.measureFormatterFn,\n    required this.measureLowerBoundFn,\n    required this.measureUpperBoundFn,\n    required this.measureOffsetFn,\n    required this.overlaySeries,\n    required this.radiusPxFn,\n    required this.seriesCategory,\n    required this.seriesColor,\n    required this.strokeWidthPxFn,\n  });\n\n  void setAttribute<R>(AttributeKey<R> key, R value) {\n    attributes.setAttr(key, value);\n  }\n\n  R? getAttribute<R>(AttributeKey<R> key) {\n    return attributes.getAttr<R>(key);\n  }\n}\n\n/// Computed property on series.\n///\n/// If the [index] argument is `null`, the accessor is asked to provide a\n/// property of [series] as a whole. Accessors are not required to support\n/// such usage.\n///\n/// Otherwise, [index] must be a valid subscript into a list of `series.length`.\ntypedef AccessorFn<R> = R Function(int? index);\n\ntypedef TypedAccessorFn<T, R> = R Function(T datum, int? index);\n\nclass AttributeKey<R> extends TypedKey<R> {\n  const AttributeKey(String uniqueKey) : super(uniqueKey);\n}\n\nclass SeriesAttributes extends TypedRegistry {}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/lib/src/data/tree.dart",
    "content": "// Copyright 2019 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:collection';\n\nimport 'package:charts_common/src/chart/cartesian/axis/spec/axis_spec.dart';\nimport 'package:charts_common/src/chart/common/chart_canvas.dart';\nimport 'package:charts_common/src/common/color.dart';\nimport 'package:charts_common/src/common/typed_registry.dart';\nimport 'package:meta/meta.dart';\n\nimport 'series.dart' show AttributeKey, Series, TypedAccessorFn;\n\n/// A tree structure that contains metadata of a rendering tree.\nclass Tree<T, D> {\n  /// Unique identifier for this [tree].\n  final String id;\n\n  /// Root node of this tree.\n  final TreeNode<T> root;\n\n  /// Accessor function that returns the domain for a tree node.\n  final TypedAccessorFn<TreeNode<T>, D> domainFn;\n\n  /// Accessor function that returns the measure for a tree node.\n  final TypedAccessorFn<TreeNode<T>, num?> measureFn;\n\n  /// Accessor function that returns the rendered stroke color for a tree node.\n  final TypedAccessorFn<TreeNode<T>, Color>? colorFn;\n\n  /// Accessor function that returns the rendered fill color for a tree node.\n  /// If not provided, then [colorFn] will be used as a fallback.\n  final TypedAccessorFn<TreeNode<T>, Color>? fillColorFn;\n\n  /// Accessor function that returns the pattern color for a tree node\n  /// If not provided, then background color is used as default.\n  final TypedAccessorFn<TreeNode<T>, Color>? patternColorFn;\n\n  /// Accessor function that returns the fill pattern for a tree node.\n  final TypedAccessorFn<TreeNode<T>, FillPatternType>? fillPatternFn;\n\n  /// Accessor function that returns the stroke width in pixel for a tree node.\n  final TypedAccessorFn<TreeNode<T>, num>? strokeWidthPxFn;\n\n  /// Accessor function that returns the label for a tree node.\n  final TypedAccessorFn<TreeNode<T>, String>? labelFn;\n\n  /// Accessor function that returns the style spec for a tree node label.\n  final TypedAccessorFn<TreeNode<T>, TextStyleSpec>? labelStyleFn;\n\n  /// [attributes] stores additional key-value pairs of attributes this tree is\n  /// associated with (e.g. rendererIdKey to renderer).\n  final TreeAttributes attributes = TreeAttributes();\n\n  factory Tree({\n    required String id,\n    required TreeNode<T> root,\n    required TypedAccessorFn<T, D> domainFn,\n    required TypedAccessorFn<T, num?> measureFn,\n    TypedAccessorFn<T, Color>? colorFn,\n    TypedAccessorFn<T, Color>? fillColorFn,\n    TypedAccessorFn<T, Color>? patternColorFn,\n    TypedAccessorFn<T, FillPatternType>? fillPatternFn,\n    TypedAccessorFn<T, num>? strokeWidthPxFn,\n    TypedAccessorFn<T, String>? labelFn,\n    TypedAccessorFn<T, TextStyleSpec>? labelStyleFn,\n  }) {\n    return Tree._(\n      id: id,\n      root: root,\n      domainFn: _castFrom<T, D>(domainFn)!,\n      measureFn: _castFrom<T, num?>(measureFn)!,\n      colorFn: _castFrom<T, Color>(colorFn),\n      fillColorFn: _castFrom<T, Color>(fillColorFn),\n      fillPatternFn: _castFrom<T, FillPatternType>(fillPatternFn),\n      patternColorFn: _castFrom<T, Color>(patternColorFn),\n      strokeWidthPxFn: _castFrom<T, num>(strokeWidthPxFn),\n      labelFn: _castFrom<T, String>(labelFn),\n      labelStyleFn: _castFrom<T, TextStyleSpec>(labelStyleFn),\n    );\n  }\n\n  Tree._({\n    required this.id,\n    required this.root,\n    required this.domainFn,\n    required this.measureFn,\n    required this.colorFn,\n    required this.fillColorFn,\n    required this.fillPatternFn,\n    required this.patternColorFn,\n    required this.strokeWidthPxFn,\n    required this.labelFn,\n    required this.labelStyleFn,\n  });\n\n  /// Creates a [Series] that contains all [TreeNode]s traversing from the\n  /// [root] of this tree.\n  ///\n  /// Considers the following tree:\n  /// ```\n  ///       A\n  ///     / | \\\n  ///    B  C  D      --->    [A, B, C, D, E, F]\n  ///         / \\\n  ///        E   F\n  /// ```\n  /// This method traverses from root node \"A\" in breadth-first order and\n  /// adds all its children to a list. The order of [TreeNode]s in the list\n  /// is based on the insertion order to children of a particular node.\n  /// All [TreeNode]s are accessible through [Series].data.\n  Series<TreeNode<T>, D> toSeries() {\n    final data = <TreeNode<T>>[];\n    root.visit(data.add);\n\n    return Series(\n      id: id,\n      data: data,\n      domainFn: domainFn,\n      measureFn: measureFn,\n      colorFn: colorFn,\n      fillColorFn: fillColorFn,\n      fillPatternFn: fillPatternFn,\n      patternColorFn: patternColorFn,\n      strokeWidthPxFn: strokeWidthPxFn,\n      labelAccessorFn: labelFn,\n      insideLabelStyleAccessorFn: labelStyleFn,\n    )..attributes.mergeFrom(attributes);\n  }\n\n  void setAttribute<R>(AttributeKey<R> key, R value) {\n    attributes.setAttr(key, value);\n  }\n\n  R? getAttribute<R>(AttributeKey<R> key) {\n    return attributes.getAttr<R>(key);\n  }\n}\n\nclass TreeNode<T> {\n  /// Associated data this node stores.\n  final T data;\n\n  final List<TreeNode<T>> _children = [];\n\n  int _depth = 0;\n\n  TreeNode<T>? parent;\n\n  TreeNode(this.data);\n\n  /// Distance between this node and the root node.\n  int get depth => _depth;\n\n  @protected\n  set depth(int val) {\n    _depth = val;\n  }\n\n  /// List of child nodes.\n  Iterable<TreeNode<T>> get children => _children;\n\n  /// Whether or not this node has any children.\n  bool get hasChildren => _children.isNotEmpty;\n\n  /// Adds a single child to this node.\n  void addChild(TreeNode<T> child) {\n    child.parent = this;\n    final delta = depth - child.depth + 1;\n    if (delta != 0) child.visit((node) => node.depth += delta);\n    _children.add(child);\n  }\n\n  /// Adds a list of children to this node.\n  void addChildren(Iterable<TreeNode<T>> newChildren) {\n    newChildren.forEach(addChild);\n  }\n\n  /// Applies the function [f] to all child nodes rooted from this node in\n  /// breadth first order.\n  void visit(void Function(TreeNode<T> node) f) {\n    final queue = Queue<TreeNode<T>>()..add(this);\n\n    while (queue.isNotEmpty) {\n      final node = queue.removeFirst();\n      f(node);\n      queue.addAll(node.children);\n    }\n  }\n}\n\n/// A registry that stores key-value pairs of attributes.\nclass TreeAttributes extends TypedRegistry {}\n\n/// Adapts a TypedAccessorFn<T, R> type to a TypedAccessorFn<TreeNode<T>, R>.\nTypedAccessorFn<TreeNode<T>, R>? _castFrom<T, R>(TypedAccessorFn<T, R>? f) {\n  return f == null\n      ? null\n      : (TreeNode<T> node, int? index) => f(node.data, index);\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_common/pubspec.yaml",
    "content": "name: charts_common\nversion: 0.11.0\ndescription: A common library for charting packages.\nauthor: Charts Team <charts_flutter@google.com>\nhomepage: https://github.com/google/charts\n\nenvironment:\n  sdk: '>=2.12.0 <3.0.0'\n\ndependencies:\n  collection: ^1.14.5\n  intl: \">=0.15.2 < 0.18.0\"\n  logging: any\n  meta: ^1.1.1\n  vector_math: ^2.0.8\n\ndev_dependencies:\n  mockito: ^5.0.0\n  test: ^1.5.3\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_flutter/CHANGELOG.md",
    "content": "# 0.11.0\n* Null support\n* Update to latest from internal repo\n\n# 0.10.0\n* Internal bug fixes\n* Bump versions of intl due to pull request\n\n# 0.9.0\n* Internal bug fixes\n* Bump versions in Gemlock file due to security alerts\n\n# 0.8.1\n* Update intl version.\n\n# 0.8.0\n* Bug fixes from open source.\n\n# 0.7.0\n* Added vertical bar label\n\n# 0.6.0\n* Bars can now be rendered on line charts.\n* Negative measure values will now be rendered on bar charts as a separate stack from the positive\nvalues.\n* Added a Datum Legend, which displays one entry per value in the first series on the chart. This is\n useful for pie and scatter plot charts.\n* The AxisPosition enum in RTLSpec was refactored to AxisDirection to better reflect its effect on\nswapping the positions of all start and end components, and not just positioning the measure axes.\n* Added custom colors for line renderer area skirts and confidence intervals. A new \"areaColorFn\"\nhas been added to Series, and corresponding data to the datum. We could not use the fillColorFn for\nthese elements, because that color is already applied to the internal section of points on line\ncharts (including highlighter behaviors).\n\n# 0.5.0\n* SelectionModelConfig's listener parameter has been renamed to \"changeListener\". This is a breaking\nchange. Please rename any existing uses of the \"listener\" parameter to \"changeListener\". This was\nnamed in order to add an additional listener \"updateListener\" that listens to any update requests,\nregardless if the selection model has changed.\n* CartesianChart's method getMeasureAxis(String axisId) has been changed to\ngetMeasureAxis({String axisId) so that getting the primary measure axis will not need passing any id\nthat does not match the secondary measure axis id. This affects users implementing custom behaviors\nusing the existing method.\n\n# 0.4.0\n* Fixed export file to export ChartsBehavior in the Flutter library instead of the one that resides\nin charts_common. The charts_common behavior should not be used except internally in the\ncharts_flutter library. This is a breaking change if you are using charts_common behavior.\n* Declare compatibility with Dart 2.\n* BasicNumericTickFormatterSpec now takes in a callback instead of NumberFormat as the default\nconstructor. Use named constructor withNumberFormat instead. This is a breaking change.\n* BarRendererConfig is no longer default of type String, please change current usage to\nBarRendererConfig<String>. This is a breaking change.\n* BarTargetLineRendererConfig is no longer default of type String, please change current usage to\nBarTargetLineRendererConfig<String>. This is a breaking change.\n\n# 0.3.0\n* Simplified API by removing the requirement for specifying the datum type when creating a chart.\nFor example, previously to construct a bar chart the syntax was 'new BarChart<MyDatumType>()'.\nThe syntax is now cleaned up to be 'new BarChart()'. Please refer to the\n[online gallery](https://google.github.io/charts/flutter/gallery.html) for the correct syntax.\n* Added scatter plot charts\n* Added tap to hide for legends\n* Added support for rendering area skirts to line charts\n* Added support for configurable fill colors to bar charts\n\n# 0.2.0\n\n* Update color palette. Please use MaterialPalette instead of QuantumPalette.\n* Dart2 fixes\n\n# 0.1.0\n\nInitial release.\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_flutter/ExternalTapQueues.METADATA",
    "content": "# Format: google3/devtools/metadata/metadata.proto (go/google3metadata)\n# https://cs.corp.google.com/#google3/devtools/metadata/presubmit.proto\n\n# External Tap queues to run for CLs to Charts Flutter.\n#\n# All TAP projects added must comply with http://go/dart-charts-testing-sla.\n# Projects that violate the testing SLA will be removed immediately.\npresubmit {\n  path_expression: \"//depot/google3/third_party/dart/charts_flutter/...\"\n  path_expression: \"//depot/google3/third_party/dart/charts_common/...\"\n\n  check_tests: {\n    failure_status: ERROR\n    # For each client TAP, please add team name, email alias, and buganizer\n    # component ID.\n\n    # Connect Sales Mobile, gt-fe-dev@, bug component ID: 122320.\n    project: \"greentea.flutter\"\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_flutter/LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_flutter/README.md",
    "content": "# Flutter Charting library\n\n[![pub package](https://img.shields.io/pub/v/charts_flutter.svg)](https://pub.dartlang.org/packages/charts_flutter)\n\nMaterial Design data visualization library written natively in Dart.\n\n## Supported charts\n\nSee the [online gallery](https://google.github.io/charts/flutter/gallery.html).\n\n## Using the library\n\nThe `/example/` folder inside `charts_flutter` in the [GitHub repo](https://github.com/google/charts)\ncontains a full Flutter app with many demo examples.\n\n## Development\nThis project is developed internally at Google and published for external\nconsumption, external contributions unfortunately cannot be taken at this time.\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_flutter/charts_flutter.gwsq",
    "content": "send_cls_to('dart-charts-team+reviews');\nsend_cls_to('dart-charts-team');\n\ndefine Main {\n  reassign_to_list(from_owners_file('third_party/dart/charts_common/OWNERS'));\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_flutter/lib/flutter.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nexport 'package:charts_common/common.dart'\n    show\n        boundsLineRadiusPxFnKey,\n        boundsLineRadiusPxKey,\n        measureAxisIdKey,\n        pointSymbolRendererFnKey,\n        pointSymbolRendererIdKey,\n        rendererIdKey,\n        AnnotationLabelAnchor,\n        AnnotationLabelDirection,\n        AnnotationLabelPosition,\n        ArcLabelDecorator,\n        ArcLabelLeaderLineStyleSpec,\n        ArcLabelPosition,\n        ArcRenderer,\n        ArcRendererConfig,\n        AutoDateTimeTickFormatterSpec,\n        AutoDateTimeTickProviderSpec,\n        Axis,\n        AxisDirection,\n        AxisSpec,\n        BarGroupingType,\n        BarLabelAnchor,\n        BarLabelDecorator,\n        BarLabelPosition,\n        BarLaneRendererConfig,\n        BarRenderer,\n        BarRendererConfig,\n        BarTargetLineRenderer,\n        BarTargetLineRendererConfig,\n        BaseCartesianRenderer,\n        BasicDateTimeTickFormatterSpec,\n        BasicNumericTickFormatterSpec,\n        BasicNumericTickProviderSpec,\n        BasicOrdinalTickProviderSpec,\n        BasicOrdinalTickFormatterSpec,\n        BehaviorPosition,\n        BucketingAxisSpec,\n        BucketingNumericTickProviderSpec,\n        CartesianChart,\n        ChartCanvas,\n        ChartContext,\n        ChartTitleDirection,\n        CircleSymbolRenderer,\n        Color,\n        ComparisonPointsDecorator,\n        ConstCornerStrategy,\n        CornerStrategy,\n        CylinderSymbolRenderer,\n        DateTimeAxisSpec,\n        DateTimeEndPointsTickProviderSpec,\n        DateTimeExtents,\n        DateTimeFactory,\n        DateTimeTickFormatter,\n        DateTimeTickFormatterSpec,\n        DateTimeTickProviderSpec,\n        DayTickProviderSpec,\n        DomainFormatter,\n        EndPointsTimeAxisSpec,\n        ExploreModeTrigger,\n        FillPatternType,\n        GestureListener,\n        GraphicsFactory,\n        GridlineRendererSpec,\n        ImmutableSeries,\n        InsideJustification,\n        LayoutPosition,\n        LayoutViewPaintOrder,\n        LayoutViewPositionOrder,\n        LegendDefaultMeasure,\n        LegendTapHandling,\n        LineAnnotationSegment,\n        LinePointHighlighterFollowLineType,\n        LineRenderer,\n        LineRendererConfig,\n        LineStyleSpec,\n        LocalDateTimeFactory,\n        LockSelection,\n        MarginSpec,\n        MaterialPalette,\n        MaterialStyle,\n        MaxWidthStrategy,\n        MeasureFormatter,\n        NoCornerStrategy,\n        NoneRenderSpec,\n        NumericAxis,\n        NumericAxisSpec,\n        NumericCartesianChart,\n        NumericEndPointsTickProviderSpec,\n        NumericExtents,\n        NumericTickFormatterSpec,\n        NumericTickProviderSpec,\n        OrdinalAxis,\n        OrdinalAxisSpec,\n        OrdinalCartesianChart,\n        OrdinalTickFormatterSpec,\n        OrdinalTickProviderSpec,\n        OrdinalViewport,\n        OutsideJustification,\n        PanningCompletedCallback,\n        PercentAxisSpec,\n        PercentInjectorTotalType,\n        Performance,\n        PointRenderer,\n        PointRendererConfig,\n        PointRendererDecorator,\n        PointRendererElement,\n        PointSymbolRenderer,\n        QuantumPalette,\n        RangeAnnotationAxisType,\n        RangeAnnotationSegment,\n        RectSymbolRenderer,\n        RenderSpec,\n        RTLSpec,\n        SelectionModel,\n        SelectionModelListener,\n        SelectionModelType,\n        SelectionTrigger,\n        Series,\n        SeriesDatum,\n        SeriesDatumConfig,\n        SeriesRenderer,\n        SeriesRendererConfig,\n        SimpleTickFormatterBase,\n        SliderListenerCallback,\n        SliderListenerDragState,\n        SliderStyle,\n        SmallTickRendererSpec,\n        StaticDateTimeTickProviderSpec,\n        StaticNumericTickProviderSpec,\n        StaticOrdinalTickProviderSpec,\n        StyleFactory,\n        SymbolAnnotationRenderer,\n        SymbolAnnotationRendererConfig,\n        TextDirection,\n        TextElement,\n        TextStyle,\n        TextStyleSpec,\n        TickFormatter,\n        TickFormatterSpec,\n        TickLabelAnchor,\n        TickLabelJustification,\n        TickSpec,\n        TimeFormatterSpec,\n        TypedAccessorFn,\n        UTCDateTimeFactory,\n        ViewMargin,\n        VocalizationCallback;\n\nexport 'src/bar_chart.dart';\nexport 'src/base_chart.dart' show BaseChart, LayoutConfig;\nexport 'src/behaviors/a11y/domain_a11y_explore_behavior.dart'\n    show DomainA11yExploreBehavior;\nexport 'src/behaviors/chart_behavior.dart' show ChartBehavior;\nexport 'src/behaviors/domain_highlighter.dart' show DomainHighlighter;\nexport 'src/behaviors/initial_selection.dart' show InitialSelection;\nexport 'src/behaviors/calculation/percent_injector.dart' show PercentInjector;\nexport 'src/behaviors/chart_title/chart_title.dart' show ChartTitle;\nexport 'src/behaviors/legend/datum_legend.dart' show DatumLegend;\nexport 'src/behaviors/legend/legend_content_builder.dart'\n    show LegendContentBuilder, TabularLegendContentBuilder;\nexport 'src/behaviors/legend/legend_entry_layout.dart'\n    show LegendEntryLayout, SimpleLegendEntryLayout;\nexport 'src/behaviors/legend/legend_layout.dart'\n    show LegendLayout, TabularLegendLayout;\nexport 'src/behaviors/legend/series_legend.dart' show SeriesLegend;\nexport 'src/behaviors/line_point_highlighter.dart' show LinePointHighlighter;\nexport 'src/behaviors/range_annotation.dart' show RangeAnnotation;\nexport 'src/behaviors/select_nearest.dart' show SelectNearest;\nexport 'src/behaviors/sliding_viewport.dart' show SlidingViewport;\nexport 'src/behaviors/slider/slider.dart' show Slider;\nexport 'src/behaviors/zoom/initial_hint_behavior.dart' show InitialHintBehavior;\nexport 'src/behaviors/zoom/pan_and_zoom_behavior.dart' show PanAndZoomBehavior;\nexport 'src/behaviors/zoom/pan_behavior.dart' show PanBehavior;\nexport 'src/combo_chart/combo_chart.dart';\nexport 'src/line_chart.dart';\nexport 'src/pie_chart.dart';\nexport 'src/scatter_plot_chart.dart';\nexport 'src/selection_model_config.dart' show SelectionModelConfig;\nexport 'src/symbol_renderer.dart' show CustomSymbolRenderer;\nexport 'src/time_series_chart.dart';\nexport 'src/user_managed_state.dart'\n    show UserManagedState, UserManagedSelectionModel;\nexport 'src/util/color.dart' show ColorUtil;\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_flutter/lib/src/bar_chart.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:collection' show LinkedHashMap;\n\nimport 'package:charts_common/common.dart' as common\n    show\n        AxisSpec,\n        BarChart,\n        BarGroupingType,\n        BarRendererConfig,\n        BarRendererDecorator,\n        NumericAxisSpec,\n        RTLSpec,\n        Series,\n        SeriesRendererConfig;\nimport 'behaviors/domain_highlighter.dart' show DomainHighlighter;\nimport 'behaviors/chart_behavior.dart' show ChartBehavior;\nimport 'package:meta/meta.dart' show immutable;\nimport 'base_chart.dart' show LayoutConfig;\nimport 'base_chart_state.dart' show BaseChartState;\nimport 'cartesian_chart.dart' show CartesianChart;\nimport 'selection_model_config.dart' show SelectionModelConfig;\nimport 'user_managed_state.dart' show UserManagedState;\n\n@immutable\nclass BarChart extends CartesianChart<String> {\n  final bool vertical;\n  final common.BarRendererDecorator<String>? barRendererDecorator;\n\n  BarChart(\n    List<common.Series<dynamic, String>> seriesList, {\n    bool? animate,\n    Duration? animationDuration,\n    common.AxisSpec? domainAxis,\n    common.NumericAxisSpec? primaryMeasureAxis,\n    common.NumericAxisSpec? secondaryMeasureAxis,\n    LinkedHashMap<String, common.NumericAxisSpec>? disjointMeasureAxes,\n    common.BarGroupingType? barGroupingType,\n    common.BarRendererConfig<String>? defaultRenderer,\n    List<common.SeriesRendererConfig<String>>? customSeriesRenderers,\n    List<ChartBehavior<String>>? behaviors,\n    List<SelectionModelConfig<String>>? selectionModels,\n    common.RTLSpec? rtlSpec,\n    this.vertical = true,\n    bool defaultInteractions = true,\n    LayoutConfig? layoutConfig,\n    UserManagedState<String>? userManagedState,\n    this.barRendererDecorator,\n    bool? flipVerticalAxis,\n  }) : super(\n          seriesList,\n          animate: animate,\n          animationDuration: animationDuration,\n          domainAxis: domainAxis,\n          primaryMeasureAxis: primaryMeasureAxis,\n          secondaryMeasureAxis: secondaryMeasureAxis,\n          disjointMeasureAxes: disjointMeasureAxes,\n          defaultRenderer: defaultRenderer ??\n              new common.BarRendererConfig<String>(\n                  groupingType: barGroupingType,\n                  barRendererDecorator: barRendererDecorator),\n          customSeriesRenderers: customSeriesRenderers,\n          behaviors: behaviors,\n          selectionModels: selectionModels,\n          rtlSpec: rtlSpec,\n          defaultInteractions: defaultInteractions,\n          layoutConfig: layoutConfig,\n          userManagedState: userManagedState,\n          flipVerticalAxis: flipVerticalAxis,\n        );\n\n  @override\n  common.BarChart createCommonChart(BaseChartState chartState) {\n    // Optionally create primary and secondary measure axes if the chart was\n    // configured with them. If no axes were configured, then the chart will\n    // use its default types (usually a numeric axis).\n    return new common.BarChart(\n        vertical: vertical,\n        layoutConfig: layoutConfig?.commonLayoutConfig,\n        primaryMeasureAxis: primaryMeasureAxis?.createAxis(),\n        secondaryMeasureAxis: secondaryMeasureAxis?.createAxis(),\n        disjointMeasureAxes: createDisjointMeasureAxes());\n  }\n\n  @override\n  void addDefaultInteractions(List<ChartBehavior> behaviors) {\n    super.addDefaultInteractions(behaviors);\n\n    behaviors.add(new DomainHighlighter<String>());\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_flutter/lib/src/base_chart.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'package:charts_common/common.dart' as common\n    show\n        BaseChart,\n        LayoutConfig,\n        MarginSpec,\n        Performance,\n        RTLSpec,\n        Series,\n        SeriesRendererConfig,\n        SelectionModelType,\n        SelectionTrigger;\nimport 'behaviors/select_nearest.dart' show SelectNearest;\nimport 'package:meta/meta.dart' show immutable;\nimport 'behaviors/chart_behavior.dart'\n    show ChartBehavior, ChartStateBehavior, GestureType;\nimport 'selection_model_config.dart' show SelectionModelConfig;\nimport 'package:flutter/material.dart' show StatefulWidget;\nimport 'base_chart_state.dart' show BaseChartState;\nimport 'user_managed_state.dart' show UserManagedState;\n\n@immutable\nabstract class BaseChart<D> extends StatefulWidget {\n  /// Series list to draw.\n  final List<common.Series<dynamic, D>> seriesList;\n\n  /// Animation transitions.\n  final bool animate;\n  final Duration animationDuration;\n\n  /// Used to configure the margin sizes around the drawArea that the axis and\n  /// other things render into.\n  final LayoutConfig? layoutConfig;\n\n  // Default renderer used to draw series data on the chart.\n  final common.SeriesRendererConfig<D>? defaultRenderer;\n\n  /// Include the default interactions or not.\n  final bool defaultInteractions;\n\n  final List<ChartBehavior<D>>? behaviors;\n\n  final List<SelectionModelConfig<D>>? selectionModels;\n\n  // List of custom series renderers used to draw series data on the chart.\n  //\n  // Series assigned a rendererIdKey will be drawn with the matching renderer in\n  // this list. Series without a rendererIdKey will be drawn by the default\n  // renderer.\n  final List<common.SeriesRendererConfig<D>>? customSeriesRenderers;\n\n  /// The spec to use if RTL is enabled.\n  final common.RTLSpec? rtlSpec;\n\n  /// Optional state that overrides internally kept state, such as selection.\n  final UserManagedState<D>? userManagedState;\n\n  BaseChart(this.seriesList,\n      {bool? animate,\n      Duration? animationDuration,\n      this.defaultRenderer,\n      this.customSeriesRenderers,\n      this.behaviors,\n      this.selectionModels,\n      this.rtlSpec,\n      this.defaultInteractions = true,\n      this.layoutConfig,\n      this.userManagedState})\n      : this.animate = animate ?? true,\n        this.animationDuration =\n            animationDuration ?? const Duration(milliseconds: 300);\n\n  @override\n  BaseChartState<D> createState() => new BaseChartState<D>();\n\n  /// Creates and returns a [common.BaseChart].\n  common.BaseChart<D> createCommonChart(BaseChartState<D> chartState);\n\n  /// Updates the [common.BaseChart].\n  void updateCommonChart(common.BaseChart<D> chart, BaseChart<D>? oldWidget,\n      BaseChartState<D> chartState) {\n    common.Performance.time('chartsUpdateRenderers');\n    // Set default renderer if one was provided.\n    if (defaultRenderer != null &&\n        defaultRenderer != oldWidget?.defaultRenderer) {\n      chart.defaultRenderer = defaultRenderer!.build();\n      chartState.markChartDirty();\n    }\n\n    // Add custom series renderers if any were provided.\n    if (customSeriesRenderers != null) {\n      // TODO: This logic does not remove old renderers and\n      // shouldn't require the series configs to remain in the same order.\n      for (var i = 0; i < customSeriesRenderers!.length; i++) {\n        if (oldWidget == null ||\n            (oldWidget.customSeriesRenderers != null &&\n                i > oldWidget.customSeriesRenderers!.length) ||\n            customSeriesRenderers![i] != oldWidget.customSeriesRenderers![i]) {\n          chart.addSeriesRenderer(customSeriesRenderers![i].build());\n          chartState.markChartDirty();\n        }\n      }\n    }\n    common.Performance.timeEnd('chartsUpdateRenderers');\n\n    common.Performance.time('chartsUpdateBehaviors');\n    _updateBehaviors(chart, chartState);\n    common.Performance.timeEnd('chartsUpdateBehaviors');\n\n    _updateSelectionModel(chart, chartState);\n\n    chart.transition = animate ? animationDuration : Duration.zero;\n  }\n\n  void _updateBehaviors(common.BaseChart chart, BaseChartState<D> chartState) {\n    final behaviorList = List<ChartBehavior<D>>.from(behaviors ?? []);\n\n    // Insert automatic behaviors to the front of the behavior list.\n    if (defaultInteractions) {\n      if (chartState.autoBehaviorWidgets.isEmpty) {\n        addDefaultInteractions(chartState.autoBehaviorWidgets);\n      }\n\n      // Add default interaction behaviors to the front of the list if they\n      // don't conflict with user behaviors by role.\n      chartState.autoBehaviorWidgets.reversed\n          .where(_notACustomBehavior)\n          .forEach((ChartBehavior<D> behavior) {\n        behaviorList.insert(0, behavior);\n      });\n    }\n\n    // Remove any behaviors from the chart that are not in the incoming list.\n    // Walk in reverse order they were added.\n    // Also, remove any persisting behaviors from incoming list.\n    for (int i = chartState.addedBehaviorWidgets.length - 1; i >= 0; i--) {\n      final addedBehavior = chartState.addedBehaviorWidgets[i];\n      if (!behaviorList.remove(addedBehavior)) {\n        final role = addedBehavior.role;\n        chartState.addedBehaviorWidgets.remove(addedBehavior);\n        chartState.addedCommonBehaviorsByRole.remove(role);\n        chart.removeBehavior(chartState.addedCommonBehaviorsByRole[role]);\n        chartState.markChartDirty();\n      }\n    }\n\n    // Add any remaining/new behaviors.\n    behaviorList.forEach((ChartBehavior<D> behaviorWidget) {\n      final commonBehavior = behaviorWidget.createCommonBehavior();\n\n      // Assign the chart state to any behavior that needs it.\n      if (commonBehavior is ChartStateBehavior) {\n        (commonBehavior as ChartStateBehavior).chartState = chartState;\n      }\n\n      chart.addBehavior(commonBehavior);\n      chartState.addedBehaviorWidgets.add(behaviorWidget);\n      chartState.addedCommonBehaviorsByRole[behaviorWidget.role] =\n          commonBehavior;\n      chartState.markChartDirty();\n    });\n  }\n\n  /// Create the list of default interaction behaviors.\n  void addDefaultInteractions(List<ChartBehavior> behaviors) {\n    // Update selection model\n    behaviors.add(new SelectNearest<D>(\n        eventTrigger: common.SelectionTrigger.tap,\n        selectionModelType: common.SelectionModelType.info,\n        selectClosestSeries: true));\n  }\n\n  bool _notACustomBehavior(ChartBehavior behavior) {\n    return behaviors == null ||\n        !behaviors!.any(\n            (ChartBehavior userBehavior) => userBehavior.role == behavior.role);\n  }\n\n  void _updateSelectionModel(\n      common.BaseChart<D> chart, BaseChartState<D> chartState) {\n    final prevTypes = new List<common.SelectionModelType>.from(\n        chartState.addedSelectionChangedListenersByType.keys);\n\n    // Update any listeners for each type.\n    selectionModels?.forEach((SelectionModelConfig<D> model) {\n      final selectionModel = chart.getSelectionModel(model.type);\n\n      final prevChangedListener =\n          chartState.addedSelectionChangedListenersByType[model.type];\n      if (!identical(model.changedListener, prevChangedListener)) {\n        if (prevChangedListener != null) {\n          selectionModel.removeSelectionChangedListener(prevChangedListener);\n        }\n        selectionModel.addSelectionChangedListener(model.changedListener!);\n        chartState.addedSelectionChangedListenersByType[model.type] =\n            model.changedListener!;\n      }\n\n      final prevUpdatedListener =\n          chartState.addedSelectionUpdatedListenersByType[model.type];\n      if (!identical(model.updatedListener, prevUpdatedListener)) {\n        if (prevUpdatedListener != null) {\n          selectionModel.removeSelectionUpdatedListener(prevUpdatedListener);\n        }\n        selectionModel.addSelectionUpdatedListener(model.updatedListener!);\n        chartState.addedSelectionUpdatedListenersByType[model.type] =\n            model.updatedListener!;\n      }\n\n      prevTypes.remove(model.type);\n    });\n\n    // Remove any lingering listeners.\n    prevTypes.forEach((common.SelectionModelType type) {\n      chart.getSelectionModel(type)\n        ..removeSelectionChangedListener(\n            chartState.addedSelectionChangedListenersByType[type]!)\n        ..removeSelectionUpdatedListener(\n            chartState.addedSelectionUpdatedListenersByType[type]!);\n    });\n  }\n\n  /// Gets distinct set of gestures this chart will subscribe to.\n  ///\n  /// This is needed to allow setup of the [GestureDetector] widget with only\n  /// gestures we need to listen to and it must wrap [ChartContainer] widget.\n  /// Gestures are then setup to be proxied in [common.BaseChart] and that is\n  /// held by [ChartContainerRenderObject].\n  Set<GestureType> getDesiredGestures(BaseChartState chartState) {\n    final types = new Set<GestureType>();\n    behaviors?.forEach((ChartBehavior behavior) {\n      types.addAll(behavior.desiredGestures);\n    });\n\n    if (defaultInteractions && chartState.autoBehaviorWidgets.isEmpty) {\n      addDefaultInteractions(chartState.autoBehaviorWidgets);\n    }\n\n    chartState.autoBehaviorWidgets.forEach((ChartBehavior behavior) {\n      types.addAll(behavior.desiredGestures);\n    });\n    return types;\n  }\n}\n\n@immutable\nclass LayoutConfig {\n  final common.MarginSpec leftMarginSpec;\n  final common.MarginSpec topMarginSpec;\n  final common.MarginSpec rightMarginSpec;\n  final common.MarginSpec bottomMarginSpec;\n\n  LayoutConfig({\n    required this.leftMarginSpec,\n    required this.topMarginSpec,\n    required this.rightMarginSpec,\n    required this.bottomMarginSpec,\n  });\n\n  common.LayoutConfig get commonLayoutConfig => new common.LayoutConfig(\n      leftSpec: leftMarginSpec,\n      topSpec: topMarginSpec,\n      rightSpec: rightMarginSpec,\n      bottomSpec: bottomMarginSpec);\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_flutter/lib/src/base_chart_state.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:ui' show TextDirection;\nimport 'package:flutter/material.dart'\n    show\n        AnimationController,\n        BuildContext,\n        State,\n        TickerProviderStateMixin,\n        Widget;\nimport 'package:charts_common/common.dart' as common;\nimport 'package:flutter/widgets.dart'\n    show Directionality, LayoutId, CustomMultiChildLayout;\nimport 'behaviors/chart_behavior.dart'\n    show BuildableBehavior, ChartBehavior, ChartStateBehavior;\nimport 'base_chart.dart' show BaseChart;\nimport 'chart_container.dart' show ChartContainer;\nimport 'chart_state.dart' show ChartState;\nimport 'chart_gesture_detector.dart' show ChartGestureDetector;\nimport 'widget_layout_delegate.dart';\n\nclass BaseChartState<D> extends State<BaseChart<D>>\n    with TickerProviderStateMixin\n    implements ChartState {\n  // Animation\n  late AnimationController _animationController;\n  double _animationValue = 0.0;\n\n  BaseChart<D>? _oldWidget;\n\n  ChartGestureDetector? _chartGestureDetector;\n\n  bool _configurationChanged = false;\n\n  final autoBehaviorWidgets = <ChartBehavior<D>>[];\n  final addedBehaviorWidgets = <ChartBehavior<D>>[];\n  final addedCommonBehaviorsByRole = <String, common.ChartBehavior>{};\n\n  final addedSelectionChangedListenersByType =\n      <common.SelectionModelType, common.SelectionModelListener<D>>{};\n  final addedSelectionUpdatedListenersByType =\n      <common.SelectionModelType, common.SelectionModelListener<D>>{};\n\n  final _behaviorAnimationControllers =\n      <ChartStateBehavior, AnimationController>{};\n\n  static const chartContainerLayoutID = 'chartContainer';\n\n  @override\n  void initState() {\n    super.initState();\n    _animationController = new AnimationController(vsync: this)\n      ..addListener(_animationTick);\n  }\n\n  @override\n  void requestRebuild() {\n    setState(() {});\n  }\n\n  @override\n  void markChartDirty() {\n    _configurationChanged = true;\n  }\n\n  @override\n  void resetChartDirtyFlag() {\n    _configurationChanged = false;\n  }\n\n  @override\n  bool get chartIsDirty => _configurationChanged;\n\n  @override\n  void setState(fn) {\n    if (mounted) {\n      super.setState(fn);\n    }\n  }\n\n  /// Builds the common chart canvas widget.\n  Widget _buildChartContainer() {\n    final chartContainer = new ChartContainer<D>(\n      oldChartWidget: _oldWidget,\n      chartWidget: widget,\n      chartState: this,\n      animationValue: _animationValue,\n      rtl: Directionality.of(context) == TextDirection.rtl,\n      rtlSpec: widget.rtlSpec,\n      userManagedState: widget.userManagedState,\n    );\n    _oldWidget = widget;\n\n    final desiredGestures = widget.getDesiredGestures(this);\n    if (desiredGestures.isNotEmpty) {\n      _chartGestureDetector ??= new ChartGestureDetector();\n      return _chartGestureDetector!\n          .makeWidget(context, chartContainer, desiredGestures);\n    } else {\n      return chartContainer;\n    }\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    final chartWidgets = <LayoutId>[];\n    final idAndBehaviorMap = <String, BuildableBehavior>{};\n\n    // Add the common chart canvas widget.\n    chartWidgets.add(new LayoutId(\n        id: chartContainerLayoutID, child: _buildChartContainer()));\n\n    // Add widget for each behavior that can build widgets\n    addedCommonBehaviorsByRole.forEach((id, behavior) {\n      if (behavior is BuildableBehavior) {\n        assert(id != chartContainerLayoutID);\n\n        final buildableBehavior = behavior as BuildableBehavior;\n        idAndBehaviorMap[id] = buildableBehavior;\n\n        final widget = buildableBehavior.build(context);\n        chartWidgets.add(new LayoutId(id: id, child: widget));\n      }\n    });\n\n    final isRTL = Directionality.of(context) == TextDirection.rtl;\n\n    return new CustomMultiChildLayout(\n        delegate: new WidgetLayoutDelegate(\n            chartContainerLayoutID, idAndBehaviorMap, isRTL),\n        children: chartWidgets);\n  }\n\n  @override\n  void dispose() {\n    _animationController.dispose();\n    _behaviorAnimationControllers\n        .forEach((_, controller) => controller.dispose());\n    _behaviorAnimationControllers.clear();\n    super.dispose();\n  }\n\n  @override\n  void setAnimation(Duration transition) {\n    _playAnimation(transition);\n  }\n\n  void _playAnimation(Duration duration) {\n    _animationController.duration = duration;\n    _animationController.forward(from: (duration == Duration.zero) ? 1.0 : 0.0);\n    _animationValue = _animationController.value;\n  }\n\n  void _animationTick() {\n    setState(() {\n      _animationValue = _animationController.value;\n    });\n  }\n\n  /// Get animation controller to be used by [behavior].\n  AnimationController getAnimationController(ChartStateBehavior behavior) {\n    _behaviorAnimationControllers[behavior] ??=\n        new AnimationController(vsync: this);\n\n    return _behaviorAnimationControllers[behavior]!;\n  }\n\n  /// Dispose of animation controller used by [behavior].\n  void disposeAnimationController(ChartStateBehavior behavior) {\n    final controller = _behaviorAnimationControllers.remove(behavior);\n    controller?.dispose();\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_flutter/lib/src/behaviors/a11y/domain_a11y_explore_behavior.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'package:charts_common/common.dart' as common\n    show\n        ChartBehavior,\n        DomainA11yExploreBehavior,\n        VocalizationCallback,\n        ExploreModeTrigger;\nimport 'package:flutter/widgets.dart' show hashValues;\nimport '../chart_behavior.dart' show ChartBehavior, GestureType;\n\n/// Behavior that generates semantic nodes for each domain.\nclass DomainA11yExploreBehavior<D> extends ChartBehavior<D> {\n  /// Returns a string for a11y vocalization from a list of series datum.\n  final common.VocalizationCallback? vocalizationCallback;\n\n  final Set<GestureType> desiredGestures;\n\n  /// The gesture that activates explore mode. Defaults to long press.\n  ///\n  /// Turning on explore mode asks this [A11yBehavior] to generate nodes within\n  /// this chart.\n  final common.ExploreModeTrigger? exploreModeTrigger;\n\n  /// Minimum width of the bounding box for the a11y focus.\n  ///\n  /// Must be 1 or higher because invisible semantic nodes should not be added.\n  final double? minimumWidth;\n\n  /// Optionally notify the OS when explore mode is enabled.\n  final String? exploreModeEnabledAnnouncement;\n\n  /// Optionally notify the OS when explore mode is disabled.\n  final String? exploreModeDisabledAnnouncement;\n\n  DomainA11yExploreBehavior._internal(\n      {this.vocalizationCallback,\n      this.exploreModeTrigger,\n      required this.desiredGestures,\n      this.minimumWidth,\n      this.exploreModeEnabledAnnouncement,\n      this.exploreModeDisabledAnnouncement});\n\n  factory DomainA11yExploreBehavior({\n    common.VocalizationCallback? vocalizationCallback,\n    common.ExploreModeTrigger? exploreModeTrigger,\n    double? minimumWidth,\n    String? exploreModeEnabledAnnouncement,\n    String? exploreModeDisabledAnnouncement,\n  }) {\n    final desiredGestures = new Set<GestureType>();\n    exploreModeTrigger ??= common.ExploreModeTrigger.pressHold;\n\n    switch (exploreModeTrigger) {\n      case common.ExploreModeTrigger.pressHold:\n        desiredGestures..add(GestureType.onLongPress);\n        break;\n      case common.ExploreModeTrigger.tap:\n        desiredGestures..add(GestureType.onTap);\n        break;\n    }\n\n    return new DomainA11yExploreBehavior._internal(\n      vocalizationCallback: vocalizationCallback,\n      desiredGestures: desiredGestures,\n      exploreModeTrigger: exploreModeTrigger,\n      minimumWidth: minimumWidth,\n      exploreModeEnabledAnnouncement: exploreModeEnabledAnnouncement,\n      exploreModeDisabledAnnouncement: exploreModeDisabledAnnouncement,\n    );\n  }\n\n  @override\n  common.DomainA11yExploreBehavior<D> createCommonBehavior() {\n    return new common.DomainA11yExploreBehavior<D>(\n        vocalizationCallback: vocalizationCallback,\n        exploreModeTrigger: exploreModeTrigger,\n        minimumWidth: minimumWidth,\n        exploreModeEnabledAnnouncement: exploreModeEnabledAnnouncement,\n        exploreModeDisabledAnnouncement: exploreModeDisabledAnnouncement);\n  }\n\n  @override\n  void updateCommonBehavior(common.ChartBehavior commonBehavior) {}\n\n  @override\n  String get role => 'DomainA11yExplore-${exploreModeTrigger}';\n\n  @override\n  bool operator ==(Object o) =>\n      o is DomainA11yExploreBehavior &&\n      vocalizationCallback == o.vocalizationCallback &&\n      exploreModeTrigger == o.exploreModeTrigger &&\n      minimumWidth == o.minimumWidth &&\n      exploreModeEnabledAnnouncement == o.exploreModeEnabledAnnouncement &&\n      exploreModeDisabledAnnouncement == o.exploreModeDisabledAnnouncement;\n\n  @override\n  int get hashCode {\n    return hashValues(minimumWidth, vocalizationCallback, exploreModeTrigger,\n        exploreModeEnabledAnnouncement, exploreModeDisabledAnnouncement);\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_flutter/lib/src/behaviors/calculation/percent_injector.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'package:charts_common/common.dart' as common\n    show ChartBehavior, PercentInjector, PercentInjectorTotalType;\nimport 'package:meta/meta.dart' show immutable;\n\nimport '../chart_behavior.dart' show ChartBehavior, GestureType;\n\n/// Chart behavior that can inject series or domain percentages into each datum.\n///\n/// [totalType] configures the type of total to be calculated.\n///\n/// The measure values of each datum will be replaced by the percent of the\n/// total measure value that each represents. The \"raw\" measure accessor\n/// function on [MutableSeries] can still be used to get the original values.\n///\n/// Note that the results for measureLowerBound and measureUpperBound are not\n/// currently well defined when converted into percentage values. This behavior\n/// will replace them as percents to prevent bad axis results, but no effort is\n/// made to bound them to within a \"0 to 100%\" data range.\n///\n/// Note that if the chart has a [Legend] that is capable of hiding series data,\n/// then this behavior must be added after the [Legend] to ensure that it\n/// calculates values after series have been potentially removed from the list.\n@immutable\nclass PercentInjector<D> extends ChartBehavior<D> {\n  final desiredGestures = new Set<GestureType>();\n\n  /// The type of data total to be calculated.\n  final common.PercentInjectorTotalType totalType;\n\n  /// Constructs a [PercentInjector].\n  ///\n  /// [totalType] configures the type of data total to be calculated.\n  PercentInjector({this.totalType = common.PercentInjectorTotalType.domain});\n\n  @override\n  common.PercentInjector<D> createCommonBehavior() =>\n      new common.PercentInjector<D>(totalType: totalType);\n\n  @override\n  void updateCommonBehavior(common.ChartBehavior commonBehavior) {}\n\n  @override\n  String get role => 'PercentInjector';\n\n  @override\n  bool operator ==(Object o) {\n    return o is PercentInjector && totalType == o.totalType;\n  }\n\n  @override\n  int get hashCode => totalType.hashCode;\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_flutter/lib/src/behaviors/chart_behavior.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math' show Rectangle;\nimport 'package:charts_common/common.dart' as common\n    show\n        BehaviorPosition,\n        InsideJustification,\n        OutsideJustification,\n        ChartBehavior;\nimport 'package:meta/meta.dart' show immutable;\nimport 'package:flutter/widgets.dart' show BuildContext, Widget;\n\nimport '../base_chart_state.dart' show BaseChartState;\n\n/// Flutter wrapper for chart behaviors.\n@immutable\nabstract class ChartBehavior<D> {\n  Set<GestureType> get desiredGestures;\n\n  common.ChartBehavior<D> createCommonBehavior();\n\n  void updateCommonBehavior(common.ChartBehavior<D> commonBehavior);\n\n  String get role;\n}\n\n/// A chart behavior that depends on Flutter [State].\nabstract class ChartStateBehavior<B extends common.ChartBehavior> {\n  set chartState(BaseChartState chartState);\n}\n\n/// A chart behavior that can build a Flutter [Widget].\nabstract class BuildableBehavior<B extends common.ChartBehavior> {\n  /// Builds a [Widget] based on the information passed in.\n  ///\n  /// [context] Flutter build context for extracting inherited properties such\n  /// as Directionality.\n  Widget build(BuildContext context);\n\n  /// The position on the widget.\n  common.BehaviorPosition get position;\n\n  /// Justification of the widget, if [position] is top, bottom, start, or end.\n  common.OutsideJustification get outsideJustification;\n\n  /// Justification of the widget if [position] is [common.BehaviorPosition.inside].\n  common.InsideJustification get insideJustification;\n\n  /// Chart's draw area bounds are used for positioning.\n  Rectangle<int>? get drawAreaBounds;\n}\n\n/// Types of gestures accepted by a chart.\nenum GestureType {\n  onLongPress,\n  onTap,\n  onHover,\n  onDrag,\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_flutter/lib/src/behaviors/chart_title/chart_title.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'package:charts_common/common.dart' as common\n    show\n        BehaviorPosition,\n        ChartBehavior,\n        ChartTitle,\n        ChartTitleDirection,\n        MaxWidthStrategy,\n        OutsideJustification,\n        TextStyleSpec;\nimport 'package:flutter/widgets.dart' show hashValues;\nimport 'package:meta/meta.dart' show immutable;\n\nimport '../chart_behavior.dart' show ChartBehavior, GestureType;\n\n/// Chart behavior that adds a ChartTitle widget to a chart.\n@immutable\nclass ChartTitle<D> extends ChartBehavior<D> {\n  final desiredGestures = new Set<GestureType>();\n\n  final common.BehaviorPosition? behaviorPosition;\n\n  /// Minimum size of the legend component. Optional.\n  ///\n  /// If the legend is positioned in the top or bottom margin, then this\n  /// configures the legend's height. If positioned in the start or end\n  /// position, this configures the legend's width.\n  final int? layoutMinSize;\n\n  /// Preferred size of the legend component. Defaults to 0.\n  ///\n  /// If the legend is positioned in the top or bottom margin, then this\n  /// configures the legend's height. If positioned in the start or end\n  /// position, this configures the legend's width.\n  final int? layoutPreferredSize;\n\n  /// Strategy for handling title text that is too large to fit. Defaults to\n  /// truncating the text with ellipses.\n  final common.MaxWidthStrategy? maxWidthStrategy;\n\n  /// Primary text for the title.\n  final String title;\n\n  /// Direction of the chart title text.\n  ///\n  /// This defaults to horizontal for a title in the top or bottom\n  /// [behaviorPosition], or vertical for start or end [behaviorPosition].\n  final common.ChartTitleDirection? titleDirection;\n\n  /// Justification of the title text if it is positioned outside of the draw\n  /// area.\n  final common.OutsideJustification? titleOutsideJustification;\n\n  /// Space between the title and sub-title text, if defined.\n  ///\n  /// This padding is not used if no sub-title is provided.\n  final int? titlePadding;\n\n  /// Style of the [title] text.\n  final common.TextStyleSpec? titleStyleSpec;\n\n  /// Secondary text for the sub-title.\n  ///\n  /// [subTitle] is rendered on a second line below the [title], and may be\n  /// styled differently.\n  final String? subTitle;\n\n  /// Style of the [subTitle] text.\n  final common.TextStyleSpec? subTitleStyleSpec;\n\n  /// Space between the \"inside\" of the chart, and the title behavior itself.\n  ///\n  /// This padding is applied to all the edge of the title that is in the\n  /// direction of the draw area. For a top positioned title, this is applied\n  /// to the bottom edge. [outerPadding] is applied to the top, left, and right\n  /// edges.\n  ///\n  /// If a sub-title is defined, this is the space between the sub-title text\n  /// and the inside of the chart. Otherwise, it is the space between the title\n  /// text and the inside of chart.\n  final int? innerPadding;\n\n  /// Space between the \"outside\" of the chart, and the title behavior itself.\n  ///\n  /// This padding is applied to all 3 edges of the title that are not in the\n  /// direction of the draw area. For a top positioned title, this is applied\n  /// to the top, left, and right edges. [innerPadding] is applied to the\n  /// bottom edge.\n  final int? outerPadding;\n\n  /// Constructs a [ChartTitle].\n  ///\n  /// [title] primary text for the title.\n  ///\n  /// [behaviorPosition] layout position for the title. Defaults to the top of\n  /// the chart.\n  ///\n  /// [innerPadding] space between the \"inside\" of the chart, and the title\n  /// behavior itself.\n  ///\n  /// [maxWidthStrategy] strategy for handling title text that is too large to\n  /// fit. Defaults to  truncating the text with ellipses.\n  ///\n  /// [titleDirection] direction of the chart title text.\n  ///\n  /// [titleOutsideJustification] Justification of the title text if it is\n  /// positioned outside of the draw. Defaults to the middle of the margin area.\n  ///\n  /// [titlePadding] space between the title and sub-title text, if defined.\n  ///\n  /// [titleStyleSpec] style of the [title] text.\n  ///\n  /// [subTitle] secondary text for the sub-title. Optional.\n  ///\n  /// [subTitleStyleSpec] style of the [subTitle] text.\n  ChartTitle(\n    this.title, {\n    this.behaviorPosition,\n    this.innerPadding,\n    this.layoutMinSize,\n    this.layoutPreferredSize,\n    this.outerPadding,\n    this.maxWidthStrategy,\n    this.titleDirection,\n    this.titleOutsideJustification,\n    this.titlePadding,\n    this.titleStyleSpec,\n    this.subTitle,\n    this.subTitleStyleSpec,\n  });\n\n  @override\n  common.ChartTitle<D> createCommonBehavior() => new common.ChartTitle<D>(title,\n      behaviorPosition: behaviorPosition,\n      innerPadding: innerPadding,\n      layoutMinSize: layoutMinSize,\n      layoutPreferredSize: layoutPreferredSize,\n      outerPadding: outerPadding,\n      maxWidthStrategy: maxWidthStrategy,\n      titleDirection: titleDirection,\n      titleOutsideJustification: titleOutsideJustification,\n      titlePadding: titlePadding,\n      titleStyleSpec: titleStyleSpec,\n      subTitle: subTitle,\n      subTitleStyleSpec: subTitleStyleSpec);\n\n  @override\n  void updateCommonBehavior(common.ChartBehavior commonBehavior) {}\n\n  @override\n  String get role => 'ChartTitle-${behaviorPosition.toString()}';\n\n  @override\n  bool operator ==(Object o) {\n    return o is ChartTitle &&\n        behaviorPosition == o.behaviorPosition &&\n        layoutMinSize == o.layoutMinSize &&\n        layoutPreferredSize == o.layoutPreferredSize &&\n        maxWidthStrategy == o.maxWidthStrategy &&\n        title == o.title &&\n        titleDirection == o.titleDirection &&\n        titleOutsideJustification == o.titleOutsideJustification &&\n        titleStyleSpec == o.titleStyleSpec &&\n        subTitle == o.subTitle &&\n        subTitleStyleSpec == o.subTitleStyleSpec &&\n        innerPadding == o.innerPadding &&\n        titlePadding == o.titlePadding &&\n        outerPadding == o.outerPadding;\n  }\n\n  @override\n  int get hashCode {\n    return hashValues(\n        behaviorPosition,\n        layoutMinSize,\n        layoutPreferredSize,\n        maxWidthStrategy,\n        title,\n        titleDirection,\n        titleOutsideJustification,\n        titleStyleSpec,\n        subTitle,\n        subTitleStyleSpec,\n        innerPadding,\n        titlePadding,\n        outerPadding);\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_flutter/lib/src/behaviors/domain_highlighter.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'package:charts_common/common.dart' as common\n    show ChartBehavior, DomainHighlighter, SelectionModelType;\n\nimport 'package:meta/meta.dart' show immutable;\n\nimport 'chart_behavior.dart' show ChartBehavior, GestureType;\n\n/// Chart behavior that monitors the specified [SelectionModel] and darkens the\n/// color for selected data.\n///\n/// This is typically used for bars and pies to highlight segments.\n///\n/// It is used in combination with SelectNearest to update the selection model\n/// and expand selection out to the domain value.\n@immutable\nclass DomainHighlighter<D> extends ChartBehavior<D> {\n  final desiredGestures = new Set<GestureType>();\n\n  final common.SelectionModelType selectionModelType;\n\n  DomainHighlighter([this.selectionModelType = common.SelectionModelType.info]);\n\n  @override\n  common.DomainHighlighter<D> createCommonBehavior() =>\n      new common.DomainHighlighter<D>(selectionModelType);\n\n  @override\n  void updateCommonBehavior(common.ChartBehavior commonBehavior) {}\n\n  @override\n  String get role => 'domainHighlight-${selectionModelType.toString()}';\n\n  @override\n  bool operator ==(Object o) =>\n      o is DomainHighlighter && selectionModelType == o.selectionModelType;\n\n  @override\n  int get hashCode => selectionModelType.hashCode;\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_flutter/lib/src/behaviors/initial_selection.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'package:collection/collection.dart' show ListEquality;\n\nimport 'package:charts_common/common.dart' as common\n    show ChartBehavior, InitialSelection, SeriesDatumConfig, SelectionModelType;\n\nimport 'package:meta/meta.dart' show immutable;\n\nimport 'chart_behavior.dart' show ChartBehavior, GestureType;\n\n/// Chart behavior that sets the initial selection for a [selectionModelType].\n@immutable\nclass InitialSelection<D> extends ChartBehavior<D> {\n  final desiredGestures = new Set<GestureType>();\n\n  final common.SelectionModelType selectionModelType;\n  final List<String>? selectedSeriesConfig;\n  final List<common.SeriesDatumConfig<D>>? selectedDataConfig;\n\n  InitialSelection(\n      {this.selectionModelType = common.SelectionModelType.info,\n      this.selectedSeriesConfig,\n      this.selectedDataConfig});\n\n  @override\n  common.InitialSelection<D> createCommonBehavior() =>\n      new common.InitialSelection<D>(\n          selectionModelType: selectionModelType,\n          selectedDataConfig: selectedDataConfig,\n          selectedSeriesConfig: selectedSeriesConfig);\n\n  @override\n  void updateCommonBehavior(common.ChartBehavior commonBehavior) {}\n\n  @override\n  String get role => 'InitialSelection-${selectionModelType.toString()}';\n\n  @override\n  bool operator ==(Object o) {\n    return o is InitialSelection &&\n        selectionModelType == o.selectionModelType &&\n        new ListEquality()\n            .equals(selectedSeriesConfig, o.selectedSeriesConfig) &&\n        new ListEquality().equals(selectedDataConfig, o.selectedDataConfig);\n  }\n\n  @override\n  int get hashCode {\n    int hashcode = selectionModelType.hashCode;\n    hashcode = hashcode * 37 + (selectedSeriesConfig?.hashCode ?? 0);\n    hashcode = hashcode * 37 + (selectedDataConfig?.hashCode ?? 0);\n    return hashcode;\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_flutter/lib/src/behaviors/legend/datum_legend.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'package:charts_common/common.dart' as common\n    show\n        BehaviorPosition,\n        ChartBehavior,\n        DatumLegend,\n        InsideJustification,\n        LegendEntry,\n        MeasureFormatter,\n        LegendDefaultMeasure,\n        OutsideJustification,\n        SelectionModelType,\n        TextStyleSpec;\nimport 'package:flutter/widgets.dart'\n    show BuildContext, EdgeInsets, Widget, hashValues;\nimport 'package:meta/meta.dart' show immutable;\nimport '../../chart_container.dart' show ChartContainerRenderObject;\nimport '../chart_behavior.dart'\n    show BuildableBehavior, ChartBehavior, GestureType;\nimport 'legend.dart' show TappableLegend;\nimport 'legend_content_builder.dart'\n    show LegendContentBuilder, TabularLegendContentBuilder;\nimport 'legend_layout.dart' show TabularLegendLayout;\n\n/// Datum legend behavior for charts.\n///\n/// By default this behavior creates one legend entry per datum in the first\n/// series rendered on the chart.\n@immutable\nclass DatumLegend<D> extends ChartBehavior<D> {\n  static const defaultBehaviorPosition = common.BehaviorPosition.top;\n  static const defaultOutsideJustification =\n      common.OutsideJustification.startDrawArea;\n  static const defaultInsideJustification = common.InsideJustification.topStart;\n\n  final desiredGestures = new Set<GestureType>();\n\n  final common.SelectionModelType? selectionModelType;\n\n  /// Builder for creating custom legend content.\n  final LegendContentBuilder contentBuilder;\n\n  /// Position of the legend relative to the chart.\n  final common.BehaviorPosition position;\n\n  /// Justification of the legend relative to the chart\n  final common.OutsideJustification outsideJustification;\n  final common.InsideJustification insideJustification;\n\n  /// Whether or not the legend should show measures.\n  ///\n  /// By default this is false, measures are not shown. When set to true, the\n  /// default behavior is to show measure only if there is selected data.\n  /// Please set [legendDefaultMeasure] to something other than none to enable\n  /// showing measures when there is no selection.\n  ///\n  /// This flag is used by the [contentBuilder], so a custom content builder\n  /// has to choose if it wants to use this flag.\n  final bool showMeasures;\n\n  /// Option to show measures when selection is null.\n  ///\n  /// By default this is set to none, so no measures are shown when there is\n  /// no selection.\n  final common.LegendDefaultMeasure? legendDefaultMeasure;\n\n  /// Formatter for measure value(s) if the measures are shown on the legend.\n  final common.MeasureFormatter? measureFormatter;\n\n  /// Formatter for secondary measure value(s) if the measures are shown on the\n  /// legend and the series uses the secondary axis.\n  final common.MeasureFormatter? secondaryMeasureFormatter;\n\n  /// Styles for legend entry label text.\n  final common.TextStyleSpec? entryTextStyle;\n\n  static const defaultCellPadding = const EdgeInsets.all(8.0);\n\n  /// Create a new tabular layout legend.\n  ///\n  /// By default, the legend is place above the chart and horizontally aligned\n  /// to the start of the draw area.\n  ///\n  /// [position] the legend will be positioned relative to the chart. Default\n  /// position is top.\n  ///\n  /// [outsideJustification] justification of the legend relative to the chart\n  /// if the position is top, bottom, left, right. Default to start of the draw\n  /// area.\n  ///\n  /// [insideJustification] justification of the legend relative to the chart if\n  /// the position is inside. Default to top of the chart, start of draw area.\n  /// Start of draw area means left for LTR directionality, and right for RTL.\n  ///\n  /// [horizontalFirst] if true, legend entries will grow horizontally first\n  /// instead of vertically first. If the position is top, bottom, or inside,\n  /// this defaults to true. Otherwise false.\n  ///\n  /// [desiredMaxRows] the max rows to use before layout out items in a new\n  /// column. By default there is no limit. The max columns created is the\n  /// smaller of desiredMaxRows and number of legend entries.\n  ///\n  /// [desiredMaxColumns] the max columns to use before laying out items in a\n  /// new row. By default there is no limit. The max columns created is the\n  /// smaller of desiredMaxColumns and number of legend entries.\n  ///\n  /// [showMeasures] show measure values for each series.\n  ///\n  /// [legendDefaultMeasure] if measure should show when there is no selection.\n  /// This is set to none by default (only shows measure for selected data).\n  ///\n  /// [measureFormatter] formats measure value if measures are shown.\n  ///\n  /// [secondaryMeasureFormatter] formats measures if measures are shown for the\n  /// series that uses secondary measure axis.\n  factory DatumLegend({\n    common.BehaviorPosition? position,\n    common.OutsideJustification? outsideJustification,\n    common.InsideJustification? insideJustification,\n    bool? horizontalFirst,\n    int? desiredMaxRows,\n    int? desiredMaxColumns,\n    EdgeInsets? cellPadding,\n    bool? showMeasures,\n    common.LegendDefaultMeasure? legendDefaultMeasure,\n    common.MeasureFormatter? measureFormatter,\n    common.MeasureFormatter? secondaryMeasureFormatter,\n    common.TextStyleSpec? entryTextStyle,\n  }) {\n    // Set defaults if empty.\n    position ??= defaultBehaviorPosition;\n    outsideJustification ??= defaultOutsideJustification;\n    insideJustification ??= defaultInsideJustification;\n    cellPadding ??= defaultCellPadding;\n\n    // Set the tabular layout settings to match the position if it is not\n    // specified.\n    horizontalFirst ??= (position == common.BehaviorPosition.top ||\n        position == common.BehaviorPosition.bottom ||\n        position == common.BehaviorPosition.inside);\n    final layoutBuilder = horizontalFirst\n        ? new TabularLegendLayout.horizontalFirst(\n            desiredMaxColumns: desiredMaxColumns, cellPadding: cellPadding)\n        : new TabularLegendLayout.verticalFirst(\n            desiredMaxRows: desiredMaxRows, cellPadding: cellPadding);\n\n    return new DatumLegend._internal(\n        contentBuilder:\n            new TabularLegendContentBuilder(legendLayout: layoutBuilder),\n        selectionModelType: common.SelectionModelType.info,\n        position: position,\n        outsideJustification: outsideJustification,\n        insideJustification: insideJustification,\n        showMeasures: showMeasures ?? false,\n        legendDefaultMeasure:\n            legendDefaultMeasure ?? common.LegendDefaultMeasure.none,\n        measureFormatter: measureFormatter,\n        secondaryMeasureFormatter: secondaryMeasureFormatter,\n        entryTextStyle: entryTextStyle);\n  }\n\n  /// Create a legend with custom layout.\n  ///\n  /// By default, the legend is place above the chart and horizontally aligned\n  /// to the start of the draw area.\n  ///\n  /// [contentBuilder] builder for the custom layout.\n  ///\n  /// [position] the legend will be positioned relative to the chart. Default\n  /// position is top.\n  ///\n  /// [outsideJustification] justification of the legend relative to the chart\n  /// if the position is top, bottom, left, right. Default to start of the draw\n  /// area.\n  ///\n  /// [insideJustification] justification of the legend relative to the chart if\n  /// the position is inside. Default to top of the chart, start of draw area.\n  /// Start of draw area means left for LTR directionality, and right for RTL.\n  ///\n  /// [showMeasures] show measure values for each series.\n  ///\n  /// [legendDefaultMeasure] if measure should show when there is no selection.\n  /// This is set to none by default (only shows measure for selected data).\n  ///\n  /// [measureFormatter] formats measure value if measures are shown.\n  ///\n  /// [secondaryMeasureFormatter] formats measures if measures are shown for the\n  /// series that uses secondary measure axis.\n  factory DatumLegend.customLayout(\n    LegendContentBuilder contentBuilder, {\n    common.BehaviorPosition? position,\n    common.OutsideJustification? outsideJustification,\n    common.InsideJustification? insideJustification,\n    bool? showMeasures,\n    common.LegendDefaultMeasure? legendDefaultMeasure,\n    common.MeasureFormatter? measureFormatter,\n    common.MeasureFormatter? secondaryMeasureFormatter,\n    common.TextStyleSpec? entryTextStyle,\n  }) {\n    // Set defaults if empty.\n    position ??= defaultBehaviorPosition;\n    outsideJustification ??= defaultOutsideJustification;\n    insideJustification ??= defaultInsideJustification;\n\n    return new DatumLegend._internal(\n      contentBuilder: contentBuilder,\n      selectionModelType: common.SelectionModelType.info,\n      position: position,\n      outsideJustification: outsideJustification,\n      insideJustification: insideJustification,\n      showMeasures: showMeasures ?? false,\n      legendDefaultMeasure:\n          legendDefaultMeasure ?? common.LegendDefaultMeasure.none,\n      measureFormatter: measureFormatter,\n      secondaryMeasureFormatter: secondaryMeasureFormatter,\n      entryTextStyle: entryTextStyle,\n    );\n  }\n\n  DatumLegend._internal({\n    required this.contentBuilder,\n    this.selectionModelType,\n    required this.position,\n    required this.outsideJustification,\n    required this.insideJustification,\n    required this.showMeasures,\n    this.legendDefaultMeasure,\n    this.measureFormatter,\n    this.secondaryMeasureFormatter,\n    this.entryTextStyle,\n  });\n\n  @override\n  common.DatumLegend<D> createCommonBehavior() =>\n      new _FlutterDatumLegend<D>(this);\n\n  @override\n  void updateCommonBehavior(common.ChartBehavior commonBehavior) {\n    (commonBehavior as _FlutterDatumLegend).config = this;\n  }\n\n  /// All Legend behaviors get the same role ID, because you should only have\n  /// one legend on a chart.\n  @override\n  String get role => 'legend';\n\n  @override\n  bool operator ==(Object o) {\n    return o is DatumLegend &&\n        selectionModelType == o.selectionModelType &&\n        contentBuilder == o.contentBuilder &&\n        position == o.position &&\n        outsideJustification == o.outsideJustification &&\n        insideJustification == o.insideJustification &&\n        showMeasures == o.showMeasures &&\n        legendDefaultMeasure == o.legendDefaultMeasure &&\n        measureFormatter == o.measureFormatter &&\n        secondaryMeasureFormatter == o.secondaryMeasureFormatter &&\n        entryTextStyle == o.entryTextStyle;\n  }\n\n  @override\n  int get hashCode {\n    return hashValues(\n        selectionModelType,\n        contentBuilder,\n        position,\n        outsideJustification,\n        insideJustification,\n        showMeasures,\n        legendDefaultMeasure,\n        measureFormatter,\n        secondaryMeasureFormatter,\n        entryTextStyle);\n  }\n}\n\n/// Flutter specific wrapper on the common Legend for building content.\nclass _FlutterDatumLegend<D> extends common.DatumLegend<D>\n    implements BuildableBehavior, TappableLegend {\n  DatumLegend config;\n\n  _FlutterDatumLegend(this.config)\n      : super(\n          selectionModelType: config.selectionModelType,\n          measureFormatter: config.measureFormatter,\n          secondaryMeasureFormatter: config.secondaryMeasureFormatter,\n          legendDefaultMeasure: config.legendDefaultMeasure,\n        ) {\n    super.entryTextStyle = config.entryTextStyle;\n  }\n\n  @override\n  void updateLegend() {\n    (chartContext as ChartContainerRenderObject).requestRebuild();\n  }\n\n  @override\n  common.BehaviorPosition get position => config.position;\n\n  @override\n  common.OutsideJustification get outsideJustification =>\n      config.outsideJustification;\n\n  @override\n  common.InsideJustification get insideJustification =>\n      config.insideJustification;\n\n  @override\n  Widget build(BuildContext context) {\n    final hasSelection =\n        legendState.legendEntries.any((entry) => entry.isSelected);\n\n    // Show measures if [showMeasures] is true and there is a selection or if\n    // showing measures when there is no selection.\n    final showMeasures = config.showMeasures &&\n        (hasSelection ||\n            legendDefaultMeasure != common.LegendDefaultMeasure.none);\n\n    return config.contentBuilder\n        .build(context, legendState, this, showMeasures: showMeasures);\n  }\n\n  /// TODO: Maybe highlight the pie wedge.\n  @override\n  onLegendEntryTapUp(common.LegendEntry detail) {}\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_flutter/lib/src/behaviors/legend/legend.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'package:charts_common/common.dart' show LegendEntry, LegendTapHandling;\n\nabstract class TappableLegend<T, D> {\n  /// Delegates handling of legend entry clicks according to the configured\n  /// [LegendTapHandling] strategy.\n  onLegendEntryTapUp(LegendEntry detail);\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_flutter/lib/src/behaviors/legend/legend_content_builder.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'package:charts_common/common.dart' as common\n    show Legend, LegendState, SeriesLegend;\nimport 'package:flutter/widgets.dart' show BuildContext, hashValues, Widget;\nimport 'legend.dart';\nimport 'legend_entry_layout.dart';\nimport 'legend_layout.dart';\n\n/// Strategy for building a legend content widget.\nabstract class LegendContentBuilder {\n  const LegendContentBuilder();\n\n  Widget build(BuildContext context, common.LegendState legendState,\n      common.Legend legend,\n      {bool showMeasures});\n}\n\n/// Base strategy for building a legend content widget.\n///\n/// Each legend entry is passed to a [LegendLayout] strategy to create a widget\n/// for each legend entry. These widgets are then passed to a\n/// [LegendEntryLayout] strategy to create the legend widget.\nabstract class BaseLegendContentBuilder implements LegendContentBuilder {\n  /// Strategy for creating one widget or each legend entry.\n  LegendEntryLayout get legendEntryLayout;\n\n  /// Strategy for creating the legend content widget from a list of widgets.\n  ///\n  /// This is typically the list of widgets from legend entries.\n  LegendLayout get legendLayout;\n\n  @override\n  Widget build(BuildContext context, common.LegendState legendState,\n      common.Legend legend,\n      {bool showMeasures = false}) {\n    final entryWidgets = legendState.legendEntries.map((entry) {\n      var isHidden = false;\n      if (legend is common.SeriesLegend) {\n        isHidden = legend.isSeriesHidden(entry.series.id);\n      }\n\n      return legendEntryLayout.build(\n          context, entry, legend as TappableLegend, isHidden,\n          showMeasures: showMeasures);\n    }).toList();\n\n    return legendLayout.build(context, entryWidgets);\n  }\n}\n\n// TODO: Expose settings for tabular layout.\n/// Strategy that builds a tabular legend.\n///\n/// [legendEntryLayout] custom strategy for creating widgets for each legend\n/// entry.\n/// [legendLayout] custom strategy for creating legend widget from list of\n/// widgets that represent a legend entry.\nclass TabularLegendContentBuilder extends BaseLegendContentBuilder {\n  final LegendEntryLayout legendEntryLayout;\n  final LegendLayout legendLayout;\n\n  TabularLegendContentBuilder(\n      {LegendEntryLayout? legendEntryLayout, LegendLayout? legendLayout})\n      : this.legendEntryLayout =\n            legendEntryLayout ?? const SimpleLegendEntryLayout(),\n        this.legendLayout =\n            legendLayout ?? new TabularLegendLayout.horizontalFirst();\n\n  @override\n  bool operator ==(Object o) {\n    return o is TabularLegendContentBuilder &&\n        legendEntryLayout == o.legendEntryLayout &&\n        legendLayout == o.legendLayout;\n  }\n\n  @override\n  int get hashCode => hashValues(legendEntryLayout, legendLayout);\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_flutter/lib/src/behaviors/legend/legend_entry_layout.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'package:charts_common/common.dart' as common;\nimport 'package:charts_flutter/src/util/color.dart';\nimport 'package:flutter/widgets.dart';\nimport 'package:flutter/material.dart'\n    show GestureDetector, GestureTapUpCallback, TapUpDetails, Theme;\n\nimport '../../symbol_renderer.dart';\nimport 'legend.dart' show TappableLegend;\n\n/// Strategy for building one widget from one [common.LegendEntry].\nabstract class LegendEntryLayout {\n  Widget build(BuildContext context, common.LegendEntry legendEntry,\n      TappableLegend legend, bool isHidden,\n      {bool showMeasures});\n}\n\n/// Builds one legend entry as a row with symbol and label from the series.\n///\n/// If directionality from the chart context indicates RTL, the symbol is placed\n/// to the right of the text instead of the left of the text.\nclass SimpleLegendEntryLayout implements LegendEntryLayout {\n  const SimpleLegendEntryLayout();\n\n  Widget createSymbol(BuildContext context, common.LegendEntry legendEntry,\n      TappableLegend legend, bool isHidden) {\n    // TODO: Consider allowing scaling the size for the symbol.\n    // A custom symbol renderer can ignore this size and use their own.\n    final materialSymbolSize = new Size(12.0, 12.0);\n\n    final entryColor = legendEntry.color;\n    final color = entryColor == null ? null : ColorUtil.toDartColor(entryColor);\n\n    // Get the SymbolRendererBuilder wrapping a common.SymbolRenderer if needed.\n    final SymbolRendererBuilder symbolRendererBuilder =\n        legendEntry.symbolRenderer! is SymbolRendererBuilder\n            ? legendEntry.symbolRenderer! as SymbolRendererBuilder\n            : new SymbolRendererCanvas(\n                legendEntry.symbolRenderer!, legendEntry.dashPattern);\n\n    return new GestureDetector(\n        child: symbolRendererBuilder.build(\n          context,\n          size: materialSymbolSize,\n          color: color,\n          enabled: !isHidden,\n        ),\n        onTapUp: makeTapUpCallback(context, legendEntry, legend));\n  }\n\n  Widget createLabel(BuildContext context, common.LegendEntry legendEntry,\n      TappableLegend legend, bool isHidden) {\n    TextStyle style =\n        _convertTextStyle(isHidden, context, legendEntry.textStyle);\n\n    return new GestureDetector(\n        child: new Text(legendEntry.label, style: style),\n        onTapUp: makeTapUpCallback(context, legendEntry, legend));\n  }\n\n  Widget createMeasureValue(BuildContext context,\n      common.LegendEntry legendEntry, TappableLegend legend, bool isHidden) {\n    return new GestureDetector(\n        child: new Text(legendEntry.formattedValue!),\n        onTapUp: makeTapUpCallback(context, legendEntry, legend));\n  }\n\n  @override\n  Widget build(BuildContext context, common.LegendEntry legendEntry,\n      TappableLegend legend, bool isHidden,\n      {bool showMeasures = false}) {\n    final rowChildren = <Widget>[];\n\n    // TODO: Allow setting to configure the padding.\n    final padding = new EdgeInsets.only(right: 8.0); // Material default.\n    final symbol = createSymbol(context, legendEntry, legend, isHidden);\n    final label = createLabel(context, legendEntry, legend, isHidden);\n\n    final measure = showMeasures\n        ? createMeasureValue(context, legendEntry, legend, isHidden)\n        : null;\n\n    rowChildren.add(symbol);\n    rowChildren.add(new Container(padding: padding));\n    rowChildren.add(label);\n    if (measure != null) {\n      rowChildren.add(new Container(padding: padding));\n      rowChildren.add(measure);\n    }\n\n    // Row automatically reverses the content if Directionality is rtl.\n    return new Row(children: rowChildren);\n  }\n\n  GestureTapUpCallback makeTapUpCallback(BuildContext context,\n      common.LegendEntry legendEntry, TappableLegend legend) {\n    return (TapUpDetails d) {\n      legend.onLegendEntryTapUp(legendEntry);\n    };\n  }\n\n  bool operator ==(Object other) => other is SimpleLegendEntryLayout;\n\n  int get hashCode {\n    return this.runtimeType.hashCode;\n  }\n\n  /// Convert the charts common TextStlyeSpec into a standard TextStyle, while\n  /// reducing the color opacity to 26% if the entry is hidden.\n  ///\n  /// For non-specified values, override the hidden text color to use the body 1\n  /// theme, but allow other properties of [Text] to be inherited.\n  TextStyle _convertTextStyle(\n      bool isHidden, BuildContext context, common.TextStyleSpec? textStyle) {\n    Color? color = textStyle?.color != null\n        ? ColorUtil.toDartColor(textStyle!.color!)\n        : null;\n    if (isHidden) {\n      // Use a default color for hidden legend entries if none is provided.\n      color ??= Theme.of(context).textTheme.bodyText2!.color;\n      color = color!.withOpacity(0.26);\n    }\n\n    return new TextStyle(\n        inherit: true,\n        fontFamily: textStyle?.fontFamily,\n        fontSize: textStyle?.fontSize != null\n            ? textStyle!.fontSize!.toDouble()\n            : null,\n        color: color);\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_flutter/lib/src/behaviors/legend/legend_layout.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math' show min;\nimport 'package:flutter/rendering.dart';\nimport 'package:flutter/widgets.dart';\n\n/// Strategy for building legend from legend entry widgets.\nabstract class LegendLayout {\n  Widget build(BuildContext context, List<Widget> legendEntryWidgets);\n}\n\n/// Layout legend entries in tabular format.\nclass TabularLegendLayout implements LegendLayout {\n  /// No limit for max rows or max columns.\n  static const _noLimit = -1;\n\n  /// Default EdgeInsets for padding rows to the max column count\n  static const defaultCellPadding = const EdgeInsets.all(8.0);\n\n  final bool isHorizontalFirst;\n  final int desiredMaxRows;\n  final int desiredMaxColumns;\n  final EdgeInsets? cellPadding;\n\n  TabularLegendLayout._internal(\n      {required this.isHorizontalFirst,\n      required this.desiredMaxRows,\n      required this.desiredMaxColumns,\n      this.cellPadding});\n\n  /// Layout horizontally until columns exceed [desiredMaxColumns].\n  ///\n  /// [desiredMaxColumns] the max columns to use before laying out items in a\n  /// new row. By default there is no limit. The max columns created is the\n  /// smaller of desiredMaxColumns and number of legend entries.\n  ///\n  /// [cellPadding] the [EdgeInsets] for each widget.\n  factory TabularLegendLayout.horizontalFirst({\n    int? desiredMaxColumns,\n    EdgeInsets? cellPadding,\n  }) {\n    return new TabularLegendLayout._internal(\n      isHorizontalFirst: true,\n      desiredMaxRows: _noLimit,\n      desiredMaxColumns: desiredMaxColumns ?? _noLimit,\n      cellPadding: cellPadding,\n    );\n  }\n\n  /// Layout vertically, until rows exceed [desiredMaxRows].\n  ///\n  /// [desiredMaxRows] the max rows to use before layout out items in a new\n  /// column. By default there is no limit. The max columns created is the\n  /// smaller of desiredMaxRows and number of legend entries.\n  ///\n  /// [cellPadding] the [EdgeInsets] for each widget.\n  factory TabularLegendLayout.verticalFirst({\n    int? desiredMaxRows,\n    EdgeInsets? cellPadding,\n  }) {\n    return new TabularLegendLayout._internal(\n      isHorizontalFirst: false,\n      desiredMaxRows: desiredMaxRows ?? _noLimit,\n      desiredMaxColumns: _noLimit,\n      cellPadding: cellPadding,\n    );\n  }\n\n  @override\n  Widget build(BuildContext context, List<Widget> legendEntries) {\n    final paddedLegendEntries = ((cellPadding == null)\n        ? legendEntries\n        : legendEntries\n            .map((entry) => new Padding(padding: cellPadding!, child: entry))\n            .toList());\n\n    return isHorizontalFirst\n        ? _buildHorizontalFirst(paddedLegendEntries)\n        : _buildVerticalFirst(paddedLegendEntries);\n  }\n\n  @override\n  bool operator ==(o) =>\n      o is TabularLegendLayout &&\n      desiredMaxRows == o.desiredMaxRows &&\n      desiredMaxColumns == o.desiredMaxColumns &&\n      isHorizontalFirst == o.isHorizontalFirst &&\n      cellPadding == o.cellPadding;\n\n  @override\n  int get hashCode => hashValues(\n      desiredMaxRows, desiredMaxColumns, isHorizontalFirst, cellPadding);\n\n  Widget _buildHorizontalFirst(List<Widget> legendEntries) {\n    final maxColumns = (desiredMaxColumns == _noLimit)\n        ? legendEntries.length\n        : min(legendEntries.length, desiredMaxColumns);\n\n    final rows = <TableRow>[];\n    for (var i = 0; i < legendEntries.length; i += maxColumns) {\n      rows.add(new TableRow(\n          children: legendEntries\n              .sublist(i, min(i + maxColumns, legendEntries.length))\n              .toList()));\n    }\n\n    return _buildTableFromRows(rows);\n  }\n\n  Widget _buildVerticalFirst(List<Widget> legendEntries) {\n    final maxRows = (desiredMaxRows == _noLimit)\n        ? legendEntries.length\n        : min(legendEntries.length, desiredMaxRows);\n\n    final rows =\n        new List.generate(maxRows, (_) => new TableRow(children: <Widget>[]));\n    for (var i = 0; i < legendEntries.length; i++) {\n      rows[i % maxRows].children!.add(legendEntries[i]);\n    }\n\n    return _buildTableFromRows(rows);\n  }\n\n  Table _buildTableFromRows(List<TableRow> rows) {\n    final padWidget = Padding(padding: cellPadding ?? defaultCellPadding);\n\n    // Pad rows to the max column count, because each TableRow in a table is\n    // required to have the same number of children.\n    final columnCount = rows\n        .map((r) => r.children!.length)\n        .fold<int>(0, (max, current) => (current > max) ? current : max);\n\n    for (var i = 0; i < rows.length; i++) {\n      final rowChildren = rows[i].children;\n      final padCount = columnCount - rowChildren!.length;\n      if (padCount > 0) {\n        rowChildren\n            .addAll(new Iterable<Padding>.generate(padCount, (_) => padWidget));\n      }\n    }\n\n    // TODO: Investigate other means of creating the tabular legend\n    // Sizing the column width using [IntrinsicColumnWidth] is expensive per\n    // Flutter's documentation, but has to be used if the table is desired to\n    // have a width that is tight on each column.\n    return new Table(\n        children: rows, defaultColumnWidth: new IntrinsicColumnWidth());\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_flutter/lib/src/behaviors/legend/series_legend.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'package:charts_common/common.dart' as common\n    show\n        BehaviorPosition,\n        ChartBehavior,\n        InsideJustification,\n        LegendEntry,\n        LegendTapHandling,\n        MeasureFormatter,\n        LegendDefaultMeasure,\n        OutsideJustification,\n        SeriesLegend,\n        SelectionModelType,\n        TextStyleSpec;\nimport 'package:collection/collection.dart' show ListEquality;\nimport 'package:flutter/widgets.dart'\n    show BuildContext, EdgeInsets, Widget, hashValues;\nimport 'package:meta/meta.dart' show immutable;\nimport '../../chart_container.dart' show ChartContainerRenderObject;\nimport '../chart_behavior.dart'\n    show BuildableBehavior, ChartBehavior, GestureType;\nimport 'legend.dart' show TappableLegend;\nimport 'legend_content_builder.dart'\n    show LegendContentBuilder, TabularLegendContentBuilder;\nimport 'legend_layout.dart' show TabularLegendLayout;\n\n/// Series legend behavior for charts.\n@immutable\nclass SeriesLegend<D> extends ChartBehavior<D> {\n  static const defaultBehaviorPosition = common.BehaviorPosition.top;\n  static const defaultOutsideJustification =\n      common.OutsideJustification.startDrawArea;\n  static const defaultInsideJustification = common.InsideJustification.topStart;\n\n  final desiredGestures = new Set<GestureType>();\n\n  final common.SelectionModelType? selectionModelType;\n\n  /// Builder for creating custom legend content.\n  final LegendContentBuilder contentBuilder;\n\n  /// Position of the legend relative to the chart.\n  final common.BehaviorPosition position;\n\n  /// Justification of the legend relative to the chart\n  final common.OutsideJustification outsideJustification;\n  final common.InsideJustification insideJustification;\n\n  /// Whether or not the legend should show measures.\n  ///\n  /// By default this is false, measures are not shown. When set to true, the\n  /// default behavior is to show measure only if there is selected data.\n  /// Please set [legendDefaultMeasure] to something other than none to enable\n  /// showing measures when there is no selection.\n  ///\n  /// This flag is used by the [contentBuilder], so a custom content builder\n  /// has to choose if it wants to use this flag.\n  final bool showMeasures;\n\n  /// Option to show measures when selection is null.\n  ///\n  /// By default this is set to none, so no measures are shown when there is\n  /// no selection.\n  final common.LegendDefaultMeasure? legendDefaultMeasure;\n\n  /// Formatter for measure value(s) if the measures are shown on the legend.\n  final common.MeasureFormatter? measureFormatter;\n\n  /// Formatter for secondary measure value(s) if the measures are shown on the\n  /// legend and the series uses the secondary axis.\n  final common.MeasureFormatter? secondaryMeasureFormatter;\n\n  /// Styles for legend entry label text.\n  final common.TextStyleSpec? entryTextStyle;\n\n  static const defaultCellPadding = const EdgeInsets.all(8.0);\n\n  final List<String>? defaultHiddenSeries;\n\n  /// Create a new tabular layout legend.\n  ///\n  /// By default, the legend is place above the chart and horizontally aligned\n  /// to the start of the draw area.\n  ///\n  /// [position] the legend will be positioned relative to the chart. Default\n  /// position is top.\n  ///\n  /// [outsideJustification] justification of the legend relative to the chart\n  /// if the position is top, bottom, left, right. Default to start of the draw\n  /// area.\n  ///\n  /// [insideJustification] justification of the legend relative to the chart if\n  /// the position is inside. Default to top of the chart, start of draw area.\n  /// Start of draw area means left for LTR directionality, and right for RTL.\n  ///\n  /// [horizontalFirst] if true, legend entries will grow horizontally first\n  /// instead of vertically first. If the position is top, bottom, or inside,\n  /// this defaults to true. Otherwise false.\n  ///\n  /// [desiredMaxRows] the max rows to use before layout out items in a new\n  /// column. By default there is no limit. The max columns created is the\n  /// smaller of desiredMaxRows and number of legend entries.\n  ///\n  /// [desiredMaxColumns] the max columns to use before laying out items in a\n  /// new row. By default there is no limit. The max columns created is the\n  /// smaller of desiredMaxColumns and number of legend entries.\n  ///\n  /// [defaultHiddenSeries] lists the IDs of series that should be hidden on\n  /// first chart draw.\n  ///\n  /// [showMeasures] show measure values for each series.\n  ///\n  /// [legendDefaultMeasure] if measure should show when there is no selection.\n  /// This is set to none by default (only shows measure for selected data).\n  ///\n  /// [measureFormatter] formats measure value if measures are shown.\n  ///\n  /// [secondaryMeasureFormatter] formats measures if measures are shown for the\n  /// series that uses secondary measure axis.\n  factory SeriesLegend({\n    common.BehaviorPosition? position,\n    common.OutsideJustification? outsideJustification,\n    common.InsideJustification? insideJustification,\n    bool? horizontalFirst,\n    int? desiredMaxRows,\n    int? desiredMaxColumns,\n    EdgeInsets? cellPadding,\n    List<String>? defaultHiddenSeries,\n    bool? showMeasures,\n    common.LegendDefaultMeasure? legendDefaultMeasure,\n    common.MeasureFormatter? measureFormatter,\n    common.MeasureFormatter? secondaryMeasureFormatter,\n    common.TextStyleSpec? entryTextStyle,\n  }) {\n    // Set defaults if empty.\n    position ??= defaultBehaviorPosition;\n    outsideJustification ??= defaultOutsideJustification;\n    insideJustification ??= defaultInsideJustification;\n    cellPadding ??= defaultCellPadding;\n\n    // Set the tabular layout settings to match the position if it is not\n    // specified.\n    horizontalFirst ??= (position == common.BehaviorPosition.top ||\n        position == common.BehaviorPosition.bottom ||\n        position == common.BehaviorPosition.inside);\n    final layoutBuilder = horizontalFirst\n        ? new TabularLegendLayout.horizontalFirst(\n            desiredMaxColumns: desiredMaxColumns, cellPadding: cellPadding)\n        : new TabularLegendLayout.verticalFirst(\n            desiredMaxRows: desiredMaxRows, cellPadding: cellPadding);\n\n    return new SeriesLegend._internal(\n        contentBuilder:\n            new TabularLegendContentBuilder(legendLayout: layoutBuilder),\n        selectionModelType: common.SelectionModelType.info,\n        position: position,\n        outsideJustification: outsideJustification,\n        insideJustification: insideJustification,\n        defaultHiddenSeries: defaultHiddenSeries,\n        showMeasures: showMeasures ?? false,\n        legendDefaultMeasure:\n            legendDefaultMeasure ?? common.LegendDefaultMeasure.none,\n        measureFormatter: measureFormatter,\n        secondaryMeasureFormatter: secondaryMeasureFormatter,\n        entryTextStyle: entryTextStyle);\n  }\n\n  /// Create a legend with custom layout.\n  ///\n  /// By default, the legend is place above the chart and horizontally aligned\n  /// to the start of the draw area.\n  ///\n  /// [contentBuilder] builder for the custom layout.\n  ///\n  /// [position] the legend will be positioned relative to the chart. Default\n  /// position is top.\n  ///\n  /// [outsideJustification] justification of the legend relative to the chart\n  /// if the position is top, bottom, left, right. Default to start of the draw\n  /// area.\n  ///\n  /// [insideJustification] justification of the legend relative to the chart if\n  /// the position is inside. Default to top of the chart, start of draw area.\n  /// Start of draw area means left for LTR directionality, and right for RTL.\n  ///\n  /// [defaultHiddenSeries] lists the IDs of series that should be hidden on\n  /// first chart draw.\n  ///\n  /// [showMeasures] show measure values for each series.\n  ///\n  /// [legendDefaultMeasure] if measure should show when there is no selection.\n  /// This is set to none by default (only shows measure for selected data).\n  ///\n  /// [measureFormatter] formats measure value if measures are shown.\n  ///\n  /// [secondaryMeasureFormatter] formats measures if measures are shown for the\n  /// series that uses secondary measure axis.\n  factory SeriesLegend.customLayout(\n    LegendContentBuilder contentBuilder, {\n    common.BehaviorPosition? position,\n    common.OutsideJustification? outsideJustification,\n    common.InsideJustification? insideJustification,\n    List<String>? defaultHiddenSeries,\n    bool? showMeasures,\n    common.LegendDefaultMeasure? legendDefaultMeasure,\n    common.MeasureFormatter? measureFormatter,\n    common.MeasureFormatter? secondaryMeasureFormatter,\n    common.TextStyleSpec? entryTextStyle,\n  }) {\n    // Set defaults if empty.\n    position ??= defaultBehaviorPosition;\n    outsideJustification ??= defaultOutsideJustification;\n    insideJustification ??= defaultInsideJustification;\n\n    return new SeriesLegend._internal(\n      contentBuilder: contentBuilder,\n      selectionModelType: common.SelectionModelType.info,\n      position: position,\n      outsideJustification: outsideJustification,\n      insideJustification: insideJustification,\n      defaultHiddenSeries: defaultHiddenSeries,\n      showMeasures: showMeasures ?? false,\n      legendDefaultMeasure:\n          legendDefaultMeasure ?? common.LegendDefaultMeasure.none,\n      measureFormatter: measureFormatter,\n      secondaryMeasureFormatter: secondaryMeasureFormatter,\n      entryTextStyle: entryTextStyle,\n    );\n  }\n\n  SeriesLegend._internal({\n    required this.contentBuilder,\n    this.selectionModelType,\n    required this.position,\n    required this.outsideJustification,\n    required this.insideJustification,\n    this.defaultHiddenSeries,\n    required this.showMeasures,\n    this.legendDefaultMeasure,\n    this.measureFormatter,\n    this.secondaryMeasureFormatter,\n    this.entryTextStyle,\n  });\n\n  @override\n  common.SeriesLegend<D> createCommonBehavior() =>\n      new _FlutterSeriesLegend<D>(this);\n\n  @override\n  void updateCommonBehavior(common.ChartBehavior commonBehavior) {\n    (commonBehavior as _FlutterSeriesLegend).config = this;\n  }\n\n  /// All Legend behaviors get the same role ID, because you should only have\n  /// one legend on a chart.\n  @override\n  String get role => 'legend';\n\n  @override\n  bool operator ==(Object o) {\n    return o is SeriesLegend &&\n        selectionModelType == o.selectionModelType &&\n        contentBuilder == o.contentBuilder &&\n        position == o.position &&\n        outsideJustification == o.outsideJustification &&\n        insideJustification == o.insideJustification &&\n        new ListEquality().equals(defaultHiddenSeries, o.defaultHiddenSeries) &&\n        showMeasures == o.showMeasures &&\n        legendDefaultMeasure == o.legendDefaultMeasure &&\n        measureFormatter == o.measureFormatter &&\n        secondaryMeasureFormatter == o.secondaryMeasureFormatter &&\n        entryTextStyle == o.entryTextStyle;\n  }\n\n  @override\n  int get hashCode {\n    return hashValues(\n        selectionModelType,\n        contentBuilder,\n        position,\n        outsideJustification,\n        insideJustification,\n        defaultHiddenSeries,\n        showMeasures,\n        legendDefaultMeasure,\n        measureFormatter,\n        secondaryMeasureFormatter,\n        entryTextStyle);\n  }\n}\n\n/// Flutter specific wrapper on the common Legend for building content.\nclass _FlutterSeriesLegend<D> extends common.SeriesLegend<D>\n    implements BuildableBehavior, TappableLegend {\n  SeriesLegend config;\n\n  _FlutterSeriesLegend(this.config)\n      : super(\n          selectionModelType: config.selectionModelType,\n          measureFormatter: config.measureFormatter,\n          secondaryMeasureFormatter: config.secondaryMeasureFormatter,\n          legendDefaultMeasure: config.legendDefaultMeasure,\n        ) {\n    super.defaultHiddenSeries = config.defaultHiddenSeries;\n    super.entryTextStyle = config.entryTextStyle;\n  }\n\n  @override\n  void updateLegend() {\n    (chartContext as ChartContainerRenderObject).requestRebuild();\n  }\n\n  @override\n  common.BehaviorPosition get position => config.position;\n\n  @override\n  common.OutsideJustification get outsideJustification =>\n      config.outsideJustification;\n\n  @override\n  common.InsideJustification get insideJustification =>\n      config.insideJustification;\n\n  @override\n  Widget build(BuildContext context) {\n    final hasSelection = legendState.legendEntries != null &&\n        legendState.legendEntries.any((entry) => entry.isSelected);\n\n    // Show measures if [showMeasures] is true and there is a selection or if\n    // showing measures when there is no selection.\n    final showMeasures = config.showMeasures &&\n        (hasSelection ||\n            legendDefaultMeasure != common.LegendDefaultMeasure.none);\n\n    return config.contentBuilder\n        .build(context, legendState, this, showMeasures: showMeasures);\n  }\n\n  @override\n  onLegendEntryTapUp(common.LegendEntry detail) {\n    switch (legendTapHandling) {\n      case common.LegendTapHandling.hide:\n        _hideSeries(detail);\n        break;\n\n      case common.LegendTapHandling.none:\n      default:\n        break;\n    }\n  }\n\n  /// Handles tap events by hiding or un-hiding entries tapped in the legend.\n  ///\n  /// Tapping on a visible series in the legend will hide it. Tapping on a\n  /// hidden series will make it visible again.\n  void _hideSeries(common.LegendEntry detail) {\n    final seriesId = detail.series.id;\n\n    // Handle the event by toggling the hidden state of the target.\n    if (isSeriesHidden(seriesId)) {\n      showSeries(seriesId);\n    } else {\n      hideSeries(seriesId);\n    }\n\n    // Redraw the chart to actually hide hidden series.\n    chart.redraw(skipLayout: true, skipAnimation: false);\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_flutter/lib/src/behaviors/line_point_highlighter.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'package:collection/collection.dart' show ListEquality;\nimport 'package:charts_common/common.dart' as common\n    show\n        ChartBehavior,\n        LinePointHighlighter,\n        LinePointHighlighterFollowLineType,\n        SelectionModelType,\n        SymbolRenderer;\nimport 'package:flutter/widgets.dart' show hashValues;\nimport 'package:meta/meta.dart' show immutable;\n\nimport 'chart_behavior.dart' show ChartBehavior, GestureType;\n\n/// Chart behavior that monitors the specified [SelectionModel] and darkens the\n/// color for selected data.\n///\n/// This is typically used for bars and pies to highlight segments.\n///\n/// It is used in combination with SelectNearest to update the selection model\n/// and expand selection out to the domain value.\n@immutable\nclass LinePointHighlighter<D> extends ChartBehavior<D> {\n  final desiredGestures = new Set<GestureType>();\n\n  final common.SelectionModelType? selectionModelType;\n\n  /// Default radius of the dots if the series has no radius mapping function.\n  ///\n  /// When no radius mapping function is provided, this value will be used as\n  /// is. [radiusPaddingPx] will not be added to [defaultRadiusPx].\n  final double? defaultRadiusPx;\n\n  /// Additional radius value added to the radius of the selected data.\n  ///\n  /// This value is only used when the series has a radius mapping function\n  /// defined.\n  final double? radiusPaddingPx;\n\n  final common.LinePointHighlighterFollowLineType? showHorizontalFollowLine;\n\n  final common.LinePointHighlighterFollowLineType? showVerticalFollowLine;\n\n  /// The dash pattern to be used for drawing the line.\n  ///\n  /// To disable dash pattern (to draw a solid line), pass in an empty list.\n  /// This is because if dashPattern is null or not set, it defaults to [1,3].\n  final List<int>? dashPattern;\n\n  /// Whether or not follow lines should be drawn across the entire chart draw\n  /// area, or just from the axis to the point.\n  ///\n  /// When disabled, measure follow lines will be drawn from the primary measure\n  /// axis to the point. In RTL mode, this means from the right-hand axis. In\n  /// LTR mode, from the left-hand axis.\n  final bool? drawFollowLinesAcrossChart;\n\n  /// Renderer used to draw the highlighted points.\n  final common.SymbolRenderer? symbolRenderer;\n\n  LinePointHighlighter(\n      {this.selectionModelType,\n      this.defaultRadiusPx,\n      this.radiusPaddingPx,\n      this.showHorizontalFollowLine,\n      this.showVerticalFollowLine,\n      this.dashPattern,\n      this.drawFollowLinesAcrossChart,\n      this.symbolRenderer});\n\n  @override\n  common.LinePointHighlighter<D> createCommonBehavior() =>\n      new common.LinePointHighlighter<D>(\n        selectionModelType: selectionModelType,\n        defaultRadiusPx: defaultRadiusPx,\n        radiusPaddingPx: radiusPaddingPx,\n        showHorizontalFollowLine: showHorizontalFollowLine,\n        showVerticalFollowLine: showVerticalFollowLine,\n        dashPattern: dashPattern,\n        drawFollowLinesAcrossChart: drawFollowLinesAcrossChart,\n        symbolRenderer: symbolRenderer,\n      );\n\n  @override\n  void updateCommonBehavior(common.ChartBehavior<D> commonBehavior) {}\n\n  @override\n  String get role => 'LinePointHighlighter-${selectionModelType.toString()}';\n\n  @override\n  bool operator ==(Object o) {\n    return o is LinePointHighlighter &&\n        defaultRadiusPx == o.defaultRadiusPx &&\n        radiusPaddingPx == o.radiusPaddingPx &&\n        showHorizontalFollowLine == o.showHorizontalFollowLine &&\n        showVerticalFollowLine == o.showVerticalFollowLine &&\n        selectionModelType == o.selectionModelType &&\n        new ListEquality().equals(dashPattern, o.dashPattern) &&\n        drawFollowLinesAcrossChart == o.drawFollowLinesAcrossChart;\n  }\n\n  @override\n  int get hashCode {\n    return hashValues(\n      selectionModelType,\n      defaultRadiusPx,\n      radiusPaddingPx,\n      showHorizontalFollowLine,\n      showVerticalFollowLine,\n      dashPattern,\n      drawFollowLinesAcrossChart,\n    );\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_flutter/lib/src/behaviors/range_annotation.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'package:charts_common/common.dart' as common\n    show\n        AnnotationLabelAnchor,\n        AnnotationLabelDirection,\n        AnnotationLabelPosition,\n        AnnotationSegment,\n        ChartBehavior,\n        Color,\n        MaterialPalette,\n        RangeAnnotation,\n        TextStyleSpec;\nimport 'package:collection/collection.dart' show ListEquality;\nimport 'package:flutter/widgets.dart' show hashValues;\nimport 'package:meta/meta.dart' show immutable;\n\nimport 'chart_behavior.dart' show ChartBehavior, GestureType;\n\n/// Chart behavior that annotations domain ranges with a solid fill color.\n///\n/// The annotations will be drawn underneath series data and chart axes.\n///\n/// This is typically used for line charts to call out sections of the data\n/// range.\n@immutable\nclass RangeAnnotation<D> extends ChartBehavior<D> {\n  final desiredGestures = new Set<GestureType>();\n\n  /// List of annotations to render on the chart.\n  final List<common.AnnotationSegment<Object>> annotations;\n\n  /// Configures where to anchor annotation label text.\n  final common.AnnotationLabelAnchor? defaultLabelAnchor;\n\n  /// Direction of label text on the annotations.\n  final common.AnnotationLabelDirection? defaultLabelDirection;\n\n  /// Configures where to place labels relative to the annotation.\n  final common.AnnotationLabelPosition? defaultLabelPosition;\n\n  /// Configures the style of label text.\n  final common.TextStyleSpec? defaultLabelStyleSpec;\n\n  /// Default color for annotations.\n  final common.Color? defaultColor;\n\n  /// Whether or not the range of the axis should be extended to include the\n  /// annotation start and end values.\n  final bool? extendAxis;\n\n  /// Space before and after label text.\n  final int? labelPadding;\n\n  /// Configures the order in which the behavior should be painted.\n  /// This value should be relative to LayoutPaintViewOrder.rangeAnnotation.\n  /// (e.g. LayoutViewPaintOrder.rangeAnnotation + 1)\n  final int? layoutPaintOrder;\n\n  RangeAnnotation(this.annotations,\n      {common.Color? defaultColor,\n      this.defaultLabelAnchor,\n      this.defaultLabelDirection,\n      this.defaultLabelPosition,\n      this.defaultLabelStyleSpec,\n      this.extendAxis,\n      this.labelPadding,\n      this.layoutPaintOrder})\n      : this.defaultColor =\n            defaultColor ?? common.MaterialPalette.gray.shade100;\n\n  @override\n  common.RangeAnnotation<D> createCommonBehavior() =>\n      new common.RangeAnnotation<D>(annotations,\n          defaultColor: defaultColor,\n          defaultLabelAnchor: defaultLabelAnchor,\n          defaultLabelDirection: defaultLabelDirection,\n          defaultLabelPosition: defaultLabelPosition,\n          defaultLabelStyleSpec: defaultLabelStyleSpec,\n          extendAxis: extendAxis,\n          labelPadding: labelPadding,\n          layoutPaintOrder: layoutPaintOrder);\n\n  @override\n  void updateCommonBehavior(common.ChartBehavior commonBehavior) {}\n\n  @override\n  String get role => 'RangeAnnotation';\n\n  @override\n  bool operator ==(Object o) {\n    return o is RangeAnnotation &&\n        new ListEquality().equals(annotations, o.annotations) &&\n        defaultColor == o.defaultColor &&\n        extendAxis == o.extendAxis &&\n        defaultLabelAnchor == o.defaultLabelAnchor &&\n        defaultLabelDirection == o.defaultLabelDirection &&\n        defaultLabelPosition == o.defaultLabelPosition &&\n        defaultLabelStyleSpec == o.defaultLabelStyleSpec &&\n        labelPadding == o.labelPadding &&\n        layoutPaintOrder == o.layoutPaintOrder;\n  }\n\n  @override\n  int get hashCode => hashValues(\n      annotations,\n      defaultColor,\n      extendAxis,\n      defaultLabelAnchor,\n      defaultLabelDirection,\n      defaultLabelPosition,\n      defaultLabelStyleSpec,\n      labelPadding,\n      layoutPaintOrder);\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_flutter/lib/src/behaviors/select_nearest.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'package:charts_common/common.dart' as common\n    show\n        ChartBehavior,\n        SelectNearest,\n        SelectionMode,\n        SelectionModelType,\n        SelectionTrigger;\n\nimport 'package:meta/meta.dart' show immutable;\n\nimport 'chart_behavior.dart' show ChartBehavior, GestureType;\n\n/// Chart behavior that listens to the given eventTrigger and updates the\n/// specified [SelectionModel]. This is used to pair input events to behaviors\n/// that listen to selection changes.\n///\n/// Input event types:\n///   hover (default) - Mouse over/near data.\n///   tap - Mouse/Touch on/near data.\n///   pressHold - Mouse/Touch and drag across the data instead of panning.\n///   longPressHold - Mouse/Touch for a while in one place then drag across the data.\n///\n/// SelectionModels that can be updated:\n///   info - To view the details of the selected items (ie: hover for web).\n///   action - To select an item as an input, drill, or other selection.\n///\n/// Other options available\n///   selectionMode - Optional mode for expanding the selection beyond the\n///       nearest datum. Defaults to expandToDomain.\n///   selectClosestSeries - mark the series for the closest data point as\n///       selected. (Default: true)\n///\n/// You can add one SelectNearest for each model type that you are updating.\n/// Any previous SelectNearest behavior for that selection model will be\n/// removed.\n@immutable\nclass SelectNearest<D> extends ChartBehavior<D> {\n  final Set<GestureType> desiredGestures;\n\n  final common.SelectionModelType selectionModelType;\n  final common.SelectionTrigger eventTrigger;\n  final common.SelectionMode selectionMode;\n  final bool selectAcrossAllDrawAreaComponents;\n  final bool selectClosestSeries;\n  final int? maximumDomainDistancePx;\n\n  SelectNearest._internal(\n      {required this.selectionModelType,\n      this.selectionMode = common.SelectionMode.expandToDomain,\n      this.selectAcrossAllDrawAreaComponents = false,\n      this.selectClosestSeries = true,\n      required this.eventTrigger,\n      required this.desiredGestures,\n      this.maximumDomainDistancePx});\n\n  factory SelectNearest(\n      {common.SelectionModelType selectionModelType =\n          common.SelectionModelType.info,\n      common.SelectionMode selectionMode = common.SelectionMode.expandToDomain,\n      bool selectAcrossAllDrawAreaComponents = false,\n      bool selectClosestSeries = true,\n      common.SelectionTrigger eventTrigger = common.SelectionTrigger.tap,\n      int? maximumDomainDistancePx}) {\n    return new SelectNearest._internal(\n        selectionModelType: selectionModelType,\n        selectionMode: selectionMode,\n        selectAcrossAllDrawAreaComponents: selectAcrossAllDrawAreaComponents,\n        selectClosestSeries: selectClosestSeries,\n        eventTrigger: eventTrigger,\n        desiredGestures: SelectNearest._getDesiredGestures(eventTrigger),\n        maximumDomainDistancePx: maximumDomainDistancePx);\n  }\n\n  static Set<GestureType> _getDesiredGestures(\n      common.SelectionTrigger eventTrigger) {\n    final desiredGestures = new Set<GestureType>();\n    switch (eventTrigger) {\n      case common.SelectionTrigger.tap:\n        desiredGestures..add(GestureType.onTap);\n        break;\n      case common.SelectionTrigger.tapAndDrag:\n        desiredGestures..add(GestureType.onTap)..add(GestureType.onDrag);\n        break;\n      case common.SelectionTrigger.pressHold:\n      case common.SelectionTrigger.longPressHold:\n        desiredGestures\n          ..add(GestureType.onTap)\n          ..add(GestureType.onLongPress)\n          ..add(GestureType.onDrag);\n        break;\n      case common.SelectionTrigger.hover:\n      default:\n        desiredGestures..add(GestureType.onHover);\n        break;\n    }\n    return desiredGestures;\n  }\n\n  @override\n  common.SelectNearest<D> createCommonBehavior() {\n    return new common.SelectNearest<D>(\n        selectionModelType: selectionModelType,\n        eventTrigger: eventTrigger,\n        selectionMode: selectionMode,\n        selectClosestSeries: selectClosestSeries,\n        maximumDomainDistancePx: maximumDomainDistancePx);\n  }\n\n  @override\n  void updateCommonBehavior(common.ChartBehavior commonBehavior) {}\n\n  // TODO: Explore the performance impact of calculating this once\n  // at the constructor for this and common ChartBehaviors.\n  @override\n  String get role => 'SelectNearest-${selectionModelType.toString()}}';\n\n  bool operator ==(Object other) {\n    if (other is SelectNearest) {\n      return (selectionModelType == other.selectionModelType) &&\n          (eventTrigger == other.eventTrigger) &&\n          (selectionMode == other.selectionMode) &&\n          (selectClosestSeries == other.selectClosestSeries) &&\n          (maximumDomainDistancePx == other.maximumDomainDistancePx);\n    } else {\n      return false;\n    }\n  }\n\n  int get hashCode {\n    int hashcode = selectionModelType.hashCode;\n    hashcode = hashcode * 37 + eventTrigger.hashCode;\n    hashcode = hashcode * 37 + selectionMode.hashCode;\n    hashcode = hashcode * 37 + selectClosestSeries.hashCode;\n    hashcode = hashcode * 37 + maximumDomainDistancePx.hashCode;\n    return hashcode;\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_flutter/lib/src/behaviors/slider/slider.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math' show Rectangle;\nimport 'package:charts_common/common.dart' as common\n    show\n        ChartBehavior,\n        LayoutViewPaintOrder,\n        RectSymbolRenderer,\n        SelectionTrigger,\n        Slider,\n        SliderListenerCallback,\n        SliderStyle,\n        SymbolRenderer;\nimport 'package:flutter/widgets.dart' show hashValues;\nimport 'package:meta/meta.dart' show immutable;\n\nimport '../chart_behavior.dart' show ChartBehavior, GestureType;\n\n/// Chart behavior that adds a slider widget to a chart. When the slider is\n/// dropped after drag, it will report its domain position and nearest datum\n/// value. This behavior only supports charts that use continuous scales.\n///\n/// Input event types:\n///   tapAndDrag - Mouse/Touch on the handle and drag across the chart.\n///   pressHold - Mouse/Touch on the handle and drag across the chart instead of\n///       panning.\n///   longPressHold - Mouse/Touch for a while on the handle, then drag across\n///       the data.\n@immutable\nclass Slider<D> extends ChartBehavior<D> {\n  final Set<GestureType> desiredGestures;\n\n  /// Type of input event for the slider.\n  ///\n  /// Input event types:\n  ///   tapAndDrag - Mouse/Touch on the handle and drag across the chart.\n  ///   pressHold - Mouse/Touch on the handle and drag across the chart instead\n  ///       of panning.\n  ///   longPressHold - Mouse/Touch for a while on the handle, then drag across\n  ///       the data.\n  final common.SelectionTrigger eventTrigger;\n\n  /// The order to paint slider on the canvas.\n  ///\n  /// The smaller number is drawn first.  This value should be relative to\n  /// LayoutPaintViewOrder.slider (e.g. LayoutViewPaintOrder.slider + 1).\n  final int? layoutPaintOrder;\n\n  /// Initial domain position of the slider, in domain units.\n  final dynamic? initialDomainValue;\n\n  /// Callback function that will be called when the position of the slider\n  /// changes during a drag event.\n  ///\n  /// The callback will be given the current domain position of the slider.\n  final common.SliderListenerCallback? onChangeCallback;\n\n  /// Custom role ID for this slider\n  final String? roleId;\n\n  /// Whether or not the slider will snap onto the nearest datum (by domain\n  /// distance) when dragged.\n  final bool snapToDatum;\n\n  /// Color and size styles for the slider.\n  final common.SliderStyle? style;\n\n  /// Renderer for the handle. Defaults to a rectangle.\n  final common.SymbolRenderer? handleRenderer;\n\n  Slider._internal(\n      {required this.eventTrigger,\n      this.onChangeCallback,\n      this.initialDomainValue,\n      this.roleId,\n      required this.snapToDatum,\n      this.style,\n      this.handleRenderer,\n      required this.desiredGestures,\n      this.layoutPaintOrder});\n\n  /// Constructs a [Slider].\n  ///\n  /// [eventTrigger] sets the type of gesture handled by the slider.\n  ///\n  /// [handleRenderer] draws a handle for the slider. Defaults to a rectangle.\n  ///\n  /// [initialDomainValue] sets the initial position of the slider in domain\n  /// units. The default is the center of the chart.\n  ///\n  /// [onChangeCallback] will be called when the position of the slider\n  /// changes during a drag event.\n  ///\n  /// [snapToDatum] configures the slider to snap snap onto the nearest datum\n  /// (by domain distance) when dragged. By default, the slider can be\n  /// positioned anywhere along the domain axis.\n  ///\n  /// [style] configures the color and sizing of the slider line and handle.\n  ///\n  /// [layoutPaintOrder] configures the order in which the behavior should be\n  /// painted. This value should be relative to LayoutPaintViewOrder.slider.\n  /// (e.g. LayoutViewPaintOrder.slider + 1).\n  factory Slider(\n      {common.SelectionTrigger? eventTrigger,\n      common.SymbolRenderer? handleRenderer,\n      dynamic? initialDomainValue,\n      String? roleId,\n      common.SliderListenerCallback? onChangeCallback,\n      bool snapToDatum = false,\n      common.SliderStyle? style,\n      int layoutPaintOrder = common.LayoutViewPaintOrder.slider}) {\n    eventTrigger ??= common.SelectionTrigger.tapAndDrag;\n    handleRenderer ??= new common.RectSymbolRenderer();\n    // Default the handle size large enough to tap on a mobile device.\n    style ??= new common.SliderStyle(handleSize: Rectangle<int>(0, 0, 20, 30));\n    return new Slider._internal(\n        eventTrigger: eventTrigger,\n        handleRenderer: handleRenderer,\n        initialDomainValue: initialDomainValue,\n        onChangeCallback: onChangeCallback,\n        roleId: roleId,\n        snapToDatum: snapToDatum,\n        style: style,\n        desiredGestures: Slider._getDesiredGestures(eventTrigger),\n        layoutPaintOrder: layoutPaintOrder);\n  }\n\n  static Set<GestureType> _getDesiredGestures(\n      common.SelectionTrigger eventTrigger) {\n    final desiredGestures = new Set<GestureType>();\n    switch (eventTrigger) {\n      case common.SelectionTrigger.tapAndDrag:\n        desiredGestures..add(GestureType.onTap)..add(GestureType.onDrag);\n        break;\n      case common.SelectionTrigger.pressHold:\n      case common.SelectionTrigger.longPressHold:\n        desiredGestures\n          ..add(GestureType.onTap)\n          ..add(GestureType.onLongPress)\n          ..add(GestureType.onDrag);\n        break;\n      default:\n        throw new ArgumentError(\n            'Slider does not support the event trigger ' + '\"${eventTrigger}\"');\n    }\n    return desiredGestures;\n  }\n\n  @override\n  common.Slider<D> createCommonBehavior() => new common.Slider<D>(\n      eventTrigger: eventTrigger,\n      handleRenderer: handleRenderer,\n      initialDomainValue: initialDomainValue as D,\n      onChangeCallback: onChangeCallback,\n      roleId: roleId,\n      snapToDatum: snapToDatum,\n      style: style);\n\n  @override\n  void updateCommonBehavior(common.ChartBehavior<D> commonBehavior) {}\n\n  @override\n  String get role => 'Slider-${eventTrigger.toString()}';\n\n  @override\n  bool operator ==(Object o) {\n    return o is Slider &&\n        eventTrigger == o.eventTrigger &&\n        handleRenderer == o.handleRenderer &&\n        initialDomainValue == o.initialDomainValue &&\n        onChangeCallback == o.onChangeCallback &&\n        roleId == o.roleId &&\n        snapToDatum == o.snapToDatum &&\n        style == o.style &&\n        layoutPaintOrder == o.layoutPaintOrder;\n  }\n\n  @override\n  int get hashCode {\n    return hashValues(eventTrigger, handleRenderer, initialDomainValue, roleId,\n        snapToDatum, style, layoutPaintOrder);\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_flutter/lib/src/behaviors/sliding_viewport.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'package:charts_common/common.dart' as common\n    show ChartBehavior, SelectionModelType, SlidingViewport;\n\nimport 'package:meta/meta.dart' show immutable;\n\nimport 'chart_behavior.dart' show ChartBehavior, GestureType;\n\n/// Chart behavior that centers the viewport on the selected domain.\n///\n/// It is used in combination with SelectNearest to update the selection model\n/// and notify this behavior to update the viewport on selection change.\n///\n/// This behavior can only be used on [CartesianChart].\n@immutable\nclass SlidingViewport<D> extends ChartBehavior<D> {\n  final desiredGestures = new Set<GestureType>();\n\n  final common.SelectionModelType selectionModelType;\n\n  SlidingViewport([this.selectionModelType = common.SelectionModelType.info]);\n\n  @override\n  common.SlidingViewport<D> createCommonBehavior() =>\n      new common.SlidingViewport<D>(selectionModelType);\n\n  @override\n  void updateCommonBehavior(common.ChartBehavior<D> commonBehavior) {}\n\n  @override\n  String get role => 'slidingViewport-${selectionModelType.toString()}';\n\n  @override\n  bool operator ==(Object o) =>\n      o is SlidingViewport && selectionModelType == o.selectionModelType;\n\n  @override\n  int get hashCode => selectionModelType.hashCode;\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_flutter/lib/src/behaviors/zoom/initial_hint_behavior.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'package:flutter/widgets.dart' show AnimationController;\n\nimport 'package:charts_common/common.dart' as common\n    show BaseChart, ChartBehavior, InitialHintBehavior;\nimport 'package:meta/meta.dart' show immutable;\n\nimport '../../base_chart_state.dart' show BaseChartState;\nimport '../chart_behavior.dart'\n    show ChartBehavior, ChartStateBehavior, GestureType;\n\n@immutable\nclass InitialHintBehavior<D> extends ChartBehavior<D> {\n  final desiredGestures = new Set<GestureType>();\n\n  final Duration? hintDuration;\n  final double? maxHintTranslate;\n  final double? maxHintScaleFactor;\n\n  InitialHintBehavior(\n      {this.hintDuration, this.maxHintTranslate, this.maxHintScaleFactor});\n\n  @override\n  common.InitialHintBehavior<D> createCommonBehavior() {\n    final behavior = new FlutterInitialHintBehavior<D>();\n\n    if (hintDuration != null) {\n      behavior.hintDuration = hintDuration!;\n    }\n\n    if (maxHintTranslate != null) {\n      behavior.maxHintTranslate = maxHintTranslate!;\n    }\n\n    if (maxHintScaleFactor != null) {\n      behavior.maxHintScaleFactor = maxHintScaleFactor!;\n    }\n\n    return behavior;\n  }\n\n  @override\n  void updateCommonBehavior(common.ChartBehavior commonBehavior) {}\n\n  @override\n  String get role => 'InitialHint';\n\n  bool operator ==(Object other) {\n    return other is InitialHintBehavior && other.hintDuration == hintDuration;\n  }\n\n  int get hashCode {\n    return hintDuration.hashCode;\n  }\n}\n\n/// Adds a native animation controller required for [common.InitialHintBehavior]\n/// to function.\nclass FlutterInitialHintBehavior<D> extends common.InitialHintBehavior<D>\n    implements ChartStateBehavior {\n  AnimationController? _hintAnimator;\n\n  BaseChartState? _chartState;\n\n  set chartState(BaseChartState chartState) {\n    assert(chartState != null);\n\n    _chartState = chartState;\n\n    _hintAnimator = chartState.getAnimationController(this);\n    _hintAnimator?.addListener(onHintTick);\n  }\n\n  @override\n  void startHintAnimation() {\n    super.startHintAnimation();\n\n    _hintAnimator!\n      ..duration = hintDuration\n      ..forward(from: 0.0);\n  }\n\n  @override\n  void stopHintAnimation() {\n    super.stopHintAnimation();\n\n    _hintAnimator?.stop();\n    // Hint animation occurs only on the first draw. The hint animator is no\n    // longer needed after the hint animation stops and is removed.\n    _chartState!.disposeAnimationController(this);\n    _hintAnimator = null;\n  }\n\n  @override\n  double get hintAnimationPercent => _hintAnimator!.value;\n\n  bool _skippedFirstTick = true;\n\n  @override\n  void onHintTick() {\n    // Skip the first tick on Flutter because the widget rebuild scheduled\n    // during onAnimation fails on an assert on render object in the framework.\n    if (_skippedFirstTick) {\n      _skippedFirstTick = false;\n      return;\n    }\n\n    super.onHintTick();\n  }\n\n  @override\n  removeFrom(common.BaseChart<D> chart) {\n    _chartState!.disposeAnimationController(this);\n    _hintAnimator = null;\n    super.removeFrom(chart);\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_flutter/lib/src/behaviors/zoom/pan_and_zoom_behavior.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'package:charts_common/common.dart' as common\n    show ChartBehavior, PanAndZoomBehavior, PanningCompletedCallback;\nimport 'package:meta/meta.dart' show immutable;\n\nimport '../chart_behavior.dart' show ChartBehavior, GestureType;\nimport 'pan_behavior.dart' show FlutterPanBehaviorMixin;\n\n@immutable\nclass PanAndZoomBehavior<D> extends ChartBehavior<D> {\n  final _desiredGestures = new Set<GestureType>.from([\n    GestureType.onDrag,\n  ]);\n\n  Set<GestureType> get desiredGestures => _desiredGestures;\n\n  /// Optional callback that is called when pan / zoom is completed.\n  ///\n  /// When flinging this callback is called after the fling is completed.\n  /// This is because panning is only completed when the flinging stops.\n  final common.PanningCompletedCallback? panningCompletedCallback;\n\n  PanAndZoomBehavior({this.panningCompletedCallback});\n\n  @override\n  common.PanAndZoomBehavior<D> createCommonBehavior() {\n    return new FlutterPanAndZoomBehavior<D>()\n      ..panningCompletedCallback = panningCompletedCallback;\n  }\n\n  @override\n  void updateCommonBehavior(common.ChartBehavior commonBehavior) {}\n\n  @override\n  String get role => 'PanAndZoom';\n\n  bool operator ==(Object other) {\n    return other is PanAndZoomBehavior &&\n        other.panningCompletedCallback == panningCompletedCallback;\n  }\n\n  int get hashCode {\n    return panningCompletedCallback.hashCode;\n  }\n}\n\n/// Adds fling gesture support to [common.PanAndZoomBehavior], by way of\n/// [FlutterPanBehaviorMixin].\nclass FlutterPanAndZoomBehavior<D> extends common.PanAndZoomBehavior<D>\n    with FlutterPanBehaviorMixin {}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_flutter/lib/src/behaviors/zoom/pan_behavior.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math' show max, pow, Point;\nimport 'dart:ui' show lerpDouble;\n\nimport 'package:flutter/widgets.dart' show AnimationController;\n\nimport 'package:charts_common/common.dart' as common\n    show BaseChart, ChartBehavior, PanBehavior, PanningCompletedCallback;\nimport 'package:meta/meta.dart' show immutable;\n\nimport '../../base_chart_state.dart' show BaseChartState;\nimport '../chart_behavior.dart'\n    show ChartBehavior, ChartStateBehavior, GestureType;\n\n@immutable\nclass PanBehavior<D> extends ChartBehavior<D> {\n  final _desiredGestures = new Set<GestureType>.from([\n    GestureType.onDrag,\n  ]);\n\n  /// Optional callback that is called when panning is completed.\n  ///\n  /// When flinging this callback is called after the fling is completed.\n  /// This is because panning is only completed when the flinging stops.\n  final common.PanningCompletedCallback? panningCompletedCallback;\n\n  PanBehavior({this.panningCompletedCallback});\n\n  Set<GestureType> get desiredGestures => _desiredGestures;\n\n  @override\n  common.PanBehavior<D> createCommonBehavior() {\n    return new FlutterPanBehavior<D>()\n      ..panningCompletedCallback = panningCompletedCallback;\n  }\n\n  @override\n  void updateCommonBehavior(common.ChartBehavior commonBehavior) {}\n\n  @override\n  String get role => 'Pan';\n\n  bool operator ==(Object other) {\n    return other is PanBehavior &&\n        other.panningCompletedCallback == panningCompletedCallback;\n  }\n\n  int get hashCode {\n    return panningCompletedCallback.hashCode;\n  }\n}\n\n/// Class extending [common.PanBehavior] with fling gesture support.\nclass FlutterPanBehavior<D> = common.PanBehavior<D>\n    with FlutterPanBehaviorMixin;\n\n/// Mixin that adds fling gesture support to [common.PanBehavior] or subclasses\n/// thereof.\nmixin FlutterPanBehaviorMixin<D> on common.PanBehavior<D>\n    implements ChartStateBehavior {\n  late BaseChartState _chartState;\n\n  set chartState(BaseChartState chartState) {\n    assert(chartState != null);\n\n    _chartState = chartState;\n    _flingAnimator = chartState.getAnimationController(this);\n    _flingAnimator?.addListener(_onFlingTick);\n  }\n\n  AnimationController? _flingAnimator;\n\n  double _flingAnimationInitialTranslatePx = 0;\n  double _flingAnimationTargetTranslatePx = 0;\n\n  bool _isFlinging = false;\n\n  static const flingDistanceMultiplier = 0.15;\n  static const flingDeceleratorFactor = 1.0;\n  static const flingDurationMultiplier = 0.15;\n  static const minimumFlingVelocity = 300.0;\n\n  @override\n  removeFrom(common.BaseChart<D> chart) {\n    stopFlingAnimation();\n    _chartState.disposeAnimationController(this);\n    _flingAnimator = null;\n    super.removeFrom(chart);\n  }\n\n  @override\n  bool onTapTest(Point<double> chartPoint) {\n    super.onTapTest(chartPoint);\n\n    stopFlingAnimation();\n\n    return true;\n  }\n\n  @override\n  bool onDragEnd(\n      Point<double> localPosition, double scale, double pixelsPerSec) {\n    if (isPanning) {\n      // Ignore slow drag gestures to avoid jitter.\n      if (pixelsPerSec.abs() < minimumFlingVelocity) {\n        onPanEnd();\n        return true;\n      }\n\n      _startFling(pixelsPerSec);\n    }\n\n    return super.onDragEnd(localPosition, scale, pixelsPerSec);\n  }\n\n  /// Starts a 'fling' in the direction and speed given by [pixelsPerSec].\n  void _startFling(double pixelsPerSec) {\n    final domainAxis = chart!.domainAxis;\n\n    _flingAnimationInitialTranslatePx = domainAxis!.viewportTranslatePx;\n    _flingAnimationTargetTranslatePx = _flingAnimationInitialTranslatePx +\n        pixelsPerSec * flingDistanceMultiplier;\n\n    final flingDuration = new Duration(\n        milliseconds:\n            max(200, (pixelsPerSec * flingDurationMultiplier).abs().round()));\n\n    _flingAnimator!\n      ..duration = flingDuration\n      ..forward(from: 0.0);\n    _isFlinging = true;\n  }\n\n  /// Decelerates a fling event.\n  double _decelerate(double value) => flingDeceleratorFactor == 1.0\n      ? 1.0 - (1.0 - value) * (1.0 - value)\n      : 1.0 - pow(1.0 - value, 2 * flingDeceleratorFactor);\n\n  /// Updates the chart axis state on each tick of the [AnimationController].\n  void _onFlingTick() {\n    if (!_isFlinging) {\n      return;\n    }\n\n    final percent = _flingAnimator!.value;\n    final deceleratedPercent = _decelerate(percent);\n    final translation = lerpDouble(_flingAnimationInitialTranslatePx,\n        _flingAnimationTargetTranslatePx, deceleratedPercent);\n\n    final domainAxis = chart!.domainAxis!;\n\n    domainAxis.setViewportSettings(\n        domainAxis.viewportScalingFactor, translation!,\n        drawAreaWidth: chart!.drawAreaBounds.width);\n\n    if (percent >= 1.0) {\n      stopFlingAnimation();\n      onPanEnd();\n      chart!.redraw();\n    } else {\n      chart!.redraw(skipAnimation: true, skipLayout: true);\n    }\n  }\n\n  /// Stops any current fling animations that may be executing.\n  void stopFlingAnimation() {\n    if (_isFlinging) {\n      _isFlinging = false;\n      _flingAnimator?.stop();\n    }\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_flutter/lib/src/canvas/circle_sector_painter.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math' show cos, pi, sin, Point;\nimport 'package:flutter/material.dart';\nimport 'package:charts_common/common.dart' as common show Color;\n\n/// Draws a sector of a circle, with an optional hole in the center.\nclass CircleSectorPainter {\n  /// Draws a sector of a circle, with an optional hole in the center.\n  ///\n  /// [center] The x, y coordinates of the circle's center.\n  /// [radius] The radius of the circle.\n  /// [innerRadius] Optional radius of a hole in the center of the circle that\n  ///     should not be filled in as part of the sector.\n  /// [startAngle] The angle at which the arc starts, measured clockwise from\n  ///     the positive x axis and expressed in radians.\n  /// [endAngle] The angle at which the arc ends, measured clockwise from the\n  ///     positive x axis and expressed in radians.\n  /// [fill] Fill color for the sector.\n  /// [stroke] Stroke color of the arc and radius lines.\n  /// [strokeWidthPx] Stroke width of the arc and radius lines.\n  static void draw({\n    required Canvas canvas,\n    required Paint paint,\n    required Point center,\n    required double radius,\n    required double innerRadius,\n    required double startAngle,\n    required double endAngle,\n    common.Color? fill,\n  }) {\n    paint.color = new Color.fromARGB(fill!.a, fill.r, fill.g, fill.b);\n    paint.style = PaintingStyle.fill;\n\n    final innerRadiusStartPoint = new Point<double>(\n        innerRadius * cos(startAngle) + center.x,\n        innerRadius * sin(startAngle) + center.y);\n\n    final innerRadiusEndPoint = new Point<double>(\n        innerRadius * cos(endAngle) + center.x,\n        innerRadius * sin(endAngle) + center.y);\n\n    final radiusStartPoint = new Point<double>(\n        radius * cos(startAngle) + center.x,\n        radius * sin(startAngle) + center.y);\n\n    final centerOffset = new Offset(center.x.toDouble(), center.y.toDouble());\n\n    final isFullCircle = startAngle != null &&\n        endAngle != null &&\n        endAngle - startAngle == 2 * pi;\n\n    final midpointAngle = (endAngle + startAngle) / 2;\n\n    final path = new Path()\n      ..moveTo(innerRadiusStartPoint.x, innerRadiusStartPoint.y);\n\n    path.lineTo(radiusStartPoint.x, radiusStartPoint.y);\n\n    // For full circles, draw the arc in two parts.\n    if (isFullCircle) {\n      path.arcTo(new Rect.fromCircle(center: centerOffset, radius: radius),\n          startAngle, midpointAngle - startAngle, true);\n      path.arcTo(new Rect.fromCircle(center: centerOffset, radius: radius),\n          midpointAngle, endAngle - midpointAngle, true);\n    } else {\n      path.arcTo(new Rect.fromCircle(center: centerOffset, radius: radius),\n          startAngle, endAngle - startAngle, true);\n    }\n\n    path.lineTo(innerRadiusEndPoint.x, innerRadiusEndPoint.y);\n\n    // For full circles, draw the arc in two parts.\n    if (isFullCircle) {\n      path.arcTo(new Rect.fromCircle(center: centerOffset, radius: innerRadius),\n          endAngle, midpointAngle - endAngle, true);\n      path.arcTo(new Rect.fromCircle(center: centerOffset, radius: innerRadius),\n          midpointAngle, startAngle - midpointAngle, true);\n    } else {\n      path.arcTo(new Rect.fromCircle(center: centerOffset, radius: innerRadius),\n          endAngle, startAngle - endAngle, true);\n    }\n\n    // Drawing two copies of this line segment, before and after the arcs,\n    // ensures that the path actually gets closed correctly.\n    path.lineTo(radiusStartPoint.x, radiusStartPoint.y);\n\n    canvas.drawPath(path, paint);\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_flutter/lib/src/canvas/line_painter.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:ui' as ui show Shader;\nimport 'dart:math' show Point, Rectangle;\nimport 'package:flutter/material.dart';\nimport 'package:charts_common/common.dart' as common show Color;\n\n/// Draws a simple line.\n///\n/// Lines may be styled with dash patterns similar to stroke-dasharray in SVG\n/// path elements. Dash patterns are currently only supported between vertical\n/// or horizontal line segments at this time.\nclass LinePainter {\n  /// Draws a simple line.\n  ///\n  /// [dashPattern] controls the pattern of dashes and gaps in a line. It is a\n  /// list of lengths of alternating dashes and gaps. The rendering is similar\n  /// to stroke-dasharray in SVG path elements. An odd number of values in the\n  /// pattern will be repeated to derive an even number of values. \"1,2,3\" is\n  /// equivalent to \"1,2,3,1,2,3.\"\n  static void draw(\n      {required Canvas canvas,\n      required Paint paint,\n      required List<Point> points,\n      Rectangle<num>? clipBounds,\n      common.Color? fill,\n      common.Color? stroke,\n      bool? roundEndCaps,\n      double? strokeWidthPx,\n      List<int>? dashPattern,\n      ui.Shader? shader}) {\n    if (points.isEmpty) {\n      return;\n    }\n\n    // Apply clip bounds as a clip region.\n    if (clipBounds != null) {\n      canvas\n        ..save()\n        ..clipRect(new Rect.fromLTWH(\n            clipBounds.left.toDouble(),\n            clipBounds.top.toDouble(),\n            clipBounds.width.toDouble(),\n            clipBounds.height.toDouble()));\n    }\n\n    paint.color = new Color.fromARGB(stroke!.a, stroke.r, stroke.g, stroke.b);\n\n    if (shader != null) {\n      paint.shader = shader;\n    }\n\n    // If the line has a single point, draw a circle.\n    if (points.length == 1) {\n      final point = points.first;\n      paint.style = PaintingStyle.fill;\n      canvas.drawCircle(new Offset(point.x.toDouble(), point.y.toDouble()),\n          strokeWidthPx ?? 0, paint);\n    } else {\n      if (strokeWidthPx != null) {\n        paint.strokeWidth = strokeWidthPx;\n      }\n      paint.strokeJoin = StrokeJoin.round;\n      paint.style = PaintingStyle.stroke;\n\n      if (dashPattern == null || dashPattern.isEmpty) {\n        if (roundEndCaps == true) {\n          paint.strokeCap = StrokeCap.round;\n        }\n\n        _drawSolidLine(canvas, paint, points);\n      } else {\n        _drawDashedLine(canvas, paint, points, dashPattern);\n      }\n    }\n\n    if (clipBounds != null) {\n      canvas.restore();\n    }\n  }\n\n  /// Draws solid lines between each point.\n  static void _drawSolidLine(Canvas canvas, Paint paint, List<Point> points) {\n    // TODO: Extract a native line component which constructs the\n    // appropriate underlying data structures to avoid conversion.\n    final path = new Path()\n      ..moveTo(points.first.x.toDouble(), points.first.y.toDouble());\n\n    for (var point in points) {\n      path.lineTo(point.x.toDouble(), point.y.toDouble());\n    }\n\n    canvas.drawPath(path, paint);\n  }\n\n  /// Draws dashed lines lines between each point.\n  static void _drawDashedLine(\n      Canvas canvas, Paint paint, List<Point> points, List<int> dashPattern) {\n    final localDashPattern = new List.from(dashPattern);\n\n    // If an odd number of parts are defined, repeat the pattern to get an even\n    // number.\n    if (dashPattern.length % 2 == 1) {\n      localDashPattern.addAll(dashPattern);\n    }\n\n    // Stores the previous point in the series.\n    var previousSeriesPoint = _getOffset(points.first);\n\n    var remainder = 0;\n    var solid = true;\n    var dashPatternIndex = 0;\n\n    // Gets the next segment in the dash pattern, looping back to the\n    // beginning once the end has been reached.\n    var getNextDashPatternSegment = () {\n      final dashSegment = localDashPattern[dashPatternIndex];\n      dashPatternIndex = (dashPatternIndex + 1) % localDashPattern.length;\n      return dashSegment;\n    };\n\n    // Array of points that is used to draw a connecting path when only a\n    // partial dash pattern segment can be drawn in the remaining length of a\n    // line segment (between two defined points in the shape).\n    var remainderPoints;\n\n    // Draw the path through all the rest of the points in the series.\n    for (var pointIndex = 1; pointIndex < points.length; pointIndex++) {\n      // Stores the current point in the series.\n      final seriesPoint = _getOffset(points[pointIndex]);\n\n      if (previousSeriesPoint == seriesPoint) {\n        // Bypass dash pattern handling if the points are the same.\n      } else {\n        // Stores the previous point along the current series line segment where\n        // we rendered a dash (or left a gap).\n        var previousPoint = previousSeriesPoint;\n\n        var d = _getOffsetDistance(previousSeriesPoint, seriesPoint);\n\n        while (d > 0) {\n          var dashSegment =\n              remainder > 0 ? remainder : getNextDashPatternSegment();\n          remainder = 0;\n\n          // Create a unit vector in the direction from previous to next point.\n          final v = seriesPoint - previousPoint;\n          final u = new Offset(v.dx / v.distance, v.dy / v.distance);\n\n          // If the remaining distance is less than the length of the dash\n          // pattern segment, then cut off the pattern segment for this portion\n          // of the overall line.\n          final distance = d < dashSegment ? d : dashSegment.toDouble();\n\n          // Compute a vector representing the length of dash pattern segment to\n          // be drawn.\n          final nextPoint = previousPoint + (u * distance);\n\n          // If we are in a solid portion of the dash pattern, draw a line.\n          // Else, move on.\n          if (solid) {\n            if (remainderPoints != null) {\n              // If we had a partial un-drawn dash from the previous point along\n              // the line, draw a path that includes it and the end of the dash\n              // pattern segment in the current line segment.\n              remainderPoints.add(new Offset(nextPoint.dx, nextPoint.dy));\n\n              final path = new Path()\n                ..moveTo(remainderPoints.first.dx, remainderPoints.first.dy);\n\n              for (var p in remainderPoints) {\n                path.lineTo(p.dx, p.dy);\n              }\n\n              canvas.drawPath(path, paint);\n\n              remainderPoints = null;\n            } else {\n              if (d < dashSegment && pointIndex < points.length - 1) {\n                // If the remaining distance d is too small to fit this dash,\n                // and we have more points in the line, save off a series of\n                // remainder points so that we can draw a path segment moving in\n                // the direction of the next point.\n                //\n                // Note that we don't need to save anything off for the \"blank\"\n                // portions of the pattern because we still take the remaining\n                // distance into account before starting the next dash in the\n                // next line segment.\n                remainderPoints = [\n                  new Offset(previousPoint.dx, previousPoint.dy),\n                  new Offset(nextPoint.dx, nextPoint.dy)\n                ];\n              } else {\n                // Otherwise, draw a simple line segment for this dash.\n                canvas.drawLine(previousPoint, nextPoint, paint);\n              }\n            }\n          }\n\n          solid = !solid;\n          previousPoint = nextPoint;\n          d = d - dashSegment;\n        }\n\n        // Save off the remaining distance so that we can continue the dash (or\n        // gap) into the next line segment.\n        remainder = -d.round();\n\n        // If we have a remaining un-drawn distance for the current dash (or\n        // gap), revert the last change to \"solid\" so that we will continue\n        // either drawing a dash or leaving a gap.\n        if (remainder > 0) {\n          solid = !solid;\n        }\n      }\n\n      previousSeriesPoint = seriesPoint;\n    }\n  }\n\n  /// Converts a [Point] into an [Offset].\n  static Offset _getOffset(Point point) =>\n      new Offset(point.x.toDouble(), point.y.toDouble());\n\n  /// Computes the distance between two [Offset]s, as if they were [Point]s.\n  static num _getOffsetDistance(Offset o1, Offset o2) {\n    final p1 = new Point(o1.dx, o1.dy);\n    final p2 = new Point(o2.dx, o2.dy);\n    return p1.distanceTo(p2);\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_flutter/lib/src/canvas/pie_painter.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math' show cos, sin, Point;\nimport 'package:flutter/material.dart';\nimport 'package:charts_common/common.dart' as common show CanvasPie;\nimport 'circle_sector_painter.dart' show CircleSectorPainter;\n\n/// Draws a pie chart, with an optional hole in the center.\nclass PiePainter {\n  /// Draws a pie chart, with an optional hole in the center.\n  static void draw(Canvas canvas, Paint paint, common.CanvasPie canvasPie) {\n    final center = canvasPie.center;\n    final radius = canvasPie.radius;\n    final innerRadius = canvasPie.innerRadius;\n\n    for (var slice in canvasPie.slices) {\n      CircleSectorPainter.draw(\n          canvas: canvas,\n          paint: paint,\n          center: center,\n          radius: radius,\n          innerRadius: innerRadius,\n          startAngle: slice.startAngle,\n          endAngle: slice.endAngle,\n          fill: slice.fill);\n    }\n\n    // Draw stroke lines between pie slices. This is done after the slices are\n    // drawn to ensure that they appear on top.\n    if (canvasPie.stroke != null &&\n        canvasPie.strokeWidthPx != null &&\n        canvasPie.slices.length > 1) {\n      paint.color = new Color.fromARGB(canvasPie.stroke!.a, canvasPie.stroke!.r,\n          canvasPie.stroke!.g, canvasPie.stroke!.b);\n\n      paint.strokeWidth = canvasPie.strokeWidthPx;\n      paint.strokeJoin = StrokeJoin.bevel;\n      paint.style = PaintingStyle.stroke;\n\n      final path = new Path();\n\n      for (var slice in canvasPie.slices) {\n        final innerRadiusStartPoint = new Point<double>(\n            innerRadius * cos(slice.startAngle) + center.x,\n            innerRadius * sin(slice.startAngle) + center.y);\n\n        final innerRadiusEndPoint = new Point<double>(\n            innerRadius * cos(slice.endAngle) + center.x,\n            innerRadius * sin(slice.endAngle) + center.y);\n\n        final radiusStartPoint = new Point<double>(\n            radius * cos(slice.startAngle) + center.x,\n            radius * sin(slice.startAngle) + center.y);\n\n        final radiusEndPoint = new Point<double>(\n            radius * cos(slice.endAngle) + center.x,\n            radius * sin(slice.endAngle) + center.y);\n\n        path.moveTo(innerRadiusStartPoint.x, innerRadiusStartPoint.y);\n\n        path.lineTo(radiusStartPoint.x, radiusStartPoint.y);\n\n        path.moveTo(innerRadiusEndPoint.x, innerRadiusEndPoint.y);\n\n        path.lineTo(radiusEndPoint.x, radiusEndPoint.y);\n      }\n\n      canvas.drawPath(path, paint);\n    }\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_flutter/lib/src/canvas/point_painter.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math' show Point;\nimport 'package:flutter/material.dart';\nimport 'package:charts_common/common.dart' as common show Color;\n\n/// Draws a simple point.\n///\n/// TODO: Support for more shapes than circles?\nclass PointPainter {\n  static void draw(\n      {required Canvas canvas,\n      required Paint paint,\n      required Point point,\n      required double radius,\n      common.Color? fill,\n      common.Color? stroke,\n      double? strokeWidthPx}) {\n    if (point == null) {\n      return;\n    }\n\n    if (fill != null) {\n      paint.color = new Color.fromARGB(fill.a, fill.r, fill.g, fill.b);\n      paint.style = PaintingStyle.fill;\n\n      canvas.drawCircle(\n          new Offset(point.x.toDouble(), point.y.toDouble()), radius, paint);\n    }\n\n    // [Canvas.drawCircle] does not support drawing a circle with both a fill\n    // and a stroke at this time. Use a separate circle for the stroke.\n    if (stroke != null && strokeWidthPx != null && strokeWidthPx > 0.0) {\n      paint.color = new Color.fromARGB(stroke.a, stroke.r, stroke.g, stroke.b);\n      paint.strokeWidth = strokeWidthPx;\n      paint.strokeJoin = StrokeJoin.bevel;\n      paint.style = PaintingStyle.stroke;\n\n      canvas.drawCircle(\n          new Offset(point.x.toDouble(), point.y.toDouble()), radius, paint);\n    }\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_flutter/lib/src/canvas/polygon_painter.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math' show Point, Rectangle;\nimport 'package:flutter/material.dart';\nimport 'package:charts_common/common.dart' as common show Color;\n\n/// Draws a simple line.\n///\n/// Lines may be styled with dash patterns similar to stroke-dasharray in SVG\n/// path elements. Dash patterns are currently only supported between vertical\n/// or horizontal line segments at this time.\nclass PolygonPainter {\n  /// Draws a simple line.\n  ///\n  /// [dashPattern] controls the pattern of dashes and gaps in a line. It is a\n  /// list of lengths of alternating dashes and gaps. The rendering is similar\n  /// to stroke-dasharray in SVG path elements. An odd number of values in the\n  /// pattern will be repeated to derive an even number of values. \"1,2,3\" is\n  /// equivalent to \"1,2,3,1,2,3.\"\n  static void draw(\n      {required Canvas canvas,\n      required Paint paint,\n      required List<Point> points,\n      Rectangle<num>? clipBounds,\n      common.Color? fill,\n      common.Color? stroke,\n      double? strokeWidthPx}) {\n    if (points.isEmpty) {\n      return;\n    }\n\n    // Apply clip bounds as a clip region.\n    if (clipBounds != null) {\n      canvas\n        ..save()\n        ..clipRect(new Rect.fromLTWH(\n            clipBounds.left.toDouble(),\n            clipBounds.top.toDouble(),\n            clipBounds.width.toDouble(),\n            clipBounds.height.toDouble()));\n    }\n\n    final strokeColor = stroke != null\n        ? new Color.fromARGB(stroke.a, stroke.r, stroke.g, stroke.b)\n        : null;\n\n    final fillColor = fill != null\n        ? new Color.fromARGB(fill.a, fill.r, fill.g, fill.b)\n        : null;\n\n    // If the line has a single point, draw a circle.\n    if (points.length == 1) {\n      final point = points.first;\n      if (fillColor != null) {\n        paint.color = fillColor;\n      }\n      paint.style = PaintingStyle.fill;\n      canvas.drawCircle(new Offset(point.x.toDouble(), point.y.toDouble()),\n          strokeWidthPx!, paint);\n    } else {\n      if (strokeColor != null && strokeWidthPx != null) {\n        paint.strokeWidth = strokeWidthPx;\n        paint.strokeJoin = StrokeJoin.bevel;\n        paint.style = PaintingStyle.stroke;\n      }\n\n      if (fillColor != null) {\n        paint.color = fillColor;\n        paint.style = PaintingStyle.fill;\n      }\n\n      final path = new Path()\n        ..moveTo(points.first.x.toDouble(), points.first.y.toDouble());\n\n      for (var point in points) {\n        path.lineTo(point.x.toDouble(), point.y.toDouble());\n      }\n\n      canvas.drawPath(path, paint);\n    }\n\n    if (clipBounds != null) {\n      canvas.restore();\n    }\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_flutter/lib/src/cartesian_chart.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:collection' show LinkedHashMap;\nimport 'package:meta/meta.dart' show immutable, protected;\n\nimport 'package:charts_common/common.dart' as common\n    show\n        AxisSpec,\n        BaseChart,\n        CartesianChart,\n        NumericAxis,\n        NumericAxisSpec,\n        RTLSpec,\n        Series,\n        SeriesRendererConfig;\nimport 'base_chart_state.dart' show BaseChartState;\nimport 'behaviors/chart_behavior.dart' show ChartBehavior;\nimport 'base_chart.dart' show BaseChart, LayoutConfig;\nimport 'selection_model_config.dart' show SelectionModelConfig;\nimport 'user_managed_state.dart' show UserManagedState;\n\n@immutable\nabstract class CartesianChart<D> extends BaseChart<D> {\n  final common.AxisSpec? domainAxis;\n  final common.NumericAxisSpec? primaryMeasureAxis;\n  final common.NumericAxisSpec? secondaryMeasureAxis;\n  final LinkedHashMap<String, common.NumericAxisSpec>? disjointMeasureAxes;\n  final bool? flipVerticalAxis;\n\n  CartesianChart(\n    List<common.Series<dynamic, D>> seriesList, {\n    bool? animate,\n    Duration? animationDuration,\n    this.domainAxis,\n    this.primaryMeasureAxis,\n    this.secondaryMeasureAxis,\n    this.disjointMeasureAxes,\n    common.SeriesRendererConfig<D>? defaultRenderer,\n    List<common.SeriesRendererConfig<D>>? customSeriesRenderers,\n    List<ChartBehavior<D>>? behaviors,\n    List<SelectionModelConfig<D>>? selectionModels,\n    common.RTLSpec? rtlSpec,\n    bool defaultInteractions = true,\n    LayoutConfig? layoutConfig,\n    UserManagedState<D>? userManagedState,\n    this.flipVerticalAxis,\n  }) : super(\n          seriesList,\n          animate: animate,\n          animationDuration: animationDuration,\n          defaultRenderer: defaultRenderer,\n          customSeriesRenderers: customSeriesRenderers,\n          behaviors: behaviors,\n          selectionModels: selectionModels,\n          rtlSpec: rtlSpec,\n          defaultInteractions: defaultInteractions,\n          layoutConfig: layoutConfig,\n          userManagedState: userManagedState,\n        );\n\n  @override\n  void updateCommonChart(common.BaseChart<D> baseChart, BaseChart<D>? oldWidget,\n      BaseChartState<D> chartState) {\n    super.updateCommonChart(baseChart, oldWidget, chartState);\n\n    final prev = oldWidget as CartesianChart?;\n    final chart = baseChart as common.CartesianChart;\n\n    if (flipVerticalAxis != null) {\n      chart.flipVerticalAxisOutput = flipVerticalAxis!;\n    }\n\n    if (domainAxis != null && domainAxis != prev?.domainAxis) {\n      chart.domainAxisSpec = domainAxis!;\n      chartState.markChartDirty();\n    }\n\n    if (primaryMeasureAxis != prev?.primaryMeasureAxis) {\n      chart.primaryMeasureAxisSpec = primaryMeasureAxis;\n      chartState.markChartDirty();\n    }\n\n    if (secondaryMeasureAxis != prev?.secondaryMeasureAxis) {\n      chart.secondaryMeasureAxisSpec = secondaryMeasureAxis;\n      chartState.markChartDirty();\n    }\n\n    if (disjointMeasureAxes != prev?.disjointMeasureAxes) {\n      chart.disjointMeasureAxisSpecs = disjointMeasureAxes;\n      chartState.markChartDirty();\n    }\n  }\n\n  @protected\n  LinkedHashMap<String, common.NumericAxis>? createDisjointMeasureAxes() {\n    if (disjointMeasureAxes != null) {\n      final disjointAxes = new LinkedHashMap<String, common.NumericAxis>();\n\n      disjointMeasureAxes!\n          .forEach((String axisId, common.NumericAxisSpec axisSpec) {\n        disjointAxes[axisId] = axisSpec.createAxis();\n      });\n\n      return disjointAxes;\n    } else {\n      return null;\n    }\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_flutter/lib/src/chart_canvas.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:ui' as ui show Gradient, Shader;\nimport 'dart:math' show Point, Rectangle, max;\nimport 'package:charts_common/common.dart' as common\n    show\n        BlendMode,\n        ChartCanvas,\n        CanvasBarStack,\n        CanvasPie,\n        Color,\n        FillPatternType,\n        GraphicsFactory,\n        StyleFactory,\n        TextElement,\n        TextDirection;\nimport 'package:flutter/material.dart';\nimport 'text_element.dart' show TextElement;\nimport 'canvas/circle_sector_painter.dart' show CircleSectorPainter;\nimport 'canvas/line_painter.dart' show LinePainter;\nimport 'canvas/pie_painter.dart' show PiePainter;\nimport 'canvas/point_painter.dart' show PointPainter;\nimport 'canvas/polygon_painter.dart' show PolygonPainter;\n\nclass ChartCanvas implements common.ChartCanvas {\n  /// Pixels to allow to overdraw above the draw area that fades to transparent.\n  static const double rect_top_gradient_pixels = 5;\n\n  final Canvas canvas;\n  final common.GraphicsFactory graphicsFactory;\n  final _paint = new Paint();\n\n  ChartCanvas(this.canvas, this.graphicsFactory);\n\n  @override\n  void drawCircleSector(Point center, double radius, double innerRadius,\n      double startAngle, double endAngle,\n      {common.Color? fill, common.Color? stroke, double? strokeWidthPx}) {\n    CircleSectorPainter.draw(\n      canvas: canvas,\n      paint: _paint,\n      center: center,\n      radius: radius,\n      innerRadius: innerRadius,\n      startAngle: startAngle,\n      endAngle: endAngle,\n      fill: fill,\n    );\n  }\n\n  @override\n  void drawLine(\n      {required List<Point> points,\n      Rectangle<num>? clipBounds,\n      common.Color? fill,\n      common.Color? stroke,\n      bool? roundEndCaps,\n      double? strokeWidthPx,\n      List<int>? dashPattern}) {\n    LinePainter.draw(\n        canvas: canvas,\n        paint: _paint,\n        points: points,\n        clipBounds: clipBounds,\n        fill: fill,\n        stroke: stroke,\n        roundEndCaps: roundEndCaps,\n        strokeWidthPx: strokeWidthPx,\n        dashPattern: dashPattern);\n  }\n\n  @override\n  void drawPie(common.CanvasPie canvasPie) {\n    PiePainter.draw(canvas, _paint, canvasPie);\n  }\n\n  @override\n  void drawPoint(\n      {required Point point,\n      required double radius,\n      common.Color? fill,\n      common.Color? stroke,\n      double? strokeWidthPx,\n      common.BlendMode? blendMode}) {\n    PointPainter.draw(\n        canvas: canvas,\n        paint: _paint,\n        point: point,\n        radius: radius,\n        fill: fill,\n        stroke: stroke,\n        strokeWidthPx: strokeWidthPx);\n  }\n\n  @override\n  void drawPolygon(\n      {required List<Point> points,\n      Rectangle<num>? clipBounds,\n      common.Color? fill,\n      common.Color? stroke,\n      double? strokeWidthPx}) {\n    PolygonPainter.draw(\n        canvas: canvas,\n        paint: _paint,\n        points: points,\n        clipBounds: clipBounds,\n        fill: fill,\n        stroke: stroke,\n        strokeWidthPx: strokeWidthPx);\n  }\n\n  /// Creates a bottom to top gradient that transitions [fill] to transparent.\n  ui.Gradient _createHintGradient(double left, double top, common.Color fill) {\n    return new ui.Gradient.linear(\n      new Offset(left, top),\n      new Offset(left, top - rect_top_gradient_pixels),\n      [\n        new Color.fromARGB(fill.a, fill.r, fill.g, fill.b),\n        new Color.fromARGB(0, fill.r, fill.g, fill.b)\n      ],\n    );\n  }\n\n  @override\n  void drawRect(Rectangle<num> bounds,\n      {common.Color? fill,\n      common.FillPatternType? pattern,\n      common.Color? stroke,\n      double? strokeWidthPx,\n      Rectangle<num>? drawAreaBounds}) {\n    final drawStroke =\n        (strokeWidthPx != null && strokeWidthPx > 0.0 && stroke != null);\n\n    final strokeWidthOffset = (drawStroke ? strokeWidthPx : 0);\n\n    // Factor out stroke width, if a stroke is enabled.\n    final fillRectBounds = new Rectangle<num>(\n        bounds.left + strokeWidthOffset! / 2,\n        bounds.top + strokeWidthOffset / 2,\n        bounds.width - strokeWidthOffset,\n        bounds.height - strokeWidthOffset);\n\n    switch (pattern) {\n      case common.FillPatternType.forwardHatch:\n        _drawForwardHatchPattern(fillRectBounds, canvas,\n            fill: fill!, drawAreaBounds: drawAreaBounds);\n        break;\n\n      case common.FillPatternType.solid:\n      default:\n        // Use separate rect for drawing stroke\n        _paint.color = new Color.fromARGB(fill!.a, fill.r, fill.g, fill.b);\n        _paint.style = PaintingStyle.fill;\n\n        // Apply a gradient to the top [rect_top_gradient_pixels] to transparent\n        // if the rectangle is higher than the [drawAreaBounds] top.\n        if (drawAreaBounds != null && bounds.top < drawAreaBounds.top) {\n          _paint.shader = _createHintGradient(drawAreaBounds.left.toDouble(),\n              drawAreaBounds.top.toDouble(), fill);\n        }\n\n        canvas.drawRect(_getRect(fillRectBounds), _paint);\n        break;\n    }\n\n    // [Canvas.drawRect] does not support drawing a rectangle with both a fill\n    // and a stroke at this time. Use a separate rect for the stroke.\n    if (drawStroke) {\n      _paint.color =\n          new Color.fromARGB(stroke!.a, stroke.r, stroke.g, stroke.b);\n      // Set shader to null if no draw area bounds so it can use the color\n      // instead.\n      _paint.shader = drawAreaBounds != null\n          ? _createHintGradient(drawAreaBounds.left.toDouble(),\n              drawAreaBounds.top.toDouble(), stroke)\n          : null;\n      _paint.strokeJoin = StrokeJoin.round;\n      _paint.strokeWidth = strokeWidthPx!;\n      _paint.style = PaintingStyle.stroke;\n\n      canvas.drawRect(_getRect(bounds), _paint);\n    }\n\n    // Reset the shader.\n    _paint.shader = null;\n  }\n\n  @override\n  void drawRRect(Rectangle<num> bounds,\n      {common.Color? fill,\n      common.Color? stroke,\n      common.Color? patternColor,\n      common.FillPatternType? fillPattern,\n      double? patternStrokeWidthPx,\n      double? strokeWidthPx,\n      num? radius,\n      bool roundTopLeft = false,\n      bool roundTopRight = false,\n      bool roundBottomLeft = false,\n      bool roundBottomRight = false}) {\n    // Use separate rect for drawing stroke\n    _paint.color = new Color.fromARGB(fill!.a, fill.r, fill.g, fill.b);\n    _paint.style = PaintingStyle.fill;\n\n    canvas.drawRRect(\n        _getRRect(bounds,\n            radius: radius?.toDouble() ?? 0.0,\n            roundTopLeft: roundTopLeft,\n            roundTopRight: roundTopRight,\n            roundBottomLeft: roundBottomLeft,\n            roundBottomRight: roundBottomRight),\n        _paint);\n  }\n\n  @override\n  void drawBarStack(common.CanvasBarStack barStack,\n      {Rectangle<num>? drawAreaBounds}) {\n    // only clip if rounded rect.\n\n    // Clip a rounded rect for the whole region if rounded bars.\n    final roundedCorners = barStack.radius != null && 0 < barStack.radius!;\n\n    if (roundedCorners) {\n      canvas\n        ..save()\n        ..clipRRect(_getRRect(\n          barStack.fullStackRect,\n          radius: barStack.radius!.toDouble(),\n          roundTopLeft: barStack.roundTopLeft,\n          roundTopRight: barStack.roundTopRight,\n          roundBottomLeft: barStack.roundBottomLeft,\n          roundBottomRight: barStack.roundBottomRight,\n        ));\n    }\n\n    // Draw each bar.\n    for (var barIndex = 0; barIndex < barStack.segments.length; barIndex++) {\n      // TODO: Add configuration for hiding stack line.\n      // TODO: Don't draw stroke on bottom of bars.\n      final segment = barStack.segments[barIndex];\n      drawRect(segment.bounds,\n          fill: segment.fill,\n          pattern: segment.pattern,\n          stroke: segment.stroke,\n          strokeWidthPx: segment.strokeWidthPx,\n          drawAreaBounds: drawAreaBounds);\n    }\n\n    if (roundedCorners) {\n      canvas.restore();\n    }\n  }\n\n  @override\n  void drawText(common.TextElement textElement, int offsetX, int offsetY,\n      {double rotation = 0.0}) {\n    // Must be Flutter TextElement.\n    assert(textElement is TextElement);\n\n    final flutterTextElement = textElement as TextElement;\n    final textDirection = flutterTextElement.textDirection;\n    final measurement = flutterTextElement.measurement;\n\n    if (rotation != 0) {\n      // TODO: Remove once textAnchor works.\n      if (textDirection == common.TextDirection.rtl) {\n        offsetY += measurement.horizontalSliceWidth.toInt();\n      }\n\n      offsetX -= flutterTextElement.verticalFontShift;\n\n      canvas.save();\n      canvas.translate(offsetX.toDouble(), offsetY.toDouble());\n      canvas.rotate(rotation);\n\n      textElement.textPainter!.paint(canvas, new Offset(0.0, 0.0));\n\n      canvas.restore();\n    } else {\n      // TODO: Remove once textAnchor works.\n      if (textDirection == common.TextDirection.rtl) {\n        offsetX -= measurement.horizontalSliceWidth.toInt();\n      }\n\n      // Account for missing center alignment.\n      if (textDirection == common.TextDirection.center) {\n        offsetX -= (measurement.horizontalSliceWidth / 2).ceil();\n      }\n\n      offsetY -= flutterTextElement.verticalFontShift;\n\n      textElement.textPainter!\n          .paint(canvas, new Offset(offsetX.toDouble(), offsetY.toDouble()));\n    }\n  }\n\n  @override\n  void setClipBounds(Rectangle<int> clipBounds) {\n    canvas\n      ..save()\n      ..clipRect(_getRect(clipBounds));\n  }\n\n  @override\n  void resetClipBounds() {\n    canvas.restore();\n  }\n\n  /// Convert dart:math [Rectangle] to Flutter [Rect].\n  Rect _getRect(Rectangle<num> rectangle) {\n    return new Rect.fromLTWH(\n        rectangle.left.toDouble(),\n        rectangle.top.toDouble(),\n        rectangle.width.toDouble(),\n        rectangle.height.toDouble());\n  }\n\n  /// Convert dart:math [Rectangle] and to Flutter [RRect].\n  RRect _getRRect(\n    Rectangle<num> rectangle, {\n    double radius = 0,\n    bool roundTopLeft = false,\n    bool roundTopRight = false,\n    bool roundBottomLeft = false,\n    bool roundBottomRight = false,\n  }) {\n    final cornerRadius =\n        radius == 0 ? Radius.zero : new Radius.circular(radius);\n\n    return new RRect.fromLTRBAndCorners(\n        rectangle.left.toDouble(),\n        rectangle.top.toDouble(),\n        rectangle.right.toDouble(),\n        rectangle.bottom.toDouble(),\n        topLeft: roundTopLeft ? cornerRadius : Radius.zero,\n        topRight: roundTopRight ? cornerRadius : Radius.zero,\n        bottomLeft: roundBottomLeft ? cornerRadius : Radius.zero,\n        bottomRight: roundBottomRight ? cornerRadius : Radius.zero);\n  }\n\n  /// Draws a forward hatch pattern in the given bounds.\n  _drawForwardHatchPattern(\n    Rectangle<num> bounds,\n    Canvas canvas, {\n    common.Color? background,\n    common.Color? fill,\n    double fillWidthPx = 4.0,\n    Rectangle<num>? drawAreaBounds,\n  }) {\n    background ??= common.StyleFactory.style.white;\n    fill ??= common.StyleFactory.style.black;\n\n    // Fill in the shape with a solid background color.\n    _paint.color = new Color.fromARGB(\n        background.a, background.r, background.g, background.b);\n    _paint.style = PaintingStyle.fill;\n\n    // Apply a gradient the background if bounds exceed the draw area.\n    if (drawAreaBounds != null && bounds.top < drawAreaBounds.top) {\n      _paint.shader = _createHintGradient(drawAreaBounds.left.toDouble(),\n          drawAreaBounds.top.toDouble(), background);\n    }\n\n    canvas.drawRect(_getRect(bounds), _paint);\n\n    // As a simplification, we will treat the bounds as a large square and fill\n    // it up with lines from the bottom-left corner to the top-right corner.\n    // Get the longer side of the bounds here for the size of this square.\n    final size = max(bounds.width, bounds.height);\n\n    final x0 = bounds.left + size + fillWidthPx;\n    final x1 = bounds.left - fillWidthPx;\n    final y0 = bounds.bottom - size - fillWidthPx;\n    final y1 = bounds.bottom + fillWidthPx;\n    final offset = 8;\n\n    final isVertical = bounds.height >= bounds.width;\n\n    // The \"first\" line segment will be drawn from the bottom left corner of the\n    // bounds, up and towards the right. Start the loop N iterations \"back\" to\n    // draw partial line segments beneath (or to the left) of this segment,\n    // where N is the number of offsets that fit inside the smaller dimension of\n    // the bounds.\n    final smallSide = isVertical ? bounds.width : bounds.height;\n    final start = -(smallSide / offset).round() * offset;\n\n    // Keep going until we reach the top or right of the bounds, depending on\n    // whether the rectangle is oriented vertically or horizontally.\n    final end = size + offset;\n\n    // Create gradient for line painter if top bounds exceeded.\n    ui.Shader? lineShader;\n    if (drawAreaBounds != null && bounds.top < drawAreaBounds.top) {\n      lineShader = _createHintGradient(\n          drawAreaBounds.left.toDouble(), drawAreaBounds.top.toDouble(), fill);\n    }\n\n    for (int i = start; i < end; i = i + offset) {\n      // For vertical bounds, we need to draw lines from top to bottom. For\n      // bounds, we need to draw lines from left to right.\n      final modifier = isVertical ? -1 * i : i;\n\n      // Draw a line segment in the bottom right corner of the pattern.\n      LinePainter.draw(\n          canvas: canvas,\n          paint: _paint,\n          points: [\n            new Point(x0 + modifier, y0),\n            new Point(x1 + modifier, y1),\n          ],\n          stroke: fill,\n          strokeWidthPx: fillWidthPx,\n          shader: lineShader);\n    }\n  }\n\n  @override\n  set drawingView(String? viewName) {}\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_flutter/lib/src/chart_container.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'package:charts_common/common.dart' as common\n    show\n        A11yNode,\n        AxisDirection,\n        BaseChart,\n        ChartContext,\n        DateTimeFactory,\n        LocalDateTimeFactory,\n        ProxyGestureListener,\n        RTLSpec,\n        SelectionModelType,\n        Series,\n        Performance;\nimport 'package:flutter/material.dart';\nimport 'package:flutter/rendering.dart';\nimport 'package:flutter/scheduler.dart';\nimport 'package:logging/logging.dart';\nimport 'chart_canvas.dart' show ChartCanvas;\nimport 'base_chart.dart' show BaseChart;\nimport 'base_chart_state.dart' show BaseChartState;\nimport 'graphics_factory.dart' show GraphicsFactory;\nimport 'time_series_chart.dart' show TimeSeriesChart;\nimport 'user_managed_state.dart' show UserManagedState;\n\n/// Widget that inflates to a [CustomPaint] that implements common [ChartContext].\nclass ChartContainer<D> extends CustomPaint {\n  final BaseChart<D> chartWidget;\n  final BaseChart<D>? oldChartWidget;\n  final BaseChartState<D> chartState;\n  final double animationValue;\n  final bool rtl;\n  final common.RTLSpec? rtlSpec;\n  final UserManagedState<D>? userManagedState;\n\n  ChartContainer(\n      {this.oldChartWidget,\n      required this.chartWidget,\n      required this.chartState,\n      required this.animationValue,\n      required this.rtl,\n      this.rtlSpec,\n      this.userManagedState});\n\n  @override\n  RenderCustomPaint createRenderObject(BuildContext context) {\n    return new ChartContainerRenderObject<D>()..reconfigure(this, context);\n  }\n\n  @override\n  void updateRenderObject(\n      BuildContext context, ChartContainerRenderObject renderObject) {\n    renderObject.reconfigure(this, context);\n  }\n}\n\n/// [RenderCustomPaint] that implements common [ChartContext].\nclass ChartContainerRenderObject<D> extends RenderCustomPaint\n    implements common.ChartContext {\n  common.BaseChart<D>? _chart;\n  List<common.Series<dynamic, D>>? _seriesList;\n  late BaseChartState<D> _chartState;\n  bool _chartContainerIsRtl = false;\n  common.RTLSpec? _rtlSpec;\n  common.DateTimeFactory? _dateTimeFactory;\n  bool _exploreMode = false;\n  List<common.A11yNode>? _a11yNodes;\n\n  final Logger _log = new Logger('charts_flutter.charts_container');\n\n  /// Keeps the last time the configuration was changed and chart draw on the\n  /// common chart is called.\n  ///\n  /// An assert uses this value to check if the configuration changes more\n  /// frequently than a threshold. This is to notify developers of something\n  /// wrong in the configuration of their charts if it keeps changes (usually\n  /// due to equality checks not being implemented and when a new object is\n  /// created inside a new chart widget, a change is detected even if nothing\n  /// has changed).\n  DateTime? _lastConfigurationChangeTime;\n\n  /// The minimum time required before the next configuration change.\n  static const configurationChangeThresholdMs = 500;\n\n  void reconfigure(ChartContainer<D> config, BuildContext context) {\n    _chartState = config.chartState;\n\n    _dateTimeFactory = (config.chartWidget is TimeSeriesChart)\n        ? (config.chartWidget as TimeSeriesChart).dateTimeFactory\n        : null;\n    _dateTimeFactory ??= new common.LocalDateTimeFactory();\n\n    if (_chart == null) {\n      common.Performance.time('chartsCreate');\n      _chart = config.chartWidget.createCommonChart(_chartState);\n      _chart!.init(this, new GraphicsFactory(context));\n      common.Performance.timeEnd('chartsCreate');\n    }\n    common.Performance.time('chartsConfig');\n    config.chartWidget\n        .updateCommonChart(_chart!, config.oldChartWidget, _chartState);\n\n    _rtlSpec = config.rtlSpec;\n    _chartContainerIsRtl = config.rtl;\n\n    common.Performance.timeEnd('chartsConfig');\n\n    // If the configuration is changed more frequently than the threshold,\n    // log the occurrence and reset the configurationChanged flag to false\n    // to skip calling chart draw and avoid getting into an infinite rebuild\n    // cycle.\n    //\n    // One common cause for the configuration changing on every chart build\n    // is because a behavior is detected to have changed when it has not.\n    // A common case is when a setting is passed to a behavior is an object\n    // and doesn't override the equality checks.\n    if (_chartState.chartIsDirty) {\n      final currentTime = DateTime.now();\n      final lastConfigurationBelowThreshold = _lastConfigurationChangeTime !=\n              null &&\n          currentTime.difference(_lastConfigurationChangeTime!).inMilliseconds <\n              configurationChangeThresholdMs;\n\n      _lastConfigurationChangeTime = currentTime;\n\n      if (lastConfigurationBelowThreshold) {\n        _chartState.resetChartDirtyFlag();\n        _log.warning(\n            'Chart configuration is changing more frequent than threshold'\n            ' of $configurationChangeThresholdMs. Check if your behavior, axis,'\n            ' or renderer config is missing equality checks that may be causing'\n            ' configuration to be detected as changed. ');\n      }\n    }\n\n    if (_chartState.chartIsDirty) {\n      _chart!.configurationChanged();\n    }\n\n    // If series list changes or other configuration changed that triggered the\n    // _chartState.configurationChanged flag to be set (such as axis, behavior,\n    // and renderer changes). Otherwise, the chart only requests repainting and\n    // does not reprocess the series.\n    //\n    // Series list is considered \"changed\" based on the instance.\n    if (_seriesList != config.chartWidget.seriesList ||\n        _chartState.chartIsDirty) {\n      _chartState.resetChartDirtyFlag();\n      _seriesList = config.chartWidget.seriesList;\n\n      // Clear out the a11y nodes generated.\n      _a11yNodes = null;\n\n      common.Performance.time('chartsDraw');\n      _chart!.draw(_seriesList!);\n      common.Performance.timeEnd('chartsDraw');\n\n      // This is needed because when a series changes we need to reset flutter's\n      // animation value from 1.0 back to 0.0.\n      _chart!.animationPercent = 0.0;\n      markNeedsLayout();\n    } else {\n      _chart!.animationPercent = config.animationValue;\n      markNeedsPaint();\n    }\n\n    _updateUserManagedState(config.userManagedState);\n\n    // Set the painter used for calling common chart for paint.\n    // This painter is also used to generate semantic nodes for a11y.\n    _setNewPainter();\n  }\n\n  /// If user managed state is set, check each setting to see if it is different\n  /// than internal chart state and only update if different.\n  _updateUserManagedState(UserManagedState<D>? newState) {\n    if (newState == null) {\n      return;\n    }\n\n    // Only override the selection model if it is different than the existing\n    // selection model so update listeners are not unnecessarily triggered.\n    for (common.SelectionModelType type in newState.selectionModels.keys) {\n      final model = _chart!.getSelectionModel(type);\n\n      final userModel =\n          newState.selectionModels[type]!.getModel(_chart!.currentSeriesList);\n\n      if (model != userModel) {\n        model.updateSelection(\n            userModel.selectedDatum, userModel.selectedSeries);\n      }\n    }\n  }\n\n  @override\n  void performLayout() {\n    common.Performance.time('chartsLayout');\n    _chart!\n        .measure(constraints.maxWidth.toInt(), constraints.maxHeight.toInt());\n    _chart!.layout(constraints.maxWidth.toInt(), constraints.maxHeight.toInt());\n    common.Performance.timeEnd('chartsLayout');\n    size = constraints.biggest;\n\n    // Check if the gestures registered in gesture registry matches what the\n    // common chart is listening to.\n    // TODO: Still need a test for this for sanity sake.\n//    assert(_desiredGestures\n//        .difference(_chart!.gestureProxy.listenedGestures)\n//        .isEmpty);\n  }\n\n  @override\n  void markNeedsLayout() {\n    super.markNeedsLayout();\n    if (parent != null) {\n      markParentNeedsLayout();\n    }\n  }\n\n  @override\n  bool hitTestSelf(Offset position) => true;\n\n  @override\n  void requestRedraw() {}\n\n  @override\n  void requestAnimation(Duration transition) {\n    void startAnimationController(_) {\n      _chartState.setAnimation(transition);\n    }\n\n    // Sometimes chart behaviors try to draw the chart outside of a Flutter draw\n    // cycle. Schedule a frame manually to handle these cases.\n    if (!SchedulerBinding.instance!.hasScheduledFrame) {\n      SchedulerBinding.instance!.scheduleFrame();\n    }\n\n    SchedulerBinding.instance!.addPostFrameCallback(startAnimationController);\n  }\n\n  /// Request Flutter to rebuild the widget/container of chart.\n  ///\n  /// This is different than requesting redraw and paint because those only\n  /// affect the chart widget. This is for requesting rebuild of the Flutter\n  /// widget that contains the chart widget. This is necessary for supporting\n  /// Flutter widgets that are layout with the chart.\n  ///\n  /// Example is legends, a legend widget can be layout on top of the chart\n  /// widget or along the sides of the chart. Requesting a rebuild allows\n  /// the legend to layout and redraw itself.\n  void requestRebuild() {\n    void doRebuild(_) {\n      _chartState.requestRebuild();\n    }\n\n    // Flutter does not allow requesting rebuild during the build cycle, this\n    // schedules rebuild request to happen after the current build cycle.\n    // This is needed to request rebuild after the legend has been added in the\n    // post process phase of the chart, which happens during the chart widget's\n    // build cycle.\n    SchedulerBinding.instance!.addPostFrameCallback(doRebuild);\n  }\n\n  /// When Flutter's markNeedsLayout is called, layout and paint are both\n  /// called. If animations are off, Flutter's paint call after layout will\n  /// paint the chart. If animations are on, Flutter's paint is called with the\n  /// initial animation value and then the animation controller is started after\n  /// this first build cycle.\n  @override\n  void requestPaint() {\n    markNeedsPaint();\n  }\n\n  @override\n  double get pixelsPerDp => 1.0;\n\n  @override\n  bool get chartContainerIsRtl => _chartContainerIsRtl;\n\n  @override\n  common.RTLSpec? get rtlSpec => _rtlSpec;\n\n  @override\n  bool get isRtl =>\n      _chartContainerIsRtl &&\n      (_rtlSpec == null ||\n          _rtlSpec?.axisDirection == common.AxisDirection.reversed);\n\n  @override\n  bool get isTappable => _chart!.isTappable;\n\n  @override\n  common.DateTimeFactory get dateTimeFactory => _dateTimeFactory!;\n\n  /// Gets the chart's gesture listener.\n  common.ProxyGestureListener get gestureProxy => _chart!.gestureProxy;\n\n  TextDirection get textDirection =>\n      _chartContainerIsRtl ? TextDirection.rtl : TextDirection.ltr;\n\n  @override\n  void enableA11yExploreMode(List<common.A11yNode> nodes,\n      {String? announcement}) {\n    _a11yNodes = nodes;\n    _exploreMode = true;\n    _setNewPainter();\n    requestRebuild();\n    if (announcement != null) {\n      SemanticsService.announce(announcement, textDirection);\n    }\n  }\n\n  @override\n  void disableA11yExploreMode({String? announcement}) {\n    _a11yNodes = [];\n    _exploreMode = false;\n    _setNewPainter();\n    requestRebuild();\n    if (announcement != null) {\n      SemanticsService.announce(announcement, textDirection);\n    }\n  }\n\n  void _setNewPainter() {\n    painter = new ChartContainerCustomPaint(\n        oldPainter: painter as ChartContainerCustomPaint?,\n        chart: _chart!,\n        exploreMode: _exploreMode,\n        a11yNodes: _a11yNodes ?? [],\n        textDirection: textDirection);\n  }\n}\n\nclass ChartContainerCustomPaint extends CustomPainter {\n  final common.BaseChart chart;\n  final bool exploreMode;\n  final List<common.A11yNode> a11yNodes;\n  final TextDirection textDirection;\n\n  factory ChartContainerCustomPaint(\n      {ChartContainerCustomPaint? oldPainter,\n      required common.BaseChart chart,\n      bool exploreMode = false,\n      List<common.A11yNode> a11yNodes = const [],\n      TextDirection textDirection = TextDirection.ltr}) {\n    if (oldPainter != null &&\n        oldPainter.exploreMode == exploreMode &&\n        oldPainter.a11yNodes == a11yNodes &&\n        oldPainter.textDirection == textDirection) {\n      return oldPainter;\n    } else {\n      return new ChartContainerCustomPaint._internal(\n          chart: chart,\n          exploreMode: exploreMode,\n          a11yNodes: a11yNodes,\n          textDirection: textDirection);\n    }\n  }\n\n  ChartContainerCustomPaint._internal(\n      {required this.chart,\n      required this.exploreMode,\n      required this.a11yNodes,\n      required this.textDirection});\n\n  @override\n  void paint(Canvas canvas, Size size) {\n    common.Performance.time('chartsPaint');\n    final chartsCanvas = new ChartCanvas(canvas, chart.graphicsFactory!);\n    chart.paint(chartsCanvas);\n    common.Performance.timeEnd('chartsPaint');\n  }\n\n  /// Common chart requests rebuild that handle repaint requests.\n  @override\n  bool shouldRepaint(ChartContainerCustomPaint oldPainter) => false;\n\n  /// Rebuild semantics when explore mode is toggled semantic properties change.\n  @override\n  bool shouldRebuildSemantics(ChartContainerCustomPaint oldDelegate) {\n    return exploreMode != oldDelegate.exploreMode ||\n        a11yNodes != oldDelegate.a11yNodes ||\n        textDirection != textDirection;\n  }\n\n  @override\n  SemanticsBuilderCallback get semanticsBuilder => _buildSemantics;\n\n  List<CustomPainterSemantics> _buildSemantics(Size size) {\n    final nodes = <CustomPainterSemantics>[];\n\n    for (common.A11yNode node in a11yNodes) {\n      final rect = new Rect.fromLTWH(\n          node.boundingBox.left.toDouble(),\n          node.boundingBox.top.toDouble(),\n          node.boundingBox.width.toDouble(),\n          node.boundingBox.height.toDouble());\n      nodes.add(new CustomPainterSemantics(\n          rect: rect,\n          properties: new SemanticsProperties(\n              value: node.label,\n              textDirection: textDirection,\n              onDidGainAccessibilityFocus: node.onFocus)));\n    }\n\n    return nodes;\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_flutter/lib/src/chart_gesture_detector.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:async' show Timer;\nimport 'dart:math' show Point;\nimport 'package:flutter/material.dart'\n    show\n        BuildContext,\n        GestureDetector,\n        RenderBox,\n        ScaleEndDetails,\n        ScaleStartDetails,\n        ScaleUpdateDetails,\n        TapDownDetails,\n        TapUpDetails;\n\nimport 'behaviors/chart_behavior.dart' show GestureType;\nimport 'chart_container.dart' show ChartContainer, ChartContainerRenderObject;\nimport 'util.dart' show getChartContainerRenderObject;\n\n// From https://docs.flutter.io/flutter/gestures/kLongPressTimeout-constant.html\nconst Duration _kLongPressTimeout = const Duration(milliseconds: 500);\n\nclass ChartGestureDetector {\n  bool _listeningForLongPress = false;\n\n  bool _isDragging = false;\n\n  Timer? _longPressTimer;\n  Point<double>? _lastTapPoint;\n  double? _lastScale;\n\n  late _ContainerResolver _containerResolver;\n\n  makeWidget(BuildContext context, ChartContainer chartContainer,\n      Set<GestureType> desiredGestures) {\n    _containerResolver = () {\n      final renderObject = context.findRenderObject()!;\n\n      return getChartContainerRenderObject(renderObject as RenderBox);\n    };\n\n    final wantTapDown = desiredGestures.isNotEmpty;\n    final wantTap = desiredGestures.contains(GestureType.onTap);\n    final wantDrag = desiredGestures.contains(GestureType.onDrag);\n\n    // LongPress is special, we'd like to be able to trigger long press before\n    // Drag/Press to trigger tooltips then explore with them. This means we\n    // can't rely on gesture detection since it will block out the scale\n    // gestures.\n    _listeningForLongPress = desiredGestures.contains(GestureType.onLongPress);\n\n    return new GestureDetector(\n      child: chartContainer,\n      onTapDown: wantTapDown ? onTapDown : null,\n      onTapUp: wantTap ? onTapUp : null,\n      onScaleStart: wantDrag ? onScaleStart : null,\n      onScaleUpdate: wantDrag ? onScaleUpdate : null,\n      onScaleEnd: wantDrag ? onScaleEnd : null,\n    );\n  }\n\n  void onTapDown(TapDownDetails d) {\n    final container = _containerResolver();\n    final localPosition = container.globalToLocal(d.globalPosition);\n    _lastTapPoint = new Point(localPosition.dx, localPosition.dy);\n    container.gestureProxy.onTapTest(_lastTapPoint!);\n\n    // Kick off a timer to see if this is a LongPress.\n    if (_listeningForLongPress) {\n      _longPressTimer = new Timer(_kLongPressTimeout, () {\n        onLongPress();\n        _longPressTimer = null;\n      });\n    }\n  }\n\n  void onTapUp(TapUpDetails d) {\n    _longPressTimer?.cancel();\n\n    final container = _containerResolver();\n    final localPosition = container.globalToLocal(d.globalPosition);\n    _lastTapPoint = new Point(localPosition.dx, localPosition.dy);\n    container.gestureProxy.onTap(_lastTapPoint!);\n  }\n\n  void onLongPress() {\n    final container = _containerResolver();\n    container.gestureProxy.onLongPress(_lastTapPoint!);\n  }\n\n  void onScaleStart(ScaleStartDetails d) {\n    _longPressTimer?.cancel();\n\n    final container = _containerResolver();\n    final localPosition = container.globalToLocal(d.focalPoint);\n    _lastTapPoint = new Point(localPosition.dx, localPosition.dy);\n\n    _isDragging = container.gestureProxy.onDragStart(_lastTapPoint!);\n  }\n\n  void onScaleUpdate(ScaleUpdateDetails d) {\n    if (!_isDragging) {\n      return;\n    }\n\n    final container = _containerResolver();\n    final localPosition = container.globalToLocal(d.focalPoint);\n    _lastTapPoint = new Point(localPosition.dx, localPosition.dy);\n    _lastScale = d.scale;\n\n    container.gestureProxy.onDragUpdate(_lastTapPoint!, d.scale);\n  }\n\n  void onScaleEnd(ScaleEndDetails d) {\n    if (!_isDragging) {\n      return;\n    }\n\n    final container = _containerResolver();\n\n    container.gestureProxy\n        .onDragEnd(_lastTapPoint!, _lastScale!, d.velocity.pixelsPerSecond.dx);\n  }\n}\n\n// Exposed for testing.\ntypedef ChartContainerRenderObject _ContainerResolver();\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_flutter/lib/src/chart_state.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nabstract class ChartState {\n  void setAnimation(Duration transition);\n\n  /// Request to the native platform to rebuild the chart.\n  void requestRebuild();\n\n  /// Informs the chart that the configuration has changed.\n  ///\n  /// This flag is set by checks that detect if a configuration has changed,\n  /// such as behaviors, axis, and renderers.\n  ///\n  /// This flag is read on chart rebuild, if chart is marked as dirty, then the\n  /// chart will call a base chart draw.\n  void markChartDirty();\n\n  /// Reset the chart dirty flag.\n  void resetChartDirtyFlag();\n\n  /// Gets if the chart is dirty.\n  bool get chartIsDirty;\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_flutter/lib/src/combo_chart/combo_chart.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'package:charts_common/common.dart' as common\n    show\n        AxisSpec,\n        NumericCartesianChart,\n        OrdinalCartesianChart,\n        NumericAxisSpec,\n        RTLSpec,\n        Series,\n        SeriesRendererConfig;\nimport '../behaviors/chart_behavior.dart' show ChartBehavior;\nimport '../base_chart.dart' show LayoutConfig;\nimport '../base_chart_state.dart' show BaseChartState;\nimport '../cartesian_chart.dart' show CartesianChart;\nimport '../selection_model_config.dart' show SelectionModelConfig;\n\n/// A numeric combo chart supports rendering each series of data with different\n/// series renderers.\n///\n/// Note that if you have DateTime data, you should use [TimeSeriesChart]. We do\n/// not expose a separate DateTimeComboChart because it would just be a copy of\n/// that chart.\nclass NumericComboChart extends CartesianChart<num> {\n  NumericComboChart(\n    List<common.Series<dynamic, num>> seriesList, {\n    bool? animate,\n    Duration? animationDuration,\n    common.AxisSpec? domainAxis,\n    common.NumericAxisSpec? primaryMeasureAxis,\n    common.NumericAxisSpec? secondaryMeasureAxis,\n    common.SeriesRendererConfig<num>? defaultRenderer,\n    List<common.SeriesRendererConfig<num>>? customSeriesRenderers,\n    List<ChartBehavior<num>>? behaviors,\n    List<SelectionModelConfig<num>>? selectionModels,\n    common.RTLSpec? rtlSpec,\n    LayoutConfig? layoutConfig,\n    bool defaultInteractions = true,\n  }) : super(\n          seriesList,\n          animate: animate,\n          animationDuration: animationDuration,\n          domainAxis: domainAxis,\n          primaryMeasureAxis: primaryMeasureAxis,\n          secondaryMeasureAxis: secondaryMeasureAxis,\n          defaultRenderer: defaultRenderer,\n          customSeriesRenderers: customSeriesRenderers,\n          behaviors: behaviors,\n          selectionModels: selectionModels,\n          rtlSpec: rtlSpec,\n          layoutConfig: layoutConfig,\n          defaultInteractions: defaultInteractions,\n        );\n\n  @override\n  common.NumericCartesianChart createCommonChart(BaseChartState chartState) {\n    // Optionally create primary and secondary measure axes if the chart was\n    // configured with them. If no axes were configured, then the chart will\n    // use its default types (usually a numeric axis).\n    return new common.NumericCartesianChart(\n        layoutConfig: layoutConfig?.commonLayoutConfig,\n        primaryMeasureAxis: primaryMeasureAxis?.createAxis(),\n        secondaryMeasureAxis: secondaryMeasureAxis?.createAxis());\n  }\n}\n\n/// An ordinal combo chart supports rendering each series of data with different\n/// series renderers.\nclass OrdinalComboChart extends CartesianChart<String> {\n  OrdinalComboChart(\n    List<common.Series<dynamic, String>> seriesList, {\n    bool? animate,\n    Duration? animationDuration,\n    common.AxisSpec? domainAxis,\n    common.NumericAxisSpec? primaryMeasureAxis,\n    common.NumericAxisSpec? secondaryMeasureAxis,\n    common.SeriesRendererConfig<String>? defaultRenderer,\n    List<common.SeriesRendererConfig<String>>? customSeriesRenderers,\n    List<ChartBehavior<String>>? behaviors,\n    List<SelectionModelConfig<String>>? selectionModels,\n    common.RTLSpec? rtlSpec,\n    LayoutConfig? layoutConfig,\n    bool defaultInteractions = true,\n  }) : super(\n          seriesList,\n          animate: animate,\n          animationDuration: animationDuration,\n          domainAxis: domainAxis,\n          primaryMeasureAxis: primaryMeasureAxis,\n          secondaryMeasureAxis: secondaryMeasureAxis,\n          defaultRenderer: defaultRenderer,\n          customSeriesRenderers: customSeriesRenderers,\n          behaviors: behaviors,\n          selectionModels: selectionModels,\n          rtlSpec: rtlSpec,\n          layoutConfig: layoutConfig,\n          defaultInteractions: defaultInteractions,\n        );\n\n  @override\n  common.OrdinalCartesianChart createCommonChart(BaseChartState chartState) {\n    // Optionally create primary and secondary measure axes if the chart was\n    // configured with them. If no axes were configured, then the chart will\n    // use its default types (usually a numeric axis).\n    return new common.OrdinalCartesianChart(\n        layoutConfig: layoutConfig?.commonLayoutConfig,\n        primaryMeasureAxis: primaryMeasureAxis?.createAxis(),\n        secondaryMeasureAxis: secondaryMeasureAxis?.createAxis());\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_flutter/lib/src/graphics_factory.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'package:charts_common/common.dart' as common\n    show GraphicsFactory, LineStyle, TextElement, TextStyle;\nimport 'package:flutter/widgets.dart'\n    show BuildContext, DefaultTextStyle, MediaQuery;\nimport 'line_style.dart' show LineStyle;\nimport 'text_element.dart' show TextElement;\nimport 'text_style.dart' show TextStyle;\n\nclass GraphicsFactory implements common.GraphicsFactory {\n  final double textScaleFactor;\n  final DefaultTextStyle defaultTextStyle;\n\n  GraphicsFactory(BuildContext context,\n      {GraphicsFactoryHelper helper = const GraphicsFactoryHelper()})\n      : textScaleFactor = helper.getTextScaleFactorOf(context),\n        defaultTextStyle = DefaultTextStyle.of(context);\n\n  /// Returns a [TextStyle] object.\n  @override\n  common.TextStyle createTextPaint() =>\n      TextStyle()..fontFamily = defaultTextStyle.style.fontFamily;\n\n  /// Returns a text element from [text].\n  @override\n  common.TextElement createTextElement(String text) {\n    return TextElement(text, textScaleFactor: textScaleFactor)\n      ..textStyle = createTextPaint();\n  }\n\n  @override\n  common.LineStyle createLinePaint() => LineStyle();\n}\n\n/// Wraps the MediaQuery function to allow for testing.\nclass GraphicsFactoryHelper {\n  const GraphicsFactoryHelper();\n\n  double getTextScaleFactorOf(BuildContext context) =>\n      MediaQuery.textScaleFactorOf(context);\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_flutter/lib/src/line_chart.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:collection' show LinkedHashMap;\n\nimport 'package:charts_common/common.dart' as common\n    show\n        AxisSpec,\n        LineChart,\n        NumericAxisSpec,\n        RTLSpec,\n        Series,\n        LineRendererConfig,\n        SeriesRendererConfig;\nimport 'behaviors/line_point_highlighter.dart' show LinePointHighlighter;\nimport 'behaviors/chart_behavior.dart' show ChartBehavior;\nimport 'base_chart.dart' show LayoutConfig;\nimport 'base_chart_state.dart' show BaseChartState;\nimport 'cartesian_chart.dart' show CartesianChart;\nimport 'selection_model_config.dart' show SelectionModelConfig;\nimport 'user_managed_state.dart' show UserManagedState;\n\nclass LineChart extends CartesianChart<num> {\n  LineChart(\n    List<common.Series<dynamic, num>> seriesList, {\n    bool? animate,\n    Duration? animationDuration,\n    common.AxisSpec? domainAxis,\n    common.NumericAxisSpec? primaryMeasureAxis,\n    common.NumericAxisSpec? secondaryMeasureAxis,\n    LinkedHashMap<String, common.NumericAxisSpec>? disjointMeasureAxes,\n    common.LineRendererConfig<num>? defaultRenderer,\n    List<common.SeriesRendererConfig<num>>? customSeriesRenderers,\n    List<ChartBehavior<num>>? behaviors,\n    List<SelectionModelConfig<num>>? selectionModels,\n    common.RTLSpec? rtlSpec,\n    LayoutConfig? layoutConfig,\n    bool defaultInteractions = true,\n    bool? flipVerticalAxis,\n    UserManagedState<num>? userManagedState,\n  }) : super(\n          seriesList,\n          animate: animate,\n          animationDuration: animationDuration,\n          domainAxis: domainAxis,\n          primaryMeasureAxis: primaryMeasureAxis,\n          secondaryMeasureAxis: secondaryMeasureAxis,\n          disjointMeasureAxes: disjointMeasureAxes,\n          defaultRenderer: defaultRenderer,\n          customSeriesRenderers: customSeriesRenderers,\n          behaviors: behaviors,\n          selectionModels: selectionModels,\n          rtlSpec: rtlSpec,\n          layoutConfig: layoutConfig,\n          defaultInteractions: defaultInteractions,\n          flipVerticalAxis: flipVerticalAxis,\n          userManagedState: userManagedState,\n        );\n\n  @override\n  common.LineChart createCommonChart(BaseChartState chartState) {\n    // Optionally create primary and secondary measure axes if the chart was\n    // configured with them. If no axes were configured, then the chart will\n    // use its default types (usually a numeric axis).\n    return new common.LineChart(\n        layoutConfig: layoutConfig?.commonLayoutConfig,\n        primaryMeasureAxis: primaryMeasureAxis?.createAxis(),\n        secondaryMeasureAxis: secondaryMeasureAxis?.createAxis(),\n        disjointMeasureAxes: createDisjointMeasureAxes());\n  }\n\n  @override\n  void addDefaultInteractions(List<ChartBehavior> behaviors) {\n    super.addDefaultInteractions(behaviors);\n\n    behaviors.add(new LinePointHighlighter<num>());\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_flutter/lib/src/line_style.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'package:charts_common/common.dart' as common show Color, LineStyle;\n\nclass LineStyle implements common.LineStyle {\n  @override\n  common.Color? color;\n\n  @override\n  List<int>? dashPattern;\n\n  @override\n  int strokeWidth;\n\n  LineStyle({this.strokeWidth = 0});\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_flutter/lib/src/pie_chart.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'package:charts_common/common.dart' as common\n    show ArcRendererConfig, PieChart, RTLSpec, Series;\nimport 'behaviors/chart_behavior.dart' show ChartBehavior;\nimport 'base_chart.dart' show BaseChart, LayoutConfig;\nimport 'base_chart_state.dart' show BaseChartState;\nimport 'selection_model_config.dart' show SelectionModelConfig;\n\nclass PieChart<D> extends BaseChart<D> {\n  PieChart(\n    List<common.Series<dynamic, D>> seriesList, {\n    bool? animate,\n    Duration? animationDuration,\n    common.ArcRendererConfig<D>? defaultRenderer,\n    List<ChartBehavior<D>>? behaviors,\n    List<SelectionModelConfig<D>>? selectionModels,\n    common.RTLSpec? rtlSpec,\n    LayoutConfig? layoutConfig,\n    bool defaultInteractions = true,\n  }) : super(\n          seriesList,\n          animate: animate,\n          animationDuration: animationDuration,\n          defaultRenderer: defaultRenderer,\n          behaviors: behaviors,\n          selectionModels: selectionModels,\n          rtlSpec: rtlSpec,\n          layoutConfig: layoutConfig,\n          defaultInteractions: defaultInteractions,\n        );\n\n  @override\n  common.PieChart<D> createCommonChart(BaseChartState chartState) =>\n      new common.PieChart<D>(layoutConfig: layoutConfig?.commonLayoutConfig);\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_flutter/lib/src/scatter_plot_chart.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:collection' show LinkedHashMap;\n\nimport 'package:charts_common/common.dart' as common\n    show\n        AxisSpec,\n        NumericAxisSpec,\n        PointRendererConfig,\n        RTLSpec,\n        ScatterPlotChart,\n        SeriesRendererConfig,\n        Series;\nimport 'behaviors/chart_behavior.dart' show ChartBehavior;\nimport 'base_chart.dart' show LayoutConfig;\nimport 'base_chart_state.dart' show BaseChartState;\nimport 'cartesian_chart.dart' show CartesianChart;\nimport 'selection_model_config.dart' show SelectionModelConfig;\nimport 'user_managed_state.dart' show UserManagedState;\n\nclass ScatterPlotChart extends CartesianChart<num> {\n  ScatterPlotChart(\n    List<common.Series<dynamic, num>> seriesList, {\n    bool? animate,\n    Duration? animationDuration,\n    common.AxisSpec? domainAxis,\n    common.NumericAxisSpec? primaryMeasureAxis,\n    common.NumericAxisSpec? secondaryMeasureAxis,\n    LinkedHashMap<String, common.NumericAxisSpec>? disjointMeasureAxes,\n    common.PointRendererConfig<num>? defaultRenderer,\n    List<common.SeriesRendererConfig<num>>? customSeriesRenderers,\n    List<ChartBehavior<num>>? behaviors,\n    List<SelectionModelConfig<num>>? selectionModels,\n    common.RTLSpec? rtlSpec,\n    LayoutConfig? layoutConfig,\n    bool defaultInteractions = true,\n    bool? flipVerticalAxis,\n    UserManagedState<num>? userManagedState,\n  }) : super(\n          seriesList,\n          animate: animate,\n          animationDuration: animationDuration,\n          domainAxis: domainAxis,\n          primaryMeasureAxis: primaryMeasureAxis,\n          secondaryMeasureAxis: secondaryMeasureAxis,\n          disjointMeasureAxes: disjointMeasureAxes,\n          defaultRenderer: defaultRenderer,\n          customSeriesRenderers: customSeriesRenderers,\n          behaviors: behaviors,\n          selectionModels: selectionModels,\n          rtlSpec: rtlSpec,\n          layoutConfig: layoutConfig,\n          defaultInteractions: defaultInteractions,\n          flipVerticalAxis: flipVerticalAxis,\n          userManagedState: userManagedState,\n        );\n\n  @override\n  common.ScatterPlotChart createCommonChart(BaseChartState chartState) {\n    // Optionally create primary and secondary measure axes if the chart was\n    // configured with them. If no axes were configured, then the chart will\n    // use its default types (usually a numeric axis).\n    return new common.ScatterPlotChart(\n        layoutConfig: layoutConfig?.commonLayoutConfig,\n        primaryMeasureAxis: primaryMeasureAxis?.createAxis(),\n        secondaryMeasureAxis: secondaryMeasureAxis?.createAxis(),\n        disjointMeasureAxes: createDisjointMeasureAxes());\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_flutter/lib/src/selection_model_config.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'package:meta/meta.dart' show immutable;\n\nimport 'package:charts_common/common.dart' as common;\n\n@immutable\nclass SelectionModelConfig<D> {\n  final common.SelectionModelType type;\n\n  /// Listens for change in selection.\n  final common.SelectionModelListener<D>? changedListener;\n\n  /// Listens anytime update selection is called.\n  final common.SelectionModelListener<D>? updatedListener;\n\n  SelectionModelConfig(\n      {this.type = common.SelectionModelType.info,\n      this.changedListener,\n      this.updatedListener});\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_flutter/lib/src/symbol_renderer.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:math' show Rectangle;\nimport 'package:charts_common/common.dart' as common\n    show ChartCanvas, Color, FillPatternType, SymbolRenderer;\nimport 'package:flutter/widgets.dart';\nimport 'chart_canvas.dart' show ChartCanvas;\nimport 'graphics_factory.dart' show GraphicsFactory;\n\n/// Flutter widget responsible for painting a common SymbolRenderer from the\n/// chart.\n///\n/// If you want to customize the symbol, then use [CustomSymbolRenderer].\nclass SymbolRendererCanvas implements SymbolRendererBuilder {\n  final common.SymbolRenderer commonSymbolRenderer;\n  final List<int>? dashPattern;\n\n  SymbolRendererCanvas(this.commonSymbolRenderer, this.dashPattern);\n\n  @override\n  Widget build(BuildContext context,\n      {Color? color, required Size size, bool enabled = true}) {\n    if (color != null && !enabled) {\n      color = color.withOpacity(0.26);\n    }\n\n    return new SizedBox.fromSize(\n        size: size,\n        child: new CustomPaint(\n            painter: new _SymbolCustomPaint(\n                context, commonSymbolRenderer, color, dashPattern)));\n  }\n}\n\n/// Convenience class allowing you to pass your Widget builder through the\n/// common chart so that it is created for you by the Legend.\n///\n/// This allows a custom SymbolRenderer in Flutter without having to create\n/// a completely custom legend.\nabstract class CustomSymbolRenderer extends common.SymbolRenderer\n    implements SymbolRendererBuilder {\n  CustomSymbolRenderer() : super(isSolid: false);\n\n  /// Must override this method to build the custom Widget with the given color\n  /// as\n  @override\n  Widget build(BuildContext context,\n      {Color? color, required Size size, bool enabled = true});\n\n  @override\n  void paint(common.ChartCanvas canvas, Rectangle<num> bounds,\n      {List<int>? dashPattern,\n      common.Color? fillColor,\n      common.FillPatternType? fillPattern,\n      common.Color? strokeColor,\n      double? strokeWidthPx}) {\n    // Intentionally ignored (never called).\n  }\n\n  @override\n  bool shouldRepaint(common.SymbolRenderer oldRenderer) {\n    return false; // Repainting is handled directly in Flutter.\n  }\n}\n\n/// Common interface for [CustomSymbolRenderer] & [SymbolRendererCanvas] for\n/// convenience for [LegendEntryLayout].\nabstract class SymbolRendererBuilder {\n  Widget build(BuildContext context,\n      {Color? color, required Size size, bool enabled});\n}\n\n/// The Widget which fulfills the guts of [SymbolRendererCanvas] actually\n/// painting the symbol to a canvas using [CustomPainter].\nclass _SymbolCustomPaint extends CustomPainter {\n  final BuildContext context;\n  final common.SymbolRenderer symbolRenderer;\n  final Color? color;\n  final List<int>? dashPattern;\n\n  _SymbolCustomPaint(\n      this.context, this.symbolRenderer, this.color, this.dashPattern);\n\n  @override\n  void paint(Canvas canvas, Size size) {\n    final bounds =\n        new Rectangle<num>(0, 0, size.width.toInt(), size.height.toInt());\n    final commonColor = color == null\n        ? null\n        : new common.Color(\n            r: color!.red, g: color!.green, b: color!.blue, a: color!.alpha);\n    symbolRenderer.paint(\n        new ChartCanvas(canvas, GraphicsFactory(context)), bounds,\n        fillColor: commonColor,\n        strokeColor: commonColor,\n        dashPattern: dashPattern);\n  }\n\n  @override\n  bool shouldRepaint(_SymbolCustomPaint oldDelegate) {\n    return symbolRenderer.shouldRepaint(oldDelegate.symbolRenderer);\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_flutter/lib/src/text_element.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:ui' show TextAlign, TextDirection;\nimport 'package:charts_common/common.dart' as common\n    show\n        MaxWidthStrategy,\n        TextElement,\n        TextDirection,\n        TextMeasurement,\n        TextStyle;\nimport 'package:flutter/rendering.dart'\n    show Color, TextBaseline, TextPainter, TextSpan, TextStyle;\n\n/// Flutter implementation for text measurement and painter.\nclass TextElement implements common.TextElement {\n  static const ellipsis = '\\u{2026}';\n\n  @override\n  final String text;\n\n  final double? textScaleFactor;\n\n  var _painterReady = false;\n  common.TextStyle? _textStyle;\n  common.TextDirection _textDirection = common.TextDirection.ltr;\n\n  int? _maxWidth;\n  common.MaxWidthStrategy? _maxWidthStrategy;\n\n  late TextPainter _textPainter;\n\n  late common.TextMeasurement _measurement;\n\n  double? _opacity;\n\n  TextElement(this.text, {common.TextStyle? style, this.textScaleFactor})\n      : _textStyle = style;\n\n  @override\n  common.TextStyle? get textStyle => _textStyle;\n\n  @override\n  set textStyle(common.TextStyle? value) {\n    if (_textStyle == value) {\n      return;\n    }\n    _textStyle = value;\n    _painterReady = false;\n  }\n\n  @override\n  set textDirection(common.TextDirection direction) {\n    if (_textDirection == direction) {\n      return;\n    }\n    _textDirection = direction;\n    _painterReady = false;\n  }\n\n  @override\n  common.TextDirection get textDirection => _textDirection;\n\n  @override\n  int? get maxWidth => _maxWidth;\n\n  @override\n  set maxWidth(int? value) {\n    if (_maxWidth == value) {\n      return;\n    }\n    _maxWidth = value;\n    _painterReady = false;\n  }\n\n  @override\n  common.MaxWidthStrategy? get maxWidthStrategy => _maxWidthStrategy;\n\n  @override\n  set maxWidthStrategy(common.MaxWidthStrategy? maxWidthStrategy) {\n    if (_maxWidthStrategy == maxWidthStrategy) {\n      return;\n    }\n    _maxWidthStrategy = maxWidthStrategy;\n    _painterReady = false;\n  }\n\n  @override\n  set opacity(double? opacity) {\n    if (opacity != _opacity) {\n      _painterReady = false;\n      _opacity = opacity;\n    }\n  }\n\n  @override\n  common.TextMeasurement get measurement {\n    if (!_painterReady) {\n      _refreshPainter();\n    }\n\n    return _measurement;\n  }\n\n  /// The estimated distance between where we asked to draw the text (top, left)\n  /// and where it visually started (top + verticalFontShift, left).\n  ///\n  /// 10% of reported font height seems to be about right.\n  int get verticalFontShift {\n    if (!_painterReady) {\n      _refreshPainter();\n    }\n\n    return (_textPainter.height * 0.1).ceil();\n  }\n\n  TextPainter? get textPainter {\n    if (!_painterReady) {\n      _refreshPainter();\n    }\n    return _textPainter;\n  }\n\n  /// Create text painter and measure based on current settings\n  void _refreshPainter() {\n    _opacity ??= 1.0;\n    var color = (textStyle == null || textStyle!.color == null)\n        ? null\n        : new Color.fromARGB(\n            (textStyle!.color!.a * _opacity!).round(),\n            textStyle!.color!.r,\n            textStyle!.color!.g,\n            textStyle!.color!.b,\n          );\n\n    _textPainter = new TextPainter(\n        text: new TextSpan(\n            text: text,\n            style: new TextStyle(\n                color: color,\n                fontSize: textStyle?.fontSize?.toDouble(),\n                fontFamily: textStyle?.fontFamily,\n                height: textStyle?.lineHeight)))\n      ..textDirection = TextDirection.ltr\n      // TODO Flip once textAlign works\n      ..textAlign = TextAlign.left\n      // ..textAlign = _textDirection == common.TextDirection.rtl ?\n      //     TextAlign.right : TextAlign.left\n      ..ellipsis = maxWidthStrategy == common.MaxWidthStrategy.ellipsize\n          ? ellipsis\n          : null;\n\n    if (textScaleFactor != null) {\n      _textPainter.textScaleFactor = textScaleFactor!;\n    }\n\n    _textPainter.layout(maxWidth: maxWidth?.toDouble() ?? double.infinity);\n\n    final baseline =\n        _textPainter.computeDistanceToActualBaseline(TextBaseline.alphabetic);\n\n    // Estimating the actual draw height to 70% of measures size.\n    //\n    // The font reports a size larger than the drawn size, which makes it\n    // difficult to shift the text around to get it to visually line up\n    // vertically with other components.\n    _measurement = new common.TextMeasurement(\n        horizontalSliceWidth: _textPainter.width,\n        verticalSliceWidth: _textPainter.height * 0.70,\n        baseline: baseline);\n\n    _painterReady = true;\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_flutter/lib/src/text_style.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:ui' show hashValues;\nimport 'package:charts_common/common.dart' as common show Color, TextStyle;\n\nclass TextStyle implements common.TextStyle {\n  int? fontSize;\n  String? fontFamily;\n  common.Color? color;\n  double? lineHeight;\n\n  @override\n  bool operator ==(Object other) =>\n      other is TextStyle &&\n      fontSize == other.fontSize &&\n      fontFamily == other.fontFamily &&\n      color == other.color &&\n      lineHeight == other.lineHeight;\n\n  @override\n  int get hashCode => hashValues(fontSize, fontFamily, color, lineHeight);\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_flutter/lib/src/time_series_chart.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:collection' show LinkedHashMap;\n\nimport 'package:charts_common/common.dart' as common\n    show\n        AxisSpec,\n        DateTimeFactory,\n        LocalDateTimeFactory,\n        NumericAxisSpec,\n        Series,\n        SeriesRendererConfig,\n        TimeSeriesChart;\nimport 'behaviors/chart_behavior.dart' show ChartBehavior;\nimport 'behaviors/line_point_highlighter.dart' show LinePointHighlighter;\nimport 'cartesian_chart.dart' show CartesianChart;\nimport 'base_chart.dart' show LayoutConfig;\nimport 'base_chart_state.dart' show BaseChartState;\nimport 'selection_model_config.dart' show SelectionModelConfig;\nimport 'user_managed_state.dart' show UserManagedState;\n\nclass TimeSeriesChart extends CartesianChart<DateTime> {\n  final common.DateTimeFactory? dateTimeFactory;\n\n  /// Create a [TimeSeriesChart].\n  ///\n  /// [dateTimeFactory] allows specifying a factory that creates [DateTime] to\n  /// be used for the time axis. If none specified, local date time is used.\n  TimeSeriesChart(\n    List<common.Series<dynamic, DateTime>> seriesList, {\n    bool? animate,\n    Duration? animationDuration,\n    common.AxisSpec? domainAxis,\n    common.NumericAxisSpec? primaryMeasureAxis,\n    common.NumericAxisSpec? secondaryMeasureAxis,\n    LinkedHashMap<String, common.NumericAxisSpec>? disjointMeasureAxes,\n    common.SeriesRendererConfig<DateTime>? defaultRenderer,\n    List<common.SeriesRendererConfig<DateTime>>? customSeriesRenderers,\n    List<ChartBehavior<DateTime>>? behaviors,\n    List<SelectionModelConfig<DateTime>>? selectionModels,\n    LayoutConfig? layoutConfig,\n    this.dateTimeFactory,\n    bool defaultInteractions = true,\n    bool? flipVerticalAxis,\n    UserManagedState<DateTime>? userManagedState,\n  }) : super(\n          seriesList,\n          animate: animate,\n          animationDuration: animationDuration,\n          domainAxis: domainAxis,\n          primaryMeasureAxis: primaryMeasureAxis,\n          secondaryMeasureAxis: secondaryMeasureAxis,\n          disjointMeasureAxes: disjointMeasureAxes,\n          defaultRenderer: defaultRenderer,\n          customSeriesRenderers: customSeriesRenderers,\n          behaviors: behaviors,\n          selectionModels: selectionModels,\n          layoutConfig: layoutConfig,\n          defaultInteractions: defaultInteractions,\n          flipVerticalAxis: flipVerticalAxis,\n          userManagedState: userManagedState,\n        );\n\n  @override\n  common.TimeSeriesChart createCommonChart(BaseChartState chartState) {\n    // Optionally create primary and secondary measure axes if the chart was\n    // configured with them. If no axes were configured, then the chart will\n    // use its default types (usually a numeric axis).\n    return new common.TimeSeriesChart(\n        layoutConfig: layoutConfig?.commonLayoutConfig,\n        primaryMeasureAxis: primaryMeasureAxis?.createAxis(),\n        secondaryMeasureAxis: secondaryMeasureAxis?.createAxis(),\n        disjointMeasureAxes: createDisjointMeasureAxes(),\n        dateTimeFactory:\n            dateTimeFactory ?? const common.LocalDateTimeFactory());\n  }\n\n  @override\n  void addDefaultInteractions(List<ChartBehavior> behaviors) {\n    super.addDefaultInteractions(behaviors);\n\n    behaviors.add(new LinePointHighlighter<DateTime>());\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_flutter/lib/src/user_managed_state.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'package:charts_common/common.dart' as common\n    show ImmutableSeries, SelectionModel, SelectionModelType, SeriesDatumConfig;\n\n/// Contains override settings for the internal chart state.\n///\n/// The chart will check non null settings and apply them if they differ from\n/// the internal chart state and trigger the appropriate level of redrawing.\nclass UserManagedState<D> {\n  /// The expected selection(s) on the chart.\n  ///\n  /// If this is set and the model for the selection model type differs from\n  /// what is in the internal chart state, the selection will be applied and\n  /// repainting will occur such that behaviors that draw differently on\n  /// selection change can update, such as the line point highlighter.\n  ///\n  /// If more than one type of selection model is used, only the one(s)\n  /// specified in this list will override what is kept in the internally.\n  ///\n  /// To clear the selection, add an empty selection model.\n  final selectionModels =\n      <common.SelectionModelType, UserManagedSelectionModel<D>>{};\n}\n\n/// Container for the user managed selection model.\n///\n/// This container is needed because the selection model generated by selection\n/// events is a [SelectionModel], while any user defined selection has to be\n/// specified by passing in [selectedSeriesConfig] and [selectedDataConfig].\n/// The configuration is converted to a selection model after the series data\n/// has been processed.\nclass UserManagedSelectionModel<D> {\n  final List<String>? selectedSeriesConfig;\n  final List<common.SeriesDatumConfig<D>>? selectedDataConfig;\n  common.SelectionModel<D>? _model;\n\n  /// Creates a [UserManagedSelectionModel] that holds [SelectionModel].\n  ///\n  /// [selectedSeriesConfig] and [selectedDataConfig] is set to null because the\n  /// [_model] is returned when [getModel] is called.\n  UserManagedSelectionModel({common.SelectionModel<D>? model})\n      : _model = model ?? common.SelectionModel(),\n        selectedSeriesConfig = null,\n        selectedDataConfig = null;\n\n  /// Creates a [UserManagedSelectionModel] with configuration that is converted\n  /// to a [SelectionModel] when [getModel] provides a processed series list.\n  UserManagedSelectionModel.fromConfig(\n      {List<String>? selectedSeriesConfig,\n      List<common.SeriesDatumConfig<D>>? selectedDataConfig})\n      : this.selectedSeriesConfig = selectedSeriesConfig,\n        this.selectedDataConfig = selectedDataConfig;\n\n  /// Gets the selection model. If the model is null, create one from\n  /// configuration and the processed [seriesList] passed in.\n  common.SelectionModel<D> getModel(\n      List<common.ImmutableSeries<D>> seriesList) {\n    _model ??= common.SelectionModel<D>.fromConfig(\n        selectedDataConfig, selectedSeriesConfig, seriesList);\n\n    return _model!;\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_flutter/lib/src/util/color.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'package:charts_common/common.dart' as common show Color;\nimport 'dart:ui' as ui;\n\nclass ColorUtil {\n  static ui.Color toDartColor(common.Color color) {\n    return ui.Color.fromARGB(color.a, color.r, color.g, color.b);\n  }\n\n  static common.Color fromDartColor(ui.Color color) {\n    return common.Color(\n        r: color.red, g: color.green, b: color.blue, a: color.alpha);\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_flutter/lib/src/util.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'package:flutter/rendering.dart'\n    show\n        RenderBox,\n        RenderSemanticsGestureHandler,\n        RenderPointerListener,\n        RenderCustomMultiChildLayoutBox;\nimport 'chart_container.dart' show ChartContainerRenderObject;\n\n/// Get the [ChartContainerRenderObject] from a [RenderBox].\n///\n/// [RenderBox] is expected to be a [RenderSemanticsGestureHandler] with child\n/// of [RenderPointerListener] with child of [ChartContainerRenderObject].\nChartContainerRenderObject getChartContainerRenderObject(RenderBox box) {\n  assert(box is RenderCustomMultiChildLayoutBox);\n  final semanticHandler = (box as RenderCustomMultiChildLayoutBox)\n      .getChildrenAsList()\n      .firstWhere((child) => child is RenderSemanticsGestureHandler);\n\n  assert(semanticHandler is RenderSemanticsGestureHandler);\n  final renderPointerListener =\n      (semanticHandler as RenderSemanticsGestureHandler).child;\n\n  assert(renderPointerListener is RenderPointerListener);\n  final chartContainerRenderObject =\n      (renderPointerListener as RenderPointerListener).child;\n\n  assert(chartContainerRenderObject is ChartContainerRenderObject);\n\n  return chartContainerRenderObject as ChartContainerRenderObject;\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_flutter/lib/src/widget_layout_delegate.dart",
    "content": "// Copyright 2018 the Charts project authors. Please see the AUTHORS file\n// for details.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport 'dart:ui' show Offset;\nimport 'package:flutter/material.dart';\nimport 'package:flutter/rendering.dart';\nimport 'package:flutter/widgets.dart';\nimport 'package:charts_common/common.dart' as common\n    show BehaviorPosition, InsideJustification, OutsideJustification;\n\nimport 'behaviors/chart_behavior.dart' show BuildableBehavior;\n\n/// Layout delegate that layout chart widget with [BuildableBehavior] widgets.\nclass WidgetLayoutDelegate extends MultiChildLayoutDelegate {\n  /// ID of the common chart widget.\n  final String chartID;\n\n  /// Directionality of the widget.\n  final isRTL;\n\n  /// ID and [BuildableBehavior] of the widgets for calculating offset.\n  final Map<String, BuildableBehavior> idAndBehavior;\n\n  WidgetLayoutDelegate(this.chartID, this.idAndBehavior, this.isRTL);\n\n  @override\n  void performLayout(Size size) {\n    // TODO: Change this to a layout manager that supports more\n    // than one buildable behavior that changes chart size. Remove assert when\n    // this is possible.\n    assert(idAndBehavior.keys.isEmpty || idAndBehavior.keys.length == 1);\n\n    // Size available for the chart widget.\n    var availableWidth = size.width;\n    var availableHeight = size.height;\n    var chartOffset = Offset.zero;\n\n    // Measure the first buildable behavior.\n    final behaviorID =\n        idAndBehavior.keys.isNotEmpty ? idAndBehavior.keys.first : null;\n    var behaviorSize = Size.zero;\n    if (behaviorID != null) {\n      if (hasChild(behaviorID)) {\n        final leftPosition =\n            isRTL ? common.BehaviorPosition.end : common.BehaviorPosition.start;\n        final rightPosition =\n            isRTL ? common.BehaviorPosition.start : common.BehaviorPosition.end;\n        final behaviorPosition = idAndBehavior[behaviorID]!.position;\n\n        behaviorSize = layoutChild(behaviorID, new BoxConstraints.loose(size));\n        if (behaviorPosition == common.BehaviorPosition.top) {\n          chartOffset = new Offset(0.0, behaviorSize.height);\n          availableHeight -= behaviorSize.height;\n        } else if (behaviorPosition == common.BehaviorPosition.bottom) {\n          availableHeight -= behaviorSize.height;\n        } else if (behaviorPosition == leftPosition) {\n          chartOffset = new Offset(behaviorSize.width, 0.0);\n          availableWidth -= behaviorSize.width;\n        } else if (behaviorPosition == rightPosition) {\n          availableWidth -= behaviorSize.width;\n        }\n      }\n    }\n\n    // Layout chart.\n    final chartSize = new Size(availableWidth, availableHeight);\n    if (hasChild(chartID)) {\n      layoutChild(chartID, new BoxConstraints.tight(chartSize));\n      positionChild(chartID, chartOffset);\n    }\n\n    // Position buildable behavior.\n    if (behaviorID != null) {\n      // TODO: Unable to relayout with new smaller width.\n      // In the delegate, all children are required to have layout called\n      // exactly once.\n      final behaviorOffset = _getBehaviorOffset(idAndBehavior[behaviorID]!,\n          behaviorSize: behaviorSize, chartSize: chartSize, isRTL: isRTL);\n\n      positionChild(behaviorID, behaviorOffset);\n    }\n  }\n\n  @override\n  bool shouldRelayout(MultiChildLayoutDelegate oldDelegate) {\n    // TODO: Deep equality check because the instance will not be\n    // the same on each build, even if the buildable behavior has not changed.\n    return idAndBehavior != (oldDelegate as WidgetLayoutDelegate).idAndBehavior;\n  }\n\n  // Calculate buildable behavior's offset.\n  Offset _getBehaviorOffset(BuildableBehavior behavior,\n      {required Size behaviorSize,\n      required Size chartSize,\n      required bool isRTL}) {\n    late Offset behaviorOffset;\n\n    final behaviorPosition = behavior.position;\n    final outsideJustification = behavior.outsideJustification;\n    final insideJustification = behavior.insideJustification;\n\n    if (behaviorPosition == common.BehaviorPosition.top ||\n        behaviorPosition == common.BehaviorPosition.bottom) {\n      final heightOffset = behaviorPosition == common.BehaviorPosition.bottom\n          ? chartSize.height\n          : 0.0;\n\n      final horizontalJustification =\n          getOutsideJustification(outsideJustification, isRTL);\n\n      switch (horizontalJustification) {\n        case _HorizontalJustification.leftDrawArea:\n          behaviorOffset = new Offset(\n              behavior.drawAreaBounds!.left.toDouble(), heightOffset);\n          break;\n        case _HorizontalJustification.left:\n          behaviorOffset = new Offset(0.0, heightOffset);\n          break;\n        case _HorizontalJustification.rightDrawArea:\n          behaviorOffset = new Offset(\n              behavior.drawAreaBounds!.right - behaviorSize.width,\n              heightOffset);\n          break;\n        case _HorizontalJustification.right:\n          behaviorOffset =\n              new Offset(chartSize.width - behaviorSize.width, heightOffset);\n          break;\n      }\n    } else if (behaviorPosition == common.BehaviorPosition.start ||\n        behaviorPosition == common.BehaviorPosition.end) {\n      final widthOffset =\n          (isRTL && behaviorPosition == common.BehaviorPosition.start) ||\n                  (!isRTL && behaviorPosition == common.BehaviorPosition.end)\n              ? chartSize.width\n              : 0.0;\n\n      switch (outsideJustification) {\n        case common.OutsideJustification.startDrawArea:\n        case common.OutsideJustification.middleDrawArea:\n          behaviorOffset =\n              new Offset(widthOffset, behavior.drawAreaBounds!.top.toDouble());\n          break;\n        case common.OutsideJustification.start:\n        case common.OutsideJustification.middle:\n          behaviorOffset = new Offset(widthOffset, 0.0);\n          break;\n        case common.OutsideJustification.endDrawArea:\n          behaviorOffset = new Offset(widthOffset,\n              behavior.drawAreaBounds!.bottom - behaviorSize.height);\n          break;\n        case common.OutsideJustification.end:\n          behaviorOffset =\n              new Offset(widthOffset, chartSize.height - behaviorSize.height);\n          break;\n      }\n    } else if (behaviorPosition == common.BehaviorPosition.inside) {\n      var rightOffset = new Offset(chartSize.width - behaviorSize.width, 0.0);\n\n      switch (insideJustification) {\n        case common.InsideJustification.topStart:\n          behaviorOffset = isRTL ? rightOffset : Offset.zero;\n          break;\n        case common.InsideJustification.topEnd:\n          behaviorOffset = isRTL ? Offset.zero : rightOffset;\n          break;\n      }\n    }\n\n    return behaviorOffset;\n  }\n\n  _HorizontalJustification getOutsideJustification(\n      common.OutsideJustification justification, bool isRTL) {\n    _HorizontalJustification mappedJustification;\n\n    switch (justification) {\n      case common.OutsideJustification.startDrawArea:\n      case common.OutsideJustification.middleDrawArea:\n        mappedJustification = isRTL\n            ? _HorizontalJustification.rightDrawArea\n            : _HorizontalJustification.leftDrawArea;\n        break;\n      case common.OutsideJustification.start:\n      case common.OutsideJustification.middle:\n        mappedJustification = isRTL\n            ? _HorizontalJustification.right\n            : _HorizontalJustification.left;\n        break;\n      case common.OutsideJustification.endDrawArea:\n        mappedJustification = isRTL\n            ? _HorizontalJustification.leftDrawArea\n            : _HorizontalJustification.rightDrawArea;\n        break;\n      case common.OutsideJustification.end:\n        mappedJustification = isRTL\n            ? _HorizontalJustification.left\n            : _HorizontalJustification.right;\n        break;\n    }\n\n    return mappedJustification;\n  }\n}\n\nenum _HorizontalJustification {\n  leftDrawArea,\n  left,\n  rightDrawArea,\n  right,\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_flutter/minimum_os.bzl",
    "content": "\"\"\"Minimum OS version definitions\"\"\"\n\nIOS_MINIMUM_OS = \"9.0\"\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/charts_flutter/pubspec.yaml",
    "content": "name: charts_flutter\nversion: 0.11.0\ndescription: Material Design charting library for flutter.\nauthor: Charts Team <charts_flutter@google.com>\nhomepage: https://github.com/google/charts\n\nenvironment:\n  sdk: '>=2.12.0 <3.0.0'\n\ndependencies:\n  # Pointing this to a local path allows for pointing to the latest code\n  # in Github for open source development.\n  #\n  # The pub version of charts_flutter will point to the pub version of charts_common.\n  # The latest pub version is commented out and shown below as an example.\n  charts_common: 0.11.0\n  # charts_common:\n  #   path: ../charts_common/\n  collection: ^1.14.5\n  flutter:\n    sdk: flutter\n  intl: \">=0.15.2 < 0.18.0\"\n  logging: any\n  meta: ^1.1.1\n\n\ndev_dependencies:\n  mockito: ^5.0.0\n  build_runner: ^1.11.0\n  flutter_test:\n    sdk: flutter\n  test: ^1.3.0\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/docs/Gemfile",
    "content": "# This file enables generation of documentation html from markdown locally.\n#\n# Ruby 2.10 or later is required.\n# To install needed dependencies:\n#\n#   gem install bundler\n#   bundle install --path .bundle\n#\n# To generate and serve html locally:\n#\n#   bundle exec jekyll serve\n#\n# --------------------------------------------------------------------------\nsource 'https://rubygems.org'\ngem 'github-pages', group: :jekyll_plugins\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/docs/flutter/gallery.md",
    "content": "## Gallery\n\n[//]: (Do_NOT_modify_gallery__generate_from_code)\n[//]: (START_EXAMPLES)\n\n### Bar Charts\n\n| | | | |\n| --- | --- | --- | --- |\n| Simple<br>[![](example/bar_charts/simple_thumb.png)](example/bar_charts/simple) | Stacked<br>[![](example/bar_charts/stacked_thumb.png)](example/bar_charts/stacked) | Grouped<br>[![](example/bar_charts/grouped_thumb.png)](example/bar_charts/grouped) | Grouped Stacked<br>[![](example/bar_charts/grouped_stacked_thumb.png)](example/bar_charts/grouped_stacked) |\n| Grouped Target Line<br>[![](example/bar_charts/grouped_target_line_thumb.png)](example/bar_charts/grouped_target_line) | Stacked Horizontal<br>[![](example/bar_charts/stacked_horizontal_thumb.png)](example/bar_charts/stacked_horizontal) | Stacked Target Line<br>[![](example/bar_charts/stacked_target_line_thumb.png)](example/bar_charts/stacked_target_line) | Horizontal<br>[![](example/bar_charts/horizontal_thumb.png)](example/bar_charts/horizontal) |\n| Horizontal Bar Label<br>[![](example/bar_charts/horizontal_bar_label_thumb.png)](example/bar_charts/horizontal_bar_label) | Horizontal Bar Label Custom<br>[![](example/bar_charts/horizontal_bar_label_custom_thumb.png)](example/bar_charts/horizontal_bar_label_custom) | Vertical Bar Label<br>[![](example/bar_charts/vertical_bar_label_thumb.png)](example/bar_charts/vertical_bar_label) | Spark Bar<br>[![](example/bar_charts/spark_bar_thumb.png)](example/bar_charts/spark_bar) |\n| Grouped Fill Color<br>[![](example/bar_charts/grouped_fill_color_thumb.png)](example/bar_charts/grouped_fill_color) | Stacked Fill Color<br>[![](example/bar_charts/stacked_fill_color_thumb.png)](example/bar_charts/stacked_fill_color) | Pattern Forward Hatch<br>[![](example/bar_charts/pattern_forward_hatch_thumb.png)](example/bar_charts/pattern_forward_hatch) | Horizontal Pattern Forward Hatch<br>[![](example/bar_charts/horizontal_pattern_forward_hatch_thumb.png)](example/bar_charts/horizontal_pattern_forward_hatch) |\n| Grouped Stacked Weight Pattern<br>[![](example/bar_charts/grouped_stacked_weight_pattern_thumb.png)](example/bar_charts/grouped_stacked_weight_pattern) | Custom Rounded Bars<br>[![](example/bar_charts/custom_rounded_bars_thumb.png)](example/bar_charts/custom_rounded_bars) | | |\n\n\n### Time Series Charts\n\n| | | | |\n| --- | --- | --- | --- |\n| Simple<br>[![](example/time_series_charts/simple_thumb.png)](example/time_series_charts/simple) | End Points Axis<br>[![](example/time_series_charts/end_points_axis_thumb.png)](example/time_series_charts/end_points_axis) | Confidence Interval<br>[![](example/time_series_charts/confidence_interval_thumb.png)](example/time_series_charts/confidence_interval) | Line Annotation<br>[![](example/time_series_charts/line_annotation_thumb.png)](example/time_series_charts/line_annotation) |\n| Range Annotation<br>[![](example/time_series_charts/range_annotation_thumb.png)](example/time_series_charts/range_annotation) | Range Annotation Margin<br>[![](example/time_series_charts/range_annotation_margin_thumb.png)](example/time_series_charts/range_annotation_margin) | Symbol Annotation<br>[![](example/time_series_charts/symbol_annotation_thumb.png)](example/time_series_charts/symbol_annotation) | With Bar Renderer<br>[![](example/time_series_charts/with_bar_renderer_thumb.png)](example/time_series_charts/with_bar_renderer) |\n\n\n### Line Charts\n\n| | | | |\n| --- | --- | --- | --- |\n| Simple<br>[![](example/line_charts/simple_thumb.png)](example/line_charts/simple) | Points<br>[![](example/line_charts/points_thumb.png)](example/line_charts/points) | Stacked Area<br>[![](example/line_charts/stacked_area_thumb.png)](example/line_charts/stacked_area) | Stacked Area Custom Color<br>[![](example/line_charts/stacked_area_custom_color_thumb.png)](example/line_charts/stacked_area_custom_color) |\n| Area And Line<br>[![](example/line_charts/area_and_line_thumb.png)](example/line_charts/area_and_line) | Simple Nulls<br>[![](example/line_charts/simple_nulls_thumb.png)](example/line_charts/simple_nulls) | Stacked Area Nulls<br>[![](example/line_charts/stacked_area_nulls_thumb.png)](example/line_charts/stacked_area_nulls) | Dash Pattern<br>[![](example/line_charts/dash_pattern_thumb.png)](example/line_charts/dash_pattern) |\n| Segments<br>[![](example/line_charts/segments_thumb.png)](example/line_charts/segments) | Line Annotation<br>[![](example/line_charts/line_annotation_thumb.png)](example/line_charts/line_annotation) | Range Annotation<br>[![](example/line_charts/range_annotation_thumb.png)](example/line_charts/range_annotation) | Range Annotation Margin<br>[![](example/line_charts/range_annotation_margin_thumb.png)](example/line_charts/range_annotation_margin) |\n\n\n### Scatter Plot Charts\n\n| | | | |\n| --- | --- | --- | --- |\n| Simple<br>[![](example/scatter_plot_charts/simple_thumb.png)](example/scatter_plot_charts/simple) | Shapes<br>[![](example/scatter_plot_charts/shapes_thumb.png)](example/scatter_plot_charts/shapes) | Comparison Points<br>[![](example/scatter_plot_charts/comparison_points_thumb.png)](example/scatter_plot_charts/comparison_points) | Bucketing Axis<br>[![](example/scatter_plot_charts/bucketing_axis_thumb.png)](example/scatter_plot_charts/bucketing_axis) |\n\n\n### Combo Charts\n\n| | | | |\n| --- | --- | --- | --- |\n| Ordinal Bar Line<br>[![](example/combo_charts/ordinal_bar_line_thumb.png)](example/combo_charts/ordinal_bar_line) | Numeric Line Bar<br>[![](example/combo_charts/numeric_line_bar_thumb.png)](example/combo_charts/numeric_line_bar) | Numeric Line Point<br>[![](example/combo_charts/numeric_line_point_thumb.png)](example/combo_charts/numeric_line_point) | Date Time Line Point<br>[![](example/combo_charts/date_time_line_point_thumb.png)](example/combo_charts/date_time_line_point) |\n| Scatter Plot Line<br>[![](example/combo_charts/scatter_plot_line_thumb.png)](example/combo_charts/scatter_plot_line) | | | |\n\n\n### Pie Charts\n\n| | | | |\n| --- | --- | --- | --- |\n| Simple<br>[![](example/pie_charts/simple_thumb.png)](example/pie_charts/simple) | Outside Label<br>[![](example/pie_charts/outside_label_thumb.png)](example/pie_charts/outside_label) | Partial Pie<br>[![](example/pie_charts/partial_pie_thumb.png)](example/pie_charts/partial_pie) | Donut<br>[![](example/pie_charts/donut_thumb.png)](example/pie_charts/donut) |\n| Auto Label<br>[![](example/pie_charts/auto_label_thumb.png)](example/pie_charts/auto_label) | Gauge<br>[![](example/pie_charts/gauge_thumb.png)](example/pie_charts/gauge) | | |\n\n\n### TreeMap Charts\n\n| | | | |\n| --- | --- | --- | --- |\n\n\n### Axes\n\n| | | | |\n| --- | --- | --- | --- |\n| Bar Secondary Axis<br>[![](example/axes/bar_secondary_axis_thumb.png)](example/axes/bar_secondary_axis) | Bar Secondary Axis Only<br>[![](example/axes/bar_secondary_axis_only_thumb.png)](example/axes/bar_secondary_axis_only) | Horizontal Bar Secondary Axis<br>[![](example/axes/horizontal_bar_secondary_axis_thumb.png)](example/axes/horizontal_bar_secondary_axis) | Flipped Vertical Axis<br>[![](example/axes/flipped_vertical_axis_thumb.png)](example/axes/flipped_vertical_axis) |\n| Short Tick Length Axis<br>[![](example/axes/short_tick_length_axis_thumb.png)](example/axes/short_tick_length_axis) | Custom Font Size And Color<br>[![](example/axes/custom_font_size_and_color_thumb.png)](example/axes/custom_font_size_and_color) | Measure Axis Label Alignment<br>[![](example/axes/measure_axis_label_alignment_thumb.png)](example/axes/measure_axis_label_alignment) | Hidden Ticks And Labels Axis<br>[![](example/axes/hidden_ticks_and_labels_axis_thumb.png)](example/axes/hidden_ticks_and_labels_axis) |\n| Custom Axis Tick Formatters<br>[![](example/axes/custom_axis_tick_formatters_thumb.png)](example/axes/custom_axis_tick_formatters) | Custom Measure Tick Count<br>[![](example/axes/custom_measure_tick_count_thumb.png)](example/axes/custom_measure_tick_count) | Integer Only Measure Axis<br>[![](example/axes/integer_only_measure_axis_thumb.png)](example/axes/integer_only_measure_axis) | Nonzero Bound Measure Axis<br>[![](example/axes/nonzero_bound_measure_axis_thumb.png)](example/axes/nonzero_bound_measure_axis) |\n| Nonzero Bound Measure Axis<br>[![](example/axes/nonzero_bound_measure_axis_thumb.png)](example/axes/nonzero_bound_measure_axis) | Statically Provided Ticks<br>[![](example/axes/statically_provided_ticks_thumb.png)](example/axes/statically_provided_ticks) | Ordinal Initial Viewport<br>[![](example/axes/ordinal_initial_viewport_thumb.png)](example/axes/ordinal_initial_viewport) | Numeric Initial Viewport<br>[![](example/axes/numeric_initial_viewport_thumb.png)](example/axes/numeric_initial_viewport) |\n| Gridline Dash Pattern<br>[![](example/axes/gridline_dash_pattern_thumb.png)](example/axes/gridline_dash_pattern) | Line Disjoint Axis<br>[![](example/axes/line_disjoint_axis_thumb.png)](example/axes/line_disjoint_axis) | | |\n\n\n### Legends\n\n| | | | |\n| --- | --- | --- | --- |\n| Simple Series Legend<br>[![](example/legends/simple_series_legend_thumb.png)](example/legends/simple_series_legend) | Series Legend Options<br>[![](example/legends/series_legend_options_thumb.png)](example/legends/series_legend_options) | Series Legend With Measures<br>[![](example/legends/series_legend_with_measures_thumb.png)](example/legends/series_legend_with_measures) | Legend Custom Symbol<br>[![](example/legends/legend_custom_symbol_thumb.png)](example/legends/legend_custom_symbol) |\n| Default Hidden Series Legend<br>[![](example/legends/default_hidden_series_legend_thumb.png)](example/legends/default_hidden_series_legend) | Simple Datum Legend<br>[![](example/legends/simple_datum_legend_thumb.png)](example/legends/simple_datum_legend) | Datum Legend Options<br>[![](example/legends/datum_legend_options_thumb.png)](example/legends/datum_legend_options) | Datum Legend With Measures<br>[![](example/legends/datum_legend_with_measures_thumb.png)](example/legends/datum_legend_with_measures) |\n\n\n### Hovercards\n\n| | | | |\n| --- | --- | --- | --- |\n\n\n### Behaviors\n\n| | | | |\n| --- | --- | --- | --- |\n| Initial Selection<br>[![](example/behaviors/initial_selection_thumb.png)](example/behaviors/initial_selection) | Selection Bar Highlight<br>[![](example/behaviors/selection_bar_highlight_thumb.png)](example/behaviors/selection_bar_highlight) | Selection Line Highlight<br>[![](example/behaviors/selection_line_highlight_thumb.png)](example/behaviors/selection_line_highlight) | Selection User Managed<br>[![](example/behaviors/selection_user_managed_thumb.png)](example/behaviors/selection_user_managed) |\n| Selection Callback Example<br>[![](example/behaviors/selection_callback_example_thumb.png)](example/behaviors/selection_callback_example) | Chart Title<br>[![](example/behaviors/chart_title_thumb.png)](example/behaviors/chart_title) | Slider<br>[![](example/behaviors/slider_thumb.png)](example/behaviors/slider) | Sliding Viewport On Selection<br>[![](example/behaviors/sliding_viewport_on_selection_thumb.png)](example/behaviors/sliding_viewport_on_selection) |\n| Percent Of Domain<br>[![](example/behaviors/percent_of_domain_thumb.png)](example/behaviors/percent_of_domain) | Percent Of Domain By Category<br>[![](example/behaviors/percent_of_domain_by_category_thumb.png)](example/behaviors/percent_of_domain_by_category) | Percent Of Series<br>[![](example/behaviors/percent_of_series_thumb.png)](example/behaviors/percent_of_series) | Initial Hint Animation<br>[![](example/behaviors/initial_hint_animation_thumb.png)](example/behaviors/initial_hint_animation) |\n\n\n### a11y\n\n| | | | |\n| --- | --- | --- | --- |\n| Domain A11y Explore Bar Chart<br>[![](example/a11ys/domain_a11y_explore_bar_chart_thumb.png)](example/a11ys/domain_a11y_explore_bar_chart) | | | |\n\n\n### i18n\n\n| | | | |\n| --- | --- | --- | --- |\n| Rtl Bar Chart<br>[![](example/i18ns/rtl_bar_chart_thumb.png)](example/i18ns/rtl_bar_chart) | Rtl Line Chart<br>[![](example/i18ns/rtl_line_chart_thumb.png)](example/i18ns/rtl_line_chart) | Rtl Line Segments<br>[![](example/i18ns/rtl_line_segments_thumb.png)](example/i18ns/rtl_line_segments) | Rtl Series Legend<br>[![](example/i18ns/rtl_series_legend_thumb.png)](example/i18ns/rtl_series_legend) |\n\n[//]: (END_EXAMPLES)\n\n### Combo Charts\n\n### Sizing & Margins\n"
  },
  {
    "path": "flutter/reddit_ticker/deps/charts/docs/index.md",
    "content": "# Charts\n\nThe charting framework is currently supported for the\n[Flutter](https://flutter.io) platform.\n\nPlease see the\n[charts_flutter page on pub dev](https://pub.dev/packages/charts_flutter)\nfor reference or the\n[online gallery of Flutter charts](https://google.github.io/charts/flutter/gallery.html)\nfor examples.\n"
  },
  {
    "path": "flutter/reddit_ticker/ios/.gitignore",
    "content": "*.mode1v3\n*.mode2v3\n*.moved-aside\n*.pbxuser\n*.perspectivev3\n**/*sync/\n.sconsign.dblite\n.tags*\n**/.vagrant/\n**/DerivedData/\nIcon?\n**/Pods/\n**/.symlinks/\nprofile\nxcuserdata\n**/.generated/\nFlutter/App.framework\nFlutter/Flutter.framework\nFlutter/Flutter.podspec\nFlutter/Generated.xcconfig\nFlutter/ephemeral/\nFlutter/app.flx\nFlutter/app.zip\nFlutter/flutter_assets/\nFlutter/flutter_export_environment.sh\nServiceDefinitions.json\nRunner/GeneratedPluginRegistrant.*\n\n# Exceptions to above rules.\n!default.mode1v3\n!default.mode2v3\n!default.pbxuser\n!default.perspectivev3\n"
  },
  {
    "path": "flutter/reddit_ticker/ios/Flutter/AppFrameworkInfo.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  <key>CFBundleDevelopmentRegion</key>\n  <string>en</string>\n  <key>CFBundleExecutable</key>\n  <string>App</string>\n  <key>CFBundleIdentifier</key>\n  <string>io.flutter.flutter.app</string>\n  <key>CFBundleInfoDictionaryVersion</key>\n  <string>6.0</string>\n  <key>CFBundleName</key>\n  <string>App</string>\n  <key>CFBundlePackageType</key>\n  <string>FMWK</string>\n  <key>CFBundleShortVersionString</key>\n  <string>1.0</string>\n  <key>CFBundleSignature</key>\n  <string>????</string>\n  <key>CFBundleVersion</key>\n  <string>1.0</string>\n  <key>MinimumOSVersion</key>\n  <string>9.0</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "flutter/reddit_ticker/ios/Flutter/Debug.xcconfig",
    "content": "#include? \"Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig\"\n#include \"Generated.xcconfig\"\n"
  },
  {
    "path": "flutter/reddit_ticker/ios/Flutter/Release.xcconfig",
    "content": "#include? \"Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig\"\n#include \"Generated.xcconfig\"\n"
  },
  {
    "path": "flutter/reddit_ticker/ios/Podfile",
    "content": "# Uncomment this line to define a global platform for your project\n# platform :ios, '9.0'\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', '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 Generated.xcconfig, then run flutter pub get\"\nend\n\nrequire File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)\n\nflutter_ios_podfile_setup\n\ntarget 'Runner' do\n  use_frameworks!\n  use_modular_headers!\n\n  flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))\nend\n\npost_install do |installer|\n  installer.pods_project.targets.each do |target|\n    flutter_additional_ios_build_settings(target)\n  end\nend\n"
  },
  {
    "path": "flutter/reddit_ticker/ios/Runner/AppDelegate.swift",
    "content": "import UIKit\nimport Flutter\n\n@UIApplicationMain\n@objc class AppDelegate: FlutterAppDelegate {\n  override func application(\n    _ application: UIApplication,\n    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?\n  ) -> Bool {\n    GeneratedPluginRegistrant.register(with: self)\n    return super.application(application, didFinishLaunchingWithOptions: launchOptions)\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"size\" : \"20x20\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-App-20x20@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"20x20\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-App-20x20@3x.png\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"size\" : \"29x29\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-App-29x29@1x.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"29x29\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-App-29x29@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"29x29\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-App-29x29@3x.png\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"size\" : \"40x40\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-App-40x40@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"40x40\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-App-40x40@3x.png\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"size\" : \"60x60\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-App-60x60@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"60x60\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-App-60x60@3x.png\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"size\" : \"20x20\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-App-20x20@1x.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"20x20\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-App-20x20@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"29x29\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-App-29x29@1x.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"29x29\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-App-29x29@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"40x40\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-App-40x40@1x.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"40x40\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-App-40x40@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"76x76\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-App-76x76@1x.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"76x76\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-App-76x76@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"83.5x83.5\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-App-83.5x83.5@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"1024x1024\",\n      \"idiom\" : \"ios-marketing\",\n      \"filename\" : \"Icon-App-1024x1024@1x.png\",\n      \"scale\" : \"1x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"LaunchImage.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"LaunchImage@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"LaunchImage@3x.png\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md",
    "content": "# Launch Screen Assets\n\nYou can customize the launch screen with your own desired assets by replacing the image files in this directory.\n\nYou can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images."
  },
  {
    "path": "flutter/reddit_ticker/ios/Runner/Base.lproj/LaunchScreen.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"12121\" systemVersion=\"16G29\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" launchScreen=\"YES\" colorMatched=\"YES\" initialViewController=\"01J-lp-oVM\">\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"12089\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"EHf-IW-A2E\">\n            <objects>\n                <viewController id=\"01J-lp-oVM\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"Ydg-fD-yQy\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"xbc-2k-c8Z\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"Ze5-6b-2t3\">\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <imageView opaque=\"NO\" clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"center\" image=\"LaunchImage\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"YRO-k0-Ey4\">\n                            </imageView>\n                        </subviews>\n                        <color key=\"backgroundColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                        <constraints>\n                            <constraint firstItem=\"YRO-k0-Ey4\" firstAttribute=\"centerX\" secondItem=\"Ze5-6b-2t3\" secondAttribute=\"centerX\" id=\"1a2-6s-vTC\"/>\n                            <constraint firstItem=\"YRO-k0-Ey4\" firstAttribute=\"centerY\" secondItem=\"Ze5-6b-2t3\" secondAttribute=\"centerY\" id=\"4X2-HB-R7a\"/>\n                        </constraints>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"iYj-Kq-Ea1\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"53\" y=\"375\"/>\n        </scene>\n    </scenes>\n    <resources>\n        <image name=\"LaunchImage\" width=\"168\" height=\"185\"/>\n    </resources>\n</document>\n"
  },
  {
    "path": "flutter/reddit_ticker/ios/Runner/Base.lproj/Main.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"10117\" systemVersion=\"15F34\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" initialViewController=\"BYZ-38-t0r\">\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"10085\"/>\n    </dependencies>\n    <scenes>\n        <!--Flutter View Controller-->\n        <scene sceneID=\"tne-QT-ifu\">\n            <objects>\n                <viewController id=\"BYZ-38-t0r\" customClass=\"FlutterViewController\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"y3c-jy-aDJ\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"wfy-db-euE\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"8bC-Xf-vdC\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"600\" height=\"600\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"calibratedWhite\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"dkx-z0-nzr\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "flutter/reddit_ticker/ios/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>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>reddit_ticker</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>CFBundleSignature</key>\n\t<string>????</string>\n\t<key>CFBundleVersion</key>\n\t<string>$(FLUTTER_BUILD_NUMBER)</string>\n\t<key>LSRequiresIPhoneOS</key>\n\t<true/>\n\t<key>UILaunchStoryboardName</key>\n\t<string>LaunchScreen</string>\n\t<key>UIMainStoryboardFile</key>\n\t<string>Main</string>\n\t<key>UISupportedInterfaceOrientations</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations~ipad</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationPortraitUpsideDown</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n\t<key>UIViewControllerBasedStatusBarAppearance</key>\n\t<false/>\n</dict>\n</plist>\n"
  },
  {
    "path": "flutter/reddit_ticker/ios/Runner/Runner-Bridging-Header.h",
    "content": "#import \"GeneratedPluginRegistrant.h\"\n"
  },
  {
    "path": "flutter/reddit_ticker/ios/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": "flutter/reddit_ticker/ios/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": "flutter/reddit_ticker/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings",
    "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>PreviewsEnabled</key>\n\t<false/>\n</dict>\n</plist>\n"
  },
  {
    "path": "flutter/reddit_ticker/lib/cubit/add_post_cubit.dart",
    "content": "import 'package:bloc/bloc.dart';\nimport 'package:meta/meta.dart';\nimport 'package:plugin/generated/rid_api.dart';\n\npart 'add_post_state.dart';\n\n// Requests to reddit can be slow especially on not so great internet\nfinal REQ_TIMEOUT = const Duration(seconds: 10);\n\nclass AddPostCubit extends Cubit<AddPostState> {\n  final Store _store = Store.instance;\n  AddPostCubit() : super(AddPostInactive());\n\n  Future<void> addPost(String url) async {\n    emit(AddPostPending(url));\n\n    final res = await _store.msgStartWatching(url, timeout: REQ_TIMEOUT);\n\n    switch (res.type) {\n      case Reply.StartedWatching:\n        assert(res.data != null, 'Successful reply should include post id');\n        final post = _store.posts[res.data];\n        assert(post != null, 'Watched post should be in the map');\n        emit(AddPostSucceeded(post!));\n        break;\n      case Reply.FailedRequest:\n        assert(res.data != null, 'Failed reply should include error message');\n        assert(state is AddPostPending,\n            'Adding post should only fail if it was pending');\n        emit(AddPostFailed((state as AddPostPending).url, res.data!));\n        break;\n      default:\n        throw ArgumentError.value(\n            res.type, 'StartWatching Reply', 'Invalid reply!');\n    }\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/lib/cubit/add_post_state.dart",
    "content": "part of 'add_post_cubit.dart';\n\n@immutable\nabstract class AddPostState {}\n\n@immutable\nclass AddPostInactive extends AddPostState {}\n\n@immutable\nclass AddPostPending extends AddPostState {\n  final String url;\n\n  AddPostPending(this.url) : super();\n}\n\n@immutable\nclass AddPostSucceeded extends AddPostState {\n  final Post post;\n\n  AddPostSucceeded(this.post) : super();\n}\n\n@immutable\nclass AddPostFailed extends AddPostState {\n  final String url;\n  final String errorMessage;\n\n  AddPostFailed(this.url, this.errorMessage) : super();\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/lib/cubit/post_cubit.dart",
    "content": "import 'dart:async';\n\nimport 'package:bloc/bloc.dart';\nimport 'package:flutter/material.dart';\nimport 'package:meta/meta.dart';\nimport 'package:plugin/generated/rid_api.dart';\n\npart 'post_state.dart';\n\nclass PostCubit extends Cubit<PostState> {\n  final _store = Store.instance;\n  StreamSubscription<PostedReply>? scoreTickSub;\n  PostCubit(Post post) : super(PostActive(post)) {\n    _subscribe();\n  }\n\n  void _subscribe() {\n    assert(scoreTickSub == null, 'Should only subscribe to post ticks once');\n    scoreTickSub = rid.replyChannel.stream\n        .where((x) => x.type == Reply.UpdatedScores)\n        .listen((_) => _refreshState());\n  }\n\n  Future<void> _unsubscribe() async {\n    await scoreTickSub?.cancel();\n    scoreTickSub = null;\n  }\n\n  Future<void> _refreshState() async {\n    assert(state is PostActive, 'Can only refresh active posts');\n    final postActive = state as PostActive;\n    final post =\n        _store.raw.runLocked((raw) => raw.posts.get(postActive.postId));\n\n    if (post == null) {\n      emit(postActive.intoRemoved());\n    } else {\n      emit(PostActive(post));\n    }\n  }\n\n  Future<bool> stopWatching() async {\n    assert(state is PostActive, 'Can only remove active posts');\n    final post = (state as PostActive).post;\n    await _store.msgStopWatching(post.id).then((_) => _refreshState());\n    emit(PostRemoved(post.id, post.url));\n    return true;\n  }\n\n  @override\n  Future<void> close() async {\n    await _unsubscribe();\n    return super.close();\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/lib/cubit/post_state.dart",
    "content": "part of 'post_cubit.dart';\n\n@immutable\nabstract class PostState {\n  final String postId;\n  final String url;\n\n  PostState(this.postId, this.url);\n}\n\n@immutable\nclass PostActive extends PostState {\n  final Post post;\n\n  PostActive(this.post) : super(post.id, post.url);\n\n  PostRemoved intoRemoved() => PostRemoved.fromPostActive(this);\n}\n\n@immutable\nclass PostRemoved extends PostState {\n  final String postId;\n\n  PostRemoved(this.postId, String url) : super(postId, url);\n\n  factory PostRemoved.fromPostActive(PostActive state) {\n    final post = state.post;\n    return PostRemoved(post.id, post.url);\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/lib/cubit/posts_cubit.dart",
    "content": "import 'dart:async';\n\nimport 'package:bloc/bloc.dart';\nimport 'package:meta/meta.dart';\nimport 'package:plugin/generated/rid_api.dart';\n\npart 'posts_state.dart';\n\nclass PostsCubit extends Cubit<PostsState> {\n  final _store = Store.instance;\n  StreamSubscription<PostedReply>? _postAddedOrRemovedSub;\n\n  PostsCubit() : super(PostsState([])) {\n    _subscribe();\n    _refresh();\n  }\n\n  void _subscribe() {\n    _postAddedOrRemovedSub = rid.replyChannel.stream\n        .where((x) =>\n            x.type == Reply.StartedWatching || x.type == Reply.StoppedWatching)\n        .listen((_) => _refresh());\n  }\n\n  Future<void> _unsubscribe() async {\n    await _postAddedOrRemovedSub?.cancel();\n    _postAddedOrRemovedSub = null;\n  }\n\n  void _refresh() {\n    final posts = _store.posts.values.toList();\n    // Show most recently added post first\n    posts.sort((a, b) => a.scores.length.compareTo(b.scores.length));\n    emit(PostsState(posts));\n  }\n\n  @override\n  Future<void> close() async {\n    await _unsubscribe();\n    return super.close();\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/lib/cubit/posts_state.dart",
    "content": "part of 'posts_cubit.dart';\n\n@immutable\nclass PostsState {\n  final List<Post> posts;\n  const PostsState(this.posts);\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/lib/main.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:flutter_bloc/flutter_bloc.dart';\nimport 'package:path_provider/path_provider.dart';\nimport 'package:plugin/generated/rid_api.dart';\nimport 'package:reddit_ticker/cubit/add_post_cubit.dart';\nimport 'package:reddit_ticker/cubit/posts_cubit.dart';\nimport 'package:reddit_ticker/rid/messaging.dart';\nimport 'package:reddit_ticker/views/add_post.dart';\nimport 'package:reddit_ticker/views/posts.dart';\n\nvoid main() async {\n  RidMessaging.init();\n\n  rid.debugLock = null;\n\n  WidgetsFlutterBinding.ensureInitialized();\n  final appDir = await getApplicationSupportDirectory();\n  await Store.instance.msgInitialize(appDir.path);\n  runApp(RedditTickerApp());\n}\n\nclass RedditTickerApp extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return MaterialApp(\n      title: 'Reddit Ticker',\n      theme: ThemeData(primarySwatch: Colors.indigo),\n      home: MultiBlocProvider(\n        providers: [\n          BlocProvider<PostsCubit>(create: (_) => PostsCubit()),\n          BlocProvider<AddPostCubit>(create: (_) => AddPostCubit()),\n        ],\n        child: RedditTickerPage(title: 'Reddit Ticker'),\n      ),\n    );\n  }\n}\n\nclass RedditTickerPage extends StatefulWidget {\n  final String title;\n  RedditTickerPage({Key? key, required this.title}) : super(key: key);\n\n  @override\n  _RedditTickerPageState createState() => _RedditTickerPageState();\n}\n\nclass _RedditTickerPageState extends State<RedditTickerPage> {\n  @override\n  void initState() {\n    super.initState();\n    ErrorHandler.instance.context = context;\n    UserMsgHandler.instance.context = context;\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    return SafeArea(\n      child: Scaffold(\n        appBar: AppBar(\n          title: Row(\n            mainAxisAlignment: MainAxisAlignment.spaceBetween,\n            children: [\n              Text(widget.title),\n              Row(\n                children: [\n                  Image.asset(\n                    \"assets/dash.png\",\n                    height: 40.0,\n                    width: 40.0,\n                  ),\n                  Icon(Icons.favorite, color: Colors.red),\n                  Image.asset(\n                    \"assets/ferris.png\",\n                    height: 50.0,\n                    width: 50.0,\n                  ),\n                ],\n              )\n            ],\n          ),\n        ),\n        body: PostsView(),\n        floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,\n        floatingActionButton: AddPostView(),\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/lib/rid/messaging.dart",
    "content": "import 'dart:async';\n\nimport 'package:flutter/material.dart';\nimport 'package:plugin/generated/rid_api.dart';\n\nconst RUST_ICON = '🦀';\nconst WARN_ICON = '⚠️ ';\nconst INFO_ICON = '💡';\nconst DEBG_ICON = '🪲';\nconst ERR_ICON = '❌';\n\nconst WARN_PREFIX = '$RUST_ICON $WARN_ICON';\nconst INFO_PREFIX = '$RUST_ICON $INFO_ICON';\nconst DEBG_PREFIX = '$RUST_ICON $DEBG_ICON';\nconst ERR_PREFIX = '$RUST_ICON $ERR_ICON';\n\nconst DETAILS_INDENT = '\\n       ';\n\nclass LogMessageHandler {\n  late final StreamSubscription<RidMessage>? _logMessagesSub;\n\n  LogMessageHandler._() {\n    _logMessagesSub = rid.messageChannel.stream.listen((RidMessage msg) {\n      late final String prefix;\n      switch (msg.type) {\n        case RidMessageType.Severe:\n        case RidMessageType.Error:\n        case RidMessageType.MsgWarn:\n        case RidMessageType.MsgInfo:\n          return;\n        case RidMessageType.LogWarn:\n          prefix = WARN_PREFIX;\n          break;\n        case RidMessageType.LogInfo:\n          prefix = INFO_PREFIX;\n          break;\n        case RidMessageType.LogDebug:\n          prefix = DEBG_PREFIX;\n          break;\n      }\n\n      debugPrint('$prefix: ${msg.message}');\n    });\n  }\n\n  void dispose() {\n    _logMessagesSub?.cancel();\n    _logMessagesSub = null;\n  }\n\n  static LogMessageHandler? _instance;\n  static LogMessageHandler get instance {\n    _instance ??= LogMessageHandler._();\n    return _instance!;\n  }\n}\n\nclass ErrorHandler {\n  BuildContext? _context;\n  late final StreamSubscription<RidMessage>? _errorSub;\n\n  ErrorHandler._() {\n    _errorSub = rid.messageChannel.stream.listen((RidMessage msg) {\n      switch (msg.type) {\n        case RidMessageType.LogWarn:\n        case RidMessageType.LogInfo:\n        case RidMessageType.LogDebug:\n        case RidMessageType.MsgWarn:\n        case RidMessageType.MsgInfo:\n          return;\n        case RidMessageType.Severe:\n          final indentedDetails = msg.details?.split('\\n').join(DETAILS_INDENT);\n          debugPrint(\n              '$ERR_PREFIX: ${msg.message}$DETAILS_INDENT$indentedDetails');\n\n          // Show UI message if we were provided a BuildContext\n          if (_context != null) {\n            ScaffoldMessenger.of(_context!).showMaterialBanner(\n              MaterialBanner(\n                backgroundColor: Colors.deepOrange,\n                content: Text(msg.message),\n                actions: [\n                  TextButton(\n                    child: const Text('Dismiss'),\n                    onPressed: () => ScaffoldMessenger.of(_context!)\n                        .hideCurrentMaterialBanner(),\n                  ),\n                ],\n              ),\n            );\n          }\n          break;\n\n        case RidMessageType.Error:\n          final indentedDetails = msg.details?.split('\\n').join('\\n    ');\n          debugPrint('$ERR_PREFIX: ${msg.message}\\n       $indentedDetails');\n\n          // Show UI message if we were provided a BuildContext\n          if (_context != null) {\n            ScaffoldMessenger.of(_context!).showSnackBar(\n              SnackBar(\n                backgroundColor: Colors.orange,\n                content: Text(msg.message),\n              ),\n            );\n          }\n          break;\n      }\n    });\n  }\n\n  set context(BuildContext val) => _context = val;\n\n  void dispose() {\n    _errorSub?.cancel();\n    _errorSub = null;\n  }\n\n  static ErrorHandler? _instance;\n  static ErrorHandler get instance {\n    _instance ??= ErrorHandler._();\n    return _instance!;\n  }\n}\n\nclass UserMsgHandler {\n  BuildContext? _context;\n  late final StreamSubscription<RidMessage>? _errorSub;\n\n  UserMsgHandler._() {\n    _errorSub = rid.messageChannel.stream.listen((RidMessage msg) {\n      switch (msg.type) {\n        case RidMessageType.LogWarn:\n        case RidMessageType.LogInfo:\n        case RidMessageType.LogDebug:\n        case RidMessageType.Severe:\n        case RidMessageType.Error:\n          return;\n        case RidMessageType.MsgWarn:\n          debugPrint('$WARN_PREFIX ${msg.message}');\n\n          // Show UI message if we were provided a BuildContext\n          if (_context != null) {\n            ScaffoldMessenger.of(_context!).showMaterialBanner(\n              MaterialBanner(\n                backgroundColor: Colors.orange,\n                content: Text(msg.message),\n                actions: [\n                  TextButton(\n                    child: const Text('Dismiss'),\n                    onPressed: () => ScaffoldMessenger.of(_context!)\n                        .hideCurrentMaterialBanner(),\n                  ),\n                ],\n              ),\n            );\n          } else {\n            debugPrint(\n                'WARN: cannot show user message since no `BuildContext` was provided to UserMsgHandler');\n          }\n          break;\n\n        case RidMessageType.MsgInfo:\n          debugPrint('$INFO_PREFIX ${msg.message}');\n\n          // Show UI message if we were provided a BuildContext\n          if (_context != null) {\n            ScaffoldMessenger.of(_context!).showSnackBar(\n              SnackBar(\n                backgroundColor: Colors.orange,\n                content: Text(msg.message),\n              ),\n            );\n          } else {\n            debugPrint(\n                'WARN: cannot show user message since no `BuildContext` was provided to UserMsgHandler');\n          }\n          break;\n      }\n    });\n  }\n\n  set context(BuildContext val) => _context = val;\n\n  void dispose() {\n    _errorSub?.cancel();\n    _errorSub = null;\n  }\n\n  static UserMsgHandler? _instance;\n  static UserMsgHandler get instance {\n    _instance ??= UserMsgHandler._();\n    return _instance!;\n  }\n}\n\nclass RidMessaging {\n  static void init() {\n    LogMessageHandler.instance;\n    ErrorHandler.instance;\n    UserMsgHandler.instance;\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/lib/views/add_post.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:flutter_bloc/flutter_bloc.dart';\nimport 'package:reddit_ticker/cubit/add_post_cubit.dart';\n\nclass AddPostView extends StatefulWidget {\n  @override\n  State<AddPostView> createState() => _AddPostViewState();\n}\n\nclass _AddPostViewState extends State<AddPostView> {\n  final _textFieldController = TextEditingController();\n  String? addPostURL;\n\n  @override\n  Widget build(BuildContext context) {\n    return FloatingActionButton(\n      onPressed: () async {\n        _textFieldController.clear();\n        await _addPostDialog(context);\n\n        final url = addPostURL;\n        if (url != null && url.trim().isNotEmpty) {\n          context.read<AddPostCubit>().addPost(url);\n        }\n      },\n      tooltip: 'Add URL of Post to Watch',\n      child: BlocListener<AddPostCubit, AddPostState>(\n        listener: (context, state) {\n          if (state is AddPostFailed) {\n            ScaffoldMessenger.of(context).showSnackBar(\n              SnackBar(\n                backgroundColor: Colors.red,\n                content: Text('Failed to add Post'),\n              ),\n            );\n          }\n        },\n        child: Icon(Icons.add),\n      ),\n    );\n  }\n\n  Future<void> _addPostDialog(BuildContext context) async {\n    return showDialog(\n        context: context,\n        builder: (context) {\n          return AlertDialog(\n            title: Text('Enter Post URL'),\n            content: TextField(\n              controller: _textFieldController,\n              decoration: InputDecoration(\n                hintText:\n                    \"https://www.reddit.com/r/rust/comments/ncc9vc/rid_integrate_rust_into_your_dart_or_flutter_app/\",\n              ),\n              autofocus: true,\n              onSubmitted: (_) => _onSubmitted(),\n            ),\n            actions: <Widget>[\n              TextButton(\n                child: Text('Done'),\n                onPressed: _onSubmitted,\n              ),\n            ],\n          );\n        });\n  }\n\n  void _onSubmitted() {\n    addPostURL = _textFieldController.value.text;\n    Navigator.pop(context);\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/lib/views/post.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:flutter_bloc/flutter_bloc.dart';\nimport 'package:plugin/generated/rid_api.dart';\nimport 'package:reddit_ticker/cubit/post_cubit.dart';\n\nimport 'package:charts_flutter/flutter.dart' as charts;\n\ncharts.Series<Score, double> _toChartData(List<Score> scores) {\n  return charts.Series<Score, double>(\n      id: 'Scores',\n      colorFn: (_, __) => charts.MaterialPalette.blue.shadeDefault,\n      domainFn: (Score score, _) => score.secsSincePostAdded / 60.0,\n      measureFn: (Score score, _) => score.score,\n      data: scores);\n}\n\nclass PostView extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return BlocBuilder<PostCubit, PostState>(builder: (context, state) {\n      if (state is PostActive) {\n        final post = state.post;\n        final chartData = _toChartData(post.scores);\n        final chart = charts.LineChart([chartData], animate: true);\n        return Dismissible(\n          key: Key(\"Post Dismissible ${state.post.id}\"),\n          child: Card(\n            child: InkWell(\n              child: ListTile(\n                title: Center(\n                  child: MouseRegion(\n                    cursor: SystemMouseCursors.click,\n                    child: Text(\n                      post.title,\n                      style: Theme.of(context).textTheme.headline6!.copyWith(\n                            decoration: TextDecoration.underline,\n                            overflow: TextOverflow.ellipsis,\n                            color: Colors.blue,\n                          ),\n                    ),\n                  ),\n                ),\n                subtitle: SizedBox(\n                  height: 140,\n                  child: chart,\n                ),\n                onTap: () => {/* TODO: launch post url */},\n              ),\n            ),\n          ),\n          confirmDismiss: (_) => context.read<PostCubit>().stopWatching(),\n          background: Padding(\n            padding: EdgeInsets.all(5.0),\n            child: Container(color: Colors.red),\n          ),\n        );\n      } else {\n        return Card(child: Text('Post removed'));\n      }\n    });\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/lib/views/posts.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:flutter_bloc/flutter_bloc.dart';\nimport 'package:reddit_ticker/cubit/post_cubit.dart';\nimport 'package:reddit_ticker/cubit/posts_cubit.dart';\nimport 'package:reddit_ticker/views/post.dart';\n\nclass PostsView extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Center(\n      child: BlocBuilder<PostsCubit, PostsState>(builder: (context, state) {\n        final posts = state.posts;\n        return ListView.builder(\n            itemCount: posts.length,\n            itemBuilder: (context, index) {\n              final post = posts[index];\n              return MultiBlocProvider(\n                providers: [\n                  BlocProvider<PostCubit>(create: (_) => PostCubit(post)),\n                ],\n                child: PostView(),\n                key: Key(post.hashCode.toString()),\n              );\n            });\n      }),\n    );\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/macos/.gitignore",
    "content": "# Flutter-related\n**/Flutter/ephemeral/\n**/Pods/\n\n# Xcode-related\n**/xcuserdata/\n"
  },
  {
    "path": "flutter/reddit_ticker/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": "flutter/reddit_ticker/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": "flutter/reddit_ticker/macos/Flutter/GeneratedPluginRegistrant.swift",
    "content": "//\n//  Generated file. Do not edit.\n//\n\nimport FlutterMacOS\nimport Foundation\n\nimport path_provider_macos\nimport plugin\n\nfunc RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {\n  PathProviderPlugin.register(with: registry.registrar(forPlugin: \"PathProviderPlugin\"))\n  Plugin.register(with: registry.registrar(forPlugin: \"Plugin\"))\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/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": "flutter/reddit_ticker/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": "flutter/reddit_ticker/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": "flutter/reddit_ticker/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            </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": "flutter/reddit_ticker/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 = reddit_ticker\n\n// The application's bundle identifier\nPRODUCT_BUNDLE_IDENTIFIER = com.example.redditTicker\n\n// The copyright displayed in application information\nPRODUCT_COPYRIGHT = Copyright © 2021 com.example. All rights reserved.\n"
  },
  {
    "path": "flutter/reddit_ticker/macos/Runner/Configs/Debug.xcconfig",
    "content": "#include \"../../Flutter/Flutter-Debug.xcconfig\"\n#include \"Warnings.xcconfig\"\n"
  },
  {
    "path": "flutter/reddit_ticker/macos/Runner/Configs/Release.xcconfig",
    "content": "#include \"../../Flutter/Flutter-Release.xcconfig\"\n#include \"Warnings.xcconfig\"\n"
  },
  {
    "path": "flutter/reddit_ticker/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": "flutter/reddit_ticker/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.server</key>\n\t<true/>\n  <key>com.apple.security.network.client</key>\n  <true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "flutter/reddit_ticker/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": "flutter/reddit_ticker/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": "flutter/reddit_ticker/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  <key>com.apple.security.network.client</key>\n  <true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "flutter/reddit_ticker/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": "flutter/reddit_ticker/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": "flutter/reddit_ticker/plugin/.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# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.\n/pubspec.lock\n**/doc/api/\n.dart_tool/\n.packages\nbuild/\n"
  },
  {
    "path": "flutter/reddit_ticker/plugin/LICENSE",
    "content": "TODO: Add your license here.\n"
  },
  {
    "path": "flutter/reddit_ticker/plugin/analysis_options.yaml",
    "content": "include: package:flutter_lints/flutter.yaml\n\n# Additional information about this file can be found at\n# https://dart.dev/guides/language/analysis-options\n"
  },
  {
    "path": "flutter/reddit_ticker/plugin/android/.gitignore",
    "content": "*.iml\n.gradle\n/local.properties\n/.idea/workspace.xml\n/.idea/libraries\n.DS_Store\n/build\n/captures\n"
  },
  {
    "path": "flutter/reddit_ticker/plugin/android/build.gradle",
    "content": "group 'com.example.plugin'\nversion '1.0-SNAPSHOT'\n\nbuildscript {\n    ext.kotlin_version = '1.3.50'\n    repositories {\n        google()\n        mavenCentral()\n    }\n\n    dependencies {\n        classpath 'com.android.tools.build:gradle:4.1.0'\n        classpath \"org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version\"\n    }\n}\n\nrootProject.allprojects {\n    repositories {\n        google()\n        mavenCentral()\n    }\n}\n\napply plugin: 'com.android.library'\napply plugin: 'kotlin-android'\n\nandroid {\n    compileSdkVersion 30\n\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n\n    kotlinOptions {\n        jvmTarget = '1.8'\n    }\n\n    sourceSets {\n        main.java.srcDirs += 'src/main/kotlin'\n    }\n\n    defaultConfig {\n        minSdkVersion 16\n    }\n}\n\ndependencies {\n    implementation \"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version\"\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/plugin/android/gradle/wrapper/gradle-wrapper.properties",
    "content": "distributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-6.7-all.zip\n"
  },
  {
    "path": "flutter/reddit_ticker/plugin/android/gradle.properties",
    "content": "org.gradle.jvmargs=-Xmx1536M\nandroid.useAndroidX=true\nandroid.enableJetifier=true\n"
  },
  {
    "path": "flutter/reddit_ticker/plugin/android/settings.gradle",
    "content": "rootProject.name = 'plugin'\n"
  },
  {
    "path": "flutter/reddit_ticker/plugin/android/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n  package=\"com.example.plugin\">\n</manifest>\n"
  },
  {
    "path": "flutter/reddit_ticker/plugin/android/src/main/kotlin/com/example/plugin/Plugin.kt",
    "content": "package com.example.plugin\n\nimport androidx.annotation.NonNull\n\nimport io.flutter.embedding.engine.plugins.FlutterPlugin\nimport io.flutter.plugin.common.MethodCall\nimport io.flutter.plugin.common.MethodChannel\nimport io.flutter.plugin.common.MethodChannel.MethodCallHandler\nimport io.flutter.plugin.common.MethodChannel.Result\n\n/** Plugin */\nclass Plugin: FlutterPlugin, MethodCallHandler {\n  /// The MethodChannel that will the communication between Flutter and native Android\n  ///\n  /// This local reference serves to register the plugin with the Flutter Engine and unregister it\n  /// when the Flutter Engine is detached from the Activity\n  private lateinit var channel : MethodChannel\n\n  override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {\n    channel = MethodChannel(flutterPluginBinding.binaryMessenger, \"plugin\")\n    channel.setMethodCallHandler(this)\n  }\n\n  override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {\n    if (call.method == \"getPlatformVersion\") {\n      result.success(\"Android ${android.os.Build.VERSION.RELEASE}\")\n    } else {\n      result.notImplemented()\n    }\n  }\n\n  override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {\n    channel.setMethodCallHandler(null)\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/plugin/ios/.gitignore",
    "content": ".idea/\n.vagrant/\n.sconsign.dblite\n.svn/\n\n.DS_Store\n*.swp\nprofile\n\nDerivedData/\nbuild/\nGeneratedPluginRegistrant.h\nGeneratedPluginRegistrant.m\n\n.generated/\n\n*.pbxuser\n*.mode1v3\n*.mode2v3\n*.perspectivev3\n\n!default.pbxuser\n!default.mode1v3\n!default.mode2v3\n!default.perspectivev3\n\nxcuserdata\n\n*.moved-aside\n\n*.pyc\n*sync/\nIcon?\n.tags*\n\n/Flutter/Generated.xcconfig\n/Flutter/ephemeral/\n/Flutter/flutter_export_environment.sh"
  },
  {
    "path": "flutter/reddit_ticker/plugin/ios/Assets/.gitkeep",
    "content": ""
  },
  {
    "path": "flutter/reddit_ticker/plugin/ios/Classes/Plugin.h",
    "content": "#import <Flutter/Flutter.h>\n\n@interface Plugin : NSObject<FlutterPlugin>\n@end\n"
  },
  {
    "path": "flutter/reddit_ticker/plugin/ios/Classes/Plugin.m",
    "content": "#import \"Plugin.h\"\n#if __has_include(<plugin/plugin-Swift.h>)\n#import <plugin/plugin-Swift.h>\n#else\n// Support project import fallback if the generated compatibility header\n// is not copied when this plugin is created as a library.\n// https://forums.swift.org/t/swift-static-libraries-dont-copy-generated-objective-c-header/19816\n#import \"plugin-Swift.h\"\n#endif\n\n@implementation Plugin\n+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {\n  [SwiftPlugin registerWithRegistrar:registrar];\n}\n@end\n"
  },
  {
    "path": "flutter/reddit_ticker/plugin/ios/Classes/SwiftPlugin.swift",
    "content": "import Flutter\nimport UIKit\n\npublic class SwiftPlugin: NSObject, FlutterPlugin {\n  public static func register(with registrar: FlutterPluginRegistrar) {\n  }\n\n  public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {\n    result(nil)\n  }\n}\n// <rid:prevent_tree_shake Start>\nfunc dummyCallsToPreventTreeShaking() {\n    _to_dart_for_Score();\n    rid_score_debug(nil);\n    rid_score_debug_pretty(nil);\n    rid_score_secs_since_post_added(nil);\n    rid_score_score(nil);\n    rid_cstring_free(nil);\n    rid_init_msg_isolate(0);\n    rid_init_reply_isolate(0);\n    _to_dart_for_Post();\n    rid_post_debug(nil);\n    rid_post_debug_pretty(nil);\n    __include_dart_for_vec_score();\n    rid_post_id(nil);\n    rid_post_id_len(nil);\n    rid_post_title(nil);\n    rid_post_title_len(nil);\n    rid_post_url(nil);\n    rid_post_url_len(nil);\n    rid_post_scores(nil);\n    rid_len_vec_score(nil);\n    rid_get_item_vec_score(nil, 0);\n    _to_dart_for_Store();\n    create_store();\n    rid_store_unlock();\n    rid_store_free();\n    __include_dart_for_hash_map_string_post();\n    rid_store_posts(nil);\n    rid_export_rid_len_hash_map_string_post(nil);\n    rid_export_rid_get_hash_map_string_post(nil, nil);\n    rid_export_rid_contains_key_hash_map_string_post(nil, nil);\n    rid_export_rid_keys_hash_map_string_post(nil);\n    __include_dart_for_ridvec_string();\n    rid_free_ridvec_string(RidVec_Pointer_String());\n    rid_get_item_ridvec_string(RidVec_Pointer_String(), 0);\n    _include_Store_field_wrappers();\n    rid_msg_Initialize(0, nil);\n    rid_msg_StartWatching(0, nil);\n    rid_msg_StopWatching(0, nil);\n}\n// <rid:prevent_tree_shake End>"
  },
  {
    "path": "flutter/reddit_ticker/plugin/ios/plugin.podspec",
    "content": "#\n# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html.\n# Run `pod lib lint plugin.podspec` to validate before publishing.\n#\nPod::Spec.new do |s|\n  s.name             = 'plugin'\n  s.version          = '0.0.1'\n  s.summary          = 'Rust bridge.'\n  s.description      = <<-DESC\nA flutter Rust bridge project.\n                       DESC\n  s.homepage         = 'http://example.com'\n  s.license          = { :file => '../LICENSE' }\n  s.author           = { 'Your Company' => 'email@example.com' }\n  s.source           = { :path => '.' }\n\n  s.source_files = 'Classes/**/*'\n  s.dependency 'Flutter'\n  s.platform = :ios, '8.0'\n\n  # Flutter.framework does not contain a i386 slice.\n  s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' }\n  s.swift_version = '5.0'\n\n  s.public_header_files = 'Classes**/*.h'\n  s.static_framework = true\n  s.vendored_libraries = '**/*.a'\nend\n"
  },
  {
    "path": "flutter/reddit_ticker/plugin/lib/plugin.dart",
    "content": "\nimport 'dart:async';\n\nimport 'package:flutter/services.dart';\n\nclass Plugin {\n  static const MethodChannel _channel = MethodChannel('plugin');\n\n  static Future<String?> get platformVersion async {\n    final String? version = await _channel.invokeMethod('getPlatformVersion');\n    return version;\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/plugin/macos/Classes/Plugin.swift",
    "content": "import Cocoa\nimport FlutterMacOS\n\npublic class Plugin: NSObject, FlutterPlugin {\n  public static func register(with registrar: FlutterPluginRegistrar) {\n  }\n\n  public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {\n    result(nil)\n  }\n}\n// <rid:prevent_tree_shake Start>\nfunc dummyCallsToPreventTreeShaking() {\n    _to_dart_for_Score();\n    rid_score_debug(nil);\n    rid_score_debug_pretty(nil);\n    rid_score_secs_since_post_added(nil);\n    rid_score_score(nil);\n    rid_cstring_free(nil);\n    rid_init_msg_isolate(0);\n    rid_init_reply_isolate(0);\n    _to_dart_for_Post();\n    rid_post_debug(nil);\n    rid_post_debug_pretty(nil);\n    __include_dart_for_vec_score();\n    rid_post_id(nil);\n    rid_post_id_len(nil);\n    rid_post_title(nil);\n    rid_post_title_len(nil);\n    rid_post_url(nil);\n    rid_post_url_len(nil);\n    rid_post_scores(nil);\n    rid_len_vec_score(nil);\n    rid_get_item_vec_score(nil, 0);\n    _to_dart_for_Store();\n    create_store();\n    rid_store_unlock();\n    rid_store_free();\n    __include_dart_for_hash_map_string_post();\n    rid_store_posts(nil);\n    rid_export_rid_len_hash_map_string_post(nil);\n    rid_export_rid_get_hash_map_string_post(nil, nil);\n    rid_export_rid_contains_key_hash_map_string_post(nil, nil);\n    rid_export_rid_keys_hash_map_string_post(nil);\n    __include_dart_for_ridvec_string();\n    rid_free_ridvec_string(RidVec_Pointer_String());\n    rid_get_item_ridvec_string(RidVec_Pointer_String(), 0);\n    _include_Store_field_wrappers();\n    rid_msg_Initialize(0, nil);\n    rid_msg_StartWatching(0, nil);\n    rid_msg_StopWatching(0, nil);\n}\n// <rid:prevent_tree_shake End>"
  },
  {
    "path": "flutter/reddit_ticker/plugin/macos/plugin.podspec",
    "content": "#\n# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html.\n# Run `pod lib lint plugin.podspec` to validate before publishing.\n#\nPod::Spec.new do |s|\n  s.name             = 'plugin'\n  s.version          = '0.0.1'\n  s.summary          = 'Rust bridge.'\n  s.description      = <<-DESC\nA flutter Rust bridge project.\n                       DESC\n  s.homepage         = 'http://example.com'\n  s.license          = { :file => '../LICENSE' }\n  s.author           = { 'Your Company' => 'email@example.com' }\n  s.source           = { :path => '.' }\n  s.source_files     = 'Classes/**/*'\n  s.dependency 'FlutterMacOS'\n\n  s.platform = :osx, '10.11'\n  s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES' }\n  s.swift_version = '5.0'\n\n  s.public_header_files = 'Classes**/*.h'\n  s.static_framework = true\n  s.vendored_libraries = '**/*.a'\nend\n"
  },
  {
    "path": "flutter/reddit_ticker/plugin/pubspec.yaml",
    "content": "name: plugin\ndescription: Plugin to provide a bridge to Rust.\nversion: 0.0.1\n\nenvironment:\n  sdk: \">=2.13.0 <3.0.0\"\n  flutter: \">=2.0.0\"\n\ndependencies:\n  ffi: ^1.0.0\n  ffigen: 4.0.0-dev.2\n\n  flutter:\n    sdk: flutter\n\nflutter:\n  # This section identifies this Flutter project as a plugin project.\n  # The 'pluginClass' and Android 'package' identifiers should not ordinarily\n  # be modified. They are used by the tooling to maintain consistency when\n  # adding or updating assets for this project.\n  plugin:\n    platforms:\n      android:\n        package: com.example.plugin\n        pluginClass: Plugin\n      ios:\n        pluginClass: Plugin\n      macos:\n        pluginClass: Plugin\n"
  },
  {
    "path": "flutter/reddit_ticker/pubspec.yaml",
    "content": "name: reddit_ticker\ndescription: A new Flutter project.\n\npublish_to: 'none' # Remove this line if you wish to publish to pub.dev\n\nversion: 1.0.0+1\n\nenvironment:\n  sdk: \">=2.13.0 <3.0.0\"\n\ndependencies:\n  flutter:\n    sdk: flutter\n\n  plugin:\n    path: plugin\n\n  cupertino_icons: ^1.0.2\n  bloc: ^7.1.0\n  flutter_bloc: ^7.2.0\n\n  charts_flutter:\n    path: ./deps/charts/charts_flutter\n  path_provider: ^2.0.5\n\ndev_dependencies:\n  flutter_test:\n    sdk: flutter\n\nflutter:\n\n  uses-material-design: true\n\n  assets:\n    - assets/dash.png\n    - assets/ferris.png\n"
  },
  {
    "path": "flutter/reddit_ticker/reddit_ticker.iml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<module type=\"JAVA_MODULE\" version=\"4\">\n  <component name=\"NewModuleRootManager\" inherit-compiler-output=\"true\">\n    <exclude-output />\n    <content url=\"file://$MODULE_DIR$\">\n      <sourceFolder url=\"file://$MODULE_DIR$/lib\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/test\" isTestSource=\"true\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/.dart_tool\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/.idea\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/.pub\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build\" />\n    </content>\n    <orderEntry type=\"sourceFolder\" forTests=\"false\" />\n    <orderEntry type=\"library\" name=\"Dart SDK\" level=\"project\" />\n    <orderEntry type=\"library\" name=\"Flutter Plugins\" level=\"project\" />\n    <orderEntry type=\"library\" name=\"Dart Packages\" level=\"project\" />\n  </component>\n</module>"
  },
  {
    "path": "flutter/reddit_ticker/rid_build.rs",
    "content": "use rid_build::{build, BuildConfig, BuildTarget, FlutterConfig, FlutterPlatform, Project};\nuse std::env;\n\nfn main() {\n    let crate_dir = env::var(\"CARGO_MANIFEST_DIR\")\n        .expect(\"Missing CARGO_MANIFEST_DIR, please run this via 'cargo run'\");\n\n    let workspace_dir = &crate_dir;\n\n    let crate_name = &env::var(\"CARGO_PKG_NAME\")\n        .expect(\"Missing CARGO_PKG_NAME, please run this via 'cargo run'\");\n    let lib_name = &format!(\"lib{}\", &crate_name);\n\n    let project = match &env::var(\"TEST_DART\") {\n        Ok(_) => Project::Dart,\n        Err(_) => Project::Flutter(FlutterConfig {\n            plugin_name: \"plugin\".to_string(),\n            platforms: vec![\n                // Mobile\n                FlutterPlatform::ios(),\n                FlutterPlatform::android(),\n                // Desktop\n                FlutterPlatform::macos(),\n            ],\n        }),\n    };\n\n    let build_config = BuildConfig {\n        target: BuildTarget::Debug,\n        project,\n        lib_name,\n        crate_name,\n        project_root: &crate_dir,\n        workspace_root: Some(&workspace_dir),\n    };\n    build(&build_config).expect(\"Build failed\");\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/sh/android",
    "content": "#!/usr/bin/env bash\n\nDIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" >/dev/null 2>&1 && pwd )\"\n\nANDROID_PLATFORM_VERSION=28\n# x86 (i686)\n# ANDROID_BUILD_TARGET=i686-linux-android\n\n# x86_64\n# ANDROID_BUILD_TARGET=x86_64-linux-android\n\n# arm64\nANDROID_BUILD_TARGET=arm64-v8a\n\n# armeabi\n# ANDROID_BUILD_TARGET=armeabi-v7a\n\nANDROID_DIR=$DIR/../plugin/android\nJNI_LIBS_DIR=$ANDROID_DIR/src/main/jniLibs\n\n# Install Android NDK https://developer.android.com/studio/projects/install-ndk\n# https://github.com/bbqsrc/cargo-ndk\ncargo ndk                              \\\n  --platform $ANDROID_PLATFORM_VERSION \\\n  --target $ANDROID_BUILD_TARGET       \\\n  --output-dir $JNI_LIBS_DIR           \\\n  build\n"
  },
  {
    "path": "flutter/reddit_ticker/sh/bindgen",
    "content": "#!/usr/bin/env bash\n\nDIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" >/dev/null 2>&1 && pwd )\"\n\ncd $DIR/.. && cargo run rid_build\n"
  },
  {
    "path": "flutter/reddit_ticker/sh/bindgen-dart",
    "content": "#!/usr/bin/env bash\n\nDIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" >/dev/null 2>&1 && pwd )\"\n\ncd $DIR/.. && TEST_DART=1 cargo run rid_build\n"
  },
  {
    "path": "flutter/reddit_ticker/sh/clean",
    "content": "#!/usr/bin/env bash\n\nDIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" >/dev/null 2>&1 && pwd )\"\n\n(cd $DIR/../plugin && flutter clean && flutter pub get)\n(cd $DIR/.. && flutter clean && flutter pub get)\n"
  },
  {
    "path": "flutter/reddit_ticker/sh/ios",
    "content": "#!/usr/bin/env bash\n\nDIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" >/dev/null 2>&1 && pwd )\"\n\nIOS_TARGETS=x86_64-apple-ios\n\n# Alternative not using jq\n# WORKSPACE_CARGO_TOML=`cargo locate-project --workspace --message-format plain`\n# WORKSPACE_ROOT=$(dirname \"${WORKSPACE_CARGO_TOML}\")\n# TARGET_DIR=$WORKSPACE_ROOT/target\n\nTARGET_DIR=`cargo metadata --format-version 1 --no-deps | jq \".target_directory\" | xargs echo`\nPROJECT_NAME=`cargo metadata --format-version 1 | jq \".resolve.root\" | xargs echo | cut -d ' ' -f1`\nLIB_NAME=lib$PROJECT_NAME.a\n\n# <root>/target/universal/debug\nUNIVERSAL_DEBUG_DIR=\"$TARGET_DIR/universal/debug\"\nFLUTTER_IOS_DIR=\"$DIR/../plugin/ios\"\n\nLIB_SOURCE_FILE=\"$UNIVERSAL_DEBUG_DIR/$LIB_NAME\"\nLIB_TARGET_FILE=\"$FLUTTER_IOS_DIR/$LIB_NAME\"\n\ncargo lipo --targets $IOS_TARGETS && \\\n  cp $LIB_SOURCE_FILE $LIB_TARGET_FILE\n"
  },
  {
    "path": "flutter/reddit_ticker/sh/linux",
    "content": "#!/usr/bin/env bash\n\nDIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" >/dev/null 2>&1 && pwd )\"\n\nTARGET_DIR=`cargo metadata --format-version 1 --no-deps | jq \".target_directory\" | xargs echo`\nPROJECT_NAME=`cargo metadata --format-version 1 | jq \".resolve.root\" | xargs echo | cut -d ' ' -f1`\nLIB_NAME_STATIC=lib$PROJECT_NAME.a\nLIB_NAME_DYNAMIC=lib$PROJECT_NAME.so\n\n# <root>/target/universal/debug\nUNIVERSAL_DEBUG_DIR=\"$TARGET_DIR/debug\"\nFLUTTER_LINUX_DIR=\"$DIR/../plugin/linux\"\n\nmkdir -p $FLUTTER_LINUX_DIR\n\nLIB_SOURCE_FILE_STATIC=\"$UNIVERSAL_DEBUG_DIR/$LIB_NAME_STATIC\"\nLIB_SOURCE_FILE_DYNAMIC=\"$UNIVERSAL_DEBUG_DIR/$LIB_NAME_DYNAMIC\"\nLIB_TARGET_FILE_STATIC=\"$FLUTTER_LINUX_DIR/$LIB_NAME_STATIC\"\nLIB_TARGET_FILE_DYNAMIC=\"$FLUTTER_LINUX_DIR/$LIB_NAME_DYNAMIC\"\n\ncargo build &&                                          \\\n  cp $LIB_SOURCE_FILE_STATIC $LIB_TARGET_FILE_STATIC && \\\n  cp $LIB_SOURCE_FILE_DYNAMIC $LIB_TARGET_FILE_DYNAMIC\n\nexit $?\n"
  },
  {
    "path": "flutter/reddit_ticker/sh/macos",
    "content": "#!/usr/bin/env bash\n\nDIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" >/dev/null 2>&1 && pwd )\"\n\nMACOS_TARGETS=aarch64-apple-ios\n\nTARGET_DIR=`cargo metadata --format-version 1 --no-deps | jq \".target_directory\" | xargs echo`\nPROJECT_NAME=`cargo metadata --format-version 1 | jq \".resolve.root\" | xargs echo | cut -d ' ' -f1`\nLIB_NAME=lib$PROJECT_NAME.a\n\n# <root>/target/universal/debug\nUNIVERSAL_DEBUG_DIR=\"$TARGET_DIR/debug\"\nFLUTTER_MACOS_DIR=\"$DIR/../plugin/macos\"\n\nLIB_SOURCE_FILE=\"$UNIVERSAL_DEBUG_DIR/$LIB_NAME\"\nLIB_TARGET_FILE=\"$FLUTTER_MACOS_DIR/$LIB_NAME\"\n\ncargo build && \\\n  cp $LIB_SOURCE_FILE $LIB_TARGET_FILE\n"
  },
  {
    "path": "flutter/reddit_ticker/sql/all-posts.sql",
    "content": "SELECT * from reddit_posts;\n"
  },
  {
    "path": "flutter/reddit_ticker/sql/all-scores.sql",
    "content": "SELECT * from reddit_scores;\n"
  },
  {
    "path": "flutter/reddit_ticker/src/db.rs",
    "content": "use std::time::{Duration, SystemTime, UNIX_EPOCH};\n\nuse anyhow::{anyhow, Result};\nuse rusqlite::{params, Connection, Row, NO_PARAMS};\n\nuse crate::reddit::{Post, Score};\n\npub const DB_NAME: &str = \"reddit_ticker.sqlite\";\n\npub struct DB {\n    conn: Connection,\n}\n\nimpl DB {\n    pub fn new(path: &str) -> Result<Self> {\n        let conn = Connection::open(path)\n            .map_err(|err| anyhow!(\"Failed to open Database at: {}\\nError: {}\", path, err))?;\n\n        let db = Self { conn };\n        db.init_tables()?;\n\n        Ok(db)\n    }\n\n    fn init_tables(&self) -> Result<()> {\n        self.conn\n            .execute_batch(\n                \"\nBEGIN;\nCREATE TABLE IF NOT EXISTS reddit_posts (\n    post_id  TEXT PRIMARY KEY,\n    title    TEXT,\n    url      TEXT,\n    added    INTEGER\n);\nCREATE TABLE IF NOT EXISTS reddit_scores (\n    post_id   TEXT,\n    added     INTEGER,\n    score     INTEGER\n);\nCREATE INDEX IF NOT EXISTS idx_post_id ON reddit_scores (post_id);\nCOMMIT;\n\",\n            )\n            .map_err(|err| anyhow!(\"Failed to create Database tables:\\nError: {}\", err))\n    }\n\n    // -----------------\n    // Insert Posts and Scores\n    // -----------------\n\n    pub fn insert_post(&self, post: &Post) -> Result<usize> {\n        let added: u32 = time_stamp_to_secs(post.added);\n        self.conn\n            .execute(\n                \"\nINSERT OR IGNORE INTO reddit_posts (post_id, title, url, added)\nVALUES (?1, ?2, ?3, ?4);\n                \",\n                params![post.id, post.title, post.url, added],\n            )\n            .map_err(|err| anyhow!(\"Failed to add post with id {}:\\nError: {}\", post.id, err))\n    }\n\n    pub fn insert_score(&self, post_id: &str, time_stamp: SystemTime, score: i32) -> Result<usize> {\n        let added = time_stamp_to_secs(time_stamp);\n        let res = self\n            .conn\n            .execute(\n                \"\nINSERT OR IGNORE INTO reddit_scores (post_id, added, score)\nVALUES (?1, ?2, ?3);\n\",\n                params!(post_id, added, score),\n            )\n            .map_err(|err| {\n                anyhow!(\n                    \"Failed to insert score for post {}:\\nError: {}\",\n                    post_id,\n                    err\n                )\n            })?;\n\n        Ok(res)\n    }\n    // -----------------\n    // Retrieving Posts and Scores\n    // -----------------\n    pub fn get_scores(&self, post: &Post) -> Result<Vec<Score>> {\n        let mut stmt = self.conn.prepare(\n            \"\nSELECT added, score\nFROM reddit_scores\nWHERE post_id = (?1)\n\",\n        )?;\n\n        let results: Vec<_> = stmt\n            .query_map(params!(post.id), |row| try_extract_score(row, post.added))?\n            .filter_map(|x| match x {\n                Ok(score) => Some(score),\n                Err(err) => {\n                    rid::log_warn!(\"Found invalid score in Database {}\", err.to_string());\n                    None\n                }\n            })\n            .collect();\n        Ok(results)\n    }\n\n    pub fn get_all_posts(&self) -> Result<Vec<Post>> {\n        let mut stmt = self.conn.prepare(\n            \"\nSELECT post_id, title, url, added \nFROM reddit_posts;\n\",\n        )?;\n        let results = stmt.query_map(NO_PARAMS, try_extract_post)?;\n        let mut posts: Vec<_> = results\n            .filter_map(|res| match res {\n                Ok(post) => Some(post),\n                Err(err) => {\n                    rid::error!(\"A post couldn't be properly extracted\", err.to_string());\n                    None\n                }\n            })\n            .collect();\n\n        for mut post in posts.iter_mut() {\n            let scores = self.get_scores(&post)?;\n            post.scores = scores\n        }\n        Ok(posts)\n    }\n\n    // -----------------\n    // Deleting Posts and Scores\n    // -----------------\n    pub fn delete_post(&self, post_id: &str) -> Result<usize> {\n        let post_rows_removed = self\n            .conn\n            .execute(\n                \"\nDELETE FROM reddit_posts \nWHERE post_id = (?1);\n\",\n                params!(post_id),\n            )\n            .map_err(|err| anyhow!(\"Failed to remove post from table:\\nError: {}\", err))?;\n\n        let score_rows_removed = self\n            .conn\n            .execute(\n                \"\nDELETE FROM reddit_scores \nWHERE post_id = (?1);\n\",\n                params!(post_id),\n            )\n            .map_err(|err| anyhow!(\"Failed to remove scores from table:\\nError: {}\", err))?;\n        Ok(post_rows_removed + score_rows_removed)\n    }\n}\n\n// -----------------\n// Sqlite helpers\n// -----------------\nfn try_extract_score(row: &Row, post_added: SystemTime) -> rusqlite::Result<Score> {\n    // Score timestamps are stored [UNIX_EPOCH] seconds, however the rest\n    // of the app treats score timestamps based on the time the post was added.\n    let secs: u32 = row.get(0)?;\n    let time_stamp = secs_to_time_stamp(secs);\n    let secs_since_post_added = time_stamp\n        .duration_since(post_added)\n        .expect(\"Invalid timestamp\")\n        .as_secs();\n\n    let score: i32 = row.get(1)?;\n\n    Ok(Score {\n        secs_since_post_added,\n        score,\n    })\n}\n\nfn try_extract_post(row: &Row) -> rusqlite::Result<Post> {\n    Ok(Post {\n        id: row.get(0)?,\n        title: row.get(1)?,\n        url: row.get(2)?,\n        added: secs_to_time_stamp(row.get(3)?),\n        scores: vec![],\n    })\n}\nfn time_stamp_to_secs(time_stamp: SystemTime) -> u32 {\n    // max u32:          4,294,967,295\n    // UNIX_EPOCH secs: ~1,631,804,843\n    time_stamp.duration_since(UNIX_EPOCH).unwrap().as_secs() as u32\n}\n\nfn secs_to_time_stamp(secs: u32) -> SystemTime {\n    UNIX_EPOCH + Duration::from_secs(secs as u64)\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/src/lib.rs",
    "content": "use core::time;\nuse std::{\n    collections::HashMap,\n    path::Path,\n    sync::{RwLockReadGuard, RwLockWriteGuard},\n    thread,\n    time::SystemTime,\n};\n\nuse anyhow::{anyhow, Result};\nuse db::{DB, DB_NAME};\nuse reddit::{query_page, Post};\nuse rid::RidStore;\n\nuse crate::reddit::{query_score, Score, RESOLUTION_MILLIS};\n\nmod db;\nmod reddit;\n\n// -----------------\n// Store\n// -----------------\n#[rid::store]\n#[rid::structs(Post)]\n#[derive(rid::Config)]\npub struct Store {\n    posts: HashMap<String, Post>,\n\n    #[rid(skip)]\n    polling: bool,\n    #[rid(skip)]\n    db: Option<DB>,\n}\n\nimpl RidStore<Msg> for Store {\n    fn create() -> Self {\n        Self {\n            posts: HashMap::new(),\n            polling: false,\n            db: None,\n        }\n    }\n\n    fn update(&mut self, req_id: u64, msg: Msg) {\n        match msg {\n            Msg::Initialize(app_dir) => {\n                // Guard against more than one polling thread\n                if !self.polling {\n                    self.polling = true;\n                    poll_posts();\n                }\n\n                if self.db.is_none() {\n                    let db_path = Path::new(&app_dir)\n                        .join(DB_NAME)\n                        .to_string_lossy()\n                        .to_string();\n\n                    match DB::new(&db_path) {\n                        Ok(db) => {\n                            self.db = Some(db);\n                            rid::log_info!(\"Initialized Database at '{}'\", db_path);\n                        }\n                        Err(err) => {\n                            rid::severe!(\n                                format!(\"Failed to open Database at '{}'\", db_path),\n                                err.to_string()\n                            );\n                        }\n                    }\n                }\n\n                if let Some(db) = &self.db {\n                    self.posts = match db.get_all_posts() {\n                        Ok(posts) => {\n                            let mut map = HashMap::<String, Post>::new();\n                            for post in posts {\n                                map.insert(post.id.clone(), post);\n                            }\n                            map\n                        }\n                        Err(err) => {\n                            rid::error!(\"Failed to retrieve existings posts\", err);\n                            HashMap::new()\n                        }\n                    };\n                }\n\n                rid::post(Reply::Initialized(req_id));\n            }\n\n            Msg::StartWatching(url) => start_watching(req_id, url),\n            Msg::StopWatching(id) => {\n                self.posts.remove(&id);\n                if let Some(db) = &self.db {\n                    match db.delete_post(&id) {\n                        Ok(rows) => {\n                            rid::log_debug!(\"Removed post and {} scores from Database\", rows - 1);\n                        }\n                        Err(err) => {\n                            rid::error!(\"Failed to delete post from Database\", err);\n                        }\n                    };\n                };\n                rid::post(Reply::StoppedWatching(req_id, id));\n            }\n        }\n    }\n}\n\nimpl Store {\n    fn read() -> RwLockReadGuard<'static, Store> {\n        store::read()\n    }\n    fn write() -> RwLockWriteGuard<'static, Store> {\n        store::write()\n    }\n}\n\n// -----------------\n// Message\n// -----------------\n#[rid::message(Reply)]\nenum Msg {\n    Initialize(String),\n\n    StartWatching(String),\n    StopWatching(String),\n}\n\n// -----------------\n// Reply\n// -----------------\n#[rid::reply]\nenum Reply {\n    Initialized(u64),\n\n    StartedWatching(u64, String),\n    StoppedWatching(u64, String),\n    FailedRequest(u64, String),\n\n    UpdatedScores,\n}\n\n// -----------------\n// Start watching Post\n// -----------------\nfn start_watching(req_id: u64, url: String) {\n    thread::spawn(move || match try_start_watching(url) {\n        Ok(post) => {\n            let id = post.id.clone();\n            Store::write().posts.insert(id.clone(), post);\n            rid::post(Reply::StartedWatching(req_id, id))\n        }\n        Err(err) => rid::post(Reply::FailedRequest(req_id, err.to_string())),\n    });\n}\n\nfn try_start_watching(url: String) -> Result<Post> {\n    let page = query_page(&url)\n        .map_err(|err| anyhow!(\"Failed to get valid page data: {}\\nError: {} \", url, err))?;\n\n    rid::log_debug!(\"Got page for url '{}' with id '{}'.\", url, page.id);\n\n    let added = SystemTime::now();\n    let post = Post {\n        added,\n        id: page.id,\n        title: page.title,\n        url: page.url,\n        scores: vec![],\n    };\n\n    if let Some(db) = Store::read().db.as_ref() {\n        if let Err(err) = db.insert_post(&post) {\n            rid::error!(\"Failed to insert post\", err.to_string());\n        }\n    }\n    Ok(post)\n}\n\n// -----------------\n// Polling Scores\n// -----------------\nfn poll_posts() {\n    rid::log_debug!(\"Creating thread to poll post data\");\n    thread::spawn(move || loop {\n        // First we query all posts and only take a write lock on the store once we have all the\n        // data in order to limit the amount of time that the UI or other threads cannot access the\n        // store.\n\n        // In order to release the read lock on the store immediately, we clone the post ids.\n        let post_ids: Vec<_> = { Store::read().posts.keys().cloned().collect() };\n        let scores: Vec<_> = post_ids\n            .into_iter()\n            .map(|id| {\n                let score = query_score(&id);\n                (id, score)\n            })\n            // Filter out all cases where we couldn't update the score and send an error so that we\n            // can log the problem and alert the user\n            .filter_map(|(id, score_res)| match score_res {\n                Ok(score) => Some((id, score)),\n                Err(err) => {\n                    rid::error!(\"Failed to update score for a post\", err.to_string());\n                    None\n                }\n            })\n            .collect();\n\n        {\n            // Aquire a write lock on the store once and make sure it gets dropped (at the end of\n            // this block) when we no longer need it\n            let mut store = Store::write();\n            for (id, score) in scores {\n                // A post could have been removed in between getting the post ids and aquiring\n                // the write lock.\n                if !store.posts.contains_key(&id) {\n                    continue;\n                }\n\n                let time_stamp = SystemTime::now();\n                let post = &mut store.posts.get_mut(&id).unwrap();\n                let secs_since_post_added = time_stamp\n                    .duration_since(post.added)\n                    .expect(\"Getting duration\")\n                    .as_secs();\n\n                post.scores.push(Score {\n                    secs_since_post_added,\n                    score,\n                });\n\n                if let Some(db) = &store.db.as_ref() {\n                    if let Err(err) = db.insert_score(&id, time_stamp, score) {\n                        rid::error!(\"Failed to add score for post\", err.to_string());\n                    }\n                }\n            }\n        }\n        rid::post(Reply::UpdatedScores);\n        thread::sleep(time::Duration::from_millis(RESOLUTION_MILLIS));\n    });\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/src/reddit/mod.rs",
    "content": "#![allow(unused_variables, dead_code)]\nmod reddit;\nmod reddit_api_response;\nmod reddit_page_response;\nuse std::time::SystemTime;\n\npub use reddit::*;\npub use reddit_api_response::*;\npub use reddit_page_response::*;\n\npub const RESOLUTION_MILLIS: u64 = 5_000;\n\n// -----------------\n// Reddit Page\n// -----------------\n#[derive(Debug, Clone)]\npub struct Page {\n    pub id: String,\n    pub title: String,\n    pub url: String,\n}\n\n// -----------------\n// Reddit Score\n// -----------------\n#[rid::model]\n#[derive(Debug)]\npub struct Score {\n    pub secs_since_post_added: u64,\n    pub score: i32,\n}\n\n// -----------------\n// Reddit Post\n// -----------------\n#[rid::model]\n#[rid::structs(Score)]\n#[derive(Debug, rid::Config)]\npub struct Post {\n    #[rid(skip)]\n    pub added: SystemTime,\n\n    pub id: String,\n    pub title: String,\n    pub url: String,\n\n    pub scores: Vec<Score>,\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/src/reddit/reddit.rs",
    "content": "use anyhow::{anyhow, Result};\n\nuse crate::reddit::ApiRoot;\n\nuse super::{Page, PageRoot};\n\npub fn query_page(url: &str) -> Result<Page> {\n    // Cut off query string\n    let url = match url.find(\"?\") {\n        Some(idx) => &url[..idx],\n        None => url,\n    };\n\n    let url = format!(\"{}.json\", url.trim_end_matches(\"/\"));\n\n    let page_response: PageRoot = ureq::get(&url)\n        .set(\"User-Agent\", \"reddit-ticker\")\n        .call()?\n        .into_json()?;\n\n    // .data.children[0].data.{title, id}\n    let data = &page_response\n        .first()\n        .ok_or_else(|| anyhow!(\"Page response did not contain any pages\"))?\n        .data\n        .children\n        .first()\n        .ok_or_else(|| anyhow!(\"The page did not contain any childre\"))?\n        .data;\n\n    let id = data.name.clone();\n\n    let title = data\n        .title\n        .as_ref()\n        .ok_or_else(|| anyhow!(\"Page was missing a title\"))?\n        .clone();\n\n    let url = data\n        .url\n        .as_ref()\n        .ok_or_else(|| anyhow!(\"Page was missing a url\"))?\n        .clone();\n\n    Ok(Page { id, title, url })\n}\n\nconst API_INFO_URL: &str = \"https://api.reddit.com/api/info\";\n\npub fn query_score(id: &str) -> Result<i32> {\n    let url = format!(\"{}?id={}\", API_INFO_URL, id);\n\n    let api_response: ApiRoot = ureq::get(&url)\n        .set(\"User-Agent\", \"reddit-ticker\")\n        .call()?\n        .into_json()?;\n\n    let score = api_response\n        .data\n        .children\n        .first()\n        .ok_or_else(|| anyhow!(\"Post info was missing children\"))?\n        .data\n        .score;\n\n    Ok(score)\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/src/reddit/reddit_api_response.rs",
    "content": "use serde::{Deserialize, Serialize};\n\n#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]\npub struct ApiRoot {\n    pub data: Data,\n}\n\n#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]\npub struct Data {\n    pub children: Vec<Children>,\n}\n\n#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]\npub struct Children {\n    pub data: Data2,\n}\n\n#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]\npub struct Data2 {\n    pub score: i32,\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/src/reddit/reddit_page_response.rs",
    "content": "use serde::{Deserialize, Serialize};\n\npub type PageRoot = Vec<RedditPage>;\n\n#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]\npub struct RedditPage {\n    pub data: ChildContainer,\n}\n\n#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]\npub struct ChildContainer {\n    pub children: Vec<Children>,\n}\n\n#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]\npub struct Children {\n    pub data: ChildData,\n}\n\n#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]\npub struct ChildData {\n    pub name: String,\n    pub title: Option<String>,\n    pub url: Option<String>,\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/test/logging.dart",
    "content": "import 'dart:async';\nimport 'package:reddit_ticker/generated/rid_api.dart';\n\nconst RUST_ICON = '🦀';\nconst WARN_ICON = '⚠️ ';\nconst INFO_ICON = '💡';\nconst DEBG_ICON = '🪲';\nconst ERR_ICON = '❌';\n\nconst WARN_PREFIX = '$RUST_ICON $WARN_ICON';\nconst INFO_PREFIX = '$RUST_ICON $INFO_ICON';\nconst DEBG_PREFIX = '$RUST_ICON $DEBG_ICON';\nconst ERR_PREFIX = '$RUST_ICON $ERR_ICON';\n\nconst DETAILS_INDENT = '\\n       ';\n\nclass LogMessageHandler {\n  late final StreamSubscription<RidMessage>? _logMessagesSub;\n\n  LogMessageHandler._() {\n    _logMessagesSub = rid.messageChannel.stream.listen((RidMessage msg) {\n      late final String prefix;\n      switch (msg.type) {\n        case RidMessageType.Severe:\n        case RidMessageType.Error:\n          return;\n        case RidMessageType.LogWarn:\n          prefix = WARN_PREFIX;\n          break;\n        case RidMessageType.LogInfo:\n          prefix = INFO_PREFIX;\n          break;\n        case RidMessageType.LogDebug:\n          prefix = DEBG_PREFIX;\n          break;\n      }\n\n      print('$prefix: ${msg.message}');\n    });\n  }\n\n  void dispose() {\n    _logMessagesSub?.cancel();\n    _logMessagesSub = null;\n  }\n\n  static LogMessageHandler? _instance;\n  static LogMessageHandler get instance {\n    if (_instance == null) {\n      _instance = LogMessageHandler._();\n    }\n    return _instance!;\n  }\n}\n\nclass ErrorHandler {\n  late final StreamSubscription<RidMessage>? _errorSub;\n\n  ErrorHandler._() {\n    _errorSub = rid.messageChannel.stream.listen((RidMessage msg) {\n      switch (msg.type) {\n        case RidMessageType.LogWarn:\n        case RidMessageType.LogInfo:\n        case RidMessageType.LogDebug:\n          return;\n        case RidMessageType.Severe:\n          final indentedDetails = msg.details?.split('\\n').join(DETAILS_INDENT);\n          print('$ERR_PREFIX: ${msg.message}$DETAILS_INDENT$indentedDetails');\n          break;\n\n        case RidMessageType.Error:\n          final indentedDetails = msg.details?.split('\\n').join('\\n    ');\n          print('$ERR_PREFIX: ${msg.message}\\n       $indentedDetails');\n          break;\n      }\n    });\n  }\n\n  void dispose() {\n    _errorSub?.cancel();\n    _errorSub = null;\n  }\n\n  static ErrorHandler? _instance;\n  static ErrorHandler get instance {\n    if (_instance == null) {\n      _instance = ErrorHandler._();\n    }\n    return _instance!;\n  }\n}\n\nclass RidMessaging {\n  static void init() {\n    LogMessageHandler.instance;\n    ErrorHandler.instance;\n  }\n}\n"
  },
  {
    "path": "flutter/reddit_ticker/test/wip.dart",
    "content": "import 'package:reddit_ticker/generated/rid_api.dart';\n\nimport 'logging.dart';\n\nvoid main() async {\n  RidMessaging.init();\n  final store = Store.instance;\n  print('${store.posts}');\n}\n"
  },
  {
    "path": "flutter/todo/.gitignore",
    "content": ".DS_Store\n.idea/\n.metadata\n\n## Flutter ###\n# Flutter/Dart/Pub related\n**/doc/api/\n.dart_tool/\n.flutter-plugins\n.flutter-plugins-dependencies\n.fvm/\n.packages\n.pub-cache/\n.pub/\nbuild/\ncoverage/\nlib/generated_plugin_registrant.dart\n# For library packages, don’t commit the pubspec.lock file.\n# Regenerating the pubspec.lock file lets you test your package against the latest compatible versions of its dependencies.\n# See https://dart.dev/guides/libraries/private-files#pubspeclock\n#pubspec.lock\n\n# Android related\n**/android/**/gradle-wrapper.jar\n**/android/.gradle\n**/android/captures/\n**/android/gradlew\n**/android/gradlew.bat\n**/android/key.properties\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/.last_build_id\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# 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\n### Rust ###\n**/target/**\n**/Cargo.lock\n\n### Rid ###\n**/generated/**\n**/Classes/bindings.h\n**/macos/*.a\n**/ios/*.a\n**/android/src/main/jniLibs/*\n"
  },
  {
    "path": "flutter/todo/Cargo.toml",
    "content": "[package]\nname = \"todo\"\nversion = \"0.1.0\"\nauthors = [\"Thorsten Lorenz <thlorenz@gmx.de>\"]\nedition = \"2018\"\n\n[lib]\ncrate-type = [\"cdylib\", \"staticlib\" ]\n\n[[bin]]\nname = \"rid_build\"\npath = \"rid_build.rs\"\n\n[dependencies]\ncbindgen = \"0.18.0\"\nrid = { path = \"../../../rid\" }\nrid_build = { path = \"../../../rid/rid-build\" }\n\n[build-dependencies]\nrid_build = { path = \"../../../rid/rid-build\" }\n"
  },
  {
    "path": "flutter/todo/README.md",
    "content": "# Todo App\n\nRust integrated Dart Flutter Project\n\n## Tutorial\n\nA tutorial on how to build this app will be provided shortly on the [rid\nhomepage](https://thlorenz.com/rid-site/docs/examples/flutter-todo-app/).\n\n## Getting Started\n\n_Please see [Caveats](#Caveats) first_.\n\nUse the below scripts to get the app ready to run with Flutter.\n\n### 0. Make sure you have the dependencies\n\n```sh\n# Install the nightly to use some needed features\nrustup toolchain install nightly\n# Switch to the nightly \nrustup default nightly\n```\n\nOn linux, you also need\n\n```sh\nsudo apt-get install libclang-dev jq\n```\n\nfor flutter's `ffigen`.\n\n### 1. Generate Glue Code\n\nBefore generating the glue code for the first time, you need to run `flutter pub get` on the plugin folder\n\n```sh\ncd plugin\nflutter pub get\n```\n\n```sh\n./sh/bindgen\n```\n\n### 2. Build For Desired Target/Device\n\nRun any of the below three to build the binary for the specific device and have it placed into\nthe devices specific plugin folder.\n\nFor macos:\n\n```sh\n./sh/macos\n```\n\nFor linux:\n\n```sh\n./sh/linux\n```\n\n### 3. Run with Flutter\n\nRun on the device.\n\n```sh\nflutter run -d macos\n```\n\n```sh\nflutter run -d linux\n```\n\nFor linux, you should pass the path to `libtodo.so`:\n\nOn `~/rid-examples/flutter/todo$`:\n\n```\nLD_LIBRARY_PATH=$PWD/plugin/linux flutter run -d linux\n```\n\n### 4. Develop\n\nRun step `1` whenever a function exposed to Flutter changes.\n\nRun step `2` whenever any of your Rust code changes.\n\n**Note** that to apply changes from Rust you need to restart the app to reload the compiled binary.\nA hot restart/reload does not achieve this.\n\n## Folder Structure\n\n```\n├── android\n├── ios\n├── macos\n├── lib\n├── plugin\n│   ├── android\n│   ├── ios\n│   ├── macos\n│   └── lib\n└── src\n```\n\n### `./plugin`\n\nProvides connection from Flutter to Rust.\n\nRust binaries are placed into the respective plugin folders `./ios, ./macos, ./android` when\nthey are built.\n\nGenerated Dart glue code is placed inside `./plugin/lib/generated` while\n`./plugin/lib/plugin.dart` just exposes the API to the app.\n\n### `./src`\n\nContains the starter Rust code inside `./src/lib.rs`. Keep developing the Rust part of your app\nhere.\n\n### `./lib`\n\nContains the starter Flutter app inside `./lib/main.dart`.\n\n### `./sh`\n\nProvides scripts to run build and code generation tasks. In the future a tool will provide the\nfunctionality currently provided by these scripts.\n\n- `bindgen` generates the `binding.h` header file for the extern Rust functions found inside\n  `./src`. These are then placed inside the `./plugin` device folders were needed as well as\n  `./plugin/lib/generated/binding.h` where they are used to generate Dart glue code\n- `ffigen` generates Dart glue code inside `./plugin/lib/generated/ffigen_binding.dart` using\n  `./plugin/lib/generated/binding.h` as input\n- `./android` builds the Rust binary to run on Android devices/emulators and places it inside\n  `./plugin/lib/android`\n- `./ios` builds the Rust binary to run on IOS devices/emulators and places it inside\n  `./plugin/lib/ios`\n- `./macos` builds the Rust binary to run on MacOs directly and places it inside\n  `./plugin/lib/macos`, this is the same format as running `cargo build` on your Mac\n\n## Caveats\n\nAt this point _Rid_ hasn't been published, therefore the build step cannot be performed and\nthis example only serves to demonstrate what is possible once it _is_ published and open\nsourced.\n\nFor more information please see [_Is Rid Open Sourced?_](../../README.md#is-rid-open-sourced)\n"
  },
  {
    "path": "flutter/todo/android/.gitignore",
    "content": "gradle-wrapper.jar\n/.gradle\n/captures/\n/gradlew\n/gradlew.bat\n/local.properties\nGeneratedPluginRegistrant.java\n\n# Remember to never publicly share your keystore.\n# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app\nkey.properties\n**/*.keystore\n**/*.jks\n"
  },
  {
    "path": "flutter/todo/android/app/build.gradle",
    "content": "def localProperties = new Properties()\ndef localPropertiesFile = rootProject.file('local.properties')\nif (localPropertiesFile.exists()) {\n    localPropertiesFile.withReader('UTF-8') { reader ->\n        localProperties.load(reader)\n    }\n}\n\ndef flutterRoot = localProperties.getProperty('flutter.sdk')\nif (flutterRoot == null) {\n    throw new GradleException(\"Flutter SDK not found. Define location with flutter.sdk in the local.properties file.\")\n}\n\ndef flutterVersionCode = localProperties.getProperty('flutter.versionCode')\nif (flutterVersionCode == null) {\n    flutterVersionCode = '1'\n}\n\ndef flutterVersionName = localProperties.getProperty('flutter.versionName')\nif (flutterVersionName == null) {\n    flutterVersionName = '1.0'\n}\n\napply plugin: 'com.android.application'\napply plugin: 'kotlin-android'\napply from: \"$flutterRoot/packages/flutter_tools/gradle/flutter.gradle\"\n\nandroid {\n    compileSdkVersion 30\n\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n\n    kotlinOptions {\n        jvmTarget = '1.8'\n    }\n\n    sourceSets {\n        main.java.srcDirs += 'src/main/kotlin'\n    }\n\n    defaultConfig {\n        // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).\n        applicationId \"com.example.todo\"\n        minSdkVersion 16\n        targetSdkVersion 30\n        versionCode flutterVersionCode.toInteger()\n        versionName flutterVersionName\n    }\n\n    buildTypes {\n        release {\n            // TODO: Add your own signing config for the release build.\n            // Signing with the debug keys for now, so `flutter run --release` works.\n            signingConfig signingConfigs.debug\n        }\n    }\n}\n\nflutter {\n    source '../..'\n}\n\ndependencies {\n    implementation \"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version\"\n}\n"
  },
  {
    "path": "flutter/todo/android/app/src/debug/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.example.todo\">\n    <!-- Flutter needs it to communicate with the running application\n         to allow setting breakpoints, to provide hot reload, etc.\n    -->\n    <uses-permission android:name=\"android.permission.INTERNET\"/>\n</manifest>\n"
  },
  {
    "path": "flutter/todo/android/app/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.example.todo\">\n   <application\n        android:label=\"todo\"\n        android:icon=\"@mipmap/ic_launcher\">\n        <activity\n            android:name=\".MainActivity\"\n            android:launchMode=\"singleTop\"\n            android:theme=\"@style/LaunchTheme\"\n            android:configChanges=\"orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode\"\n            android:hardwareAccelerated=\"true\"\n            android:windowSoftInputMode=\"adjustResize\">\n            <!-- Specifies an Android theme to apply to this Activity as soon as\n                 the Android process has started. This theme is visible to the user\n                 while the Flutter UI initializes. After that, this theme continues\n                 to determine the Window background behind the Flutter UI. -->\n            <meta-data\n              android:name=\"io.flutter.embedding.android.NormalTheme\"\n              android:resource=\"@style/NormalTheme\"\n              />\n            <!-- Displays an Android View that continues showing the launch screen\n                 Drawable until Flutter paints its first frame, then this splash\n                 screen fades out. A splash screen is useful to avoid any visual\n                 gap between the end of Android's launch screen and the painting of\n                 Flutter's first frame. -->\n            <meta-data\n              android:name=\"io.flutter.embedding.android.SplashScreenDrawable\"\n              android:resource=\"@drawable/launch_background\"\n              />\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\"/>\n                <category android:name=\"android.intent.category.LAUNCHER\"/>\n            </intent-filter>\n        </activity>\n        <!-- Don't delete the meta-data below.\n             This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->\n        <meta-data\n            android:name=\"flutterEmbedding\"\n            android:value=\"2\" />\n    </application>\n</manifest>\n"
  },
  {
    "path": "flutter/todo/android/app/src/main/kotlin/com/example/todo/MainActivity.kt",
    "content": "package com.example.todo\n\nimport io.flutter.embedding.android.FlutterActivity\n\nclass MainActivity: FlutterActivity() {\n}\n"
  },
  {
    "path": "flutter/todo/android/app/src/main/res/drawable/launch_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- Modify this file to customize your launch splash screen -->\n<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:drawable=\"@android:color/white\" />\n\n    <!-- You can insert your own image assets here -->\n    <!-- <item>\n        <bitmap\n            android:gravity=\"center\"\n            android:src=\"@mipmap/launch_image\" />\n    </item> -->\n</layer-list>\n"
  },
  {
    "path": "flutter/todo/android/app/src/main/res/drawable-v21/launch_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- Modify this file to customize your launch splash screen -->\n<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:drawable=\"?android:colorBackground\" />\n\n    <!-- You can insert your own image assets here -->\n    <!-- <item>\n        <bitmap\n            android:gravity=\"center\"\n            android:src=\"@mipmap/launch_image\" />\n    </item> -->\n</layer-list>\n"
  },
  {
    "path": "flutter/todo/android/app/src/main/res/values/styles.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->\n    <style name=\"LaunchTheme\" parent=\"@android:style/Theme.Light.NoTitleBar\">\n        <!-- Show a splash screen on the activity. Automatically removed when\n             Flutter draws its first frame -->\n        <item name=\"android:windowBackground\">@drawable/launch_background</item>\n    </style>\n    <!-- Theme applied to the Android Window as soon as the process has started.\n         This theme determines the color of the Android Window while your\n         Flutter UI initializes, as well as behind your Flutter UI while its\n         running.\n         \n         This Theme is only used starting with V2 of Flutter's Android embedding. -->\n    <style name=\"NormalTheme\" parent=\"@android:style/Theme.Light.NoTitleBar\">\n        <item name=\"android:windowBackground\">?android:colorBackground</item>\n    </style>\n</resources>\n"
  },
  {
    "path": "flutter/todo/android/app/src/main/res/values-night/styles.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->\n    <style name=\"LaunchTheme\" parent=\"@android:style/Theme.Black.NoTitleBar\">\n        <!-- Show a splash screen on the activity. Automatically removed when\n             Flutter draws its first frame -->\n        <item name=\"android:windowBackground\">@drawable/launch_background</item>\n    </style>\n    <!-- Theme applied to the Android Window as soon as the process has started.\n         This theme determines the color of the Android Window while your\n         Flutter UI initializes, as well as behind your Flutter UI while its\n         running.\n         \n         This Theme is only used starting with V2 of Flutter's Android embedding. -->\n    <style name=\"NormalTheme\" parent=\"@android:style/Theme.Black.NoTitleBar\">\n        <item name=\"android:windowBackground\">?android:colorBackground</item>\n    </style>\n</resources>\n"
  },
  {
    "path": "flutter/todo/android/app/src/profile/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.example.todo\">\n    <!-- Flutter needs it to communicate with the running application\n         to allow setting breakpoints, to provide hot reload, etc.\n    -->\n    <uses-permission android:name=\"android.permission.INTERNET\"/>\n</manifest>\n"
  },
  {
    "path": "flutter/todo/android/build.gradle",
    "content": "buildscript {\n    ext.kotlin_version = '1.3.50'\n    repositories {\n        google()\n        jcenter()\n    }\n\n    dependencies {\n        classpath 'com.android.tools.build:gradle:4.1.0'\n        classpath \"org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version\"\n    }\n}\n\nallprojects {\n    repositories {\n        google()\n        jcenter()\n    }\n}\n\nrootProject.buildDir = '../build'\nsubprojects {\n    project.buildDir = \"${rootProject.buildDir}/${project.name}\"\n    project.evaluationDependsOn(':app')\n}\n\ntask clean(type: Delete) {\n    delete rootProject.buildDir\n}\n"
  },
  {
    "path": "flutter/todo/android/gradle/wrapper/gradle-wrapper.properties",
    "content": "#Fri Jun 23 08:50:38 CEST 2017\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-6.7-all.zip\n"
  },
  {
    "path": "flutter/todo/android/gradle.properties",
    "content": "org.gradle.jvmargs=-Xmx1536M\nandroid.useAndroidX=true\nandroid.enableJetifier=true\n"
  },
  {
    "path": "flutter/todo/android/settings.gradle",
    "content": "include ':app'\n\ndef localPropertiesFile = new File(rootProject.projectDir, \"local.properties\")\ndef properties = new Properties()\n\nassert localPropertiesFile.exists()\nlocalPropertiesFile.withReader(\"UTF-8\") { reader -> properties.load(reader) }\n\ndef flutterSdkPath = properties.getProperty(\"flutter.sdk\")\nassert flutterSdkPath != null, \"flutter.sdk not set in local.properties\"\napply from: \"$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle\"\n"
  },
  {
    "path": "flutter/todo/android/todo_android.iml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<module type=\"JAVA_MODULE\" version=\"4\">\n  <component name=\"FacetManager\">\n    <facet type=\"android\" name=\"Android\">\n      <configuration>\n        <option name=\"ALLOW_USER_CONFIGURATION\" value=\"false\" />\n        <option name=\"GEN_FOLDER_RELATIVE_PATH_APT\" value=\"/gen\" />\n        <option name=\"GEN_FOLDER_RELATIVE_PATH_AIDL\" value=\"/gen\" />\n        <option name=\"MANIFEST_FILE_RELATIVE_PATH\" value=\"/app/src/main/AndroidManifest.xml\" />\n        <option name=\"RES_FOLDER_RELATIVE_PATH\" value=\"/app/src/main/res\" />\n        <option name=\"ASSETS_FOLDER_RELATIVE_PATH\" value=\"/app/src/main/assets\" />\n        <option name=\"LIBS_FOLDER_RELATIVE_PATH\" value=\"/app/src/main/libs\" />\n        <option name=\"PROGUARD_LOGS_FOLDER_RELATIVE_PATH\" value=\"/app/src/main/proguard_logs\" />\n      </configuration>\n    </facet>\n  </component>\n  <component name=\"NewModuleRootManager\" inherit-compiler-output=\"true\">\n    <exclude-output />\n    <content url=\"file://$MODULE_DIR$\">\n      <sourceFolder url=\"file://$MODULE_DIR$/app/src/main/java\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/app/src/main/kotlin\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/gen\" isTestSource=\"false\" generated=\"true\" />\n    </content>\n    <orderEntry type=\"jdk\" jdkName=\"Android API 29 Platform\" jdkType=\"Android SDK\" />\n    <orderEntry type=\"sourceFolder\" forTests=\"false\" />\n    <orderEntry type=\"library\" name=\"Flutter for Android\" level=\"project\" />\n    <orderEntry type=\"library\" name=\"KotlinJavaRuntime\" level=\"project\" />\n  </component>\n</module>\n"
  },
  {
    "path": "flutter/todo/ios/.gitignore",
    "content": "*.mode1v3\n*.mode2v3\n*.moved-aside\n*.pbxuser\n*.perspectivev3\n**/*sync/\n.sconsign.dblite\n.tags*\n**/.vagrant/\n**/DerivedData/\nIcon?\n**/Pods/\n**/.symlinks/\nprofile\nxcuserdata\n**/.generated/\nFlutter/App.framework\nFlutter/Flutter.framework\nFlutter/Flutter.podspec\nFlutter/Generated.xcconfig\nFlutter/ephemeral/\nFlutter/app.flx\nFlutter/app.zip\nFlutter/flutter_assets/\nFlutter/flutter_export_environment.sh\nServiceDefinitions.json\nRunner/GeneratedPluginRegistrant.*\n\n# Exceptions to above rules.\n!default.mode1v3\n!default.mode2v3\n!default.pbxuser\n!default.perspectivev3\n"
  },
  {
    "path": "flutter/todo/ios/Flutter/AppFrameworkInfo.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  <key>CFBundleDevelopmentRegion</key>\n  <string>en</string>\n  <key>CFBundleExecutable</key>\n  <string>App</string>\n  <key>CFBundleIdentifier</key>\n  <string>io.flutter.flutter.app</string>\n  <key>CFBundleInfoDictionaryVersion</key>\n  <string>6.0</string>\n  <key>CFBundleName</key>\n  <string>App</string>\n  <key>CFBundlePackageType</key>\n  <string>FMWK</string>\n  <key>CFBundleShortVersionString</key>\n  <string>1.0</string>\n  <key>CFBundleSignature</key>\n  <string>????</string>\n  <key>CFBundleVersion</key>\n  <string>1.0</string>\n  <key>MinimumOSVersion</key>\n  <string>8.0</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "flutter/todo/ios/Flutter/Debug.xcconfig",
    "content": "#include? \"Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig\"\n#include \"Generated.xcconfig\"\n"
  },
  {
    "path": "flutter/todo/ios/Flutter/Release.xcconfig",
    "content": "#include? \"Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig\"\n#include \"Generated.xcconfig\"\n"
  },
  {
    "path": "flutter/todo/ios/Podfile",
    "content": "# Uncomment this line to define a global platform for your project\n# platform :ios, '9.0'\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', '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 Generated.xcconfig, then run flutter pub get\"\nend\n\nrequire File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)\n\nflutter_ios_podfile_setup\n\ntarget 'Runner' do\n  use_frameworks!\n  use_modular_headers!\n\n  flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))\nend\n\npost_install do |installer|\n  installer.pods_project.targets.each do |target|\n    flutter_additional_ios_build_settings(target)\n  end\nend\n"
  },
  {
    "path": "flutter/todo/ios/Runner/AppDelegate.swift",
    "content": "import UIKit\nimport Flutter\n\n@UIApplicationMain\n@objc class AppDelegate: FlutterAppDelegate {\n  override func application(\n    _ application: UIApplication,\n    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?\n  ) -> Bool {\n    GeneratedPluginRegistrant.register(with: self)\n    return super.application(application, didFinishLaunchingWithOptions: launchOptions)\n  }\n}\n"
  },
  {
    "path": "flutter/todo/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"size\" : \"20x20\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-App-20x20@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"20x20\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-App-20x20@3x.png\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"size\" : \"29x29\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-App-29x29@1x.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"29x29\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-App-29x29@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"29x29\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-App-29x29@3x.png\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"size\" : \"40x40\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-App-40x40@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"40x40\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-App-40x40@3x.png\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"size\" : \"60x60\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-App-60x60@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"60x60\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-App-60x60@3x.png\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"size\" : \"20x20\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-App-20x20@1x.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"20x20\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-App-20x20@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"29x29\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-App-29x29@1x.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"29x29\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-App-29x29@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"40x40\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-App-40x40@1x.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"40x40\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-App-40x40@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"76x76\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-App-76x76@1x.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"76x76\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-App-76x76@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"83.5x83.5\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-App-83.5x83.5@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"1024x1024\",\n      \"idiom\" : \"ios-marketing\",\n      \"filename\" : \"Icon-App-1024x1024@1x.png\",\n      \"scale\" : \"1x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}\n"
  },
  {
    "path": "flutter/todo/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"LaunchImage.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"LaunchImage@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"LaunchImage@3x.png\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}\n"
  },
  {
    "path": "flutter/todo/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md",
    "content": "# Launch Screen Assets\n\nYou can customize the launch screen with your own desired assets by replacing the image files in this directory.\n\nYou can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images."
  },
  {
    "path": "flutter/todo/ios/Runner/Base.lproj/LaunchScreen.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"12121\" systemVersion=\"16G29\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" launchScreen=\"YES\" colorMatched=\"YES\" initialViewController=\"01J-lp-oVM\">\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"12089\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"EHf-IW-A2E\">\n            <objects>\n                <viewController id=\"01J-lp-oVM\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"Ydg-fD-yQy\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"xbc-2k-c8Z\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"Ze5-6b-2t3\">\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <imageView opaque=\"NO\" clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"center\" image=\"LaunchImage\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"YRO-k0-Ey4\">\n                            </imageView>\n                        </subviews>\n                        <color key=\"backgroundColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                        <constraints>\n                            <constraint firstItem=\"YRO-k0-Ey4\" firstAttribute=\"centerX\" secondItem=\"Ze5-6b-2t3\" secondAttribute=\"centerX\" id=\"1a2-6s-vTC\"/>\n                            <constraint firstItem=\"YRO-k0-Ey4\" firstAttribute=\"centerY\" secondItem=\"Ze5-6b-2t3\" secondAttribute=\"centerY\" id=\"4X2-HB-R7a\"/>\n                        </constraints>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"iYj-Kq-Ea1\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"53\" y=\"375\"/>\n        </scene>\n    </scenes>\n    <resources>\n        <image name=\"LaunchImage\" width=\"168\" height=\"185\"/>\n    </resources>\n</document>\n"
  },
  {
    "path": "flutter/todo/ios/Runner/Base.lproj/Main.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"10117\" systemVersion=\"15F34\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" initialViewController=\"BYZ-38-t0r\">\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"10085\"/>\n    </dependencies>\n    <scenes>\n        <!--Flutter View Controller-->\n        <scene sceneID=\"tne-QT-ifu\">\n            <objects>\n                <viewController id=\"BYZ-38-t0r\" customClass=\"FlutterViewController\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"y3c-jy-aDJ\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"wfy-db-euE\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"8bC-Xf-vdC\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"600\" height=\"600\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"calibratedWhite\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"dkx-z0-nzr\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "flutter/todo/ios/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>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>todo</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>CFBundleSignature</key>\n\t<string>????</string>\n\t<key>CFBundleVersion</key>\n\t<string>$(FLUTTER_BUILD_NUMBER)</string>\n\t<key>LSRequiresIPhoneOS</key>\n\t<true/>\n\t<key>UILaunchStoryboardName</key>\n\t<string>LaunchScreen</string>\n\t<key>UIMainStoryboardFile</key>\n\t<string>Main</string>\n\t<key>UISupportedInterfaceOrientations</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations~ipad</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationPortraitUpsideDown</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n\t<key>UIViewControllerBasedStatusBarAppearance</key>\n\t<false/>\n</dict>\n</plist>\n"
  },
  {
    "path": "flutter/todo/ios/Runner/Runner-Bridging-Header.h",
    "content": "#import \"GeneratedPluginRegistrant.h\"\n"
  },
  {
    "path": "flutter/todo/ios/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": "flutter/todo/ios/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": "flutter/todo/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings",
    "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>PreviewsEnabled</key>\n\t<false/>\n</dict>\n</plist>\n"
  },
  {
    "path": "flutter/todo/lib/main.dart",
    "content": "import 'dart:async';\n\nimport 'package:flutter/material.dart';\nimport 'package:plugin/generated/rid_api.dart';\nimport 'package:todo/views/menu.dart';\nimport 'package:todo/views/todos.dart';\n\nconst Color FILTER_SELECTED_COLOR = Colors.blue;\nconst Color FILTER_UNSELECTED_COLOR = Colors.black;\n\nvoid configRid() {\n  rid.debugReply = (reply) => debugPrint('$reply');\n}\n\nvoid main() async {\n  configRid();\n  await Store.instance.msgSetAutoExpireCompletedTodos(false);\n  runApp(TodoApp());\n}\n\nclass TodoApp extends StatelessWidget with StatelessLock {\n  @override\n  Widget build(BuildContext context) {\n    debugPrint('  build: TodoApp');\n    return MaterialApp(\n      title: 'Rust/Flutter Todo App',\n      theme: ThemeData(\n        primarySwatch: Colors.blue,\n      ),\n      home: TodosPage(title: 'Todo App'),\n      debugShowCheckedModeBanner: false,\n    );\n  }\n}\n\nclass TodosPage extends StatefulWidget with StatefulLock {\n  final String title;\n\n  TodosPage({Key? key, required this.title}) : super(key: key);\n\n  @override\n  _TodosPageState createState() => _TodosPageState();\n}\n\nclass _TodosPageState extends State<TodosPage> with StateAsync<TodosPage> {\n  late final StreamSubscription<PostedReply> sub;\n  final _textFieldController = TextEditingController();\n  String? addTodoTitle;\n  final Store _store = Store.instance;\n\n  @override\n  void initState() {\n    // Completed todos are expired on a separate thread from Rust, i.e. not in\n    // direct response to a user message.\n    // We subscribe to this event here to update the list of filtered todos\n    // when that happens.\n    sub = rid.replyChannel.stream\n        .where((reply) => reply.type == Reply.CompletedTodoExpired)\n        .listen((_) {\n      setState(() {});\n    });\n    super.initState();\n  }\n\n  @override\n  void dispose() {\n    sub.cancel();\n    super.dispose();\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    debugPrint('  build: TodosPage');\n    final Filter filter = _store.filter;\n    final filteredTodos = _store.filteredTodos();\n    final settings = _store.settings;\n    debugPrint(\"filtered: \\n  ${filteredTodos.join('\\n  ')}\");\n\n    return SafeArea(\n      child: Scaffold(\n        appBar: AppBar(\n          title: Row(\n            mainAxisAlignment: MainAxisAlignment.spaceBetween,\n            children: [\n              Text(widget.title),\n              Row(\n                children: [\n                  Image.asset(\n                    \"assets/dash.png\",\n                    height: 40.0,\n                    width: 40.0,\n                  ),\n                  Icon(Icons.favorite, color: Colors.red),\n                  Image.asset(\n                    \"assets/ferris.png\",\n                    height: 50.0,\n                    width: 50.0,\n                  ),\n                ],\n              )\n            ],\n          ),\n        ),\n        drawer: Drawer(\n          child: Menu(\n            settings,\n            restartAll: () => setStateAsync(_store.msgRestartAll),\n            completeAll: () => setStateAsync(_store.msgCompleteAll),\n            removeCompleted: () => setStateAsync(_store.msgRemoveCompleted),\n            setAutoExpireCompleted: (val) =>\n                setStateAsync(() => _store.msgSetAutoExpireCompletedTodos(val)),\n          ),\n        ),\n        bottomNavigationBar: BottomAppBar(\n          child: Row(\n            children: <Widget>[\n              IconButton(\n                icon: Icon(\n                  Icons.calendar_today_rounded,\n                  color: filter == Filter.Pending\n                      ? FILTER_SELECTED_COLOR\n                      : FILTER_UNSELECTED_COLOR,\n                ),\n                onPressed: () =>\n                    setStateAsync(() => _store.msgSetFilter(Filter.Pending)),\n              ),\n              Spacer(),\n              IconButton(\n                icon: Icon(\n                  Icons.check,\n                  color: filter == Filter.Completed\n                      ? FILTER_SELECTED_COLOR\n                      : FILTER_UNSELECTED_COLOR,\n                ),\n                onPressed: () =>\n                    setStateAsync(() => _store.msgSetFilter(Filter.Completed)),\n              ),\n              IconButton(\n                icon: Icon(\n                  Icons.all_inclusive,\n                  color: filter == Filter.All\n                      ? FILTER_SELECTED_COLOR\n                      : FILTER_UNSELECTED_COLOR,\n                ),\n                onPressed: () =>\n                    setStateAsync(() => _store.msgSetFilter(Filter.All)),\n              ),\n            ],\n          ),\n        ),\n        body: TodosView(\n          filteredTodos,\n          settings,\n          getTodoById: (id) => _store.todoById(id),\n          onToggleTodo: (id) async {\n            await _store.msgToggleTodo(id);\n            setState(() {});\n          },\n          onRemoveTodo: (id) async {\n            await _store.msgRemoveTodo(id);\n            setState(() {});\n          },\n        ),\n        floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,\n        floatingActionButton: FloatingActionButton(\n          onPressed: () async {\n            _textFieldController.clear();\n            await _addTodoDialog(context);\n            if (addTodoTitle != null && addTodoTitle!.trim().isNotEmpty) {\n              await _store.msgAddTodo(addTodoTitle!);\n              setState(() {});\n              debugPrint(\"${_store.raw.debug(true)}\");\n            }\n          },\n          tooltip: 'Add Todo',\n          child: Icon(Icons.add),\n        ),\n      ),\n    );\n  }\n\n  Future<void> _addTodoDialog(BuildContext context) async {\n    return showDialog(\n        context: context,\n        builder: (context) {\n          return AlertDialog(\n            title: Text('Enter Todo Title'),\n            content: TextField(\n              controller: _textFieldController,\n              decoration: InputDecoration(hintText: \"Todo title\"),\n              autofocus: true,\n            ),\n            actions: <Widget>[\n              TextButton(\n                child: Text('Done'),\n                onPressed: () {\n                  addTodoTitle = _textFieldController.value.text;\n                  Navigator.pop(context);\n                },\n              ),\n            ],\n          );\n        });\n  }\n}\n"
  },
  {
    "path": "flutter/todo/lib/views/expiry.dart",
    "content": "import 'package:flutter/material.dart';\n\nColor expiryColor(double completedExpiryMillis, double remaining) {\n  return remaining > completedExpiryMillis * 0.80\n      ? Colors.greenAccent\n      : remaining > completedExpiryMillis * 0.60\n          ? Colors.green\n          : remaining > completedExpiryMillis * 0.4\n              ? Colors.orange\n              : remaining > completedExpiryMillis * 0.2\n                  ? Colors.redAccent\n                  : Colors.red;\n}\n\nclass ExpiryWidget extends StatelessWidget {\n  final double completedExpiryMillis;\n  final double remainingMillis;\n\n  const ExpiryWidget({\n    required this.completedExpiryMillis,\n    required this.remainingMillis,\n  }) : super();\n\n  Widget build(BuildContext context) {\n    final totalWidth = MediaQuery.of(context).size.width * 0.8;\n    final expiryWidth = (remainingMillis / completedExpiryMillis) * totalWidth;\n    return Container(\n      height: 10,\n      width: totalWidth,\n      decoration: BoxDecoration(\n        border: Border.all(\n          color: Colors.blueGrey,\n          width: 1.0,\n          style: BorderStyle.solid,\n        ),\n        borderRadius: BorderRadius.all(Radius.circular(2.0)),\n      ),\n      child: Container(\n        margin: EdgeInsets.only(right: totalWidth - expiryWidth),\n        color: expiryColor(completedExpiryMillis, remainingMillis),\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "flutter/todo/lib/views/menu.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:flutter/widgets.dart';\nimport 'package:plugin/generated/rid_api.dart';\n\nclass Menu extends StatelessWidget {\n  final Settings settings;\n\n  final void Function() restartAll;\n  final void Function() completeAll;\n  final void Function() removeCompleted;\n\n  final void Function(bool) setAutoExpireCompleted;\n\n  const Menu(\n    this.settings, {\n    required this.restartAll,\n    required this.completeAll,\n    required this.removeCompleted,\n    required this.setAutoExpireCompleted,\n    Key? key,\n  }) : super(key: key);\n  @override\n  Widget build(BuildContext context) {\n    debugPrint('  build: Menu');\n    return ListView(\n      padding: EdgeInsets.zero,\n      children: <Widget>[\n        ListTile(title: Text('Todo Actions')),\n        Divider(),\n        ListTile(\n          title: Text('Restart All'),\n          onTap: restartAll,\n        ),\n        ListTile(\n          title: Text('Complete All'),\n          onTap: completeAll,\n        ),\n        ListTile(\n          title: Text('Remove Completed'),\n          onTap: removeCompleted,\n        ),\n        ListTile(\n          title: Row(\n            mainAxisAlignment: MainAxisAlignment.start,\n            children: [\n              Text('Expire Completed'),\n              AutoRemoveCompletedWidget(\n                autoExpireCompleted: settings.autoExpireCompletedTodos,\n                setAutoExpireCompleted: setAutoExpireCompleted,\n              ),\n            ],\n          ),\n        ),\n      ],\n    );\n  }\n}\n\nclass AutoRemoveCompletedWidget extends StatefulWidget with StatefulLock {\n  final bool autoExpireCompleted;\n  final void Function(bool) setAutoExpireCompleted;\n\n  const AutoRemoveCompletedWidget({\n    Key? key,\n    required this.autoExpireCompleted,\n    required this.setAutoExpireCompleted,\n  }) : super(key: key);\n\n  @override\n  State<AutoRemoveCompletedWidget> createState() =>\n      _AutoRemoveCompletedWidgetState();\n}\n\nclass _AutoRemoveCompletedWidgetState extends State<AutoRemoveCompletedWidget>\n    with StateAsync {\n  @override\n  Widget build(BuildContext context) {\n    debugPrint('  build: AutoRemoveCompleted');\n    return Checkbox(\n      value: widget.autoExpireCompleted,\n      onChanged: (val) {\n        if (val != null) widget.setAutoExpireCompleted(val);\n      },\n    );\n  }\n}\n"
  },
  {
    "path": "flutter/todo/lib/views/todo.dart",
    "content": "import 'dart:async';\n\nimport 'package:flutter/material.dart';\nimport 'package:plugin/generated/rid_api.dart';\nimport 'package:todo/views/expiry.dart';\n\nclass TodoView extends StatefulWidget with StatefulLock {\n  final Todo todo;\n  final Settings settings;\n  final Todo? Function(int) getTodoById;\n  final Future<void> Function(int) onToggleTodo;\n  final Future<void> Function(int) onRemoveTodo;\n\n  TodoView(\n    this.todo,\n    this.settings, {\n    required this.getTodoById,\n    required this.onToggleTodo,\n    required this.onRemoveTodo,\n  }) : super(key: Key(\"Todo ${todo.hashCode}\"));\n\n  @override\n  _TodoViewState createState() => _TodoViewState(todo, settings);\n}\n\nclass _TodoViewState extends State<TodoView> with StateAsync<TodoView> {\n  Todo todo;\n  final Settings settings;\n  late final StreamSubscription<PostedReply> expirySub;\n\n  _TodoViewState(this.todo, this.settings) : super();\n\n  bool _replyIsForThisTodo(PostedReply reply) {\n    assert(\n      reply.data != null,\n      'Reply.Tick should include data containing the id of the ticked todo',\n    );\n    final id = int.tryParse(reply.data!);\n    assert(id != null, 'Reply.Tick included invalid id ${reply.data}');\n    return id == todo.id;\n  }\n\n  @override\n  void initState() {\n    // Todos are expired on a separate thread in Rust tick by tick. Those tick\n    // events aren't directly related to a user message and therefore we\n    // subscribe to them.\n    expirySub = rid.replyChannel.stream\n        .where(\n            (reply) => reply.type == Reply.Tick && _replyIsForThisTodo(reply))\n        .listen((_) {\n      final update = widget.getTodoById(todo.id);\n      if (update != null) {\n        setState(() => {todo = update});\n      }\n    });\n    super.initState();\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    debugPrint('  build: TodoView ${todo.title}');\n    return Dismissible(\n      key: Key(\"Todo Dismissible ${todo.id}\"),\n      child: Card(\n        child: InkWell(\n            onTap: () => setStateAsync(() => widget.onToggleTodo(todo.id)),\n            child: ListTile(\n              leading: todo.completed\n                  ? Icon(Icons.check, color: Colors.green)\n                  : Icon(Icons.calendar_today_rounded),\n              title: Text('${todo.title}'),\n              subtitle:\n                  widget.settings.autoExpireCompletedTodos && todo.completed\n                      ? ExpiryWidget(\n                          completedExpiryMillis:\n                              settings.completedExpiryMillis.toDouble(),\n                          remainingMillis: todo.expiryMillis.toDouble(),\n                        )\n                      : null,\n            )),\n      ),\n      direction: DismissDirection.endToStart,\n      // Make sure we removed the Todo and got the reply before updating the UI\n      confirmDismiss: (_) => widget.onRemoveTodo(todo.id).then((_) => true),\n      background: Padding(\n        padding: EdgeInsets.all(5.0),\n        child: Container(color: Colors.red),\n      ),\n    );\n  }\n\n  @override\n  void dispose() {\n    expirySub.cancel();\n    super.dispose();\n  }\n}\n"
  },
  {
    "path": "flutter/todo/lib/views/todos.dart",
    "content": "import 'dart:async';\n\nimport 'package:flutter/material.dart';\nimport 'package:todo/views/todo.dart';\nimport 'package:plugin/generated/rid_api.dart';\n\nclass TodosView extends StatelessWidget {\n  final List<Todo> todos;\n  final Settings settings;\n  final Todo? Function(int) getTodoById;\n  final Future<void> Function(int) onToggleTodo;\n  final Future<void> Function(int) onRemoveTodo;\n\n  const TodosView(\n    this.todos,\n    this.settings, {\n    required this.getTodoById,\n    required this.onToggleTodo,\n    required this.onRemoveTodo,\n    Key? key,\n  }) : super(key: key);\n\n  @override\n  Widget build(BuildContext context) {\n    debugPrint('  build: TodosView ($todos)');\n    return Center(\n      child: ListView.builder(\n          itemCount: todos.length,\n          itemBuilder: (context, index) {\n            final todo = todos[index];\n            return TodoView(\n              todo,\n              settings,\n              getTodoById: getTodoById,\n              onToggleTodo: onToggleTodo,\n              onRemoveTodo: onRemoveTodo,\n            );\n          }),\n    );\n  }\n}\n"
  },
  {
    "path": "flutter/todo/linux/.gitignore",
    "content": "flutter/ephemeral\n"
  },
  {
    "path": "flutter/todo/linux/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.10)\nproject(runner LANGUAGES CXX)\n\nset(BINARY_NAME \"rid_walker\")\nset(APPLICATION_ID \"com.example.rid_walker\")\n\ncmake_policy(SET CMP0063 NEW)\n\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# Configure build 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.\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\nset(FLUTTER_MANAGED_DIR \"${CMAKE_CURRENT_SOURCE_DIR}/flutter\")\n\n# Flutter library and tool build rules.\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# Application build\nadd_executable(${BINARY_NAME}\n  \"main.cc\"\n  \"my_application.cc\"\n  \"${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc\"\n)\napply_standard_settings(${BINARY_NAME})\nfind_library(TODO_LIBRARY\n    NAMES todo libtodo\n    HINTS \"${CMAKE_CURRENT_SOURCE_DIR}/../plugin/linux\"\n)\n\ntarget_link_libraries(${BINARY_NAME} PRIVATE flutter ${TODO_LIBRARY})\ntarget_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK)\nadd_dependencies(${BINARY_NAME} flutter_assemble)\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\nif(PLUGIN_BUNDLED_LIBRARIES)\n  install(FILES \"${PLUGIN_BUNDLED_LIBRARIES}\"\n    DESTINATION \"${INSTALL_BUNDLE_LIB_DIR}\"\n    COMPONENT Runtime)\nendif()\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": "flutter/todo/linux/flutter/CMakeLists.txt",
    "content": "cmake_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": "flutter/todo/linux/flutter/generated_plugin_registrant.cc",
    "content": "//\n//  Generated file. Do not edit.\n//\n\n#include \"generated_plugin_registrant.h\"\n\n\nvoid fl_register_plugins(FlPluginRegistry* registry) {\n}\n"
  },
  {
    "path": "flutter/todo/linux/flutter/generated_plugin_registrant.h",
    "content": "//\n//  Generated file. Do not edit.\n//\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": "flutter/todo/linux/flutter/generated_plugins.cmake",
    "content": "#\n# Generated file, do not edit.\n#\n\nlist(APPEND FLUTTER_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"
  },
  {
    "path": "flutter/todo/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": "flutter/todo/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, \"rid_walker\");\n    gtk_header_bar_set_show_close_button(header_bar, TRUE);\n    gtk_window_set_titlebar(window, GTK_WIDGET(header_bar));\n  }\n  else {\n    gtk_window_set_title(window, \"rid_walker\");\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": "flutter/todo/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": "flutter/todo/macos/.gitignore",
    "content": "# Flutter-related\n**/Flutter/ephemeral/\n**/Pods/\n\n# Xcode-related\n**/xcuserdata/\n"
  },
  {
    "path": "flutter/todo/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": "flutter/todo/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": "flutter/todo/macos/Flutter/GeneratedPluginRegistrant.swift",
    "content": "//\n//  Generated file. Do not edit.\n//\n\nimport FlutterMacOS\nimport Foundation\n\nimport plugin\n\nfunc RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {\n  Plugin.register(with: registry.registrar(forPlugin: \"Plugin\"))\n}\n"
  },
  {
    "path": "flutter/todo/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": "flutter/todo/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": "flutter/todo/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": "flutter/todo/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            </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": "flutter/todo/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 = todo\n\n// The application's bundle identifier\nPRODUCT_BUNDLE_IDENTIFIER = com.example.todo\n\n// The copyright displayed in application information\nPRODUCT_COPYRIGHT = Copyright © 2021 com.example. All rights reserved.\n"
  },
  {
    "path": "flutter/todo/macos/Runner/Configs/Debug.xcconfig",
    "content": "#include \"../../Flutter/Flutter-Debug.xcconfig\"\n#include \"Warnings.xcconfig\"\n"
  },
  {
    "path": "flutter/todo/macos/Runner/Configs/Release.xcconfig",
    "content": "#include \"../../Flutter/Flutter-Release.xcconfig\"\n#include \"Warnings.xcconfig\"\n"
  },
  {
    "path": "flutter/todo/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": "flutter/todo/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.server</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "flutter/todo/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": "flutter/todo/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": "flutter/todo/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": "flutter/todo/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": "flutter/todo/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": "flutter/todo/plugin/.gitignore",
    "content": ".DS_Store\n.dart_tool/\n\n.packages\n.pub/\n\nbuild/\n"
  },
  {
    "path": "flutter/todo/plugin/LICENSE",
    "content": "TODO: Add your license here.\n"
  },
  {
    "path": "flutter/todo/plugin/android/.gitignore",
    "content": "*.iml\n.gradle\n/local.properties\n/.idea/workspace.xml\n/.idea/libraries\n.DS_Store\n/build\n/captures\n"
  },
  {
    "path": "flutter/todo/plugin/android/build.gradle",
    "content": "group 'com.example.plugin'\nversion '1.0-SNAPSHOT'\n\nbuildscript {\n    ext.kotlin_version = '1.3.50'\n    repositories {\n        google()\n        jcenter()\n    }\n\n    dependencies {\n        classpath 'com.android.tools.build:gradle:4.1.0'\n        classpath \"org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version\"\n    }\n}\n\nrootProject.allprojects {\n    repositories {\n        google()\n        jcenter()\n    }\n}\n\napply plugin: 'com.android.library'\napply plugin: 'kotlin-android'\n\nandroid {\n    compileSdkVersion 30\n\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n\n    kotlinOptions {\n        jvmTarget = '1.8'\n    }\n\n    sourceSets {\n        main.java.srcDirs += 'src/main/kotlin'\n    }\n\n    defaultConfig {\n        minSdkVersion 16\n    }\n}\n\ndependencies {\n    implementation \"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version\"\n}\n"
  },
  {
    "path": "flutter/todo/plugin/android/gradle/wrapper/gradle-wrapper.properties",
    "content": "distributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-6.7-all.zip\n"
  },
  {
    "path": "flutter/todo/plugin/android/gradle.properties",
    "content": "org.gradle.jvmargs=-Xmx1536M\nandroid.useAndroidX=true\nandroid.enableJetifier=true\n"
  },
  {
    "path": "flutter/todo/plugin/android/settings.gradle",
    "content": "rootProject.name = 'plugin'\n"
  },
  {
    "path": "flutter/todo/plugin/android/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n  package=\"com.example.plugin\">\n</manifest>\n"
  },
  {
    "path": "flutter/todo/plugin/android/src/main/kotlin/com/example/plugin/Plugin.kt",
    "content": "package com.example.plugin\n\nimport androidx.annotation.NonNull\n\nimport io.flutter.embedding.engine.plugins.FlutterPlugin\nimport io.flutter.plugin.common.MethodCall\nimport io.flutter.plugin.common.MethodChannel\nimport io.flutter.plugin.common.MethodChannel.MethodCallHandler\nimport io.flutter.plugin.common.MethodChannel.Result\n\n/** Plugin */\nclass Plugin: FlutterPlugin, MethodCallHandler {\n  /// The MethodChannel that will the communication between Flutter and native Android\n  ///\n  /// This local reference serves to register the plugin with the Flutter Engine and unregister it\n  /// when the Flutter Engine is detached from the Activity\n  private lateinit var channel : MethodChannel\n\n  override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {\n    channel = MethodChannel(flutterPluginBinding.binaryMessenger, \"plugin\")\n    channel.setMethodCallHandler(this)\n  }\n\n  override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {\n    if (call.method == \"getPlatformVersion\") {\n      result.success(\"Android ${android.os.Build.VERSION.RELEASE}\")\n    } else {\n      result.notImplemented()\n    }\n  }\n\n  override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {\n    channel.setMethodCallHandler(null)\n  }\n}\n"
  },
  {
    "path": "flutter/todo/plugin/ios/.gitignore",
    "content": ".idea/\n.vagrant/\n.sconsign.dblite\n.svn/\n\n.DS_Store\n*.swp\nprofile\n\nDerivedData/\nbuild/\nGeneratedPluginRegistrant.h\nGeneratedPluginRegistrant.m\n\n.generated/\n\n*.pbxuser\n*.mode1v3\n*.mode2v3\n*.perspectivev3\n\n!default.pbxuser\n!default.mode1v3\n!default.mode2v3\n!default.perspectivev3\n\nxcuserdata\n\n*.moved-aside\n\n*.pyc\n*sync/\nIcon?\n.tags*\n\n/Flutter/Generated.xcconfig\n/Flutter/ephemeral/\n/Flutter/flutter_export_environment.sh"
  },
  {
    "path": "flutter/todo/plugin/ios/Assets/.gitkeep",
    "content": ""
  },
  {
    "path": "flutter/todo/plugin/ios/Classes/Plugin.h",
    "content": "#import <Flutter/Flutter.h>\n\n@interface Plugin : NSObject<FlutterPlugin>\n@end\n"
  },
  {
    "path": "flutter/todo/plugin/ios/Classes/Plugin.m",
    "content": "#import \"Plugin.h\"\n#if __has_include(<plugin/plugin-Swift.h>)\n#import <plugin/plugin-Swift.h>\n#else\n// Support project import fallback if the generated compatibility header\n// is not copied when this plugin is created as a library.\n// https://forums.swift.org/t/swift-static-libraries-dont-copy-generated-objective-c-header/19816\n#import \"plugin-Swift.h\"\n#endif\n\n@implementation Plugin\n+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {\n  [SwiftPlugin registerWithRegistrar:registrar];\n}\n@end\n"
  },
  {
    "path": "flutter/todo/plugin/ios/Classes/SwiftPlugin.swift",
    "content": "import Flutter\nimport UIKit\n\npublic class SwiftPlugin: NSObject, FlutterPlugin {\n  public static func register(with registrar: FlutterPluginRegistrar) {\n  }\n\n  public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {\n    result(nil)\n  }\n}\n// <rid:prevent_tree_shake Start>\nfunc dummyCallsToPreventTreeShaking() {\n    _export_dart_enum_Filter();\n    _to_dart_for_Store();\n    rid_store_debug(nil);\n    rid_store_debug_pretty(nil);\n    create_store();\n    rid_store_unlock();\n    rid_store_free();\n    __include_dart_for_vec_todo();\n    rid_store_last_added_id(nil);\n    rid_store_todos(nil);\n    rid_store_filter(nil);\n    rid_store_settings(nil);\n    rid_len_vec_todo(nil);\n    rid_get_item_vec_todo(nil, 0);\n    _include_Store_field_wrappers();\n    rid_cstring_free(nil);\n    rid_init_msg_isolate(0);\n    rid_init_reply_isolate(0);\n    rid_export_Store_filtered_todos(nil);\n    rid_export_Store_todo_by_id(nil, 0);\n    __include_dart_for_ridvec_todo();\n    rid_free_ridvec_todo(RidVec_Pointer_Todo());\n    rid_get_item_ridvec_todo(RidVec_Pointer_Todo(), 0);\n    _to_dart_for_Settings();\n    rid_settings_debug(nil);\n    rid_settings_debug_pretty(nil);\n    rid_settings_auto_expire_completed_todos(nil);\n    rid_settings_completed_expiry_millis(nil);\n    _to_dart_for_Todo();\n    rid_todo_debug(nil);\n    rid_todo_debug_pretty(nil);\n    rid_todo_id(nil);\n    rid_todo_title(nil);\n    rid_todo_title_len(nil);\n    rid_todo_completed(nil);\n    rid_todo_expiry_millis(nil);\n    rid_filter_debug(0);\n    rid_filter_debug_pretty(0);\n    rid_msg_AddTodo(0, nil);\n    rid_msg_RemoveTodo(0, 0);\n    rid_msg_RemoveCompleted(0);\n    rid_msg_CompleteTodo(0, 0);\n    rid_msg_RestartTodo(0, 0);\n    rid_msg_ToggleTodo(0, 0);\n    rid_msg_CompleteAll(0);\n    rid_msg_RestartAll(0);\n    rid_msg_SetFilter(0, Filter(rawValue: 0));\n    rid_msg_SetAutoExpireCompletedTodos(0, 0);\n}\n// <rid:prevent_tree_shake End>"
  },
  {
    "path": "flutter/todo/plugin/ios/plugin.podspec",
    "content": "#\n# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html.\n# Run `pod lib lint plugin.podspec` to validate before publishing.\n#\nPod::Spec.new do |s|\n  s.name             = 'plugin'\n  s.version          = '0.0.1'\n  s.summary          = 'Rust bridge.'\n  s.description      = <<-DESC\nA flutter Rust bridge project.\n                       DESC\n  s.homepage         = 'http://example.com'\n  s.license          = { :file => '../LICENSE' }\n  s.author           = { 'Your Company' => 'email@example.com' }\n  s.source           = { :path => '.' }\n\n  s.source_files = 'Classes/**/*'\n  s.dependency 'Flutter'\n  s.platform = :ios, '8.0'\n\n  # Flutter.framework does not contain a i386 slice.\n  s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' }\n  s.swift_version = '5.0'\n\n  s.public_header_files = 'Classes**/*.h'\n  s.static_framework = true\n  s.vendored_libraries = '**/*.a'\nend\n"
  },
  {
    "path": "flutter/todo/plugin/macos/Classes/Plugin.swift",
    "content": "import Cocoa\nimport FlutterMacOS\n\npublic class Plugin: NSObject, FlutterPlugin {\n  public static func register(with registrar: FlutterPluginRegistrar) {\n  }\n\n  public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {\n    result(nil)\n  }\n}\n// <rid:prevent_tree_shake Start>\nfunc dummyCallsToPreventTreeShaking() {\n    _export_dart_enum_Filter();\n    _to_dart_for_Store();\n    rid_store_debug(nil);\n    rid_store_debug_pretty(nil);\n    create_store();\n    rid_store_unlock();\n    rid_store_free();\n    __include_dart_for_vec_todo();\n    rid_store_last_added_id(nil);\n    rid_store_todos(nil);\n    rid_store_filter(nil);\n    rid_store_settings(nil);\n    rid_len_vec_todo(nil);\n    rid_get_item_vec_todo(nil, 0);\n    _include_Store_field_wrappers();\n    rid_cstring_free(nil);\n    rid_init_msg_isolate(0);\n    rid_init_reply_isolate(0);\n    rid_export_Store_filtered_todos(nil);\n    rid_export_Store_todo_by_id(nil, 0);\n    __include_dart_for_ridvec_todo();\n    rid_free_ridvec_todo(RidVec_Pointer_Todo());\n    rid_get_item_ridvec_todo(RidVec_Pointer_Todo(), 0);\n    _to_dart_for_Settings();\n    rid_settings_debug(nil);\n    rid_settings_debug_pretty(nil);\n    rid_settings_auto_expire_completed_todos(nil);\n    rid_settings_completed_expiry_millis(nil);\n    _to_dart_for_Todo();\n    rid_todo_debug(nil);\n    rid_todo_debug_pretty(nil);\n    rid_todo_id(nil);\n    rid_todo_title(nil);\n    rid_todo_title_len(nil);\n    rid_todo_completed(nil);\n    rid_todo_expiry_millis(nil);\n    rid_filter_debug(0);\n    rid_filter_debug_pretty(0);\n    rid_msg_AddTodo(0, nil);\n    rid_msg_RemoveTodo(0, 0);\n    rid_msg_RemoveCompleted(0);\n    rid_msg_CompleteTodo(0, 0);\n    rid_msg_RestartTodo(0, 0);\n    rid_msg_ToggleTodo(0, 0);\n    rid_msg_CompleteAll(0);\n    rid_msg_RestartAll(0);\n    rid_msg_SetFilter(0, Filter(rawValue: 0));\n    rid_msg_SetAutoExpireCompletedTodos(0, 0);\n}\n// <rid:prevent_tree_shake End>"
  },
  {
    "path": "flutter/todo/plugin/macos/plugin.podspec",
    "content": "#\n# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html.\n# Run `pod lib lint plugin.podspec` to validate before publishing.\n#\nPod::Spec.new do |s|\n  s.name             = 'plugin'\n  s.version          = '0.0.1'\n  s.summary          = 'Rust bridge.'\n  s.description      = <<-DESC\nA flutter Rust bridge project.\n                       DESC\n  s.homepage         = 'http://example.com'\n  s.license          = { :file => '../LICENSE' }\n  s.author           = { 'Your Company' => 'email@example.com' }\n  s.source           = { :path => '.' }\n  s.source_files     = 'Classes/**/*'\n  s.dependency 'FlutterMacOS'\n\n  s.platform = :osx, '10.11'\n  s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES' }\n  s.swift_version = '5.0'\n\n  s.public_header_files = 'Classes**/*.h'\n  s.static_framework = true\n  s.vendored_libraries = '**/*.a'\nend\n"
  },
  {
    "path": "flutter/todo/plugin/plugin.iml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<module type=\"JAVA_MODULE\" version=\"4\">\n  <component name=\"NewModuleRootManager\" inherit-compiler-output=\"true\">\n    <exclude-output />\n    <content url=\"file://$MODULE_DIR$\">\n      <sourceFolder url=\"file://$MODULE_DIR$/lib\" isTestSource=\"false\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/.dart_tool\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/.idea\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/.pub\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/example/.pub\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/example/build\" />\n    </content>\n    <orderEntry type=\"sourceFolder\" forTests=\"false\" />\n    <orderEntry type=\"library\" name=\"Dart Packages\" level=\"project\" />\n    <orderEntry type=\"library\" name=\"Dart SDK\" level=\"project\" />\n    <orderEntry type=\"library\" name=\"Flutter Plugins\" level=\"project\" />\n  </component>\n</module>"
  },
  {
    "path": "flutter/todo/plugin/pubspec.yaml",
    "content": "name: plugin\ndescription: Plugin to provide a bridge to Rust.\nversion: 0.0.1\n\nenvironment:\n  sdk: \">=2.13.0 <3.0.0\"\n  flutter: \">=2.0.0\"\n\ndependencies: \n  ffi: ^1.0.0\n  ffigen: 4.0.0-dev.2\n\n  flutter:\n    sdk: flutter\n\nflutter:\n  # This section identifies this Flutter project as a plugin project.\n  # The 'pluginClass' and Android 'package' identifiers should not ordinarily\n  # be modified. They are used by the tooling to maintain consistency when\n  # adding or updating assets for this project.\n  plugin:\n    platforms:\n      android:\n        package: com.example.plugin\n        pluginClass: Plugin\n      ios:\n        pluginClass: Plugin\n      macos:\n        pluginClass: Plugin\n"
  },
  {
    "path": "flutter/todo/pubspec.yaml",
    "content": "name: todo\ndescription: A new Flutter project.\n\npublish_to: 'none' # Remove this line if you wish to publish to pub.dev\n\nversion: 1.0.0+1\n\nenvironment:\n  sdk: \">=2.13.0 <3.0.0\"\n\ndependencies:\n  flutter:\n    sdk: flutter\n\n  plugin:\n    path: plugin\n\n  cupertino_icons: ^1.0.2\n\ndev_dependencies:\n  flutter_test:\n    sdk: flutter\n\nflutter:\n\n  uses-material-design: true\n\n  assets:\n    - assets/dash.png\n    - assets/ferris.png\n"
  },
  {
    "path": "flutter/todo/rid_build.rs",
    "content": "use rid_build::{build, BuildConfig, BuildTarget, FlutterConfig, FlutterPlatform, Project};\nuse std::env;\n\nfn main() {\n    let crate_dir = env::var(\"CARGO_MANIFEST_DIR\")\n        .expect(\"Missing CARGO_MANIFEST_DIR, please run this via 'cargo run'\");\n\n    let workspace_dir = &crate_dir;\n\n    let crate_name = &env::var(\"CARGO_PKG_NAME\")\n        .expect(\"Missing CARGO_PKG_NAME, please run this via 'cargo run'\");\n    let lib_name = &format!(\"lib{}\", &crate_name);\n\n    let build_config = BuildConfig {\n        target: BuildTarget::Debug,\n        project: Project::Flutter(FlutterConfig {\n            plugin_name: \"plugin\".to_string(),\n            platforms: vec![\n                FlutterPlatform::ios(),\n                FlutterPlatform::macos(),\n                FlutterPlatform::android(),\n                FlutterPlatform::linux(),\n            ],\n        }),\n        lib_name,\n        crate_name,\n        project_root: &crate_dir,\n        workspace_root: Some(&workspace_dir),\n    };\n    build(&build_config).expect(\"Build failed\");\n}\n"
  },
  {
    "path": "flutter/todo/sh/android",
    "content": "#!/usr/bin/env bash\n\nDIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" >/dev/null 2>&1 && pwd )\"\n\nANDROID_PLATFORM_VERSION=28\n\n# x86 (i686)\nANDROID_BUILD_TARGET=i686-linux-android\n\n# x86_64\n# ANDROID_BUILD_TARGET=x86_64-linux-android\n\n# arm64\n# ANDROID_BUILD_TARGET=arm64-v8a\n\n# armeabi\n# ANDROID_BUILD_TARGET=armeabi-v7a\n\nANDROID_DIR=$DIR/../plugin/android\nJNI_LIBS_DIR=$ANDROID_DIR/src/main/jniLibs\n\n# Install Android NDK https://developer.android.com/studio/projects/install-ndk\n# https://github.com/bbqsrc/cargo-ndk\ncargo ndk                              \\\n  --platform $ANDROID_PLATFORM_VERSION \\\n  --target $ANDROID_BUILD_TARGET       \\\n  --output-dir $JNI_LIBS_DIR           \\\n  build\n"
  },
  {
    "path": "flutter/todo/sh/bindgen",
    "content": "#!/usr/bin/env bash\n\nDIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" >/dev/null 2>&1 && pwd )\"\n\ncd $DIR/.. && cargo run rid_build\n"
  },
  {
    "path": "flutter/todo/sh/clean",
    "content": "#!/usr/bin/env bash\n\nDIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" >/dev/null 2>&1 && pwd )\"\n\n(cd $DIR/../plugin && flutter clean && flutter pub get)\n(cd $DIR/.. && flutter clean && flutter pub get)\n"
  },
  {
    "path": "flutter/todo/sh/ios",
    "content": "#!/usr/bin/env bash\n\nDIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" >/dev/null 2>&1 && pwd )\"\n\nIOS_TARGETS=x86_64-apple-ios\n\n# Alternative not using jq\n# WORKSPACE_CARGO_TOML=`cargo locate-project --workspace --message-format plain`\n# WORKSPACE_ROOT=$(dirname \"${WORKSPACE_CARGO_TOML}\")\n# TARGET_DIR=$WORKSPACE_ROOT/target\n\nTARGET_DIR=`cargo metadata --format-version 1 --no-deps | jq \".target_directory\" | xargs echo`\nPROJECT_NAME=`cargo metadata --format-version 1 | jq \".resolve.root\" | xargs echo | cut -d ' ' -f1`\nLIB_NAME=lib$PROJECT_NAME.a\n\n# <root>/target/universal/debug\nUNIVERSAL_DEBUG_DIR=\"$TARGET_DIR/universal/debug\"\nFLUTTER_IOS_DIR=\"$DIR/../plugin/ios\"\n\nLIB_SOURCE_FILE=\"$UNIVERSAL_DEBUG_DIR/$LIB_NAME\"\nLIB_TARGET_FILE=\"$FLUTTER_IOS_DIR/$LIB_NAME\"\n\ncargo lipo \\\n  --targets $IOS_TARGETS\n\ncp $LIB_SOURCE_FILE $LIB_TARGET_FILE\n"
  },
  {
    "path": "flutter/todo/sh/linux",
    "content": "#!/usr/bin/env bash\n\nDIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" >/dev/null 2>&1 && pwd )\"\n\nTARGET_DIR=`cargo metadata --format-version 1 --no-deps | jq \".target_directory\" | xargs echo`\nPROJECT_NAME=`cargo metadata --format-version 1 | jq \".resolve.root\" | xargs echo | cut -d ' ' -f1`\nLIB_NAME_STATIC=lib$PROJECT_NAME.a\nLIB_NAME_DYNAMIC=lib$PROJECT_NAME.so\n\n# <root>/target/universal/debug\nUNIVERSAL_DEBUG_DIR=\"$TARGET_DIR/debug\"\nFLUTTER_LINUX_DIR=\"$DIR/../plugin/linux\"\n\nmkdir -p $FLUTTER_LINUX_DIR\n\nLIB_SOURCE_FILE_STATIC=\"$UNIVERSAL_DEBUG_DIR/$LIB_NAME_STATIC\"\nLIB_SOURCE_FILE_DYNAMIC=\"$UNIVERSAL_DEBUG_DIR/$LIB_NAME_DYNAMIC\"\nLIB_TARGET_FILE_STATIC=\"$FLUTTER_LINUX_DIR/$LIB_NAME_STATIC\"\nLIB_TARGET_FILE_DYNAMIC=\"$FLUTTER_LINUX_DIR/$LIB_NAME_DYNAMIC\"\n\ncargo build && cp $LIB_SOURCE_FILE_STATIC $LIB_TARGET_FILE_STATIC && cp $LIB_SOURCE_FILE_DYNAMIC $LIB_TARGET_FILE_DYNAMIC\n\nexit $?\n"
  },
  {
    "path": "flutter/todo/sh/macos",
    "content": "#!/usr/bin/env bash\n\nDIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" >/dev/null 2>&1 && pwd )\"\n\nMACOS_TARGETS=aarch64-apple-ios\n\nTARGET_DIR=`cargo metadata --format-version 1 --no-deps | jq \".target_directory\" | xargs echo`\nPROJECT_NAME=`cargo metadata --format-version 1 | jq \".resolve.root\" | xargs echo | cut -d ' ' -f1`\nLIB_NAME=lib$PROJECT_NAME.a\n\n# <root>/target/universal/debug\nUNIVERSAL_DEBUG_DIR=\"$TARGET_DIR/debug\"\nFLUTTER_MACOS_DIR=\"$DIR/../plugin/macos\"\n\nLIB_SOURCE_FILE=\"$UNIVERSAL_DEBUG_DIR/$LIB_NAME\"\nLIB_TARGET_FILE=\"$FLUTTER_MACOS_DIR/$LIB_NAME\"\n\ncargo build && cp $LIB_SOURCE_FILE $LIB_TARGET_FILE\n\nexit $?\n"
  },
  {
    "path": "flutter/todo/src/lib.rs",
    "content": "use core::time;\nuse std::{\n    sync::{RwLockReadGuard, RwLockWriteGuard},\n    thread,\n};\n\nuse rid::RidStore;\n\nconst COMPLETED_EXPIRY_MILLIS: u64 = 7000;\nconst EXPIRY_STEP: u64 = 7;\n\n// -----------------\n// Store\n// -----------------\n#[rid::store]\n#[rid::structs(Todo, Settings)]\n#[rid::enums(Filter)]\n#[derive(Debug)]\npub struct Store {\n    last_added_id: u32,\n    todos: Vec<Todo>,\n    filter: Filter,\n    settings: Settings,\n}\n\nimpl RidStore<Msg> for Store {\n    fn create() -> Self {\n        let first_todo = Todo {\n            id: 0,\n            title: \"Learn Flutter\".to_string(),\n            completed: true,\n            expiry_millis: COMPLETED_EXPIRY_MILLIS,\n        };\n        let second_todo = Todo {\n            id: 1,\n            title: \"Learn Rust\".to_string(),\n            completed: true,\n            expiry_millis: COMPLETED_EXPIRY_MILLIS,\n        };\n        let third_todo = Todo {\n            id: 2,\n            title: \"Learn Rid\".to_string(),\n            completed: false,\n            expiry_millis: COMPLETED_EXPIRY_MILLIS,\n        };\n        let fourth_todo = Todo {\n            id: 3,\n            title: \"Build Awesome Apps\".to_string(),\n            completed: false,\n            expiry_millis: COMPLETED_EXPIRY_MILLIS,\n        };\n        Self {\n            last_added_id: 3,\n            todos: vec![first_todo, second_todo, third_todo, fourth_todo],\n            filter: Filter::All,\n            settings: Settings {\n                auto_expire_completed_todos: false,\n                completed_expiry_millis: COMPLETED_EXPIRY_MILLIS,\n            },\n        }\n    }\n\n    fn update(&mut self, req_id: u64, msg: Msg) {\n        use Msg::*;\n        match msg {\n            AddTodo(title) => {\n                self.last_added_id += 1;\n                let todo = Todo {\n                    id: self.last_added_id,\n                    title,\n                    completed: false,\n                    expiry_millis: COMPLETED_EXPIRY_MILLIS,\n                };\n                self.todos.push(todo);\n                rid::post(Reply::AddedTodo(req_id, self.last_added_id.to_string()));\n            }\n            RemoveTodo(id) => {\n                self.remove_todo(id);\n                rid::post(Reply::RemovedTodo(req_id, self.last_added_id.to_string()));\n            }\n\n            RemoveCompleted => {\n                self.todos.retain(|todo| !todo.completed);\n                rid::post(Reply::RemovedCompleted(req_id));\n            }\n\n            CompleteTodo(id) => {\n                self.update_todo(id, |todo| todo.set_completed(true));\n                rid::post(Reply::CompletedTodo(req_id, id.to_string()));\n            }\n            RestartTodo(id) => {\n                self.update_todo(id, |todo| todo.set_completed(false));\n                rid::post(Reply::RestartedTodo(req_id, id.to_string()));\n            }\n            ToggleTodo(id) => {\n                self.update_todo(id, |todo| todo.set_completed(!todo.completed));\n                rid::post(Reply::ToggledTodo(req_id, id.to_string()));\n            }\n\n            CompleteAll => {\n                self.todos.iter_mut().for_each(|x| x.set_completed(true));\n                rid::post(Reply::CompletedAll(req_id));\n            }\n            RestartAll => {\n                self.todos.iter_mut().for_each(|x| x.set_completed(false));\n                rid::post(Reply::RestartedAll(req_id));\n            }\n\n            SetFilter(filter) => {\n                self.filter = filter;\n                rid::post(Reply::SetFilter(req_id));\n            }\n            SetAutoExpireCompletedTodos(expire) => {\n                self.set_auto_expire_completed_todos(expire);\n                rid::post(Reply::SetAutoExpireCompletedTodos(req_id));\n            }\n        };\n    }\n}\n\n#[rid::export]\n#[rid::structs(Todo)]\nimpl Store {\n    fn remove_todo(&mut self, id: u32) {\n        let mut enumerated = self.todos.iter().enumerate();\n        let idx = match enumerated.find(|(_, todo)| todo.id == id) {\n            Some((idx, _)) => idx,\n            None => return eprintln!(\"Could not find Todo with id '{}'\", id),\n        };\n        self.todos.remove(idx);\n    }\n\n    fn update_todo<F: FnOnce(&mut Todo)>(&mut self, id: u32, update: F) {\n        match self.todos.iter_mut().find(|x| x.id == id) {\n            Some(todo) => update(todo),\n            None => eprintln!(\"Could not find Todo with id '{}'\", id),\n        };\n    }\n\n    #[rid::export]\n    fn filtered_todos(&self) -> Vec<&Todo> {\n        let mut vec: Vec<&Todo> = match self.filter {\n            Filter::Completed => self.todos.iter().filter(|x| x.completed).collect(),\n            Filter::Pending => self.todos.iter().filter(|x| !x.completed).collect(),\n            Filter::All => self.todos.iter().collect(),\n        };\n        vec.sort();\n        vec\n    }\n\n    #[rid::export]\n    fn todo_by_id(&self, id: u32) -> Option<&Todo> {\n        self.todos.iter().find(|x| x.id == id)\n    }\n\n    // The below read/write wrappers help with auto complete since procmacros\n    // aren't very well supported by the rust analyzer yet\n    fn read() -> RwLockReadGuard<'static, Store> {\n        store::read()\n    }\n\n    fn write() -> RwLockWriteGuard<'static, Store> {\n        store::write()\n    }\n\n    pub fn set_auto_expire_completed_todos(&mut self, expire: bool) {\n        self.settings.auto_expire_completed_todos = expire;\n        if expire {\n            thread::spawn(move || {\n                eprintln!(\n                    \"rust: thread {:?} started auto expiring\",\n                    thread::current().id()\n                );\n                while Store::read().settings.auto_expire_completed_todos {\n                    thread::sleep(time::Duration::from_millis(EXPIRY_STEP));\n                    {\n                        let ids_to_update: Vec<(u32, bool)> = Store::write()\n                            .todos\n                            .iter_mut()\n                            .filter(|x| x.completed)\n                            .map(|x: &mut Todo| {\n                                let next_value = x.expiry_millis - EXPIRY_STEP;\n                                if next_value <= 0 {\n                                    (x.id, true)\n                                } else {\n                                    x.expiry_millis = next_value;\n                                    (x.id, false)\n                                }\n                            })\n                            .collect();\n\n                        for (id, remove) in ids_to_update {\n                            if remove {\n                                Store::write().remove_todo(id);\n                                rid::post(Reply::CompletedTodoExpired);\n                            } else {\n                                rid::post(Reply::Tick(id.to_string()));\n                            }\n                        }\n                    }\n                }\n                eprintln!(\n                    \"rust: thread {:?} stopped auto expiring\",\n                    thread::current().id()\n                );\n            });\n        }\n    }\n}\n\n// -----------------\n// Settings\n// -----------------\n#[rid::model]\n#[derive(Debug)]\npub struct Settings {\n    auto_expire_completed_todos: bool,\n    completed_expiry_millis: u64,\n}\n\n// -----------------\n// Todo Model\n// -----------------\n#[rid::model]\n#[derive(PartialEq, Eq, PartialOrd, Debug)]\npub struct Todo {\n    id: u32,\n    title: String,\n    completed: bool,\n    expiry_millis: u64,\n}\n\nimpl Todo {\n    fn set_completed(&mut self, completed: bool) {\n        self.completed = completed;\n        self.expiry_millis = COMPLETED_EXPIRY_MILLIS;\n    }\n}\n\nimpl Ord for Todo {\n    fn cmp(&self, other: &Self) -> std::cmp::Ordering {\n        self.id.cmp(&other.id)\n    }\n}\n\n// -----------------\n// Filter\n// -----------------\n#[rid::model]\n#[derive(Clone, Debug)]\npub enum Filter {\n    Completed,\n    Pending,\n    All,\n}\n\n// -----------------\n// Msg\n// -----------------\n#[rid::message(Reply)]\n#[rid::enums(Filter)]\n#[derive(Debug)]\npub enum Msg {\n    AddTodo(String),\n    RemoveTodo(u32),\n    RemoveCompleted,\n\n    CompleteTodo(u32),\n    RestartTodo(u32),\n    ToggleTodo(u32),\n    CompleteAll,\n    RestartAll,\n\n    SetFilter(Filter),\n    SetAutoExpireCompletedTodos(bool),\n}\n\n// -----------------\n// Reply\n// -----------------\n#[rid::reply]\npub enum Reply {\n    // Message Replies\n    AddedTodo(u64, String),\n    RemovedTodo(u64, String),\n    RemovedCompleted(u64),\n\n    CompletedTodo(u64, String),\n    RestartedTodo(u64, String),\n    ToggledTodo(u64, String),\n    CompletedAll(u64),\n    RestartedAll(u64),\n\n    SetFilter(u64),\n    SetAutoExpireCompletedTodos(u64),\n\n    // Application Events\n    CompletedTodoExpired,\n    Tick(String),\n}\n"
  },
  {
    "path": "flutter/todo/test/widget_test.dart",
    "content": "// This is a basic Flutter widget test.\n//\n// To perform an interaction with a widget in your test, use the WidgetTester\n// utility that Flutter provides. For example, you can send tap and scroll\n// gestures. You can also use WidgetTester to find child widgets in the widget\n// tree, read text, and verify that the values of widget properties are correct.\n\nimport 'package:flutter/material.dart';\nimport 'package:flutter_test/flutter_test.dart';\n\nimport 'package:todo/main.dart';\n\nvoid main() {\n  testWidgets('Counter increments smoke test', (WidgetTester tester) async {\n    // Build our app and trigger a frame.\n    await tester.pumpWidget(MyApp());\n\n    // Verify that our counter starts at 0.\n    expect(find.text('0'), findsOneWidget);\n    expect(find.text('1'), findsNothing);\n\n    // Tap the '+' icon and trigger a frame.\n    await tester.tap(find.byIcon(Icons.add));\n    await tester.pump();\n\n    // Verify that our counter has incremented.\n    expect(find.text('0'), findsNothing);\n    expect(find.text('1'), findsOneWidget);\n  });\n}\n"
  },
  {
    "path": "flutter/todo/todo.iml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<module type=\"JAVA_MODULE\" version=\"4\">\n  <component name=\"NewModuleRootManager\" inherit-compiler-output=\"true\">\n    <exclude-output />\n    <content url=\"file://$MODULE_DIR$\">\n      <sourceFolder url=\"file://$MODULE_DIR$/lib\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/test\" isTestSource=\"true\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/src\" isTestSource=\"false\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/.dart_tool\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/.idea\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/.pub\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/ios/.symlinks/plugins/plugin/.dart_tool\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/ios/.symlinks/plugins/plugin/.pub\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/ios/.symlinks/plugins/plugin/build\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/macos/Flutter/ephemeral/.symlinks/plugins/plugin/build\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/macos/Flutter/ephemeral/.symlinks/plugins/plugin/.dart_tool\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/macos/Flutter/ephemeral/.symlinks/plugins/plugin/.pub\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/plugin/.dart_tool\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/plugin/build\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/plugin/.pub\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/target\" />\n    </content>\n    <orderEntry type=\"sourceFolder\" forTests=\"false\" />\n    <orderEntry type=\"library\" name=\"Dart SDK\" level=\"project\" />\n    <orderEntry type=\"library\" name=\"Flutter Plugins\" level=\"project\" />\n    <orderEntry type=\"library\" name=\"Dart Packages\" level=\"project\" />\n  </component>\n</module>"
  },
  {
    "path": "flutter/todo_cubit/.gitignore",
    "content": ".DS_Store\n.idea/\n.metadata\n\n## Flutter ###\n# Flutter/Dart/Pub related\n**/doc/api/\n.dart_tool/\n.flutter-plugins\n.flutter-plugins-dependencies\n.fvm/\n.packages\n.pub-cache/\n.pub/\nbuild/\ncoverage/\nlib/generated_plugin_registrant.dart\n# For library packages, don’t commit the pubspec.lock file.\n# Regenerating the pubspec.lock file lets you test your package against the latest compatible versions of its dependencies.\n# See https://dart.dev/guides/libraries/private-files#pubspeclock\n#pubspec.lock\n\n# Android related\n**/android/**/gradle-wrapper.jar\n**/android/.gradle\n**/android/captures/\n**/android/gradlew\n**/android/gradlew.bat\n**/android/key.properties\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/.last_build_id\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# 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\n### Rust ###\n**/target/**\n**/Cargo.lock\n\n### Rid ###\n**/generated/**\n**/Classes/bindings.h\n**/macos/*.a\n**/ios/*.a\n**/android/src/main/jniLibs/*\n"
  },
  {
    "path": "flutter/todo_cubit/Cargo.toml",
    "content": "[package]\nname = \"todo_cubit\"\nversion = \"0.1.0\"\nauthors = [\"Thorsten Lorenz <thlorenz@gmx.de>\"]\nedition = \"2018\"\n\n[lib]\ncrate-type = [\"cdylib\", \"staticlib\" ]\n\n[[bin]]\nname = \"rid_build\"\npath = \"rid_build.rs\"\n\n[dependencies]\ncbindgen = \"0.18.0\"\nrid_build = { path = \"../../../rid/rid-build\" }\nrid = { path = \"../../../rid\" }\n"
  },
  {
    "path": "flutter/todo_cubit/README.md",
    "content": "# todo_cubit\n\nRust integrated Dart Flutter Project\n\n## Getting Started\n\nUse the below scripts to get the app ready to run with Flutter.\n\n### 1. Generate Glue Code\n\n```sh\n./sh/bindgen\n```\n\n### 2. Build For Desired Target/Device\n\nRun any of the below three to build the binary for the specific device and have it placed into\nthe devices specific plugin folder.\n\n```sh\n./sh/macos\n```\n\n### 3. Run with Flutter\n\nRun on the device.\n\n```sh\nflutter run -d macos\n```\n\n### 4. Develop\n\nRun step `1` whenever a function exposed to Flutter changes.\n\nRun step `2` whenever any of your Rust code changes.\n\n**Note** that to apply changes from Rust you need to restart the app to reload the compiled binary.\nA hot restart/reload does not achieve this.\n\n## Folder Structure\n\n```\n├── android\n├── ios\n├── macos\n├── lib\n├── plugin\n│   ├── android\n│   ├── ios\n│   ├── macos\n│   └── lib\n└── src\n```\n\n### `./plugin`\n\nProvides connection from Flutter to Rust.\n\nRust binaries are placed into the respective plugin folders `./ios, ./macos, ./android` when\nthey are built.\n\nGenerated Dart glue code is placed inside `./plugin/lib/generated` while\n`./plugin/lib/plugin.dart` just exposes the API to the app.\n\n### `./src`\n\nContains the starter Rust code inside `./src/lib.rs`. Keep developing the Rust part of your app\nhere.\n\n### `./lib`\n\nContains the starter Flutter app inside `./lib/main.dart`.\n\n### `./sh`\n\nProvides scripts to run build and code generation tasks. In the future a tool will provide the\nfunctionality currently provided by these scripts.\n\n- `bindgen` generates the `binding.h` header file for the extern Rust functions found inside\n  `./src`. These are then placed inside the `./plugin` device folders were needed as well as\n  `./plugin/lib/generated/binding.h` where they are used to generate Dart glue code\n  - as part of this script `ffigen` generates Dart glue code inside\n    `./plugin/lib/generated/ffigen_binding.dart` using `./plugin/lib/generated/binding.h` as input\n- `./android` builds the Rust binary to run on Android devices/emulators and places it inside\n  `./plugin/lib/android`\n- `./ios` builds the Rust binary to run on IOS devices/emulators and places it inside\n  `./plugin/lib/ios`\n- `./macos` builds the Rust binary to run on MacOs directly and places it inside\n  `./plugin/lib/macos`, this is the same format as running `cargo build` on your Mac\n- `clean` cleans both the Flutter plugin and application, run this to reset Flutter when things\n  aren't working\n"
  },
  {
    "path": "flutter/todo_cubit/analysis_options.yaml",
    "content": "# This file configures the analyzer, which statically analyzes Dart code to\n# check for errors, warnings, and lints.\n#\n# The issues identified by the analyzer are surfaced in the UI of Dart-enabled\n# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be\n# invoked from the command line by running `flutter analyze`.\n\n# The following line activates a set of recommended lints for Flutter apps,\n# packages, and plugins designed to encourage good coding practices.\ninclude: package:flutter_lints/flutter.yaml\n\nlinter:\n  # The lint rules applied to this project can be customized in the\n  # section below to disable rules from the `package:flutter_lints/flutter.yaml`\n  # included above or to enable additional rules. A list of all available lints\n  # and their documentation is published at\n  # https://dart-lang.github.io/linter/lints/index.html.\n  #\n  # Instead of disabling a lint rule for the entire project in the\n  # section below, it can also be suppressed for a single line of code\n  # or a specific dart file by using the `// ignore: name_of_lint` and\n  # `// ignore_for_file: name_of_lint` syntax on the line or in the file\n  # producing the lint.\n  rules:\n    # avoid_print: false  # Uncomment to disable the `avoid_print` rule\n    # prefer_single_quotes: true  # Uncomment to enable the `prefer_single_quotes` rule\n\n# Additional information about this file can be found at\n# https://dart.dev/guides/language/analysis-options\n"
  },
  {
    "path": "flutter/todo_cubit/android/.gitignore",
    "content": "gradle-wrapper.jar\n/.gradle\n/captures/\n/gradlew\n/gradlew.bat\n/local.properties\nGeneratedPluginRegistrant.java\n\n# Remember to never publicly share your keystore.\n# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app\nkey.properties\n**/*.keystore\n**/*.jks\n"
  },
  {
    "path": "flutter/todo_cubit/android/app/build.gradle",
    "content": "def localProperties = new Properties()\ndef localPropertiesFile = rootProject.file('local.properties')\nif (localPropertiesFile.exists()) {\n    localPropertiesFile.withReader('UTF-8') { reader ->\n        localProperties.load(reader)\n    }\n}\n\ndef flutterRoot = localProperties.getProperty('flutter.sdk')\nif (flutterRoot == null) {\n    throw new GradleException(\"Flutter SDK not found. Define location with flutter.sdk in the local.properties file.\")\n}\n\ndef flutterVersionCode = localProperties.getProperty('flutter.versionCode')\nif (flutterVersionCode == null) {\n    flutterVersionCode = '1'\n}\n\ndef flutterVersionName = localProperties.getProperty('flutter.versionName')\nif (flutterVersionName == null) {\n    flutterVersionName = '1.0'\n}\n\napply plugin: 'com.android.application'\napply plugin: 'kotlin-android'\napply from: \"$flutterRoot/packages/flutter_tools/gradle/flutter.gradle\"\n\nandroid {\n    compileSdkVersion 30\n\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n\n    kotlinOptions {\n        jvmTarget = '1.8'\n    }\n\n    sourceSets {\n        main.java.srcDirs += 'src/main/kotlin'\n    }\n\n    defaultConfig {\n        // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).\n        applicationId \"com.example.todo_cubit\"\n        minSdkVersion 16\n        targetSdkVersion 30\n        versionCode flutterVersionCode.toInteger()\n        versionName flutterVersionName\n    }\n\n    buildTypes {\n        release {\n            // TODO: Add your own signing config for the release build.\n            // Signing with the debug keys for now, so `flutter run --release` works.\n            signingConfig signingConfigs.debug\n        }\n    }\n}\n\nflutter {\n    source '../..'\n}\n\ndependencies {\n    implementation \"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version\"\n}\n"
  },
  {
    "path": "flutter/todo_cubit/android/app/src/debug/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.example.todo_cubit\">\n    <!-- Flutter needs it to communicate with the running application\n         to allow setting breakpoints, to provide hot reload, etc.\n    -->\n    <uses-permission android:name=\"android.permission.INTERNET\"/>\n</manifest>\n"
  },
  {
    "path": "flutter/todo_cubit/android/app/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.example.todo_cubit\">\n   <application\n        android:label=\"todo_cubit\"\n        android:icon=\"@mipmap/ic_launcher\">\n        <activity\n            android:name=\".MainActivity\"\n            android:launchMode=\"singleTop\"\n            android:theme=\"@style/LaunchTheme\"\n            android:configChanges=\"orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode\"\n            android:hardwareAccelerated=\"true\"\n            android:windowSoftInputMode=\"adjustResize\">\n            <!-- Specifies an Android theme to apply to this Activity as soon as\n                 the Android process has started. This theme is visible to the user\n                 while the Flutter UI initializes. After that, this theme continues\n                 to determine the Window background behind the Flutter UI. -->\n            <meta-data\n              android:name=\"io.flutter.embedding.android.NormalTheme\"\n              android:resource=\"@style/NormalTheme\"\n              />\n            <!-- Displays an Android View that continues showing the launch screen\n                 Drawable until Flutter paints its first frame, then this splash\n                 screen fades out. A splash screen is useful to avoid any visual\n                 gap between the end of Android's launch screen and the painting of\n                 Flutter's first frame. -->\n            <meta-data\n              android:name=\"io.flutter.embedding.android.SplashScreenDrawable\"\n              android:resource=\"@drawable/launch_background\"\n              />\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\"/>\n                <category android:name=\"android.intent.category.LAUNCHER\"/>\n            </intent-filter>\n        </activity>\n        <!-- Don't delete the meta-data below.\n             This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->\n        <meta-data\n            android:name=\"flutterEmbedding\"\n            android:value=\"2\" />\n    </application>\n</manifest>\n"
  },
  {
    "path": "flutter/todo_cubit/android/app/src/main/kotlin/com/example/todo_cubit/MainActivity.kt",
    "content": "package com.example.todo_cubit\n\nimport io.flutter.embedding.android.FlutterActivity\n\nclass MainActivity: FlutterActivity() {\n}\n"
  },
  {
    "path": "flutter/todo_cubit/android/app/src/main/res/drawable/launch_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- Modify this file to customize your launch splash screen -->\n<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:drawable=\"@android:color/white\" />\n\n    <!-- You can insert your own image assets here -->\n    <!-- <item>\n        <bitmap\n            android:gravity=\"center\"\n            android:src=\"@mipmap/launch_image\" />\n    </item> -->\n</layer-list>\n"
  },
  {
    "path": "flutter/todo_cubit/android/app/src/main/res/drawable-v21/launch_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- Modify this file to customize your launch splash screen -->\n<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:drawable=\"?android:colorBackground\" />\n\n    <!-- You can insert your own image assets here -->\n    <!-- <item>\n        <bitmap\n            android:gravity=\"center\"\n            android:src=\"@mipmap/launch_image\" />\n    </item> -->\n</layer-list>\n"
  },
  {
    "path": "flutter/todo_cubit/android/app/src/main/res/values/styles.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->\n    <style name=\"LaunchTheme\" parent=\"@android:style/Theme.Light.NoTitleBar\">\n        <!-- Show a splash screen on the activity. Automatically removed when\n             Flutter draws its first frame -->\n        <item name=\"android:windowBackground\">@drawable/launch_background</item>\n    </style>\n    <!-- Theme applied to the Android Window as soon as the process has started.\n         This theme determines the color of the Android Window while your\n         Flutter UI initializes, as well as behind your Flutter UI while its\n         running.\n         \n         This Theme is only used starting with V2 of Flutter's Android embedding. -->\n    <style name=\"NormalTheme\" parent=\"@android:style/Theme.Light.NoTitleBar\">\n        <item name=\"android:windowBackground\">?android:colorBackground</item>\n    </style>\n</resources>\n"
  },
  {
    "path": "flutter/todo_cubit/android/app/src/main/res/values-night/styles.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->\n    <style name=\"LaunchTheme\" parent=\"@android:style/Theme.Black.NoTitleBar\">\n        <!-- Show a splash screen on the activity. Automatically removed when\n             Flutter draws its first frame -->\n        <item name=\"android:windowBackground\">@drawable/launch_background</item>\n    </style>\n    <!-- Theme applied to the Android Window as soon as the process has started.\n         This theme determines the color of the Android Window while your\n         Flutter UI initializes, as well as behind your Flutter UI while its\n         running.\n         \n         This Theme is only used starting with V2 of Flutter's Android embedding. -->\n    <style name=\"NormalTheme\" parent=\"@android:style/Theme.Black.NoTitleBar\">\n        <item name=\"android:windowBackground\">?android:colorBackground</item>\n    </style>\n</resources>\n"
  },
  {
    "path": "flutter/todo_cubit/android/app/src/profile/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.example.todo_cubit\">\n    <!-- Flutter needs it to communicate with the running application\n         to allow setting breakpoints, to provide hot reload, etc.\n    -->\n    <uses-permission android:name=\"android.permission.INTERNET\"/>\n</manifest>\n"
  },
  {
    "path": "flutter/todo_cubit/android/build.gradle",
    "content": "buildscript {\n    ext.kotlin_version = '1.3.50'\n    repositories {\n        google()\n        mavenCentral()\n    }\n\n    dependencies {\n        classpath 'com.android.tools.build:gradle:4.1.0'\n        classpath \"org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version\"\n    }\n}\n\nallprojects {\n    repositories {\n        google()\n        mavenCentral()\n    }\n}\n\nrootProject.buildDir = '../build'\nsubprojects {\n    project.buildDir = \"${rootProject.buildDir}/${project.name}\"\n    project.evaluationDependsOn(':app')\n}\n\ntask clean(type: Delete) {\n    delete rootProject.buildDir\n}\n"
  },
  {
    "path": "flutter/todo_cubit/android/gradle/wrapper/gradle-wrapper.properties",
    "content": "#Fri Jun 23 08:50:38 CEST 2017\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-6.7-all.zip\n"
  },
  {
    "path": "flutter/todo_cubit/android/gradle.properties",
    "content": "org.gradle.jvmargs=-Xmx1536M\nandroid.useAndroidX=true\nandroid.enableJetifier=true\n"
  },
  {
    "path": "flutter/todo_cubit/android/settings.gradle",
    "content": "include ':app'\n\ndef localPropertiesFile = new File(rootProject.projectDir, \"local.properties\")\ndef properties = new Properties()\n\nassert localPropertiesFile.exists()\nlocalPropertiesFile.withReader(\"UTF-8\") { reader -> properties.load(reader) }\n\ndef flutterSdkPath = properties.getProperty(\"flutter.sdk\")\nassert flutterSdkPath != null, \"flutter.sdk not set in local.properties\"\napply from: \"$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle\"\n"
  },
  {
    "path": "flutter/todo_cubit/android/todo_cubit_android.iml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<module type=\"JAVA_MODULE\" version=\"4\">\n  <component name=\"FacetManager\">\n    <facet type=\"android\" name=\"Android\">\n      <configuration>\n        <option name=\"ALLOW_USER_CONFIGURATION\" value=\"false\" />\n        <option name=\"GEN_FOLDER_RELATIVE_PATH_APT\" value=\"/gen\" />\n        <option name=\"GEN_FOLDER_RELATIVE_PATH_AIDL\" value=\"/gen\" />\n        <option name=\"MANIFEST_FILE_RELATIVE_PATH\" value=\"/app/src/main/AndroidManifest.xml\" />\n        <option name=\"RES_FOLDER_RELATIVE_PATH\" value=\"/app/src/main/res\" />\n        <option name=\"ASSETS_FOLDER_RELATIVE_PATH\" value=\"/app/src/main/assets\" />\n        <option name=\"LIBS_FOLDER_RELATIVE_PATH\" value=\"/app/src/main/libs\" />\n        <option name=\"PROGUARD_LOGS_FOLDER_RELATIVE_PATH\" value=\"/app/src/main/proguard_logs\" />\n      </configuration>\n    </facet>\n  </component>\n  <component name=\"NewModuleRootManager\" inherit-compiler-output=\"true\">\n    <exclude-output />\n    <content url=\"file://$MODULE_DIR$\">\n      <sourceFolder url=\"file://$MODULE_DIR$/app/src/main/java\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/app/src/main/kotlin\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/gen\" isTestSource=\"false\" generated=\"true\" />\n    </content>\n    <orderEntry type=\"jdk\" jdkName=\"Android API 29 Platform\" jdkType=\"Android SDK\" />\n    <orderEntry type=\"sourceFolder\" forTests=\"false\" />\n    <orderEntry type=\"library\" name=\"Flutter for Android\" level=\"project\" />\n    <orderEntry type=\"library\" name=\"KotlinJavaRuntime\" level=\"project\" />\n  </component>\n</module>\n"
  },
  {
    "path": "flutter/todo_cubit/ios/.gitignore",
    "content": "*.mode1v3\n*.mode2v3\n*.moved-aside\n*.pbxuser\n*.perspectivev3\n**/*sync/\n.sconsign.dblite\n.tags*\n**/.vagrant/\n**/DerivedData/\nIcon?\n**/Pods/\n**/.symlinks/\nprofile\nxcuserdata\n**/.generated/\nFlutter/App.framework\nFlutter/Flutter.framework\nFlutter/Flutter.podspec\nFlutter/Generated.xcconfig\nFlutter/ephemeral/\nFlutter/app.flx\nFlutter/app.zip\nFlutter/flutter_assets/\nFlutter/flutter_export_environment.sh\nServiceDefinitions.json\nRunner/GeneratedPluginRegistrant.*\n\n# Exceptions to above rules.\n!default.mode1v3\n!default.mode2v3\n!default.pbxuser\n!default.perspectivev3\n"
  },
  {
    "path": "flutter/todo_cubit/ios/Flutter/AppFrameworkInfo.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  <key>CFBundleDevelopmentRegion</key>\n  <string>en</string>\n  <key>CFBundleExecutable</key>\n  <string>App</string>\n  <key>CFBundleIdentifier</key>\n  <string>io.flutter.flutter.app</string>\n  <key>CFBundleInfoDictionaryVersion</key>\n  <string>6.0</string>\n  <key>CFBundleName</key>\n  <string>App</string>\n  <key>CFBundlePackageType</key>\n  <string>FMWK</string>\n  <key>CFBundleShortVersionString</key>\n  <string>1.0</string>\n  <key>CFBundleSignature</key>\n  <string>????</string>\n  <key>CFBundleVersion</key>\n  <string>1.0</string>\n  <key>MinimumOSVersion</key>\n  <string>8.0</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "flutter/todo_cubit/ios/Flutter/Debug.xcconfig",
    "content": "#include? \"Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig\"\n#include \"Generated.xcconfig\"\n"
  },
  {
    "path": "flutter/todo_cubit/ios/Flutter/Release.xcconfig",
    "content": "#include? \"Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig\"\n#include \"Generated.xcconfig\"\n"
  },
  {
    "path": "flutter/todo_cubit/ios/Podfile",
    "content": "# Uncomment this line to define a global platform for your project\n# platform :ios, '9.0'\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', '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 Generated.xcconfig, then run flutter pub get\"\nend\n\nrequire File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)\n\nflutter_ios_podfile_setup\n\ntarget 'Runner' do\n  use_frameworks!\n  use_modular_headers!\n\n  flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))\nend\n\npost_install do |installer|\n  installer.pods_project.targets.each do |target|\n    flutter_additional_ios_build_settings(target)\n  end\nend\n"
  },
  {
    "path": "flutter/todo_cubit/ios/Runner/AppDelegate.swift",
    "content": "import UIKit\nimport Flutter\n\n@UIApplicationMain\n@objc class AppDelegate: FlutterAppDelegate {\n  override func application(\n    _ application: UIApplication,\n    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?\n  ) -> Bool {\n    GeneratedPluginRegistrant.register(with: self)\n    return super.application(application, didFinishLaunchingWithOptions: launchOptions)\n  }\n}\n"
  },
  {
    "path": "flutter/todo_cubit/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"size\" : \"20x20\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-App-20x20@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"20x20\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-App-20x20@3x.png\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"size\" : \"29x29\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-App-29x29@1x.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"29x29\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-App-29x29@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"29x29\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-App-29x29@3x.png\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"size\" : \"40x40\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-App-40x40@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"40x40\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-App-40x40@3x.png\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"size\" : \"60x60\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-App-60x60@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"60x60\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-App-60x60@3x.png\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"size\" : \"20x20\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-App-20x20@1x.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"20x20\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-App-20x20@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"29x29\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-App-29x29@1x.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"29x29\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-App-29x29@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"40x40\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-App-40x40@1x.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"40x40\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-App-40x40@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"76x76\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-App-76x76@1x.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"76x76\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-App-76x76@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"83.5x83.5\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-App-83.5x83.5@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"1024x1024\",\n      \"idiom\" : \"ios-marketing\",\n      \"filename\" : \"Icon-App-1024x1024@1x.png\",\n      \"scale\" : \"1x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}\n"
  },
  {
    "path": "flutter/todo_cubit/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"LaunchImage.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"LaunchImage@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"LaunchImage@3x.png\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}\n"
  },
  {
    "path": "flutter/todo_cubit/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md",
    "content": "# Launch Screen Assets\n\nYou can customize the launch screen with your own desired assets by replacing the image files in this directory.\n\nYou can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images."
  },
  {
    "path": "flutter/todo_cubit/ios/Runner/Base.lproj/LaunchScreen.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"12121\" systemVersion=\"16G29\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" launchScreen=\"YES\" colorMatched=\"YES\" initialViewController=\"01J-lp-oVM\">\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"12089\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"EHf-IW-A2E\">\n            <objects>\n                <viewController id=\"01J-lp-oVM\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"Ydg-fD-yQy\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"xbc-2k-c8Z\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"Ze5-6b-2t3\">\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <imageView opaque=\"NO\" clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"center\" image=\"LaunchImage\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"YRO-k0-Ey4\">\n                            </imageView>\n                        </subviews>\n                        <color key=\"backgroundColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                        <constraints>\n                            <constraint firstItem=\"YRO-k0-Ey4\" firstAttribute=\"centerX\" secondItem=\"Ze5-6b-2t3\" secondAttribute=\"centerX\" id=\"1a2-6s-vTC\"/>\n                            <constraint firstItem=\"YRO-k0-Ey4\" firstAttribute=\"centerY\" secondItem=\"Ze5-6b-2t3\" secondAttribute=\"centerY\" id=\"4X2-HB-R7a\"/>\n                        </constraints>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"iYj-Kq-Ea1\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"53\" y=\"375\"/>\n        </scene>\n    </scenes>\n    <resources>\n        <image name=\"LaunchImage\" width=\"168\" height=\"185\"/>\n    </resources>\n</document>\n"
  },
  {
    "path": "flutter/todo_cubit/ios/Runner/Base.lproj/Main.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"10117\" systemVersion=\"15F34\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" initialViewController=\"BYZ-38-t0r\">\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"10085\"/>\n    </dependencies>\n    <scenes>\n        <!--Flutter View Controller-->\n        <scene sceneID=\"tne-QT-ifu\">\n            <objects>\n                <viewController id=\"BYZ-38-t0r\" customClass=\"FlutterViewController\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"y3c-jy-aDJ\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"wfy-db-euE\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"8bC-Xf-vdC\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"600\" height=\"600\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"calibratedWhite\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"dkx-z0-nzr\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "flutter/todo_cubit/ios/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>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>todo_cubit</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>CFBundleSignature</key>\n\t<string>????</string>\n\t<key>CFBundleVersion</key>\n\t<string>$(FLUTTER_BUILD_NUMBER)</string>\n\t<key>LSRequiresIPhoneOS</key>\n\t<true/>\n\t<key>UILaunchStoryboardName</key>\n\t<string>LaunchScreen</string>\n\t<key>UIMainStoryboardFile</key>\n\t<string>Main</string>\n\t<key>UISupportedInterfaceOrientations</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations~ipad</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationPortraitUpsideDown</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n\t<key>UIViewControllerBasedStatusBarAppearance</key>\n\t<false/>\n</dict>\n</plist>\n"
  },
  {
    "path": "flutter/todo_cubit/ios/Runner/Runner-Bridging-Header.h",
    "content": "#import \"GeneratedPluginRegistrant.h\"\n"
  },
  {
    "path": "flutter/todo_cubit/ios/Runner.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };\n\t\t3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };\n\t\t74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };\n\t\t97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };\n\t\t97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };\n\t\t97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXCopyFilesBuildPhase section */\n\t\t9705A1C41CF9048500538489 /* Embed Frameworks */ = {\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 = \"Embed Frameworks\";\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXCopyFilesBuildPhase section */\n\n/* Begin PBXFileReference section */\n\t\t1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = \"<group>\"; };\n\t\t1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = \"<group>\"; };\n\t\t3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = \"<group>\"; };\n\t\t74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = \"Runner-Bridging-Header.h\"; sourceTree = \"<group>\"; };\n\t\t74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = \"<group>\"; };\n\t\t7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = \"<group>\"; };\n\t\t9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = \"<group>\"; };\n\t\t9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = \"<group>\"; };\n\t\t97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = \"<group>\"; };\n\t\t97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = \"<group>\"; };\n\t\t97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = \"<group>\"; };\n\t\t97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t97C146EB1CF9000F007C117D /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t9740EEB11CF90186004384FC /* Flutter */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,\n\t\t\t\t9740EEB21CF90195004384FC /* Debug.xcconfig */,\n\t\t\t\t7AFA3C8E1D35360C0083082E /* Release.xcconfig */,\n\t\t\t\t9740EEB31CF90195004384FC /* Generated.xcconfig */,\n\t\t\t);\n\t\t\tname = Flutter;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t97C146E51CF9000F007C117D = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t9740EEB11CF90186004384FC /* Flutter */,\n\t\t\t\t97C146F01CF9000F007C117D /* Runner */,\n\t\t\t\t97C146EF1CF9000F007C117D /* Products */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t97C146EF1CF9000F007C117D /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t97C146EE1CF9000F007C117D /* Runner.app */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t97C146F01CF9000F007C117D /* Runner */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t97C146FA1CF9000F007C117D /* Main.storyboard */,\n\t\t\t\t97C146FD1CF9000F007C117D /* Assets.xcassets */,\n\t\t\t\t97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,\n\t\t\t\t97C147021CF9000F007C117D /* Info.plist */,\n\t\t\t\t1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,\n\t\t\t\t1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,\n\t\t\t\t74858FAE1ED2DC5600515810 /* AppDelegate.swift */,\n\t\t\t\t74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,\n\t\t\t);\n\t\t\tpath = Runner;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t97C146ED1CF9000F007C117D /* Runner */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget \"Runner\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t9740EEB61CF901F6004384FC /* Run Script */,\n\t\t\t\t97C146EA1CF9000F007C117D /* Sources */,\n\t\t\t\t97C146EB1CF9000F007C117D /* Frameworks */,\n\t\t\t\t97C146EC1CF9000F007C117D /* Resources */,\n\t\t\t\t9705A1C41CF9048500538489 /* Embed Frameworks */,\n\t\t\t\t3B06AD1E1E4923F5004D2608 /* Thin Binary */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = Runner;\n\t\t\tproductName = Runner;\n\t\t\tproductReference = 97C146EE1CF9000F007C117D /* Runner.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t97C146E61CF9000F007C117D /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastUpgradeCheck = 1020;\n\t\t\t\tORGANIZATIONNAME = \"\";\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t97C146ED1CF9000F007C117D = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 7.3.1;\n\t\t\t\t\t\tLastSwiftMigration = 1100;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject \"Runner\" */;\n\t\t\tcompatibilityVersion = \"Xcode 9.3\";\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 = 97C146E51CF9000F007C117D;\n\t\t\tproductRefGroup = 97C146EF1CF9000F007C117D /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t97C146ED1CF9000F007C117D /* Runner */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t97C146EC1CF9000F007C117D /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,\n\t\t\t\t3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,\n\t\t\t\t97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,\n\t\t\t\t97C146FC1CF9000F007C117D /* Main.storyboard 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\t3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {\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);\n\t\t\tname = \"Thin Binary\";\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"/bin/sh \\\"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\\\" embed_and_thin\";\n\t\t};\n\t\t9740EEB61CF901F6004384FC /* Run Script */ = {\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);\n\t\t\tname = \"Run Script\";\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"/bin/sh \\\"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\\\" build\";\n\t\t};\n/* End PBXShellScriptBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t97C146EA1CF9000F007C117D /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,\n\t\t\t\t1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXVariantGroup section */\n\t\t97C146FA1CF9000F007C117D /* Main.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t97C146FB1CF9000F007C117D /* Base */,\n\t\t\t);\n\t\t\tname = Main.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t97C147001CF9000F007C117D /* Base */,\n\t\t\t);\n\t\t\tname = LaunchScreen.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXVariantGroup section */\n\n/* Begin XCBuildConfiguration section */\n\t\t249021D3217E4FDB00AE95B9 /* Profile */ = {\n\t\t\tisa = XCBuildConfiguration;\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_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\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_COMMA = 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_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_IMPLICIT_RETAIN_SELF = 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_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\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 = gnu99;\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_UNDECLARED_SELECTOR = YES;\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\tIPHONEOS_DEPLOYMENT_TARGET = 9.0;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSUPPORTED_PLATFORMS = iphoneos;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Profile;\n\t\t};\n\t\t249021D4217E4FDB00AE95B9 /* Profile */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.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\tCURRENT_PROJECT_VERSION = \"$(FLUTTER_BUILD_NUMBER)\";\n\t\t\t\tENABLE_BITCODE = NO;\n\t\t\t\tINFOPLIST_FILE = Runner/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.example.todoCubit;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_OBJC_BRIDGING_HEADER = \"Runner/Runner-Bridging-Header.h\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tVERSIONING_SYSTEM = \"apple-generic\";\n\t\t\t};\n\t\t\tname = Profile;\n\t\t};\n\t\t97C147031CF9000F007C117D /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\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_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\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_COMMA = 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_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_IMPLICIT_RETAIN_SELF = 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_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\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 = gnu99;\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_UNDECLARED_SELECTOR = YES;\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\tIPHONEOS_DEPLOYMENT_TARGET = 9.0;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t97C147041CF9000F007C117D /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\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_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\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_COMMA = 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_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_IMPLICIT_RETAIN_SELF = 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_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\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 = gnu99;\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_UNDECLARED_SELECTOR = YES;\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\tIPHONEOS_DEPLOYMENT_TARGET = 9.0;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSUPPORTED_PLATFORMS = iphoneos;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Owholemodule\";\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t97C147061CF9000F007C117D /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.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\tCURRENT_PROJECT_VERSION = \"$(FLUTTER_BUILD_NUMBER)\";\n\t\t\t\tENABLE_BITCODE = NO;\n\t\t\t\tINFOPLIST_FILE = Runner/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.example.todoCubit;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_OBJC_BRIDGING_HEADER = \"Runner/Runner-Bridging-Header.h\";\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tVERSIONING_SYSTEM = \"apple-generic\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t97C147071CF9000F007C117D /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.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\tCURRENT_PROJECT_VERSION = \"$(FLUTTER_BUILD_NUMBER)\";\n\t\t\t\tENABLE_BITCODE = NO;\n\t\t\t\tINFOPLIST_FILE = Runner/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.example.todoCubit;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_OBJC_BRIDGING_HEADER = \"Runner/Runner-Bridging-Header.h\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tVERSIONING_SYSTEM = \"apple-generic\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t97C146E91CF9000F007C117D /* Build configuration list for PBXProject \"Runner\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t97C147031CF9000F007C117D /* Debug */,\n\t\t\t\t97C147041CF9000F007C117D /* Release */,\n\t\t\t\t249021D3217E4FDB00AE95B9 /* Profile */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget \"Runner\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t97C147061CF9000F007C117D /* Debug */,\n\t\t\t\t97C147071CF9000F007C117D /* Release */,\n\t\t\t\t249021D4217E4FDB00AE95B9 /* 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 = 97C146E61CF9000F007C117D /* Project object */;\n}\n"
  },
  {
    "path": "flutter/todo_cubit/ios/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:\">\n   </FileRef>\n</Workspace>\n"
  },
  {
    "path": "flutter/todo_cubit/ios/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": "flutter/todo_cubit/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings",
    "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>PreviewsEnabled</key>\n\t<false/>\n</dict>\n</plist>\n"
  },
  {
    "path": "flutter/todo_cubit/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1020\"\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 = \"97C146ED1CF9000F007C117D\"\n               BuildableName = \"Runner.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      </Testables>\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"97C146ED1CF9000F007C117D\"\n            BuildableName = \"Runner.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 = \"97C146ED1CF9000F007C117D\"\n            BuildableName = \"Runner.app\"\n            BlueprintName = \"Runner\"\n            ReferencedContainer = \"container:Runner.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Profile\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"97C146ED1CF9000F007C117D\"\n            BuildableName = \"Runner.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": "flutter/todo_cubit/ios/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</Workspace>\n"
  },
  {
    "path": "flutter/todo_cubit/ios/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": "flutter/todo_cubit/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings",
    "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>PreviewsEnabled</key>\n\t<false/>\n</dict>\n</plist>\n"
  },
  {
    "path": "flutter/todo_cubit/lib/blocs/cubit/filter_cubit.dart",
    "content": "import 'package:bloc/bloc.dart';\nimport 'package:plugin/generated/rid_api.dart';\n\nclass FilterCubit extends Cubit<Filter> {\n  final Store _store = Store.instance;\n  FilterCubit() : super(Store.instance.filter);\n\n  Future<void> setFilter(Filter filter) async {\n    await _store.msgSetFilter(filter);\n    emit(_store.filter);\n  }\n}\n"
  },
  {
    "path": "flutter/todo_cubit/lib/blocs/cubit/settings_cubit.dart",
    "content": "import 'package:bloc/bloc.dart';\nimport 'package:plugin/generated/rid_api.dart';\n\nclass SettingsCubit extends Cubit<Settings> {\n  final Store _store = Store.instance;\n  SettingsCubit() : super(Store.instance.settings);\n\n  Future<void> setAutoExpireCompleted(bool val) async {\n    await _store.msgSetAutoExpireCompletedTodos(val);\n    emit(_store.settings);\n  }\n}\n"
  },
  {
    "path": "flutter/todo_cubit/lib/blocs/cubit/todo_cubit.dart",
    "content": "import 'dart:async';\n\nimport 'package:bloc/bloc.dart';\nimport 'package:flutter/foundation.dart';\nimport 'package:meta/meta.dart';\nimport 'package:plugin/generated/rid_api.dart';\n\npart 'todo_state.dart';\n\nclass TodoCubit extends Cubit<TodoState> {\n  final Store _store = Store.instance;\n  late final StreamSubscription<PostedReply> tickSub;\n  TodoCubit(Todo todo) : super(ExistingTodo(todo)) {\n    _subscribe();\n  }\n\n  // Reply.Tick is a reply that includes data, in this case the id\n  // of the completed todo whose life is ticking away\n  bool _tickIsForThisTodo(PostedReply reply) {\n    // We make sure that the data is a parseable int id\n    assert(\n      reply.data != null,\n      'Reply.Tick should include data containing the id of the ticked todo',\n    );\n    final id = int.tryParse(reply.data!);\n    assert(id != null, 'Reply.Tick included invalid id ${reply.data}');\n    return id == state.id;\n  }\n\n  void _subscribe() {\n    tickSub = rid.replyChannel.stream\n        .where((x) => x.type == Reply.Tick && _tickIsForThisTodo(x))\n        .listen(_refreshState);\n  }\n\n  @override\n  Future<void> close() {\n    tickSub.cancel();\n    return super.close();\n  }\n\n  void _refreshState(PostedReply _reply) async {\n    final todo = _store.todoById(state.id);\n    if (todo == null) {\n      emit(MissingTodo(state.id));\n    } else {\n      emit(ExistingTodo(todo));\n    }\n  }\n\n  Future<void> toggleCompleted() =>\n      _store.msgToggleTodo(state.id).then(_refreshState);\n\n  Future<void> removeTodo(int id) =>\n      _store.msgRemoveTodo(id).then(_refreshState);\n}\n"
  },
  {
    "path": "flutter/todo_cubit/lib/blocs/cubit/todo_state.dart",
    "content": "part of 'todo_cubit.dart';\n\n@immutable\nabstract class TodoState {\n  final int id;\n\n  TodoState(this.id);\n\n  @override\n  bool operator ==(Object other) =>\n      identical(this, other) || other is TodoState && other.id == id;\n\n  @override\n  int get hashCode => id;\n}\n\nclass ExistingTodo extends TodoState {\n  final Todo todo;\n\n  ExistingTodo(this.todo) : super(todo.id);\n\n  @override\n  bool operator ==(Object other) =>\n      identical(this, other) || other is ExistingTodo && other.todo == todo;\n\n  @override\n  int get hashCode => todo.hashCode;\n}\n\nclass MissingTodo extends TodoState {\n  MissingTodo(int id) : super(id);\n\n  @override\n  bool operator ==(Object other) =>\n      identical(this, other) || other is MissingTodo && other.id == id;\n\n  @override\n  int get hashCode => super.hashCode;\n}\n"
  },
  {
    "path": "flutter/todo_cubit/lib/blocs/cubit/todos_cubit.dart",
    "content": "import 'dart:async';\n\nimport 'package:bloc/bloc.dart';\nimport 'package:flutter/foundation.dart';\nimport 'package:meta/meta.dart';\nimport 'package:plugin/generated/rid_api.dart';\n\npart 'todos_state.dart';\n\nclass TodosCubit extends Cubit<TodosState> {\n  late final StreamSubscription<PostedReply> removedTodosSub;\n  final Store _store = Store.instance;\n\n  TodosCubit() : super(TodosState(Store.instance.filteredTodos())) {\n    _subscribe();\n  }\n\n  void _subscribe() {\n    removedTodosSub = rid.replyChannel.stream\n        .where((x) =>\n            x.type == Reply.RemovedTodo ||\n            x.type == Reply.RemovedCompleted ||\n            x.type == Reply.CompletedTodoExpired ||\n            x.type == Reply.SetFilter)\n        .listen(_refreshList);\n  }\n\n  @override\n  Future<void> close() async {\n    await removedTodosSub.cancel();\n    return super.close();\n  }\n\n  void _refreshList(PostedReply _reply) async {\n    final todos = _store.filteredTodos();\n    emit(TodosState(todos));\n    debugPrint('${_store.raw.debug(true)}');\n  }\n\n  Future<void> addTodo(String title) =>\n      _store.msgAddTodo(title).then(_refreshList);\n\n  Future<void> restartAll() => _store.msgRestartAll().then(_refreshList);\n  Future<void> completeAll() => _store.msgCompleteAll().then(_refreshList);\n  Future<void> removeCompleted() =>\n      _store.msgRemoveCompleted().then(_refreshList);\n}\n"
  },
  {
    "path": "flutter/todo_cubit/lib/blocs/cubit/todos_state.dart",
    "content": "part of 'todos_cubit.dart';\n\n@immutable\nclass TodosState {\n  final List<Todo> todos;\n  const TodosState(this.todos);\n\n  @override\n  bool operator ==(Object other) =>\n      identical(this, other) || other is TodosState && other.todos == todos;\n\n  @override\n  int get hashCode => todos.hashCode;\n}\n"
  },
  {
    "path": "flutter/todo_cubit/lib/main.dart",
    "content": "import 'dart:async';\n\nimport 'package:flutter/material.dart';\nimport 'package:flutter_bloc/flutter_bloc.dart';\nimport 'package:plugin/generated/rid_api.dart';\nimport 'package:todo_cubit/blocs/cubit/filter_cubit.dart';\nimport 'package:todo_cubit/blocs/cubit/settings_cubit.dart';\nimport 'package:todo_cubit/blocs/cubit/todos_cubit.dart';\nimport 'package:todo_cubit/views/menu.dart';\nimport 'package:todo_cubit/views/todos.dart';\n\nconst Color FILTER_SELECTED_COLOR = Colors.blue;\nconst Color FILTER_UNSELECTED_COLOR = Colors.black;\n\nvoid configRid() {\n  rid.debugReply = (reply) => debugPrint('$reply');\n}\n\nvoid main() {\n  configRid();\n  runApp(TodoApp());\n}\n\nclass TodoApp extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return MaterialApp(\n      title: 'Rust/Flutter Cubit Todo App',\n      theme: ThemeData(\n        primarySwatch: Colors.blue,\n      ),\n      home: MultiBlocProvider(\n        providers: [\n          BlocProvider<SettingsCubit>(create: (_) => SettingsCubit()),\n          BlocProvider<TodosCubit>(create: (_) => TodosCubit()),\n          BlocProvider<FilterCubit>(create: (_) => FilterCubit())\n        ],\n        child: TodosPage(title: 'Cubit Todo App'),\n      ),\n      debugShowCheckedModeBanner: false,\n    );\n  }\n}\n\nclass TodosPage extends StatefulWidget {\n  final String title;\n  TodosPage({Key? key, required this.title}) : super(key: key);\n\n  @override\n  _TodosPageState createState() => _TodosPageState();\n}\n\nclass _TodosPageState extends State<TodosPage> {\n  final _textFieldController = TextEditingController();\n  String? addTodoTitle;\n\n  @override\n  Widget build(BuildContext context) {\n    final filter = context.watch<FilterCubit>().state;\n\n    return SafeArea(\n      child: Scaffold(\n        appBar: AppBar(\n          title: Row(\n            mainAxisAlignment: MainAxisAlignment.spaceBetween,\n            children: [\n              Text(widget.title),\n              Row(\n                children: [\n                  Image.asset(\n                    \"assets/dash.png\",\n                    height: 40.0,\n                    width: 40.0,\n                  ),\n                  Icon(Icons.favorite, color: Colors.red),\n                  Image.asset(\n                    \"assets/ferris.png\",\n                    height: 50.0,\n                    width: 50.0,\n                  ),\n                ],\n              )\n            ],\n          ),\n        ),\n        drawer: Drawer(child: Menu()),\n        bottomNavigationBar: BottomAppBar(\n          child: Row(\n            children: <Widget>[\n              IconButton(\n                  icon: Icon(\n                    Icons.calendar_today_rounded,\n                    color: filter == Filter.Pending\n                        ? FILTER_SELECTED_COLOR\n                        : FILTER_UNSELECTED_COLOR,\n                  ),\n                  onPressed: () =>\n                      context.read<FilterCubit>().setFilter(Filter.Pending)),\n              Spacer(),\n              IconButton(\n                  icon: Icon(\n                    Icons.check,\n                    color: filter == Filter.Completed\n                        ? FILTER_SELECTED_COLOR\n                        : FILTER_UNSELECTED_COLOR,\n                  ),\n                  onPressed: () =>\n                      context.read<FilterCubit>().setFilter(Filter.Completed)),\n              IconButton(\n                  icon: Icon(\n                    Icons.all_inclusive,\n                    color: filter == Filter.All\n                        ? FILTER_SELECTED_COLOR\n                        : FILTER_UNSELECTED_COLOR,\n                  ),\n                  onPressed: () =>\n                      context.read<FilterCubit>().setFilter(Filter.All)),\n            ],\n          ),\n        ),\n        body: TodosView(),\n        floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,\n        floatingActionButton: FloatingActionButton(\n          onPressed: () async {\n            _textFieldController.clear();\n            await _addTodoDialog(context);\n            final title = addTodoTitle;\n            if (title != null && title.trim().isNotEmpty) {\n              context.read<TodosCubit>().addTodo(title);\n            }\n          },\n          tooltip: 'Add Todo',\n          child: Icon(Icons.add),\n        ),\n      ),\n    );\n  }\n\n  Future<void> _addTodoDialog(BuildContext context) async {\n    return showDialog(\n        context: context,\n        builder: (context) {\n          return AlertDialog(\n            title: Text('Enter Todo Title'),\n            content: TextField(\n              controller: _textFieldController,\n              decoration: InputDecoration(hintText: \"Todo title\"),\n              autofocus: true,\n            ),\n            actions: <Widget>[\n              TextButton(\n                child: Text('Done'),\n                onPressed: () {\n                  addTodoTitle = _textFieldController.value.text;\n                  Navigator.pop(context);\n                },\n              ),\n            ],\n          );\n        });\n  }\n}\n"
  },
  {
    "path": "flutter/todo_cubit/lib/views/expiry.dart",
    "content": "import 'package:flutter/material.dart';\n\nColor expiryColor(double completedExpiryMillis, double remaining) {\n  return remaining > completedExpiryMillis * 0.80\n      ? Colors.greenAccent\n      : remaining > completedExpiryMillis * 0.60\n          ? Colors.green\n          : remaining > completedExpiryMillis * 0.4\n              ? Colors.orange\n              : remaining > completedExpiryMillis * 0.2\n                  ? Colors.redAccent\n                  : Colors.red;\n}\n\nclass ExpiryWidget extends StatelessWidget {\n  final double completedExpiryMillis;\n  final double remainingMillis;\n\n  const ExpiryWidget({\n    required this.completedExpiryMillis,\n    required this.remainingMillis,\n  }) : super();\n\n  Widget build(BuildContext context) {\n    final totalWidth = MediaQuery.of(context).size.width * 0.8;\n    final expiryWidth = (remainingMillis / completedExpiryMillis) * totalWidth;\n    return Container(\n      height: 10,\n      width: totalWidth,\n      decoration: BoxDecoration(\n        border: Border.all(\n          color: Colors.blueGrey,\n          width: 1.0,\n          style: BorderStyle.solid,\n        ),\n        borderRadius: BorderRadius.all(Radius.circular(2.0)),\n      ),\n      child: Container(\n        margin: EdgeInsets.only(right: totalWidth - expiryWidth),\n        color: expiryColor(completedExpiryMillis, remainingMillis),\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "flutter/todo_cubit/lib/views/menu.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:flutter/widgets.dart';\nimport 'package:flutter_bloc/flutter_bloc.dart';\nimport 'package:todo_cubit/blocs/cubit/settings_cubit.dart';\nimport 'package:todo_cubit/blocs/cubit/todos_cubit.dart';\n\nclass Menu extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return ListView(\n      padding: EdgeInsets.zero,\n      children: <Widget>[\n        ListTile(title: Text('Todo Actions')),\n        Divider(),\n        ListTile(\n          title: Text('Restart All'),\n          onTap: () => context.read<TodosCubit>().restartAll(),\n        ),\n        ListTile(\n          title: Text('Complete All'),\n          onTap: () => context.read<TodosCubit>().completeAll(),\n        ),\n        ListTile(\n          title: Text('Remove Completed'),\n          onTap: () => context.read<TodosCubit>().removeCompleted(),\n        ),\n        ListTile(\n          title: Row(\n            mainAxisAlignment: MainAxisAlignment.start,\n            children: [\n              Text('Expire Completed'),\n              AutoRemoveCompletedWidget(),\n            ],\n          ),\n        ),\n      ],\n    );\n  }\n}\n\nclass AutoRemoveCompletedWidget extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Checkbox(\n      value: context.select<SettingsCubit, bool>(\n        (x) => x.state.autoExpireCompletedTodos,\n      ),\n      onChanged: (val) {\n        if (val != null)\n          context.read<SettingsCubit>().setAutoExpireCompleted(val);\n      },\n    );\n  }\n}\n"
  },
  {
    "path": "flutter/todo_cubit/lib/views/todo.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:flutter_bloc/flutter_bloc.dart';\nimport 'package:plugin/generated/rid_api.dart';\nimport 'package:todo_cubit/blocs/cubit/settings_cubit.dart';\nimport 'package:todo_cubit/blocs/cubit/todo_cubit.dart';\nimport 'package:todo_cubit/views/expiry.dart';\n\nclass TodoView extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return BlocBuilder<TodoCubit, TodoState>(builder: (context, state) {\n      if (state is MissingTodo) {\n        return Text('Todo ${state.id} missing, most likely removed');\n      }\n      if (state is ExistingTodo) {\n        final todo = state.todo;\n        return Dismissible(\n          key: Key(\"Todo Dismissible ${todo.id}\"),\n          child: Card(\n            child: InkWell(\n              onTap: () => context.read<TodoCubit>().toggleCompleted(),\n              child: ListTile(\n                leading: todo.completed\n                    ? Icon(Icons.check, color: Colors.green)\n                    : Icon(Icons.calendar_today_rounded),\n                title: Text('${todo.title}'),\n                subtitle: BlocBuilder<SettingsCubit, Settings>(\n                  builder: (context, settings) {\n                    return settings.autoExpireCompletedTodos && todo.completed\n                        ? ExpiryWidget(\n                            completedExpiryMillis:\n                                settings.completedExpiryMillis.toDouble(),\n                            remainingMillis: todo.expiryMillis.toDouble(),\n                          )\n                        : Container();\n                  },\n                ),\n              ),\n            ),\n          ),\n          direction: DismissDirection.endToStart,\n          // Make sure we removed the Todo and got the reply before updating the UI\n          confirmDismiss: (_) =>\n              context.read<TodoCubit>().removeTodo(todo.id).then((_) => true),\n          background: Padding(\n            padding: EdgeInsets.all(5.0),\n            child: Container(color: Colors.red),\n          ),\n        );\n      } else {\n        return Text('Unkown TodoState type $state');\n      }\n    });\n  }\n}\n"
  },
  {
    "path": "flutter/todo_cubit/lib/views/todos.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:todo_cubit/blocs/cubit/todo_cubit.dart';\nimport 'package:todo_cubit/blocs/cubit/todos_cubit.dart';\nimport 'package:todo_cubit/views/todo.dart';\nimport 'package:flutter_bloc/flutter_bloc.dart';\n\nclass TodosView extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Center(\n      child: BlocBuilder<TodosCubit, TodosState>(builder: (context, state) {\n        final todos = state.todos;\n        return ListView.builder(\n            itemCount: todos.length,\n            itemBuilder: (context, index) {\n              final todo = todos[index];\n              return BlocProvider(\n                create: (_) => TodoCubit(todo),\n                child: TodoView(),\n                key: Key(todo.hashCode.toString()),\n              );\n            });\n      }),\n    );\n  }\n}\n"
  },
  {
    "path": "flutter/todo_cubit/linux/.gitignore",
    "content": "flutter/ephemeral\n"
  },
  {
    "path": "flutter/todo_cubit/linux/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.10)\nproject(runner LANGUAGES CXX)\n\nset(BINARY_NAME \"todo_cubit\")\nset(APPLICATION_ID \"com.example.todo_cubit\")\n\ncmake_policy(SET CMP0063 NEW)\n\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# Configure build 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.\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\nset(FLUTTER_MANAGED_DIR \"${CMAKE_CURRENT_SOURCE_DIR}/flutter\")\n\n# Flutter library and tool build rules.\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# Application build\nadd_executable(${BINARY_NAME}\n  \"main.cc\"\n  \"my_application.cc\"\n  \"${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc\"\n)\napply_standard_settings(${BINARY_NAME})\ntarget_link_libraries(${BINARY_NAME} PRIVATE flutter)\ntarget_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK)\nadd_dependencies(${BINARY_NAME} flutter_assemble)\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\nif(PLUGIN_BUNDLED_LIBRARIES)\n  install(FILES \"${PLUGIN_BUNDLED_LIBRARIES}\"\n    DESTINATION \"${INSTALL_BUNDLE_LIB_DIR}\"\n    COMPONENT Runtime)\nendif()\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": "flutter/todo_cubit/linux/flutter/CMakeLists.txt",
    "content": "cmake_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": "flutter/todo_cubit/linux/flutter/generated_plugin_registrant.cc",
    "content": "//\n//  Generated file. Do not edit.\n//\n\n#include \"generated_plugin_registrant.h\"\n\n\nvoid fl_register_plugins(FlPluginRegistry* registry) {\n}\n"
  },
  {
    "path": "flutter/todo_cubit/linux/flutter/generated_plugin_registrant.h",
    "content": "//\n//  Generated file. Do not edit.\n//\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": "flutter/todo_cubit/linux/flutter/generated_plugins.cmake",
    "content": "#\n# Generated file, do not edit.\n#\n\nlist(APPEND FLUTTER_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"
  },
  {
    "path": "flutter/todo_cubit/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": "flutter/todo_cubit/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, \"todo_cubit\");\n    gtk_header_bar_set_show_close_button(header_bar, TRUE);\n    gtk_window_set_titlebar(window, GTK_WIDGET(header_bar));\n  }\n  else {\n    gtk_window_set_title(window, \"todo_cubit\");\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": "flutter/todo_cubit/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": "flutter/todo_cubit/macos/.gitignore",
    "content": "# Flutter-related\n**/Flutter/ephemeral/\n**/Pods/\n\n# Xcode-related\n**/xcuserdata/\n"
  },
  {
    "path": "flutter/todo_cubit/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": "flutter/todo_cubit/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": "flutter/todo_cubit/macos/Flutter/GeneratedPluginRegistrant.swift",
    "content": "//\n//  Generated file. Do not edit.\n//\n\nimport FlutterMacOS\nimport Foundation\n\nimport plugin\n\nfunc RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {\n  Plugin.register(with: registry.registrar(forPlugin: \"Plugin\"))\n}\n"
  },
  {
    "path": "flutter/todo_cubit/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": "flutter/todo_cubit/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": "flutter/todo_cubit/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": "flutter/todo_cubit/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            </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": "flutter/todo_cubit/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 = todo_cubit\n\n// The application's bundle identifier\nPRODUCT_BUNDLE_IDENTIFIER = com.example.todoCubit\n\n// The copyright displayed in application information\nPRODUCT_COPYRIGHT = Copyright © 2021 com.example. All rights reserved.\n"
  },
  {
    "path": "flutter/todo_cubit/macos/Runner/Configs/Debug.xcconfig",
    "content": "#include \"../../Flutter/Flutter-Debug.xcconfig\"\n#include \"Warnings.xcconfig\"\n"
  },
  {
    "path": "flutter/todo_cubit/macos/Runner/Configs/Release.xcconfig",
    "content": "#include \"../../Flutter/Flutter-Release.xcconfig\"\n#include \"Warnings.xcconfig\"\n"
  },
  {
    "path": "flutter/todo_cubit/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": "flutter/todo_cubit/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.server</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "flutter/todo_cubit/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": "flutter/todo_cubit/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": "flutter/todo_cubit/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": "flutter/todo_cubit/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\t7CC513913857B230490BB8FC /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FE832B76C3274791B6E1CF37 /* 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\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 /* todo_cubit.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = todo_cubit.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\t7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = \"<group>\"; };\n\t\t8F9D38D36A436B4B23027013 /* 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\t\t901C4FCA7B7F499425F18AE0 /* 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\t9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = \"<group>\"; };\n\t\tD4AD4E5E6EDB6DEA300EA746 /* 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\tFE832B76C3274791B6E1CF37 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };\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\t7CC513913857B230490BB8FC /* 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\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\tA4F61188EAFD80961AEC2007 /* 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 /* todo_cubit.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\tA4F61188EAFD80961AEC2007 /* Pods */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tD4AD4E5E6EDB6DEA300EA746 /* Pods-Runner.debug.xcconfig */,\n\t\t\t\t8F9D38D36A436B4B23027013 /* Pods-Runner.release.xcconfig */,\n\t\t\t\t901C4FCA7B7F499425F18AE0 /* 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\tD73912EC22F37F3D000D13A0 /* Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tFE832B76C3274791B6E1CF37 /* 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\t233F5DA7F94578156A27D962 /* [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);\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 /* todo_cubit.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 = \"\";\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 9.3\";\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\t233F5DA7F94578156A27D962 /* [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\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 && touch Flutter/ephemeral/tripwire\";\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\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\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\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\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\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\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": "flutter/todo_cubit/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": "flutter/todo_cubit/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 = \"todo_cubit.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      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"33CC10EC2044A3C60003C045\"\n            BuildableName = \"todo_cubit.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 = \"todo_cubit.app\"\n            BlueprintName = \"Runner\"\n            ReferencedContainer = \"container:Runner.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Profile\"\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 = \"todo_cubit.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": "flutter/todo_cubit/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": "flutter/todo_cubit/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": "flutter/todo_cubit/plugin/.gitignore",
    "content": ".DS_Store\n.dart_tool/\n\n.packages\n.pub/\n\nbuild/\n"
  },
  {
    "path": "flutter/todo_cubit/plugin/LICENSE",
    "content": "TODO: Add your license here.\n"
  },
  {
    "path": "flutter/todo_cubit/plugin/analysis_options.yaml",
    "content": "include: package:flutter_lints/flutter.yaml\n\n# Additional information about this file can be found at\n# https://dart.dev/guides/language/analysis-options\n"
  },
  {
    "path": "flutter/todo_cubit/plugin/android/.gitignore",
    "content": "*.iml\n.gradle\n/local.properties\n/.idea/workspace.xml\n/.idea/libraries\n.DS_Store\n/build\n/captures\n"
  },
  {
    "path": "flutter/todo_cubit/plugin/android/build.gradle",
    "content": "group 'com.example.plugin'\nversion '1.0-SNAPSHOT'\n\nbuildscript {\n    ext.kotlin_version = '1.3.50'\n    repositories {\n        google()\n        mavenCentral()\n    }\n\n    dependencies {\n        classpath 'com.android.tools.build:gradle:4.1.0'\n        classpath \"org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version\"\n    }\n}\n\nrootProject.allprojects {\n    repositories {\n        google()\n        mavenCentral()\n    }\n}\n\napply plugin: 'com.android.library'\napply plugin: 'kotlin-android'\n\nandroid {\n    compileSdkVersion 30\n\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n\n    kotlinOptions {\n        jvmTarget = '1.8'\n    }\n\n    sourceSets {\n        main.java.srcDirs += 'src/main/kotlin'\n    }\n\n    defaultConfig {\n        minSdkVersion 16\n    }\n}\n\ndependencies {\n    implementation \"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version\"\n}\n"
  },
  {
    "path": "flutter/todo_cubit/plugin/android/gradle/wrapper/gradle-wrapper.properties",
    "content": "distributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-6.7-all.zip\n"
  },
  {
    "path": "flutter/todo_cubit/plugin/android/gradle.properties",
    "content": "org.gradle.jvmargs=-Xmx1536M\nandroid.useAndroidX=true\nandroid.enableJetifier=true\n"
  },
  {
    "path": "flutter/todo_cubit/plugin/android/settings.gradle",
    "content": "rootProject.name = 'plugin'\n"
  },
  {
    "path": "flutter/todo_cubit/plugin/android/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n  package=\"com.example.plugin\">\n</manifest>\n"
  },
  {
    "path": "flutter/todo_cubit/plugin/android/src/main/kotlin/com/example/plugin/Plugin.kt",
    "content": "package com.example.plugin\n\nimport androidx.annotation.NonNull\n\nimport io.flutter.embedding.engine.plugins.FlutterPlugin\nimport io.flutter.plugin.common.MethodCall\nimport io.flutter.plugin.common.MethodChannel\nimport io.flutter.plugin.common.MethodChannel.MethodCallHandler\nimport io.flutter.plugin.common.MethodChannel.Result\n\n/** Plugin */\nclass Plugin: FlutterPlugin, MethodCallHandler {\n  /// The MethodChannel that will the communication between Flutter and native Android\n  ///\n  /// This local reference serves to register the plugin with the Flutter Engine and unregister it\n  /// when the Flutter Engine is detached from the Activity\n  private lateinit var channel : MethodChannel\n\n  override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {\n    channel = MethodChannel(flutterPluginBinding.binaryMessenger, \"plugin\")\n    channel.setMethodCallHandler(this)\n  }\n\n  override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {\n    if (call.method == \"getPlatformVersion\") {\n      result.success(\"Android ${android.os.Build.VERSION.RELEASE}\")\n    } else {\n      result.notImplemented()\n    }\n  }\n\n  override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {\n    channel.setMethodCallHandler(null)\n  }\n}\n"
  },
  {
    "path": "flutter/todo_cubit/plugin/ios/.gitignore",
    "content": ".idea/\n.vagrant/\n.sconsign.dblite\n.svn/\n\n.DS_Store\n*.swp\nprofile\n\nDerivedData/\nbuild/\nGeneratedPluginRegistrant.h\nGeneratedPluginRegistrant.m\n\n.generated/\n\n*.pbxuser\n*.mode1v3\n*.mode2v3\n*.perspectivev3\n\n!default.pbxuser\n!default.mode1v3\n!default.mode2v3\n!default.perspectivev3\n\nxcuserdata\n\n*.moved-aside\n\n*.pyc\n*sync/\nIcon?\n.tags*\n\n/Flutter/Generated.xcconfig\n/Flutter/ephemeral/\n/Flutter/flutter_export_environment.sh"
  },
  {
    "path": "flutter/todo_cubit/plugin/ios/Assets/.gitkeep",
    "content": ""
  },
  {
    "path": "flutter/todo_cubit/plugin/ios/Classes/Plugin.h",
    "content": "#import <Flutter/Flutter.h>\n\n@interface Plugin : NSObject<FlutterPlugin>\n@end\n"
  },
  {
    "path": "flutter/todo_cubit/plugin/ios/Classes/Plugin.m",
    "content": "#import \"Plugin.h\"\n#if __has_include(<plugin/plugin-Swift.h>)\n#import <plugin/plugin-Swift.h>\n#else\n// Support project import fallback if the generated compatibility header\n// is not copied when this plugin is created as a library.\n// https://forums.swift.org/t/swift-static-libraries-dont-copy-generated-objective-c-header/19816\n#import \"plugin-Swift.h\"\n#endif\n\n@implementation Plugin\n+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {\n  [SwiftPlugin registerWithRegistrar:registrar];\n}\n@end\n"
  },
  {
    "path": "flutter/todo_cubit/plugin/ios/Classes/SwiftPlugin.swift",
    "content": "import Flutter\nimport UIKit\n\npublic class SwiftPlugin: NSObject, FlutterPlugin {\n  public static func register(with registrar: FlutterPluginRegistrar) {\n  }\n\n  public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {\n    result(nil)\n  }\n}\n// <rid:prevent_tree_shake Start>\nfunc dummyCallsToPreventTreeShaking() {\n    _export_dart_enum_Filter();\n    _to_dart_for_Store();\n    rid_store_debug(nil);\n    rid_store_debug_pretty(nil);\n    create_store();\n    rid_store_unlock();\n    rid_store_free();\n    __include_dart_for_vec_todo();\n    rid_store_last_added_id(nil);\n    rid_store_todos(nil);\n    rid_store_filter(nil);\n    rid_store_settings(nil);\n    rid_len_vec_todo(nil);\n    rid_get_item_vec_todo(nil, 0);\n    _include_Store_field_wrappers();\n    rid_cstring_free(nil);\n    rid_init_msg_isolate(0);\n    rid_init_reply_isolate(0);\n    rid_export_Store_filtered_todos(nil);\n    rid_export_Store_todo_by_id(nil, 0);\n    __include_dart_for_ridvec_todo();\n    rid_free_ridvec_todo(RidVec_Pointer_Todo());\n    rid_get_item_ridvec_todo(RidVec_Pointer_Todo(), 0);\n    _to_dart_for_Settings();\n    rid_settings_debug(nil);\n    rid_settings_debug_pretty(nil);\n    rid_settings_auto_expire_completed_todos(nil);\n    rid_settings_completed_expiry_millis(nil);\n    _to_dart_for_Todo();\n    rid_todo_debug(nil);\n    rid_todo_debug_pretty(nil);\n    rid_todo_id(nil);\n    rid_todo_title(nil);\n    rid_todo_title_len(nil);\n    rid_todo_completed(nil);\n    rid_todo_expiry_millis(nil);\n    rid_filter_debug(0);\n    rid_filter_debug_pretty(0);\n    rid_msg_AddTodo(0, nil);\n    rid_msg_RemoveTodo(0, 0);\n    rid_msg_RemoveCompleted(0);\n    rid_msg_CompleteTodo(0, 0);\n    rid_msg_RestartTodo(0, 0);\n    rid_msg_ToggleTodo(0, 0);\n    rid_msg_CompleteAll(0);\n    rid_msg_RestartAll(0);\n    rid_msg_SetFilter(0, Filter(rawValue: 0));\n    rid_msg_SetAutoExpireCompletedTodos(0, 0);\n}\n// <rid:prevent_tree_shake End>"
  },
  {
    "path": "flutter/todo_cubit/plugin/ios/plugin.podspec",
    "content": "#\n# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html.\n# Run `pod lib lint plugin.podspec` to validate before publishing.\n#\nPod::Spec.new do |s|\n  s.name             = 'plugin'\n  s.version          = '0.0.1'\n  s.summary          = 'Rust bridge.'\n  s.description      = <<-DESC\nA flutter Rust bridge project.\n                       DESC\n  s.homepage         = 'http://example.com'\n  s.license          = { :file => '../LICENSE' }\n  s.author           = { 'Your Company' => 'email@example.com' }\n  s.source           = { :path => '.' }\n\n  s.source_files = 'Classes/**/*'\n  s.dependency 'Flutter'\n  s.platform = :ios, '8.0'\n\n  # Flutter.framework does not contain a i386 slice.\n  s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' }\n  s.swift_version = '5.0'\n\n  s.public_header_files = 'Classes**/*.h'\n  s.static_framework = true\n  s.vendored_libraries = '**/*.a'\nend\n"
  },
  {
    "path": "flutter/todo_cubit/plugin/macos/Classes/Plugin.swift",
    "content": "import Cocoa\nimport FlutterMacOS\n\npublic class Plugin: NSObject, FlutterPlugin {\n  public static func register(with registrar: FlutterPluginRegistrar) {\n  }\n\n  public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {\n    result(nil)\n  }\n}\n// <rid:prevent_tree_shake Start>\nfunc dummyCallsToPreventTreeShaking() {\n    _export_dart_enum_Filter();\n    _to_dart_for_Store();\n    rid_store_debug(nil);\n    rid_store_debug_pretty(nil);\n    create_store();\n    rid_store_unlock();\n    rid_store_free();\n    __include_dart_for_vec_todo();\n    rid_store_last_added_id(nil);\n    rid_store_todos(nil);\n    rid_store_filter(nil);\n    rid_store_settings(nil);\n    rid_len_vec_todo(nil);\n    rid_get_item_vec_todo(nil, 0);\n    _include_Store_field_wrappers();\n    rid_cstring_free(nil);\n    rid_init_msg_isolate(0);\n    rid_init_reply_isolate(0);\n    rid_export_Store_filtered_todos(nil);\n    rid_export_Store_todo_by_id(nil, 0);\n    __include_dart_for_ridvec_todo();\n    rid_free_ridvec_todo(RidVec_Pointer_Todo());\n    rid_get_item_ridvec_todo(RidVec_Pointer_Todo(), 0);\n    _to_dart_for_Settings();\n    rid_settings_debug(nil);\n    rid_settings_debug_pretty(nil);\n    rid_settings_auto_expire_completed_todos(nil);\n    rid_settings_completed_expiry_millis(nil);\n    _to_dart_for_Todo();\n    rid_todo_debug(nil);\n    rid_todo_debug_pretty(nil);\n    rid_todo_id(nil);\n    rid_todo_title(nil);\n    rid_todo_title_len(nil);\n    rid_todo_completed(nil);\n    rid_todo_expiry_millis(nil);\n    rid_filter_debug(0);\n    rid_filter_debug_pretty(0);\n    rid_msg_AddTodo(0, nil);\n    rid_msg_RemoveTodo(0, 0);\n    rid_msg_RemoveCompleted(0);\n    rid_msg_CompleteTodo(0, 0);\n    rid_msg_RestartTodo(0, 0);\n    rid_msg_ToggleTodo(0, 0);\n    rid_msg_CompleteAll(0);\n    rid_msg_RestartAll(0);\n    rid_msg_SetFilter(0, Filter(rawValue: 0));\n    rid_msg_SetAutoExpireCompletedTodos(0, 0);\n}\n// <rid:prevent_tree_shake End>"
  },
  {
    "path": "flutter/todo_cubit/plugin/macos/plugin.podspec",
    "content": "#\n# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html.\n# Run `pod lib lint plugin.podspec` to validate before publishing.\n#\nPod::Spec.new do |s|\n  s.name             = 'plugin'\n  s.version          = '0.0.1'\n  s.summary          = 'Rust bridge.'\n  s.description      = <<-DESC\nA flutter Rust bridge project.\n                       DESC\n  s.homepage         = 'http://example.com'\n  s.license          = { :file => '../LICENSE' }\n  s.author           = { 'Your Company' => 'email@example.com' }\n  s.source           = { :path => '.' }\n  s.source_files     = 'Classes/**/*'\n  s.dependency 'FlutterMacOS'\n\n  s.platform = :osx, '10.11'\n  s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES' }\n  s.swift_version = '5.0'\n\n  s.public_header_files = 'Classes**/*.h'\n  s.static_framework = true\n  s.vendored_libraries = '**/*.a'\nend\n"
  },
  {
    "path": "flutter/todo_cubit/plugin/plugin.iml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<module type=\"JAVA_MODULE\" version=\"4\">\n  <component name=\"NewModuleRootManager\" inherit-compiler-output=\"true\">\n    <exclude-output />\n    <content url=\"file://$MODULE_DIR$\">\n      <sourceFolder url=\"file://$MODULE_DIR$/lib\" isTestSource=\"false\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/.dart_tool\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/.idea\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/.pub\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/example/.pub\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/example/build\" />\n    </content>\n    <orderEntry type=\"sourceFolder\" forTests=\"false\" />\n    <orderEntry type=\"library\" name=\"Dart Packages\" level=\"project\" />\n    <orderEntry type=\"library\" name=\"Dart SDK\" level=\"project\" />\n    <orderEntry type=\"library\" name=\"Flutter Plugins\" level=\"project\" />\n  </component>\n</module>"
  },
  {
    "path": "flutter/todo_cubit/plugin/pubspec.yaml",
    "content": "name: plugin\ndescription: Plugin to provide a bridge to Rust.\nversion: 0.0.1\n\nenvironment:\n  sdk: \">=2.13.0 <3.0.0\"\n  flutter: \">=2.0.0\"\n\ndependencies: \n  ffi: ^1.0.0\n  ffigen: 4.0.0-dev.2\n\n  flutter:\n    sdk: flutter\n\nflutter:\n  # This section identifies this Flutter project as a plugin project.\n  # The 'pluginClass' and Android 'package' identifiers should not ordinarily\n  # be modified. They are used by the tooling to maintain consistency when\n  # adding or updating assets for this project.\n  plugin:\n    platforms:\n      android:\n        package: com.example.plugin\n        pluginClass: Plugin\n      ios:\n        pluginClass: Plugin\n      macos:\n        pluginClass: Plugin\n"
  },
  {
    "path": "flutter/todo_cubit/pubspec.yaml",
    "content": "name: todo_cubit\ndescription: A new Flutter project.\n\npublish_to: 'none' # Remove this line if you wish to publish to pub.dev\n\nversion: 1.0.0+1\n\nenvironment:\n  sdk: \">=2.13.0 <3.0.0\"\n\ndependencies:\n  flutter:\n    sdk: flutter\n\n  plugin:\n    path: plugin\n\n  cupertino_icons: ^1.0.2\n  bloc: ^7.0.0\n  flutter_bloc: ^7.0.1\n  provider: ^5.0.0\n\ndev_dependencies:\n  flutter_test:\n    sdk: flutter\n\nflutter:\n\n  uses-material-design: true\n\n  assets:\n    - assets/dash.png\n    - assets/ferris.png\n"
  },
  {
    "path": "flutter/todo_cubit/rid_build.rs",
    "content": "use rid_build::{build, BuildConfig, BuildTarget, FlutterConfig, FlutterPlatform, Project};\nuse std::env;\n\nfn main() {\n    let crate_dir = env::var(\"CARGO_MANIFEST_DIR\")\n        .expect(\"Missing CARGO_MANIFEST_DIR, please run this via 'cargo run'\");\n\n    let workspace_dir = &crate_dir;\n\n    let crate_name = &env::var(\"CARGO_PKG_NAME\")\n        .expect(\"Missing CARGO_PKG_NAME, please run this via 'cargo run'\");\n    let lib_name = &format!(\"lib{}\", &crate_name);\n\n    let build_config = BuildConfig {\n        target: BuildTarget::Debug,\n        project: Project::Flutter(FlutterConfig {\n            plugin_name: \"plugin\".to_string(),\n            platforms: vec![\n                FlutterPlatform::ios(),\n                FlutterPlatform::macos(),\n                FlutterPlatform::android(),\n            ],\n        }),\n        lib_name,\n        crate_name,\n        project_root: &crate_dir,\n        workspace_root: Some(&workspace_dir),\n    };\n    build(&build_config).expect(\"Build failed\");\n}\n"
  },
  {
    "path": "flutter/todo_cubit/sh/android",
    "content": "#!/usr/bin/env bash\n\nDIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" >/dev/null 2>&1 && pwd )\"\n\nANDROID_PLATFORM_VERSION=28\n# x86 (i686)\nANDROID_BUILD_TARGET=i686-linux-android\n\n# x86_64\n# ANDROID_BUILD_TARGET=x86_64-linux-android\n\n# arm64\n# ANDROID_BUILD_TARGET=arm64-v8a\n\n# armeabi\n# ANDROID_BUILD_TARGET=armeabi-v7a\n\nANDROID_DIR=$DIR/../plugin/android\nJNI_LIBS_DIR=$ANDROID_DIR/src/main/jniLibs\n\n# Install Android NDK https://developer.android.com/studio/projects/install-ndk\n# https://github.com/bbqsrc/cargo-ndk\ncargo ndk                              \\\n  --platform $ANDROID_PLATFORM_VERSION \\\n  --target $ANDROID_BUILD_TARGET       \\\n  --output-dir $JNI_LIBS_DIR           \\\n  build\n"
  },
  {
    "path": "flutter/todo_cubit/sh/android-emulator",
    "content": "#!/usr/bin/env bash\n\nDIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" >/dev/null 2>&1 && pwd )\"\n\nANDROID_PLATFORM_VERSION=28\n# x86 (i686)\nANDROID_BUILD_TARGET=i686-linux-android\n\n# x86_64\n# ANDROID_BUILD_TARGET=x86_64-linux-android\n\n# arm64\n# ANDROID_BUILD_TARGET=arm64-v8a\n\n# armeabi\n# ANDROID_BUILD_TARGET=armeabi-v7a\n\nANDROID_DIR=$DIR/../plugin/android\nJNI_LIBS_DIR=$ANDROID_DIR/src/main/jniLibs\n\n# Install Android NDK https://developer.android.com/studio/projects/install-ndk\n# https://github.com/bbqsrc/cargo-ndk\ncargo ndk                              \\\n  --platform $ANDROID_PLATFORM_VERSION \\\n  --target $ANDROID_BUILD_TARGET       \\\n  --output-dir $JNI_LIBS_DIR           \\\n  build\n"
  },
  {
    "path": "flutter/todo_cubit/sh/bindgen",
    "content": "#!/usr/bin/env bash\n\nDIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" >/dev/null 2>&1 && pwd )\"\n\ncd $DIR/.. && cargo run rid_build\n"
  },
  {
    "path": "flutter/todo_cubit/sh/clean",
    "content": "#!/usr/bin/env bash\n\nDIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" >/dev/null 2>&1 && pwd )\"\n\n(cd $DIR/../plugin && flutter clean && flutter pub get)\n(cd $DIR/.. && flutter clean && flutter pub get)\n"
  },
  {
    "path": "flutter/todo_cubit/sh/ios",
    "content": "#!/usr/bin/env bash\n\nDIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" >/dev/null 2>&1 && pwd )\"\n\nIOS_TARGETS=x86_64-apple-ios\n\n# Alternative not using jq\n# WORKSPACE_CARGO_TOML=`cargo locate-project --workspace --message-format plain`\n# WORKSPACE_ROOT=$(dirname \"${WORKSPACE_CARGO_TOML}\")\n# TARGET_DIR=$WORKSPACE_ROOT/target\n\nTARGET_DIR=`cargo metadata --format-version 1 --no-deps | jq \".target_directory\" | xargs echo`\nPROJECT_NAME=`cargo metadata --format-version 1 | jq \".resolve.root\" | xargs echo | cut -d ' ' -f1`\nLIB_NAME=lib$PROJECT_NAME.a\n\n# <root>/target/universal/debug\nUNIVERSAL_DEBUG_DIR=\"$TARGET_DIR/universal/debug\"\nFLUTTER_IOS_DIR=\"$DIR/../plugin/ios\"\n\nLIB_SOURCE_FILE=\"$UNIVERSAL_DEBUG_DIR/$LIB_NAME\"\nLIB_TARGET_FILE=\"$FLUTTER_IOS_DIR/$LIB_NAME\"\n\ncargo lipo \\\n  --targets $IOS_TARGETS\n\ncp $LIB_SOURCE_FILE $LIB_TARGET_FILE\n"
  },
  {
    "path": "flutter/todo_cubit/sh/linux",
    "content": "#!/usr/bin/env bash\n\nDIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" >/dev/null 2>&1 && pwd )\"\n\nTARGET_DIR=`cargo metadata --format-version 1 --no-deps | jq \".target_directory\" | xargs echo`\nPROJECT_NAME=`cargo metadata --format-version 1 | jq \".resolve.root\" | xargs echo | cut -d ' ' -f1`\nLIB_NAME_STATIC=lib$PROJECT_NAME.a\nLIB_NAME_DYNAMIC=lib$PROJECT_NAME.so\n\n# <root>/target/universal/debug\nUNIVERSAL_DEBUG_DIR=\"$TARGET_DIR/debug\"\nFLUTTER_LINUX_DIR=\"$DIR/../plugin/linux\"\n\nmkdir -p $FLUTTER_LINUX_DIR\n\nLIB_SOURCE_FILE_STATIC=\"$UNIVERSAL_DEBUG_DIR/$LIB_NAME_STATIC\"\nLIB_SOURCE_FILE_DYNAMIC=\"$UNIVERSAL_DEBUG_DIR/$LIB_NAME_DYNAMIC\"\nLIB_TARGET_FILE_STATIC=\"$FLUTTER_LINUX_DIR/$LIB_NAME_STATIC\"\nLIB_TARGET_FILE_DYNAMIC=\"$FLUTTER_LINUX_DIR/$LIB_NAME_DYNAMIC\"\n\ncargo build && cp $LIB_SOURCE_FILE_STATIC $LIB_TARGET_FILE_STATIC && cp $LIB_SOURCE_FILE_DYNAMIC $LIB_TARGET_FILE_DYNAMIC\n\nexit $?\n"
  },
  {
    "path": "flutter/todo_cubit/sh/macos",
    "content": "#!/usr/bin/env bash\n\nDIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" >/dev/null 2>&1 && pwd )\"\n\nMACOS_TARGETS=aarch64-apple-ios\n\nTARGET_DIR=`cargo metadata --format-version 1 --no-deps | jq \".target_directory\" | xargs echo`\nPROJECT_NAME=`cargo metadata --format-version 1 | jq \".resolve.root\" | xargs echo | cut -d ' ' -f1`\nLIB_NAME=lib$PROJECT_NAME.a\n\n# <root>/target/universal/debug\nUNIVERSAL_DEBUG_DIR=\"$TARGET_DIR/debug\"\nFLUTTER_MACOS_DIR=\"$DIR/../plugin/macos\"\n\nLIB_SOURCE_FILE=\"$UNIVERSAL_DEBUG_DIR/$LIB_NAME\"\nLIB_TARGET_FILE=\"$FLUTTER_MACOS_DIR/$LIB_NAME\"\n\ncargo build\n\ncp $LIB_SOURCE_FILE $LIB_TARGET_FILE\n"
  },
  {
    "path": "flutter/todo_cubit/src/lib.rs",
    "content": "use core::time;\nuse std::{\n    sync::{RwLockReadGuard, RwLockWriteGuard},\n    thread,\n};\n\nuse rid::RidStore;\n\nconst COMPLETED_EXPIRY_MILLIS: u64 = 7000;\nconst EXPIRY_STEP: u64 = 10;\n\n// -----------------\n// Store\n// -----------------\n#[rid::store]\n#[rid::structs(Todo, Settings)]\n#[rid::enums(Filter)]\n#[derive(Debug)]\npub struct Store {\n    last_added_id: u32,\n    todos: Vec<Todo>,\n    filter: Filter,\n    settings: Settings,\n}\n\nimpl RidStore<Msg> for Store {\n    fn create() -> Self {\n        let first_todo = Todo {\n            id: 0,\n            title: \"Learn Flutter\".to_string(),\n            completed: true,\n            expiry_millis: COMPLETED_EXPIRY_MILLIS,\n        };\n        let second_todo = Todo {\n            id: 1,\n            title: \"Learn Rust\".to_string(),\n            completed: true,\n            expiry_millis: COMPLETED_EXPIRY_MILLIS,\n        };\n        let third_todo = Todo {\n            id: 2,\n            title: \"Learn Rid\".to_string(),\n            completed: false,\n            expiry_millis: COMPLETED_EXPIRY_MILLIS,\n        };\n        let fourth_todo = Todo {\n            id: 3,\n            title: \"Build Awesome Apps\".to_string(),\n            completed: false,\n            expiry_millis: COMPLETED_EXPIRY_MILLIS,\n        };\n        Self {\n            last_added_id: 3,\n            todos: vec![first_todo, second_todo, third_todo, fourth_todo],\n            filter: Filter::All,\n            settings: Settings {\n                auto_expire_completed_todos: false,\n                completed_expiry_millis: COMPLETED_EXPIRY_MILLIS,\n            },\n        }\n    }\n\n    fn update(&mut self, req_id: u64, msg: Msg) {\n        use Msg::*;\n        match msg {\n            AddTodo(title) => {\n                self.last_added_id += 1;\n                let todo = Todo {\n                    id: self.last_added_id,\n                    title,\n                    completed: false,\n                    expiry_millis: COMPLETED_EXPIRY_MILLIS,\n                };\n                self.todos.push(todo);\n                rid::post(Reply::AddedTodo(req_id, self.last_added_id.to_string()));\n            }\n            RemoveTodo(id) => {\n                self.remove_todo(id);\n                rid::post(Reply::RemovedTodo(req_id, self.last_added_id.to_string()));\n            }\n\n            RemoveCompleted => {\n                self.todos.retain(|todo| !todo.completed);\n                rid::post(Reply::RemovedCompleted(req_id));\n            }\n\n            CompleteTodo(id) => {\n                self.update_todo(id, |todo| todo.set_completed(true));\n                rid::post(Reply::CompletedTodo(req_id, id.to_string()));\n            }\n            RestartTodo(id) => {\n                self.update_todo(id, |todo| todo.set_completed(false));\n                rid::post(Reply::RestartedTodo(req_id, id.to_string()));\n            }\n            ToggleTodo(id) => {\n                self.update_todo(id, |todo| todo.set_completed(!todo.completed));\n                rid::post(Reply::ToggledTodo(req_id, id.to_string()));\n            }\n\n            CompleteAll => {\n                self.todos.iter_mut().for_each(|x| x.set_completed(true));\n                rid::post(Reply::CompletedAll(req_id));\n            }\n            RestartAll => {\n                self.todos.iter_mut().for_each(|x| x.set_completed(false));\n                rid::post(Reply::RestartedAll(req_id));\n            }\n\n            SetFilter(filter) => {\n                self.filter = filter;\n                rid::post(Reply::SetFilter(req_id));\n            }\n            SetAutoExpireCompletedTodos(expire) => {\n                self.set_auto_expire_completed_todos(expire);\n                rid::post(Reply::SetAutoExpireCompletedTodos(req_id));\n            }\n        };\n    }\n}\n\n#[rid::export]\n#[rid::structs(Todo)]\nimpl Store {\n    fn remove_todo(&mut self, id: u32) {\n        let mut enumerated = self.todos.iter().enumerate();\n        let idx = match enumerated.find(|(_, todo)| todo.id == id) {\n            Some((idx, _)) => idx,\n            None => return eprintln!(\"Could not find Todo with id '{}'\", id),\n        };\n        self.todos.remove(idx);\n    }\n\n    fn update_todo<F: FnOnce(&mut Todo)>(&mut self, id: u32, update: F) {\n        match self.todos.iter_mut().find(|x| x.id == id) {\n            Some(todo) => update(todo),\n            None => eprintln!(\"Could not find Todo with id '{}'\", id),\n        };\n    }\n\n    #[rid::export]\n    fn filtered_todos(&self) -> Vec<&Todo> {\n        let mut vec: Vec<&Todo> = match self.filter {\n            Filter::Completed => self.todos.iter().filter(|x| x.completed).collect(),\n            Filter::Pending => self.todos.iter().filter(|x| !x.completed).collect(),\n            Filter::All => self.todos.iter().collect(),\n        };\n        vec.sort();\n        vec\n    }\n\n    #[rid::export]\n    fn todo_by_id(&self, id: u32) -> Option<&Todo> {\n        self.todos.iter().find(|x| x.id == id)\n    }\n\n    // The below read/write wrappers help with auto complete since procmacros\n    // aren't very well supported by the rust analyzer yet\n    fn read() -> RwLockReadGuard<'static, Store> {\n        store::read()\n    }\n\n    fn write() -> RwLockWriteGuard<'static, Store> {\n        store::write()\n    }\n\n    pub fn set_auto_expire_completed_todos(&mut self, expire: bool) {\n        self.settings.auto_expire_completed_todos = expire;\n        if expire {\n            thread::spawn(move || {\n                eprintln!(\n                    \"rust: thread {:?} started auto expiring\",\n                    thread::current().id()\n                );\n                while Store::read().settings.auto_expire_completed_todos {\n                    thread::sleep(time::Duration::from_millis(EXPIRY_STEP));\n                    {\n                        let ids_to_update: Vec<(u32, bool)> = Store::write()\n                            .todos\n                            .iter_mut()\n                            .filter(|x| x.completed)\n                            .map(|x: &mut Todo| {\n                                let next_value = x.expiry_millis - EXPIRY_STEP;\n                                if next_value <= 0 {\n                                    (x.id, true)\n                                } else {\n                                    x.expiry_millis = next_value;\n                                    (x.id, false)\n                                }\n                            })\n                            .collect();\n\n                        for (id, remove) in ids_to_update {\n                            if remove {\n                                Store::write().remove_todo(id);\n                                rid::post(Reply::CompletedTodoExpired);\n                            } else {\n                                rid::post(Reply::Tick(id.to_string()));\n                            }\n                        }\n                    }\n                }\n                eprintln!(\n                    \"rust: thread {:?} stopped auto expiring\",\n                    thread::current().id()\n                );\n            });\n        }\n    }\n}\n\n// -----------------\n// Settings\n// -----------------\n#[rid::model]\n#[derive(Debug)]\npub struct Settings {\n    auto_expire_completed_todos: bool,\n    completed_expiry_millis: u64,\n}\n\n// -----------------\n// Todo Model\n// -----------------\n#[rid::model]\n#[derive(PartialEq, Eq, PartialOrd, Debug)]\npub struct Todo {\n    id: u32,\n    title: String,\n    completed: bool,\n    expiry_millis: u64,\n}\n\nimpl Todo {\n    fn set_completed(&mut self, completed: bool) {\n        self.completed = completed;\n        self.expiry_millis = COMPLETED_EXPIRY_MILLIS;\n    }\n}\n\nimpl Ord for Todo {\n    fn cmp(&self, other: &Self) -> std::cmp::Ordering {\n        self.id.cmp(&other.id)\n    }\n}\n\n// -----------------\n// Filter\n// -----------------\n#[rid::model]\n#[derive(Clone, Debug)]\npub enum Filter {\n    Completed,\n    Pending,\n    All,\n}\n\n// -----------------\n// Msg\n// -----------------\n#[rid::message(Reply)]\n#[rid::enums(Filter)]\n#[derive(Debug)]\npub enum Msg {\n    AddTodo(String),\n    RemoveTodo(u32),\n    RemoveCompleted,\n\n    CompleteTodo(u32),\n    RestartTodo(u32),\n    ToggleTodo(u32),\n    CompleteAll,\n    RestartAll,\n\n    SetFilter(Filter),\n    SetAutoExpireCompletedTodos(bool),\n}\n\n// -----------------\n// Reply\n// -----------------\n#[rid::reply]\npub enum Reply {\n    // Message Replies\n    AddedTodo(u64, String),\n    RemovedTodo(u64, String),\n    RemovedCompleted(u64),\n\n    CompletedTodo(u64, String),\n    RestartedTodo(u64, String),\n    ToggledTodo(u64, String),\n    CompletedAll(u64),\n    RestartedAll(u64),\n\n    SetFilter(u64),\n    SetAutoExpireCompletedTodos(u64),\n\n    // Application Events\n    CompletedTodoExpired,\n    Tick(String),\n}\n"
  },
  {
    "path": "flutter/todo_cubit/test/widget_test.dart",
    "content": "// This is a basic Flutter widget test.\n//\n// To perform an interaction with a widget in your test, use the WidgetTester\n// utility that Flutter provides. For example, you can send tap and scroll\n// gestures. You can also use WidgetTester to find child widgets in the widget\n// tree, read text, and verify that the values of widget properties are correct.\n\nimport 'package:flutter/material.dart';\nimport 'package:flutter_test/flutter_test.dart';\n\nimport 'package:todo_cubit/main.dart';\n\nvoid main() {\n  testWidgets('Counter increments smoke test', (WidgetTester tester) async {\n    // Build our app and trigger a frame.\n    await tester.pumpWidget(MyApp());\n\n    // Verify that our counter starts at 0.\n    expect(find.text('0'), findsOneWidget);\n    expect(find.text('1'), findsNothing);\n\n    // Tap the '+' icon and trigger a frame.\n    await tester.tap(find.byIcon(Icons.add));\n    await tester.pump();\n\n    // Verify that our counter has incremented.\n    expect(find.text('0'), findsNothing);\n    expect(find.text('1'), findsOneWidget);\n  });\n}\n"
  },
  {
    "path": "flutter/todo_cubit/todo_cubit.iml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<module type=\"JAVA_MODULE\" version=\"4\">\n  <component name=\"NewModuleRootManager\" inherit-compiler-output=\"true\">\n    <exclude-output />\n    <content url=\"file://$MODULE_DIR$\">\n      <sourceFolder url=\"file://$MODULE_DIR$/lib\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/test\" isTestSource=\"true\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/.dart_tool\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/.idea\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/.pub\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build\" />\n    </content>\n    <orderEntry type=\"sourceFolder\" forTests=\"false\" />\n    <orderEntry type=\"library\" name=\"Dart SDK\" level=\"project\" />\n    <orderEntry type=\"library\" name=\"Flutter Plugins\" level=\"project\" />\n    <orderEntry type=\"library\" name=\"Dart Packages\" level=\"project\" />\n  </component>\n</module>"
  },
  {
    "path": "flutter/todo_cubit/web/index.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n  <!--\n    If you are serving your web app in a path other than the root, change the\n    href value below to reflect the base path you are serving from.\n\n    The path provided below has to start and end with a slash \"/\" in order for\n    it to work correctly.\n\n    For more details:\n    * https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base\n  -->\n  <base href=\"/\">\n\n  <meta charset=\"UTF-8\">\n  <meta content=\"IE=Edge\" http-equiv=\"X-UA-Compatible\">\n  <meta name=\"description\" content=\"A new Flutter project.\">\n\n  <!-- iOS meta tags & icons -->\n  <meta name=\"apple-mobile-web-app-capable\" content=\"yes\">\n  <meta name=\"apple-mobile-web-app-status-bar-style\" content=\"black\">\n  <meta name=\"apple-mobile-web-app-title\" content=\"todo_cubit\">\n  <link rel=\"apple-touch-icon\" href=\"icons/Icon-192.png\">\n\n  <title>todo_cubit</title>\n  <link rel=\"manifest\" href=\"manifest.json\">\n</head>\n<body>\n  <!-- This script installs service_worker.js to provide PWA functionality to\n       application. For more information, see:\n       https://developers.google.com/web/fundamentals/primers/service-workers -->\n  <script>\n    var serviceWorkerVersion = null;\n    var scriptLoaded = false;\n    function loadMainDartJs() {\n      if (scriptLoaded) {\n        return;\n      }\n      scriptLoaded = true;\n      var scriptTag = document.createElement('script');\n      scriptTag.src = 'main.dart.js';\n      scriptTag.type = 'application/javascript';\n      document.body.append(scriptTag);\n    }\n\n    if ('serviceWorker' in navigator) {\n      // Service workers are supported. Use them.\n      window.addEventListener('load', function () {\n        // Wait for registration to finish before dropping the <script> tag.\n        // Otherwise, the browser will load the script multiple times,\n        // potentially different versions.\n        var serviceWorkerUrl = 'flutter_service_worker.js?v=' + serviceWorkerVersion;\n        navigator.serviceWorker.register(serviceWorkerUrl)\n          .then((reg) => {\n            function waitForActivation(serviceWorker) {\n              serviceWorker.addEventListener('statechange', () => {\n                if (serviceWorker.state == 'activated') {\n                  console.log('Installed new service worker.');\n                  loadMainDartJs();\n                }\n              });\n            }\n            if (!reg.active && (reg.installing || reg.waiting)) {\n              // No active web worker and we have installed or are installing\n              // one for the first time. Simply wait for it to activate.\n              waitForActivation(reg.installing ?? reg.waiting);\n            } else if (!reg.active.scriptURL.endsWith(serviceWorkerVersion)) {\n              // When the app updates the serviceWorkerVersion changes, so we\n              // need to ask the service worker to update.\n              console.log('New service worker available.');\n              reg.update();\n              waitForActivation(reg.installing);\n            } else {\n              // Existing service worker is still good.\n              console.log('Loading app from service worker.');\n              loadMainDartJs();\n            }\n          });\n\n        // If service worker doesn't succeed in a reasonable amount of time,\n        // fallback to plaint <script> tag.\n        setTimeout(() => {\n          if (!scriptLoaded) {\n            console.warn(\n              'Failed to load app from service worker. Falling back to plain <script> tag.',\n            );\n            loadMainDartJs();\n          }\n        }, 4000);\n      });\n    } else {\n      // Service workers not supported. Just drop the <script> tag.\n      loadMainDartJs();\n    }\n  </script>\n</body>\n</html>\n"
  },
  {
    "path": "flutter/todo_cubit/web/manifest.json",
    "content": "{\n    \"name\": \"todo_cubit\",\n    \"short_name\": \"todo_cubit\",\n    \"start_url\": \".\",\n    \"display\": \"standalone\",\n    \"background_color\": \"#0175C2\",\n    \"theme_color\": \"#0175C2\",\n    \"description\": \"A new Flutter project.\",\n    \"orientation\": \"portrait-primary\",\n    \"prefer_related_applications\": false,\n    \"icons\": [\n        {\n            \"src\": \"icons/Icon-192.png\",\n            \"sizes\": \"192x192\",\n            \"type\": \"image/png\"\n        },\n        {\n            \"src\": \"icons/Icon-512.png\",\n            \"sizes\": \"512x512\",\n            \"type\": \"image/png\"\n        }\n    ]\n}\n"
  },
  {
    "path": "flutter/todo_cubit/windows/.gitignore",
    "content": "flutter/ephemeral/\n\n# Visual Studio user-specific files.\n*.suo\n*.user\n*.userosscache\n*.sln.docstates\n\n# Visual Studio build-related files.\nx64/\nx86/\n\n# Visual Studio cache files\n# files ending in .cache can be ignored\n*.[Cc]ache\n# but keep track of directories ending in .cache\n!*.[Cc]ache/\n"
  },
  {
    "path": "flutter/todo_cubit/windows/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.15)\nproject(todo_cubit LANGUAGES CXX)\n\nset(BINARY_NAME \"todo_cubit\")\n\ncmake_policy(SET CMP0063 NEW)\n\nset(CMAKE_INSTALL_RPATH \"$ORIGIN/lib\")\n\n# Configure build options.\nget_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)\nif(IS_MULTICONFIG)\n  set(CMAKE_CONFIGURATION_TYPES \"Debug;Profile;Release\"\n    CACHE STRING \"\" FORCE)\nelse()\n  if(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\")\n  endif()\nendif()\n\nset(CMAKE_EXE_LINKER_FLAGS_PROFILE \"${CMAKE_EXE_LINKER_FLAGS_RELEASE}\")\nset(CMAKE_SHARED_LINKER_FLAGS_PROFILE \"${CMAKE_SHARED_LINKER_FLAGS_RELEASE}\")\nset(CMAKE_C_FLAGS_PROFILE \"${CMAKE_C_FLAGS_RELEASE}\")\nset(CMAKE_CXX_FLAGS_PROFILE \"${CMAKE_CXX_FLAGS_RELEASE}\")\n\n# Use Unicode for all projects.\nadd_definitions(-DUNICODE -D_UNICODE)\n\n# Compilation settings that should be applied to most targets.\nfunction(APPLY_STANDARD_SETTINGS TARGET)\n  target_compile_features(${TARGET} PUBLIC cxx_std_17)\n  target_compile_options(${TARGET} PRIVATE /W4 /WX /wd\"4100\")\n  target_compile_options(${TARGET} PRIVATE /EHsc)\n  target_compile_definitions(${TARGET} PRIVATE \"_HAS_EXCEPTIONS=0\")\n  target_compile_definitions(${TARGET} PRIVATE \"$<$<CONFIG:Debug>:_DEBUG>\")\nendfunction()\n\nset(FLUTTER_MANAGED_DIR \"${CMAKE_CURRENT_SOURCE_DIR}/flutter\")\n\n# Flutter library and tool build rules.\nadd_subdirectory(${FLUTTER_MANAGED_DIR})\n\n# Application build\nadd_subdirectory(\"runner\")\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# Support files are copied into place next to the executable, so that it can\n# run in place. This is done instead of making a separate bundle (as on Linux)\n# so that building and running from within Visual Studio will work.\nset(BUILD_BUNDLE_DIR \"$<TARGET_FILE_DIR:${BINARY_NAME}>\")\n# Make the \"install\" step default, as it's required to run.\nset(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1)\nif(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)\n  set(CMAKE_INSTALL_PREFIX \"${BUILD_BUNDLE_DIR}\" CACHE PATH \"...\" FORCE)\nendif()\n\nset(INSTALL_BUNDLE_DATA_DIR \"${CMAKE_INSTALL_PREFIX}/data\")\nset(INSTALL_BUNDLE_LIB_DIR \"${CMAKE_INSTALL_PREFIX}\")\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\nif(PLUGIN_BUNDLED_LIBRARIES)\n  install(FILES \"${PLUGIN_BUNDLED_LIBRARIES}\"\n    DESTINATION \"${INSTALL_BUNDLE_LIB_DIR}\"\n    COMPONENT Runtime)\nendif()\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.\ninstall(FILES \"${AOT_LIBRARY}\" DESTINATION \"${INSTALL_BUNDLE_DATA_DIR}\"\n  CONFIGURATIONS Profile;Release\n  COMPONENT Runtime)\n"
  },
  {
    "path": "flutter/todo_cubit/windows/flutter/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.15)\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.\nset(WRAPPER_ROOT \"${EPHEMERAL_DIR}/cpp_client_wrapper\")\n\n# === Flutter Library ===\nset(FLUTTER_LIBRARY \"${EPHEMERAL_DIR}/flutter_windows.dll\")\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/windows/app.so\" PARENT_SCOPE)\n\nlist(APPEND FLUTTER_LIBRARY_HEADERS\n  \"flutter_export.h\"\n  \"flutter_windows.h\"\n  \"flutter_messenger.h\"\n  \"flutter_plugin_registrar.h\"\n  \"flutter_texture_registrar.h\"\n)\nlist(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND \"${EPHEMERAL_DIR}/\")\nadd_library(flutter INTERFACE)\ntarget_include_directories(flutter INTERFACE\n  \"${EPHEMERAL_DIR}\"\n)\ntarget_link_libraries(flutter INTERFACE \"${FLUTTER_LIBRARY}.lib\")\nadd_dependencies(flutter flutter_assemble)\n\n# === Wrapper ===\nlist(APPEND CPP_WRAPPER_SOURCES_CORE\n  \"core_implementations.cc\"\n  \"standard_codec.cc\"\n)\nlist(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND \"${WRAPPER_ROOT}/\")\nlist(APPEND CPP_WRAPPER_SOURCES_PLUGIN\n  \"plugin_registrar.cc\"\n)\nlist(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND \"${WRAPPER_ROOT}/\")\nlist(APPEND CPP_WRAPPER_SOURCES_APP\n  \"flutter_engine.cc\"\n  \"flutter_view_controller.cc\"\n)\nlist(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND \"${WRAPPER_ROOT}/\")\n\n# Wrapper sources needed for a plugin.\nadd_library(flutter_wrapper_plugin STATIC\n  ${CPP_WRAPPER_SOURCES_CORE}\n  ${CPP_WRAPPER_SOURCES_PLUGIN}\n)\napply_standard_settings(flutter_wrapper_plugin)\nset_target_properties(flutter_wrapper_plugin PROPERTIES\n  POSITION_INDEPENDENT_CODE ON)\nset_target_properties(flutter_wrapper_plugin PROPERTIES\n  CXX_VISIBILITY_PRESET hidden)\ntarget_link_libraries(flutter_wrapper_plugin PUBLIC flutter)\ntarget_include_directories(flutter_wrapper_plugin PUBLIC\n  \"${WRAPPER_ROOT}/include\"\n)\nadd_dependencies(flutter_wrapper_plugin flutter_assemble)\n\n# Wrapper sources needed for the runner.\nadd_library(flutter_wrapper_app STATIC\n  ${CPP_WRAPPER_SOURCES_CORE}\n  ${CPP_WRAPPER_SOURCES_APP}\n)\napply_standard_settings(flutter_wrapper_app)\ntarget_link_libraries(flutter_wrapper_app PUBLIC flutter)\ntarget_include_directories(flutter_wrapper_app PUBLIC\n  \"${WRAPPER_ROOT}/include\"\n)\nadd_dependencies(flutter_wrapper_app 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.\nset(PHONY_OUTPUT \"${CMAKE_CURRENT_BINARY_DIR}/_phony_\")\nset_source_files_properties(\"${PHONY_OUTPUT}\" PROPERTIES SYMBOLIC TRUE)\nadd_custom_command(\n  OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS}\n    ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN}\n    ${CPP_WRAPPER_SOURCES_APP}\n    ${PHONY_OUTPUT}\n  COMMAND ${CMAKE_COMMAND} -E env\n    ${FLUTTER_TOOL_ENVIRONMENT}\n    \"${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat\"\n      windows-x64 $<CONFIG>\n  VERBATIM\n)\nadd_custom_target(flutter_assemble DEPENDS\n  \"${FLUTTER_LIBRARY}\"\n  ${FLUTTER_LIBRARY_HEADERS}\n  ${CPP_WRAPPER_SOURCES_CORE}\n  ${CPP_WRAPPER_SOURCES_PLUGIN}\n  ${CPP_WRAPPER_SOURCES_APP}\n)\n"
  },
  {
    "path": "flutter/todo_cubit/windows/flutter/generated_plugin_registrant.cc",
    "content": "//\n//  Generated file. Do not edit.\n//\n\n#include \"generated_plugin_registrant.h\"\n\n\nvoid RegisterPlugins(flutter::PluginRegistry* registry) {\n}\n"
  },
  {
    "path": "flutter/todo_cubit/windows/flutter/generated_plugin_registrant.h",
    "content": "//\n//  Generated file. Do not edit.\n//\n\n#ifndef GENERATED_PLUGIN_REGISTRANT_\n#define GENERATED_PLUGIN_REGISTRANT_\n\n#include <flutter/plugin_registry.h>\n\n// Registers Flutter plugins.\nvoid RegisterPlugins(flutter::PluginRegistry* registry);\n\n#endif  // GENERATED_PLUGIN_REGISTRANT_\n"
  },
  {
    "path": "flutter/todo_cubit/windows/flutter/generated_plugins.cmake",
    "content": "#\n# Generated file, do not edit.\n#\n\nlist(APPEND FLUTTER_PLUGIN_LIST\n)\n\nset(PLUGIN_BUNDLED_LIBRARIES)\n\nforeach(plugin ${FLUTTER_PLUGIN_LIST})\n  add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows 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"
  },
  {
    "path": "flutter/todo_cubit/windows/runner/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.15)\nproject(runner LANGUAGES CXX)\n\nadd_executable(${BINARY_NAME} WIN32\n  \"flutter_window.cpp\"\n  \"main.cpp\"\n  \"run_loop.cpp\"\n  \"utils.cpp\"\n  \"win32_window.cpp\"\n  \"${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc\"\n  \"Runner.rc\"\n  \"runner.exe.manifest\"\n)\napply_standard_settings(${BINARY_NAME})\ntarget_compile_definitions(${BINARY_NAME} PRIVATE \"NOMINMAX\")\ntarget_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app)\ntarget_include_directories(${BINARY_NAME} PRIVATE \"${CMAKE_SOURCE_DIR}\")\nadd_dependencies(${BINARY_NAME} flutter_assemble)\n"
  },
  {
    "path": "flutter/todo_cubit/windows/runner/Runner.rc",
    "content": "// Microsoft Visual C++ generated resource script.\n//\n#pragma code_page(65001)\n#include \"resource.h\"\n\n#define APSTUDIO_READONLY_SYMBOLS\n/////////////////////////////////////////////////////////////////////////////\n//\n// Generated from the TEXTINCLUDE 2 resource.\n//\n#include \"winres.h\"\n\n/////////////////////////////////////////////////////////////////////////////\n#undef APSTUDIO_READONLY_SYMBOLS\n\n/////////////////////////////////////////////////////////////////////////////\n// English (United States) resources\n\n#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\nLANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US\n\n#ifdef APSTUDIO_INVOKED\n/////////////////////////////////////////////////////////////////////////////\n//\n// TEXTINCLUDE\n//\n\n1 TEXTINCLUDE\nBEGIN\n    \"resource.h\\0\"\nEND\n\n2 TEXTINCLUDE\nBEGIN\n    \"#include \"\"winres.h\"\"\\r\\n\"\n    \"\\0\"\nEND\n\n3 TEXTINCLUDE\nBEGIN\n    \"\\r\\n\"\n    \"\\0\"\nEND\n\n#endif    // APSTUDIO_INVOKED\n\n\n/////////////////////////////////////////////////////////////////////////////\n//\n// Icon\n//\n\n// Icon with lowest ID value placed first to ensure application icon\n// remains consistent on all systems.\nIDI_APP_ICON            ICON                    \"resources\\\\app_icon.ico\"\n\n\n/////////////////////////////////////////////////////////////////////////////\n//\n// Version\n//\n\n#ifdef FLUTTER_BUILD_NUMBER\n#define VERSION_AS_NUMBER FLUTTER_BUILD_NUMBER\n#else\n#define VERSION_AS_NUMBER 1,0,0\n#endif\n\n#ifdef FLUTTER_BUILD_NAME\n#define VERSION_AS_STRING #FLUTTER_BUILD_NAME\n#else\n#define VERSION_AS_STRING \"1.0.0\"\n#endif\n\nVS_VERSION_INFO VERSIONINFO\n FILEVERSION VERSION_AS_NUMBER\n PRODUCTVERSION VERSION_AS_NUMBER\n FILEFLAGSMASK VS_FFI_FILEFLAGSMASK\n#ifdef _DEBUG\n FILEFLAGS VS_FF_DEBUG\n#else\n FILEFLAGS 0x0L\n#endif\n FILEOS VOS__WINDOWS32\n FILETYPE VFT_APP\n FILESUBTYPE 0x0L\nBEGIN\n    BLOCK \"StringFileInfo\"\n    BEGIN\n        BLOCK \"040904e4\"\n        BEGIN\n            VALUE \"CompanyName\", \"com.example\" \"\\0\"\n            VALUE \"FileDescription\", \"A new Flutter project.\" \"\\0\"\n            VALUE \"FileVersion\", VERSION_AS_STRING \"\\0\"\n            VALUE \"InternalName\", \"todo_cubit\" \"\\0\"\n            VALUE \"LegalCopyright\", \"Copyright (C) 2021 com.example. All rights reserved.\" \"\\0\"\n            VALUE \"OriginalFilename\", \"todo_cubit.exe\" \"\\0\"\n            VALUE \"ProductName\", \"todo_cubit\" \"\\0\"\n            VALUE \"ProductVersion\", VERSION_AS_STRING \"\\0\"\n        END\n    END\n    BLOCK \"VarFileInfo\"\n    BEGIN\n        VALUE \"Translation\", 0x409, 1252\n    END\nEND\n\n#endif    // English (United States) resources\n/////////////////////////////////////////////////////////////////////////////\n\n\n\n#ifndef APSTUDIO_INVOKED\n/////////////////////////////////////////////////////////////////////////////\n//\n// Generated from the TEXTINCLUDE 3 resource.\n//\n\n\n/////////////////////////////////////////////////////////////////////////////\n#endif    // not APSTUDIO_INVOKED\n"
  },
  {
    "path": "flutter/todo_cubit/windows/runner/flutter_window.cpp",
    "content": "#include \"flutter_window.h\"\n\n#include <optional>\n\n#include \"flutter/generated_plugin_registrant.h\"\n\nFlutterWindow::FlutterWindow(RunLoop* run_loop,\n                             const flutter::DartProject& project)\n    : run_loop_(run_loop), project_(project) {}\n\nFlutterWindow::~FlutterWindow() {}\n\nbool FlutterWindow::OnCreate() {\n  if (!Win32Window::OnCreate()) {\n    return false;\n  }\n\n  RECT frame = GetClientArea();\n\n  // The size here must match the window dimensions to avoid unnecessary surface\n  // creation / destruction in the startup path.\n  flutter_controller_ = std::make_unique<flutter::FlutterViewController>(\n      frame.right - frame.left, frame.bottom - frame.top, project_);\n  // Ensure that basic setup of the controller was successful.\n  if (!flutter_controller_->engine() || !flutter_controller_->view()) {\n    return false;\n  }\n  RegisterPlugins(flutter_controller_->engine());\n  run_loop_->RegisterFlutterInstance(flutter_controller_->engine());\n  SetChildContent(flutter_controller_->view()->GetNativeWindow());\n  return true;\n}\n\nvoid FlutterWindow::OnDestroy() {\n  if (flutter_controller_) {\n    run_loop_->UnregisterFlutterInstance(flutter_controller_->engine());\n    flutter_controller_ = nullptr;\n  }\n\n  Win32Window::OnDestroy();\n}\n\nLRESULT\nFlutterWindow::MessageHandler(HWND hwnd, UINT const message,\n                              WPARAM const wparam,\n                              LPARAM const lparam) noexcept {\n  // Give Flutter, including plugins, an opportunity to handle window messages.\n  if (flutter_controller_) {\n    std::optional<LRESULT> result =\n        flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam,\n                                                      lparam);\n    if (result) {\n      return *result;\n    }\n  }\n\n  switch (message) {\n    case WM_FONTCHANGE:\n      flutter_controller_->engine()->ReloadSystemFonts();\n      break;\n  }\n\n  return Win32Window::MessageHandler(hwnd, message, wparam, lparam);\n}\n"
  },
  {
    "path": "flutter/todo_cubit/windows/runner/flutter_window.h",
    "content": "#ifndef RUNNER_FLUTTER_WINDOW_H_\n#define RUNNER_FLUTTER_WINDOW_H_\n\n#include <flutter/dart_project.h>\n#include <flutter/flutter_view_controller.h>\n\n#include <memory>\n\n#include \"run_loop.h\"\n#include \"win32_window.h\"\n\n// A window that does nothing but host a Flutter view.\nclass FlutterWindow : public Win32Window {\n public:\n  // Creates a new FlutterWindow driven by the |run_loop|, hosting a\n  // Flutter view running |project|.\n  explicit FlutterWindow(RunLoop* run_loop,\n                         const flutter::DartProject& project);\n  virtual ~FlutterWindow();\n\n protected:\n  // Win32Window:\n  bool OnCreate() override;\n  void OnDestroy() override;\n  LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam,\n                         LPARAM const lparam) noexcept override;\n\n private:\n  // The run loop driving events for this window.\n  RunLoop* run_loop_;\n\n  // The project to run.\n  flutter::DartProject project_;\n\n  // The Flutter instance hosted by this window.\n  std::unique_ptr<flutter::FlutterViewController> flutter_controller_;\n};\n\n#endif  // RUNNER_FLUTTER_WINDOW_H_\n"
  },
  {
    "path": "flutter/todo_cubit/windows/runner/main.cpp",
    "content": "#include <flutter/dart_project.h>\n#include <flutter/flutter_view_controller.h>\n#include <windows.h>\n\n#include \"flutter_window.h\"\n#include \"run_loop.h\"\n#include \"utils.h\"\n\nint APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,\n                      _In_ wchar_t *command_line, _In_ int show_command) {\n  // Attach to console when present (e.g., 'flutter run') or create a\n  // new console when running with a debugger.\n  if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) {\n    CreateAndAttachConsole();\n  }\n\n  // Initialize COM, so that it is available for use in the library and/or\n  // plugins.\n  ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);\n\n  RunLoop run_loop;\n\n  flutter::DartProject project(L\"data\");\n\n  std::vector<std::string> command_line_arguments =\n      GetCommandLineArguments();\n\n  project.set_dart_entrypoint_arguments(std::move(command_line_arguments));\n\n  FlutterWindow window(&run_loop, project);\n  Win32Window::Point origin(10, 10);\n  Win32Window::Size size(1280, 720);\n  if (!window.CreateAndShow(L\"todo_cubit\", origin, size)) {\n    return EXIT_FAILURE;\n  }\n  window.SetQuitOnClose(true);\n\n  run_loop.Run();\n\n  ::CoUninitialize();\n  return EXIT_SUCCESS;\n}\n"
  },
  {
    "path": "flutter/todo_cubit/windows/runner/resource.h",
    "content": "//{{NO_DEPENDENCIES}}\n// Microsoft Visual C++ generated include file.\n// Used by Runner.rc\n//\n#define IDI_APP_ICON                    101\n\n// Next default values for new objects\n//\n#ifdef APSTUDIO_INVOKED\n#ifndef APSTUDIO_READONLY_SYMBOLS\n#define _APS_NEXT_RESOURCE_VALUE        102\n#define _APS_NEXT_COMMAND_VALUE         40001\n#define _APS_NEXT_CONTROL_VALUE         1001\n#define _APS_NEXT_SYMED_VALUE           101\n#endif\n#endif\n"
  },
  {
    "path": "flutter/todo_cubit/windows/runner/run_loop.cpp",
    "content": "#include \"run_loop.h\"\n\n#include <windows.h>\n\n#include <algorithm>\n\nRunLoop::RunLoop() {}\n\nRunLoop::~RunLoop() {}\n\nvoid RunLoop::Run() {\n  bool keep_running = true;\n  TimePoint next_flutter_event_time = TimePoint::clock::now();\n  while (keep_running) {\n    std::chrono::nanoseconds wait_duration =\n        std::max(std::chrono::nanoseconds(0),\n                 next_flutter_event_time - TimePoint::clock::now());\n    ::MsgWaitForMultipleObjects(\n        0, nullptr, FALSE, static_cast<DWORD>(wait_duration.count() / 1000),\n        QS_ALLINPUT);\n    bool processed_events = false;\n    MSG message;\n    // All pending Windows messages must be processed; MsgWaitForMultipleObjects\n    // won't return again for items left in the queue after PeekMessage.\n    while (::PeekMessage(&message, nullptr, 0, 0, PM_REMOVE)) {\n      processed_events = true;\n      if (message.message == WM_QUIT) {\n        keep_running = false;\n        break;\n      }\n      ::TranslateMessage(&message);\n      ::DispatchMessage(&message);\n      // Allow Flutter to process messages each time a Windows message is\n      // processed, to prevent starvation.\n      next_flutter_event_time =\n          std::min(next_flutter_event_time, ProcessFlutterMessages());\n    }\n    // If the PeekMessage loop didn't run, process Flutter messages.\n    if (!processed_events) {\n      next_flutter_event_time =\n          std::min(next_flutter_event_time, ProcessFlutterMessages());\n    }\n  }\n}\n\nvoid RunLoop::RegisterFlutterInstance(\n    flutter::FlutterEngine* flutter_instance) {\n  flutter_instances_.insert(flutter_instance);\n}\n\nvoid RunLoop::UnregisterFlutterInstance(\n    flutter::FlutterEngine* flutter_instance) {\n  flutter_instances_.erase(flutter_instance);\n}\n\nRunLoop::TimePoint RunLoop::ProcessFlutterMessages() {\n  TimePoint next_event_time = TimePoint::max();\n  for (auto instance : flutter_instances_) {\n    std::chrono::nanoseconds wait_duration = instance->ProcessMessages();\n    if (wait_duration != std::chrono::nanoseconds::max()) {\n      next_event_time =\n          std::min(next_event_time, TimePoint::clock::now() + wait_duration);\n    }\n  }\n  return next_event_time;\n}\n"
  },
  {
    "path": "flutter/todo_cubit/windows/runner/run_loop.h",
    "content": "#ifndef RUNNER_RUN_LOOP_H_\n#define RUNNER_RUN_LOOP_H_\n\n#include <flutter/flutter_engine.h>\n\n#include <chrono>\n#include <set>\n\n// A runloop that will service events for Flutter instances as well\n// as native messages.\nclass RunLoop {\n public:\n  RunLoop();\n  ~RunLoop();\n\n  // Prevent copying\n  RunLoop(RunLoop const&) = delete;\n  RunLoop& operator=(RunLoop const&) = delete;\n\n  // Runs the run loop until the application quits.\n  void Run();\n\n  // Registers the given Flutter instance for event servicing.\n  void RegisterFlutterInstance(\n      flutter::FlutterEngine* flutter_instance);\n\n  // Unregisters the given Flutter instance from event servicing.\n  void UnregisterFlutterInstance(\n      flutter::FlutterEngine* flutter_instance);\n\n private:\n  using TimePoint = std::chrono::steady_clock::time_point;\n\n  // Processes all currently pending messages for registered Flutter instances.\n  TimePoint ProcessFlutterMessages();\n\n  std::set<flutter::FlutterEngine*> flutter_instances_;\n};\n\n#endif  // RUNNER_RUN_LOOP_H_\n"
  },
  {
    "path": "flutter/todo_cubit/windows/runner/runner.exe.manifest",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">\n  <application xmlns=\"urn:schemas-microsoft-com:asm.v3\">\n    <windowsSettings>\n      <dpiAwareness xmlns=\"http://schemas.microsoft.com/SMI/2016/WindowsSettings\">PerMonitorV2</dpiAwareness>\n    </windowsSettings>\n  </application>\n  <compatibility xmlns=\"urn:schemas-microsoft-com:compatibility.v1\">\n    <application>\n      <!-- Windows 10 -->\n      <supportedOS Id=\"{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}\"/>\n      <!-- Windows 8.1 -->\n      <supportedOS Id=\"{1f676c76-80e1-4239-95bb-83d0f6d0da78}\"/>\n      <!-- Windows 8 -->\n      <supportedOS Id=\"{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}\"/>\n      <!-- Windows 7 -->\n      <supportedOS Id=\"{35138b9a-5d96-4fbd-8e2d-a2440225f93a}\"/>\n    </application>\n  </compatibility>\n</assembly>\n"
  },
  {
    "path": "flutter/todo_cubit/windows/runner/utils.cpp",
    "content": "#include \"utils.h\"\n\n#include <flutter_windows.h>\n#include <io.h>\n#include <stdio.h>\n#include <windows.h>\n\n#include <iostream>\n\nvoid CreateAndAttachConsole() {\n  if (::AllocConsole()) {\n    FILE *unused;\n    if (freopen_s(&unused, \"CONOUT$\", \"w\", stdout)) {\n      _dup2(_fileno(stdout), 1);\n    }\n    if (freopen_s(&unused, \"CONOUT$\", \"w\", stderr)) {\n      _dup2(_fileno(stdout), 2);\n    }\n    std::ios::sync_with_stdio();\n    FlutterDesktopResyncOutputStreams();\n  }\n}\n\nstd::vector<std::string> GetCommandLineArguments() {\n  // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use.\n  int argc;\n  wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc);\n  if (argv == nullptr) {\n    return std::vector<std::string>();\n  }\n\n  std::vector<std::string> command_line_arguments;\n\n  // Skip the first argument as it's the binary name.\n  for (int i = 1; i < argc; i++) {\n    command_line_arguments.push_back(Utf8FromUtf16(argv[i]));\n  }\n\n  ::LocalFree(argv);\n\n  return command_line_arguments;\n}\n\nstd::string Utf8FromUtf16(const wchar_t* utf16_string) {\n  if (utf16_string == nullptr) {\n    return std::string();\n  }\n  int target_length = ::WideCharToMultiByte(\n      CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string,\n      -1, nullptr, 0, nullptr, nullptr);\n  if (target_length == 0) {\n    return std::string();\n  }\n  std::string utf8_string;\n  utf8_string.resize(target_length);\n  int converted_length = ::WideCharToMultiByte(\n      CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string,\n      -1, utf8_string.data(),\n      target_length, nullptr, nullptr);\n  if (converted_length == 0) {\n    return std::string();\n  }\n  return utf8_string;\n}\n"
  },
  {
    "path": "flutter/todo_cubit/windows/runner/utils.h",
    "content": "#ifndef RUNNER_UTILS_H_\n#define RUNNER_UTILS_H_\n\n#include <string>\n#include <vector>\n\n// Creates a console for the process, and redirects stdout and stderr to\n// it for both the runner and the Flutter library.\nvoid CreateAndAttachConsole();\n\n// Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string\n// encoded in UTF-8. Returns an empty std::string on failure.\nstd::string Utf8FromUtf16(const wchar_t* utf16_string);\n\n// Gets the command line arguments passed in as a std::vector<std::string>,\n// encoded in UTF-8. Returns an empty std::vector<std::string> on failure.\nstd::vector<std::string> GetCommandLineArguments();\n\n#endif  // RUNNER_UTILS_H_\n"
  },
  {
    "path": "flutter/todo_cubit/windows/runner/win32_window.cpp",
    "content": "#include \"win32_window.h\"\n\n#include <flutter_windows.h>\n\n#include \"resource.h\"\n\nnamespace {\n\nconstexpr const wchar_t kWindowClassName[] = L\"FLUTTER_RUNNER_WIN32_WINDOW\";\n\n// The number of Win32Window objects that currently exist.\nstatic int g_active_window_count = 0;\n\nusing EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd);\n\n// Scale helper to convert logical scaler values to physical using passed in\n// scale factor\nint Scale(int source, double scale_factor) {\n  return static_cast<int>(source * scale_factor);\n}\n\n// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module.\n// This API is only needed for PerMonitor V1 awareness mode.\nvoid EnableFullDpiSupportIfAvailable(HWND hwnd) {\n  HMODULE user32_module = LoadLibraryA(\"User32.dll\");\n  if (!user32_module) {\n    return;\n  }\n  auto enable_non_client_dpi_scaling =\n      reinterpret_cast<EnableNonClientDpiScaling*>(\n          GetProcAddress(user32_module, \"EnableNonClientDpiScaling\"));\n  if (enable_non_client_dpi_scaling != nullptr) {\n    enable_non_client_dpi_scaling(hwnd);\n    FreeLibrary(user32_module);\n  }\n}\n\n}  // namespace\n\n// Manages the Win32Window's window class registration.\nclass WindowClassRegistrar {\n public:\n  ~WindowClassRegistrar() = default;\n\n  // Returns the singleton registar instance.\n  static WindowClassRegistrar* GetInstance() {\n    if (!instance_) {\n      instance_ = new WindowClassRegistrar();\n    }\n    return instance_;\n  }\n\n  // Returns the name of the window class, registering the class if it hasn't\n  // previously been registered.\n  const wchar_t* GetWindowClass();\n\n  // Unregisters the window class. Should only be called if there are no\n  // instances of the window.\n  void UnregisterWindowClass();\n\n private:\n  WindowClassRegistrar() = default;\n\n  static WindowClassRegistrar* instance_;\n\n  bool class_registered_ = false;\n};\n\nWindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr;\n\nconst wchar_t* WindowClassRegistrar::GetWindowClass() {\n  if (!class_registered_) {\n    WNDCLASS window_class{};\n    window_class.hCursor = LoadCursor(nullptr, IDC_ARROW);\n    window_class.lpszClassName = kWindowClassName;\n    window_class.style = CS_HREDRAW | CS_VREDRAW;\n    window_class.cbClsExtra = 0;\n    window_class.cbWndExtra = 0;\n    window_class.hInstance = GetModuleHandle(nullptr);\n    window_class.hIcon =\n        LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON));\n    window_class.hbrBackground = 0;\n    window_class.lpszMenuName = nullptr;\n    window_class.lpfnWndProc = Win32Window::WndProc;\n    RegisterClass(&window_class);\n    class_registered_ = true;\n  }\n  return kWindowClassName;\n}\n\nvoid WindowClassRegistrar::UnregisterWindowClass() {\n  UnregisterClass(kWindowClassName, nullptr);\n  class_registered_ = false;\n}\n\nWin32Window::Win32Window() {\n  ++g_active_window_count;\n}\n\nWin32Window::~Win32Window() {\n  --g_active_window_count;\n  Destroy();\n}\n\nbool Win32Window::CreateAndShow(const std::wstring& title,\n                                const Point& origin,\n                                const Size& size) {\n  Destroy();\n\n  const wchar_t* window_class =\n      WindowClassRegistrar::GetInstance()->GetWindowClass();\n\n  const POINT target_point = {static_cast<LONG>(origin.x),\n                              static_cast<LONG>(origin.y)};\n  HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST);\n  UINT dpi = FlutterDesktopGetDpiForMonitor(monitor);\n  double scale_factor = dpi / 96.0;\n\n  HWND window = CreateWindow(\n      window_class, title.c_str(), WS_OVERLAPPEDWINDOW | WS_VISIBLE,\n      Scale(origin.x, scale_factor), Scale(origin.y, scale_factor),\n      Scale(size.width, scale_factor), Scale(size.height, scale_factor),\n      nullptr, nullptr, GetModuleHandle(nullptr), this);\n\n  if (!window) {\n    return false;\n  }\n\n  return OnCreate();\n}\n\n// static\nLRESULT CALLBACK Win32Window::WndProc(HWND const window,\n                                      UINT const message,\n                                      WPARAM const wparam,\n                                      LPARAM const lparam) noexcept {\n  if (message == WM_NCCREATE) {\n    auto window_struct = reinterpret_cast<CREATESTRUCT*>(lparam);\n    SetWindowLongPtr(window, GWLP_USERDATA,\n                     reinterpret_cast<LONG_PTR>(window_struct->lpCreateParams));\n\n    auto that = static_cast<Win32Window*>(window_struct->lpCreateParams);\n    EnableFullDpiSupportIfAvailable(window);\n    that->window_handle_ = window;\n  } else if (Win32Window* that = GetThisFromHandle(window)) {\n    return that->MessageHandler(window, message, wparam, lparam);\n  }\n\n  return DefWindowProc(window, message, wparam, lparam);\n}\n\nLRESULT\nWin32Window::MessageHandler(HWND hwnd,\n                            UINT const message,\n                            WPARAM const wparam,\n                            LPARAM const lparam) noexcept {\n  switch (message) {\n    case WM_DESTROY:\n      window_handle_ = nullptr;\n      Destroy();\n      if (quit_on_close_) {\n        PostQuitMessage(0);\n      }\n      return 0;\n\n    case WM_DPICHANGED: {\n      auto newRectSize = reinterpret_cast<RECT*>(lparam);\n      LONG newWidth = newRectSize->right - newRectSize->left;\n      LONG newHeight = newRectSize->bottom - newRectSize->top;\n\n      SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth,\n                   newHeight, SWP_NOZORDER | SWP_NOACTIVATE);\n\n      return 0;\n    }\n    case WM_SIZE: {\n      RECT rect = GetClientArea();\n      if (child_content_ != nullptr) {\n        // Size and position the child window.\n        MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left,\n                   rect.bottom - rect.top, TRUE);\n      }\n      return 0;\n    }\n\n    case WM_ACTIVATE:\n      if (child_content_ != nullptr) {\n        SetFocus(child_content_);\n      }\n      return 0;\n  }\n\n  return DefWindowProc(window_handle_, message, wparam, lparam);\n}\n\nvoid Win32Window::Destroy() {\n  OnDestroy();\n\n  if (window_handle_) {\n    DestroyWindow(window_handle_);\n    window_handle_ = nullptr;\n  }\n  if (g_active_window_count == 0) {\n    WindowClassRegistrar::GetInstance()->UnregisterWindowClass();\n  }\n}\n\nWin32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept {\n  return reinterpret_cast<Win32Window*>(\n      GetWindowLongPtr(window, GWLP_USERDATA));\n}\n\nvoid Win32Window::SetChildContent(HWND content) {\n  child_content_ = content;\n  SetParent(content, window_handle_);\n  RECT frame = GetClientArea();\n\n  MoveWindow(content, frame.left, frame.top, frame.right - frame.left,\n             frame.bottom - frame.top, true);\n\n  SetFocus(child_content_);\n}\n\nRECT Win32Window::GetClientArea() {\n  RECT frame;\n  GetClientRect(window_handle_, &frame);\n  return frame;\n}\n\nHWND Win32Window::GetHandle() {\n  return window_handle_;\n}\n\nvoid Win32Window::SetQuitOnClose(bool quit_on_close) {\n  quit_on_close_ = quit_on_close;\n}\n\nbool Win32Window::OnCreate() {\n  // No-op; provided for subclasses.\n  return true;\n}\n\nvoid Win32Window::OnDestroy() {\n  // No-op; provided for subclasses.\n}\n"
  },
  {
    "path": "flutter/todo_cubit/windows/runner/win32_window.h",
    "content": "#ifndef RUNNER_WIN32_WINDOW_H_\n#define RUNNER_WIN32_WINDOW_H_\n\n#include <windows.h>\n\n#include <functional>\n#include <memory>\n#include <string>\n\n// A class abstraction for a high DPI-aware Win32 Window. Intended to be\n// inherited from by classes that wish to specialize with custom\n// rendering and input handling\nclass Win32Window {\n public:\n  struct Point {\n    unsigned int x;\n    unsigned int y;\n    Point(unsigned int x, unsigned int y) : x(x), y(y) {}\n  };\n\n  struct Size {\n    unsigned int width;\n    unsigned int height;\n    Size(unsigned int width, unsigned int height)\n        : width(width), height(height) {}\n  };\n\n  Win32Window();\n  virtual ~Win32Window();\n\n  // Creates and shows a win32 window with |title| and position and size using\n  // |origin| and |size|. New windows are created on the default monitor. Window\n  // sizes are specified to the OS in physical pixels, hence to ensure a\n  // consistent size to will treat the width height passed in to this function\n  // as logical pixels and scale to appropriate for the default monitor. Returns\n  // true if the window was created successfully.\n  bool CreateAndShow(const std::wstring& title,\n                     const Point& origin,\n                     const Size& size);\n\n  // Release OS resources associated with window.\n  void Destroy();\n\n  // Inserts |content| into the window tree.\n  void SetChildContent(HWND content);\n\n  // Returns the backing Window handle to enable clients to set icon and other\n  // window properties. Returns nullptr if the window has been destroyed.\n  HWND GetHandle();\n\n  // If true, closing this window will quit the application.\n  void SetQuitOnClose(bool quit_on_close);\n\n  // Return a RECT representing the bounds of the current client area.\n  RECT GetClientArea();\n\n protected:\n  // Processes and route salient window messages for mouse handling,\n  // size change and DPI. Delegates handling of these to member overloads that\n  // inheriting classes can handle.\n  virtual LRESULT MessageHandler(HWND window,\n                                 UINT const message,\n                                 WPARAM const wparam,\n                                 LPARAM const lparam) noexcept;\n\n  // Called when CreateAndShow is called, allowing subclass window-related\n  // setup. Subclasses should return false if setup fails.\n  virtual bool OnCreate();\n\n  // Called when Destroy is called.\n  virtual void OnDestroy();\n\n private:\n  friend class WindowClassRegistrar;\n\n  // OS callback called by message pump. Handles the WM_NCCREATE message which\n  // is passed when the non-client area is being created and enables automatic\n  // non-client DPI scaling so that the non-client area automatically\n  // responsponds to changes in DPI. All other messages are handled by\n  // MessageHandler.\n  static LRESULT CALLBACK WndProc(HWND const window,\n                                  UINT const message,\n                                  WPARAM const wparam,\n                                  LPARAM const lparam) noexcept;\n\n  // Retrieves a class instance pointer for |window|\n  static Win32Window* GetThisFromHandle(HWND const window) noexcept;\n\n  bool quit_on_close_ = false;\n\n  // window handle for top level window.\n  HWND window_handle_ = nullptr;\n\n  // window handle for hosted content.\n  HWND child_content_ = nullptr;\n};\n\n#endif  // RUNNER_WIN32_WINDOW_H_\n"
  },
  {
    "path": "flutter/todo_cubit_wasm/.gitignore",
    "content": ".DS_Store\n.idea/\n.metadata\n\n## Flutter ###\n# Flutter/Dart/Pub related\n**/doc/api/\n.dart_tool/\n.flutter-plugins\n.flutter-plugins-dependencies\n.fvm/\n.packages\n.pub-cache/\n.pub/\nbuild/\ncoverage/\nlib/generated_plugin_registrant.dart\n# For library packages, don’t commit the pubspec.lock file.\n# Regenerating the pubspec.lock file lets you test your package against the latest compatible versions of its dependencies.\n# See https://dart.dev/guides/libraries/private-files#pubspeclock\n#pubspec.lock\n\n# Android related\n**/android/**/gradle-wrapper.jar\n**/android/.gradle\n**/android/captures/\n**/android/gradlew\n**/android/gradlew.bat\n**/android/key.properties\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/.last_build_id\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# 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\n### Rust ###\n**/target/**\n**/target_wasm/**\n**/Cargo.lock\n\n### Rid ###\n**/generated/**\n**/Classes/bindings.h\n**/macos/*.a\n**/ios/*.a\n**/android/src/main/jniLibs/*\n\n"
  },
  {
    "path": "flutter/todo_cubit_wasm/Cargo.toml",
    "content": "[package]\nname = \"todo_cubit\"\nversion = \"0.1.0\"\nauthors = [\"Thorsten Lorenz <thlorenz@gmx.de>\"]\nedition = \"2018\"\n\n[lib]\ncrate-type = [\"cdylib\", \"staticlib\" ]\n\n[[bin]]\nname = \"rid_build\"\npath = \"rid_build.rs\"\n\n[dependencies]\ncbindgen = \"0.18.0\"\nrid_build = { path = \"../../../rid/rid-build\" }\nrid = { path = \"../../../rid\" }\nserde = \"1.0.123\"\nserde_json = \"1.0.64\"\n\n# https://rustwasm.github.io/docs/book/reference/code-size.html\n[profile.release]\nopt-level = 'z'\n"
  },
  {
    "path": "flutter/todo_cubit_wasm/README.md",
    "content": "# todo_cubit\n\nRust integrated Dart Flutter Project\n\n## Getting Started\n\nUse the below scripts to get the app ready to run with Flutter.\n\n### 1. Generate Glue Code\n\n```sh\n./sh/bindgen\n```\n\n### 2. Build For Desired Target/Device\n\nRun any of the below three to build the binary for the specific device and have it placed into\nthe devices specific plugin folder.\n\n```sh\n./sh/macos\n```\n\n### 3. Run with Flutter\n\nRun on the device.\n\n```sh\nflutter run -d macos\n```\n\n### 4. Develop\n\nRun step `1` whenever a function exposed to Flutter changes.\n\nRun step `2` whenever any of your Rust code changes.\n\n**Note** that to apply changes from Rust you need to restart the app to reload the compiled binary.\nA hot restart/reload does not achieve this.\n\n## Folder Structure\n\n```\n├── android\n├── ios\n├── macos\n├── lib\n├── plugin\n│   ├── android\n│   ├── ios\n│   ├── macos\n│   └── lib\n└── src\n```\n\n### `./plugin`\n\nProvides connection from Flutter to Rust.\n\nRust binaries are placed into the respective plugin folders `./ios, ./macos, ./android` when\nthey are built.\n\nGenerated Dart glue code is placed inside `./plugin/lib/generated` while\n`./plugin/lib/plugin.dart` just exposes the API to the app.\n\n### `./src`\n\nContains the starter Rust code inside `./src/lib.rs`. Keep developing the Rust part of your app\nhere.\n\n### `./lib`\n\nContains the starter Flutter app inside `./lib/main.dart`.\n\n### `./sh`\n\nProvides scripts to run build and code generation tasks. In the future a tool will provide the\nfunctionality currently provided by these scripts.\n\n- `bindgen` generates the `binding.h` header file for the extern Rust functions found inside\n  `./src`. These are then placed inside the `./plugin` device folders were needed as well as\n  `./plugin/lib/generated/binding.h` where they are used to generate Dart glue code\n  - as part of this script `ffigen` generates Dart glue code inside\n    `./plugin/lib/generated/ffigen_binding.dart` using `./plugin/lib/generated/binding.h` as input\n- `./android` builds the Rust binary to run on Android devices/emulators and places it inside\n  `./plugin/lib/android`\n- `./ios` builds the Rust binary to run on IOS devices/emulators and places it inside\n  `./plugin/lib/ios`\n- `./macos` builds the Rust binary to run on MacOs directly and places it inside\n  `./plugin/lib/macos`, this is the same format as running `cargo build` on your Mac\n- `clean` cleans both the Flutter plugin and application, run this to reset Flutter when things\n  aren't working\n"
  },
  {
    "path": "flutter/todo_cubit_wasm/analysis_options.yaml",
    "content": "# This file configures the analyzer, which statically analyzes Dart code to\n# check for errors, warnings, and lints.\n#\n# The issues identified by the analyzer are surfaced in the UI of Dart-enabled\n# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be\n# invoked from the command line by running `flutter analyze`.\n\n# The following line activates a set of recommended lints for Flutter apps,\n# packages, and plugins designed to encourage good coding practices.\ninclude: package:flutter_lints/flutter.yaml\n\nlinter:\n  # The lint rules applied to this project can be customized in the\n  # section below to disable rules from the `package:flutter_lints/flutter.yaml`\n  # included above or to enable additional rules. A list of all available lints\n  # and their documentation is published at\n  # https://dart-lang.github.io/linter/lints/index.html.\n  #\n  # Instead of disabling a lint rule for the entire project in the\n  # section below, it can also be suppressed for a single line of code\n  # or a specific dart file by using the `// ignore: name_of_lint` and\n  # `// ignore_for_file: name_of_lint` syntax on the line or in the file\n  # producing the lint.\n  rules:\n    # avoid_print: false  # Uncomment to disable the `avoid_print` rule\n    # prefer_single_quotes: true  # Uncomment to enable the `prefer_single_quotes` rule\n\n# Additional information about this file can be found at\n# https://dart.dev/guides/language/analysis-options\n"
  },
  {
    "path": "flutter/todo_cubit_wasm/lib/blocs/cubit/filter_cubit.dart",
    "content": "import 'package:bloc/bloc.dart';\nimport 'package:plugin/generated/rid_api.dart';\n\nclass FilterCubit extends Cubit<Filter> {\n  final Store _store = Store.instance;\n  FilterCubit() : super(Store.instance.filter);\n\n  Future<void> setFilter(Filter filter) async {\n    await _store.msgSetFilter(filter);\n    emit(_store.filter);\n  }\n}\n"
  },
  {
    "path": "flutter/todo_cubit_wasm/lib/blocs/cubit/settings_cubit.dart",
    "content": "import 'package:bloc/bloc.dart';\nimport 'package:plugin/generated/rid_api.dart';\n\nclass SettingsCubit extends Cubit<Settings> {\n  final Store _store = Store.instance;\n  SettingsCubit() : super(Store.instance.settings);\n\n  Future<void> setAutoExpireCompleted(bool val) async {\n    await _store.msgSetAutoExpireCompletedTodos(val);\n    emit(_store.settings);\n  }\n}\n"
  },
  {
    "path": "flutter/todo_cubit_wasm/lib/blocs/cubit/todo_cubit.dart",
    "content": "import 'dart:async';\n\nimport 'package:bloc/bloc.dart';\nimport 'package:flutter/foundation.dart';\nimport 'package:meta/meta.dart';\nimport 'package:plugin/generated/rid_api.dart';\n\npart 'todo_state.dart';\n\nclass TodoCubit extends Cubit<TodoState> {\n  final Store _store = Store.instance;\n  late final StreamSubscription<PostedReply> tickSub;\n  TodoCubit(Todo todo) : super(ExistingTodo(todo)) {\n    _subscribe();\n  }\n\n  // Reply.Tick is a reply that includes data, in this case the id\n  // of the completed todo whose life is ticking away\n  bool _tickIsForThisTodo(PostedReply reply) {\n    // We make sure that the data is a parseable int id\n    assert(\n      reply.data != null,\n      'Reply.Tick should include data containing the id of the ticked todo',\n    );\n    final id = int.tryParse(reply.data!);\n    assert(id != null, 'Reply.Tick included invalid id ${reply.data}');\n    return id == state.id;\n  }\n\n  void _subscribe() {\n    tickSub = rid.replyChannel.stream\n        .where((x) => x.type == Reply.Tick && _tickIsForThisTodo(x))\n        .listen(_refreshState);\n  }\n\n  @override\n  Future<void> close() {\n    tickSub.cancel();\n    return super.close();\n  }\n\n  void _refreshState(PostedReply _reply) async {\n    final todo = _store.todoById(state.id);\n    if (todo == null) {\n      emit(MissingTodo(state.id));\n    } else {\n      emit(ExistingTodo(todo));\n    }\n  }\n\n  Future<void> toggleCompleted() =>\n      _store.msgToggleTodo(state.id).then(_refreshState);\n\n  Future<void> removeTodo(int id) =>\n      _store.msgRemoveTodo(id).then(_refreshState);\n}\n"
  },
  {
    "path": "flutter/todo_cubit_wasm/lib/blocs/cubit/todo_state.dart",
    "content": "part of 'todo_cubit.dart';\n\n@immutable\nabstract class TodoState {\n  final int id;\n\n  TodoState(this.id);\n\n  @override\n  bool operator ==(Object other) =>\n      identical(this, other) || other is TodoState && other.id == id;\n\n  @override\n  int get hashCode => id;\n}\n\nclass ExistingTodo extends TodoState {\n  final Todo todo;\n\n  ExistingTodo(this.todo) : super(todo.id);\n\n  @override\n  bool operator ==(Object other) =>\n      identical(this, other) || other is ExistingTodo && other.todo == todo;\n\n  @override\n  int get hashCode => todo.hashCode;\n}\n\nclass MissingTodo extends TodoState {\n  MissingTodo(int id) : super(id);\n\n  @override\n  bool operator ==(Object other) =>\n      identical(this, other) || other is MissingTodo && other.id == id;\n\n  @override\n  int get hashCode => super.hashCode;\n}\n"
  },
  {
    "path": "flutter/todo_cubit_wasm/lib/blocs/cubit/todos_cubit.dart",
    "content": "import 'dart:async';\n\nimport 'package:bloc/bloc.dart';\nimport 'package:flutter/foundation.dart';\nimport 'package:meta/meta.dart';\nimport 'package:plugin/generated/rid_api.dart';\n\npart 'todos_state.dart';\n\nclass TodosCubit extends Cubit<TodosState> {\n  late final StreamSubscription<PostedReply> removedTodosSub;\n  final Store _store = Store.instance;\n\n  TodosCubit() : super(TodosState(Store.instance.filteredTodos())) {\n    _subscribe();\n  }\n\n  void _subscribe() {\n    removedTodosSub = rid.replyChannel.stream\n        .where((x) =>\n            x.type == Reply.RemovedTodo ||\n            x.type == Reply.RemovedCompleted ||\n            x.type == Reply.CompletedTodoExpired ||\n            x.type == Reply.SetFilter)\n        .listen(_refreshList);\n  }\n\n  @override\n  Future<void> close() async {\n    await removedTodosSub.cancel();\n    return super.close();\n  }\n\n  void _refreshList(PostedReply _reply) async {\n    final todos = _store.filteredTodos();\n    emit(TodosState(todos));\n    debugPrint('${_store.raw.debug(true)}');\n  }\n\n  Future<void> addTodo(String title) =>\n      _store.msgAddTodo(title).then(_refreshList);\n\n  Future<void> restartAll() => _store.msgRestartAll().then(_refreshList);\n  Future<void> completeAll() => _store.msgCompleteAll().then(_refreshList);\n  Future<void> removeCompleted() =>\n      _store.msgRemoveCompleted().then(_refreshList);\n}\n"
  },
  {
    "path": "flutter/todo_cubit_wasm/lib/blocs/cubit/todos_state.dart",
    "content": "part of 'todos_cubit.dart';\n\n@immutable\nclass TodosState {\n  final List<Todo> todos;\n  const TodosState(this.todos);\n\n  @override\n  bool operator ==(Object other) =>\n      identical(this, other) || other is TodosState && other.todos == todos;\n\n  @override\n  int get hashCode => todos.hashCode;\n}\n"
  },
  {
    "path": "flutter/todo_cubit_wasm/lib/main.dart",
    "content": "import 'dart:async';\n\nimport 'package:flutter/material.dart';\nimport 'package:flutter_bloc/flutter_bloc.dart';\nimport 'package:plugin/generated/rid_api.dart';\nimport 'package:todo_cubit/blocs/cubit/filter_cubit.dart';\nimport 'package:todo_cubit/blocs/cubit/settings_cubit.dart';\nimport 'package:todo_cubit/blocs/cubit/todos_cubit.dart';\nimport 'package:todo_cubit/views/menu.dart';\nimport 'package:todo_cubit/views/todos.dart';\n\nconst Color FILTER_SELECTED_COLOR = Colors.blue;\nconst Color FILTER_UNSELECTED_COLOR = Colors.black;\n\nvoid configRid() {\n  rid.debugReply = (reply) => debugPrint('$reply');\n}\n\nconst WASM_FILE = 'todo_cubit.wasm';\nvoid main() async {\n  // HTTP_HOST = 'localhost:8080';\n  await initWasm(WASM_FILE);\n  debugPrint(rid_ffi.toString());\n  configRid();\n  // await diagnose();\n  runApp(TodoApp());\n}\n\nclass TodoApp extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return MaterialApp(\n      title: 'Rust/Flutter Cubit Todo App',\n      theme: ThemeData(\n        primarySwatch: Colors.blue,\n      ),\n      home: MultiBlocProvider(\n        providers: [\n          BlocProvider<SettingsCubit>(create: (_) => SettingsCubit()),\n          BlocProvider<TodosCubit>(create: (_) => TodosCubit()),\n          BlocProvider<FilterCubit>(create: (_) => FilterCubit())\n        ],\n        child: TodosPage(title: 'Cubit Todo App'),\n      ),\n      debugShowCheckedModeBanner: false,\n    );\n  }\n}\n\nclass TodosPage extends StatefulWidget {\n  final String title;\n  TodosPage({Key? key, required this.title}) : super(key: key);\n\n  @override\n  _TodosPageState createState() => _TodosPageState();\n}\n\nclass _TodosPageState extends State<TodosPage> {\n  final _textFieldController = TextEditingController();\n  String? addTodoTitle;\n\n  @override\n  Widget build(BuildContext context) {\n    final filter = context.watch<FilterCubit>().state;\n\n    return SafeArea(\n      child: Scaffold(\n        appBar: AppBar(\n          title: Row(\n            mainAxisAlignment: MainAxisAlignment.spaceBetween,\n            children: [\n              Text(widget.title),\n              Row(\n                children: [\n                  Image.asset(\n                    \"assets/dash.png\",\n                    height: 40.0,\n                    width: 40.0,\n                  ),\n                  Icon(Icons.favorite, color: Colors.red),\n                  Image.asset(\n                    \"assets/ferris.png\",\n                    height: 50.0,\n                    width: 50.0,\n                  ),\n                ],\n              )\n            ],\n          ),\n        ),\n        drawer: Drawer(child: Menu()),\n        bottomNavigationBar: BottomAppBar(\n          child: Row(\n            children: <Widget>[\n              IconButton(\n                  icon: Icon(\n                    Icons.calendar_today_rounded,\n                    color: filter == Filter.Pending\n                        ? FILTER_SELECTED_COLOR\n                        : FILTER_UNSELECTED_COLOR,\n                  ),\n                  onPressed: () =>\n                      context.read<FilterCubit>().setFilter(Filter.Pending)),\n              Spacer(),\n              IconButton(\n                  icon: Icon(\n                    Icons.check,\n                    color: filter == Filter.Completed\n                        ? FILTER_SELECTED_COLOR\n                        : FILTER_UNSELECTED_COLOR,\n                  ),\n                  onPressed: () =>\n                      context.read<FilterCubit>().setFilter(Filter.Completed)),\n              IconButton(\n                  icon: Icon(\n                    Icons.all_inclusive,\n                    color: filter == Filter.All\n                        ? FILTER_SELECTED_COLOR\n                        : FILTER_UNSELECTED_COLOR,\n                  ),\n                  onPressed: () =>\n                      context.read<FilterCubit>().setFilter(Filter.All)),\n            ],\n          ),\n        ),\n        body: TodosView(),\n        floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,\n        floatingActionButton: FloatingActionButton(\n          onPressed: () async {\n            _textFieldController.clear();\n            await _addTodoDialog(context);\n            final title = addTodoTitle;\n            if (title != null && title.trim().isNotEmpty) {\n              context.read<TodosCubit>().addTodo(title);\n            }\n          },\n          tooltip: 'Add Todo',\n          child: Icon(Icons.add),\n        ),\n      ),\n    );\n  }\n\n  Future<void> _addTodoDialog(BuildContext context) async {\n    return showDialog(\n        context: context,\n        builder: (context) {\n          return AlertDialog(\n            title: Text('Enter Todo Title'),\n            content: TextField(\n              controller: _textFieldController,\n              decoration: InputDecoration(hintText: \"Todo title\"),\n              autofocus: true,\n            ),\n            actions: <Widget>[\n              TextButton(\n                child: Text('Done'),\n                onPressed: () {\n                  addTodoTitle = _textFieldController.value.text;\n                  Navigator.pop(context);\n                },\n              ),\n            ],\n          );\n        });\n  }\n}\n"
  },
  {
    "path": "flutter/todo_cubit_wasm/lib/views/expiry.dart",
    "content": "import 'package:flutter/material.dart';\n\nColor expiryColor(double completedExpiryMillis, double remaining) {\n  return remaining > completedExpiryMillis * 0.80\n      ? Colors.greenAccent\n      : remaining > completedExpiryMillis * 0.60\n          ? Colors.green\n          : remaining > completedExpiryMillis * 0.4\n              ? Colors.orange\n              : remaining > completedExpiryMillis * 0.2\n                  ? Colors.redAccent\n                  : Colors.red;\n}\n\nclass ExpiryWidget extends StatelessWidget {\n  final double completedExpiryMillis;\n  final double remainingMillis;\n\n  const ExpiryWidget({\n    required this.completedExpiryMillis,\n    required this.remainingMillis,\n  }) : super();\n\n  Widget build(BuildContext context) {\n    final totalWidth = MediaQuery.of(context).size.width * 0.8;\n    final expiryWidth = (remainingMillis / completedExpiryMillis) * totalWidth;\n    return Container(\n      height: 10,\n      width: totalWidth,\n      decoration: BoxDecoration(\n        border: Border.all(\n          color: Colors.blueGrey,\n          width: 1.0,\n          style: BorderStyle.solid,\n        ),\n        borderRadius: BorderRadius.all(Radius.circular(2.0)),\n      ),\n      child: Container(\n        margin: EdgeInsets.only(right: totalWidth - expiryWidth),\n        color: expiryColor(completedExpiryMillis, remainingMillis),\n      ),\n    );\n  }\n}\n"
  },
  {
    "path": "flutter/todo_cubit_wasm/lib/views/menu.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:flutter/widgets.dart';\nimport 'package:flutter_bloc/flutter_bloc.dart';\nimport 'package:todo_cubit/blocs/cubit/settings_cubit.dart';\nimport 'package:todo_cubit/blocs/cubit/todos_cubit.dart';\n\nclass Menu extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return ListView(\n      padding: EdgeInsets.zero,\n      children: <Widget>[\n        ListTile(title: Text('Todo Actions')),\n        Divider(),\n        ListTile(\n          title: Text('Restart All'),\n          onTap: () => context.read<TodosCubit>().restartAll(),\n        ),\n        ListTile(\n          title: Text('Complete All'),\n          onTap: () => context.read<TodosCubit>().completeAll(),\n        ),\n        ListTile(\n          title: Text('Remove Completed'),\n          onTap: () => context.read<TodosCubit>().removeCompleted(),\n        ),\n      ],\n    );\n  }\n}\n\nclass AutoRemoveCompletedWidget extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Checkbox(\n      value: context.select<SettingsCubit, bool>(\n        (x) => x.state.autoExpireCompletedTodos,\n      ),\n      onChanged: (val) {\n        if (val != null)\n          context.read<SettingsCubit>().setAutoExpireCompleted(val);\n      },\n    );\n  }\n}\n"
  },
  {
    "path": "flutter/todo_cubit_wasm/lib/views/todo.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:flutter_bloc/flutter_bloc.dart';\nimport 'package:plugin/generated/rid_api.dart';\nimport 'package:todo_cubit/blocs/cubit/settings_cubit.dart';\nimport 'package:todo_cubit/blocs/cubit/todo_cubit.dart';\nimport 'package:todo_cubit/views/expiry.dart';\n\nclass TodoView extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return BlocBuilder<TodoCubit, TodoState>(builder: (context, state) {\n      if (state is MissingTodo) {\n        return Text('Todo ${state.id} missing, most likely removed');\n      }\n      if (state is ExistingTodo) {\n        final todo = state.todo;\n        return Dismissible(\n          key: Key(\"Todo Dismissible ${todo.id}\"),\n          child: Card(\n            child: InkWell(\n              onTap: () => context.read<TodoCubit>().toggleCompleted(),\n              child: ListTile(\n                leading: todo.completed\n                    ? Icon(Icons.check, color: Colors.green)\n                    : Icon(Icons.calendar_today_rounded),\n                title: Text('${todo.title}'),\n                subtitle: BlocBuilder<SettingsCubit, Settings>(\n                  builder: (context, settings) {\n                    return settings.autoExpireCompletedTodos && todo.completed\n                        ? ExpiryWidget(\n                            completedExpiryMillis:\n                                settings.completedExpiryMillis.toDouble(),\n                            remainingMillis: todo.expiryMillis.toDouble(),\n                          )\n                        : Container();\n                  },\n                ),\n              ),\n            ),\n          ),\n          direction: DismissDirection.endToStart,\n          // Make sure we removed the Todo and got the reply before updating the UI\n          confirmDismiss: (_) =>\n              context.read<TodoCubit>().removeTodo(todo.id).then((_) => true),\n          background: Padding(\n            padding: EdgeInsets.all(5.0),\n            child: Container(color: Colors.red),\n          ),\n        );\n      } else {\n        return Text('Unkown TodoState type $state');\n      }\n    });\n  }\n}\n"
  },
  {
    "path": "flutter/todo_cubit_wasm/lib/views/todos.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:todo_cubit/blocs/cubit/todo_cubit.dart';\nimport 'package:todo_cubit/blocs/cubit/todos_cubit.dart';\nimport 'package:todo_cubit/views/todo.dart';\nimport 'package:flutter_bloc/flutter_bloc.dart';\n\nclass TodosView extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return Center(\n      child: BlocBuilder<TodosCubit, TodosState>(builder: (context, state) {\n        final todos = state.todos;\n        return ListView.builder(\n            itemCount: todos.length,\n            itemBuilder: (context, index) {\n              final todo = todos[index];\n              return BlocProvider(\n                create: (_) => TodoCubit(todo),\n                child: TodoView(),\n                key: Key(todo.hashCode.toString()),\n              );\n            });\n      }),\n    );\n  }\n}\n"
  },
  {
    "path": "flutter/todo_cubit_wasm/plugin/.gitignore",
    "content": ".DS_Store\n.dart_tool/\n\n.packages\n.pub/\n\nbuild/\n"
  },
  {
    "path": "flutter/todo_cubit_wasm/plugin/LICENSE",
    "content": "TODO: Add your license here.\n"
  },
  {
    "path": "flutter/todo_cubit_wasm/plugin/analysis_options.yaml",
    "content": "include: package:flutter_lints/flutter.yaml\n\n# Additional information about this file can be found at\n# https://dart.dev/guides/language/analysis-options\n"
  },
  {
    "path": "flutter/todo_cubit_wasm/plugin/lib/wasm/reply_channel.dart",
    "content": "import 'dart:async';\nimport '../generated/rid_api.dart';\n\nconst String RESPONSE_SEPARATOR = '^';\n\nabstract class IReply {\n  int? get reqId;\n  String? get data;\n}\n\ntypedef Decode<TReply> = TReply Function(ReplyStruct reply);\n\n// TODO: error handling (could be part of Post data)\nclass ReplyChannel<TReply extends IReply> {\n  final _zone = Zone.current;\n  final StreamController<TReply> _sink;\n  final Decode<TReply> _decode;\n  final NativeLibrary _dl;\n  late final _zonedAdd;\n  late final Timer _pollTimer;\n  int _lastReqId = 0;\n\n  ReplyChannel._(this._dl, this._decode, bool isDebugMode)\n      : _sink = StreamController.broadcast() {\n    _zonedAdd = _zone.registerUnaryCallback(_add);\n    _pollReplies();\n  }\n\n  void _pollReplies() {\n    _pollTimer = Timer.periodic(Duration(milliseconds: 100), (_) {\n      // TODO: ugly hack to prevent printing polling logs for now\n      final save = rid.debugLock;\n      rid.debugLock = null;\n      // TODO: need to Readlock replies\n      final ptr = _dl.rid_poll_reply();\n      final castPtr = Pointer.fromAddress(RawReplyStruct(ptr.address));\n      final reply = ptr.address == 0x0 ? null : castPtr.toDart();\n      rid.debugLock = save;\n      if (reply != null) {\n        _onReceivedReply(reply);\n        _dl.rid_handled_reply(reply.reqId);\n      }\n    });\n  }\n\n  void _onReceivedReply(ReplyStruct reply) {\n    _zone.runUnary(_zonedAdd, reply);\n  }\n\n  void _add(ReplyStruct reply) {\n    if (!_sink.isClosed) {\n      _sink.add(_decode(reply));\n    }\n  }\n\n  Stream<TReply> get stream => _sink.stream;\n  Future<TReply> reply(int reqId) {\n    assert(reqId != 0, \"Invalid requestID \");\n    return stream.firstWhere((reply) {\n      final replyId = reply.reqId;\n      if (replyId == null) return false;\n      return reqId == replyId;\n    }).onError((error, stackTrace) {\n      print(\n          \"The responseChannel was disposed while a message was waiting for a reply.\\n\"\n          \"Did you forget to `await` the reply to the message with reqId: '$reqId'?\\n\"\n          \"Ignore the message further down about type 'Null'.\\n\"\n          \"The real problem is that no reply for the message was posted yet, but the reply \\n\"\n          \"stream is being disposed most likely via `store.dispose()` causing the following:.\\n\");\n      print(error);\n      print(stackTrace);\n      return null as TReply;\n    });\n  }\n\n  int get reqId {\n    _lastReqId++;\n    return _lastReqId;\n  }\n\n  Future<void> dispose() {\n    if (_pollTimer.isActive) _pollTimer.cancel();\n    return _sink.close();\n  }\n\n  static bool _initialized = false;\n  static ReplyChannel<TReply> instance<TReply extends IReply>(\n    NativeLibrary dl,\n    Decode<TReply> decode,\n    bool isDebugMode,\n  ) {\n    if (_initialized && !isDebugMode) {\n      throw Exception(\n          \"The reply channel can only be initialized once unless running in debug mode\");\n    }\n    _initialized = true;\n    return ReplyChannel<TReply>._(dl, decode, isDebugMode);\n  }\n}\n"
  },
  {
    "path": "flutter/todo_cubit_wasm/plugin/lib/wasm/utils.dart",
    "content": "import 'dart:html';\nimport 'dart:typed_data';\n\nimport 'package:flutter/services.dart';\nimport 'package:universal_io/io.dart';\n\nString HTTP_ROOT = window.location.href.replaceFirst(RegExp('#/\\$'), '');\nFuture<Uint8List> loadWasmFromNetwork(String wasmFile) async {\n  final path = '$HTTP_ROOT/$wasmFile';\n  try {\n    // http-server --cors\n    final httpClient = HttpClient();\n    final request = await httpClient.getUrl(Uri.parse(path));\n    if (request is BrowserHttpClientRequest) {\n      request.browserResponseType = 'arraybuffer';\n    }\n    final response = await request.close();\n    final list = await response.toList().then((List<List<int>> lists) {\n      return lists.fold<List<int>>(<int>[], (List<int> acc, List<int> list) {\n        acc.addAll(list);\n        return acc;\n      });\n    });\n    return Uint8List.fromList(list);\n  } catch (e) {\n    print(e);\n    print(\"Couldn't open $path\");\n    return Uint8List.fromList([]);\n  }\n}\n\n// This is currently not working for web apps\n// It may be useful once we support Wasm for non-web apps\nFuture<Uint8List> loadWasmAsset(String wasmAsset) async {\n  return rootBundle.load(wasmAsset).then((bytes) => bytes.buffer.asUint8List());\n}\n"
  },
  {
    "path": "flutter/todo_cubit_wasm/plugin/plugin.iml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<module type=\"JAVA_MODULE\" version=\"4\">\n  <component name=\"NewModuleRootManager\" inherit-compiler-output=\"true\">\n    <exclude-output />\n    <content url=\"file://$MODULE_DIR$\">\n      <sourceFolder url=\"file://$MODULE_DIR$/lib\" isTestSource=\"false\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/.dart_tool\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/.idea\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/.pub\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/example/.pub\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/example/build\" />\n    </content>\n    <orderEntry type=\"sourceFolder\" forTests=\"false\" />\n    <orderEntry type=\"library\" name=\"Dart Packages\" level=\"project\" />\n    <orderEntry type=\"library\" name=\"Dart SDK\" level=\"project\" />\n    <orderEntry type=\"library\" name=\"Flutter Plugins\" level=\"project\" />\n  </component>\n</module>"
  },
  {
    "path": "flutter/todo_cubit_wasm/plugin/pubspec.yaml",
    "content": "name: plugin\ndescription: Plugin to provide a bridge to Rust.\nversion: 0.0.1\n\nenvironment:\n  sdk: \">=2.13.0 <=3.0.0\"\n  flutter: \">=2.0.0\"\n\nwasmjsgen:\n  comments: false\n  allocate: 'rid_malloc'\n  deallocate: 'rid_free'\n  reallocate: 'rid_realloc'\n  output: 'lib/generated/ffigen_binding.dart'\n  headers:\n    entry-points:\n      - 'lib/generated/bindings.h'\n\nffigen:\n  name: plugin\n  description: Plugin to provide a bridge to Rust.\n  output: 'lib/generated/nativ_binding.dart'\n  headers:\n    entry-points:\n      - 'lib/generated/bindings.h'\n\ndependencies:\n  ffi: ^1.0.0\n  wasm_interop: ^2.0.0\n\n  flutter:\n    sdk: flutter\n  universal_io: ^2.0.4\n\ndev_dependencies: \n  wasmjsgen: ^0.0.4\n\nflutter:\n  # This section identifies this Flutter project as a plugin project.\n  # The 'pluginClass' and Android 'package' identifiers should not ordinarily\n  # be modified. They are used by the tooling to maintain consistency when\n  # adding or updating assets for this project.\n  plugin:\n    platforms:\n      android:\n        package: com.example.plugin\n        pluginClass: Plugin\n      ios:\n        pluginClass: Plugin\n      macos:\n        pluginClass: Plugin\n"
  },
  {
    "path": "flutter/todo_cubit_wasm/pubspec.yaml",
    "content": "name: todo_cubit\ndescription: A new Flutter project.\n\npublish_to: 'none' # Remove this line if you wish to publish to pub.dev\n\nversion: 1.0.0+1\n\nenvironment:\n  sdk: \">=2.13.0 <3.0.0\"\n\ndependencies:\n  flutter:\n    sdk: flutter\n\n  plugin:\n    path: plugin\n\n  bloc: ^7.0.0\n  flutter_bloc: ^7.0.1\n  provider: ^5.0.0\n\ndev_dependencies:\n  flutter_test:\n    sdk: flutter\n\nflutter:\n\n  uses-material-design: true\n\n  assets:\n    - assets/dash.png\n    - assets/ferris.png\n"
  },
  {
    "path": "flutter/todo_cubit_wasm/rid_build.rs",
    "content": "use rid_build::{build, BuildConfig, BuildTarget, FlutterConfig, Project};\nuse std::env;\n\nfn main() {\n    let crate_dir = env::var(\"CARGO_MANIFEST_DIR\")\n        .expect(\"Missing CARGO_MANIFEST_DIR, please run this via 'cargo run'\");\n\n    let workspace_dir = &crate_dir;\n\n    let crate_name = &env::var(\"CARGO_PKG_NAME\")\n        .expect(\"Missing CARGO_PKG_NAME, please run this via 'cargo run'\");\n    let lib_name = &format!(\"lib{}\", &crate_name);\n\n    let build_config = BuildConfig {\n        target: BuildTarget::Debug,\n        project: Project::Flutter(FlutterConfig {\n            plugin_name: \"plugin\".to_string(),\n            // TODO: once rid itself supports WASM we need to add web architecture here\n            platforms: vec![],\n        }),\n        lib_name,\n        crate_name,\n        project_root: &crate_dir,\n        workspace_root: Some(&workspace_dir),\n    };\n    build(&build_config).expect(\"Build failed\");\n}\n"
  },
  {
    "path": "flutter/todo_cubit_wasm/sh/build-web",
    "content": "#!/usr/bin/env bash\n\nDIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" >/dev/null 2>&1 && pwd )\"\n\nflutter build web --web-renderer html --base-href=/rid-examples/todo_cubit/\n$DIR/wasm-release\n"
  },
  {
    "path": "flutter/todo_cubit_wasm/sh/clean",
    "content": "#!/usr/bin/env bash\n\nDIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" >/dev/null 2>&1 && pwd )\"\n\n(cd $DIR/../plugin && flutter clean && flutter pub get)\n(cd $DIR/.. && flutter clean && flutter pub get)\n"
  },
  {
    "path": "flutter/todo_cubit_wasm/sh/debug-web",
    "content": "#!/usr/bin/env bash\n\nDIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" >/dev/null 2>&1 && pwd )\"\n\nflutter build web --web-renderer html --profile --dart-define=Dart2jsOptimization=O0\n$DIR/wasm-release\n\n(cd $DIR/../build/web && http-server)\n"
  },
  {
    "path": "flutter/todo_cubit_wasm/sh/wasm",
    "content": "#!/usr/bin/env bash\n\nDIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" >/dev/null 2>&1 && pwd )\"\nROOT=$DIR/..\n\ncargo build --target wasm32-unknown-unknown --lib --target-dir target_wasm\n\nmv $ROOT/target_wasm/wasm32-unknown-unknown/debug/todo_cubit.wasm  $ROOT/todo_cubit.wasm\n"
  },
  {
    "path": "flutter/todo_cubit_wasm/sh/wasm-release",
    "content": "#!/usr/bin/env bash\n\nDIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" >/dev/null 2>&1 && pwd )\"\nROOT=$DIR/..\n\ncargo build --release --target wasm32-unknown-unknown --lib --target-dir target_wasm \n\n# https://rustwasm.github.io/docs/book/reference/code-size.html#use-the-wasm-opt-tool\nWASM_INTERFACE_TYPES=1 wasm-opt -Oz -o   \\\n  $ROOT/todo_cubit.wasm \\\n  $ROOT/target_wasm/wasm32-unknown-unknown/release/todo_cubit.wasm  \n\ncp $ROOT/todo_cubit.wasm $ROOT/build/web/todo_cubit.wasm\n"
  },
  {
    "path": "flutter/todo_cubit_wasm/sh/wasmgen",
    "content": "#!/usr/bin/env bash\n\nDIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" >/dev/null 2>&1 && pwd )\"\n\nROOT=$DIR/..\n\ncd $ROOT && cargo run rid_build && \\\ncd $ROOT/plugin && flutter pub run wasmjsgen --verbose severe\ncp $ROOT/plugin/lib/generated/rid_api.sav.dart $ROOT/plugin/lib/generated/rid_api.dart \n"
  },
  {
    "path": "flutter/todo_cubit_wasm/src/alloc.rs",
    "content": "// https://radu-matei.com/blog/practical-guide-to-wasm-memory/\n// https://github.com/rustwasm/wasm-bindgen/blob/eb855e3fd48188bef6bbea8180102f5fe550a0e5/src/lib.rs#L969-L1026\n\n// TODO: look into this hack to get it included in the binary (possibly also into bindings?)\n// https://github.com/rustwasm/wasm-bindgen/blob/eb855e3fd48188bef6bbea8180102f5fe550a0e5/src/lib.rs#L1028-L1063\nmod __rid_malloc_methods {\n    use std::alloc::{alloc, dealloc, realloc, Layout};\n    use std::mem;\n\n    #[no_mangle]\n    pub extern \"C\" fn rid_malloc(size: usize) -> *mut u8 {\n        let align = mem::align_of::<usize>();\n        if let Ok(layout) = Layout::from_size_align(size, align) {\n            unsafe {\n                if layout.size() > 0 {\n                    let ptr = alloc(layout);\n                    if !ptr.is_null() {\n                        return ptr;\n                    }\n                } else {\n                    return align as *mut u8;\n                }\n            }\n        }\n\n        malloc_failure();\n    }\n\n    #[no_mangle]\n    pub unsafe extern \"C\" fn rid_realloc(\n        ptr: *mut u8,\n        old_size: usize,\n        new_size: usize,\n    ) -> *mut u8 {\n        let align = mem::align_of::<usize>();\n        debug_assert!(old_size > 0);\n        debug_assert!(new_size > 0);\n        if let Ok(layout) = Layout::from_size_align(old_size, align) {\n            let ptr = realloc(ptr, layout, new_size);\n            if !ptr.is_null() {\n                return ptr;\n            }\n        }\n        malloc_failure();\n    }\n\n    #[cold]\n    fn malloc_failure() -> ! {\n        std::process::abort();\n    }\n\n    #[no_mangle]\n    pub unsafe extern \"C\" fn rid_free(ptr: *mut u8, size: usize) {\n        // This happens for zero-length slices, and in that case `ptr` is\n        // likely bogus so don't actually send this to the system allocator\n        if size == 0 {\n            return;\n        }\n        let align = mem::align_of::<usize>();\n        let layout = Layout::from_size_align_unchecked(size, align);\n        dealloc(ptr, layout);\n    }\n}\n"
  },
  {
    "path": "flutter/todo_cubit_wasm/src/lib.rs",
    "content": "mod alloc;\nmod replies;\n\nuse rid::RidStore;\nuse serde::Serialize;\n\nconst COMPLETED_EXPIRY_MILLIS: u64 = 7000;\n\n// -----------------\n// Store\n// -----------------\n#[rid::store]\n#[rid::structs(Todo, Settings)]\n#[rid::enums(Filter)]\n#[derive(Debug)]\npub struct Store {\n    last_added_id: u32,\n    todos: Vec<Todo>,\n    filter: Filter,\n    settings: Settings,\n}\n\nimpl RidStore<Msg> for Store {\n    fn create() -> Self {\n        let first_todo = Todo {\n            id: 0,\n            title: \"Learn Flutter\".to_string(),\n            completed: true,\n            expiry_millis: COMPLETED_EXPIRY_MILLIS,\n        };\n        let second_todo = Todo {\n            id: 1,\n            title: \"Learn Rust\".to_string(),\n            completed: true,\n            expiry_millis: COMPLETED_EXPIRY_MILLIS,\n        };\n        let third_todo = Todo {\n            id: 2,\n            title: \"Learn Rid\".to_string(),\n            completed: false,\n            expiry_millis: COMPLETED_EXPIRY_MILLIS,\n        };\n        let fourth_todo = Todo {\n            id: 3,\n            title: \"Build Awesome Apps\".to_string(),\n            completed: false,\n            expiry_millis: COMPLETED_EXPIRY_MILLIS,\n        };\n        Self {\n            last_added_id: 3,\n            todos: vec![first_todo, second_todo, third_todo, fourth_todo],\n            filter: Filter::All,\n            settings: Settings {\n                auto_expire_completed_todos: false,\n                completed_expiry_millis: COMPLETED_EXPIRY_MILLIS,\n            },\n        }\n    }\n\n    fn update(&mut self, req_id: u64, msg: Msg) {\n        use Msg::*;\n        match msg {\n            AddTodo(title) => {\n                self.last_added_id += 1;\n                let todo = Todo {\n                    id: self.last_added_id,\n                    title,\n                    completed: false,\n                    expiry_millis: COMPLETED_EXPIRY_MILLIS,\n                };\n                self.todos.push(todo);\n                replies::post(Reply::AddedTodo(req_id, self.last_added_id.to_string()));\n            }\n            RemoveTodo(id) => {\n                self.remove_todo(id);\n                replies::post(Reply::RemovedTodo(req_id, self.last_added_id.to_string()));\n            }\n\n            RemoveCompleted => {\n                self.todos.retain(|todo| !todo.completed);\n                replies::post(Reply::RemovedCompleted(req_id));\n            }\n\n            CompleteTodo(id) => {\n                self.update_todo(id, |todo| todo.set_completed(true));\n                replies::post(Reply::CompletedTodo(req_id, id.to_string()));\n            }\n            RestartTodo(id) => {\n                self.update_todo(id, |todo| todo.set_completed(false));\n                replies::post(Reply::RestartedTodo(req_id, id.to_string()));\n            }\n            ToggleTodo(id) => {\n                self.update_todo(id, |todo| todo.set_completed(!todo.completed));\n                replies::post(Reply::ToggledTodo(req_id, id.to_string()));\n            }\n\n            CompleteAll => {\n                self.todos.iter_mut().for_each(|x| x.set_completed(true));\n                replies::post(Reply::CompletedAll(req_id));\n            }\n            RestartAll => {\n                self.todos.iter_mut().for_each(|x| x.set_completed(false));\n                replies::post(Reply::RestartedAll(req_id));\n            }\n\n            SetFilter(filter) => {\n                self.filter = filter;\n                replies::post(Reply::SetFilter(req_id));\n            }\n            SetAutoExpireCompletedTodos(_) => {\n                panic!(\"The Auto Expire Todos feature has been disabled in the WASM version\")\n            }\n        };\n    }\n}\n\n#[rid::export]\n#[rid::structs(Todo)]\nimpl Store {\n    fn remove_todo(&mut self, id: u32) {\n        let mut enumerated = self.todos.iter().enumerate();\n        let idx = match enumerated.find(|(_, todo)| todo.id == id) {\n            Some((idx, _)) => idx,\n            None => return eprintln!(\"Could not find Todo with id '{}'\", id),\n        };\n        self.todos.remove(idx);\n    }\n\n    fn update_todo<F: FnOnce(&mut Todo)>(&mut self, id: u32, update: F) {\n        match self.todos.iter_mut().find(|x| x.id == id) {\n            Some(todo) => update(todo),\n            None => eprintln!(\"Could not find Todo with id '{}'\", id),\n        };\n    }\n\n    fn filtered_todos(&self) -> Vec<&Todo> {\n        let mut vec: Vec<&Todo> = match self.filter {\n            Filter::Completed => self.todos.iter().filter(|x| x.completed).collect(),\n            Filter::Pending => self.todos.iter().filter(|x| !x.completed).collect(),\n            Filter::All => self.todos.iter().collect(),\n        };\n        vec.sort();\n        vec\n    }\n\n    // At this point sending a Vec is not supported in WASM, therefore we work around this\n    // by sending serializing here and deserializing on the Dart side\n    #[rid::export]\n    fn filtered_todos_string(&self) -> String {\n        serde_json::to_string(&self.filtered_todos()).expect(\"Unable JSON stringify filtred todos\")\n    }\n\n    #[rid::export]\n    fn todo_by_id(&self, id: u32) -> Option<&Todo> {\n        self.todos.iter().find(|x| x.id == id)\n    }\n}\n\n// -----------------\n// Settings\n// -----------------\n#[rid::model]\n#[derive(Debug)]\npub struct Settings {\n    auto_expire_completed_todos: bool,\n    completed_expiry_millis: u64,\n}\n\n// -----------------\n// Todo Model\n// -----------------\n#[rid::model]\n#[derive(PartialEq, Eq, PartialOrd, Debug, Serialize)]\npub struct Todo {\n    id: u32,\n    title: String,\n    completed: bool,\n    expiry_millis: u64,\n}\n\nimpl Todo {\n    fn set_completed(&mut self, completed: bool) {\n        self.completed = completed;\n        self.expiry_millis = COMPLETED_EXPIRY_MILLIS;\n    }\n}\n\nimpl Ord for Todo {\n    fn cmp(&self, other: &Self) -> std::cmp::Ordering {\n        self.id.cmp(&other.id)\n    }\n}\n\n// -----------------\n// Filter\n// -----------------\n#[rid::model]\n#[derive(Clone, Debug)]\npub enum Filter {\n    Completed,\n    Pending,\n    All,\n}\n\n// -----------------\n// Msg\n// -----------------\n#[rid::message(Reply)]\n#[rid::enums(Filter)]\n#[derive(Debug)]\npub enum Msg {\n    AddTodo(String),\n    RemoveTodo(u32),\n    RemoveCompleted,\n\n    CompleteTodo(u32),\n    RestartTodo(u32),\n    ToggleTodo(u32),\n    CompleteAll,\n    RestartAll,\n\n    SetFilter(Filter),\n    SetAutoExpireCompletedTodos(bool),\n}\n\n// -----------------\n// Reply\n// -----------------\n#[rid::reply]\npub enum Reply {\n    // Message Replies\n    AddedTodo(u64, String),\n    RemovedTodo(u64, String),\n    RemovedCompleted(u64),\n\n    CompletedTodo(u64, String),\n    RestartedTodo(u64, String),\n    ToggledTodo(u64, String),\n    CompletedAll(u64),\n    RestartedAll(u64),\n\n    SetFilter(u64),\n\n    // Application Events\n    CompletedTodoExpired,\n    Tick(String),\n}\n"
  },
  {
    "path": "flutter/todo_cubit_wasm/src/replies.rs",
    "content": "use crate::Reply;\n\n/// cbindgen:ignore\nstatic mut REPLIES_LOCK: Option<::std::sync::RwLock<Vec<ReplyStruct>>> = None;\n/// cbindgen:ignore\nstatic mut REPLIES_ACCESS: Option<RidRepliesAccess> = None;\n/// cbindgen:ignore\nstatic INIT_REPLIES: ::std::sync::Once = ::std::sync::Once::new();\n\nstruct RidRepliesAccess {\n    lock: &'static ::std::sync::RwLock<Vec<ReplyStruct>>,\n}\n\nimpl RidRepliesAccess {\n    fn instance() -> &'static RidRepliesAccess {\n        unsafe {\n            INIT_REPLIES.call_once(|| {\n                REPLIES_LOCK = Some(::std::sync::RwLock::new(vec![]));\n                REPLIES_ACCESS = Some(RidRepliesAccess {\n                    lock: REPLIES_LOCK.as_ref().unwrap(),\n                });\n            });\n            REPLIES_ACCESS.as_ref().unwrap()\n        }\n    }\n}\n\n// -----------------\n// API used by rid internally when we poll replies for wasm support\n// -----------------\npub fn post(reply: Reply) {\n    replies_write().push(reply.into())\n}\n\npub fn replies_read() -> ::std::sync::RwLockReadGuard<'static, Vec<ReplyStruct>> {\n    RidRepliesAccess::instance().lock.read().unwrap()\n}\n\npub fn replies_write() -> ::std::sync::RwLockWriteGuard<'static, Vec<ReplyStruct>> {\n    RidRepliesAccess::instance().lock.write().unwrap()\n}\n\n#[no_mangle]\npub extern \"C\" fn rid_poll_reply() -> *const ReplyStruct {\n    rid::_option_ref_to_pointer(replies_read().iter().next())\n}\n\n#[no_mangle]\npub extern \"C\" fn rid_handled_reply(req_id: u64) {\n    replies_write().retain(|x| x.req_id != req_id)\n}\n\n#[rid::model]\n#[derive(Debug, Clone)]\npub struct ReplyStruct {\n    ty: u8,\n    req_id: u64,\n    data: String,\n}\n\nimpl ReplyStruct {\n    fn with_req_id(ty: u8, req_id: u64) -> Self {\n        Self {\n            ty,\n            req_id,\n            data: \"\".to_string(),\n        }\n    }\n    fn with_data(ty: u8, req_id: u64, data: String) -> Self {\n        Self { ty, req_id, data }\n    }\n}\n\nimpl From<Reply> for ReplyStruct {\n    fn from(reply: Reply) -> Self {\n        match reply {\n            Reply::AddedTodo(req_id, data) => ReplyStruct::with_data(0, req_id, data),\n            Reply::RemovedTodo(req_id, data) => ReplyStruct::with_data(1, req_id, data),\n            Reply::RemovedCompleted(req_id) => ReplyStruct::with_req_id(2, req_id),\n            Reply::CompletedTodo(req_id, data) => ReplyStruct::with_data(3, req_id, data),\n            Reply::RestartedTodo(req_id, data) => ReplyStruct::with_data(4, req_id, data),\n            Reply::ToggledTodo(req_id, data) => ReplyStruct::with_data(5, req_id, data),\n            Reply::CompletedAll(req_id) => ReplyStruct::with_req_id(6, req_id),\n            Reply::RestartedAll(req_id) => ReplyStruct::with_req_id(7, req_id),\n            Reply::SetFilter(req_id) => ReplyStruct::with_req_id(8, req_id),\n            Reply::CompletedTodoExpired => Self {\n                ty: 10,\n                req_id: 0,\n                data: \"\".to_string(),\n            },\n            Reply::Tick(data) => Self {\n                ty: 11,\n                req_id: 0,\n                data,\n            },\n        }\n    }\n}\n"
  },
  {
    "path": "flutter/todo_cubit_wasm/todo_cubit.iml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<module type=\"JAVA_MODULE\" version=\"4\">\n  <component name=\"NewModuleRootManager\" inherit-compiler-output=\"true\">\n    <exclude-output />\n    <content url=\"file://$MODULE_DIR$\">\n      <sourceFolder url=\"file://$MODULE_DIR$/lib\" isTestSource=\"false\" />\n      <sourceFolder url=\"file://$MODULE_DIR$/test\" isTestSource=\"true\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/.dart_tool\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/.idea\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/.pub\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/plugin/.dart_tool\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/plugin/.pub\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/plugin/build\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/macos/Flutter/ephemeral/.symlinks/plugins/plugin/build\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/macos/Flutter/ephemeral/.symlinks/plugins/plugin/.pub\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/macos/Flutter/ephemeral/.symlinks/plugins/plugin/.dart_tool\" />\n    </content>\n    <orderEntry type=\"sourceFolder\" forTests=\"false\" />\n    <orderEntry type=\"library\" name=\"Dart SDK\" level=\"project\" />\n    <orderEntry type=\"library\" name=\"Flutter Plugins\" level=\"project\" />\n    <orderEntry type=\"library\" name=\"Dart Packages\" level=\"project\" />\n  </component>\n</module>"
  },
  {
    "path": "flutter/todo_cubit_wasm/twitch.md",
    "content": "# Twitch Cubit Todo\n\n## Intro\n\n- show app\n- we'll most likely build parts of it focusing on multi threading and leveraging the higher\n  level API with cubits\n- remaining parts at github\n\n### Miro\n\n- walk through [miro](https://miro.com/app/board/o9J_l9TpJQI=/)\n- explain how multi threaded apps work while providing memory safety\n\n#### 1\n\n- app starting up\n- get Todos\n- `TodosCubit` has list of `Todo` which is a Dart list of Dart class instances\n- converted for us behind the scenes to guarantee memory safety\n- **Rust provides that safety**, but once we leave it and re-enter from Dart we lost the guarantees\n- rid locks the store for reading for us when retrieving Todos to ensure no other thread can\n  write to it while we perform this step\n\n#### 2\n\n- render the Todos\n\n#### 3 \n\n- toggle Todo\n- **we never directly mutate** the store from Dart\n- send messages to it instead\n- rid receives the message and locks store for writing\n- no other thread can read from nor write to it\n- store update receives `mut Store` and while it runs, the Store remains locked\n- **Flutter is `await` ing** the completion of the action triggered by sending the message\n- when Todo toggled Rust posts a _toggled_ reply with the `req_id` included in the message\n- Flutter `TodoCubit` now knows that that message has been handled and retrieves the updated\n  Todo state\n- while that is going on the Store is read locked and we get a Dart Todo instance back\n\n#### 4\n\n- Todo is now re-rendered with completed checked\n\n#### 5\n\n- user configures to auto expire completed Todos\n- SettingsCubit sends message to Store which updates the settings\n- activates ticker thread\n- and posts reply causing Todo to re-render with expire progress bar -> (6)\n- expiry ticker thread is now active and starts ticking down the life of completed todos\n- everytime it updates a Todo it aquires a write lock on the Store to make sure no other thread\n  is reading todos while they're modified\n\n#### 7\n\n- TodoCubit listening on reply channel stream for tick updates for its todo\n- receives todo tick\n- gets updated todo state from store (with locked store)\n\n#### 8\n\n- another tick update .. Todo about to expire\n\n#### 9\n\n- another Todo tick and Todo expired\n- TodoCubit tries to retrieve state of Todo\n- ticker thread wants to remove expired Todo and aquired write lock, causing resolution of Todo\n  state to wait until that step is complete and it can aquire a read lock\n- now the Todo isn't found anymore and we return `null`, could show an empty container also\n\n#### 10\n\n- TodosCubit receives TodoExpired reply\n- gets latest state of filtered todos which no longer includes our Todo\n- renders todos without it\n\nIf we would not read-lock the store and allow to use a pointer of a Todo that might have been\nremoved in the meantime making the pointer invalid we'd run into all kinds of trouble most\nlikely causing the app to crash.\n\n## Counter Start\n\n- show app and point out logs\n- point out debug feature since we won't use that most likely in the todo\n"
  },
  {
    "path": "flutter/todo_cubit_wasm/web/index.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n  <!--\n    If you are serving your web app in a path other than the root, change the\n    href value below to reflect the base path you are serving from.\n\n    The path provided below has to start and end with a slash \"/\" in order for\n    it to work correctly.\n\n    For more details:\n    * https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base\n\n    This is a placeholder for base href that will be replaced by the value of\n    the `--base-href` argument provided to `flutter build`.\n  -->\n  <base href=\"$FLUTTER_BASE_HREF\">\n\n  <meta charset=\"UTF-8\">\n  <meta content=\"IE=Edge\" http-equiv=\"X-UA-Compatible\">\n  <meta name=\"description\" content=\"A new Flutter project.\">\n\n  <!-- iOS meta tags & icons -->\n  <meta name=\"apple-mobile-web-app-capable\" content=\"yes\">\n  <meta name=\"apple-mobile-web-app-status-bar-style\" content=\"black\">\n  <meta name=\"apple-mobile-web-app-title\" content=\"todo_cubit_wasm\">\n  <link rel=\"apple-touch-icon\" href=\"icons/Icon-192.png\">\n\n  <title>todo_cubit_wasm</title>\n  <link rel=\"manifest\" href=\"manifest.json\">\n</head>\n<body>\n  <!-- This script installs service_worker.js to provide PWA functionality to\n       application. For more information, see:\n       https://developers.google.com/web/fundamentals/primers/service-workers -->\n  <script>\n    var serviceWorkerVersion = null;\n    var scriptLoaded = false;\n    function loadMainDartJs() {\n      if (scriptLoaded) {\n        return;\n      }\n      scriptLoaded = true;\n      var scriptTag = document.createElement('script');\n      scriptTag.src = 'main.dart.js';\n      scriptTag.type = 'application/javascript';\n      document.body.append(scriptTag);\n    }\n\n    if ('serviceWorker' in navigator) {\n      // Service workers are supported. Use them.\n      window.addEventListener('load', function () {\n        // Wait for registration to finish before dropping the <script> tag.\n        // Otherwise, the browser will load the script multiple times,\n        // potentially different versions.\n        var serviceWorkerUrl = 'flutter_service_worker.js?v=' + serviceWorkerVersion;\n        navigator.serviceWorker.register(serviceWorkerUrl)\n          .then((reg) => {\n            function waitForActivation(serviceWorker) {\n              serviceWorker.addEventListener('statechange', () => {\n                if (serviceWorker.state == 'activated') {\n                  console.log('Installed new service worker.');\n                  loadMainDartJs();\n                }\n              });\n            }\n            if (!reg.active && (reg.installing || reg.waiting)) {\n              // No active web worker and we have installed or are installing\n              // one for the first time. Simply wait for it to activate.\n              waitForActivation(reg.installing || reg.waiting);\n            } else if (!reg.active.scriptURL.endsWith(serviceWorkerVersion)) {\n              // When the app updates the serviceWorkerVersion changes, so we\n              // need to ask the service worker to update.\n              console.log('New service worker available.');\n              reg.update();\n              waitForActivation(reg.installing);\n            } else {\n              // Existing service worker is still good.\n              console.log('Loading app from service worker.');\n              loadMainDartJs();\n            }\n          });\n\n        // If service worker doesn't succeed in a reasonable amount of time,\n        // fallback to plaint <script> tag.\n        setTimeout(() => {\n          if (!scriptLoaded) {\n            console.warn(\n              'Failed to load app from service worker. Falling back to plain <script> tag.',\n            );\n            loadMainDartJs();\n          }\n        }, 4000);\n      });\n    } else {\n      // Service workers not supported. Just drop the <script> tag.\n      loadMainDartJs();\n    }\n  </script>\n</body>\n</html>\n"
  },
  {
    "path": "flutter/todo_cubit_wasm/web/manifest.json",
    "content": "{\n  \"name\": \"todo_cubit_wasm\",\n  \"short_name\": \"todo_cubit\",\n  \"start_url\": \".\",\n  \"display\": \"standalone\",\n  \"background_color\": \"#0175C2\",\n  \"theme_color\": \"#0175C2\",\n  \"description\": \"Todo Cubit Wasm Version.\",\n  \"orientation\": \"portrait-primary\",\n  \"prefer_related_applications\": false,\n  \"icons\": [\n    {\n      \"src\": \"icons/Icon-192.png\",\n      \"sizes\": \"192x192\",\n      \"type\": \"image/png\"\n    },\n    {\n      \"src\": \"icons/Icon-512.png\",\n      \"sizes\": \"512x512\",\n      \"type\": \"image/png\"\n    },\n    {\n      \"src\": \"icons/Icon-maskable-192.png\",\n      \"sizes\": \"192x192\",\n      \"type\": \"image/png\",\n      \"purpose\": \"maskable\"\n    },\n    {\n      \"src\": \"icons/Icon-maskable-512.png\",\n      \"sizes\": \"512x512\",\n      \"type\": \"image/png\",\n      \"purpose\": \"maskable\"\n    }\n  ]\n}\n"
  }
]