[
  {
    "path": ".credo.exs",
    "content": "# This file contains the configuration for Credo and you are probably reading\n# this after creating it with `mix credo.gen.config`.\n#\n# If you find anything wrong or unclear in this file, please report an\n# issue on GitHub: https://github.com/rrrene/credo/issues\n#\n%{\n  #\n  # You can have as many configs as you like in the `configs:` field.\n  configs: [\n    %{\n      #\n      # Run any config using `mix credo -C <name>`. If no config name is given\n      # \"default\" is used.\n      name: \"default\",\n      #\n      # these are the files included in the analysis\n      files: %{\n        #\n        # you can give explicit globs or simply directories\n        # in the latter case `**/*.{ex,exs}` will be used\n        included: [\"lib/\", \"src/\", \"web/\", \"apps/\"],\n        excluded: [~r\"/_build/\", ~r\"/deps/\"]\n      },\n      #\n      # If you create your own checks, you must specify the source files for\n      # them here, so they can be loaded by Credo before running the analysis.\n      requires: [],\n      #\n      # Credo automatically checks for updates, like e.g. Hex does.\n      # You can disable this behaviour below:\n      check_for_updates: true,\n      #\n      # You can customize the parameters of any check by adding a second element\n      # to the tuple.\n      #\n      # To disable a check put `false` as second element:\n      #\n      #     {Credo.Check.Design.DuplicatedCode, false}\n      #\n      checks: [\n        {Credo.Check.Consistency.ExceptionNames},\n        {Credo.Check.Consistency.LineEndings},\n        {Credo.Check.Consistency.SpaceAroundOperators},\n        {Credo.Check.Consistency.SpaceInParentheses},\n        {Credo.Check.Consistency.TabsOrSpaces},\n\n        # For some checks, like AliasUsage, you can only customize the priority\n        # Priority values are: `low, normal, high, higher`\n        {Credo.Check.Design.AliasUsage, priority: :low},\n\n        # For others you can set parameters\n\n        # If you don't want the `setup` and `test` macro calls in ExUnit tests\n        # or the `schema` macro in Ecto schemas to trigger DuplicatedCode, just\n        # set the `excluded_macros` parameter to `[:schema, :setup, :test]`.\n        {Credo.Check.Design.DuplicatedCode, excluded_macros: []},\n\n        # You can also customize the exit_status of each check.\n        # If you don't want TODO comments to cause `mix credo` to fail, just\n        # set this value to 0 (zero).\n        {Credo.Check.Design.TagTODO, exit_status: 2},\n        {Credo.Check.Design.TagFIXME},\n\n        {Credo.Check.Readability.FunctionNames},\n        {Credo.Check.Readability.LargeNumbers},\n        {Credo.Check.Readability.MaxLineLength, priority: :low, max_length: 80},\n        {Credo.Check.Readability.ModuleAttributeNames},\n        {Credo.Check.Readability.ModuleDoc, false},\n        {Credo.Check.Readability.ModuleNames},\n        {Credo.Check.Readability.ParenthesesInCondition},\n        {Credo.Check.Readability.PredicateFunctionNames},\n        {Credo.Check.Readability.TrailingBlankLine},\n        {Credo.Check.Readability.TrailingWhiteSpace},\n        {Credo.Check.Readability.VariableNames},\n\n        {Credo.Check.Refactor.ABCSize},\n        # {Credo.Check.Refactor.CaseTrivialMatches}, # deprecated in 0.4.0\n        {Credo.Check.Refactor.CondStatements},\n        {Credo.Check.Refactor.FunctionArity},\n        {Credo.Check.Refactor.MatchInCondition},\n        {Credo.Check.Refactor.PipeChainStart, false},\n        {Credo.Check.Refactor.CyclomaticComplexity},\n        {Credo.Check.Refactor.NegatedConditionsInUnless},\n        {Credo.Check.Refactor.NegatedConditionsWithElse},\n        {Credo.Check.Refactor.Nesting},\n        {Credo.Check.Refactor.UnlessWithElse},\n\n        {Credo.Check.Warning.IExPry},\n        {Credo.Check.Warning.IoInspect},\n        {Credo.Check.Warning.NameRedeclarationByAssignment},\n        {Credo.Check.Warning.NameRedeclarationByCase},\n        {Credo.Check.Warning.NameRedeclarationByDef},\n        {Credo.Check.Warning.NameRedeclarationByFn},\n        {Credo.Check.Warning.OperationOnSameValues},\n        {Credo.Check.Warning.BoolOperationOnSameValues},\n        {Credo.Check.Warning.UnusedEnumOperation},\n        {Credo.Check.Warning.UnusedKeywordOperation},\n        {Credo.Check.Warning.UnusedListOperation},\n        {Credo.Check.Warning.UnusedStringOperation},\n        {Credo.Check.Warning.UnusedTupleOperation},\n        {Credo.Check.Warning.OperationWithConstantResult},\n\n        # Custom checks can be created using `mix credo.gen.check`.\n        #\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": ".gitignore",
    "content": "# App artifacts\n/_build\n/db\n/deps\n/*.ez\n\n# Generated on crash by the VM\nerl_crash.dump\n\n# Since we are building assets from assets/,\n# we ignore priv/static. You may want to comment\n# this depending on your deployment strategy.\n/priv/static/\n\n# Files matching config/*.secret.exs pattern contain sensitive\n# data and you should not commit them into version control.\n#\n# Alternatively, you may comment the line below and commit the\n# secrets files as long as you replace their contents by environment\n# variables.\n/config/*.secret.exs\n\n# Assets\n# Dependency directories\n/assets/node_modules\n\n# Ignore test coverage results\n/assets/coverage\n\n# Optional npm cache directory\n/assets/.npm\n/assets/npm-debug.log*\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2017 Dmitriy Chernyshov\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "Procfile",
    "content": "web: MIX_ENV=prod mix phx.server\n"
  },
  {
    "path": "README.md",
    "content": "# React + Phoenix boilerplate\n\nDemo: http://phxboilerplate.herokuapp.com\n\nThis is a basic setup for an React(16) + Phoenix(1.3)/Elixir(1.7) project, using webpack(4) and users with authentication.\n\n## STARTING PROJECT\n#### [You should have git installed](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)\n```\ngit clone https://github.com/chernyshof/react-phoenix-users-boilerplate appname\ncd appname\n```\n\n#### Changing app name in files(commands for unix like systems)\n```\ngrep -rl Boilerplate | xargs sed -i s@Boilerplate@Appname@g\ngrep --exclude={package.json,yarn.lock,.babelrc} -rl boilerplate | xargs sed -i s@boilerplate@appname@g\nfind . -depth -exec rename 's/boilerplate/appname/g' {} \\; \n```\nOr if you're using different rename version\n```\nfind . -iname \"*boilerplate*\" -exec rename boilerplate appname '{}' \\;\n```\n\n\n#### Reinit git\n```\nrm -rf .git\ngit init\ngit add priv/static/favicon.ico -f\ngit add priv/static/images/phoenix.png -f\n```\n\n#### Download dependencies\n```\nmix deps.get\nmix ecto.create\nmix ecto.migrate\ncd assets\nyarn install\ncd ..\n```\n\n\n#### Start server\n```\nmix phx.server\n```\n\n## SUPERUSER\nAfter running `mix ecto.migrate` command you will have superuser:\n```\nemail: admin@admin.com\npassword: 12345678\n```\nYou probably wanna change it :)\n\n## SETUP\n#### Redux logger\nIf you want to turn redux logger on just assign `true` to useReduxLogger in app/store/index.js\n```javascript\n...\nconst useReduxLogger = true;\n...\n```\n\n## DEPLOYING TO HEROKU\n[You should have installed heroku-cli](https://devcenter.heroku.com/articles/heroku-cli)\n\n#### Create heroku application\n```\nheroku create --buildpack \"https://github.com/HashNuke/heroku-buildpack-elixir.git\"\n```\n\n#### Optional change app address \n```\nheroku apps:rename appname\n```\n\n#### Adding phoenix buildpack\n```\nheroku buildpacks:add https://github.com/chernyshof/heroku-buildpack-phoenix-static.git\n```\n\n#### Add you address\nin `config/prod.exs`\nchange in config, :appname, Appname.Repo, url line(if needed)\n```elixir\nurl: [scheme: \"https\", host: \"appnameaddress.herokuapp.com\", port: 443],\n```\n\n#### Creating Environment Variables\n```\nheroku addons:create heroku-postgresql:hobby-dev\nheroku config:set POOL_SIZE=18\n```\n\n#### Secret key\ngen secret key\n```\n$ mix phx.gen.secret\nxvafzY4y01jYuzLm3ecJqo008dVnU3CN4f+MamNd1Zue4pXvfvUjbiXT8akaIF53\n```\n##### now set key that you got in heroku\n```\nheroku config:set SECRET_KEY_BASE=\"xvafzY4y01jYuzLm3ecJqo008dVnU3CN4f+MamNd1Zue4pXvfvUjbiXT8akaIF53\"\n```\n\n#### Guardian secret key\n```\n$ mix phx.gen.secret\nxvafzY4y01jYuzLm3ecJqo008dVnU3CN4f+MamNd1Zue4pXvfvUjbiXT8akaIF53\n```\n##### now set key that you got in heroku\n```\nheroku config:set GUARDIAN_SECRET_KEY=\"xvafzY4y01jYuzLm3ecJqo008dVnU3CN4f+MamNd1Zue4pXvfvUjbiXT8akaIF53\"\n```\n\n#### Deploy time!\n```\ngit push heroku master\nheroku run \"POOL_SIZE=2 mix ecto.migrate\"\n```\n\n\n## REQUIREMENTS\n- [Elixir](http://elixir-lang.org/)/[Mix](http://elixir-lang.org/getting-started/mix-otp/introduction-to-mix.html)/[Phoenix](http://www.phoenixframework.org/) ([Installation guide](http://www.phoenixframework.org/docs/installation), [Phoenix1.3](https://gist.github.com/chrismccord/71ab10d433c98b714b75c886eff17357))\n- [Node.js](https://nodejs.org/en/)/[yarn](https://yarnpkg.com/) or [npm](https://www.npmjs.com/)\n- A [PostgreSQL](https://www.postgresql.org/) server running on your machine.\n- [Watchman](https://facebook.github.io/watchman/) file watching service\n\n## USED PLUGINS AND TECHNOLOGIES\n**Frontend**\n* [React](https://github.com/facebook/react)\n* [React hot reloader](https://github.com/gaearon/react-hot-loader) Tweak React components in real time.\n* [Redux logger](https://github.com/evgenyrodionov/redux-logger)\n* [React Router 4](https://github.com/ReactTraining/react-router) Declarative routing for React.\n* [Babel](http://babeljs.io) For ES6 and ES7 magic.\n* [Webpack 4](http://webpack.github.io) For bundling.\n* [Webpack Dev Middleware](http://webpack.github.io/docs/webpack-dev-middleware.html)\n* [Redux](https://github.com/reactjs/redux) Predictable state container for JavaScript apps.\n* [Redux Dev Tools](https://github.com/gaearon/redux-devtools) DevTools for Redux with hot reloading, action replay, and customizable UI. Watch [Dan Abramov's talk](https://www.youtube.com/watch?v=xsSnOQynTHs)\n* [Redux Saga](https://github.com/redux-saga/redux-saga) Middleware for Redux - used in async actions.\n* [React Router Redux 5](https://github.com/reactjs/react-router-redux) Ruthlessly simple bindings to keep react-router and redux in sync.\n* [ESLint](http://eslint.org) And many librarys for this.\n* [Jest](https://facebook.github.io/jest/) JavaScript Testing framework.\n* [Enzyme](http://airbnb.io/enzyme/) JavaScript Testing utilities for React.\n* [Sass](http://sass-lang.com/) Css extenstion language.\n* [PostCSS](http://postcss.org/) Tool for transforming css to javascript\n* [husky](https://github.com/typicode/husky) Husky can prevent bad commit, push and more.\n* [OpenBrowserPlugin](https://github.com/baldore/open-browser-webpack-plugin) Opens a new browser tab when Webpack loads.\nand other stuff...\n\n**Backend**\n* [Elixir 1.7](http://elixir-lang.org/)\n* [Phoenix 1.3](http://www.phoenixframework.org/)\n* [Credo](https://github.com/rrrene/credo) Static code analysis tool for the Elixir language.\n"
  },
  {
    "path": "assets/.babelrc",
    "content": "{\r\n  \"presets\": [\r\n    \"@babel/preset-env\",\r\n    \"@babel/preset-react\",\r\n  ],\r\n\r\n  \"plugins\": [\r\n      // Stage 0\r\n      \"@babel/plugin-proposal-function-bind\",\r\n\r\n      // Stage 1\r\n      \"@babel/plugin-proposal-export-default-from\",\r\n      \"@babel/plugin-proposal-logical-assignment-operators\",\r\n      [\"@babel/plugin-proposal-optional-chaining\", { loose: false }],\r\n      [\"@babel/plugin-proposal-pipeline-operator\", { proposal: \"minimal\" }],\r\n      [\"@babel/plugin-proposal-nullish-coalescing-operator\", { loose: false }],\r\n      \"@babel/plugin-proposal-do-expressions\",\r\n\r\n      // Stage 2\r\n      [\"@babel/plugin-proposal-decorators\", { legacy: true }],\r\n      \"@babel/plugin-proposal-function-sent\",\r\n      \"@babel/plugin-proposal-export-namespace-from\",\r\n      \"@babel/plugin-proposal-numeric-separator\",\r\n      \"@babel/plugin-proposal-throw-expressions\",\r\n\r\n      // Stage 3\r\n      \"@babel/plugin-syntax-dynamic-import\",\r\n      \"@babel/plugin-syntax-import-meta\",\r\n      [\"@babel/plugin-proposal-class-properties\", { loose: false }],\r\n      \"@babel/plugin-proposal-json-strings\",\r\n\r\n\r\n\r\n      // -\\_(:/)_/-\r\n      '@babel/plugin-transform-modules-commonjs',\r\n      '@babel/plugin-proposal-object-rest-spread',\r\n    ]\r\n}\r\n"
  },
  {
    "path": "assets/.eslintrc",
    "content": "{\r\n  \"parser\": \"babel-eslint\",\r\n  \"plugins\": [\"react\", \"import\"],\r\n  \"env\": {\r\n    \"browser\": true,\r\n    \"jest\": true,\r\n    \"node\": true,\r\n    \"mocha\": true\r\n  },\r\n  \"extends\": [\"airbnb\"],\r\n  \"rules\": {\r\n    \"space-before-function-paren\": 0,\r\n    \"react/prefer-stateless-function\": 0,\r\n    \"react/jsx-filename-extension\": [1, { \"extensions\": [\".js\", \".jsx\"] }],\r\n    \"react/jsx-one-expression-per-line\": 0, // fix\r\n    \"react/destructuring-assignment\": 0,\r\n    \"jsx-a11y/href-no-hash\": \"off\",\r\n    \"linebreak-style\": 0,\r\n    \"global-require\": 0,\r\n    \"jsx-a11y/anchor-is-valid\": [ \"error\", {\r\n        \"components\": [ \"Link\" ],\r\n        \"specialLink\": [ \"to\", \"hrefLeft\", \"hrefRight\" ],\r\n        \"aspects\": [ \"noHref\", \"invalidHref\", \"preferButton\" ]\r\n      }],\r\n  },\r\n  \"settings\": {\r\n    \"import/resolver\": {\r\n      \"webpack\": {\r\n        \"config\": \"webpack.config.js\"\r\n        }\r\n      }\r\n    }\r\n  }\r\n"
  },
  {
    "path": "assets/.travis.yml",
    "content": "sudo: false\nlanguage: node_js\ncache:\n  directories:\n    - node_modules\nbranches:\n  only:\n      - master\n      - /^greenkeeper/.*$/\nnotifications:\n  email: false\nnode_js:\n  - 6.1\n  - 6\n  - 5.6.0\n  - 4.3.0\nbefore_install:\n  - npm i -g npm@^3.8.2\nbefore_script:\n  - npm prune\nscript:\n  - npm run test\ninstall: npm install"
  },
  {
    "path": "assets/NERD_tree_1",
    "content": "@babel/plugin-transform-modules-commonjs @babel/plugin-proposal-export-default-from @babel/plugin-proposal-export-namespace-from @babel/plugin-proposal-class-properties @babel/plugin-proposal-object-rest-spread\n\n"
  },
  {
    "path": "assets/app/actions/errors.js",
    "content": "export const types = {\n  NEW_ERROR: 'ERRORS/NEW_ERROR',\n};\n\nexport const newError = message => ({ type: types.NEW_ERROR, message });\n"
  },
  {
    "path": "assets/app/actions/session.js",
    "content": "export const types = {\n  LOGIN_REQUEST: 'SESSION/LOGIN_REQUEST',\n  SIGNUP_REQUEST: 'SESSION/SIGNUP_REQUEST',\n  LOGOUT: 'SESSION/LOGOUT',\n  AUTHENTICATION_REQUEST: 'SESSION/AUTHENTICATION_REQUEST',\n  AUTHENTICATION_SUCCESS: 'SESSION/AUTHENTICATION_SUCCESS',\n  AUTHENTICATION_FAILURE: 'SESSION/AUTHENTICATION_FAILURE',\n};\n\nexport const login = data => ({ type: types.LOGIN_REQUEST, data });\nexport const signup = data => ({ type: types.SIGNUP_REQUEST, data });\nexport const logout = () => ({ type: types.LOGOUT });\nexport const authenticate = () => ({ type: types.AUTHENTICATION_REQUEST });\nexport const unauthenticate = () => ({ type: types.AUTHENTICATION_FAILURE });\n"
  },
  {
    "path": "assets/app/assets/scss/components/app.scss",
    "content": ".app{\n  padding-top: 50px;\n\n  form, ul, table {\n    margin-top: 20px;\n    margin-bottom: 20px;\n  }\n  \n  .username {\n    color: $primary_color;\n  }\n\n\n  /* Phoenix flash messages */\n  .alert:empty { display: none; }\n  \n  /* Phoenix inline forms in links and buttons */\n  form.link, form.button {\n    display: inline;\n  }\n  \n  /* Custom page header */\n  .header {\n    border-bottom: 1px solid $grey;\n  }\n  .logo {\n    width: 519px;\n    height: 71px;\n    display: inline-block;\n    margin-bottom: 1em;\n    background-image: url(\"/images/phoenix.png\");\n    background-size: 519px 71px;\n  }\n  \n  /* Everything but the jumbotron gets side spacing for mobile first views */\n  .header,\n  .marketing {\n    padding-right: 15px;\n    padding-left: 15px;\n  }\n  \n  /* Customize container */\n  @media (min-width: 768px) {\n    .container {\n      max-width: 730px;\n    }\n  }\n  .container-narrow > hr {\n    margin: 30px 0;\n  }\n  \n  /* Main marketing message */\n  .jumbotron {\n    text-align: center;\n    border-bottom: 1px solid $grey;\n  }\n  \n  /* Supporting marketing content */\n  .marketing {\n    margin: 35px 0;\n  }\n  \n  /* Responsive: Portrait tablets and up */\n  @media screen and (min-width: 768px) {\n    /* Remove the padding we set earlier */\n    .header,\n    .marketing {\n      padding-right: 0;\n      padding-left: 0;\n    }\n    /* Space out the masthead */\n    .header {\n      margin-bottom: 30px;\n    }\n    /* Remove the bottom border on the jumbotron for visual effect */\n    .jumbotron {\n      border-bottom: 0;\n    }\n  }\n}\n"
  },
  {
    "path": "assets/app/assets/scss/components/sign.scss",
    "content": ".login, .signup {\n  height: 100%;\n  width: 100%;\n  background: $grey;\n  padding-top: 40px;\n\n  .input {\n    position: relative;\n\n    .validation-error {\n      white-space: nowrap;\n      padding: 0 5px;\n      padding-bottom: 2px;\n      top: 5px;\n      left: 110%;\n      position: absolute;\n      background: $error;\n      color: white;\n      border-top-right-radius: 5px;\n      border-bottom-right-radius: 5px;\n\n      &:before {\n        content:\"\";\n        position: absolute;\n        right: 100%;\n        width: 0;\n        height: 0;\n        border-top: 13px solid transparent;\n        border-right: 20px solid $error;\n        border-bottom: 13px solid transparent;\n      }\n    }\n  }\n\n  .form-login, .form-signup {\n    margin: 0 auto;\n    max-width: 330px;\n    padding: 15px;\n    background: white;\n  }\n\n  .form-login {\n    input[type=\"email\"] {\n      margin-bottom: -1px;\n      border-bottom-right-radius: 0;\n      border-bottom-left-radius: 0;\n    }\n\n    input[type=\"password\"] {\n      border-top-right-radius: 0;\n      border-top-left-radius: 0;\n      margin-bottom: 25px;\n    }\n  }\n\n  .form-signup {\n    input[name=\"name\"] {\n      margin-bottom: -1px;\n      border-bottom-right-radius: 0;\n      border-bottom-left-radius: 0;\n    }\n\n    input[name=\"password\"] {\n      border-top-right-radius: 0;\n      border-top-left-radius: 0;\n      margin-bottom: 25px;\n    }\n\n    input[type=\"email\"],\n    input[name=\"username\"] {\n      margin-bottom: -1px;\n      border-radius: 0;\n      border-radius: 0;\n    }\n  }\n}\n"
  },
  {
    "path": "assets/app/assets/scss/index.scss",
    "content": "@import 'variables.scss';\n@import 'components/sign.scss';\n@import 'components/app.scss';\n\n\nbody, html, #root, .full-height {\n  margin: 0;\n  height: 100%;\n  width: 100%;\n  font-family: sans-serif;\n}\n"
  },
  {
    "path": "assets/app/assets/scss/variables.scss",
    "content": "$grey: #EEEEEE;\n$error: #e53935;\n$primary_color: #F05423;\n"
  },
  {
    "path": "assets/app/components/App/index.js",
    "content": "import React, { Component } from 'react';\r\nimport { connect } from 'react-redux';\r\nimport PropTypes from 'prop-types';\r\nimport DocumentTitle from 'react-document-title';\r\n\r\nimport { logout } from 'actions/session';\r\n\r\n\r\nexport class App extends Component {\r\n  render() {\r\n    const { username } = this.props;\r\n\r\n    return (\r\n      <DocumentTitle title=\"Home\">\r\n        <div className=\"app\">\r\n          <div className=\"container col-md-8\">\r\n            <header className=\"header\">\r\n              <nav>\r\n                <span className=\"logo\" />\r\n                <ul className=\"nav nav-pills pull-right\">\r\n                  <li><a href=\"http://www.phoenixframework.org/docs\">Get Started</a></li>\r\n\r\n                  <button type=\"button\" className=\"btn btn-sm\" onClick={this.props.logout}>Logout</button>\r\n                </ul>\r\n              </nav>\r\n            </header>\r\n\r\n            <main role=\"main\">\r\n              <div className=\"jumbotron\">\r\n                <h2 id=\"heading\">\r\n                  Hello, <span className=\"username\">{ username }</span>!\r\n                </h2>\r\n                <h2>Welcome to Phoenix</h2>\r\n                <p className=\"lead\">A productive web framework that<br />does not compromise speed and maintainability.</p>\r\n              </div>\r\n\r\n              <div className=\"row marketing\">\r\n                <div className=\"col-lg-6\">\r\n                  <h4>Resources</h4>\r\n                  <ul>\r\n                    <li>\r\n                      <a href=\"http://phoenixframework.org/docs/overview\">Guides</a>\r\n                    </li>\r\n                    <li>\r\n                      <a href=\"https://hexdocs.pm/phoenix\">Docs</a>\r\n                    </li>\r\n                    <li>\r\n                      <a href=\"https://github.com/phoenixframework/phoenix\">Source</a>\r\n                    </li>\r\n                  </ul>\r\n                </div>\r\n\r\n                <div className=\"col-lg-6\">\r\n                  <h4>Help</h4>\r\n                  <ul>\r\n                    <li>\r\n                      <a href=\"http://groups.google.com/group/phoenix-talk\">Mailing list</a>\r\n                    </li>\r\n                    <li>\r\n                      <a href=\"http://webchat.freenode.net/?channels=elixir-lang\">#elixir-lang on freenode IRC</a>\r\n                    </li>\r\n                    <li>\r\n                      <a href=\"https://twitter.com/elixirphoenix\">@elixirphoenix</a>\r\n                    </li>\r\n                  </ul>\r\n                </div>\r\n              </div>\r\n            </main>\r\n          </div>\r\n        </div>\r\n      </DocumentTitle>\r\n    );\r\n  }\r\n}\r\n\r\nApp.propTypes = {\r\n  username: PropTypes.string,\r\n  logout: PropTypes.func.isRequired,\r\n};\r\n\r\nApp.defaultProps = {\r\n  username: '',\r\n};\r\n\r\nconst mapDispatchToProps = dispatch => ({\r\n  dispatch,\r\n  logout: () => dispatch(logout()),\r\n});\r\n\r\nconst mapStateProps = state => ({\r\n  username: state.session.currentUser.username,\r\n});\r\n\r\nexport default connect(mapStateProps, mapDispatchToProps)(App);\r\n"
  },
  {
    "path": "assets/app/components/NotFound/index.js",
    "content": "import React, { Component } from 'react';\r\n\r\nexport default class NotFound extends Component {\r\n  render() {\r\n    return (\r\n      <h2 id=\"heading\">404 Not Found</h2>\r\n    );\r\n  }\r\n}\r\n"
  },
  {
    "path": "assets/app/components/Sign/Login/LoginForm/index.js",
    "content": "import React, { Component } from 'react';\nimport { Field, reduxForm } from 'redux-form';\nimport { Link } from 'react-router-dom';\nimport PropTypes from 'prop-types';\n\nimport { FormInput } from 'components';\nimport { login } from 'actions/session';\n\nclass LoginForm extends Component {\n  submit = (data, dispatch) => dispatch(login(data));\n\n  render() {\n    const { handleSubmit, submittingForm, invalid } = this.props;\n\n    return (\n      <form className=\"form-login card\" onSubmit={handleSubmit(this.submit)} noValidate>\n        <h3>Login to Boilerplate</h3>\n        <Field\n          name=\"email\"\n          type=\"email\"\n          component={FormInput}\n          placeholder=\"Email\"\n        />\n        <Field\n          name=\"password\"\n          type=\"password\"\n          component={FormInput}\n          placeholder=\"Password\"\n        />\n        <button\n          type=\"submit\"\n          disabled={invalid || submittingForm}\n          className=\"btn btn-primary btn-lg btn-block\"\n        >\n          {submittingForm ? 'Logging in...' : 'Login'}\n        </button>\n        <hr />\n        <Link to=\"/signup\" className=\"btn\">\n          Create a new account\n        </Link>\n      </form>\n    );\n  }\n}\n\n\nLoginForm.propTypes = {\n  submittingForm: PropTypes.bool,\n  invalid: PropTypes.bool.isRequired,\n  handleSubmit: PropTypes.func.isRequired,\n};\n\nLoginForm.defaultProps = {\n  submittingForm: false,\n};\n\n\nconst validate = (values) => {\n  const errors = {};\n  const emailRegex = /^(([^<>()[\\]\\\\.,;:\\s@\"]+(\\.[^<>()[\\]\\\\.,;:\\s@\"]+)*)|(\".+\"))@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}])|(([a-zA-Z\\-0-9]+\\.)+[a-zA-Z]{2,}))$/;\n\n  if (!values.email) {\n    errors.email = 'Required';\n  } else if (!emailRegex.test(values.email)) {\n    errors.email = 'Invalid email';\n  }\n\n  if (!values.password) {\n    errors.password = 'Required';\n  } else if (values.password.length < 6 || values.password.length > 100) {\n    errors.password = 'Must be more than 5 characters and less than 101';\n  }\n\n  return errors;\n};\n\nexport default reduxForm({\n  form: 'login',\n  validate,\n})(LoginForm);\n"
  },
  {
    "path": "assets/app/components/Sign/Login/index.js",
    "content": "import React, { Component } from 'react';\nimport { connect } from 'react-redux';\nimport PropTypes from 'prop-types';\nimport DocumentTitle from 'react-document-title';\n\nimport { LoginForm } from 'components';\n\nexport class Login extends Component {\n  render() {\n    const { submittingForm } = this.props;\n\n    return (\n      <DocumentTitle title=\"Login\">\n        <div className=\"login\">\n          <div className=\"container\">\n            <LoginForm submittingForm={submittingForm} />\n          </div>\n        </div>\n      </DocumentTitle>\n    );\n  }\n}\n\n\nLogin.propTypes = {\n  submittingForm: PropTypes.bool,\n};\n\nLogin.defaultProps = {\n  submittingForm: false,\n};\n\n\nconst mapStateProps = state => ({\n  submittingForm: state.session.submittingForm,\n});\n\nexport default connect(mapStateProps)(Login);\n"
  },
  {
    "path": "assets/app/components/Sign/Signup/SignupForm/index.js",
    "content": "import React, { Component } from 'react';\nimport { Field, reduxForm } from 'redux-form';\nimport { Link } from 'react-router-dom';\nimport PropTypes from 'prop-types';\n\nimport { FormInput } from 'components';\nimport { signup } from 'actions/session';\n\nclass SignupForm extends Component {\n  submit = (data, dispatch) => dispatch(signup(data));\n\n  render() {\n    const { handleSubmit, submittingForm, invalid } = this.props;\n\n    return (\n      <form className=\"form-signup card\" onSubmit={handleSubmit(this.submit)} noValidate>\n        <h3>Create an account</h3>\n        <Field\n          name=\"name\"\n          type=\"text\"\n          component={FormInput}\n          placeholder=\"Full name\"\n          className=\"form-control\"\n        />\n        <Field\n          name=\"username\"\n          type=\"text\"\n          component={FormInput}\n          placeholder=\"Username\"\n          className=\"form-control\"\n        />\n        <Field\n          name=\"email\"\n          type=\"email\"\n          component={FormInput}\n          placeholder=\"Email\"\n          className=\"form-control\"\n        />\n        <Field\n          name=\"password\"\n          type=\"password\"\n          component={FormInput}\n          placeholder=\"Password\"\n          className=\"form-control\"\n        />\n        <button\n          type=\"submit\"\n          disabled={invalid || submittingForm}\n          className=\"btn btn-primary btn-lg btn-block\"\n        >\n          {submittingForm ? 'Submitting...' : 'Sign up'}\n        </button>\n        <hr />\n        <Link to=\"/login\" className=\"btn\">\n          Login to your account\n        </Link>\n      </form>\n    );\n  }\n}\n\nSignupForm.propTypes = {\n  submittingForm: PropTypes.bool,\n  invalid: PropTypes.bool.isRequired,\n  handleSubmit: PropTypes.func.isRequired,\n};\n\nSignupForm.defaultProps = {\n  submittingForm: false,\n};\n\n\nconst validate = (values) => {\n  const errors = {};\n  const emailRegex = /^(([^<>()[\\]\\\\.,;:\\s@\"]+(\\.[^<>()[\\]\\\\.,;:\\s@\"]+)*)|(\".+\"))@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}])|(([a-zA-Z\\-0-9]+\\.)+[a-zA-Z]{2,}))$/;\n  const usernameRegex = /^[A-Za-z0-9._]+$/;\n\n  if (!values.name) {\n    errors.name = 'Required';\n  } else if (values.name.length < 1 || values.name.length > 255) {\n    errors.name = 'Must be less than 256 characters';\n  }\n\n  if (!values.username) {\n    errors.username = 'Required';\n  } else if (!usernameRegex.test(values.username)) {\n    errors.username = 'Only EN letters, digits, \\'.\\' and \\'_\\' are allowed';\n  } else if (values.username.length < 1 || values.username.length > 26) {\n    errors.username = 'Must be less than 27 characters';\n  }\n\n  if (!values.email) {\n    errors.email = 'Required';\n  } else if (!emailRegex.test(values.email)) {\n    errors.email = 'Invalid email';\n  }\n\n  if (!values.password) {\n    errors.password = 'Required';\n  } else if (values.password.length < 6 || values.password.length > 100) {\n    errors.password = 'Must be more than 5 characters and less than 101';\n  }\n\n  return errors;\n};\n\nexport default reduxForm({\n  form: 'signup',\n  validate,\n})(SignupForm);\n"
  },
  {
    "path": "assets/app/components/Sign/Signup/index.js",
    "content": "import React, { Component } from 'react';\nimport { connect } from 'react-redux';\nimport PropTypes from 'prop-types';\nimport DocumentTitle from 'react-document-title';\n\nimport { SignupForm } from 'components';\n\nexport class Signup extends Component {\n  render() {\n    const { submittingForm } = this.props;\n\n    return (\n      <DocumentTitle title=\"Signup\">\n        <div className=\"signup\">\n          <div className=\"container\">\n            <SignupForm submittingForm={submittingForm} />\n          </div>\n        </div>\n      </DocumentTitle>\n    );\n  }\n}\n\n\nSignup.propTypes = {\n  submittingForm: PropTypes.bool,\n};\n\nSignup.defaultProps = {\n  submittingForm: false,\n};\n\nconst mapStateProps = state => ({\n  submittingForm: state.session.submittingForm,\n});\n\nexport default connect(mapStateProps)(Signup);\n"
  },
  {
    "path": "assets/app/components/Sign/Signup/index.test.js",
    "content": "import React from 'react';\nimport { shallow } from 'enzyme';\nimport { Signup } from '.';\n\ndescribe('Signup', () => {\n  it('shoud exists', () => {\n    const wrapper = shallow(<Signup />);\n    expect(wrapper.exists()).toBe(true);\n  });\n});\n"
  },
  {
    "path": "assets/app/components/Utils/ErrorMessage/index.js",
    "content": "import React, { Component } from 'react';\nimport { connect } from 'react-redux';\nimport PropTypes from 'prop-types';\nimport NotificationSystem from 'react-notification-system';\n\nexport class ErrorMessage extends Component {\n  constructor(props) {\n    super(props);\n\n    this.notificationSystem = null;\n  }\n\n  componentDidUpdate(prevProps) {\n    const { errors } = prevProps;\n\n    for (let i = 0; i < this.props.errors.length; i += 1) {\n      if (errors[i] !== this.props.errors[i] && this.props.errors[i]) {\n        this.addNotification(this.props.errors[i]);\n      }\n    }\n  }\n\n\n  addNotification(message) {\n    this.notificationSystem.addNotification({\n      message,\n      level: 'error',\n    });\n  }\n\n\n  render() {\n    return (\n      <div className=\"errorMessage\">\n        <NotificationSystem ref={(n) => {\n          this.notificationSystem = n;\n          return n;\n        }}\n        />\n      </div>\n    );\n  }\n}\n\nErrorMessage.propTypes = {\n  errors: PropTypes.array, // eslint-disable-line react/forbid-prop-types\n};\n\nErrorMessage.defaultProps = {\n  errors: [],\n};\n\nconst mapStateProps = state => ({\n  errors: state.errors.errors,\n});\n\nexport default connect(mapStateProps)(ErrorMessage);\n"
  },
  {
    "path": "assets/app/components/Utils/FormInput/index.js",
    "content": "import React, { Component } from 'react';\nimport PropTypes from 'prop-types';\n\nexport default class Input extends Component {\n  render() {\n    const {\n      input,\n      type,\n      placeholder,\n      meta,\n    } = this.props;\n\n    return (\n      <div className=\"input\">\n        <input\n          {...input}\n          type={type}\n          placeholder={placeholder}\n          className=\"form-control\"\n        />\n        {meta.touched\n            && meta.error\n            && <div className=\"validation-error\">{meta.error}</div>\n        }\n      </div>\n    );\n  }\n}\n\nInput.propTypes = {\n  input: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types\n  label: PropTypes.string,\n  type: PropTypes.string,\n  placeholder: PropTypes.string,\n  meta: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types\n};\n\nInput.defaultProps = {\n  label: '',\n  type: '',\n  placeholder: '',\n};\n"
  },
  {
    "path": "assets/app/components/Utils/MatchAuthenticated/index.js",
    "content": "import React, { Component } from 'react';\nimport { Route, Redirect } from 'react-router';\nimport PropTypes from 'prop-types';\n\n\nexport default class MatchAuthenticated extends Component {\n  render() {\n    const {\n      path,\n      exact,\n      isAuthenticated,\n      willAuthenticate,\n      component,\n    } = this.props;\n    const RouteComponent = component;\n\n    return (\n      <Route\n        exact={exact}\n        path={path}\n        render={(props) => {\n          if (isAuthenticated) { return <RouteComponent {...props} />; }\n          if (willAuthenticate) { return null; }\n          if (!willAuthenticate && !isAuthenticated) { return <Redirect to={{ pathname: '/login' }} />; }\n          return null;\n        }}\n      />\n    );\n  }\n}\n\n\nMatchAuthenticated.propTypes = {\n  component: PropTypes.any.isRequired, // eslint-disable-line react/forbid-prop-types\n  path: PropTypes.string.isRequired,\n  exact: PropTypes.bool,\n  isAuthenticated: PropTypes.bool.isRequired,\n  willAuthenticate: PropTypes.bool.isRequired,\n};\n\nMatchAuthenticated.defaultProps = {\n  exact: false,\n};\n"
  },
  {
    "path": "assets/app/components/Utils/RedirectAuthenticated/index.js",
    "content": "import React, { Component } from 'react';\nimport { Route, Redirect } from 'react-router';\nimport PropTypes from 'prop-types';\n\n\nexport default class RedirectAuthenticated extends Component {\n  render() {\n    const {\n      path,\n      exact,\n      isAuthenticated,\n      willAuthenticate,\n      component,\n    } = this.props;\n    const RouteComponent = component;\n\n    return (\n      <Route\n        exact={exact}\n        path={path}\n        render={(props) => {\n          if (isAuthenticated) { return <Redirect to={{ pathname: '/' }} />; }\n          if (willAuthenticate) { return null; }\n          return <RouteComponent {...props} />;\n        }}\n      />\n    );\n  }\n}\n\n\nRedirectAuthenticated.propTypes = {\n  component: PropTypes.any.isRequired, // eslint-disable-line react/forbid-prop-types\n  path: PropTypes.string.isRequired,\n  exact: PropTypes.bool,\n  isAuthenticated: PropTypes.bool.isRequired,\n  willAuthenticate: PropTypes.bool.isRequired,\n};\n\nRedirectAuthenticated.defaultProps = {\n  exact: true,\n};\n"
  },
  {
    "path": "assets/app/components/index.js",
    "content": "const req = require.context('.', true, /[^/]+\\/[^/]+\\/index\\.js$/);\n\nreq.keys().forEach((key) => {\n  const componentName = key.replace(/^.+\\/([^/]+)\\/index\\.js/, '$1');\n  module.exports[componentName] = req(key).default;\n});\n"
  },
  {
    "path": "assets/app/config/CustomRedbox.js",
    "content": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport Redbox from 'redbox-react';\n\nconst styles = {\n  redbox: {\n    boxSizing: 'border-box',\n    fontFamily: 'sans-serif',\n    position: 'fixed',\n    padding: 10,\n    top: '0px',\n    left: '0px',\n    bottom: '0px',\n    right: '0px',\n    width: '100%',\n    background: 'rgb(92,107,192)',\n    color: 'white',\n    zIndex: 2147483647,\n    textAlign: 'left',\n    fontSize: '16px',\n    lineHeight: 1.2,\n    overflow: 'auto',\n  },\n  message: {\n    fontWeight: 'bold',\n  },\n  stack: {\n    fontFamily: 'monospace',\n    marginTop: '2em',\n  },\n  frame: {\n    marginTop: '1em',\n  },\n  file: {\n    fontSize: '0.8em',\n    color: 'rgba(255, 255, 255, 0.7)',\n  },\n  linkToFile: {\n    textDecoration: 'none',\n    color: 'rgba(255, 255, 255, 0.7)',\n  },\n};\n\nexport default class CustomRedbox extends React.Component {\n  render() {\n    return (\n      <Redbox\n        error={this.props.error}\n        style={styles}\n      />);\n  }\n}\n\nCustomRedbox.propTypes = {\n  error: PropTypes.string.isRequired,\n};\n"
  },
  {
    "path": "assets/app/config/Root.js",
    "content": "import React, { Component } from 'react';\nimport { connect } from 'react-redux';\nimport { Route, Switch } from 'react-router';\nimport { ConnectedRouter as Router } from 'react-router-redux';\nimport PropTypes from 'prop-types';\n\n\nimport { authenticate, unauthenticate } from 'actions/session';\nimport {\n  App,\n  ErrorMessage,\n  NotFound,\n  Signup,\n  Login,\n  MatchAuthenticated,\n  RedirectAuthenticated,\n} from 'components';\n\n\nclass Root extends Component {\n  componentDidMount() {\n    const token = localStorage.getItem('token');\n\n    if (token) {\n      this.props.authenticate();\n    } else {\n      this.props.unauthenticate();\n    }\n  }\n\n  render() {\n    const { isAuthenticated, willAuthenticate } = this.props;\n    const authProps = {\n      isAuthenticated,\n      willAuthenticate,\n    };\n\n    return (\n      <div className=\"full-height\">\n        <ErrorMessage />\n        <Router history={this.props.history}>\n          <Switch>\n            <MatchAuthenticated exact path=\"/\" component={App} {...authProps} />\n            <RedirectAuthenticated exact path=\"/signup\" component={Signup} {...authProps} />\n            <RedirectAuthenticated exact path=\"/login\" component={Login} {...authProps} />\n            <Route component={NotFound} />\n          </Switch>\n        </Router>\n      </div>\n    );\n  }\n}\n\n\nRoot.propTypes = {\n  history: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types\n  authenticate: PropTypes.func.isRequired,\n  unauthenticate: PropTypes.func.isRequired,\n  isAuthenticated: PropTypes.bool.isRequired,\n  willAuthenticate: PropTypes.bool.isRequired,\n};\n\nconst mapDispatchToProps = dispatch => ({\n  dispatch,\n  authenticate: () => dispatch(authenticate()),\n  unauthenticate: () => dispatch(unauthenticate()),\n});\n\nconst mapStateProps = state => ({\n  isAuthenticated: state.session.isAuthenticated,\n  willAuthenticate: state.session.willAuthenticate,\n});\n\nexport default connect(mapStateProps, mapDispatchToProps)(Root);\n"
  },
  {
    "path": "assets/app/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>ReactJS Boilerplate</title>\n</head>\n<body>\n\n    <div id=\"root\"></div>\n</body>\n</html>"
  },
  {
    "path": "assets/app/main.js",
    "content": "import React from 'react';\nimport ReactDOM from 'react-dom';\nimport { AppContainer } from 'react-hot-loader';\nimport { Provider } from 'react-redux';\nimport createHistory from 'history/createBrowserHistory';\n\nimport configureStore, { sagaMiddleware } from 'store';\nimport Root from 'config/Root';\nimport CustomRedbox from 'config/CustomRedbox';\nimport Sagas from 'sagas';\n\nimport 'bootstrap/dist/css/bootstrap.css';\nimport 'font-awesome/css/font-awesome.css';\n\nconst history = createHistory();\nconst store = configureStore(history);\n\nsagaMiddleware.run(Sagas);\n\n\nconst render = (Component) => {\n  ReactDOM.render(\n    <AppContainer errorReporter={CustomRedbox}>\n      <Provider store={store}>\n        <Component history={history} />\n      </Provider>\n    </AppContainer>,\n    document.getElementById('root'),\n  );\n};\n\nrender(Root);\n\nif (module.hot) {\n  module.hot.accept('./config/Root', () => {\n    const newApp = require('./config/Root').default;\n    render(newApp);\n  });\n}\n"
  },
  {
    "path": "assets/app/reducers/errors.js",
    "content": "import { types as errorTypes } from 'actions/errors';\n\nconst initialState = {\n  errors: [],\n};\n\nexport default function (state = initialState, action) {\n  switch (action.type) {\n    case errorTypes.NEW_ERROR:\n      return {\n        ...state,\n        errors: [...state.errors, action.message],\n      };\n    default:\n      return state;\n  }\n}\n"
  },
  {
    "path": "assets/app/reducers/index.js",
    "content": "import { combineReducers } from 'redux';\nimport { routerReducer } from 'react-router-redux';\nimport { reducer as form } from 'redux-form';\n\nimport session from 'reducers/session';\nimport errors from 'reducers/errors';\nimport { types as sessionTypes } from 'actions/session';\n\nconst appReducer = combineReducers({\n  form,\n  session,\n  errors,\n  routing: routerReducer,\n});\n\nexport default function (state, action) {\n  if (action.type === sessionTypes.LOGOUT) {\n    return appReducer(undefined, action);\n  }\n  return appReducer(state, action);\n}\n"
  },
  {
    "path": "assets/app/reducers/session.js",
    "content": "import { types as sessionTypes } from 'actions/session';\n\nconst initialState = {\n  isAuthenticated: false,\n  willAuthenticate: true,\n  submittingForm: false,\n  currentUser: {},\n};\n\nexport default function (state = initialState, action) {\n  switch (action.type) {\n    case sessionTypes.LOGIN_REQUEST:\n      return {\n        ...state,\n        submittingForm: true,\n      };\n    case sessionTypes.SIGNUP_REQUEST:\n      return {\n        ...state,\n        submittingForm: true,\n      };\n    case sessionTypes.AUTHENTICATION_SUCCESS:\n      return {\n        ...state,\n        isAuthenticated: true,\n        willAuthenticate: false,\n        submittingForm: false,\n        currentUser: action.response.data,\n      };\n    case sessionTypes.AUTHENTICATION_FAILURE:\n      return {\n        ...state,\n        willAuthenticate: false,\n        submittingForm: false,\n      };\n    case sessionTypes.LOGOUT:\n      return {\n        ...state,\n        isAuthenticated: false,\n        willAuthenticate: false,\n        submittingForm: false,\n        currentUser: {},\n      };\n    default:\n      return state;\n  }\n}\n"
  },
  {
    "path": "assets/app/sagas/index.js",
    "content": "import { fork } from 'redux-saga/effects';\nimport Session from 'sagas/session';\n\nconst sagas = [\n  ...Session,\n];\n\nexport default function* root() {\n  yield sagas.map(saga => fork(saga));\n}\n"
  },
  {
    "path": "assets/app/sagas/session.js",
    "content": "import { takeEvery } from 'redux-saga';\nimport { call, put } from 'redux-saga/effects';\nimport { push } from 'react-router-redux';\nimport { reset } from 'redux-form';\n\nimport api from 'utils/api';\nimport { types as sessionTypes } from 'actions/session';\nimport { types as errorTypes } from 'actions/errors';\n\nfunction setCurrentUser(response) {\n  localStorage.setItem('token', JSON.stringify(response.meta.token));\n}\n\n\n// Login\n\nfunction login(data) {\n  return api.post('/sessions', data);\n}\n\nfunction* callLogin({ data }) {\n  const result = yield call(login, data);\n\n  if (result.data.data) {\n    yield put({ type: sessionTypes.AUTHENTICATION_SUCCESS, response: result.data });\n    setCurrentUser(result.data);\n    yield put(reset('signup'));\n  } else {\n    yield put({ type: sessionTypes.AUTHENTICATION_FAILURE });\n    yield put({ type: errorTypes.NEW_ERROR, message: result.data.errors });\n    localStorage.removeItem('token');\n  }\n}\n\nfunction* loginSaga() {\n  yield* takeEvery(sessionTypes.LOGIN_REQUEST, callLogin);\n}\n\n// Signup\n\nfunction signup(data) {\n  return api.post('/users', data);\n}\n\nfunction* callSignup({ data }) {\n  const result = yield call(signup, data);\n\n  if (result.data.data) {\n    yield put({ type: sessionTypes.AUTHENTICATION_SUCCESS, response: result.data });\n    setCurrentUser(result.data);\n    yield put(reset('signup'));\n    yield put(push('/'));\n  } else {\n    yield put({ type: sessionTypes.AUTHENTICATION_FAILURE });\n    yield put({ type: errorTypes.NEW_ERROR, message: result.data.errors });\n    localStorage.removeItem('token');\n    yield put(push('/login'));\n  }\n}\n\n\nfunction* signupSaga() {\n  yield* takeEvery(sessionTypes.SIGNUP_REQUEST, callSignup);\n}\n\n// Logout\n\nfunction logout() {\n  return api.delete('/sessions');\n}\n\nfunction* callLogout() {\n  yield call(logout);\n  localStorage.removeItem('token');\n}\n\nfunction* logoutSaga() {\n  yield* takeEvery(sessionTypes.LOGOUT, callLogout);\n}\n\n// Authenticate\n\nfunction authenticate() {\n  return api.post('/sessions/refresh');\n}\n\nfunction* callAuthenticate() {\n  const result = yield call(authenticate);\n\n  if (result.data.data) {\n    yield put({ type: sessionTypes.AUTHENTICATION_SUCCESS, response: result.data });\n    setCurrentUser(result.data);\n  } else {\n    yield put({ type: sessionTypes.AUTHENTICATION_FAILURE });\n    yield put({ type: errorTypes.NEW_ERROR, message: result.data.errors });\n    localStorage.removeItem('token');\n    window.location = '/login';\n  }\n}\n\nfunction* authenticateSaga() {\n  yield* takeEvery(sessionTypes.AUTHENTICATION_REQUEST, callAuthenticate);\n}\n\nexport default [loginSaga, signupSaga, logoutSaga, authenticateSaga];\n"
  },
  {
    "path": "assets/app/store/index.js",
    "content": "import '@babel/polyfill';\nimport { createStore, applyMiddleware, compose } from 'redux';\nimport { createLogger } from 'redux-logger';\nimport createSagaMiddleware from 'redux-saga';\nimport { routerMiddleware } from 'react-router-redux';\n\nimport reducers from 'reducers';\n\n\nconst loggerMiddleware = createLogger({\n  level: 'info',\n  collapsed: true,\n});\nconst useReduxLogger = false;\n\nexport const sagaMiddleware = createSagaMiddleware();\n\n/* eslint-disable no-underscore-dangle */\nexport default function configureStore(browserHistory) {\n  const router = routerMiddleware(browserHistory);\n  const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;\n  // const reduxRouterMiddleware = syncHistoryWithStore(browserHistory);\n\n  let middleware = [sagaMiddleware, router];\n\n  if (useReduxLogger && process.env.NODE_ENV !== 'production') {\n    middleware = [...middleware, loggerMiddleware];\n  }\n\n  const createStoreWithMiddleware = composeEnhancers(applyMiddleware(...middleware))(createStore);\n\n  return createStoreWithMiddleware(reducers);\n}\n/* eslint-enable */\n"
  },
  {
    "path": "assets/app/utils/api.js",
    "content": "import axios from 'axios';\n\nconst API = '/api';\n\nfunction headers() {\n  const token = JSON.parse(localStorage.getItem('token'));\n\n  return {\n    Accept: 'application/json',\n    'Content-Type': 'application/json',\n    Authorization: `Bearer: ${token}`,\n  };\n}\n\nfunction queryString(params) {\n  const query = Object.keys(params)\n    .map(k => `${encodeURIComponent(k)}=${encodeURIComponent(params[k])}`)\n    .join('&');\n  return `${query.length ? '?' : ''}${query}`;\n}\n\nexport default {\n  fetch(url, params = {}) {\n    return axios.get(`${API}${url}${queryString(params)}`, { headers: headers() });\n  },\n\n  post(url, data) {\n    return axios.post(`${API}${url}`, data, { headers: headers() })\n      .catch(error => error.response);\n  },\n\n  patch(url, data) {\n    return axios.patch(`${API}${url}`, data, { headers: headers() });\n  },\n\n  delete(url) {\n    return axios.delete(`${API}${url}`, { headers: headers() });\n  },\n};\n"
  },
  {
    "path": "assets/app/utils/socket.js",
    "content": "/* eslint-disable */\n// NOTE: The contents of this file will only be executed if\n// you uncomment its entry in \"assets/js/app.js\".\n\n// To use Phoenix channels, the first step is to import Socket\n// and connect at the socket path in \"lib/web/endpoint.ex\":\nimport { Socket } from 'phoenix';\n\nlet socket = new Socket('/socket', { params: { token: window.userToken } });\n\n// When you connect, you'll often need to authenticate the client.\n// For example, imagine you have an authentication plug, `MyAuth`,\n// which authenticates the session and assigns a `:current_user`.\n// If the current user exists you can assign the user's token in\n// the connection for use in the layout.\n//\n// In your \"lib/web/router.ex\":\n//\n//     pipeline :browser do\n//       ...\n//       plug MyAuth\n//       plug :put_user_token\n//     end\n//\n//     defp put_user_token(conn, _) do\n//       if current_user = conn.assigns[:current_user] do\n//         token = Phoenix.Token.sign(conn, \"user socket\", current_user.id)\n//         assign(conn, :user_token, token)\n//       else\n//         conn\n//       end\n//     end\n//\n// Now you need to pass this token to JavaScript. You can do so\n// inside a script tag in \"lib/web/templates/layout/app.html.eex\":\n//\n//     <script>window.userToken = \"<%= assigns[:user_token] %>\";</script>\n//\n// You will need to verify the user token in the \"connect/2\" function\n// in \"lib/web/channels/user_socket.ex\":\n//\n//     def connect(%{\"token\" => token}, socket) do\n//       # max_age: 1209600 is equivalent to two weeks in seconds\n//       case Phoenix.Token.verify(socket, \"user socket\", token, max_age: 1209600) do\n//         {:ok, user_id} ->\n//           {:ok, assign(socket, :user, user_id)}\n//         {:error, reason} ->\n//           :error\n//       end\n//     end\n//\n// Finally, pass the token on connect as below. Or remove it\n// from connect if you don't care about authentication.\n\nsocket.connect();\n\n// Now that you are connected, you can join channels with a topic:\nlet channel = socket.channel('topic:subtopic', {});\nchannel.join()\n  .receive('ok', (resp) => { console.log('Joined successfully', resp);})\n  .receive('error', (resp) => { console.log('Unable to join', resp);})\n\nexport default socket;\n/* eslint-enable */\n"
  },
  {
    "path": "assets/app/vendors/.gitkeep",
    "content": ""
  },
  {
    "path": "assets/package.json",
    "content": "{\n  \"name\": \"react-webpack-boilerplate\",\n  \"version\": \"0.0.1\",\n  \"description\": \"Minimalistic ES6 React boilerplate\",\n  \"main\": \"index.js\",\n  \"scripts\": {\n    \"prestart\": \"npm run production\",\n    \"start\": \"webpack-dev-server --colors --stdin\",\n    \"production\": \"webpack --config webpack.production.config.js --progress --profile --colors\",\n    \"lint\": \"eslint app\",\n    \"lintf\": \"eslint app --fix\",\n    \"test\": \"jest\",\n    \"precommit\": \"cross-env npm run lint && npm test && cd .. && mix test\",\n    \"prepush\": \"cross-env npm run lint && npm test && cd .. && mix test\",\n    \"watch\": \"webpack --watch --color\"\n  },\n  \"author\": \"Dmitriy Chernyshov <dmitriy.chernyshof@gmail.com>\",\n  \"license\": \"MIT\",\n  \"jest\": {\n    \"modulePaths\": [\n      \"app\"\n    ],\n    \"moduleDirectories\": [\n      \"node_modules\"\n    ],\n    \"moduleNameMapper\": {\n      \"^.+\\\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$\": \"<rootDir>/private/jest/fileMock.js\",\n      \"^components$\": \"<rootDir>/private/jest/componentsMock.js\"\n    },\n    \"setupFiles\": [\n      \"<rootDir>/private/jest/shim.js\",\n      \"<rootDir>/private/jest/setupTests.js\"\n    ]\n  },\n  \"dependencies\": {\n    \"@babel/polyfill\": \"^7.0.0\",\n    \"axios\": \"^0.18.0\",\n    \"bootstrap\": \"^4.1.3\",\n    \"cross-env\": \"^5.2.0\",\n    \"font-awesome\": \"^4.7.0\",\n    \"history\": \"^4.7.2\",\n    \"jquery\": \"^3.3.1\",\n    \"lodash\": \"^4.17.11\",\n    \"md5\": \"^2.2.1\",\n    \"moment\": \"^2.22.2\",\n    \"phoenix\": \"^1.3.4\",\n    \"popper.js\": \"^1.14.4\",\n    \"prop-types\": \"^15.6.2\",\n    \"react\": \"^16.6.0\",\n    \"react-document-title\": \"^2.0.3\",\n    \"react-dom\": \"^16.6.0\",\n    \"react-hot-loader\": \"^4.3.11\",\n    \"react-notification-system\": \"^0.2.17\",\n    \"react-redux\": \"^5.0.7\",\n    \"react-router\": \"^4.3.1\",\n    \"react-router-dom\": \"^4.3.1\",\n    \"react-router-redux\": \"^5.0.0-alpha.9\",\n    \"redbox-react\": \"^1.6.0\",\n    \"redux\": \"^4.0.1\",\n    \"redux-form\": \"^7.4.2\",\n    \"redux-logger\": \"^3.0.6\",\n    \"redux-saga\": \"^0.16.2\",\n    \"tether\": \"^1.4.5\"\n  },\n  \"devDependencies\": {\n    \"@babel/cli\": \"^7.1.2\",\n    \"@babel/core\": \"^7.1.2\",\n    \"@babel/plugin-proposal-class-properties\": \"^7.1.0\",\n    \"@babel/plugin-proposal-decorators\": \"^7.1.2\",\n    \"@babel/plugin-proposal-do-expressions\": \"^7.0.0\",\n    \"@babel/plugin-proposal-export-default-from\": \"^7.0.0\",\n    \"@babel/plugin-proposal-export-namespace-from\": \"^7.0.0\",\n    \"@babel/plugin-proposal-function-bind\": \"^7.0.0\",\n    \"@babel/plugin-proposal-function-sent\": \"^7.1.0\",\n    \"@babel/plugin-proposal-json-strings\": \"^7.0.0\",\n    \"@babel/plugin-proposal-logical-assignment-operators\": \"^7.0.0\",\n    \"@babel/plugin-proposal-nullish-coalescing-operator\": \"^7.0.0\",\n    \"@babel/plugin-proposal-numeric-separator\": \"^7.0.0\",\n    \"@babel/plugin-proposal-object-rest-spread\": \"^7.0.0\",\n    \"@babel/plugin-proposal-optional-chaining\": \"^7.0.0\",\n    \"@babel/plugin-proposal-pipeline-operator\": \"^7.0.0\",\n    \"@babel/plugin-proposal-throw-expressions\": \"^7.0.0\",\n    \"@babel/plugin-syntax-dynamic-import\": \"^7.0.0\",\n    \"@babel/plugin-syntax-import-meta\": \"^7.0.0\",\n    \"@babel/plugin-transform-modules-commonjs\": \"^7.1.0\",\n    \"@babel/preset-env\": \"^7.0.0\",\n    \"@babel/preset-react\": \"^7.0.0\",\n    \"@babel/preset-stage-0\": \"^7.0.0\",\n    \"@babel/preset-stage-1\": \"^7.0.0\",\n    \"@babel/preset-stage-2\": \"^7.0.0\",\n    \"@babel/preset-stage-3\": \"^7.0.0\",\n    \"babel-core\": \"7.0.0-bridge.0\",\n    \"babel-eslint\": \"^10.0.1\",\n    \"babel-jest\": \"^23.6.0\",\n    \"babel-loader\": \"^8.0.4\",\n    \"copy-webpack-plugin\": \"^4.5.4\",\n    \"css-hot-loader\": \"^1.4.2\",\n    \"css-loader\": \"^1.0.0\",\n    \"enzyme\": \"^3.7.0\",\n    \"enzyme-adapter-react-16\": \"^1.6.0\",\n    \"eslint\": \"^5.7.0\",\n    \"eslint-config-airbnb\": \"^17.1.0\",\n    \"eslint-import-resolver-webpack\": \"^0.10.1\",\n    \"eslint-plugin-import\": \"^2.14.0\",\n    \"eslint-plugin-jsx-a11y\": \"^6.1.2\",\n    \"eslint-plugin-react\": \"^7.11.1\",\n    \"extract-text-webpack-plugin\": \"^4.0.0-beta.0\",\n    \"file-loader\": \"^2.0.0\",\n    \"html-webpack-plugin\": \"^3.2.0\",\n    \"husky\": \"^1.1.2\",\n    \"jest\": \"^23.6.0\",\n    \"node-sass\": \"^4.9.4\",\n    \"open-browser-webpack-plugin\": \"^0.0.5\",\n    \"postcss-loader\": \"^3.0.0\",\n    \"react-test-renderer\": \"^16.6.0\",\n    \"sass-loader\": \"^7.1.0\",\n    \"style-loader\": \"^0.23.1\",\n    \"uglifyjs-webpack-plugin\": \"^2.0.1\",\n    \"url-loader\": \"^1.1.2\",\n    \"webpack\": \"^4.23.1\",\n    \"webpack-cli\": \"^3.1.2\",\n    \"webpack-dev-server\": \"^3.1.10\"\n  }\n}\n"
  },
  {
    "path": "assets/private/jest/componentsMock.js",
    "content": "import React from 'react'\nimport PropTypes from 'prop-types'\n\nmodule.exports = new Proxy({}, {\n  get: (target, property) => {\n    const Mock = props => <span>{props.children}</span>\n\n    Mock.displayName = property\n    Mock.propTypes = {\n      children: PropTypes.any,\n    }\n\n    return Mock\n  },\n})\n"
  },
  {
    "path": "assets/private/jest/fileMock.js",
    "content": "export default 'file'\n"
  },
  {
    "path": "assets/private/jest/setupTests.js",
    "content": "import { configure } from 'enzyme'\nimport Adapter from 'enzyme-adapter-react-16'\n\nconfigure({ adapter: new Adapter() })\n"
  },
  {
    "path": "assets/private/jest/shim.js",
    "content": "global.requestAnimationFrame = /* istanbul ignore next */ (callback) => {\n  setTimeout(callback, 0)\n}\n"
  },
  {
    "path": "assets/webpack.config.js",
    "content": "const { resolve } = require('path');\r\n\r\nconst publicPath = 'http://localhost:3000/'; \r\nconst webpack = require('webpack');\r\nconst CopyWebpackPlugin = require('copy-webpack-plugin');\r\nconst OpenBrowserPlugin = require('open-browser-webpack-plugin');\r\n\r\n// const MiniCssExtractPlugin = require('mini-css-extract-plugin');\r\n// const ExtractCssChunks = require(\"extract-css-chunks-webpack-plugin\")\r\nconst ExtractTextPlugin = require('extract-text-webpack-plugin');\r\n\r\n\r\nconst config = {\r\n  devtool: 'cheap-module-eval-source-map',\r\n  // devtool: 'inline-source-map',\r\n\r\n  entry: [\r\n    'react-hot-loader/patch',\r\n    // activate HMR for React\r\n\r\n    'webpack-dev-server/client?http://localhost:3000',\r\n    // bundle the client for webpack-dev-server\r\n    // and connect to the provided endpoint\r\n\r\n    'webpack/hot/only-dev-server',\r\n    // bundle the client for hot reloading\r\n    // only- means to only hot reload for successful updates\r\n \r\n    './main.js',\r\n    // entry point\r\n\r\n    './assets/scss/index.scss',\r\n    'jquery/dist/jquery.js',\r\n    'tether/dist/js/tether.js',\r\n    'bootstrap/dist/js/bootstrap.js',\r\n  ],\r\n\r\n  resolve: {\r\n    alias: {\r\n      components: resolve(__dirname, 'app/components/index.js'),\r\n      reducers: resolve(__dirname, 'app/reducers'),\r\n      actions: resolve(__dirname, 'app/actions'),\r\n      config: resolve(__dirname, 'app/config'),\r\n      store: resolve(__dirname, 'app/store'),\r\n      utils: resolve(__dirname, 'app/utils'),\r\n      sagas: resolve(__dirname, 'app/sagas'),\r\n    },\r\n  },\r\n\r\n\r\n  output: {\r\n    filename: 'js/app.js',\r\n    path: resolve(__dirname, '../priv/static'),\r\n    publicPath: publicPath,\r\n    hotUpdateChunkFilename: 'hot-update.js',\r\n    hotUpdateMainFilename: 'hot-update.json',\r\n    crossOriginLoading: \"anonymous\",\r\n  },\r\n\r\n  context: resolve(__dirname, 'app'),\r\n\r\n  mode: 'development',\r\n\r\n  devServer: {\r\n    host: 'localhost',\r\n    port: 3000,\r\n    headers: {\r\n      'Access-Control-Allow-Origin': '*',\r\n    },\r\n    hot: true,\r\n    // enable HMR on the server\r\n\r\n    historyApiFallback: true,\r\n    // respond to 404s with index.html\r\n\r\n    contentBase: resolve(__dirname, '../priv/static'),\r\n    publicPath: '/',\r\n\r\n    // overlay: true,\r\n\r\n    overlay: {\r\n      warnings: true,\r\n      errors: true,\r\n    },\r\n  },\r\n\r\n  module: {\r\n    rules: [\r\n      {\r\n        test: /\\.js$/,\r\n        loaders: [\r\n          'babel-loader',\r\n        ],\r\n        exclude: /node_modules/,\r\n      },\r\n      {\r\n        test: /\\.scss$/, // files ending with .scss\r\n        use: ['css-hot-loader'].concat(ExtractTextPlugin.extract({\r\n          fallback: 'style-loader',\r\n          use: ['css-loader', 'sass-loader'],\r\n        })),\r\n        // use: [\r\n        //   // MiniCssExtractPlugin.loader,\r\n        //   ExtractCssChunks.loader,\r\n        //   // 'css-hot-loader',\r\n        //   'css-loader',\r\n        //   'sass-loader',\r\n        // ],\r\n        // use: ['css-hot-loader'].concat(MiniCssExtractPlugin.extract({\r\n        //   fallback: 'style-loader',\r\n        //   use: ['css-loader', 'sass-loader'],\r\n        // })),\r\n      },\r\n      { test: /\\.css$/, loader: ['style-loader', 'css-loader'] },\r\n      { test: /\\.(png|jpg)$/, use: 'url-loader?limit=15000' },\r\n      { test: /\\.svg$/, loader: 'url-loader?limit=65000&mimetype=image/svg+xml&name=fonts/[name].[ext]' },\r\n      { test: /\\.woff$/, loader: 'url-loader?limit=65000&mimetype=application/font-woff&name=fonts/[name].[ext]' },\r\n      { test: /\\.woff2$/, loader: 'url-loader?limit=65000&mimetype=application/font-woff2&name=fonts/[name].[ext]' },\r\n      { test: /\\.[ot]tf$/, loader: 'url-loader?limit=65000&mimetype=application/octet-stream&name=fonts/[name].[ext]' },\r\n      { test: /\\.eot$/, loader: 'url-loader?limit=65000&mimetype=application/vnd.ms-fontobject&name=fonts/[name].[ext]' },\r\n    ],\r\n  },\r\n\r\n  plugins: [\r\n    new webpack.ProvidePlugin({\r\n      $: 'jquery',\r\n      jQuery: 'jquery',\r\n      'window.jQuery': 'jquery',\r\n      Tether: 'tether',\r\n    }),\r\n    new webpack.HotModuleReplacementPlugin(),\r\n    // enable HMR globally\r\n\r\n    new webpack.NamedModulesPlugin(),\r\n    // prints more readable module names in the browser console on HMR updates\r\n\r\n    new webpack.NoEmitOnErrorsPlugin(),\r\n    // do not emit compiled assets that include errors\r\n\r\n    new CopyWebpackPlugin([{ from: 'vendors', to: 'vendors' }]),\r\n    new OpenBrowserPlugin({ url: 'http://localhost:4000' }),\r\n\r\n    // new ExtractCssChunks(\r\n    //     {\r\n    //       // Options similar to the same options in webpackOptions.output\r\n    //       // both options are optional\r\n    //       filename: \"./css/style.css\",\r\n    //       hot: true, // if you want HMR - we try to automatically inject hot reloading but if it's not working, add it to the config\r\n    //       orderWarning: true, // Disable to remove warnings about conflicting order between imports\r\n    //       reloadAll: true, // when desperation kicks in - this is a brute force HMR flag\r\n    //       cssModules: true // if you use cssModules, this can help.\r\n    //     }),\r\n    // new MiniCssExtractPlugin({ filename: 'css/style.css', hot: true}),\r\n    new ExtractTextPlugin({ filename: './css/style.css', disable: false, allChunks: true }),\r\n  ],\r\n};\r\n\r\nmodule.exports = config;\r\n"
  },
  {
    "path": "assets/webpack.production.config.js",
    "content": "const { resolve } = require('path');\nconst webpack = require('webpack');\nconst HtmlWebpackPlugin = require('html-webpack-plugin');\nconst CopyWebpackPlugin = require('copy-webpack-plugin');\n// const MiniCssExtractPlugin = require('mini-css-extract-plugin');\nconst ExtractTextPlugin = require('extract-text-webpack-plugin');\nconst UglifyJsPlugin = require('uglifyjs-webpack-plugin')\n\nconst config = {\n  devtool: 'cheap-module-source-map',\n\n  entry: [\n    './main.js',\n    './assets/scss/index.scss',\n  ],\n\n  context: resolve(__dirname, 'app'),\n\n  resolve: {\n    alias: {\n      components: resolve(__dirname, 'app/components/index.js'),\n      reducers: resolve(__dirname, 'app/reducers'),\n      actions: resolve(__dirname, 'app/actions'),\n      config: resolve(__dirname, 'app/config'),\n      store: resolve(__dirname, 'app/store'),\n      utils: resolve(__dirname, 'app/utils'),\n      sagas: resolve(__dirname, 'app/sagas'),\n    },\n  },\n\n\n  output: {\n    filename: 'js/app.js',\n    path: resolve(__dirname, '../priv/static'),\n    publicPath: '/',\n  },\n\n  optimization: {\n    minimizer: [\n\n      new UglifyJsPlugin({\n        uglifyOptions: {\n          // beautify: false,\n          // mangle: {\n          //   screw_ie8: true,\n          //   keep_fnames: true,\n          // },\n          compress: {\n            booleans: true,\n            // screw_ie8: true,\n          },\n          output: {\n            comments: false,\n          },\n          minify: {},\n        }\n      }),\n    ]\n  },\n\n  plugins: [\n    new HtmlWebpackPlugin({\n      template: `${__dirname}/app/index.html`,\n      filename: 'index.html',\n      inject: 'body',\n    }),\n    new webpack.optimize.OccurrenceOrderPlugin(),\n    new webpack.LoaderOptionsPlugin({\n      minimize: true,\n      debug: false,\n    }),\n    new webpack.DefinePlugin({ 'process.env': { NODE_ENV: JSON.stringify('production') } }),\n    // new MiniCssExtractPlugin({ filename: 'css/style.css'}),\n    new ExtractTextPlugin({ filename: 'css/style.css', disable: false, allChunks: true }),\n    new CopyWebpackPlugin([{ from: './vendors', to: 'vendors' }]),\n  ],\n\n  module: {\n    rules: [\n      {\n        test: /\\.js?$/,\n        exclude: /node_modules/,\n        use: [{\n          loader: 'babel-loader',\n        }]\n      },\n      {\n        test: /\\.scss$/,\n        exclude: /node_modules/,\n        use: ExtractTextPlugin.extract({\n          fallback: 'style-loader',\n          use: [\n            'css-loader',\n            { loader: 'sass-loader', query: { sourceMap: false } },\n          ],\n        }),\n\n        // use: [\n        //   MiniCssExtractPlugin.loader,\n        //   'css-hot-loader',\n        //   'css-loader',\n        //   'sass-loader',\n        // ],\n\n        // use: MiniCssExtractPlugin.extract({\n        //   fallback: 'style-loader',\n        //   use: [\n        //     'css-loader',\n        //     { loader: 'sass-loader', query: { sourceMap: false } },\n        //   ],\n        // }),\n      },\n      { test: /\\.css$/, loader: ['style-loader', 'css-loader'] },\n      { test: /\\.(png|jpg)$/, use: 'url-loader?limit=15000' },\n      { test: /\\.svg$/, loader: 'url-loader?limit=65000&mimetype=image/svg+xml&name=fonts/[name].[ext]' },\n      { test: /\\.woff$/, loader: 'url-loader?limit=65000&mimetype=application/font-woff&name=fonts/[name].[ext]' },\n      { test: /\\.woff2$/, loader: 'url-loader?limit=65000&mimetype=application/font-woff2&name=fonts/[name].[ext]' },\n      { test: /\\.[ot]tf$/, loader: 'url-loader?limit=65000&mimetype=application/octet-stream&name=fonts/[name].[ext]' },\n      { test: /\\.eot$/, loader: 'url-loader?limit=65000&mimetype=application/vnd.ms-fontobject&name=fonts/[name].[ext]' },\n    ],\n  },\n};\n\nmodule.exports = config;\n"
  },
  {
    "path": "config/config.exs",
    "content": "# This file is responsible for configuring your application\n# and its dependencies with the aid of the Mix.Config module.\n#\n# This configuration file is loaded before any dependency and\n# is restricted to this project.\nuse Mix.Config\n\n# General application configuration\nconfig :boilerplate,\n  ecto_repos: [Boilerplate.Repo]\n\n# Configures the endpoint\nconfig :boilerplate, BoilerplateWeb.Endpoint,\n  url: [host: \"localhost\"],\n  secret_key_base: \"H5AcfaG9fEz2gjjKEBJ3PNT7peIPEo270GOHwgataQEsfdx8Ujsi3aDlxel77eQH\",\n  render_errors: [view: BoilerplateWeb.ErrorView, accepts: ~w(html json)],\n  pubsub: [name: Boilerplate.PubSub,\n           adapter: Phoenix.PubSub.PG2]\n\n# Configures Elixir's Logger\nconfig :logger, :console,\n  format: \"$time $metadata[$level] $message\\n\",\n  metadata: [:user_id]\n\n# Configures Guardian\nconfig :boilerplate, BoilerplateWeb.Guardian,\n  issuer: \"boilerplate\",\n  ttl: {30, :days},\n  verify_issuer: true\n  # serializer: Boilerplate.GuardianSerializer\n\n# Import environment specific config. This must remain at the bottom\n# of this file so it overrides the configuration defined above.\nimport_config \"#{Mix.env}.exs\"\n"
  },
  {
    "path": "config/dev.exs",
    "content": "use Mix.Config\n\n# For development, we disable any cache and enable\n# debugging and code reloading.\n#\n# The watchers configuration can be used to run external\n# watchers to your application. For example, we use it\n# with brunch.io to recompile .js and .css sources.\nconfig :boilerplate, BoilerplateWeb.Endpoint,\n  http: [port: 4000],\n  debug_errors: true,\n  code_reloader: true,\n  check_origin: false,\n  watchers: [node: [\"node_modules/webpack-dev-server/bin/webpack-dev-server.js\", \"--colors\", \"--stdin\", cd: Path.expand(\"../assets\", __DIR__)]]\n\n  # Not working in windows because of npm permission issue\n  # watchers: [npm: [\"run\", \"start\", cd: Path.expand(\"../assets\", __DIR__)]]\n\n  # watchers: [npm: [\"run\", \"watch\", cd: Path.expand(\"../assets\", __DIR__)]]\n\n# ## SSL Support\n#\n# In order to use HTTPS in development, a self-signed\n# certificate can be generated by running the following\n# command from your terminal:\n#\n#     openssl req -new -newkey rsa:4096 -days 365 -nodes -x509 -subj \"/C=US/ST=Denial/L=Springfield/O=Dis/CN=www.example.com\" -keyout priv/server.key -out priv/server.pem\n#\n# The `http:` config above can be replaced with:\n#\n#     https: [port: 4000, keyfile: \"priv/server.key\", certfile: \"priv/server.pem\"],\n#\n# If desired, both `http:` and `https:` keys can be\n# configured to run both http and https servers on\n# different ports.\n\n# Watch static and templates for browser reloading.\nconfig :boilerplate, BoilerplateWeb.Endpoint,\n  live_reload: [\n    patterns: [\n      ~r{priv/static/.*(js|css|png|jpeg|jpg|gif|svg)$},\n      ~r{priv/gettext/.*(po)$},\n      ~r{lib/boilerplate_web/views/.*(ex)$},\n      ~r{lib/boilerplate_web/templates/.*(eex)$}\n    ]\n  ]\n\n# Do not include metadata nor timestamps in development logs\nconfig :logger, :console, format: \"[$level] $message\\n\"\n\n# Set a higher stacktrace during development. Avoid configuring such\n# in production as building large stacktraces may be expensive.\nconfig :phoenix, :stacktrace_depth, 20\n\n# Configure your database\nconfig :boilerplate, Boilerplate.Repo,\n  adapter: Ecto.Adapters.Postgres,\n  username: \"postgres\",\n  password: \"postgres\",\n  database: \"boilerplate_dev\",\n  hostname: \"localhost\",\n  pool_size: 10\n\n# Configure Guardian secret key\nconfig :boilerplate, BoilerplateWeb.Guardian,\n  secret_key: \"OSMuzr1uWJthItzsyXItnRoM3MLNaZXUwkamEHTwxUBYPPDuQTLPJnMBMiMATRjF\"\n"
  },
  {
    "path": "config/prod.exs",
    "content": "use Mix.Config\n\n# For production, we often load configuration from external\n# sources, such as your system environment. For this reason,\n# you won't find the :http configuration below, but set inside\n# BoilerplateWeb.Endpoint.init/2 when load_from_system_env is\n# true. Any dynamic configuration should be done there.\n#\n# Don't forget to configure the url host to something meaningful,\n# Phoenix uses this information when generating URLs.\n#\n# Finally, we also include the path to a cache manifest\n# containing the digested version of static files. This\n# manifest is generated by the mix phx.digest task\n# which you typically run after static files are built.\nconfig :boilerplate, BoilerplateWeb.Endpoint,\n  load_from_system_env: true,\n  url: [scheme: \"https\", host: \"phxboilerplate.herokuapp.com\", port: 443],\n  force_ssl: [rewrite_on: [:x_forwarded_proto]],\n  cache_static_manifest: \"priv/static/cache_manifest.json\",\n  secret_key_base: Map.fetch!(System.get_env(), \"SECRET_KEY_BASE\")\n\n# Do not print debug messages in production\nconfig :logger, level: :info\n\n# Configure database\nconfig :boilerplate, Boilerplate.Repo,\n  adapter: Ecto.Adapters.Postgres,\n  url: System.get_env(\"DATABASE_URL\"),\n  pool_size: String.to_integer(System.get_env(\"POOL_SIZE\") || \"10\"),\n  ssl: true\n\n# ## SSL Support\n#\n# To get SSL working, you will need to add the `https` key\n# to the previous section and set your `:url` port to 443:\n#\n#     config :boilerplate, BoilerplateWeb.Endpoint,\n#       ...\n#       url: [host: \"example.com\", port: 443],\n#       https: [:inet6,\n#               port: 443,\n#               keyfile: System.get_env(\"SOME_APP_SSL_KEY_PATH\"),\n#               certfile: System.get_env(\"SOME_APP_SSL_CERT_PATH\")]\n#\n# Where those two env variables return an absolute path to\n# the key and cert in disk or a relative path inside priv,\n# for example \"priv/ssl/server.key\".\n#\n# We also recommend setting `force_ssl`, ensuring no data is\n# ever sent via http, always redirecting to https:\n#\n#     config :boilerplate, BoilerplateWeb.Endpoint,\n#       force_ssl: [hsts: true]\n#\n# Check `Plug.SSL` for all available options in `force_ssl`.\n\n# ## Using releases\n#\n# If you are doing OTP releases, you need to instruct Phoenix\n# to start the server for all endpoints:\n#\n#     config :phoenix, :serve_endpoints, true\n#\n# Alternatively, you can configure exactly which server to\n# start per endpoint:\n#\n#     config :boilerplate, BoilerplateWeb.Endpoint, server: true\n#\n\nconfig :boilerplate, BoilerplateWeb.Guardian,\n  secret_key: System.get_env(\"GUARDIAN_SECRET_KEY\")\n\n# Finally import the config/prod.secret.exs\n# which should be versioned separately.\n# import_config \"prod.secret.exs\"\n"
  },
  {
    "path": "config/test.exs",
    "content": "use Mix.Config\n\n# We don't run a server during test. If one is required,\n# you can enable the server option below.\nconfig :boilerplate, BoilerplateWeb.Endpoint,\n  http: [port: 4001],\n  server: false\n\n# Print only warnings and errors during test\nconfig :logger, level: :warn\n\n# Reduce number of rounds\nconfig :bcrypt_elixir, log_rounds: 4\n\n# Configure your database\nconfig :boilerplate, Boilerplate.Repo,\n  adapter: Ecto.Adapters.Postgres,\n  username: \"postgres\",\n  password: \"postgres\",\n  database: \"boilerplate_test\",\n  hostname: \"localhost\",\n  pool: Ecto.Adapters.SQL.Sandbox\n\n# Configure Guardian secret key\nconfig :boilerplate, BoilerplateWeb.Guardian,\n  secret_key: \"OSMuzr1uWJthItzsyXItnRoM3MLNaZXUwkamEHTwxUBYPPDuQTLPJnMBMiMATRjF\"\n"
  },
  {
    "path": "elixir_buildpack.config",
    "content": "elixir_version=1.6.1\n"
  },
  {
    "path": "lib/boilerplate/accounts/accounts.ex",
    "content": "defmodule Boilerplate.Accounts do\n  @moduledoc \"\"\"\n  The Accounts context.\n  \"\"\"\n\n  import Ecto.{Query, Changeset}, warn: false\n  alias Boilerplate.Repo\n\n  alias Boilerplate.Accounts.User\n\n  @doc \"\"\"\n  Returns the list of users.\n\n  ## Examples\n\n      iex> list_users()\n      [%User{}, ...]\n\n  \"\"\"\n  def list_users do\n    Repo.all(User)\n  end\n\n  @doc \"\"\"\n  Gets a single user.\n\n  Raises `Ecto.NoResultsError` if the User does not exist.\n\n  ## Examples\n\n      iex> get_user!(123)\n      %User{}\n\n      iex> get_user!(456)\n      ** (Ecto.NoResultsError)\n\n  \"\"\"\n  def get_user!(id), do: Repo.get!(User, id)\n\n  def get_user_by_username(username) do\n    username = String.downcase(username)\n\n    Repo.one(from(p in User, where: fragment(\"lower(?)\", p.username) == ^username)) ||\n      {:error, :user_not_found}\n  end\n\n  @doc \"\"\"\n  Creates a user.\n\n  ## Examples\n\n      iex> create_user(%{field: value})\n      {:ok, %User{}}\n\n      iex> create_user(%{field: bad_value})\n      {:error, %Ecto.Changeset{}}\n\n  \"\"\"\n  def create_user(attrs \\\\ %{}, superuser \\\\ %{}) do\n    if !is_exist_username(attrs) do\n      if !is_exist_email(attrs) do\n        %User{}\n        |> match_superuser_registration_changeset(attrs, superuser)\n        |> Repo.insert()\n      else\n        {:error, :already_taken_email}\n      end\n    else\n      {:error, :already_taken_username}\n    end\n  end\n\n  @doc \"\"\"\n  Updates a user.\n\n  ## Examples\n\n      iex> update_user(user, %{field: new_value})\n      {:ok, %User{}}\n\n      iex> update_user(user, %{field: bad_value})\n      {:error, %Ecto.Changeset{}}\n\n  \"\"\"\n  def update_user(%User{} = user, attrs, current_user \\\\ %{}) do\n    if is_superuser_or_same_user?(user, current_user) do\n      user\n      |> match_superuser_changeset(attrs, current_user)\n      |> Repo.update()\n    else\n      {:error, :forbidden}\n    end\n  end\n\n  @doc \"\"\"\n  Deletes a User.\n\n  ## Examples\n\n      iex> delete_user(user)\n      {:ok, %User{}}\n\n      iex> delete_user(user)\n      {:error, %Ecto.Changeset{}}\n\n  \"\"\"\n  # def delete_user(%User{} = user), do: delete_user(user, user)\n  def delete_user(%User{} = user, %User{} = current_user) do\n    if is_superuser_or_same_user?(user, current_user) do\n      Repo.delete(user)\n    else\n      {:error, :forbidden}\n    end\n  end\n\n  @doc \"\"\"\n  Returns an `%Ecto.Changeset{}` for tracking user changes.\n\n  ## Examples\n\n      iex> change_user(user)\n      %Ecto.Changeset{source: %User{}}\n\n  \"\"\"\n  def change_user(%User{} = user) do\n    User.changeset(user, %{})\n  end\n\n  defp is_exist_username(attrs) do\n    username = attrs[\"username\"] || attrs[:username]\n\n    if username do\n      username = String.downcase(username)\n\n      Repo.one(\n        from(\n          p in User,\n          where: fragment(\"lower(?)\", p.username) == fragment(\"lower(?)\", ^username)\n        )\n      )\n    end\n  end\n\n  defp is_exist_email(attrs) do\n    email = attrs[\"email\"] || attrs[:email]\n\n    if email do\n      email = String.downcase(email)\n\n      Repo.one(\n        from(p in User, where: fragment(\"lower(?)\", p.email) == fragment(\"lower(?)\", ^email))\n      )\n    end\n  end\n\n  def get_current_token(conn) do\n    BoilerplateWeb.Guardian.Plug.current_token(conn)\n  end\n\n  def sign_out(conn) do\n    BoilerplateWeb.Guardian.Plug.sign_out(conn)\n  end\n\n  def get_claims(conn) do\n    BoilerplateWeb.Guardian.Plug.current_claims(conn)\n  end\n\n  def refresh_token(jwt) do\n    BoilerplateWeb.Guardian.refresh(jwt)\n  end\n\n  def get_current_user(conn) do\n    BoilerplateWeb.Guardian.Plug.current_resource(conn)\n  end\n\n  def sign_in_user(conn, user) do\n    BoilerplateWeb.Guardian.Plug.sign_in(conn, user)\n  end\n\n  def authenticate(%{\"email\" => email, \"password\" => password}) do\n    user =\n      Repo.one(\n        from(p in User, where: fragment(\"lower(?)\", p.email) == fragment(\"lower(?)\", ^email))\n      )\n\n    case check_password(user, password) do\n      true -> {:ok, user}\n      _ -> {:error, :wrong_credentials}\n    end\n  end\n\n  def update_last_login(%User{} = user) do\n    last_login = NaiveDateTime.utc_now()\n\n    user\n    |> User.last_login_changeset(%{last_login: last_login})\n    |> Repo.update()\n  end\n\n  defp check_password(user, password) do\n    case user do\n      nil -> Comeonin.Bcrypt.dummy_checkpw()\n      _ -> Comeonin.Bcrypt.checkpw(password, user.password_hash)\n    end\n  end\n\n  defp is_superuser?(user) do\n    Map.get(user, :is_superuser)\n  end\n\n  def is_the_same_users?(user, current_user) do\n    id1 = Map.get(user, :id)\n    id2 = Map.get(current_user, :id)\n    id1 == id2\n  end\n\n  defp match_superuser_changeset(%User{} = user, attrs, superuser) do\n    if is_superuser?(superuser) do\n      User.superuser_changeset(user, attrs)\n    else\n      User.changeset(user, attrs)\n    end\n  end\n\n  defp match_superuser_registration_changeset(%User{} = user, attrs, superuser) do\n    if is_superuser?(superuser) do\n      User.superuser_registration_changeset(user, attrs)\n    else\n      User.registration_changeset(user, attrs)\n    end\n  end\n\n  defp is_superuser_or_same_user?(user, current_user) do\n    is_superuser?(current_user) || is_the_same_users?(user, current_user)\n  end\nend\n"
  },
  {
    "path": "lib/boilerplate/accounts/user.ex",
    "content": "defmodule Boilerplate.Accounts.User do\n  use Ecto.Schema\n  import Ecto.Changeset\n  alias Boilerplate.Accounts.User\n\n  schema \"users\" do\n    field(:name, :string)\n    field(:email, :string)\n    field(:password, :string, virtual: true)\n    field(:password_hash, :string)\n    field(:username, :string)\n    field(:is_staff, :boolean, default: false)\n    field(:is_superuser, :boolean, default: false)\n    field(:last_login, :naive_datetime)\n\n    timestamps()\n  end\n\n  @doc false\n  def changeset(%User{} = user, attrs) do\n    user\n    |> cast(attrs, [:name, :username, :email])\n    |> validate_required([:name, :username, :email])\n    |> validate_length(:username, min: 1, max: 20)\n    |> validate_format(:username, ~r/^[A-Za-z0-9._]+$/)\n    |> validate_format(:email, ~r/^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}$/)\n    |> unique_constraint(:username)\n    |> unique_constraint(:email)\n  end\n\n  @doc false\n  def superuser_changeset(%User{} = user, attrs) do\n    user\n    |> changeset(attrs)\n    |> cast(attrs, [:is_staff, :is_superuser])\n  end\n\n  @doc false\n  def registration_changeset(%User{} = user, attrs) do\n    user\n    |> changeset(attrs)\n    |> cast(attrs, [:password])\n    |> validate_length(:password, min: 6, max: 100)\n    |> put_password_hash\n  end\n\n  @doc false\n  def superuser_registration_changeset(%User{} = user, attrs) do\n    user\n    |> superuser_changeset(attrs)\n    |> cast(attrs, [:password])\n    |> validate_length(:password, min: 6, max: 100)\n    |> put_password_hash\n  end\n\n  @doc false\n  def last_login_changeset(%User{} = user, attrs) do\n    user\n    |> cast(attrs, [:last_login])\n    |> validate_required([:last_login])\n  end\n\n  defp put_password_hash(changeset) do\n    case changeset do\n      %Ecto.Changeset{valid?: true, changes: %{password: password}} ->\n        put_change(changeset, :password_hash, Comeonin.Bcrypt.hashpwsalt(password))\n\n      _ ->\n        changeset\n    end\n  end\nend\n"
  },
  {
    "path": "lib/boilerplate/application.ex",
    "content": "defmodule Boilerplate.Application do\n  use Application\n\n  # See https://hexdocs.pm/elixir/Application.html\n  # for more information on OTP Applications\n  def start(_type, _args) do\n    import Supervisor.Spec\n\n    # Define workers and child supervisors to be supervised\n    children = [\n      # Start the Ecto repository\n      supervisor(Boilerplate.Repo, []),\n      # Start the endpoint when the application starts\n      supervisor(BoilerplateWeb.Endpoint, [])\n      # Start your own worker by calling: Boilerplate.Worker.start_link(arg1, arg2, arg3)\n      # worker(Boilerplate.Worker, [arg1, arg2, arg3]),\n    ]\n\n    # See https://hexdocs.pm/elixir/Supervisor.html\n    # for other strategies and supported options\n    opts = [strategy: :one_for_one, name: Boilerplate.Supervisor]\n    Supervisor.start_link(children, opts)\n  end\n\n  # Tell Phoenix to update the endpoint configuration\n  # whenever the application is updated.\n  def config_change(changed, _new, removed) do\n    BoilerplateWeb.Endpoint.config_change(changed, removed)\n    :ok\n  end\nend\n"
  },
  {
    "path": "lib/boilerplate/repo.ex",
    "content": "defmodule Boilerplate.Repo do\n  use Ecto.Repo, otp_app: :boilerplate\n\n  @doc \"\"\"\n  Dynamically loads the repository url from the\n  DATABASE_URL environment variable.\n  \"\"\"\n  def init(_, opts) do\n    {:ok, Keyword.put(opts, :url, System.get_env(\"DATABASE_URL\"))}\n  end\nend\n"
  },
  {
    "path": "lib/boilerplate.ex",
    "content": "defmodule Boilerplate do\n  @moduledoc \"\"\"\n  Boilerplate keeps the contexts that define your domain\n  and business logic.\n\n  Contexts are also responsible for managing your data, regardless\n  if it comes from the database, an external API or others.\n  \"\"\"\nend\n"
  },
  {
    "path": "lib/boilerplate_web/channels/user_socket.ex",
    "content": "defmodule BoilerplateWeb.UserSocket do\n  use Phoenix.Socket\n\n  ## Channels\n  # channel \"room:*\", BoilerplateWeb.RoomChannel\n\n  ## Transports\n  transport(:websocket, Phoenix.Transports.WebSocket, timeout: 45_000)\n  # transport :longpoll, Phoenix.Transports.LongPoll\n\n  # Socket params are passed from the client and can\n  # be used to verify and authenticate a user. After\n  # verification, you can put default assigns into\n  # the socket that will be set for all channels, ie\n  #\n  #     {:ok, assign(socket, :user_id, verified_user_id)}\n  #\n  # To deny connection, return `:error`.\n  #\n  # See `Phoenix.Token` documentation for examples in\n  # performing token verification on connect.\n  def connect(_params, socket) do\n    {:ok, socket}\n  end\n\n  # Socket id's are topics that allow you to identify all sockets for a given user:\n  #\n  #     def id(socket), do: \"user_socket:#{socket.assigns.user_id}\"\n  #\n  # Would allow you to broadcast a \"disconnect\" event and terminate\n  # all active sockets and channels for a given user:\n  #\n  #     BoilerplateWeb.Endpoint.broadcast(\"user_socket:#{user.id}\", \"disconnect\", %{})\n  #\n  # Returning `nil` makes this socket anonymous.\n  def id(_socket), do: nil\nend\n"
  },
  {
    "path": "lib/boilerplate_web/controllers/api/session_controller.ex",
    "content": "defmodule BoilerplateWeb.SessionController do\n  use BoilerplateWeb, :controller\n\n  alias Boilerplate.Accounts\n\n  action_fallback(BoilerplateWeb.FallbackController)\n\n  def create(conn, params) do\n    with {:ok, user} <- Accounts.authenticate(params) do\n      new_conn = Accounts.sign_in_user(conn, user)\n      jwt = Accounts.get_current_token(new_conn)\n\n      spawn(fn -> Accounts.update_last_login(user) end)\n\n      new_conn\n      |> put_status(:created)\n      |> render(\"show.json\", user: user, jwt: jwt)\n    end\n  end\n\n  def delete(conn, _) do\n    user = Accounts.get_current_user(conn)\n\n    with new_conn = Accounts.sign_out(conn) do\n      spawn(fn -> Accounts.update_last_login(user) end)\n\n      new_conn\n      |> put_status(:ok)\n      |> render(\"delete.json\")\n    end\n  end\n\n  def refresh(conn, _params) do\n    user = Accounts.get_current_user(conn)\n\n    with jwt = Accounts.get_current_token(conn),\n         {:ok, _, {new_jwt, _new_claims}} <- Accounts.refresh_token(jwt) do\n      spawn(fn -> Accounts.update_last_login(user) end)\n\n      conn\n      |> put_status(:ok)\n      |> render(\"show.json\", user: user, jwt: new_jwt)\n    end\n  end\nend\n"
  },
  {
    "path": "lib/boilerplate_web/controllers/api/user_controller.ex",
    "content": "defmodule BoilerplateWeb.UserController do\n  use BoilerplateWeb, :controller\n\n  alias Boilerplate.Accounts\n  alias Boilerplate.Accounts.User\n\n  action_fallback(BoilerplateWeb.FallbackController)\n\n  def index(conn, _) do\n    users = Accounts.list_users()\n    current_user = Accounts.get_current_user(conn)\n\n    render(conn, \"index.json\", users: users, current_user: current_user)\n  end\n\n  def show(conn, %{\"username\" => username}) do\n    with %User{} = user <- Accounts.get_user_by_username(username) do\n      current_user = Accounts.get_current_user(conn)\n      render(conn, \"show.json\", user: user, current_user: current_user)\n    end\n  end\n\n  def update(conn, %{\"id\" => id, \"user\" => user_params}) do\n    user = Accounts.get_user!(id)\n    current_user = Accounts.get_current_user(conn)\n\n    with {:ok, %User{} = user} <- Accounts.update_user(user, user_params, current_user) do\n      render(conn, \"show.json\", user: user)\n    end\n  end\n\n  def create(conn, user_params) do\n    with {:ok, %User{} = user} <- Accounts.create_user(user_params) do\n      new_conn = Accounts.sign_in_user(conn, user)\n      jwt = Accounts.get_current_token(new_conn)\n\n      new_conn\n      |> put_status(:created)\n      |> render(BoilerplateWeb.SessionView, \"show.json\", user: user, jwt: jwt)\n    end\n  end\n\n  def delete(conn, %{\"id\" => id}) do\n    user = Accounts.get_user!(id)\n    current_user = Accounts.get_current_user(conn)\n\n    with {:ok, %User{}} <- Accounts.delete_user(user, current_user) do\n      send_resp(conn, :no_content, \"\")\n    end\n  end\nend\n"
  },
  {
    "path": "lib/boilerplate_web/controllers/auth_error_controller.ex",
    "content": "defmodule BoilerplateWeb.AuthErrorController do\n  import Plug.Conn\n  use BoilerplateWeb, :controller\n\n  def auth_error(conn, {_type, _reason}, _opts) do\n    conn\n    |> put_status(:unauthorized)\n    |> render(BoilerplateWeb.SessionView, \"wrong_credentials.json\")\n  end\nend\n"
  },
  {
    "path": "lib/boilerplate_web/controllers/fallback_controller.ex",
    "content": "defmodule BoilerplateWeb.FallbackController do\n  @moduledoc \"\"\"\n  Translates controller action results into valid `Plug.Conn` responses.\n\n  See `Phoenix.Controller.action_fallback/1` for more details.\n  \"\"\"\n  use BoilerplateWeb, :controller\n\n  def call(conn, {:error, %Ecto.Changeset{} = changeset}) do\n    conn\n    |> put_status(:unprocessable_entity)\n    |> render(BoilerplateWeb.ChangesetView, \"error.json\", changeset: changeset)\n  end\n\n  def call(conn, {:error, :not_found}) do\n    conn\n    |> put_status(:not_found)\n    |> render(BoilerplateWeb.ErrorView, :\"404\")\n  end\n\n  def call(conn, {:error, :wrong_credentials}) do\n    conn\n    |> put_status(:unprocessable_entity)\n    |> render(BoilerplateWeb.SessionView, \"wrong_credentials.json\")\n  end\n\n  def call(conn, {:error, :no_session}) do\n    conn\n    |> put_status(:unprocessable_entity)\n    |> render(BoilerplateWeb.SessionView, \"no_session.json\")\n  end\n\n  def call(conn, {:error, :invalid_issuer}) do\n    conn\n    |> put_status(:bad_request)\n    |> render(BoilerplateWeb.SessionView, \"invalid_issuer.json\")\n  end\n\n  def call(conn, {:error, :already_taken_username}) do\n    conn\n    |> put_status(:bad_request)\n    |> render(BoilerplateWeb.SessionView, \"already_taken_username.json\")\n  end\n\n  def call(conn, {:error, :already_taken_email}) do\n    conn\n    |> put_status(:bad_request)\n    |> render(BoilerplateWeb.SessionView, \"already_taken_email.json\")\n  end\n\n  def call(conn, {:error, \"Unknown resource type\"}) do\n    conn\n    |> put_status(:unauthorized)\n    |> render(BoilerplateWeb.SessionView, \"wrong_token.json\")\n  end\n\n  def call(conn, {:error, :user_not_found}) do\n    conn\n    |> put_status(:not_found)\n    |> render(BoilerplateWeb.UserView, \"404.json\")\n  end\n\n  def call(conn, {:error, :forbidden}) do\n    conn\n    |> put_status(:forbidden)\n    |> render(BoilerplateWeb.ErrorView, \"permission_denied.json\")\n  end\nend\n"
  },
  {
    "path": "lib/boilerplate_web/controllers/page_controller.ex",
    "content": "defmodule BoilerplateWeb.PageController do\n  use BoilerplateWeb, :controller\n\n  def index(conn, _params) do\n    render(conn, \"index.html\")\n  end\nend\n"
  },
  {
    "path": "lib/boilerplate_web/endpoint.ex",
    "content": "defmodule BoilerplateWeb.Endpoint do\n  use Phoenix.Endpoint, otp_app: :boilerplate\n\n  socket(\"/socket\", BoilerplateWeb.UserSocket)\n\n  # Serve at \"/\" the static files from \"priv/static\" directory.\n  #\n  # You should set gzip to true if you are running phoenix.digest\n  # when deploying your static files in production.\n  plug(\n    Plug.Static,\n    at: \"/\",\n    from: :boilerplate,\n    gzip: false,\n    only: ~w(css fonts images js favicon.ico robots.txt)\n  )\n\n  # Code reloading can be explicitly enabled under the\n  # :code_reloader configuration of your endpoint.\n  if code_reloading? do\n    socket(\"/phoenix/live_reload/socket\", Phoenix.LiveReloader.Socket)\n    plug(Phoenix.LiveReloader)\n    plug(Phoenix.CodeReloader)\n  end\n\n  plug(Plug.Logger)\n\n  plug(\n    Plug.Parsers,\n    parsers: [:urlencoded, :multipart, :json],\n    pass: [\"*/*\"],\n    json_decoder: Poison\n  )\n\n  plug Plug.MethodOverride\n  plug Plug.Head\n\n  # The session will be stored in the cookie and signed,\n  # this means its contents can be read but not tampered with.\n  # Set :encryption_salt if you would also like to encrypt it.\n  plug(\n    Plug.Session,\n    store: :cookie,\n    key: \"_boilerplate_key\",\n    signing_salt: \"7ptxdQY6\"\n  )\n\n  plug BoilerplateWeb.Router\n\n  @doc \"\"\"\n  Callback invoked for dynamically configuring the endpoint.\n\n  It receives the endpoint configuration and checks if\n  configuration should be loaded from the system environment.\n  \"\"\"\n  def init(_key, config) do\n    if config[:load_from_system_env] do\n      port = System.get_env(\"PORT\") || raise \"expected the PORT environment variable to be set\"\n      {:ok, Keyword.put(config, :http, [:inet6, port: port])}\n    else\n      {:ok, config}\n    end\n  end\nend\n"
  },
  {
    "path": "lib/boilerplate_web/gettext.ex",
    "content": "defmodule BoilerplateWeb.Gettext do\n  @moduledoc \"\"\"\n  A module providing Internationalization with a gettext-based API.\n\n  By using [Gettext](https://hexdocs.pm/gettext),\n  your module gains a set of macros for translations, for example:\n\n      import BoilerplateWeb.Gettext\n\n      # Simple translation\n      gettext \"Here is the string to translate\"\n\n      # Plural translation\n      ngettext \"Here is the string to translate\",\n               \"Here are the strings to translate\",\n               3\n\n      # Domain-based translation\n      dgettext \"errors\", \"Here is the error message to translate\"\n\n  See the [Gettext Docs](https://hexdocs.pm/gettext) for detailed usage.\n  \"\"\"\n  use Gettext, otp_app: :boilerplate\nend\n"
  },
  {
    "path": "lib/boilerplate_web/guardian.ex",
    "content": "defmodule BoilerplateWeb.Guardian do\n  use Guardian, otp_app: :boilerplate\n\n  def subject_for_token(resource, _claims) do\n    # You can use any value for the subject of your token but\n    # it should be useful in retrieving the resource later, see\n    # how it being used on `resource_from_claims/1` function.\n    # A unique `id` is a good subject, a non-unique email address\n    # is a poor subject.\n    sub = to_string(resource.id)\n    {:ok, sub}\n  end\n\n  def resource_from_claims(claims) do\n    # Here we'll look up our resource from the claims, the subject can be\n    # found in the `\"sub\"` key. In `above subject_for_token/2` we returned\n    # the resource id so here we'll rely on that to look it up.\n    id = claims[\"sub\"]\n    resource = Boilerplate.Accounts.get_user!(id)\n    {:ok, resource}\n  end\nend\n"
  },
  {
    "path": "lib/boilerplate_web/router.ex",
    "content": "defmodule BoilerplateWeb.Router do\n  use BoilerplateWeb, :router\n\n  pipeline :browser do\n    plug(:accepts, [\"html\"])\n    plug(:fetch_session)\n    plug(:fetch_flash)\n    plug(:protect_from_forgery)\n    plug(:put_secure_browser_headers)\n  end\n\n  pipeline :api do\n    plug(:accepts, [\"json\"])\n  end\n\n  pipeline :unauthorized do\n    plug(:fetch_session)\n  end\n\n  pipeline :authorized do\n    plug(:fetch_session)\n\n    plug(\n      Guardian.Plug.Pipeline,\n      module: BoilerplateWeb.Guardian,\n      error_handler: BoilerplateWeb.AuthErrorController\n    )\n\n    plug(Guardian.Plug.VerifySession)\n    plug(Guardian.Plug.LoadResource)\n  end\n\n  scope \"/api\", BoilerplateWeb do\n    pipe_through(:api)\n\n    scope \"/\" do\n      pipe_through(:unauthorized)\n\n      post(\"/sessions\", SessionController, :create)\n      resources(\"/users\", UserController, only: [:create])\n    end\n\n    scope \"/\" do\n      pipe_through(:authorized)\n\n      delete(\"/sessions\", SessionController, :delete)\n      post(\"/sessions/refresh\", SessionController, :refresh)\n      resources(\"/users\", UserController, except: [:create])\n    end\n  end\n\n  scope \"/\", BoilerplateWeb do\n    # Use the default browser stack\n    pipe_through(:browser)\n\n    get(\"/*path\", PageController, :index)\n  end\nend\n"
  },
  {
    "path": "lib/boilerplate_web/templates/layout/app.html.eex",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n    <meta name=\"description\" content=\"description\">\n    <meta name=\"author\" content=\"Dmitriy Chernyshov\">\n\n    <title>Boilerplate</title>\n\n    <%= if Mix.env == :dev do %>\n    <link crossorigin rel=\"stylesheet\" href=\"http://localhost:3000/css/style.css\">\n    <% else %>\n    <link rel=\"stylesheet\" href=\"<%= static_path(@conn, \"/css/style.css\") %>\">\n    <% end %>\n  </head>\n\n  <body>\n    <div id=\"root\"></div>\n    <%= if Mix.env == :dev do %>\n      <script crossorigin src='http://localhost:3000/js/app.js'></script>\n    <% else %>\n      <script src=\"<%= static_path(@conn, \"/js/app.js\") %>\"></script>\n    <% end %>\n  </body>\n</html>\n"
  },
  {
    "path": "lib/boilerplate_web/views/changeset_view.ex",
    "content": "defmodule BoilerplateWeb.ChangesetView do\n  use BoilerplateWeb, :view\n\n  @doc \"\"\"\n  Traverses and translates changeset errors.\n\n  See `Ecto.Changeset.traverse_errors/2` and\n  `BoilerplateWeb.ErrorHelpers.translate_error/1` for more details.\n  \"\"\"\n  def translate_errors(changeset) do\n    Ecto.Changeset.traverse_errors(changeset, &translate_error/1)\n  end\n\n  def render(\"error.json\", %{changeset: changeset}) do\n    # When encoded, the changeset returns its errors\n    # as a JSON object. So we just pass it forward.\n    %{errors: translate_errors(changeset)}\n  end\nend\n"
  },
  {
    "path": "lib/boilerplate_web/views/error_helpers.ex",
    "content": "defmodule BoilerplateWeb.ErrorHelpers do\n  @moduledoc \"\"\"\n  Conveniences for translating and building error messages.\n  \"\"\"\n\n  use Phoenix.HTML\n\n  @doc \"\"\"\n  Generates tag for inlined form input errors.\n  \"\"\"\n  def error_tag(form, field) do\n    Enum.map(Keyword.get_values(form.errors, field), fn error ->\n      content_tag(:span, translate_error(error), class: \"help-block\")\n    end)\n  end\n\n  @doc \"\"\"\n  Translates an error message using gettext.\n  \"\"\"\n  def translate_error({msg, opts}) do\n    # Because error messages were defined within Ecto, we must\n    # call the Gettext module passing our Gettext backend. We\n    # also use the \"errors\" domain as translations are placed\n    # in the errors.po file.\n    # Ecto will pass the :count keyword if the error message is\n    # meant to be pluralized.\n    # On your own code and templates, depending on whether you\n    # need the message to be pluralized or not, this could be\n    # written simply as:\n    #\n    #     dngettext \"errors\", \"1 file\", \"%{count} files\", count\n    #     dgettext \"errors\", \"is invalid\"\n    #\n    if count = opts[:count] do\n      Gettext.dngettext(BoilerplateWeb.Gettext, \"errors\", msg, msg, count, opts)\n    else\n      Gettext.dgettext(BoilerplateWeb.Gettext, \"errors\", msg, opts)\n    end\n  end\nend\n"
  },
  {
    "path": "lib/boilerplate_web/views/error_view.ex",
    "content": "defmodule BoilerplateWeb.ErrorView do\n  use BoilerplateWeb, :view\n\n  def render(\"permission_denied\", _assigns) do\n    %{errors: \"Permission denied\"}\n  end\n\n  def render(\"404.html\", _assigns) do\n    \"Page not found\"\n  end\n\n  def render(\"500.html\", _assigns) do\n    \"Internal server error\"\n  end\n\n  # In case no render clause matches or no\n  # template is found, let's render it as 500\n  def template_not_found(_template, assigns) do\n    render(\"500.html\", assigns)\n  end\nend\n"
  },
  {
    "path": "lib/boilerplate_web/views/layout_view.ex",
    "content": "defmodule BoilerplateWeb.LayoutView do\n  use BoilerplateWeb, :view\nend\n"
  },
  {
    "path": "lib/boilerplate_web/views/page_view.ex",
    "content": "defmodule BoilerplateWeb.PageView do\n  use BoilerplateWeb, :view\nend\n"
  },
  {
    "path": "lib/boilerplate_web/views/session_view.ex",
    "content": "defmodule BoilerplateWeb.SessionView do\n  use BoilerplateWeb, :view\n  alias BoilerplateWeb.SessionView\n\n  def render(\"show.json\", %{user: user, jwt: jwt}) do\n    %{data: render_one(user, BoilerplateWeb.UserView, \"user.json\"), meta: %{token: jwt}}\n  end\n\n  def render(\"delete.json\", _) do\n    %{ok: true}\n  end\n\n  def render(\"no_session.json\", _) do\n    %{errors: \"invalid or expired session token\"}\n  end\n\n  def render(\"wrong_credentials.json\", _) do\n    %{errors: \"Wrong email or password\"}\n  end\n\n  def render(\"invalid_issuer.json\", _) do\n    %{errors: \"invalid issuer\"}\n  end\n\n  def render(\"already_taken_username.json\", _) do\n    %{errors: \"This username has already been taken. Please take another username\"}\n  end\n\n  def render(\"already_taken_email.json\", _) do\n    %{errors: \"This email has already been taken. Please take another email\"}\n  end\n\n  def render(\"invalid_token.json\", _) do\n    %{errors: \"invalid token\"}\n  end\nend\n"
  },
  {
    "path": "lib/boilerplate_web/views/user_view.ex",
    "content": "defmodule BoilerplateWeb.UserView do\n  use BoilerplateWeb, :view\n  alias BoilerplateWeb.UserView\n\n  def render(\"index.json\", %{users: users, current_user: %{is_staff: true}}) do\n    %{\n      data: %{\n        users: render_many(users, UserView, \"user.json\")\n      }\n    }\n  end\n\n  def render(\"index.json\", %{users: users}) do\n    %{\n      data: %{\n        users: render_many(users, UserView, \"show_user.json\")\n      }\n    }\n  end\n\n  def render(\"show.json\", %{user: user, current_user: %{is_staff: true}}) do\n    %{data: render_one(user, UserView, \"user.json\")}\n  end\n\n  def render(\"show.json\", %{user: user}) do\n    %{data: render_one(user, UserView, \"show_user.json\")}\n  end\n\n  def render(\"user.json\", %{user: user}) do\n    %{\n      id: user.id,\n      username: user.username,\n      name: user.name,\n      email: user.email,\n      last_login: user.last_login,\n      is_staff: user.is_staff,\n      is_superuser: user.is_superuser\n    }\n  end\n\n  def render(\"show_user.json\", %{user: user}) do\n    %{id: user.id, username: user.username, name: user.name, last_login: user.last_login}\n    # email: user.email\n  end\n\n  def render(\"404.json\", _assigns) do\n    %{errors: \"User not found\"}\n  end\nend\n"
  },
  {
    "path": "lib/boilerplate_web.ex",
    "content": "defmodule BoilerplateWeb do\n  @moduledoc \"\"\"\n  The entrypoint for defining your web interface, such\n  as controllers, views, channels and so on.\n\n  This can be used in your application as:\n\n      use BoilerplateWeb, :controller\n      use BoilerplateWeb, :view\n\n  The definitions below will be executed for every view,\n  controller, etc, so keep them short and clean, focused\n  on imports, uses and aliases.\n\n  Do NOT define functions inside the quoted expressions\n  below. Instead, define any helper function in modules\n  and import those modules here.\n  \"\"\"\n\n  def controller do\n    quote do\n      use Phoenix.Controller, namespace: BoilerplateWeb\n      import Plug.Conn\n      import BoilerplateWeb.Router.Helpers\n      import BoilerplateWeb.Gettext\n    end\n  end\n\n  def view do\n    quote do\n      use Phoenix.View,\n        root: \"lib/boilerplate_web/templates\",\n        namespace: BoilerplateWeb\n\n      # Import convenience functions from controllers\n      import Phoenix.Controller, only: [get_flash: 2, view_module: 1]\n\n      # Use all HTML functionality (forms, tags, etc)\n      use Phoenix.HTML\n\n      import BoilerplateWeb.Router.Helpers\n      import BoilerplateWeb.ErrorHelpers\n      import BoilerplateWeb.Gettext\n    end\n  end\n\n  def router do\n    quote do\n      use Phoenix.Router\n      import Plug.Conn\n      import Phoenix.Controller\n    end\n  end\n\n  def channel do\n    quote do\n      use Phoenix.Channel\n      import BoilerplateWeb.Gettext\n    end\n  end\n\n  @doc \"\"\"\n  When used, dispatch to the appropriate controller/view/etc.\n  \"\"\"\n  defmacro __using__(which) when is_atom(which) do\n    apply(__MODULE__, which, [])\n  end\nend\n"
  },
  {
    "path": "mix.exs",
    "content": "defmodule Boilerplate.Mixfile do\n  use Mix.Project\n\n  def project do\n    [\n      app: :boilerplate,\n      version: \"0.0.1\",\n      elixir: \"~> 1.6\",\n      elixirc_paths: elixirc_paths(Mix.env()),\n      compilers: [:phoenix, :gettext] ++ Mix.compilers(),\n      start_permanent: Mix.env() == :prod,\n      aliases: aliases(),\n      deps: deps()\n    ]\n  end\n\n  # Configuration for the OTP application.\n  #\n  # Type `mix help compile.app` for more information.\n  def application do\n    [\n      mod: {Boilerplate.Application, []},\n      extra_applications: [:logger, :runtime_tools, :comeonin]\n    ]\n  end\n\n  # Specifies which paths to compile per environment.\n  defp elixirc_paths(:test), do: [\"lib\", \"test/support\"]\n  defp elixirc_paths(_), do: [\"lib\"]\n\n  # Specifies your project dependencies.\n  #\n  # Type `mix help deps` for examples and options.\n  defp deps do\n    [\n      {:phoenix, \"~> 1.3.4\"},\n      {:phoenix_pubsub, \"~> 1.1\"},\n      {:phoenix_ecto, \"~> 3.5\"},\n      {:postgrex, \">= 0.0.0\"},\n      {:phoenix_html, \"~> 2.12\"},\n      {:phoenix_live_reload, \"~> 1.1\", only: :dev},\n      {:gettext, \"~> 0.16\"},\n      {:credo, \"~> 0.10\", only: [:dev, :test], runtime: false},\n      {:cowboy, \"~> 1.1\"},\n      {:comeonin, \"~> 4.1\"},\n      {:bcrypt_elixir, \"~> 1.1\"},\n      {:plug_cowboy, \"~> 1.0\"},\n      {:guardian, \"~> 1.1\"}\n    ]\n  end\n\n  # Aliases are shortcuts or tasks specific to the current project.\n  # For example, to create, migrate and run the seeds file at once:\n  #\n  #     $ mix ecto.setup\n  #\n  # See the documentation for `Mix` for more info on aliases.\n  defp aliases do\n    [\n      \"ecto.setup\": [\"ecto.create\", \"ecto.migrate\", \"run priv/repo/seeds.exs\"],\n      \"ecto.reset\": [\"ecto.drop\", \"ecto.setup\"],\n      test: [\"ecto.create --quiet\", \"ecto.migrate\", \"test\"]\n    ]\n  end\nend\n"
  },
  {
    "path": "phoenix_static_buildpack.config",
    "content": "node_version=10.12.0\nnpm_version=6.4.1\nassets_path=assets\nphoenix_ex=phx\n"
  },
  {
    "path": "priv/gettext/en/LC_MESSAGES/errors.po",
    "content": "## `msgid`s in this file come from POT (.pot) files.\n##\n## Do not add, change, or remove `msgid`s manually here as\n## they're tied to the ones in the corresponding POT file\n## (with the same domain).\n##\n## Use `mix gettext.extract --merge` or `mix gettext.merge`\n## to merge POT files into PO files.\nmsgid \"\"\nmsgstr \"\"\n\"Language: en\\n\"\n\n## From Ecto.Changeset.cast/4\nmsgid \"can't be blank\"\nmsgstr \"\"\n\n## From Ecto.Changeset.unique_constraint/3\nmsgid \"has already been taken\"\nmsgstr \"\"\n\n## From Ecto.Changeset.put_change/3\nmsgid \"is invalid\"\nmsgstr \"\"\n\n## From Ecto.Changeset.validate_acceptance/3\nmsgid \"must be accepted\"\nmsgstr \"\"\n\n## From Ecto.Changeset.validate_format/3\nmsgid \"has invalid format\"\nmsgstr \"\"\n\n## From Ecto.Changeset.validate_subset/3\nmsgid \"has an invalid entry\"\nmsgstr \"\"\n\n## From Ecto.Changeset.validate_exclusion/3\nmsgid \"is reserved\"\nmsgstr \"\"\n\n## From Ecto.Changeset.validate_confirmation/3\nmsgid \"does not match confirmation\"\nmsgstr \"\"\n\n## From Ecto.Changeset.no_assoc_constraint/3\nmsgid \"is still associated with this entry\"\nmsgstr \"\"\n\nmsgid \"are still associated with this entry\"\nmsgstr \"\"\n\n## From Ecto.Changeset.validate_length/3\nmsgid \"should be %{count} character(s)\"\nmsgid_plural \"should be %{count} character(s)\"\nmsgstr[0] \"\"\nmsgstr[1] \"\"\n\nmsgid \"should have %{count} item(s)\"\nmsgid_plural \"should have %{count} item(s)\"\nmsgstr[0] \"\"\nmsgstr[1] \"\"\n\nmsgid \"should be at least %{count} character(s)\"\nmsgid_plural \"should be at least %{count} character(s)\"\nmsgstr[0] \"\"\nmsgstr[1] \"\"\n\nmsgid \"should have at least %{count} item(s)\"\nmsgid_plural \"should have at least %{count} item(s)\"\nmsgstr[0] \"\"\nmsgstr[1] \"\"\n\nmsgid \"should be at most %{count} character(s)\"\nmsgid_plural \"should be at most %{count} character(s)\"\nmsgstr[0] \"\"\nmsgstr[1] \"\"\n\nmsgid \"should have at most %{count} item(s)\"\nmsgid_plural \"should have at most %{count} item(s)\"\nmsgstr[0] \"\"\nmsgstr[1] \"\"\n\n## From Ecto.Changeset.validate_number/3\nmsgid \"must be less than %{number}\"\nmsgstr \"\"\n\nmsgid \"must be greater than %{number}\"\nmsgstr \"\"\n\nmsgid \"must be less than or equal to %{number}\"\nmsgstr \"\"\n\nmsgid \"must be greater than or equal to %{number}\"\nmsgstr \"\"\n\nmsgid \"must be equal to %{number}\"\nmsgstr \"\"\n"
  },
  {
    "path": "priv/gettext/errors.pot",
    "content": "## This file is a PO Template file.\n##\n## `msgid`s here are often extracted from source code.\n## Add new translations manually only if they're dynamic\n## translations that can't be statically extracted.\n##\n## Run `mix gettext.extract` to bring this file up to\n## date. Leave `msgstr`s empty as changing them here as no\n## effect: edit them in PO (`.po`) files instead.\n\n## From Ecto.Changeset.cast/4\nmsgid \"can't be blank\"\nmsgstr \"\"\n\n## From Ecto.Changeset.unique_constraint/3\nmsgid \"has already been taken\"\nmsgstr \"\"\n\n## From Ecto.Changeset.put_change/3\nmsgid \"is invalid\"\nmsgstr \"\"\n\n## From Ecto.Changeset.validate_acceptance/3\nmsgid \"must be accepted\"\nmsgstr \"\"\n\n## From Ecto.Changeset.validate_format/3\nmsgid \"has invalid format\"\nmsgstr \"\"\n\n## From Ecto.Changeset.validate_subset/3\nmsgid \"has an invalid entry\"\nmsgstr \"\"\n\n## From Ecto.Changeset.validate_exclusion/3\nmsgid \"is reserved\"\nmsgstr \"\"\n\n## From Ecto.Changeset.validate_confirmation/3\nmsgid \"does not match confirmation\"\nmsgstr \"\"\n\n## From Ecto.Changeset.no_assoc_constraint/3\nmsgid \"is still associated with this entry\"\nmsgstr \"\"\n\nmsgid \"are still associated with this entry\"\nmsgstr \"\"\n\n## From Ecto.Changeset.validate_length/3\nmsgid \"should be %{count} character(s)\"\nmsgid_plural \"should be %{count} character(s)\"\nmsgstr[0] \"\"\nmsgstr[1] \"\"\n\nmsgid \"should have %{count} item(s)\"\nmsgid_plural \"should have %{count} item(s)\"\nmsgstr[0] \"\"\nmsgstr[1] \"\"\n\nmsgid \"should be at least %{count} character(s)\"\nmsgid_plural \"should be at least %{count} character(s)\"\nmsgstr[0] \"\"\nmsgstr[1] \"\"\n\nmsgid \"should have at least %{count} item(s)\"\nmsgid_plural \"should have at least %{count} item(s)\"\nmsgstr[0] \"\"\nmsgstr[1] \"\"\n\nmsgid \"should be at most %{count} character(s)\"\nmsgid_plural \"should be at most %{count} character(s)\"\nmsgstr[0] \"\"\nmsgstr[1] \"\"\n\nmsgid \"should have at most %{count} item(s)\"\nmsgid_plural \"should have at most %{count} item(s)\"\nmsgstr[0] \"\"\nmsgstr[1] \"\"\n\n## From Ecto.Changeset.validate_number/3\nmsgid \"must be less than %{number}\"\nmsgstr \"\"\n\nmsgid \"must be greater than %{number}\"\nmsgstr \"\"\n\nmsgid \"must be less than or equal to %{number}\"\nmsgstr \"\"\n\nmsgid \"must be greater than or equal to %{number}\"\nmsgstr \"\"\n\nmsgid \"must be equal to %{number}\"\nmsgstr \"\"\n"
  },
  {
    "path": "priv/repo/migrations/20170731093912_create_users.exs",
    "content": "defmodule Boilerplate.Repo.Migrations.CreateUsers do\n  use Ecto.Migration\n\n  def change do\n    create table(:users) do\n      add :name, :string, null: false\n      add :username, :string, null: false\n      add :email, :string, null: false\n      add :password_hash, :string, null: false\n      add :is_staff, :boolean, null: false, default: false\n      add :is_superuser, :boolean, null: false, default: false\n      add :last_login, :naive_datetime, default: fragment(\"now()\")\n\n      timestamps()\n    end\n\n    create index(:users, [\"lower(username)\"], unique: true)\n    create index(:users, [\"lower(email)\"], unique: true)\n\n    # In case if you not using postgres(not quite what we want but still better than nothing):\n    # create index(:users, :username, unique: true)\n    # create index(:users, :email, unique: true)\n  end\nend\n"
  },
  {
    "path": "priv/repo/migrations/20170731093913_insert_superuser.exs",
    "content": "defmodule Boilerplate.Repo.Migrations.CreateUsers do\n  use Ecto.Migration\n\n  def change do\n    Boilerplate.Accounts.create_user(%{name: \"admin\", username: \"admin\", password: \"12345678\", email: \"admin@admin.com\", is_superuser: true, is_staff: true}, %{is_superuser: true})\n  end\nend\n"
  },
  {
    "path": "priv/repo/seeds.exs",
    "content": "# Script for populating the database. You can run it as:\n#\n#     mix run priv/repo/seeds.exs\n#\n# Inside the script, you can read and write to any of your\n# repositories directly:\n#\n#     Boilerplate.Repo.insert!(%Boilerplate.SomeSchema{})\n#\n# We recommend using the bang functions (`insert!`, `update!`\n# and so on) as they will fail if something goes wrong.\n"
  },
  {
    "path": "test/boilerplate/accounts/accounts_test.exs",
    "content": "defmodule Boilerplate.AccountsTest do\n  use Boilerplate.DataCase\n\n  alias Boilerplate.Accounts\n\n  describe \"users\" do\n    alias Boilerplate.Accounts.User\n\n    @valid_attrs %{\n      name: \"Test Name\",\n      email: \"test@test.com\",\n      password: \"password\",\n      username: \"username\"\n    }\n    @update_attrs %{\n      name: \"Updated Name\",\n      email: \"test_update@test.com\",\n      password: \"updated_password\",\n      username: \"testusername_updated\"\n    }\n    @invalid_attrs %{name: nil, email: nil, password_hash: nil, username: nil}\n    @valid_attrs2 %{\n      name: \"Test Name\",\n      email: \"test2@test.com\",\n      password: \"password\",\n      username: \"UsErNaMe\"\n    }\n    @valid_attrs3 %{\n      name: \"Test Name\",\n      email: \"TeSt@TeSt.com\",\n      password: \"password\",\n      username: \"username2\"\n    }\n\n    def user_fixture(attrs \\\\ %{}) do\n      {:ok, user} =\n        attrs\n        |> Enum.into(@valid_attrs)\n        |> Accounts.create_user()\n\n      user\n    end\n\n    defp usermap(user), do: Map.drop(user, [:last_login, :password])\n\n    defp is_the_same_users([], []), do: true\n\n    defp is_the_same_users([user | t], [user2 | t2]) do\n      user = usermap(user)\n      user2 = usermap(user2)\n      # assert\n      assert user == user2\n      is_the_same_users(t, t2)\n    end\n\n    defp is_the_same_users(user, user2) do\n      is_the_same_users([user], [user2])\n    end\n\n    test \"list_users/0 returns all users\" do\n      user = user_fixture()\n      admin = Accounts.get_user_by_username(\"admin\")\n      is_the_same_users(Accounts.list_users(), [admin, user])\n    end\n\n    test \"get_user_by_username/1 returns the user with given username\" do\n      user = user_fixture()\n      user2 = Accounts.get_user_by_username(user.username)\n      is_the_same_users(user, user2)\n    end\n\n    test \"get_user_by_username/1 returns the user with given username but different case\" do\n      user = user_fixture()\n      user2 = Accounts.get_user_by_username(\"UsErNaMe\")\n      is_the_same_users(user, user2)\n    end\n\n    test \"get_user!/1 returns the user with given id\" do\n      user = user_fixture()\n      user2 = Accounts.get_user!(user.id)\n      is_the_same_users(user, user2)\n    end\n\n    test \"create_user/1 with valid data creates a user\" do\n      assert {:ok, %User{} = user} = Accounts.create_user(@valid_attrs)\n      assert user.name == @valid_attrs.name\n      assert user.email == @valid_attrs.email\n      assert user.username == @valid_attrs.username\n    end\n\n    test \"create_user/1 with valid data and username has already been taken returns error changeset\" do\n      assert {:ok, %User{} = user} = Accounts.create_user(@valid_attrs)\n      assert user.name == @valid_attrs.name\n      assert user.email == @valid_attrs.email\n      assert user.username == @valid_attrs.username\n\n      assert {:error, :already_taken_username} = Accounts.create_user(@valid_attrs2)\n    end\n\n    test \"create_user/1 with valid data and email has already been taken returns error changeset\" do\n      assert {:ok, %User{} = user} = Accounts.create_user(@valid_attrs)\n      assert user.name == @valid_attrs.name\n      assert user.email == @valid_attrs.email\n      assert user.username == @valid_attrs.username\n\n      assert {:error, :already_taken_email} = Accounts.create_user(@valid_attrs3)\n    end\n\n    test \"create_user/1 with invalid data returns error changeset\" do\n      assert {:error, %Ecto.Changeset{}} = Accounts.create_user(@invalid_attrs)\n    end\n\n    test \"update_user/2 with valid data updates the user\" do\n      user = user_fixture()\n      assert {:ok, user} = Accounts.update_user(user, @update_attrs, user)\n      assert %User{} = user\n      assert user.email == @update_attrs.email\n      assert user.name == @update_attrs.name\n      assert user.username == @update_attrs.username\n    end\n\n    test \"update_user/2 not updates current_user rights if user is not admin\" do\n      user = user_fixture()\n      assert {:ok, user} = Accounts.update_user(user, %{is_staff: true, is_superuser: true}, user)\n      assert %User{} = user\n      assert user.is_staff == false\n      assert user.is_superuser == false\n    end\n\n    test \"update_user/2 updates current_user rights if user is admin\" do\n      user = user_fixture()\n      admin = Accounts.get_user_by_username(\"admin\")\n\n      assert {:ok, user} =\n               Accounts.update_user(user, %{is_staff: true, is_superuser: true}, admin)\n\n      assert %User{} = user\n      assert user.is_staff == true\n      assert user.is_superuser == true\n    end\n\n    test \"update_user/2 with invalid data returns error changeset\" do\n      user = user_fixture()\n      assert {:ok, user} = Accounts.update_user(user, @update_attrs, user)\n      assert {:error, %Ecto.Changeset{}} = Accounts.update_user(user, @invalid_attrs, user)\n      user_u = Accounts.get_user!(user.id)\n      is_the_same_users(user_u, user)\n    end\n\n    test \"delete_user/1 deletes the user\" do\n      user = user_fixture()\n      assert {:ok, %User{}} = Accounts.delete_user(user, user)\n      assert_raise Ecto.NoResultsError, fn -> Accounts.get_user!(user.id) end\n    end\n\n    test \"change_user/1 returns a user changeset\" do\n      user = user_fixture()\n      assert %Ecto.Changeset{} = Accounts.change_user(user)\n    end\n  end\nend\n"
  },
  {
    "path": "test/boilerplate_web/controllers/page_controller_test.exs",
    "content": "defmodule BoilerplateWeb.PageControllerTest do\n  use BoilerplateWeb.ConnCase\n\n  test \"GET /\", %{conn: conn} do\n    conn = get(conn, \"/\")\n    assert html_response(conn, 200)\n  end\nend\n"
  },
  {
    "path": "test/boilerplate_web/controllers/user_controller_test.exs",
    "content": "defmodule BoilerplateWeb.UserControllerTest do\n  use BoilerplateWeb.ConnCase\n\n  alias Boilerplate.Accounts\n  alias Boilerplate.Accounts.User\n\n  @create_attrs %{\n    name: \"Test Name\",\n    email: \"test@test.com\",\n    password: \"password\",\n    username: \"username\"\n  }\n  @create_attrs2 %{\n    name: \"Test Name\",\n    email: \"test2@test.com\",\n    password: \"password\",\n    username: \"username2\"\n  }\n  @update_attrs %{\n    name: \"Updated Name\",\n    email: \"test_update@test.com\",\n    password: \"updated_password\",\n    username: \"testusername_updated\"\n  }\n  @invalid_attrs %{name: nil, email: nil, password_hash: nil, username: nil}\n\n  defp usermap(user), do: Map.drop(user, [:last_login, :password, \"last_login\", \"password\"])\n\n  defp is_the_same_users([], []), do: true\n\n  defp is_the_same_users([user | t], [user2 | t2]) do\n    user = usermap(user)\n    user2 = usermap(user2)\n    # assert\n    assert user == user2\n    is_the_same_users(t, t2)\n  end\n\n  defp is_the_same_users(user, user2) do\n    is_the_same_users([user], [user2])\n  end\n\n  def fixture(:user) do\n    {:ok, user} = Accounts.create_user(@create_attrs)\n    user\n  end\n\n  setup %{conn: conn} do\n    {:ok, conn: put_req_header(conn, \"accept\", \"application/json\")}\n  end\n\n  describe \"index users\" do\n    test \"lists all users\", %{conn: conn} do\n      t = Accounts.get_user_by_username(\"admin\")\n\n      admin = %{\n        \"id\" => t.id,\n        \"name\" => t.name,\n        \"username\" => t.username,\n        \"email\" => t.email,\n        \"is_staff\" => t.is_staff,\n        \"is_superuser\" => t.is_superuser\n      }\n\n      conn = Boilerplate.Accounts.sign_in_user(conn, t)\n      conn = get(conn, user_path(conn, :index))\n      assert %{\"users\" => users} = json_response(conn, 200)[\"data\"]\n      is_the_same_users(users, [admin])\n    end\n\n    test \"list should not be showed for unauthorized user\", %{conn: conn} do\n      conn = get(conn, user_path(conn, :index))\n      assert json_response(conn, 401)[\"errors\"]\n    end\n  end\n\n  describe \"show user\" do\n    test \"show user\", %{conn: conn} do\n      t = Accounts.get_user_by_username(\"admin\")\n\n      admin = %{\n        \"id\" => t.id,\n        \"name\" => t.name,\n        \"username\" => t.username,\n        \"email\" => t.email,\n        \"is_staff\" => t.is_staff,\n        \"is_superuser\" => t.is_superuser\n      }\n\n      conn = Boilerplate.Accounts.sign_in_user(conn, t)\n      conn = get(conn, user_path(conn, :show, t.id, %{\"username\" => \"admin\"}))\n      assert user = json_response(conn, 200)[\"data\"]\n      is_the_same_users(user, admin)\n    end\n\n    test \"list should not be showed for unauthorized user\", %{conn: conn} do\n      conn = get(conn, user_path(conn, :show, 1, %{\"username\" => \"admin\"}))\n      assert json_response(conn, 401)[\"errors\"]\n    end\n  end\n\n  describe \"create user\" do\n    test \"renders user when data is valid\", %{conn: conn} do\n      conn = post(conn, user_path(conn, :create), @create_attrs)\n      assert %{\"id\" => id} = json_response(conn, 201)[\"data\"]\n\n      conn = get(conn, user_path(conn, :show, id, %{\"username\" => @create_attrs.username}))\n      assert data = json_response(conn, 200)[\"data\"]\n\n      assert Map.drop(data, [\"last_login\"]) == %{\n               \"id\" => id,\n               \"name\" => @create_attrs.name,\n               \"username\" => @create_attrs.username\n             }\n    end\n\n    test \"renders errors when data is invalid\", %{conn: conn} do\n      conn = post(conn, user_path(conn, :create), @invalid_attrs)\n      assert json_response(conn, 422)[\"errors\"] != %{}\n    end\n  end\n\n  describe \"update user\" do\n    setup [:create_user]\n\n    test \"renders user when data is valid and users are the same\", %{\n      conn: conn,\n      user: %User{id: id} = user\n    } do\n      conn = Boilerplate.Accounts.sign_in_user(conn, user)\n      new_conn = put(conn, user_path(conn, :update, user), user: @update_attrs)\n      assert %{\"id\" => ^id} = json_response(new_conn, 200)[\"data\"]\n\n      conn = get(conn, user_path(conn, :show, id, %{\"username\" => @update_attrs.username}))\n      assert data = json_response(conn, 200)[\"data\"]\n\n      assert Map.drop(data, [\"last_login\"]) == %{\n               \"id\" => id,\n               \"name\" => @update_attrs.name,\n               \"username\" => @update_attrs.username\n             }\n\n      # \"email\" => @update_attrs.email,\n    end\n\n    test \"renders user when data is valid and admin is changing\", %{\n      conn: conn,\n      user: %User{id: id} = user\n    } do\n      admin = Accounts.get_user_by_username(\"admin\")\n      conn = Boilerplate.Accounts.sign_in_user(conn, admin)\n      new_conn = put(conn, user_path(conn, :update, user), user: @update_attrs)\n      assert %{\"id\" => ^id} = json_response(new_conn, 200)[\"data\"]\n\n      conn = get(conn, user_path(conn, :show, id, %{\"username\" => @update_attrs.username}))\n      assert data = json_response(conn, 200)[\"data\"]\n\n      assert Map.drop(data, [\"last_login\"]) == %{\n               \"id\" => id,\n               \"name\" => @update_attrs.name,\n               \"username\" => @update_attrs.username,\n               \"email\" => @update_attrs.email,\n               \"is_staff\" => false,\n               \"is_superuser\" => false\n             }\n    end\n\n    test \"not renders user when data is valid and users are not the same\", %{\n      conn: conn,\n      user: %User{id: id} = user\n    } do\n      {:ok, %User{} = user2} = Accounts.create_user(@create_attrs2)\n      conn = Boilerplate.Accounts.sign_in_user(conn, user2)\n      new_conn = put(conn, user_path(conn, :update, user), user: @update_attrs)\n      assert json_response(new_conn, 403)\n\n      conn = get(conn, user_path(conn, :show, id, %{\"username\" => @create_attrs.username}))\n      assert data = json_response(conn, 200)[\"data\"]\n\n      assert Map.drop(data, [\"last_login\"]) == %{\n               \"id\" => id,\n               \"name\" => @create_attrs.name,\n               \"username\" => @create_attrs.username\n             }\n\n      # \"email\" => @update_attrs.email,\n    end\n\n    test \"not renders user when data is valid and user are not authorised\", %{\n      conn: conn,\n      user: %User{id: id} = user\n    } do\n      new_conn = put(conn, user_path(conn, :update, user), user: @update_attrs)\n      assert json_response(new_conn, 401)[\"errors\"]\n\n      conn = Boilerplate.Accounts.sign_in_user(conn, user)\n      conn = get(conn, user_path(conn, :show, id, %{\"username\" => @create_attrs.username}))\n      assert data = json_response(conn, 200)[\"data\"]\n\n      assert Map.drop(data, [\"last_login\"]) == %{\n               \"id\" => id,\n               \"name\" => @create_attrs.name,\n               \"username\" => @create_attrs.username\n             }\n\n      # \"email\" => @update_attrs.email,\n    end\n\n    test \"renders errors when data is invalid\", %{conn: conn, user: user} do\n      conn = Boilerplate.Accounts.sign_in_user(conn, user)\n      conn = put(conn, user_path(conn, :update, user), user: @invalid_attrs)\n      assert json_response(conn, 422)[\"errors\"] != %{}\n    end\n  end\n\n  describe \"delete user\" do\n    setup [:create_user]\n\n    test \"deletes chosen user when users are the same\", %{conn: conn, user: user} do\n      new_conn = Boilerplate.Accounts.sign_in_user(conn, user)\n      new_conn = delete(new_conn, user_path(new_conn, :delete, user.id))\n      assert response(new_conn, 204)\n\n      admin = Accounts.get_user_by_username(\"admin\")\n      conn = Boilerplate.Accounts.sign_in_user(conn, admin)\n      conn = get(conn, user_path(conn, :show, user.id, %{\"username\" => user.username}))\n      assert response(conn, 404)\n    end\n\n    test \"deletes chosen user when admin is deleting\", %{conn: conn, user: user} do\n      admin = Accounts.get_user_by_username(\"admin\")\n      new_conn = Boilerplate.Accounts.sign_in_user(conn, admin)\n      new_conn = delete(new_conn, user_path(new_conn, :delete, user.id))\n      assert response(new_conn, 204)\n\n      conn = Boilerplate.Accounts.sign_in_user(conn, admin)\n      conn = get(conn, user_path(conn, :show, user.id, %{\"username\" => user.username}))\n      assert response(conn, 404)\n    end\n\n    test \"not deletes chosen user when users are not the same\", %{conn: conn, user: user} do\n      {:ok, %User{} = user2} = Accounts.create_user(@create_attrs2)\n      new_conn = Boilerplate.Accounts.sign_in_user(conn, user2)\n      new_conn = delete(new_conn, user_path(new_conn, :delete, user.id))\n      assert response(new_conn, 403)\n\n      admin = Accounts.get_user_by_username(\"admin\")\n      conn = Boilerplate.Accounts.sign_in_user(conn, admin)\n      conn = get(conn, user_path(conn, :show, user.id, %{\"username\" => user.username}))\n      assert response(conn, 200)\n    end\n\n    test \"not deletes chosen user when user are not authorised\", %{conn: conn, user: user} do\n      new_conn = delete(conn, user_path(conn, :delete, user.id))\n      assert json_response(new_conn, 401)[\"errors\"]\n\n      admin = Accounts.get_user_by_username(\"admin\")\n      conn = Boilerplate.Accounts.sign_in_user(conn, admin)\n      conn = get(conn, user_path(conn, :show, user.id, %{\"username\" => user.username}))\n      assert response(conn, 200)\n    end\n  end\n\n  defp create_user(_) do\n    user = fixture(:user)\n    {:ok, user: user}\n  end\nend\n"
  },
  {
    "path": "test/boilerplate_web/views/error_view_test.exs",
    "content": "defmodule BoilerplateWeb.ErrorViewTest do\n  use BoilerplateWeb.ConnCase, async: true\n\n  # Bring render/3 and render_to_string/3 for testing custom views\n  import Phoenix.View\n\n  test \"renders 404.html\" do\n    assert render_to_string(BoilerplateWeb.ErrorView, \"404.html\", []) == \"Page not found\"\n  end\n\n  test \"renders 500.html\" do\n    assert render_to_string(BoilerplateWeb.ErrorView, \"500.html\", []) == \"Internal server error\"\n  end\n\n  test \"render any other\" do\n    assert render_to_string(BoilerplateWeb.ErrorView, \"505.html\", []) == \"Internal server error\"\n  end\nend\n"
  },
  {
    "path": "test/boilerplate_web/views/layout_view_test.exs",
    "content": "defmodule BoilerplateWeb.LayoutViewTest do\n  use BoilerplateWeb.ConnCase, async: true\nend\n"
  },
  {
    "path": "test/boilerplate_web/views/page_view_test.exs",
    "content": "defmodule BoilerplateWeb.PageViewTest do\n  use BoilerplateWeb.ConnCase, async: true\nend\n"
  },
  {
    "path": "test/support/channel_case.ex",
    "content": "defmodule BoilerplateWeb.ChannelCase do\n  @moduledoc \"\"\"\n  This module defines the test case to be used by\n  channel tests.\n\n  Such tests rely on `Phoenix.ChannelTest` and also\n  import other functionality to make it easier\n  to build common datastructures and query the data layer.\n\n  Finally, if the test case interacts with the database,\n  it cannot be async. For this reason, every test runs\n  inside a transaction which is reset at the beginning\n  of the test unless the test case is marked as async.\n  \"\"\"\n\n  use ExUnit.CaseTemplate\n\n  using do\n    quote do\n      # Import conveniences for testing with channels\n      use Phoenix.ChannelTest\n\n      # The default endpoint for testing\n      @endpoint BoilerplateWeb.Endpoint\n    end\n  end\n\n  setup tags do\n    :ok = Ecto.Adapters.SQL.Sandbox.checkout(Boilerplate.Repo)\n\n    unless tags[:async] do\n      Ecto.Adapters.SQL.Sandbox.mode(Boilerplate.Repo, {:shared, self()})\n    end\n\n    :ok\n  end\nend\n"
  },
  {
    "path": "test/support/conn_case.ex",
    "content": "defmodule BoilerplateWeb.ConnCase do\n  @moduledoc \"\"\"\n  This module defines the test case to be used by\n  tests that require setting up a connection.\n\n  Such tests rely on `Phoenix.ConnTest` and also\n  import other functionality to make it easier\n  to build common datastructures and query the data layer.\n\n  Finally, if the test case interacts with the database,\n  it cannot be async. For this reason, every test runs\n  inside a transaction which is reset at the beginning\n  of the test unless the test case is marked as async.\n  \"\"\"\n\n  use ExUnit.CaseTemplate\n\n  using do\n    quote do\n      # Import conveniences for testing with connections\n      use Phoenix.ConnTest\n      import BoilerplateWeb.Router.Helpers\n\n      # The default endpoint for testing\n      @endpoint BoilerplateWeb.Endpoint\n    end\n  end\n\n  setup tags do\n    :ok = Ecto.Adapters.SQL.Sandbox.checkout(Boilerplate.Repo)\n\n    unless tags[:async] do\n      Ecto.Adapters.SQL.Sandbox.mode(Boilerplate.Repo, {:shared, self()})\n    end\n\n    {:ok, conn: Phoenix.ConnTest.build_conn()}\n  end\nend\n"
  },
  {
    "path": "test/support/data_case.ex",
    "content": "defmodule Boilerplate.DataCase do\n  @moduledoc \"\"\"\n  This module defines the setup for tests requiring\n  access to the application's data layer.\n\n  You may define functions here to be used as helpers in\n  your tests.\n\n  Finally, if the test case interacts with the database,\n  it cannot be async. For this reason, every test runs\n  inside a transaction which is reset at the beginning\n  of the test unless the test case is marked as async.\n  \"\"\"\n\n  use ExUnit.CaseTemplate\n\n  using do\n    quote do\n      alias Boilerplate.Repo\n\n      import Ecto\n      import Ecto.Changeset\n      import Ecto.Query\n      import Boilerplate.DataCase\n    end\n  end\n\n  setup tags do\n    :ok = Ecto.Adapters.SQL.Sandbox.checkout(Boilerplate.Repo)\n\n    unless tags[:async] do\n      Ecto.Adapters.SQL.Sandbox.mode(Boilerplate.Repo, {:shared, self()})\n    end\n\n    :ok\n  end\n\n  @doc \"\"\"\n  A helper that transform changeset errors to a map of messages.\n\n      assert {:error, changeset} = Accounts.create_user(%{password: \"short\"})\n      assert \"password is too short\" in errors_on(changeset).password\n      assert %{password: [\"password is too short\"]} = errors_on(changeset)\n\n  \"\"\"\n  def errors_on(changeset) do\n    Ecto.Changeset.traverse_errors(changeset, fn {message, opts} ->\n      Enum.reduce(opts, message, fn {key, value}, acc ->\n        String.replace(acc, \"%{#{key}}\", to_string(value))\n      end)\n    end)\n  end\nend\n"
  },
  {
    "path": "test/test_helper.exs",
    "content": "ExUnit.start()\n\nEcto.Adapters.SQL.Sandbox.mode(Boilerplate.Repo, :manual)\n"
  }
]