[
  {
    "path": ".gitattributes",
    "content": "* text=auto"
  },
  {
    "path": ".github/CONTRIBUTING.md",
    "content": "### Contributor guidelines\n\nFirst of all - thanks for taking the time to contribute!\n\nWith that in mind, elmish is a young project and as such while we welcome the contributions from non-member there are certain things we'd like to get more right than fast. To make everyone's experience as enjoyable as possible please keep the following things in mind:\n\n* Unless it's a trivial fix, consider opening an issue first to discuss it with the team.\n* If you are just looking for something to take on, check the [help wanted](/elmish/elmish/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22) labeled items\n\n\n### Opening an Issue\n\n* Before you do, please check if there's a known work around, existing issue or already a work in progress to address it.\n* If you just don't know how to do something consider asking in the gitter, there are always helpful people around.\n* Provide as much info as possible - follow the template if it makes sense, attach screenshots or logs if applicable.\n\n\n### Pull requests\n\nTo make it easier to review the changes and get you code into the repo keep the commit history clean:\n\n* [rebase your pulls](https://coderwall.com/p/tnoiug/rebase-by-default-when-doing-git-pull) on the latest from repo\n* only push the commits relevant to the PR\n* consider [squashing](https://robots.thoughtbot.com/git-interactive-rebase-squash-amend-rewriting-history) multiple commits to keep the history clean (you *can* force push to your fork!)\n\nIf adding a feature, also consider adding a sample (or link to one).\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE.md",
    "content": "### Description\n\nPlease provide a succinct description of your issue.\n\n### Repro code\n\nPlease provide the F# code to reproduce the problem.\nIdeally, it should be possibe to easily turn this code into a unit test.\n\n### Expected and actual results\n\nPlease provide the expected and actual results.\n\n### Related information \n\n* elmish version:\n* fable-compiler version:\n* fable-core version:\n* Operating system:\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "content": "name: .NET\n\non:\n  push:\n    branches: [ v4.x ]\n  pull_request:\n    branches: [ v4.x ]\n\njobs:\n  build:\n\n    runs-on: ubuntu-latest\n\n    steps:\n    - uses: actions/checkout@v4\n    - name: Setup .NET\n      uses: actions/setup-dotnet@v4\n      with:\n        global-json-file: global.json\n    - name: Build\n      run: ./build.fsx\n"
  },
  {
    "path": ".github/workflows/publish.yml",
    "content": "name: Publish\non:\n  push:\n    branches:\n      - v4.x\n  workflow_dispatch:\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - name: Setup .NET\n        uses: actions/setup-dotnet@v4\n        with:\n          global-json-file: global.json\n      - name: Setup Node.js\n        uses: actions/setup-node@v4\n        with:\n          node-version: '16'\n      - name: Install and use custom npm version\n        run: npm i -g npm@7\n      - name: Install NPM dependencies\n        run: npm install\n      - name: Build site\n        run: ./build.fsx -t GenerateDocs\n      - name: Deploy site\n        uses: peaceiris/actions-gh-pages@v4\n        with:\n          personal_token: ${{ secrets.GITHUB_TOKEN }}\n          publish_dir: ./docs_deploy\n"
  },
  {
    "path": ".gitignore",
    "content": "# OSX\n#\n.DS_Store\n\n# node.js\n#\n**/node_modules/\n**/npm/\nnpm-debug.log\n\n# F#\n.fake/\npackages/\nbuild/\nobj\nbin\nout\n\n# git\n*.orig\n\n.vs\n*.log\ndocs/output\ndocs/temp\n\nDirectory.Build.props\ntemp\npaket-files\n.ionide\ndocs_deploy/\n"
  },
  {
    "path": ".nacara/_partials/footer.js",
    "content": "import React from 'react';\n\nconst SitemapSection = ({\n  title,\n  children\n}) => /*#__PURE__*/React.createElement(\"div\", {\n  className: \"sitemap-section\"\n}, /*#__PURE__*/React.createElement(\"div\", {\n  className: \"sitemap-section-title\"\n}, title), /*#__PURE__*/React.createElement(\"ul\", {\n  className: \"sitemap-section-list\"\n}, children));\n\nconst SitemapSectionItem = ({\n  text,\n  icon,\n  url\n}) => /*#__PURE__*/React.createElement(\"li\", null, /*#__PURE__*/React.createElement(\"a\", {\n  href: url,\n  className: \"icon-text sitemap-section-list-item\"\n}, /*#__PURE__*/React.createElement(\"span\", {\n  className: \"icon\"\n}, /*#__PURE__*/React.createElement(\"i\", {\n  className: icon\n})), /*#__PURE__*/React.createElement(\"span\", {\n  className: \"sitemap-section-list-item-text\"\n}, text)));\n\nconst CopyrightScript = () => /*#__PURE__*/React.createElement(\"script\", {\n  dangerouslySetInnerHTML: {\n    __html: `\n        const year = new Date().getFullYear();\n        document.getElementById('copyright-end-year').innerHTML = year;\n        `\n  }\n});\n\nexport default /*#__PURE__*/React.createElement(\"div\", {\n  className: \"is-size-5\"\n}, /*#__PURE__*/React.createElement(\"div\", {\n  className: \"sitemap\"\n}, /*#__PURE__*/React.createElement(SitemapSection, {\n  title: \"Project ressources\"\n}, /*#__PURE__*/React.createElement(SitemapSectionItem, {\n  text: \"Repository\",\n  icon: \"fas fa-file-code\",\n  url: \"https://github.com/elmish/elmish\"\n}), /*#__PURE__*/React.createElement(SitemapSectionItem, {\n  text: \"Release notes\",\n  icon: \"fas fa-list\",\n  url: \"/elmish/release_notes.html\"\n}), /*#__PURE__*/React.createElement(SitemapSectionItem, {\n  text: \"License\",\n  icon: \"fas fa-id-card\",\n  url: \"https://github.com/elmish/elmish/blob/v4.x/LICENSE.md\"\n})), /*#__PURE__*/React.createElement(SitemapSection, {\n  title: \"Elmish modules\"\n}, /*#__PURE__*/React.createElement(SitemapSectionItem, {\n  text: \"Fable.Elmish\",\n  icon: \"fa fa-book\",\n  url: \"https://elmish.github.io/elmish/\"\n}), /*#__PURE__*/React.createElement(SitemapSectionItem, {\n  text: \"Fable.Elmish.Browser\",\n  icon: \"fa fa-book\",\n  url: \"https://elmish.github.io/browser/\"\n}), /*#__PURE__*/React.createElement(SitemapSectionItem, {\n  text: \"Fable.Elmish.UrlParser\",\n  icon: \"fa fa-book\",\n  url: \"https://elmish.github.io/urlParser/\"\n}), /*#__PURE__*/React.createElement(SitemapSectionItem, {\n  text: \"Fable.Elmish.Debugger\",\n  icon: \"fa fa-book\",\n  url: \"https://elmish.github.io/debugger/\"\n}), /*#__PURE__*/React.createElement(SitemapSectionItem, {\n  text: \"Fable.Elmish.React\",\n  icon: \"fa fa-book\",\n  url: \"https://elmish.github.io/react/\"\n}), /*#__PURE__*/React.createElement(SitemapSectionItem, {\n  text: \"Fable.Elmish.HMR\",\n  icon: \"fa fa-book\",\n  url: \"https://elmish.github.io/hmr/\"\n})), /*#__PURE__*/React.createElement(SitemapSection, {\n  title: \"Other Links\"\n}, /*#__PURE__*/React.createElement(SitemapSectionItem, {\n  text: \"Fable\",\n  icon: \"faf faf-fable\",\n  url: \"https://fable.io\"\n}), /*#__PURE__*/React.createElement(SitemapSectionItem, {\n  text: \"Fable Gitter\",\n  icon: \"fab fa-gitter\",\n  url: \"https://gitter.im/fable-compiler/Fable\"\n}), /*#__PURE__*/React.createElement(SitemapSectionItem, {\n  text: \"F# Slack\",\n  icon: \"fab fa-slack\",\n  url: \"https://fsharp.org/guides/slack/\"\n}), /*#__PURE__*/React.createElement(SitemapSectionItem, {\n  text: \"F# Software Foundation\",\n  icon: \"faf faf-fsharp-org\",\n  url: \"https://fsharp.org/\"\n}))), /*#__PURE__*/React.createElement(\"p\", {\n  className: \"has-text-centered\"\n}, \"Built with \", /*#__PURE__*/React.createElement(\"a\", {\n  className: \"is-underlined\",\n  href: \"https://mangelmaxime.github.io/Nacara/\"\n}, \"Nacara\")), /*#__PURE__*/React.createElement(\"p\", {\n  className: \"has-text-centered mt-2\"\n}, \"Copyright \\xA9 2021-\", /*#__PURE__*/React.createElement(\"span\", {\n  id: \"copyright-end-year\"\n}), \" Elmish contributors.\"), /*#__PURE__*/React.createElement(CopyrightScript, null));"
  },
  {
    "path": ".npmrc",
    "content": "engine-strict=true\n"
  },
  {
    "path": ".vscode/settings.json",
    "content": "{\n    \"plantuml.exportOutDir\": \"docs/files/img\",\n    \"plantuml.diagramsRoot\": \"docs/content\",\n    \"plantuml.exportSubFolder\": false\n}"
  },
  {
    "path": ".vscode/tasks.json",
    "content": "{\n    // See https://go.microsoft.com/fwlink/?LinkId=733558\n    // for the documentation about the tasks.json format\n    \"version\": \"2.0.0\",\n    \"tasks\": [\n        {\n            \"label\": \"build\",\n            \"command\": \"dotnet\",\n            \"type\": \"shell\",\n            \"args\": [\n                \"build\",\n                \"netstandard\",\n                // Ask dotnet build to generate full paths for file names.\n                \"/property:GenerateFullPaths=true\",\n                // Do not generate summary otherwise it leads to duplicate errors in Problems panel\n                \"/consoleloggerparameters:NoSummary\"\n            ],\n            \"group\": \"build\",\n            \"presentation\": {\n                \"reveal\": \"silent\"\n            },\n            \"problemMatcher\": \"$msCompile\"\n        }\n    ]\n}"
  },
  {
    "path": "Elmish.slnx",
    "content": "<Solution>\n  <Folder Name=\"/Solution Items/\">\n    <File Path=\"build.fsx\" />\n    <File Path=\"global.json\" />\n    <File Path=\"package.json\" />\n    <File Path=\"README.md\" />\n    <File Path=\"RELEASE_NOTES.md\" />\n  </Folder>\n  <Project Path=\"netstandard/Elmish.fsproj\" />\n  <Project Path=\"src/Fable.Elmish.fsproj\" />\n  <Project Path=\"tests/Elmish.Tests.fsproj\" />\n  <Project Path=\"websharper/WebSharper.Elmish.fsproj\" />\n</Solution>\n"
  },
  {
    "path": "LICENSE.md",
    "content": "Copyright 2016-2020 elmish contributors\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\nhttp://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License."
  },
  {
    "path": "README.md",
    "content": "Elmish: Elm-like abstractions for F# applications.\n=======\n\n[![Gitter](https://badges.gitter.im/gitterHQ/gitter.svg)](https://gitter.im/fable-compiler/Fable)\n[![Windows Build status](https://ci.appveyor.com/api/projects/status/c8k7a67evgci6ama/branch/v4.x?svg=true)](https://ci.appveyor.com/project/et1975/elmish/branch/v4.x)\n[![NuGet version](https://badge.fury.io/nu/Fable.Elmish.svg)](https://badge.fury.io/nu/Fable.Elmish)\n\nElmish implements core abstractions that can be used to build applications following the “model view update” style of architecture, as made famous by Elm.\nThe library however does not model any \"view\" and is intended for use in conjuction with a DOM/renderer, like React/ReactNative or VirtualDOM.\nThose familiar with Redux may find Elmish a more natural fit when targeting React or ReactNative as it allows one to stay completely in idiomatic F#.\n\n\nElmish abstractions have been carefully designed to resemble Elm's \"look and feel\" and anyone familiar with post-Signal Elm terminology will find themselves right at home.\n\nSee the [docs site](https://elmish.github.io/elmish/) for more information.\n\n\nUsing Elmish\n------\nv2.0 and above releases use `dotnet` SDK and can be installed with `dotnet nuget` or `paket`:\n\nFor use in a Fable project:\n`paket add nuget Fable.Elmish -i`\n\nFor use in a WebSharper project:\n`paket add nuget WebSharper.Elmish -i`\n\nIf targeting CLR, please use Elmish package:\n`paket add nuget Elmish -i`\n\nFor v1.x release information please see the [v1.x branch](https://github.com/elmish/elmish/tree/v1.x)\nFor v2.x release information please see the [v2.x branch](https://github.com/elmish/elmish/tree/v2.x)\nFor v3.x release information please see the [v3.x branch](https://github.com/elmish/elmish/tree/v3.x)\nFor v4.x release information please see the [v3.x branch](https://github.com/elmish/elmish/tree/v4.x)\n\n\nBuilding Elmish\n------\nElmish depends on [dotnet SDK 8](https://www.microsoft.com/net/download/core):\n\n* `dotnet fsi build.fsx` or `./build.fsx` on a *nix system.\n\n\nContributing\n------\nPlease have a look at the [guidelines](https://github.com/elmish/elmish/blob/master/.github/CONTRIBUTING.md).\n"
  },
  {
    "path": "RELEASE_NOTES.md",
    "content": "## 5.0.2\n* Fix: OfTask.attempt signature\n\n## 5.0.1\n* Fix: Conditions around ValueTask for target platforms\n\n## 5.0.0\n* Implement native support for Task and ValueTask by (@xperiandri) (#303)\n\n## 4.3.0\n* CE Cmds handle more exceptions (#300)\n\n## 4.2.0\n* reintroduce try/catch in the dispatch loop\n\n## 4.1.0\n* Reverse order of subs and cmds evaluation [#66](https://github.com/elmish/browser/issues/66)\n\n## 4.0.2\n* Loosen the tasks contraint when we don't care about the result (#277).\n\n## 4.0.1\n* Elmish targeting .NET runtime was imposing v6 FSharp.Core despite 4.7 being the reference (#267), thanks @JordanMarr.\n\n## 4.0.0\n* Breaking: `withSubscription` replaces existing subscription, use `mapSubscription` to add/accumulate the subscribers\n* Obsolete all `Cmd.xxx.result` functions\n* Breaking: subs receive current model, automatically started/stopped as needed (#248), thanks Kasey Speakman!\n\n## 4.0.0-beta-6\n* WebSharper support by @granicz (Adam Granicz)\n\n## 4.0.0-beta-5\n* Breaking: subs receive current model, automatically started/stopped as needed (#248), thanks Kasey Speakman!\n\n## 4.0.0-beta-4\n* Move to .NET 6 SDK\n* Breaking: dropping .NET 4.6.1 as the target\n\n## 4.0.0-beta-3\n* Breaking: `withSubscription` replaces existing subscription, use `mapSubscription` to add/accumulate the subscribers\n\n## 4.0.0-beta-2\n* Obsolete all `Cmd.xxx.result` functions\n\n## 4.0.0-beta-1\n* Move to .NET 5 SDK\n* Deferring `Cmd` and `Sub` changes to v5\n* For end-user compatibility with v3 keep `Program.runWith` signature and introduce `Program.runWithDispatch` to allow for multi-threaded sync function.\n\n## 4.0.0-alpha-2\n* Changing `Cmd` and `Sub` aliases to DUs\n* Changing `ofSub` to take the error mapper\n* Dropping netstandard1.6 from Elmish (for CLR) targets\n\n## 4.0.0-alpha-1\n\n* Adding termination\n* Moving `syncDispatch` into `runWith` args\n\n## 3.1.0\n* Changing Cmd.OfAsync/OfAsyncImmediate `result` implementation to allow exceptions to escape into the dispatch loop.\n\n## 3.0.6\n\n* Changing Cmd.OfAsync implementations to start via 0-interval StartImmediate to mimic .NET behavior\n\n## 3.0.5\n\n* Changing Cmd.OfAsync implementations to start on thread pool to restore v2.x experience\n* Adding Cmd.OfAsyncImmediate implementations\n* Adding Cmd.OfAsyncWith for custom async start implementations\n\n## 3.0.4\n\n* Access to `Program`'s error handler\n\n## 3.0.3\n\n* Reordering: call `trace` with updated state\n\n## 3.0.1\n\n* Bugfix for ring resizing\n\n## 3.0.0\n\n* Releasing stable 3.0\n\n## 3.0.0-beta-8\n\n* Making `Program` type opaque and reorganizing `Cmd` functions\n\n## 3.0.0-beta-5\n\n* Fable 3 conversion courtesy of Alfonso\n\n## 3.0.0-beta-4\n\n* Ditching PowerPack in favour of Fable.Promise\n\n## 3.0.0-beta-2\n\n* Ditching MailboxProcessor\n\n## 2.0.3\n\n* Adding `Cmd.ofTask` for netstandard\n\n## 2.0.1\n\n* Adding `Cmd.exec`\n\n## 2.0.0\n\n* Stable release\n\n## 2.0.0-beta-4\n\n* re-releasing v1.x for Fable2\n\n## 1.0.3\n\n* re-releasing with azure-functions compatible FSharp.Core dependency\n\n## 1.0.2\n\n* backporting CLR (platform) support\n\n## 1.0.1\n\n* handle exceptions raising from initial subscription\n\n## 1.0.0\n\n* dotnet 2.0 SDK build\n\n## 0.9.2\n\n* `withErrorHandler` modifier\n* cumulative `withSubscription`\n\n## 0.9.1\n\n* packaging fix: Console.WriteLine replaced with console, as commited\n* Fable 1.1.3 dependency\n\n## 0.9.0\n\n* Releasing using fable 1.x \"stable\"\n* Console tracing from @forki\n\n## 0.9.0-beta-9\n\n* Paket!\n\n## 0.9.0-beta-7\n\n* standalone package repo\n\n## 0.9.0-beta-5\n\n* BREAKING: Moved browser-specific stuff (navigation, urlparser) to elmish-browser\n\n## 0.8.2\n\n* Stricter signatures\n\n## 0.8.1\n\n* Browser navigation: working around IE11/Edge lack of `popstate` event\n\n## 0.8.0\n\n* Expanding `Program` to accommodate plugabble error reporting\n\n## 0.7.2\n\n* Fable dev tools bump\n\n## 0.7.1\n\n* Stable release\n\n## 0.7.1-alpha.3\n\n* Update dependencies\n\n## 0.7.1-alpha.2\n\n* Rearranging `Program` API to prepare for debugger\n\n## 0.7.0-alpha.4\n\n* Update README\n\n## 0.7.0-alpha.3\n\n* Update libraries\n\n## 0.7.0-alpha.2\n\n* Move Promise extensions to `Elmish.Cmd` module\n\n## 0.7.0-alpha.1\n\n* Migrate to Fable 0.7\n"
  },
  {
    "path": "appveyor.yml",
    "content": "image: Visual Studio 2022\n\ninstall:\n  - ps: Install-Product node 17 x64\n\nbuild_script:\n  - cmd: dotnet fsi build.fsx\n\ncache:\n- \"%LOCALAPPDATA%\\\\Yarn\"\n"
  },
  {
    "path": "babel.config.json",
    "content": "{\n    \"presets\": [\n        \"@babel/preset-react\"\n    ]\n}\n"
  },
  {
    "path": "build.fsx",
    "content": "#!/usr/bin/env -S dotnet fsi\n#r \"nuget: Fake.Core.Target, 5.23.1\"\n#r \"nuget: Fake.IO.FileSystem, 5.23.1\"\n#r \"nuget: Fake.DotNet.Cli, 5.23.1\"\n#r \"nuget: Fake.Core.Target, 5.23.1\"\n#r \"nuget: Fake.Core.ReleaseNotes, 5.23.1\"\n#r \"nuget: Fake.Tools.Git, 5.23.1\"\n#r \"nuget: MSBuild.StructuredLogger, 2.2.441\"\n\nopen Fake.Core\nopen Fake.Core.TargetOperators\nopen Fake.DotNet\nopen Fake.Tools\nopen Fake.IO\nopen Fake.IO.FileSystemOperators\nopen Fake.IO.Globbing.Operators\nopen System\nopen System.IO\n\n\n// Filesets\nlet projects  =\n    !! \"src/**.fsproj\"\n    ++ \"netstandard/**.fsproj\"\n    ++ \"websharper/**.fsproj\"\n\n\nSystem.Environment.GetCommandLineArgs() \n|> Array.skip 2 // fsi.exe; build.fsx\n|> Array.toList\n|> Context.FakeExecutionContext.Create false __SOURCE_FILE__\n|> Context.RuntimeContext.Fake\n|> Context.setExecutionContext\n\nTarget.create \"Clean\" (fun _ ->\n    Shell.cleanDir \"src/obj\"\n    Shell.cleanDir \"src/bin\"\n    Shell.cleanDir \"netstandard/obj\"\n    Shell.cleanDir \"netstandard/bin\"\n    Shell.cleanDir \"websharper/obj\"\n    Shell.cleanDir \"websharper/bin\"\n)\n\nTarget.create \"Restore\" (fun _ ->\n    projects\n    |> Seq.iter (Path.GetDirectoryName >> DotNet.restore id)\n)\n\nTarget.create \"Build\" (fun _ ->\n    projects\n    |> Seq.iter (Path.GetDirectoryName >> DotNet.build id)\n)\n\nTarget.create \"Test\" (fun _ ->\n    DotNet.test (fun a -> a.WithCommon id) \"tests\"\n)\n\nlet release = ReleaseNotes.load \"RELEASE_NOTES.md\"\n\nTarget.create \"Meta\" (fun _ ->\n    [ \"<Project xmlns=\\\"http://schemas.microsoft.com/developer/msbuild/2003\\\">\"\n      \"<ItemGroup>\"\n      \"<None Include=\\\"../docs/static/img/logo.png\\\" Pack=\\\"true\\\" PackagePath=\\\"\\\\\\\"/>\"\n      \"<PackageReference Include=\\\"Microsoft.SourceLink.GitHub\\\" Version=\\\"1.0.0\\\" PrivateAssets=\\\"All\\\"/>\"\n      \"</ItemGroup>\"\n      \"<PropertyGroup>\"\n      \"<EmbedUntrackedSources>true</EmbedUntrackedSources>\"\n      \"<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>\"\n      \"<PackageProjectUrl>https://github.com/elmish/elmish</PackageProjectUrl>\"\n      \"<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>\"\n      \"<PackageIconUrl>https://raw.githubusercontent.com/elmish/elmish/master/docs/files/img/logo.png</PackageIconUrl>\"\n      \"<PackageIcon>logo.png</PackageIcon>\"\n      \"<RepositoryUrl>https://github.com/elmish/elmish.git</RepositoryUrl>\"\n      sprintf \"<PackageReleaseNotes>%s</PackageReleaseNotes>\" (List.head release.Notes)\n      \"<PackageTags>MVU;fsharp</PackageTags>\"\n      \"<Authors>Eugene Tolmachev</Authors>\"\n      sprintf \"<Version>%s</Version>\" (string release.SemVer)\n      \"</PropertyGroup>\"\n      \"</Project>\"]\n    |> File.write false \"Directory.Build.props\"\n)\n\n// --------------------------------------------------------------------------------------\n// Build a NuGet package\n\nTarget.create \"Package\" (fun _ ->\n    projects\n    |> Seq.iter (Path.GetDirectoryName >> DotNet.pack id)\n)\n\nTarget.create \"PublishNuget\" (fun _ ->\n    let exec dir = DotNet.exec (DotNet.Options.withWorkingDirectory dir)\n\n    let args = sprintf \"push Fable.Elmish.%s.nupkg -s nuget.org -k %s\" (string release.SemVer) (Environment.environVar \"nugetkey\")\n    let result = exec \"src/bin/Release\" \"nuget\" args\n    if (not result.OK) then failwithf \"%A\" result.Errors\n\n    let args = sprintf \"push WebSharper.Elmish.%s.nupkg -s nuget.org -k %s\" (string release.SemVer) (Environment.environVar \"nugetkey\")\n    let result = exec \"websharper/bin/Release\" \"nuget\" args\n    if (not result.OK) then failwithf \"%A\" result.Errors\n\n    let args = sprintf \"push Elmish.%s.nupkg -s nuget.org -k %s\" (string release.SemVer) (Environment.environVar \"nugetkey\")\n    let result = exec \"netstandard/bin/Release\" \"nuget\" args\n    if (not result.OK) then\n        failwithf \"%A\" result.Errors\n)\n\n\n// --------------------------------------------------------------------------------------\n// Generate the documentation\nTarget.create \"GenerateDocs\" (fun _ ->\n    let res = Shell.Exec(\"npm\", \"run docs:build\")\n\n    if res <> 0 then\n        failwithf \"Failed to generate docs\"\n)\n\nTarget.create \"WatchDocs\" (fun _ ->\n    let res = Shell.Exec(\"npm\", \"run docs:watch\")\n\n    if res <> 0 then\n        failwithf \"Failed to watch docs: %d\" res\n)\n\n// --------------------------------------------------------------------------------------\n// Release Scripts\n\nTarget.create \"ReleaseDocs\" (fun _ ->\n    let res = Shell.Exec(\"npm\", \"run docs:publish\")\n\n    if res <> 0 then\n        failwithf \"Failed to publish docs: %d\" res\n)\n\nTarget.create \"Publish\" ignore\n\n// Build order\n\"Clean\"\n    ==> \"Meta\"\n    ==> \"Restore\"\n    ==> \"Build\"\n    ==> \"Test\"\n    ==> \"Package\"\n    ==> \"PublishNuget\"\n    ==> \"Publish\"\n\n// start build\nTarget.runOrDefault \"Test\"\n"
  },
  {
    "path": "docs/_partials/footer.jsx",
    "content": "import React from 'react';\n\nconst SitemapSection = ({ title, children }) => (\n    <div className=\"sitemap-section\">\n        <div className=\"sitemap-section-title\">\n            {title}\n        </div>\n        <ul className=\"sitemap-section-list\">\n            {children}\n        </ul>\n    </div>\n)\n\nconst SitemapSectionItem = ({ text, icon, url }) => (\n    <li>\n        <a href={url} className=\"icon-text sitemap-section-list-item\">\n            <span className=\"icon\">\n                <i className={icon}></i>\n            </span>\n            <span className=\"sitemap-section-list-item-text\">\n                {text}\n            </span>\n        </a>\n    </li>\n)\n\nconst CopyrightScript = () => (\n    <script dangerouslySetInnerHTML={{\n        __html: `\n        const year = new Date().getFullYear();\n        document.getElementById('copyright-end-year').innerHTML = year;\n        `\n    }} />\n)\n\nexport default (\n    <div className=\"is-size-5\">\n        <div className=\"sitemap\">\n            <SitemapSection title=\"Project ressources\">\n                <SitemapSectionItem\n                    text=\"Repository\"\n                    icon=\"fas fa-file-code\"\n                    url=\"https://github.com/elmish/elmish\" />\n\n                <SitemapSectionItem\n                    text=\"Release notes\"\n                    icon=\"fas fa-list\"\n                    url=\"/elmish/release_notes.html\" />\n\n                <SitemapSectionItem\n                    text=\"License\"\n                    icon=\"fas fa-id-card\"\n                    url=\"https://github.com/elmish/elmish/blob/v4.x/LICENSE.md\" />\n            </SitemapSection>\n            <SitemapSection title=\"Elmish modules\">\n                <SitemapSectionItem\n                    text=\"Fable.Elmish\"\n                    icon=\"fa fa-book\"\n                    url=\"https://elmish.github.io/elmish/\" />\n\n                <SitemapSectionItem\n                    text=\"Fable.Elmish.Browser\"\n                    icon=\"fa fa-book\"\n                    url=\"https://elmish.github.io/browser/\" />\n\n                <SitemapSectionItem\n                    text=\"Fable.Elmish.UrlParser\"\n                    icon=\"fa fa-book\"\n                    url=\"https://elmish.github.io/urlParser/\" />\n\n                <SitemapSectionItem\n                    text=\"Fable.Elmish.Debugger\"\n                    icon=\"fa fa-book\"\n                    url=\"https://elmish.github.io/debugger/\" />\n\n                <SitemapSectionItem\n                    text=\"Fable.Elmish.React\"\n                    icon=\"fa fa-book\"\n                    url=\"https://elmish.github.io/react/\" />\n\n                <SitemapSectionItem\n                    text=\"Fable.Elmish.HMR\"\n                    icon=\"fa fa-book\"\n                    url=\"https://elmish.github.io/hmr/\" />\n\n            </SitemapSection>\n            <SitemapSection title=\"Other Links\">\n                <SitemapSectionItem\n                    text=\"Fable\"\n                    icon=\"faf faf-fable\"\n                    url=\"https://fable.io\" />\n\n                <SitemapSectionItem\n                    text=\"Fable Gitter\"\n                    icon=\"fab fa-gitter\"\n                    url=\"https://gitter.im/fable-compiler/Fable\" />\n\n                <SitemapSectionItem\n                    text=\"F# Slack\"\n                    icon=\"fab fa-slack\"\n                    url=\"https://fsharp.org/guides/slack/\" />\n\n                <SitemapSectionItem\n                    text=\"F# Software Foundation\"\n                    icon=\"faf faf-fsharp-org\"\n                    url=\"https://fsharp.org/\" />\n            </SitemapSection>\n\n        </div>\n        <p className=\"has-text-centered\">\n            Built with <a className=\"is-underlined\" href=\"https://mangelmaxime.github.io/Nacara/\">Nacara</a>\n        </p>\n        <p className=\"has-text-centered mt-2\">\n            Copyright © 2021-<span id=\"copyright-end-year\"/> Elmish contributors.\n        </p>\n        <CopyrightScript />\n    </div>\n)\n"
  },
  {
    "path": "docs/docs/basics.fsx",
    "content": "(**\n---\nlayout: standard\ntitle: Basics\n---\n**)\n\n(*** hide ***)\n\n// This block of code is omitted in the generated HTML documentation. Use\n// it to define helpers that you do not want to show in the documentation.\n\n#I \"../../src/bin/Debug/netstandard2.0\"\n\n(**\nThis is a very basic example of an Elmish app - it simply prints the current state in the Console.\nFirst, let's import our dependencies. In a real application, these imports will be in your project file and/or `paket.references`.\n*)\n\n#r \"Fable.Elmish.dll\"\n\n(**\nLet's define our `Model` and `Msg` types. `Model` will hold the current state and `Msg` will tell us the nature of the change that we need to apply to the current state.\n*)\n\ntype Model =\n    {\n        Value : int\n    }\n\ntype Msg =\n    | Increment\n    | Decrement\n\n(**\nNow we define the `init` function that will produce initial state once the program starts running.\nIt can take any arguments, but we'll just use `unit`. We'll need the [`Cmd`](cmd.html) type, so we'll open Elmish for that:\n*)\nopen Elmish\n\nlet init () =\n    {\n        Value = 0\n    }\n    , Cmd.ofMsg Increment\n\n(**\nNotice that we return a tuple. The first field of the tuple tells the program the initial state. The second field holds the command to issue an `Increment` message.\n\nThe `update` function will receive the change required by `Msg`, and the current state. It will produce a new state and potentially new command(s).\n\n*)\n\nlet update msg model =\n    match msg with\n    | Increment when model.Value < 2 ->\n        { model with\n            Value = model.Value + 1\n        }\n        , Cmd.ofMsg Increment\n\n    | Increment ->\n        { model with\n            Value = model.Value + 1\n        }\n        , Cmd.ofMsg Decrement\n\n    | Decrement when model.Value > 1 ->\n        { model with\n            Value = model.Value - 1\n        }\n        , Cmd.ofMsg Decrement\n\n    | Decrement ->\n        { model with\n            Value = model.Value - 1\n        }\n        , Cmd.ofMsg Increment\n\n(**\nAgain we return a tuple: new state, command.\n\nIf we execute this as Elmish program, it will keep updating the model from 0 to 3 and back, printing the current state to the console:\n\n*)\n\nProgram.mkProgram init update (fun model _ -> printf \"%A\\n\" model)\n|> Program.run\n"
  },
  {
    "path": "docs/docs/menu.json",
    "content": "[\n    {\n        \"type\": \"section\",\n        \"label\": \"Step by step\",\n        \"items\": [\n            \"docs/basics\",\n            \"docs/parent-child\",\n            \"docs/subscription\",\n            \"docs/subscriptionv3\"\n        ]\n    }\n]\n"
  },
  {
    "path": "docs/docs/parent-child.fsx",
    "content": "(**\n---\nlayout: standard\ntitle: Parent-child composition\n---\n**)\n\n(*** hide ***)\n// This block of code is omitted in the generated HTML documentation. Use\n// it to define helpers that you do not want to show in the documentation.\n\n#I \"../../src/bin/Debug/netstandard2.0\"\n#r \"Fable.Elmish.dll\"\n\n(**\nThis is an example of nesting logic, where each child looks like an individual app.\nIt knows nothing about what contains it or how it's run, and that's a good thing, as it allows for great flexibility in how things are put together.\n\nLet's define our `Counter` module to hold child logic:\n*)\n\nopen Elmish\n\nmodule Counter =\n\n    type Model =\n        {\n            count : int\n        }\n\n    let init() =\n        {\n            count = 0\n        }\n        , Cmd.none // no initial command\n\n    type Msg =\n        | Increment\n        | Decrement\n\n    let update msg model =\n        match msg with\n        | Increment ->\n            { model with\n                count = model.count + 1\n            }\n            , Cmd.none\n\n        | Decrement ->\n            { model with\n                count = model.count - 1\n            }\n            , Cmd.none\n\n\n(**\nNow we'll define types to hold two counters `top` and `bottom`, and message cases for each counter instance:\n*)\n\ntype Model =\n    {\n        top : Counter.Model\n        bottom : Counter.Model\n    }\n\ntype Msg =\n    | Reset\n    | Top of Counter.Msg\n    | Bottom of Counter.Msg\n\n(**\nAnd our initialization logic, where we ask for two counters to be initialized:\n*)\n\nlet init() =\n    let top, topCmd = Counter.init()\n    let bottom, bottomCmd = Counter.init()\n\n    {\n        top = top\n        bottom = bottom\n    }\n    , Cmd.batch [\n        Cmd.map Top topCmd\n        Cmd.map Bottom bottomCmd\n    ]\n\n(**\n`Cmd.map` is used to \"elevate\" the Counter message into the container type, using corresponding `Top`/`Bottom` case constructors as the mapping function.\nWe batch the commands together to produce a single command for our entire container.\n\nNote that even though we've implemented the counter as not issuing any commands,\nin a real application we still may want to map the commands to facilitate encapsulation - if at any point the child does emit some messages, we'll be in a position to handle them correctly.\n\nAnd finally our update function:\n*)\n\n\nlet update msg model : Model * Cmd<Msg> =\n  match msg with\n  | Reset ->\n    let top, topCmd = Counter.init()\n    let bottom, bottomCmd = Counter.init()\n\n    {\n        top = top\n        bottom = bottom\n    }\n    , Cmd.batch [\n        Cmd.map Top topCmd\n        Cmd.map Bottom bottomCmd\n    ]\n\n  | Top msg' ->\n    let res, cmd = Counter.update msg' model.top\n\n    { model with\n        top = res\n    }\n    , Cmd.map Top cmd\n\n  | Bottom msg' ->\n    let res, cmd = Counter.update msg' model.bottom\n\n    { model with\n        bottom = res\n    }\n    , Cmd.map Bottom cmd\n\n\n(**\nHere we see how pattern matching is used to extract counter message from `Top` and `Bottom` cases into `msg'` and it's routed to the appropriate child.\nAnd again, we map the command issued by the child back to the container `Msg` type.\n\nThis may seem like a lot of work, but what we've done is recruited the compiler to make sure that our parent-child relationship is correctly established!\n*)\n\n(**\nAnd finally, we execute this as an Elmish program:\n\n*)\n\nProgram.mkProgram init update (fun model _ -> printf \"%A\\n\" model)\n|> Program.run\n"
  },
  {
    "path": "docs/docs/subscription.fsx",
    "content": "﻿(**\n---\nlayout: standard\ntitle: Subscriptions\n---\n**)\n\n(*** hide ***)\n// This block of code is omitted in the generated HTML documentation. Use\n// it to define helpers that you do not want to show in the documentation.\n\n#I \"../../src/bin/Debug/netstandard2.0\"\n#r \"Fable.Elmish.dll\"\n#r \"nuget: Fable.Core\"\n#r \"nuget: Feliz\"\n\n(**\n\n> Subscriptions changed in v4. For v3 and earlier subscription, see [Subscriptions (v3)](./subscriptionv3.html).\n> Or see [Migrating from v3](#migrating-from-v3) below.\n\n## Working with external sources of events\n\nSometimes we have a source of events that runs independently of Elmish, like a timer.\nWe can use subscriptions control when those sources are running, and forward its events to our `update` function.\n\nLet's define our `Model` and `Msg` types. `Model` will hold the current state and `Msg` will tell us the nature of the change that we need to apply to the current state.\n*)\n\nopen Elmish\nopen Fable.Core\nopen System\n\n\nmodule BasicTimer =\n\n    type Model =\n        {\n            current : DateTime\n        }\n\n    type Msg =\n        | Tick of DateTime\n\n(**\nNow let's define `init` and `update`.\n*)\n\n    let init () =\n        {\n            current = DateTime.MinValue\n        }, []\n\n    let update msg model =\n        match msg with\n        | Tick current ->\n            { model with\n                current = current\n            }, []\n\n(**\nNow lets define our timer subscription:\n*)\n    let timer onTick =\n        let start dispatch =\n            let intervalId = \n                JS.setInterval\n                    (fun _ -> dispatch (onTick DateTime.Now))\n                    1000\n            { new IDisposable with\n                member _.Dispose() = JS.clearInterval intervalId }\n        start\n\n    let subscribe model =\n        [ [\"timer\"], timer Tick ]\n\n    Program.mkProgram init update (fun model _ -> printf \"%A\\n\" model)\n    |> Program.withSubscription subscribe\n    |> Program.run\n\n\n(**\n`subscribe` answers the question: \"Which subscriptions should be running?\" `subscribe` is provided the current program state, `model`, to use for decisions.\nWhen the model changes, `subscribe` is called. Elmish then starts or stops subscriptions to match what is returned.\n\nA subscription has an ID, `[\"timer\"]` here, and a start function. The ID needs to be unique within that page.\n\n> **ID is a list?**\n> \n> This allows us to include dependencies. Later we will use this to change the timer's interval.\n\n\n## Conditional subscriptions\n\nIn the above example, the timer subscription is always returned from `subscribe`, so it will stay running as long as the program is running.\nLet's look at an example where the timer can be turned off.\n\nFirst we add the field `enabled` and a msg `Toggle` to change it.\n*)\n\nmodule ToggleTimer =\n\n    type Model =\n        {\n            current : DateTime\n            enabled : bool\n        }\n\n    type Msg =\n        | Tick of now: DateTime\n        | Toggle of enabled: bool\n\n    let init () =\n        {\n            current = DateTime.MinValue\n            enabled = true\n        }, []\n\n(**\nNow let's handle the `Toggle` message.\n*)\n    let update msg model =\n        match msg with\n        | Tick now ->\n            { model with\n                current = now\n            }, []\n        | Toggle enabled ->\n            { model with\n                enabled = enabled\n            }, []\n\n(**\n`timer` is the same as before.\n*)\n\n    let timer onTick =\n        let start dispatch =\n            let intervalId = \n                JS.setInterval\n                    (fun _ -> dispatch (onTick DateTime.Now))\n                    1000\n            { new IDisposable with\n                member _.Dispose() = JS.clearInterval intervalId }\n        start\n\n(**\nNext, we change the subscribe function to check `enabled` before including the timer subscription.\n*)\n    let subscribe model =\n        [ if model.enabled then\n            [\"timer\"], timer Tick ]\n\n(**\nNow let's add an HTML view to visualize and control the timer.\n*)\n\n    open Feliz\n\n    let view model dispatch =\n        let timestamp = model.current.ToString(\"yyyy-MM-dd HH:mm:ss.ffff\")\n        Html.div [\n            Html.div [Html.text timestamp]\n            Html.div [\n                Html.label [\n                    prop.children [\n                        Html.input [\n                            prop.type' \"checkbox\"\n                            prop.isChecked model.enabled\n                            prop.onCheckedChange (fun b -> dispatch (Toggle b))\n                        ]\n                        Html.text \" enabled\"\n                    ]\n                ]\n            ]\n        ]\n\n\n    Program.mkProgram init update view\n    |> Program.withSubscription subscribe\n    |> Program.run\n\n(**\nHere is the running program.\n\n![demo of user toggling checkbox to stop and start time updates](../static/img/timer-with-enable.gif)\n*)\n\n(**\n## Aggregating multiple subscribers\nIf you need to aggregate multiple subscriptions follow the same pattern as when implementing `init`, `update`, and `view` functions - delegate to child components to setup their own subscriptions.\n\nFor example:\n*)\n\nmodule Sub =\n\n    // now usable for different intervals\n    let timer intervalMs onTick =\n        let start dispatch =\n            let intervalId = \n                JS.setInterval\n                    (fun _ -> dispatch (onTick DateTime.Now))\n                    intervalMs\n            { new IDisposable with\n                member _.Dispose() = JS.clearInterval intervalId }\n        start\n\n\nmodule Second =\n\n    type Msg =\n        | Second of int\n\n    type Model = int\n\n    let init () =\n        0, []\n\n    let update (Second seconds) model =\n        seconds, []\n\n    let subscribe model =\n        [ [\"timer\"], Sub.timer 1000 (fun now -> Second now.Second) ]\n\nmodule Hour =\n\n    type Msg =\n        | Hour of int\n\n    type Model = int\n\n    let init () =\n        0, []\n\n    let update (Hour hour) model =\n        hour, []\n\n    let subscribe model =\n        [ [\"timer\"], Sub.timer (60*1000) (fun now -> Hour now.Hour) ]\n\nmodule App =\n\n    type Model =\n        {\n            seconds : Second.Model\n            hours : Hour.Model\n        }\n\n    type Msg =\n        | SecondMsg of Second.Msg\n        | HourMsg of Hour.Msg\n\n    let init () =\n        let seconds, secondsCmd = Second.init ()\n        let hours, hoursCmd = Hour.init ()\n        {\n            seconds = seconds\n            hours = hours\n        }, Cmd.batch [Cmd.map SecondMsg secondsCmd; Cmd.map HourMsg hoursCmd]\n\n    let update msg model =\n        match msg with\n        | HourMsg msg ->\n            let hours, hoursCmd = Hour.update msg model.hours\n            { model with\n                hours = hours\n            }, Cmd.map HourMsg hoursCmd\n\n        | SecondMsg msg ->\n            let seconds, secondsCmd = Second.update msg model.seconds\n            { model with\n                seconds = seconds\n            }, Cmd.map SecondMsg secondsCmd\n\n    let subscribe model =\n        Sub.batch [\n            Sub.map \"hour\" HourMsg (Hour.subscribe model.hours)\n            Sub.map \"second\" SecondMsg (Second.subscribe model.seconds)\n        ]\n\n    Program.mkProgram init update (fun model _ -> printf \"%A\\n\" model)\n    |> Program.withSubscription subscribe\n    |> Program.run\n\n(**\nNotice `Sub.map` takes an id prefix as its first parameter. This helps keep subscriptions distinct from each other.\n\nBefore `Sub.map`, Second and Hour have the same ID: `[\"timer\"]`. After `Sub.map`, their IDs are: `[\"hour\"; \"timer\"]` and `[\"second\"; \"timer\"]`.\n\nIt is common for parent pages to have one active child page. This partial example shows `subscribe` in that case.\n*)\n\n(*** hide ***)\nmodule ActiveChildPage =\n    open App\n\n(**\n*)\n\n    type Msg =\n        | SecondMsg of Second.Msg\n        | HourMsg of Hour.Msg\n\n    type Page =\n        | Second of Second.Model\n        | Hour of Hour.Model\n\n    type Model =\n        {\n            page: Page\n        }\n\n    let subscribe model =\n        match model.page with\n        | Second model_ ->\n            Sub.map \"second\" SecondMsg (Second.subscribe model_)\n        | Hour model_ ->\n            Sub.map \"hour\" HourMsg (Hour.subscribe model_)\n\n(**\nWhen the active page changes, the old page's subscriptions are stopped and the new page's subscriptions are started.\n*)\n\n(**\n## Subscription reusability\n\n> 📌 **Effect**\n> \n> The `Effect` type was known as `Sub` in v3. With the change to subscriptions, `Sub` would have been an overloaded and confusing term.\n> Helper functions have also been renamed. For example, `Cmd.ofSub` is now `Cmd.ofEffect`.\n> This is a change in name only -- `Effect` works exactly the same as v3 `Sub`.\n\nIn the last section, we increased reusability of the timer by taking the interval as a parameter.\nWe can use Effect to factor out the hard-coded `DateTime.Now` behavior for even more reuse.\n\nFirst let's turn `DateTime.Now` into an Effect.\n*)\n\nmodule EffectTimer =\n\n    module Time =\n\n        let now (tag: DateTime -> 'msg) : Effect<'msg> =\n            let effectFn dispatch =\n                dispatch (tag DateTime.Now)\n            effectFn\n\n(**\n> Strange as it seems, `DateTime.Now` is a side effect. This property reads from a clock and may return a different value each time. Code that uses it becomes nondeterministic.\n\nNow let's change timer to run an `Effect` when the interval fires.\n*)\n\n    module Sub =\n\n        let timer intervalMs (effect: Effect<'msg>) =\n            let start dispatch =\n                let intervalId = \n                    JS.setInterval (fun _ -> effect dispatch) intervalMs\n                { new IDisposable with\n                    member _.Dispose() = JS.clearInterval intervalId }\n            start\n\n(**\nAnd finally, here is the updated `subscribe` function.\n*)\n\n    type Model =\n        {\n            current : DateTime\n            intervalMs : int\n        }\n\n    type Msg =\n        | Tick of DateTime\n\n    let subscribe model =\n        [ [\"timer\"], Sub.timer model.intervalMs (Time.now Tick) ]\n\n(**\nThe timer subscription can now run any kind of effect. Calling an API, playing a sound, etc.\n\n`Time.now` is also usable for Cmds.\n*)\n\n    let init () =\n        {\n            current = DateTime.MinValue\n            intervalMs = 1000\n        }\n        , Cmd.ofEffect (Time.now Tick)\n\n(**\n## IDs and dependencies\n\nEarlier we noted that ID is a list so that you can add dependencies to it. We'll use that to improve the last example.\n\nIn that example, the timer's interval came from the model:\n\n```fsharp\nSub.timer model.intervalMs (Time.now Tick)\n```\n\nBut nothing happens to the subscription if `model.intervalMs` changes. Let's fix that.\n*)\n\n(*** hide ***)\nmodule IdDeps =\n\n    open EffectTimer // reuse last example's code\n\n(**\n*)\n    let subscribe model =\n        let subId = [\"timer\"; string model.intervalMs]\n        [ subId, Sub.timer model.intervalMs (Time.now Tick) ]\n\n(**\nNow that `intervalMs` is part of the ID, the timer will stop the old interval then start with the new interval whenever the interval changes.\n\nHow does it work? It is taking advantage of ID uniqueness.\nLet's say that `intervalMs` is initially 1000. The sub ID is `[\"timer\"; \"1000\"]`, Elmish starts the subscription.\nThen `intervalMs` changes to 2000. The sub ID becomes `[\"timer\"; \"2000\"]`.\nElmish sees that `[\"timer\"; \"1000\"]` is no longer active and stops it. Then it starts the \"new\" subscription `[\"timer\"; \"2000\"]`.\n\nTo Elmish each interval is a different subscription. But to `subscribe` this is a single timer that changes intervals.\n\nLet's look at another example: multiple timers. This one will be a full-fledged example including UI forms to take user input.\n*)\n\nmodule MultipleTimers =\n\n    module Time =\n\n        let now (tag: DateTime -> 'msg) : Effect<'msg> =\n            let effectFn dispatch =\n                dispatch (tag DateTime.Now)\n            effectFn\n\n    module Sub =\n\n        let timer intervalMs (effect: Effect<'msg>) =\n            let start dispatch =\n                let intervalId = \n                    JS.setInterval (fun _ -> effect dispatch) intervalMs\n                { new IDisposable with\n                    member _.Dispose() = JS.clearInterval intervalId }\n            start\n\n(**\nThis includes the same `Sub.timer` subscription and `Time.now` effect from the last example.\n\nNow let's create a reusable form that accepts timer interval changes and validates them.\n*)\n\n    // type aliases to make the model more legible, in theory\n    type TimerId = int\n    type IntervalMs = int\n\n    type FormState =\n        | Unchanged\n        | NewValue of IntervalMs\n        | Invalid of error: string\n\n    type IntervalForm =\n        {\n            current : IntervalMs\n            userEntry : string\n            state : FormState\n        }\n\n    module IntervalForm =\n        let [<Literal>] NoInterval = -1\n\n        let empty =\n            {\n                current = NoInterval\n                userEntry = \"\"\n                state = Unchanged\n            }\n\n        let create intervalMs =\n            {\n                current = intervalMs\n                userEntry = string intervalMs\n                state = Unchanged\n            }\n\n        let reset form =\n            let userEntry =\n                if form.current = NoInterval then\n                    \"\"\n                else\n                    string form.current\n            {form with userEntry = userEntry; state = Unchanged}\n\n        let validate form =\n            match Int32.TryParse form.userEntry with\n            | false, _ when form.current = NoInterval && form.userEntry = \"\" ->\n                {form with state = Unchanged}\n            | false, _ when form.userEntry = \"\" ->\n                {form with state = Invalid \"cannot be blank\"}\n            | false, _ ->\n                {form with state = Invalid \"must be an integer\"}\n            | true, interval when interval <= 0 ->\n                {form with state = Invalid \"must be greater than zero\"}\n            | true, interval when interval = form.current ->\n                {form with state = Unchanged}\n            | true, interval ->\n                {form with state = NewValue interval}\n\n        let userEntry text form =\n            validate {form with userEntry = text}\n\n(**\nNow let's create the overall model to manage timers.\n*)\n\n\n    type Model =\n        {\n            // lookup by TimerId, last tick and interval settings\n            timers : Map<TimerId, DateTime * IntervalForm>\n            // incrementing ID\n            nextId : TimerId\n            // form for the user to add a new interval\n            addForm : IntervalForm\n        }\n\n    type Msg =\n        | AddFormReset\n        | AddFormUserEntry of text: string\n        | ChangeFormReset of timerId: int\n        | ChangeFormUserEntry of timerId: int * text: string\n        | AddTimer of intervalMs: int\n        | RemoveTimer of timerId: int\n        | ChangeInterval of timerId: int * intervalMs: int\n        | Tick of timerId: int * now: DateTime\n\n     module Model =\n\n        let updateTimer timerId f model =\n            { model with\n                timers =\n                    model.timers\n                    |> Map.change timerId (Option.map f)\n            }\n\n        let updateForm timerId f model =\n            model |> updateTimer timerId (fun (now, form) -> now, f form)\n\n        let updateNow timerId newNow model =\n            model |> updateTimer timerId (fun (now, form) -> newNow, form)\n\n    let init () =\n        {\n            timers = Map.empty\n            nextId = 1\n            addForm = IntervalForm.empty\n        }, []\n\n    let update msg model =\n        match msg with\n        // form changes\n        | AddFormReset ->\n            { model with\n                addForm = IntervalForm.reset model.addForm\n            }, []\n        | AddFormUserEntry text ->\n            { model with\n                addForm = IntervalForm.userEntry text model.addForm\n            }, []\n        | ChangeFormReset timerId ->\n            Model.updateForm timerId IntervalForm.reset model, []\n        | ChangeFormUserEntry (timerId, text) ->\n            Model.updateForm timerId (IntervalForm.userEntry text) model, []\n        // timer changes\n        | AddTimer intervalMs ->\n            { model with\n                timers =\n                    let form = IntervalForm.create intervalMs\n                    Map.add model.nextId (DateTime.MinValue, form) model.timers\n                nextId = model.nextId + 1\n                addForm = IntervalForm.empty\n            }, [Time.now (fun now -> Tick (model.nextId, now))]\n        | RemoveTimer timerId ->\n            { model with\n                timers = Map.remove timerId model.timers\n            }, []\n        | ChangeInterval (timerId, intervalMs) ->\n            let form = IntervalForm.create intervalMs\n            Model.updateForm timerId (fun _ -> form) model, []\n        | Tick (timerId, now) ->\n            Model.updateNow timerId now model, []\n\n    let subscribe model =\n        [\n            for timerId, (_now, {current = intervalMs}) in Map.toList model.timers do\n                let subId = [\"timer\"; string timerId; string intervalMs]\n                let tick now = Tick (timerId, now)\n                subId, Sub.timer intervalMs (Time.now tick)\n        ]\n\n(**\nIn the subscription IDs, we included `timerId` and `intervalMs`. Each serves a slightly different purpose.\n\nWe can't use just \"timer\" because it won't be unique. `timerId` provides a unique (auto-incrementing) ID, so it satisfies that requirement.\nAny data we add to the ID beyond that, like `intervalMs` will cause the subscription to restart when that data changes. This is perfect for settings that affect the subscription runtime behavior, like interval changes.\n\nNote that \"timer\" isn't needed in the ID here. Since timerId is providing uniqueness, \"timer\" is only a prefix now.\nA prefix might still be useful if there are other subscriptions on that page.\n\nLet's finish things off with view functions.\n*)\n\n    open Feliz\n\n    let formView resetTag userEntryTag saveTag (saveText: string) form dispatch =\n        Html.div [\n            Html.text \" \"\n            Html.input [\n                prop.type'.text\n                prop.value form.userEntry\n                prop.onChange (fun (text: string) -> dispatch (userEntryTag text))\n            ]\n            Html.text \" \"\n            Html.button [\n                prop.type'.button\n                prop.text saveText\n                match form.state with\n                | Unchanged | Invalid _ ->\n                    prop.disabled true\n                | NewValue intervalMs ->\n                    prop.onClick (fun _ -> dispatch (saveTag intervalMs))\n            ]\n            Html.text \" \"\n            Html.a [\n                prop.text \"Reset\"\n                prop.style [style.userSelect.none]\n                match form.state with\n                | Unchanged ->\n                    prop.disabled true\n                    prop.style [style.color.gray; style.pointerEvents.none; style.userSelect.none]\n                | _ ->\n                    prop.onClick (fun _ -> dispatch resetTag)\n            ]\n            Html.text \" \"\n            Html.br []\n            match form.state with\n            | Unchanged | NewValue _ ->\n                Html.span [\n                    prop.style [style.visibility.hidden]\n                    prop.text \"no error\"\n                ]\n            | Invalid error ->\n                Html.span [\n                    prop.style [style.color.orangeRed; style.fontSize (length.rem 0.8)]\n                    prop.text error\n                ]\n        ]\n\n    let view model dispatch =\n        Html.div [\n            prop.style [style.padding (length.px 12)]\n            prop.children [\n                Html.style\n                    \"\"\"\n                    table {border-collapse: collapse; border-spacing: 0; box-sizing: border-box; border: 1px solid gray}\n                    table th, table td {padding: 3px 12px}\n                    \"\"\"\n                Html.h4 \"Add a timer\"\n                formView AddFormReset AddFormUserEntry AddTimer \"Add\" model.addForm dispatch\n                Html.h4 \"Timers\"\n                Html.table [\n                    Html.thead [\n                        Html.tr [\n                            Html.th \" \"\n                            Html.th \" Timer ID \"\n                            Html.th \" Last Tick \"\n                            Html.th \" Interval (ms) \"\n                        ]\n                    ]\n                    Html.tbody [\n                        for timerId, (now, form) in Map.toList model.timers do\n                            Html.tr [\n                                prop.key timerId\n                                prop.children [\n                                    Html.td [\n                                        Html.text \" \"\n                                        Html.button [\n                                            prop.type' \"button\"\n                                            prop.onClick (fun _ -> dispatch (RemoveTimer timerId))\n                                            prop.text \" X \"\n                                        ]\n                                        Html.text \" \"\n                                    ]\n                                    Html.td [\n                                        prop.style [style.textAlign.right]\n                                        prop.text (\" \" + string timerId + \" \")\n                                    ]\n                                    Html.td [\n                                        Html.div [\n                                            prop.key (string now.Ticks)\n                                            let timestampStr = now.ToString(\"yyyy-MM-dd HH:mm:ss.ffff\")\n                                            prop.text timestampStr\n                                        ]\n                                    ]\n                                    Html.td [\n                                        let reset = ChangeFormReset timerId\n                                        let userEntry text = ChangeFormUserEntry (timerId, text)\n                                        let save intervalMs = ChangeInterval (timerId, intervalMs)\n                                        formView reset userEntry save \"Save\" form dispatch\n                                    ]\n                                ]\n                            ]\n                    ]\n                ]\n            ]\n        ]\n\n    Program.mkProgram init update view\n    |> Program.withSubscription subscribe\n    |> Program.run\n\n(**\nHere is a demo.\n\n![demo of user adding updating and removing timers in a table](../static/img/timer-multi.gif)\n\n## Migrating from v3\n\nMigrating from Elmish v3 is fairly simple. First we will look at what we have from V3.\n\n### v3 example\n*)\n\n// from v3 docs\nmodule V3Sub =\n    open System\n\n    type Model =\n        {\n            current : DateTime\n        }\n\n    type Msg =\n        | Tick of DateTime\n\n    let init () =\n        {\n            current = DateTime.Now\n        }\n\n    let update msg model =\n        match msg with\n        | Tick current ->\n            { model with\n                current = current\n            }\n\n(**\nHere is the main part we are concerned with: the subscription. Type annotations have been added.\n*)\n\n    open Elmish\n    open Fable.Core\n\n    let timer (initial: Model) : Cmd<Msg> =\n        let sub dispatch =\n            JS.setInterval\n                (fun _ ->\n                    dispatch (Tick DateTime.Now)\n                )\n                1000\n                |> ignore\n        Cmd.ofSub sub\n\n    Program.mkSimple init update (fun model _ -> printf \"%A\\n\" model)\n    |> Program.withSubscription timer\n    |> Program.run\n\n\n(**\n### v4 conversion\n\nFirst, let's see the v4-migrated `timer` function. Then we'll go through the differences.\n*)\n\n(*** hide ***)\nmodule V4Sub =\n    open V3Sub\n(**\n*)\n    let timer (model: Model) : (SubId * Subscribe<Msg>) list =\n        let sub dispatch : IDisposable =\n            JS.setInterval\n                (fun _ ->\n                    dispatch (Tick DateTime.Now)\n                )\n                1000\n                |> ignore\n            {new IDisposable with member _.Dispose() = ()}\n        [ [\"timer\"], sub ]\n\n    Program.mkSimple init update (fun model _ -> printf \"%A\\n\" model)\n    |> Program.withSubscription timer\n    |> Program.run\n\n(*** hide ***)\nmodule V4SubExplained =\n    open V3Sub\n(**\n### Differences\n\nFirst, the function signature is different.\n*)\n                             //vvvvvvvvvvvvvvvvvvvvvvvvvvvvv\n    let timer (model: Model) : (SubId * Subscribe<Msg>) list =\n(**\nInstead of returning `Cmd<Msg>`, the subscription now returns a list containing `SubId`s and their associated `Subscribe` functions in a tuple.\n\nTo convert `sub` into a `Subscribe<Msg>` function, the only change is that it returns an `IDisposable` instead of `unit`.\n*)\n                         //vvvvvvvvvvv\n        let sub dispatch : IDisposable =\n            JS.setInterval\n                (fun _ ->\n                    dispatch (Tick DateTime.Now)\n                )\n                1000\n                |> ignore\n            {new IDisposable with member _.Dispose() = ()}\n          //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n(**\nThe `IDisposable` is meant to provide a way to stop the subscription. We used an empty `IDisposable` because v3 subscriptions did not have \"stop\" functionality. So this matches v3 behavior.\n\n> If \"stop\" functionality was needed in v3, it had to be manually coded. By behaving like v3, the above remains compatible with any such code.\n> Then the full v4 subscription functionality can be implemented when and if it is convenient.\n\nNow let's examine the return value.\n*)\n        [ [\"timer\"], sub ]\n\n(**\nThe return value is a list containing a single element: a combination of `[\"timer\"]` (the subscription ID) and `sub` (the subscribe function) in a tuple.\nThe subscription ID should be unique among other subscriptions in the list. For more info on why the ID is a list, see the section [IDs and dependencies](#ids-and-dependencies).\n\nThis is all that's necessary to migrate v3 subs to v4 to get an existing code base working.\nSubscriptions in v4 offer new functionality, such as automatically stopping or restarting subscriptions when the model changes.\nFor more information, please consult the previous sections in this document. They offer a step-by-step guide to the new features.\n*)\n\n\n(**\n\n## Style used in this guide\n\nThis guide uses a named fn, `start`, inside subscriptions for increased explicitness. The pattern looks like this:\n*)\n\n(*** hide ***)\nmodule Style2 =\n\n(**\n*)\n    let timer intervalMs onTick =\n        let start dispatch = // define start fn\n            ((* . . . *))\n        start // return start fn\n\n(**\nIn the source code of Elmish libraries, you will typically find anonymous function returns instead. Like this:\n*)\n\n(*** hide ***)\nmodule Style1 =\n\n(**\n*)\n    let timer intervalMs onTick =\n        fun dispatch ->\n            ((* . . . *))\n\n(**\nBoth styles are equivalent in functionality. Feel free to use whichever you prefer.\n*)\n"
  },
  {
    "path": "docs/docs/subscriptionv3.fsx",
    "content": "(**\n---\nlayout: standard\ntitle: Subscriptions (v3)\n---\n**)\n\n(*** hide ***)\n// This block of code is omitted in the generated HTML documentation. Use\n// it to define helpers that you do not want to show in the documentation.\n\n#I \"../../src/bin/Debug/netstandard2.0\"\n#r \"Fable.Elmish.dll\"\n#r \"nuget: Fable.Core\"\n\n(**\n\n## Working with external sources of events\n\nSometimes we have a source of events that doesn't depend on the current state of the model, like a timer.\nWe can setup forwarding of those events to be processed by our `update` function like any other change.\n\nLet's define our `Model` and `Msg` types. `Model` will hold the current state and `Msg` will tell us the nature of the change that we need to apply to the current state.\n*)\n\nopen System\n\n\ntype Model =\n    {\n        current : DateTime\n    }\n\ntype Msg =\n    | Tick of DateTime\n\n(**\nThis time we'll define the \"simple\" version of `init` and `update` functions, that don't produce commands:\n*)\n\nlet init () =\n    {\n        current = DateTime.Now\n    }\n\nlet update msg model =\n    match msg with\n    | Tick current ->\n        { model with\n            current = current\n        }\n\n(**\n\nNote that \"simple\" is not a requirement and is just a matter of convenience for the purpose of the example!\n\nNow lets define our timer subscription:\n\n*)\nopen Elmish\nopen Fable.Core\n\nlet timer initial =\n    let sub dispatch =\n        JS.setInterval\n            (fun _ ->\n                dispatch (Tick DateTime.Now)\n            )\n            1000\n            |> ignore\n    Cmd.ofSub sub\n\nProgram.mkSimple init update (fun model _ -> printf \"%A\\n\" model)\n|> Program.withSubscription timer\n|> Program.run\n\n\n(**\nIn this example program initialization will call our subscriber (once) with inital `Model` state, passing the `dispatch` function to be called whenever an event occurs.\nHowever, any time you need to issue a message (for example from a callback) you can use `Cmd.ofSub`.\n*)\n\n(**\n## Aggregating multiple subscribers\nIf you need to aggregate multiple subscriptions follow the same pattern as when implementing `init`, `update`, and `view` functions - delegate to child components to setup their own subscriptions.\n\nFor example:\n*)\n\nmodule Second =\n    type Msg =\n        | Second of int\n\n    type Model = int\n\n    let subscribe initial =\n        let sub dispatch =\n            JS.setInterval\n                (fun _ ->\n                    dispatch (Second DateTime.Now.Second)\n                )\n                1000\n                |> ignore\n        Cmd.ofSub sub\n\n    let init () =\n        0\n\n    let update (Second seconds) model =\n        seconds\n\nmodule Hour =\n    type Msg =\n        | Hour of int\n\n    type Model = int\n\n    let init () =\n        0\n\n    let update (Hour hours) model =\n        hours\n\n    let subscribe initial =\n        let sub dispatch =\n            JS.setInterval\n                (fun _ ->\n                    dispatch (Hour DateTime.Now.Hour)\n                )\n                1000*60\n                |> ignore\n        Cmd.ofSub sub\n\nmodule App =\n    type Model =\n        {\n            seconds : Second.Model\n            hours : Hour.Model\n        }\n\n    type Msg =\n        | SecondMsg of Second.Msg\n        | HourMsg of Hour.Msg\n\n    let init () =\n        {\n            seconds = Second.init()\n            hours = Hour.init()\n        }\n\n    let update msg model =\n        match msg with\n        | HourMsg msg ->\n            { model with\n                hours = Hour.update msg model.hours\n            }\n\n        | SecondMsg msg ->\n            { model with\n                seconds = Second.update msg model.seconds\n            }\n\n    let subscription model =\n        Cmd.batch [\n            Cmd.map HourMsg (Hour.subscribe model.hours)\n            Cmd.map SecondMsg (Second.subscribe model.seconds)\n        ]\n\n    Program.mkSimple init update (fun model _ -> printf \"%A\\n\" model)\n    |> Program.withSubscription subscription\n    |> Program.run\n"
  },
  {
    "path": "docs/index.md",
    "content": "---\nlayout: standard\ntoc: false\ntitle: Elmish\n---\n\n>`-ish` <br />\n>  a suffix used to convey the sense of “having some characteristics of”\n\nElmish implements core abstractions that can be used to build F# applications following the [“model view update”](https://guide.elm-lang.org/architecture/) style of architecture, as made famous by Elm.\n\nThe goal of the architecture is to provide a solid UI-independent core to build the rest of the functionality around.\nElm architecture operates using the following concepts, as they translate to Elmish:\n\n* **Model** <br />\n  This is a snapshot of your application's state, defined as an immutable data structure.\n\n<div/> <!-- Add a small gap -->\n\n* **Message** <br />\n  This an event representing a change (delta) in the state of your application, defined as a discriminated union.\n\n<div/> <!-- Add a small gap -->\n\n* **Command** <br />\n  This is a carrier of instructions, that when evaluated may produce one or more messages.\n\n<div/> <!-- Add a small gap -->\n\n* **Init** <br />\n  This is a pure function that produces the inital state of your application and, optionally, commands to process.\n\n<div/> <!-- Add a small gap -->\n\n* **Update** <br />\n  This is a pure function that produces a new state of your application given the previous state and, optionally, new commands to process.\n\n<div/> <!-- Add a small gap -->\n\n* **View** <br />\n  This is a pure function that produces a new UI layout/content given the current state, defined as an F# function that uses a renderer (such as React) to declaratively build a UI.\n\n<div/> <!-- Add a small gap -->\n\n* **Program** <br />\n  This is an opaque data structure that combines all of the above plus a `setState` function to produce a view from the model.\n  See the [`Program`](program.html) module for more details.\n\n### Installation\n\n```sh\ndotnet add package Fable.Elmish\n```\n\nConcepts\n---------------\n\n\n### Dispatch loop\n\n![flow](static/img/flow.svg)\n\nOnce started, Program runs a dispatch loop, producing a new Model given the current state and an input Message.\n\nSee the [basics example](docs/basics.html) for details.\n\n\n\n### Parent-child composition and user interaction\n\nParent-child hierarchy is made explicit by wrapping model and message types of the child with those of the parent.\n\nFollowing diagrams show interactions between components in case of a user interacting with an example web app.\nNote that Elmish doesn't depend on any specific UI such as HTML rendering (it actually does not require any UI at all), and HTML is used just for explanation purposes.\n\nFirst the UI is initialised:\n\n![parent-child composition: UML diagram of UI initialisation](static/img/parent-child-1-ui-init.svg)\n\n1. `program` requests the initial model from the parent, top-level component (`Main`)\n2. Parent component requests the initial model from its child subcomponent (`Widget`)\n3. `Widget.initialModel` returns its initial model to the parent\n4. `Main.initialModel` wraps child's model and returns the top-level initial model to the program\n5. Program sends the model to the parent's `Main.view`\n6. Parent unwraps the child's component model from its model and sends it to child's `Widget.view`\n7. `Widget.view` returns a rendered `HTML` page\n8. `Main.view` embeds child's `HTML` page in its `HTML` page\n9. The resulting `HTML` page is send to the user\n\nThen the user interacts with the browser:\n\n![parent-child composition: UML diagram of user interacting with the browser](static/img/parent-child-2-user-interaction.svg)\n\n1. User clicks on the increase button\n2. `Widget.view` dispatches an `Increase` message\n3. `Main.view` has augemented the `dispatch` so the message becomes `WidgetMsg Increase` as it is sent along to `program`\n4. `program` calls `Main.update` with this message and `mainModel`\n5. As the message was tagged with `WidgetMsg`, `Main.update` delegates the update to `Widget.update`, sending along the way the `widgetModel` part of `mainModel`\n6. `Widget.update` modifies the model according to the given message, in this case `Increase`, and returns the modified `widgetModel` plus a command\n7. `Main.update` returns the updated `mainModel` to `program`\n8. `program` then renders the view again passing the updated `mainModel`\n\nSee the [example](docs/parent-child.html) for details.\n\n\n\n### Tasks and side-effects\n\nTasks such as reading a database or making a Web API call are performed using `async` and `promise` blocks or just plain functions.\nThese operations may return immediately but complete (or fail) at some later time.\nTo feed the results back into the dispatch loop, instead of executing the operations directly, we instruct Elmish to do it for us by wrapping the instruction in a command.\n\n\n### Commands\n\nCommands are carriers of instructions, which you issue from the `init` and `update` functions.\nOnce evaluated, a command may produce one or more new messages, mapping success or failure as instructed ahead of time.\nAs with any message dispatch, in the case of Parent-Child composition, child commands need to be mapped to the parent's type:\n\n![cmd](static/img/commands.svg)\n\n1. `Program` calls the `Main.update` with a message\n2. `Main.update` does its own update and/or delegates to `Child.update`\n3. `Child.update` does its own update and/or delegates to `GrandChild.update`\n4. `GrandChild.update` returns with its model and `Cmd` (of GrandChild message type)\n5. `Child.update` processes GrandChild's model and maps its `Cmd` into `Cmd` of Child's message type and batches it with its own `Cmd`, if any\n6. `Main.update` processes Child's model and maps its `Cmd` into `Cmd` of Main's message type and batches it with its own `Cmd`, if any\n\nHere we collect commands from three different levels. At the end we send all these commands to our `Program` instance to run.\n\nSee the [`Cmd`](cmd.html) module for ways to construct, map and batch commands.\n\n\n### Subscriptions\n\nMost of the messages (changes in the state) will originate within your code, but some will come from the outside, for example from a timer or a websocket.\nThese sources can be tapped into with subscriptions, defined as F# functions that can dispatch new messages as they happen.\n\nSee the [subscriptions example](docs/subscription.html) for details.\n\n\n### View\n\nThe core is independent of any particular technolgy, instead relying on a renderer library to implement `setState` in any way seen fit.\nIn fact, an Elmish app can run entirely without a UI!\n\nAt the moment, there are two UI technologies for which rendering has been implemented: React and React Native.\n\nFor details please see [elmish-react](https://elmish.github.io/react).\n\n\n### Interacting with a browser\n\nLarger Elmish applications for the browser may benefit from advanced features like routing and explicit navigation control.\n\nFor information about these features please see [elmish-browser](https://elmish.github.io/browser).\n\n\n### Controlling termination\n\nHot reloading requires the new version of the application loop to be started. To faciliate the interaction with libraries that implement this functionality the v4 elmish extends the abstractions with \"termination\". Use `withTermination` function to specify the predicate that can evaluate incoming messages and decide if the dispatch loop should stop processing the messages, as well as specify how to release the resources.\n\n### Observing the state changes\n\nEvery message going through the dispatch loop can be traced, along with the current state of the app.\nJust augument the program instance with a trace function:\n\n```fs\nopen Elmish\n\nProgram.mkProgram init update view\n|> Program.withConsoleTrace\n|> Program.run\n```\n\nAnd start seeing the state and messages as updates happen in the browser developer console.\n\nFor more advanced debugging capabilities please see [elmish-debugger](https://elmish.github.io/debugger).\n"
  },
  {
    "path": "docs/release_notes.md",
    "content": "---\nlayout: changelog\nchangelog_path: ./../RELEASE_NOTES.md\n---\n"
  },
  {
    "path": "docs/scss/fable-font.scss",
    "content": "@font-face {\n    font-family: 'fable-font';\n    src: url('/static/fonts/fable-font/fable-font.eot?qh7nog');\n    src: url('/static/fonts/fable-font/fable-font.eot?qh7nog#iefix') format('embedded-opentype'),\n         url('/static/fonts/fable-font/fable-font.ttf?qh7nog') format('truetype'),\n         url('/static/fonts/fable-font/fable-font.woff?qh7nog') format('woff'),\n         url('/static/fonts/fable-font/fable-font.svg?qh7nog#fable-font') format('svg');\n    font-weight: normal;\n    font-style: normal;\n}\n\n// Prepare bulma to accept our customs icons\n.icon {\n    .faf {\n        font-size: 21px;\n    }\n\n    &.is-small {\n        height: 1rem;\n        width: 1rem;\n\n        .faf {\n            font-size: 14px;\n        }\n    }\n\n    &.is-medium {\n        height: 2rem;\n        width: 2rem;\n\n        .faf {\n            // font-size: 28px;\n            font-size: 1.33333em;\n            line-height: 0.75em;\n            vertical-align: -.0667em;\n        }\n    }\n\n    &.is-large {\n        height: 3rem;\n        width: 3rem;\n\n        .faf {\n            font-size: 42px;\n        }\n    }\n}\n\n.faf {\n    display: inline-block;\n    font: normal normal normal 14px/1 'fable-font';\n    font-size: inherit;\n    text-rendering: auto;\n    -webkit-font-smoothing: antialiased;\n    -moz-osx-font-smoothing: grayscale;\n}\n\n$icons: (\n    fable: \"\\e900\",\n    fsharp-org: \"\\e901\"\n);\n\n@each $name, $icon in $icons {\n    .faf-#{$name}:after {\n        content: $icon;\n    }\n}\n"
  },
  {
    "path": "docs/static/img/commands.wsd",
    "content": "@startuml\nautonumber \"<b>(#)\"\n' © Sebastian Porto 2016, \n' licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.\n\nparticipant program #white\nparticipant Main.update as MU #white\nparticipant Child.update as CU #white\nparticipant GrandChild.update as GC #white\n\nprogram -> MU: update\nMU -> CU: update\nCU -> GC: update\nGC --> CU: (model, command)\nCU --> MU: (model, command)\nMU -> program : (model, command)\n\n@enduml"
  },
  {
    "path": "docs/static/img/flow.wsd",
    "content": "@startuml\n' © Sebastian Porto 2016, \n' licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.\nautonumber\nparticipant program #white\nparticipant update #white\nparticipant view #white\n\nprogram -> view : Render view\n|||\nview -> program : Trigger message e.g. Expand\nprogram -> update : Send message with the current state\nupdate --> program : Return updated state and command\nprogram -> view : Render view\n@enduml"
  },
  {
    "path": "docs/static/img/parent-child.wsd",
    "content": "@startuml \"parent-child\"\n' © Sebastian Porto 2016, \n' licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.\nautonumber \"<b>(#)\"\nparticipant User #white\nparticipant program #white\nparticipant Main.initialModel as Mim #white\nparticipant Main.view as MV #white\nparticipant Main.update as MU #white\nparticipant Widget.initialModel as Wim #white\nparticipant Widget.view as WV #white\nparticipant Widget.update as WU #white\n\nprogram -> Mim: initialModel\nMim -> Wim: initialModel\nWim --> Mim: widgetModel\nMim --> program: mainModel\nprogram -> MV : mainModel\nMV -> WV : widgetModel\nWV --> MV : Html\nMV --> program : Html\nprogram -> User : Html\n\nnewpage\n\nautonumber 1 \"<b>(#)\"\nUser -> WV : Click\nWV -> MV: Increase\nMV -> program: (WidgetMsg Increase)\nprogram -> MU: (WidgetMsg Increase) mainModel\nMU -> WU : Increase widgetModel\nWU --> MU: (updated widgetModel, command)\nMU --> program: (updated mainModel, command)\nprogram -> MV : mainModel\nMV -> WV : widgetModel\nWV --> MV : Html\nMV --> program : Html\n@enduml"
  },
  {
    "path": "docs/style.scss",
    "content": "@import \"./../node_modules/bulma/sass/utilities/initial-variables\";\n\n// Color palette\n// https://lospec.com/palette-list/fluffy8\n\n/////////////////////////////////\n/// Customize Bulma\n/////////////////////////////////\n$primary: #2d3947;\n$text: #2b2b2b;\n$danger: #c43636;\n\n@import \"./../node_modules/bulma/sass/utilities/derived-variables\";\n\n/////////////////////////////////\n/// nacara-layout-standard customizations\n/// Do not touch unless you know what you are doing\n/////////////////////////////////\n$navbar-breakpoint: 0px;\n$navbar-padding-vertical: 0.5rem;\n$navbar-padding-horizontal: 1rem;\n/////////////////////////////////\n\n// Specific to gatsby-remark-vscode usage\n$content-pre-padding: unset;\n\n/////////////////////////////////\n/// Customize Bulma\n/////////////////////////////////\n\n$navbar-item-color: $white;\n$navbar-background-color: $primary;\n$navbar-item-active-color: $white;\n$navbar-item-active-background-color: lighten($primary, 12%);\n$navbar-item-hover-color: $white;\n$navbar-item-hover-background-color: lighten($primary, 12%);;\n$navbar-dropdown-item-active-background-color: $primary;\n$navbar-dropdown-item-hover-background-color: $primary;\n$navbar-dropdown-item-hover-color: $white;\n$navbar-dropdown-item-active-color: $white;\n\n$menu-item-active-background-color: $primary;\n$menu-item-active-color: $white;\n$menu-item-hover-color: $primary;\n$menu-item-hover-background-color: transparent;\n$menu-label-font-size: $size-6;\n$menu-item-radius: $radius-large $radius-large;\n\n$footer-background-color: $primary;\n$footer-color: $white;\n\n$code: $red;\n\n$nacara-navbar-dropdown-floating-max-width: 450px;\n\n$body-size: 14px;\n\n@import \"../node_modules/bulma/sass/utilities/_all.sass\";\n@import \"./../node_modules/bulma/bulma.sass\";\n@import \"./../node_modules/nacara-layout-standard/scss/nacara.scss\";\n@import \"./scss/fable-font.scss\";\n\n// Begin gatsby-remark-vscode specific\n:root {\n    --grvsc-padding-v: 1.25rem;\n}\n\n// Make the code use the full width for when user use line highlighting\n.content {\n    pre > code {\n        width: 100%;\n    }\n}\n// End gatsby-remark-vscode specific\n\n// Override bulma\n.navbar {\n    .navbar-dropdown {\n        @include desktop {\n            // Force navbar item text color otherwise it is the same as $navbar-item-color\n            // Which is white in our case...\n            .navbar-item {\n                color: $text;\n            }\n        }\n    }\n\n    .navbar-link {\n        &:not(.is-arrowless)::after {\n            border-color: $white;\n        }\n    }\n}\n\n.footer a {\n    color: $white;\n}\n\n.sitemap {\n\n    max-width: 1024px;\n    margin: 0 auto 2rem;\n    display: grid;\n    grid-gap: 4rem;\n    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));\n    font-size: $size-6;\n\n    @include mobile {\n        grid-template-columns: 1fr;\n        grid-gap: 1rem;\n    }\n\n    a {\n        color : white;\n    }\n\n    .sitemap-section {\n        width: 100%;\n\n        .sitemap-section-title {\n            font-size: $size-4;\n            font-weight: $weight-bold;\n            text-align: center;\n            padding-bottom: 1rem;\n\n            @include mobile {\n                text-align: left;\n            }\n        }\n\n        .sitemap-section-list {\n\n            li {\n                border-top: 2px solid lighten($primary, 8%);\n            }\n\n            .sitemap-section-list-item {\n                padding: 1rem 0.5rem;\n                width: 100%;\n\n                &:hover {\n                    background-color: lighten($primary, 4%);\n                }\n\n                .icon-text:hover {\n                    .sitemap-section-list-item-text {\n                        text-decoration: underline;\n                    }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "global.json",
    "content": "{\n  \"sdk\": {\n    \"version\": \"8.0.401\",\n    \"rollForward\": \"latestMinor\"\n  }\n}"
  },
  {
    "path": "nacara.config.json",
    "content": "{\n    \"siteMetadata\": {\n        \"title\": \"Elmish\",\n        \"url\": \"https://elmish.github.io\",\n        \"baseUrl\": \"/elmish/\",\n        \"editUrl\" : \"https://github.com/elmish/elmish/edit/v4.x/docs\",\n        \"favIcon\": \"img/logo.png\"\n    },\n    \"navbar\": {\n        \"start\": [\n            {\n                \"pinned\": true,\n                \"label\": \"Docs\",\n                \"url\": \"/elmish/docs/basics.html\"\n            }\n        ],\n        \"end\": [\n            {\n                \"url\": \"https://github.com/elmish/elmish\",\n                \"icon\": \"fab fa-2x fa-github\",\n                \"label\": \"GitHub\"\n            }\n        ]\n    },\n    \"remarkPlugins\": [\n        {\n            \"resolve\": \"gatsby-remark-vscode\",\n            \"property\": \"remarkPlugin\",\n            \"options\": {\n                \"theme\": \"Atom One Light\",\n                \"extensions\": [\n                    \"vscode-theme-onelight\"\n                ]\n            }\n        }\n    ],\n    \"layouts\": [\n        \"nacara-layout-standard\"\n    ]\n}\n"
  },
  {
    "path": "netstandard/Elmish.fsproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <Description>Elmish core for .NET apps</Description>\n    <TargetFrameworks>netstandard2.0;net8.0</TargetFrameworks>\n    <GenerateDocumentationFile>true</GenerateDocumentationFile>\n    <DisableImplicitFSharpCoreReference>True</DisableImplicitFSharpCoreReference>\n  </PropertyGroup>\n  <ItemGroup>\n    <Compile Include=\"../src/prelude.fs\" />\n    <Compile Include=\"../src/cmd.fs\" />\n    <Compile Include=\"../src/sub.fs\" />\n    <Compile Include=\"../src/ring.fs\" />\n    <Compile Include=\"../src/program.fs\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ImportPackage Update=\"FSharp.Core\" Version=\"4.7.*\" />\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "package.json",
    "content": "{\n    \"name\": \"hmr\",\n    \"private\": true,\n    \"type\": \"module\",\n    \"engines\": {\n        \"node\": \"^12.20.0 || ^14.13.1 || >=16.0.0\",\n        \"npm\": \">=7.0.0\"\n    },\n    \"scripts\": {\n        \"docs:watch\": \"nacara watch\",\n        \"docs:build\": \"nacara build\",\n        \"docs:publish\": \"nacara build && gh-pages -d docs_deploy\"\n    },\n    \"repository\": {\n        \"type\": \"git\",\n        \"url\": \"git+https://github.com/elmish/hmr.git\"\n    },\n    \"devDependencies\": {\n        \"@babel/preset-react\": \"^7.16.0\",\n        \"bulma\": \"^0.9.3\",\n        \"gatsby-remark-vscode\": \"^3.3.1\",\n        \"nacara-layout-standard\": \"^1.8.0\",\n        \"react\": \"^18.2.0\",\n        \"react-dom\": \"^18.2.0\",\n        \"unified\": \"^10.1.1\",\n        \"vscode-theme-onelight\": \"github:akamud/vscode-theme-onelight\"\n    },\n    \"dependencies\": {\n        \"nacara\": \"^1.8.0\",\n        \"remark-parse\": \"^10.0.1\"\n    }\n}\n"
  },
  {
    "path": "src/Fable.Elmish.fsproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <TargetFramework>netstandard2.0</TargetFramework>\n    <GenerateDocumentationFile>true</GenerateDocumentationFile>\n    <DefineConstants>$(DefineConstants);FABLE_COMPILER</DefineConstants>\n    <Description>Elmish for Fable apps</Description>\n  </PropertyGroup>\n  <ItemGroup>\n    <Compile Include=\"prelude.fs\" />\n    <Compile Include=\"cmd.fs\" />\n    <Compile Include=\"cmd.obsolete.fs\" />\n    <Compile Include=\"sub.fs\" />\n    <Compile Include=\"ring.fs\" />\n    <Compile Include=\"program.fs\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Content Include=\"*.fsproj; *.fs\" PackagePath=\"fable\\\" />\n  </ItemGroup>\n  <ItemGroup>\n    <PackageReference Update=\"FSharp.Core\" Version=\"4.7.*\" />\n    <PackageReference Include=\"Fable.Core\" Version=\"4.0.0\" />\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "src/cmd.fs",
    "content": "(**\nCmd\n---------\nCore abstractions for dispatching messages in Elmish.\n\n*)\n\nnamespace Elmish\n\nopen System\n\n/// Dispatch - feed new message into the processing loop\ntype Dispatch<'msg> = 'msg -> unit\n\n/// Effect - return immediately, but may schedule dispatch of a message at any time\ntype Effect<'msg> = Dispatch<'msg> -> unit\n\n/// Cmd - container for effects that may produce messages\ntype Cmd<'msg> = Effect<'msg> list\n\n/// Cmd module for creating and manipulating commands\n[<RequireQualifiedAccess>]\nmodule Cmd =\n    /// Execute the commands using the supplied dispatcher\n    let internal exec onError (dispatch: Dispatch<'msg>) (cmd: Cmd<'msg>) =\n        cmd |> List.iter (fun call -> try call dispatch with ex -> onError ex)\n\n    /// None - no commands, also known as `[]`\n    let none : Cmd<'msg> =\n        []\n\n    /// When emitting the message, map to another type\n    let map (f: 'a -> 'msg) (cmd: Cmd<'a>) : Cmd<'msg> =\n        cmd |> List.map (fun g -> (fun dispatch -> f >> dispatch) >> g)\n\n    /// Aggregate multiple commands\n    let batch (cmds: #seq<Cmd<'msg>>) : Cmd<'msg> =\n        cmds |> List.concat\n\n    /// Command to call the effect\n    let ofEffect (effect: Effect<'msg>) : Cmd<'msg> =\n        [effect]\n\n    module OfFunc =\n        /// Command to evaluate a simple function and map the result\n        /// into success or error (of exception)\n        let either (task: 'a -> _) (arg: 'a) (ofSuccess: _ -> 'msg) (ofError: _ -> 'msg) : Cmd<'msg> =\n            let bind dispatch =\n                try\n                    task arg\n                    |> (ofSuccess >> dispatch)\n                with x ->\n                    x |> (ofError >> dispatch)\n            [bind]\n\n        /// Command to evaluate a simple function and map the success to a message\n        /// discarding any possible error\n        let perform (task: 'a -> _) (arg: 'a) (ofSuccess: _ -> 'msg) : Cmd<'msg> =\n            let bind dispatch =\n                try\n                    task arg\n                    |> (ofSuccess >> dispatch)\n                with _ ->\n                    ()\n            [bind]\n\n        /// Command to evaluate a simple function and map the error (in case of exception)\n        let attempt (task: 'a -> unit) (arg: 'a) (ofError: _ -> 'msg) : Cmd<'msg> =\n            let bind dispatch =\n                try\n                    task arg\n                with x ->\n                    x |> (ofError >> dispatch)\n            [bind]\n\n    module OfAsyncWith =\n        /// Command that will evaluate an async block and map the result\n        /// into success or error (of exception)\n        let either (start: Async<unit> -> unit)\n                   (task: 'a -> Async<_>)\n                   (arg: 'a)\n                   (ofSuccess: _ -> 'msg)\n                   (ofError: _ -> 'msg) : Cmd<'msg> =\n            let bind dispatch =\n                async {\n                    try\n                        let! r = task arg\n                        dispatch (ofSuccess r)\n                    with x -> dispatch (ofError x)\n                }\n            [bind >> start]\n\n        /// Command that will evaluate an async block and map the success\n        let perform (start: Async<unit> -> unit)\n                    (task: 'a -> Async<_>)\n                    (arg: 'a)\n                    (ofSuccess: _ -> 'msg) : Cmd<'msg> =\n            let bind dispatch =\n                async {\n                    try\n                        let! r = task arg\n                        dispatch (ofSuccess r)\n                    with _ -> ()\n                }\n            [bind >> start]\n\n        /// Command that will evaluate an async block and map the error (of exception)\n        let attempt (start: Async<unit> -> unit)\n                    (task: 'a -> Async<_>)\n                    (arg: 'a)\n                    (ofError: _ -> 'msg) : Cmd<'msg> =\n            let bind dispatch =\n                async {\n                    try\n                        let! _ = task arg\n                        ()\n                    with x -> dispatch (ofError x)\n                }\n            [bind >> start]\n\n    module OfAsync =\n        [<Obsolete(\"Use `AsyncHelpers.start` instead\")>]\n#if FABLE_COMPILER\n        let start x = Timer.delay 1 (fun _ -> Async.StartImmediate x)\n#else\n        let inline start x = Async.Start x\n#endif\n        /// Command that will evaluate an async block and map the result\n        /// into success or error (of exception)\n        let inline either (task: 'a -> Async<_>)\n                          (arg: 'a)\n                          (ofSuccess: _ -> 'msg)\n                          (ofError: _ -> 'msg) : Cmd<'msg> =\n            OfAsyncWith.either AsyncHelpers.start task arg ofSuccess ofError\n\n        /// Command that will evaluate an async block and map the success\n        let inline perform (task: 'a -> Async<_>)\n                           (arg: 'a)\n                           (ofSuccess: _ -> 'msg) : Cmd<'msg> =\n            OfAsyncWith.perform AsyncHelpers.start task arg ofSuccess\n\n        /// Command that will evaluate an async block and map the error (of exception)\n        let inline attempt (task: 'a -> Async<_>)\n                           (arg: 'a)\n                           (ofError: _ -> 'msg) : Cmd<'msg> =\n            OfAsyncWith.attempt AsyncHelpers.start task arg ofError\n\n    module OfAsyncImmediate =\n        /// Command that will evaluate an async block and map the result\n        /// into success or error (of exception)\n        let inline either (task: 'a -> Async<_>)\n                          (arg: 'a)\n                          (ofSuccess: _ -> 'msg)\n                          (ofError: _ -> 'msg) : Cmd<'msg> =\n            OfAsyncWith.either Async.StartImmediate task arg ofSuccess ofError\n\n        /// Command that will evaluate an async block and map the success\n        let inline perform (task: 'a -> Async<_>)\n                           (arg: 'a)\n                           (ofSuccess: _ -> 'msg) : Cmd<'msg> =\n            OfAsyncWith.perform Async.StartImmediate task arg ofSuccess\n\n        /// Command that will evaluate an async block and map the error (of exception)\n        let inline attempt (task: 'a -> Async<_>)\n                           (arg: 'a)\n                           (ofError: _ -> 'msg) : Cmd<'msg> =\n            OfAsyncWith.attempt Async.StartImmediate task arg ofError\n\n#if FABLE_COMPILER\n    module OfPromise =\n        /// Command to call `promise` block and map the results\n        let either (task: 'a -> Fable.Core.JS.Promise<_>)\n                   (arg:'a)\n                   (ofSuccess: _ -> 'msg)\n                   (ofError: #exn -> 'msg) : Cmd<'msg> =\n            let bind dispatch =\n                try\n                    (task arg)\n                        .``then``(ofSuccess >> dispatch)\n                        .catch(unbox >> ofError >> dispatch)\n                        |> ignore\n                with x -> x |> unbox |> ofError |> dispatch\n            [bind]\n\n        /// Command to call `promise` block and map the success\n        let perform (task: 'a -> Fable.Core.JS.Promise<_>)\n                   (arg:'a)\n                   (ofSuccess: _ -> 'msg) =\n            let bind dispatch =\n                try\n                    (task arg)\n                        .``then``(ofSuccess >> dispatch)\n                        |> ignore\n                with _ -> ()\n            [bind]\n\n        /// Command to call `promise` block and map the error\n        let attempt (task: 'a -> Fable.Core.JS.Promise<_>)\n                    (arg:'a)\n                    (ofError: #exn -> 'msg) : Cmd<'msg> =\n            let bind dispatch =\n                try\n                    (task arg)\n                        .catch(unbox >> ofError >> dispatch)\n                        |> ignore\n                with x -> x |> unbox |> ofError |> dispatch\n            [bind]\n#else\n    open System.Threading.Tasks\n#if WEBSHARPER\n    module OfTask =\n        /// Command to call a task and map the results\n        let inline either (task: 'a -> Task<_>)\n                          (arg:'a)\n                          (ofSuccess: _ -> 'msg)\n                          (ofError: _ -> 'msg) : Cmd<'msg> =\n            OfAsync.either (task >> Async.AwaitTask) arg ofSuccess ofError\n\n        /// Command to call a task and map the success\n        let inline perform (task: 'a -> Task<_>)\n                           (arg:'a)\n                           (ofSuccess: _ -> 'msg) : Cmd<'msg> =\n            OfAsync.perform (task >> Async.AwaitTask) arg ofSuccess\n\n        /// Command to call a task and map the error\n        let inline attempt (task: 'a -> #Task)\n                           (arg:'a)\n                           (ofError: _ -> 'msg) : Cmd<'msg> =\n            OfAsync.attempt (task >> Async.AwaitTask) arg ofError\n#else\n    module OfTask =\n        /// Command to call a task and map the results\n        let either (task: 'a -> Task<'b>)\n                   (arg:'a)\n                   (ofSuccess: 'b -> 'msg)\n                   (ofError: exn -> 'msg) : Cmd<'msg> =\n            let bind dispatch =\n                try\n                    TaskBuilder.task {\n                        try\n                            let! r = task arg in dispatch (ofSuccess r)\n                        with ex ->\n                            dispatch (ofError ex)\n                    } |> ignore\n                with x ->\n                    dispatch (ofError x)\n            [bind]\n\n        /// Command to call a task and map the success\n        let perform (task: 'a -> Task<'b>)\n                    (arg:'a)\n                    (ofSuccess: 'b -> 'msg) : Cmd<'msg> =\n            let bind dispatch =\n                try\n                    TaskBuilder.task {\n                        try\n                            let! r = task arg in dispatch (ofSuccess r)\n                        with _ -> ()\n                    } |> ignore\n                with _ -> ()\n            [bind]\n\n        /// Command to call a task and map the error\n        let attempt (task: 'a -> #Task)\n                    (arg:'a)\n                    (ofError: exn -> 'msg) : Cmd<'msg> =\n            let bind dispatch =\n                try\n                    TaskBuilder.task {\n                        try\n                            do! (task arg :> Task)\n                        with ex ->\n                            dispatch (ofError ex)\n                    } |> ignore\n                with x ->\n                    dispatch (ofError x)\n            [bind]\n#endif // WEBSHARPER\n#endif // FABLE_COMPILER\n#if NET8_0_OR_GREATER && !(FABLE_COMPILER || WEBSHARPER)\n    module OfValueTask =\n        open System.Threading.Tasks\n        /// Command to call a value task and map the results\n        let either (task: 'a -> ValueTask<'b>)\n                   (arg:'a)\n                   (ofSuccess: 'b -> 'msg)\n                   (ofError: exn -> 'msg) : Cmd<'msg> =\n            let bind dispatch =\n                try\n                    let vt: ValueTask<'b> = task arg\n                    if vt.IsCompleted then\n                        if not vt.IsCompletedSuccessfully then\n                            try\n                                vt.GetAwaiter().GetResult() |> ignore\n                            with ex ->\n                                dispatch (ofError ex)\n                        else\n                            dispatch (ofSuccess vt.Result)\n                    else\n                        TaskBuilder.task {\n                            try\n                                let! r = vt in dispatch (ofSuccess r)\n                            with ex ->\n                                dispatch (ofError ex)\n                        } |> ignore\n                with x ->\n                    dispatch (ofError x)\n            [bind]\n\n        /// Command to call a value task and map the success\n        let perform (task: 'a -> ValueTask<'b>)\n                    (arg:'a)\n                    (ofSuccess: 'b -> 'msg) : Cmd<'msg> =\n            let bind dispatch =\n                try\n                    let vt: ValueTask<'b> = task arg\n                    if vt.IsCompleted then\n                        if not vt.IsCompletedSuccessfully then\n                            try\n                                vt.GetAwaiter().GetResult() |> ignore\n                            with _ -> ()\n                        else\n                            dispatch (ofSuccess vt.Result)\n                    else\n                        TaskBuilder.task {\n                            try\n                                let! r = vt in dispatch (ofSuccess r)\n                            with _ -> ()\n                        } |> ignore\n                with _ -> ()\n            [bind]\n\n        /// Command to call a value task and map the error\n        let attempt (task: 'a -> ValueTask)\n                    (arg:'a)\n                    (ofError: exn -> 'msg) : Cmd<'msg> =\n            let bind dispatch =\n                try\n                    let vt: ValueTask = task arg\n                    if vt.IsCompleted then\n                        if not vt.IsCompletedSuccessfully then\n                            try\n                                vt.GetAwaiter().GetResult()\n                            with ex ->\n                                dispatch (ofError ex)\n                    else\n                        TaskBuilder.task {\n                            try\n                                let! _ = vt in ()\n                            with ex ->\n                                dispatch (ofError ex)\n                        } |> ignore\n                with x ->\n                    dispatch (ofError x)\n            [bind]\n#endif\n\n    /// Command to issue a specific message\n    let inline ofMsg (msg:'msg) : Cmd<'msg> =\n        [fun dispatch -> dispatch msg]\n"
  },
  {
    "path": "src/cmd.obsolete.fs",
    "content": "namespace Elmish\n\nopen System\n\n#nowarn \"44\"\n[<AutoOpen>]\nmodule Obsolete =\n    /// Cmd module for creating and manipulating commands\n    [<RequireQualifiedAccess>]\n    module Cmd =\n        module OfFunc =\n            /// Command to issue a specific message\n            [<Obsolete(\"Use `either`,`attempt` or `perform` instead\")>]\n            let result (msg:'msg) : Cmd<'msg> =\n                [fun dispatch -> dispatch msg]\n\n        module OfAsyncWith =\n            /// Command that will evaluate an async block to the message\n            [<Obsolete(\"Use `either`,`attempt` or `perform` instead\")>]\n            let result (start: Async<unit> -> unit)\n                    (task: Async<'msg>) : Cmd<'msg> =\n                let bind dispatch =\n                    async {\n                        let! r = task\n                        dispatch r\n                    }\n                [bind >> start]\n\n        module OfAsync =\n            /// Command that will evaluate an async block to the message\n            [<Obsolete(\"Use `either`,`attempt` or `perform` instead\")>]\n            let inline result (task: Async<'msg>) : Cmd<'msg> =\n                OfAsyncWith.result Cmd.OfAsync.start task\n\n        module OfAsyncImmediate =\n            /// Command that will evaluate an async block to the message\n            [<Obsolete(\"Use `either`,`attempt` or `perform` instead\")>]\n            let inline result (task: Async<'msg>) : Cmd<'msg> =\n                OfAsyncWith.result Async.StartImmediate task\n\n    #if FABLE_COMPILER\n        module OfPromise =\n            /// Command to dispatch the `promise` result\n            [<Obsolete(\"Use `either`,`attempt` or `perform` instead\")>]\n            let result (task: Fable.Core.JS.Promise<'msg>) : Cmd<'msg> =\n                let bind dispatch =\n                    task.``then`` dispatch\n                    |> ignore\n                [bind]\n    #else\n        open System.Threading.Tasks\n        module OfTask =\n            /// Command and map the task success\n            [<Obsolete(\"Use `either`,`attempt` or `perform` instead\")>]\n            let inline result (task: Task<'msg>) : Cmd<'msg> =\n                OfAsync.result (task |> Async.AwaitTask)\n    #endif\n"
  },
  {
    "path": "src/prelude.fs",
    "content": "namespace Elmish\n\n(**\nLog\n---------\nBasic cross-platform logging API.\n\n*)\nmodule internal Log =\n\n#if FABLE_COMPILER\n    open Fable.Core.JS\n\n    let onError (text: string, ex: exn) = console.error (text,ex)\n    let toConsole(text: string, o: #obj) = console.log(text,o)\n\n#else\n#if NETSTANDARD2_0\n    let onError (text: string, ex: exn) = System.Diagnostics.Trace.TraceError(\"{0}: {1}\", text, ex)\n    let toConsole(text: string, o: #obj) = printfn \"%s: %A\" text o\n#else\n    let onError (text: string, ex: exn) = System.Console.Error.WriteLine(\"{0}: {1}\", text, ex)\n    let toConsole(text: string, o: #obj) = printfn \"%s: %A\" text o\n#endif\n#endif\n\n#if FABLE_COMPILER\nmodule internal Timer =\n    open System.Timers\n    let delay interval callback =\n        let t = new Timer(float interval, AutoReset = false)\n        t.Elapsed.Add callback\n        t.Enabled <- true\n        t.Start()\n#endif\n\nmodule AsyncHelpers =\n#if FABLE_COMPILER\n    let start x = Timer.delay 1 (fun _ -> Async.StartImmediate x)\n#else\n    let inline start x = Async.Start x\n#endif"
  },
  {
    "path": "src/program.fs",
    "content": "(**\nProgram\n---------\nCore abstractions for creating and running the dispatch loop.\n\n*)\n\nnamespace Elmish\n\n\n/// Program type captures various aspects of program behavior\ntype Program<'arg, 'model, 'msg, 'view> = private {\n    init : 'arg -> 'model * Cmd<'msg>\n    update : 'msg -> 'model -> 'model * Cmd<'msg>\n    subscribe : 'model -> Sub<'msg>\n    view : 'model -> Dispatch<'msg> -> 'view\n    setState : 'model -> Dispatch<'msg> -> unit\n    onError : (string*exn) -> unit\n    termination : ('msg -> bool) * ('model -> unit)\n}\n\n/// Program module - functions to manipulate program instances\n[<RequireQualifiedAccess>]\n[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]\nmodule Program =\n    /// Typical program, new commands are produced by `init` and `update` along with the new state.\n    let mkProgram\n        (init : 'arg -> 'model * Cmd<'msg>)\n        (update : 'msg -> 'model -> 'model * Cmd<'msg>)\n        (view : 'model -> Dispatch<'msg> -> 'view) =\n        { init = init\n          update = update\n          view = view\n          setState = fun model -> view model >> ignore\n          subscribe = fun _ -> Sub.none\n          onError = Log.onError\n          termination = (fun _ -> false), ignore }\n\n    /// Simple program that produces only new state with `init` and `update`.\n    let mkSimple\n        (init : 'arg -> 'model)\n        (update : 'msg -> 'model -> 'model)\n        (view : 'model -> Dispatch<'msg> -> 'view) =\n        { init = init >> fun state -> state, Cmd.none\n          update = fun msg -> update msg >> fun state -> state, Cmd.none\n          view = view\n          setState = fun model -> view model >> ignore\n          subscribe = fun _ -> Sub.none\n          onError = Log.onError\n          termination = (fun _ -> false), ignore }\n\n    /// Subscribe to external source of events, overrides existing subscription.\n    /// Return the subscriptions that should be active based on the current model.\n    /// Subscriptions will be started or stopped automatically to match.\n    let withSubscription (subscribe : 'model -> Sub<'msg>) (program: Program<'arg, 'model, 'msg, 'view>) =\n        { program with\n            subscribe = subscribe }\n\n    /// Map existing subscription to external source of events.\n    let mapSubscription map (program: Program<'arg, 'model, 'msg, 'view>) =\n        { program with\n            subscribe = map program.subscribe }\n\n    /// Trace all the updates to the console\n    let withConsoleTrace (program: Program<'arg, 'model, 'msg, 'view>) =\n        let traceInit (arg:'arg) =\n            let initModel,cmd = program.init arg\n            Log.toConsole (\"Initial state:\", initModel)\n            initModel,cmd\n\n        let traceUpdate msg model =\n            Log.toConsole (\"New message:\", msg)\n            let newModel,cmd = program.update msg model\n            Log.toConsole (\"Updated state:\", newModel)\n            newModel,cmd\n\n        let traceSubscribe model =\n            let sub = program.subscribe model\n            Log.toConsole (\"Updated subs:\", sub |> List.map fst)\n            sub\n\n        { program with\n            init = traceInit\n            update = traceUpdate\n            subscribe = traceSubscribe }\n\n    /// Trace all the messages as they update the model and subscriptions\n    let withTrace trace (program: Program<'arg, 'model, 'msg, 'view>) =\n        let update msg model =\n            let state,cmd = program.update msg model\n            let subIds = program.subscribe state |> List.map fst\n            trace msg state subIds\n            state,cmd\n        { program with\n            update = update }\n\n    /// Handle dispatch loop exceptions\n    let withErrorHandler onError (program: Program<'arg, 'model, 'msg, 'view>) =\n        { program with\n            onError = onError }\n\n    /// Exit criteria and the handler, overrides existing.\n    let withTermination (predicate: 'msg -> bool) (terminate: 'model -> unit) (program: Program<'arg, 'model, 'msg, 'view>) =\n        { program with\n            termination = predicate, terminate }\n\n    /// Map existing criteria and the handler.\n    let mapTermination map (program: Program<'arg, 'model, 'msg, 'view>) =\n        { program with\n            termination = map program.termination }\n\n    /// Map existing error handler and return new `Program`\n    let mapErrorHandler map (program: Program<'arg, 'model, 'msg, 'view>) =\n        { program with\n            onError = map program.onError }\n\n    /// Get the current error handler\n    let onError (program: Program<'arg, 'model, 'msg, 'view>) =\n        program.onError\n\n    /// Function to render the view with the latest state\n    let withSetState (setState:'model -> Dispatch<'msg> -> unit)\n                     (program: Program<'arg, 'model, 'msg, 'view>) =\n        { program with\n            setState = setState }\n\n    /// Return the function to render the state\n    let setState (program: Program<'arg, 'model, 'msg, 'view>) =\n        program.setState\n\n    /// Return the view function\n    let view (program: Program<'arg, 'model, 'msg, 'view>) =\n        program.view\n\n    /// Return the init function\n    let init (program: Program<'arg, 'model, 'msg, 'view>) =\n        program.init\n\n    /// Return the update function\n    let update (program: Program<'arg, 'model, 'msg, 'view>) =\n        program.update\n\n    /// Map the program type\n    let map mapInit mapUpdate mapView mapSetState mapSubscribe mapTermination\n            (program: Program<'arg, 'model, 'msg, 'view>) =\n        { init = mapInit program.init\n          update = mapUpdate program.update\n          view = mapView program.view\n          setState = mapSetState program.setState\n          subscribe = mapSubscribe program.subscribe\n          onError = program.onError\n          termination = mapTermination program.termination }\n\n    module Subs = Sub.Internal\n\n    /// Start the program loop.\n    /// syncDispatch: specify how to serialize dispatch calls.\n    /// arg: argument to pass to the init() function.\n    /// program: program created with 'mkSimple' or 'mkProgram'.\n    let runWithDispatch (syncDispatch: Dispatch<'msg> -> Dispatch<'msg>) (arg: 'arg) (program: Program<'arg, 'model, 'msg, 'view>) =\n        let (model,cmd) = program.init arg\n        let sub = program.subscribe model\n        let toTerminate, terminate = program.termination\n        let rb = RingBuffer 10\n        let mutable reentered = false\n        let mutable state = model\n        let mutable activeSubs = Subs.empty\n        let mutable terminated = false\n        let rec dispatch msg =\n            if not terminated then\n                rb.Push msg\n                if not reentered then\n                    reentered <- true\n                    processMsgs ()\n                    reentered <- false\n        and dispatch' = syncDispatch dispatch // serialized dispatch\n        and processMsgs () =\n            let mutable nextMsg = rb.Pop()\n            while not terminated && Option.isSome nextMsg do\n                let msg = nextMsg.Value\n                try\n                    if toTerminate msg then\n                        Subs.Fx.stop program.onError activeSubs\n                        terminate state\n                        terminated <- true\n                    else\n                        let (model',cmd') = program.update msg state\n                        let sub' = program.subscribe model'\n                        program.setState model' dispatch'\n                        activeSubs <- Subs.diff activeSubs sub' |> Subs.Fx.change program.onError dispatch'\n                        cmd' |> Cmd.exec (fun ex -> program.onError (sprintf \"Error handling the message: %A\" msg, ex)) dispatch'\n                        state <- model'\n                with ex ->\n                    program.onError (sprintf \"Unable to process the message: %A\" msg, ex)\n                nextMsg <- rb.Pop()\n\n        reentered <- true\n        program.setState model dispatch'\n        activeSubs <- Subs.diff activeSubs sub |> Subs.Fx.change program.onError dispatch'\n        cmd |> Cmd.exec (fun ex -> program.onError (sprintf \"Error intitializing:\", ex)) dispatch'\n        processMsgs ()\n        reentered <- false\n\n\n    /// Start the single-threaded dispatch loop.\n    /// arg: argument to pass to the 'init' function.\n    /// program: program created with 'mkSimple' or 'mkProgram'.\n    let runWith (arg: 'arg) (program: Program<'arg, 'model, 'msg, 'view>) = runWithDispatch id arg program\n\n    /// Start the dispatch loop with `unit` for the init() function.\n    let run (program: Program<unit, 'model, 'msg, 'view>) = runWith () program\n"
  },
  {
    "path": "src/ring.fs",
    "content": "namespace Elmish\nopen System\n\n[<Struct>]\ntype internal RingState<'item> =\n    | Writable of wx:'item array * ix:int\n    | ReadWritable of rw:'item array * wix:int * rix:int\n\ntype internal RingBuffer<'item>(size) =\n    let doubleSize ix (items: 'item array) =\n        seq { yield! items |> Seq.skip ix\n              yield! items |> Seq.take ix\n              for _ in 0..items.Length do\n                yield Unchecked.defaultof<'item> }\n        |> Array.ofSeq\n\n    let mutable state : 'item RingState =\n        Writable (Array.zeroCreate (max size 10), 0)\n\n    member __.Pop() =\n        match state with\n        | ReadWritable (items, wix, rix) ->\n            let rix' = (rix + 1) % items.Length\n            match rix' = wix with\n            | true ->\n                state <- Writable(items, wix)\n            | _ ->\n                state <- ReadWritable(items, wix, rix')\n            Some items.[rix]\n        | _ ->\n            None\n\n    member __.Push (item:'item) =\n        match state with\n        | Writable (items, ix) ->\n            items.[ix] <- item\n            let wix = (ix + 1) % items.Length\n            state <- ReadWritable(items, wix, ix)\n        | ReadWritable (items, wix, rix) ->\n            items.[wix] <- item\n            let wix' = (wix + 1) % items.Length\n            match wix' = rix with\n            | true ->\n                state <- ReadWritable(items |> doubleSize rix, items.Length, 0)\n            | _ ->\n                state <- ReadWritable(items, wix', rix)"
  },
  {
    "path": "src/sub.fs",
    "content": "namespace Elmish\n\nopen System\n\n/// SubId - Subscription ID, alias for string list\ntype SubId = string list\n\n/// Subscribe - Starts a subscription, returns IDisposable to stop it\ntype Subscribe<'msg> = Dispatch<'msg> -> IDisposable\n\n/// Subscription - Generates new messages when running\ntype Sub<'msg> = (SubId * Subscribe<'msg>) list\n\nmodule Sub =\n\n    /// None - no subscriptions, also known as `[]`\n    let none : Sub<'msg> =\n        []\n\n    /// Aggregate multiple subscriptions\n    let batch (subs: #seq<Sub<'msg>>) : Sub<'msg> =\n        subs |> List.concat\n\n    /// When emitting the message, map to another type.\n    /// To avoid ID conflicts with other components, scope SubIds with a prefix.\n    let map (idPrefix: string) (f: 'a -> 'msg) (sub: Sub<'a>) : Sub<'msg> =\n        sub |> List.map (fun (subId, subscribe) ->\n            idPrefix :: subId,\n            fun dispatch -> subscribe (f >> dispatch))\n\n    module Internal =\n\n        module SubId =\n\n            let toString (subId: SubId) =\n                String.Join(\"/\", subId)\n\n        module Fx =\n\n            let warnDupe onError subId =\n                let ex = exn \"Duplicate SubId\"\n                onError (\"Duplicate SubId: \" + SubId.toString subId, ex)\n\n            let tryStop onError (subId, sub: IDisposable) =\n                try\n                    sub.Dispose()\n                with ex ->\n                    onError (\"Error stopping subscription: \" + SubId.toString subId, ex)\n\n            let tryStart onError dispatch (subId, start) : (SubId * IDisposable) option =\n                try\n                    Some (subId, start dispatch)\n                with ex ->\n                    onError (\"Error starting subscription: \" + SubId.toString subId, ex)\n                    None\n\n            let stop onError subs =\n                subs |> List.iter (tryStop onError)\n\n            let change onError dispatch (dupes, toStop, toKeep, toStart) =\n                dupes |> List.iter (warnDupe onError)\n                toStop |> List.iter (tryStop onError)\n                let started = toStart |> List.choose (tryStart onError dispatch)\n                List.append toKeep started\n\n        module NewSubs =\n\n            let (_dupes, _newKeys, _newSubs) as init =\n                List.empty, Set.empty, List.empty\n\n            let update (subId, start) (dupes, newKeys, newSubs) =\n                if Set.contains subId newKeys then\n                    subId :: dupes, newKeys, newSubs\n                else\n                    dupes, Set.add subId newKeys, (subId, start) :: newSubs\n\n            let calculate subs =\n                List.foldBack update subs init\n\n        let empty = List.empty<SubId * IDisposable>\n\n        let diff (activeSubs: (SubId * IDisposable) list) (sub: Sub<'msg>) =\n            let keys = activeSubs |> List.map fst |> Set.ofList\n            let dupes, newKeys, newSubs = NewSubs.calculate sub\n            if keys = newKeys then\n                dupes, [], activeSubs, []\n            else\n                let toKeep, toStop = activeSubs |> List.partition (fun (k, _) -> Set.contains k newKeys)\n                let toStart = newSubs |> List.filter (fun (k, _) -> not (Set.contains k keys))\n                dupes, toStop, toKeep, toStart\n"
  },
  {
    "path": "tests/Attributes.fs",
    "content": "﻿namespace Elmish.Tests\n\nopen NUnit.Framework\n\n[<assembly: Parallelizable(ParallelScope.All)>]\n\ndo ()"
  },
  {
    "path": "tests/CmdTests.fs",
    "content": "module Elmish.CmdTests\n\nopen NUnit.Framework\nopen Swensen.Unquote\nopen Elmish\n\ntype Msg =\n    | OnError of exn\n    | OnSuccess of string\n\n\n[<Test>]\nlet ``Cmd.OfAsync.either - works`` () =\n    let myTask () =\n        async {\n            return \"Task completed\"\n        }\n\n    let init () = \"initial\", Cmd.OfAsync.either myTask () OnSuccess OnError\n    let update msg _ =\n        match msg with\n        | OnError ex -> ex.Message, Cmd.none\n        | OnSuccess res -> res, Cmd.none\n    let mutable result = \"\"\n    let view model _ = result <- model\n    async {\n        Program.mkProgram init update view\n        |> Program.run\n    } |> Async.Start\n    System.Threading.Thread.Sleep (1_000)\n    result =! \"Task completed\"\n\n[<Test>]\nlet ``Cmd.OfAsync.attempt - works`` () =\n    let mutable result = \"\"\n    let myTask () =\n        async {\n            // Cmd.OfAsync.attempt don't notifiy about success\n            // so we use a mutable variable to check if the task was called\n            result <- \"Task called\"\n            return \"Task completed\"\n        }\n    let init () = \"initial\", Cmd.OfAsync.attempt myTask () OnError\n    let update msg _ =\n        match msg with\n        | OnError ex -> \"Error was captured\", Cmd.none\n        | OnSuccess res -> res, Cmd.none\n    let view model _ = result <- model\n    async {\n        Program.mkProgram init update view\n        |> Program.run\n    } |> Async.Start\n    System.Threading.Thread.Sleep (1_000)\n    result =! \"Task called\"\n\n[<Test>]\nlet ``Cmd.OfAsync.perform - works`` () =\n    let myTask () =\n        async {\n            return \"Task completed\"\n        }\n\n    let init () = \"initial\", Cmd.OfAsync.perform myTask () OnSuccess\n    let update msg _ =\n        match msg with\n        | OnError ex -> ex.Message, Cmd.none\n        | OnSuccess res -> res, Cmd.none\n    let mutable result = \"\"\n    let view model _ = result <- model\n    async {\n        Program.mkProgram init update view\n        |> Program.run\n    } |> Async.Start\n    System.Threading.Thread.Sleep (1_000)\n    result =! \"Task completed\"\n\n[<Test>]\nlet ``Cmd.OfAsync.either - thrown exception when generating task should be captured`` () =\n    let myTask () =\n        failwith \"Boom!\"\n        async {\n            return \"Task completed\"\n        }\n\n    let init () = \"initial\", Cmd.OfAsync.either myTask () OnSuccess OnError\n    let update msg _ =\n        match msg with\n        | OnError ex -> ex.Message, Cmd.none\n        | OnSuccess res -> res, Cmd.none\n    let mutable result = \"\"\n    let view model _ = result <- model\n    async {\n        Program.mkProgram init update view\n        |> Program.run\n    } |> Async.Start\n    System.Threading.Thread.Sleep (1_000)\n    result =! \"Boom!\"\n\n[<Test>]\nlet ``Cmd.OfAsync.attempt - thrown exception when generating task should be captured`` () =\n    let myTask () =\n        failwith \"Boom!\"\n        async {\n            return \"Task completed\"\n        }\n\n    let init () = \"initial\", Cmd.OfAsync.attempt myTask () OnError\n    let update msg _ =\n        match msg with\n        | OnError ex -> \"Error was captured\", Cmd.none\n        | OnSuccess res -> res, Cmd.none\n    let mutable result = \"\"\n    let view model _ = result <- model\n    async {\n        Program.mkProgram init update view\n        |> Program.run\n    } |> Async.Start\n    System.Threading.Thread.Sleep (1_000)\n    result =! \"Error was captured\"\n\n[<Test>]\nlet ``Cmd.OfAsync.perform - thrown exception when generating task should be discarded`` () =\n    let myTask () =\n        failwith \"Boom!\"\n        async {\n            return \"Task completed\"\n        }\n\n    let init () = \"initial\", Cmd.OfAsync.perform myTask () OnSuccess\n    let update msg _ =\n        match msg with\n        | OnError ex -> ex.Message, Cmd.none\n        | OnSuccess res -> res, Cmd.none\n    let mutable result = \"\"\n    let view model _ = result <- model\n    async {\n        Program.mkProgram init update view\n        |> Program.run\n    } |> Async.Start\n    System.Threading.Thread.Sleep (1_000)\n    result =! \"initial\"\n\n[<Test>]\nlet ``Cmd.OfAsync.either - thrown exception from inside task should be captured`` () =\n    let myTask () =\n        async {\n            failwith \"Boom!\"\n            return \"Task completed\"\n        }\n\n    let init () = \"initial\", Cmd.OfAsync.either myTask () OnSuccess OnError\n    let update msg _ =\n        match msg with\n        | OnError ex -> ex.Message, Cmd.none\n        | OnSuccess res -> res, Cmd.none\n    let mutable result = \"\"\n    let view model _ = result <- model\n    async {\n        Program.mkProgram init update view\n        |> Program.run\n    } |> Async.Start\n    System.Threading.Thread.Sleep (1_000)\n    result =! \"Boom!\"\n\n[<Test>]\nlet ``Cmd.OfAsync.attempt - thrown exception from inside task should be captured`` () =\n    let myTask () =\n        async {\n            failwith \"Boom!\"\n            return \"Task completed\"\n        }\n\n    let init () = \"initial\", Cmd.OfAsync.attempt myTask () OnError\n    let update msg _ =\n        match msg with\n        | OnError ex -> \"Error was captured\", Cmd.none\n        | OnSuccess res -> res, Cmd.none\n    let mutable result = \"\"\n    let view model _ = result <- model\n    async {\n        Program.mkProgram init update view\n        |> Program.run\n    } |> Async.Start\n    System.Threading.Thread.Sleep (1_000)\n    result =! \"Error was captured\"\n\n[<Test>]\nlet ``Cmd.OfAsync.perform - thrown exception from inside task should be discarded`` () =\n    let myTask () =\n        async {\n            failwith \"Boom!\"\n            return \"Task completed\"\n        }\n\n    let init () = \"initial\", Cmd.OfAsync.perform myTask () OnSuccess\n    let update msg _ =\n        match msg with\n        | OnError ex -> ex.Message, Cmd.none\n        | OnSuccess res -> res, Cmd.none\n    let mutable result = \"\"\n    let view model _ = result <- model\n    async {\n        Program.mkProgram init update view\n        |> Program.run\n    } |> Async.Start\n    System.Threading.Thread.Sleep (1_000)\n    result =! \"initial\"\n\n#if !FABLE_COMPILER\n\n[<Test>]\nlet ``Cmd.OfTask.either - works`` () =\n    let myTask () =\n        System.Threading.Tasks.Task.FromResult(\"Task completed\")\n\n    let init () = \"initial\", Cmd.OfTask.either myTask () OnSuccess OnError\n    let update msg _ =\n        match msg with\n        | OnError ex -> ex.Message, Cmd.none\n        | OnSuccess res -> res, Cmd.none\n    let mutable result = \"\"\n    let view model _ = result <- model\n    async {\n        Program.mkProgram init update view\n        |> Program.run\n    } |> Async.Start\n    System.Threading.Thread.Sleep (1_000)\n    result =! \"Task completed\"\n\n[<Test>]\nlet ``Cmd.OfTask.attempt - works`` () =\n    let mutable result = \"\"\n    let myTask () =\n        // Cmd.OfTask.attempt don't notify about success\n        // so we use a mutable variable to check if the task was called\n        result <- \"Task called\"\n        System.Threading.Tasks.Task.CompletedTask\n\n    let init () = \"initial\", Cmd.OfTask.attempt myTask () OnError\n    let update msg _ =\n        match msg with\n        | OnError ex -> \"Error was captured\", Cmd.none\n        | OnSuccess res -> res, Cmd.none\n    let view model _ = result <- model\n    async {\n        Program.mkProgram init update view\n        |> Program.run\n    } |> Async.Start\n    System.Threading.Thread.Sleep (1_000)\n    result =! \"Task called\"\n\n[<Test>]\nlet ``Cmd.OfTask.perform - works`` () =\n    let myTask () =\n        System.Threading.Tasks.Task.FromResult(\"Task completed\")\n\n    let init () = \"initial\", Cmd.OfTask.perform myTask () OnSuccess\n    let update msg _ =\n        match msg with\n        | OnError ex -> ex.Message, Cmd.none\n        | OnSuccess res -> res, Cmd.none\n    let mutable result = \"\"\n    let view model _ = result <- model\n    async {\n        Program.mkProgram init update view\n        |> Program.run\n    } |> Async.Start\n    System.Threading.Thread.Sleep (1_000)\n    result =! \"Task completed\"\n\n[<Test>]\nlet ``Cmd.OfTask.either - thrown exception when generating task should be captured`` () =\n    let myTask () =\n        failwith \"Boom!\"\n        System.Threading.Tasks.Task.FromResult(\"Task completed\")\n\n    let init () = \"initial\", Cmd.OfTask.either myTask () OnSuccess OnError\n    let update msg _ =\n        match msg with\n        | OnError ex -> ex.Message, Cmd.none\n        | OnSuccess res -> res, Cmd.none\n    let mutable result = \"\"\n    let view model _ = result <- model\n    async {\n        Program.mkProgram init update view\n        |> Program.run\n    } |> Async.Start\n    System.Threading.Thread.Sleep (1_000)\n    result =! \"Boom!\"\n\n[<Test>]\nlet ``Cmd.OfTask.attempt - thrown exception when generating task should be captured`` () =\n    let myTask () =\n        failwith \"Boom!\"\n        System.Threading.Tasks.Task.CompletedTask\n\n    let init () = \"initial\", Cmd.OfTask.attempt myTask () OnError\n    let update msg _ =\n        match msg with\n        | OnError ex -> \"Error was captured\", Cmd.none\n        | OnSuccess res -> res, Cmd.none\n    let mutable result = \"\"\n    let view model _ = result <- model\n    async {\n        Program.mkProgram init update view\n        |> Program.run\n    } |> Async.Start\n    System.Threading.Thread.Sleep (1_000)\n    result =! \"Error was captured\"\n\n[<Test>]\nlet ``Cmd.OfTask.perform - thrown exception when generating task should be discarded`` () =\n    let myTask () =\n        failwith \"Boom!\"\n        System.Threading.Tasks.Task.FromResult(\"Task completed\")\n\n    let init () = \"initial\", Cmd.OfTask.perform myTask () OnSuccess\n    let update msg _ =\n        match msg with\n        | OnError ex -> ex.Message, Cmd.none\n        | OnSuccess res -> res, Cmd.none\n    let mutable result = \"\"\n    let view model _ = result <- model\n    async {\n        Program.mkProgram init update view\n        |> Program.run\n    } |> Async.Start\n    System.Threading.Thread.Sleep (1_000)\n    result =! \"initial\"\n\n[<Test>]\nlet ``Cmd.OfTask.either - faulted task should be captured`` () =\n    let myTask () =\n        System.Threading.Tasks.Task.FromException<string>(System.Exception(\"Task failed\"))\n\n    let init () = \"initial\", Cmd.OfTask.either myTask () OnSuccess OnError\n    let update msg _ =\n        match msg with\n        | OnError ex -> ex.Message, Cmd.none\n        | OnSuccess res -> res, Cmd.none\n    let mutable result = \"\"\n    let view model _ = result <- model\n    async {\n        Program.mkProgram init update view\n        |> Program.run\n    } |> Async.Start\n    System.Threading.Thread.Sleep (1_000)\n    result =! \"Task failed\"\n\n[<Test>]\nlet ``Cmd.OfTask.attempt - faulted task should be captured`` () =\n    let myTask () =\n        System.Threading.Tasks.Task.FromException(System.Exception(\"Task failed\"))\n\n    let init () = \"initial\", Cmd.OfTask.attempt myTask () OnError\n    let update msg _ =\n        match msg with\n        | OnError ex -> \"Error was captured\", Cmd.none\n        | OnSuccess res -> res, Cmd.none\n    let mutable result = \"\"\n    let view model _ = result <- model\n    async {\n        Program.mkProgram init update view\n        |> Program.run\n    } |> Async.Start\n    System.Threading.Thread.Sleep (1_000)\n    result =! \"Error was captured\"\n\n[<Test>]\nlet ``Cmd.OfTask.perform - faulted task should be discarded`` () =\n    let myTask () =\n        System.Threading.Tasks.Task.FromException<string>(System.Exception(\"Task failed\"))\n\n    let init () = \"initial\", Cmd.OfTask.perform myTask () OnSuccess\n    let update msg _ =\n        match msg with\n        | OnError ex -> ex.Message, Cmd.none\n        | OnSuccess res -> res, Cmd.none\n    let mutable result = \"\"\n    let view model _ = result <- model\n    async {\n        Program.mkProgram init update view\n        |> Program.run\n    } |> Async.Start\n    System.Threading.Thread.Sleep (1_000)\n    result =! \"initial\"\n\n#endif\n\n#if !FABLE_COMPILER && !NETSTANDARD2_0\nopen System.Threading.Tasks\nopen System\n\n[<Test>]\nlet ``Cmd.OfValueTask.either - works`` () =\n    let myTask () = ValueTask<string>(\"ValueTask completed\")\n    let init () = \"initial\", Cmd.OfValueTask.either myTask () OnSuccess OnError\n    let update msg _ =\n        match msg with\n        | OnError ex -> ex.Message, Cmd.none\n        | OnSuccess res -> res, Cmd.none\n    let mutable result = \"\"\n    let view model _ = result <- model\n    async {\n        Program.mkProgram init update view\n        |> Program.run\n    } |> Async.Start\n    System.Threading.Thread.Sleep (1_000)\n    result =! \"ValueTask completed\"\n\n[<Test>]\nlet ``Cmd.OfValueTask.perform - works`` () =\n    let myTask () = ValueTask<string>(\"ValueTask completed\")\n    let init () = \"initial\", Cmd.OfValueTask.perform myTask () OnSuccess\n    let update msg _ =\n        match msg with\n        | OnError ex -> ex.Message, Cmd.none\n        | OnSuccess res -> res, Cmd.none\n    let mutable result = \"\"\n    let view model _ = result <- model\n    async {\n        Program.mkProgram init update view\n        |> Program.run\n    } |> Async.Start\n    System.Threading.Thread.Sleep (1_000)\n    result =! \"ValueTask completed\"\n\n[<Test>]\nlet ``Cmd.OfValueTask.attempt - works`` () =\n    let mutable result = \"\"\n    let myTask () =\n        result <- \"ValueTask called\"\n        ValueTask.CompletedTask\n    let init () = \"initial\", Cmd.OfValueTask.attempt myTask () OnError\n    let update msg _ =\n        match msg with\n        | OnError ex -> \"Error was captured\", Cmd.none\n        | OnSuccess res -> res, Cmd.none\n    let view model _ = result <- model\n    async {\n        Program.mkProgram init update view\n        |> Program.run\n    } |> Async.Start\n    System.Threading.Thread.Sleep (1_000)\n    result =! \"ValueTask called\"\n\n[<Test>]\nlet ``Cmd.OfValueTask.either - thrown exception when generating task should be captured`` () =\n    let myTask () =\n        failwith \"Boom!\"\n        ValueTask<string>(\"ValueTask completed\")\n    let init () = \"initial\", Cmd.OfValueTask.either myTask () OnSuccess OnError\n    let update msg _ =\n        match msg with\n        | OnError ex -> ex.Message, Cmd.none\n        | OnSuccess res -> res, Cmd.none\n    let mutable result = \"\"\n    let view model _ = result <- model\n    async {\n        Program.mkProgram init update view\n        |> Program.run\n    } |> Async.Start\n    System.Threading.Thread.Sleep (1_000)\n    result =! \"Boom!\"\n\n[<Test>]\nlet ``Cmd.OfValueTask.attempt - thrown exception when generating task should be captured`` () =\n    let myTask () =\n        failwith \"Boom!\"\n        ValueTask.CompletedTask\n    let init () = \"initial\", Cmd.OfValueTask.attempt myTask () OnError\n    let update msg _ =\n        match msg with\n        | OnError ex -> \"Error was captured\", Cmd.none\n        | OnSuccess res -> res, Cmd.none\n    let mutable result = \"\"\n    let view model _ = result <- model\n    async {\n        Program.mkProgram init update view\n        |> Program.run\n    } |> Async.Start\n    System.Threading.Thread.Sleep (1_000)\n    result =! \"Error was captured\"\n\n[<Test>]\nlet ``Cmd.OfValueTask.perform - thrown exception when generating task should be discarded`` () =\n    let myTask () =\n        failwith \"Boom!\"\n        ValueTask<string>(\"ValueTask completed\")\n    let init () = \"initial\", Cmd.OfValueTask.perform myTask () OnSuccess\n    let update msg _ =\n        match msg with\n        | OnError ex -> ex.Message, Cmd.none\n        | OnSuccess res -> res, Cmd.none\n    let mutable result = \"\"\n    let view model _ = result <- model\n    async {\n        Program.mkProgram init update view\n        |> Program.run\n    } |> Async.Start\n    System.Threading.Thread.Sleep (1_000)\n    result =! \"initial\"\n\n[<Test>]\nlet ``Cmd.OfValueTask.either - faulted ValueTask should be captured`` () =\n    let myTask () = ValueTask<string>(Task.FromException<string>(Exception(\"ValueTask failed\")))\n    let init () = \"initial\", Cmd.OfValueTask.either myTask () OnSuccess OnError\n    let update msg _ =\n        match msg with\n        | OnError ex -> ex.Message, Cmd.none\n        | OnSuccess res -> res, Cmd.none\n    let mutable result = \"\"\n    let view model _ = result <- model\n    async {\n        Program.mkProgram init update view\n        |> Program.run\n    } |> Async.Start\n    System.Threading.Thread.Sleep (1_000)\n    result =! \"ValueTask failed\"\n\n[<Test>]\nlet ``Cmd.OfValueTask.attempt - faulted ValueTask should be captured`` () =\n    let myTask () = ValueTask(Task.FromException(Exception(\"ValueTask failed\")))\n    let init () = \"initial\", Cmd.OfValueTask.attempt myTask () OnError\n    let update msg _ =\n        match msg with\n        | OnError ex -> \"Error was captured\", Cmd.none\n        | OnSuccess res -> res, Cmd.none\n    let mutable result = \"\"\n    let view model _ = result <- model\n    async {\n        Program.mkProgram init update view\n        |> Program.run\n    } |> Async.Start\n    System.Threading.Thread.Sleep (1_000)\n    result =! \"Error was captured\"\n\n[<Test>]\nlet ``Cmd.OfValueTask.perform - faulted ValueTask should be discarded`` () =\n    let myTask () = ValueTask<string>(Task.FromException<string>(Exception(\"ValueTask failed\")))\n    let init () = \"initial\", Cmd.OfValueTask.perform myTask () OnSuccess\n    let update msg _ =\n        match msg with\n        | OnError ex -> ex.Message, Cmd.none\n        | OnSuccess res -> res, Cmd.none\n    let mutable result = \"\"\n    let view model _ = result <- model\n    async {\n        Program.mkProgram init update view\n        |> Program.run\n    } |> Async.Start\n    System.Threading.Thread.Sleep (1_000)\n    result =! \"initial\"\n#endif\n"
  },
  {
    "path": "tests/Elmish.Tests.fsproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n  </PropertyGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"../netstandard/Elmish.fsproj\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Compile Include=\"../src/ring.fs\" />\n    <Compile Include=\"SubTests.fs\" />\n    <Compile Include=\"RingTest.fs\" />\n    <Compile Include=\"ProgramTest.fs\" />\n    <Compile Include=\"CmdTests.fs\" />\n    <Compile Include=\"Attributes.fs\" />\n  </ItemGroup>\n  <ItemGroup>\n    <PackageReference Include=\"FsCheck\" Version=\"3.3.0\" />\n    <PackageReference Include=\"FsCheck.NUnit\" Version=\"3.3.0\" />\n    <PackageReference Include=\"NUnit\" Version=\"4.3.2\" />\n    <PackageReference Include=\"NUnit3TestAdapter\" Version=\"5.0.0\">\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n      <PrivateAssets>all</PrivateAssets>\n    </PackageReference>\n    <PackageReference Include=\"Unquote\" Version=\"7.0.1\" />\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"17.14.1\" />\n  </ItemGroup>\n  <ItemGroup>\n    <PackageReference Update=\"FSharp.Core\" Version=\"9.0.300\" />\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "tests/ProgramTest.fs",
    "content": "module Elmish.ProgramTests\n\nopen NUnit.Framework\nopen FsCheck.NUnit\nopen Swensen.Unquote\nopen Elmish\n\ntype Model = int\ntype Msg =\n  | Increment\n  | Decrement\n  | Increment10Times\n\n[<Property(MaxTest = 10, EndSize = 100)>]\nlet dispatchesBatch (msgs: Msg list) =  \n    let init msgs = 0, msgs |> List.map Cmd.ofMsg |> Cmd.batch\n    let update msg m =\n        match msg with\n        | Increment -> m + 1, Cmd.none\n        | Decrement -> m - 1, Cmd.none\n        | Increment10Times -> m, Cmd.batch [ for _ in 1..10 -> Cmd.ofMsg Increment ] \n    printfn \"Folding...\"\n    let expected =\n      (0, msgs)\n      ||> List.fold (fun s -> function Increment -> s + 1 | Decrement -> s - 1 | Increment10Times -> s + 10)\n    let mutable counted = 0\n    let count m _ = counted <- m\n    printfn \"Starting...\"\n    async {\n      Program.mkProgram init update count\n      |> Program.runWith msgs\n    } |> Async.Start\n    System.Threading.Thread.Sleep (1_000)\n    counted =! expected\n\n[<Test>]\nlet ``update throwing exception should not crash the program`` () =\n    let o = obj()\n    let syncDispatch dispatch = lock o (fun () -> dispatch)\n    let init _ = 0, Cmd.OfAsync.perform async.Return Increment id\n    let update _ _ = failwith \"Boom!\"\n    let view _ = ignore\n    let mutable called = false\n    let onError _ = called <- true\n    Program.mkProgram init update view\n    |> Program.withConsoleTrace\n    |> Program.mapErrorHandler (fun _ -> onError)\n    |> Program.runWithDispatch syncDispatch ()\n    System.Threading.Thread.Sleep (1_000)\n    called =! true\n\n"
  },
  {
    "path": "tests/RingTest.fs",
    "content": "module Elmish.RingTests\n\nopen FsCheck\nopen FsCheck.NUnit\nopen System.Collections.Generic\nopen Swensen.Unquote\n\ntype Op =\n    | Pop\n    | Push of PositiveInt\n\ntype OpResult =\n    | Poped of PositiveInt option\n    | Pushed\n\nlet internal applyQOps (ops:Op list) (q:PositiveInt Queue) =\n    ops\n    |> List.map (function \n                 | Pop -> \n                   match q.TryDequeue() with (true, v) -> Some v | _ -> None\n                   |> Poped\n                 | Push v -> \n                   q.Enqueue v\n                   Pushed)\n\nlet internal applyRBOps (ops:Op list) (rb:PositiveInt RingBuffer) =\n    ops\n    |> List.map (function \n                 | Pop -> \n                   Poped <| rb.Pop()\n                 | Push v -> \n                   rb.Push v\n                   Pushed)\n                   \n[<Property(MaxTest = 1000, EndSize = 1000)>]\nlet actsLikeAQueue (ops:Op list) =  \n    let q = Queue()\n    let rb = RingBuffer 10\n    (q |> applyQOps ops) =! (rb |> applyRBOps ops)\n\n// have to have these here or dotnet won't find the nunit tests :/\nopen NUnit.Framework\n[<Test>]\nlet ok() =\n  1 =! 1"
  },
  {
    "path": "tests/SubTests.fs",
    "content": "﻿module Elmish.SubTests\n\nopen Elmish\nopen NUnit.Framework\nopen Swensen.Unquote\nopen System\n\n// TIL: Each use of a let fn binding creates a new FSharpFunc object.\n// Meaning reference equality with let fn binding is always false.\n// As record properties, these become concrete objects, ref equality works.\ntype SubContainer =\n    { Sub: Dispatch<obj> -> IDisposable\n      Dupe: Dispatch<obj> -> IDisposable }\n\n[<TestFixture>]\ntype DiffBehavior() =\n    // data\n    let stop = {new IDisposable with member _.Dispose() = () }\n    let sub = {Sub = (fun _ -> stop); Dupe = (fun _ -> stop) }\n    let newId i = [\"sub\"; string i]\n    let gen idRangeStart idRangeEnd second =\n        let count = idRangeEnd + 1 - idRangeStart\n        List.init count (fun i -> newId (idRangeStart + i), second)\n    let genSub idRangeStart idRangeEnd whichSub =\n        let count = idRangeEnd + 1 - idRangeStart\n        List.init count (fun i -> newId (idRangeStart + i), whichSub)\n    // helpers\n    let toKeys keyValueList =\n        List.map fst keyValueList\n    let toIds (dupes, toStop, toKeep, toStart) =\n        {| Dupes = dupes; ToStop = toKeys toStop; ToKeep = toKeys toKeep; ToStart = toKeys toStart |}\n    let toIds2 (dupes, toStop, toKeep, toStart) =\n        {| Dupes = toKeys dupes; ToStop = toKeys toStop; ToKeep = toKeys toKeep; ToStart = toKeys toStart |}\n    let run = Sub.Internal.diff\n    let eq expected actual =\n        toIds2 expected =! toIds actual\n\n    [<Test>]\n    member _.``no changes when subs and active subs are the same`` () =\n        let activeSubs = gen 0 6 stop\n        let subs = genSub 0 6 sub.Sub\n        let expected = [], [], activeSubs, []\n        let actual = run activeSubs subs\n        eq expected actual\n\n    [<Test>]\n    member _.``active subs are stopped when not found in subs`` () =\n        let activeSubs = gen 0 6 stop\n        let subs = genSub 3 6 sub.Sub\n        let expected = [], activeSubs[0..2], activeSubs[3..6], []\n        let actual = run activeSubs subs\n        eq expected actual\n\n    [<Test>]\n    member _.``subs are started when not found in active subs`` () =\n        let activeSubs = gen 0 2 stop\n        let subs = genSub 0 6 sub.Sub\n        let expected = [], [], activeSubs, subs[3..6]\n        let actual = run activeSubs subs\n        eq expected actual\n\n    [<Test>]\n    member _.``subs are started and stopped when subs has new ids and omits old ids`` () =\n        let activeSubs = gen 0 6 stop\n        let tmp = genSub 0 9 sub.Sub\n        let subs = tmp[3..9]\n        let expected = [], activeSubs[0..2], activeSubs[3..6], tmp[7..9]\n        let actual = run activeSubs subs\n        eq expected actual\n\n    [<Test>]\n    member _.``dupe subs are detected even when there are no changes`` () =\n        let activeSubs = gen 0 6 stop\n        let subs = Sub.batch [genSub 2 2 sub.Dupe; genSub 2 2 sub.Dupe; genSub 0 6 sub.Sub]\n        let expected = subs[0..1], [], activeSubs, []\n        let actual = run activeSubs subs\n        eq expected actual\n\n    [<Test>]\n    member _.``last dupe wins when starting new subs`` () =\n        let activeSubs = []\n        let dupeSubId = newId 2\n        let subs = List.concat [genSub 2 2 sub.Dupe; genSub 2 2 sub.Dupe; genSub 0 6 sub.Sub]\n        let expected = subs[0..1], [], activeSubs, subs[2..8]\n        let ((dupes, _, _, toStart) as actual) = run activeSubs subs\n        let startId, startDupe = toStart[2]\n        Assert.That(List.forall (fun subId -> dupeSubId = subId) dupes, \"Dupes have wrong ID\")\n        Assert.That(dupeSubId, Is.EqualTo<string> startId, \"Started dupe has wrong ID\")\n        Assert.That(sub.Sub, Is.SameAs startDupe, \"Started dupe is the wrong one\")\n        Assert.That(sub.Dupe, Is.Not.SameAs startDupe, \"Started dupe is the wrong one\")\n        eq expected actual\n\n"
  },
  {
    "path": "websharper/WebSharper.Elmish.fsproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <Description>Elmish core for WebSharper apps</Description>\n    <TargetFrameworks>netstandard2.0</TargetFrameworks>\n    <GenerateDocumentationFile>true</GenerateDocumentationFile>\n    <DefineConstants>$(DefineConstants);WEBSHARPER</DefineConstants>\n  </PropertyGroup>\n  <ItemGroup>\n    <Compile Include=\"prelude.fs\" />\n    <Compile Include=\"../src/cmd.fs\" />\n    <Compile Include=\"../src/sub.fs\" />\n    <Compile Include=\"../src/ring.fs\" />\n    <Compile Include=\"../src/program.fs\" />\n    <None Include=\"wsconfig.json\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ImportPackage Update=\"FSharp.Core\" Version=\"6.0.*\" />\n    <PackageReference Include=\"WebSharper\" Version=\"8.0.0.540\" />\n    <PackageReference Include=\"WebSharper.FSharp\" Version=\"8.0.0.540\" />\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "websharper/prelude.fs",
    "content": "namespace Elmish\n\nopen WebSharper\nopen WebSharper.JavaScript\n\nmodule internal Unchecked =\n    [<Inline>]\n    let defaultof<'T> = As<'T> null\n\nmodule internal Array =\n    [<Inline>]\n    let zeroCreate size = As<'T[]> (Array.zeroCreate<obj> size)\n\nmodule internal Log =\n    let onError (text: string, ex: exn) = Console.Error (text,ex)\n    let toConsole(text: string, o: #obj) = Console.Log(text,o)\n\nmodule AsyncHelpers =\n    let inline start x = Async.Start x"
  },
  {
    "path": "websharper/wsconfig.json",
    "content": "﻿{\n  \"$schema\": \"https://websharper.com/wsconfig.schema.json\",\n  \"project\": \"proxy\",\n  \"proxyTargetName\": \"Elmish\"\n}\n"
  }
]