[
  {
    "path": ".circleci/config.yml",
    "content": "# Javascript Node CircleCI 2.0 configuration file\n#\n# Check https://circleci.com/docs/2.0/language-javascript/ for more details\n#\n\ndefaults: &defaults\n  docker:\n    # Choose the version of Node you want here\n    - image: circleci/node:12.16\n  working_directory: ~/repo\n\nversion: 2\njobs:\n  setup:\n    <<: *defaults\n    steps:\n      - checkout\n      - restore_cache:\n          name: Restore node modules\n          keys:\n            - v1-dependencies-{{ checksum \"package.json\" }}\n            # fallback to using the latest cache if no exact match is found\n            - v1-dependencies-\n      - run:\n          name: Install dependencies\n          command: |\n            yarn install\n      - save_cache:\n          name: Save node modules\n          paths:\n            - node_modules\n          key: v1-dependencies-{{ checksum \"package.json\" }}\n\n  tests:\n    <<: *defaults\n    steps:\n      - checkout\n      - restore_cache:\n          name: Restore node modules\n          keys:\n            - v1-dependencies-{{ checksum \"package.json\" }}\n            # fallback to using the latest cache if no exact match is found\n            - v1-dependencies-\n      - run:\n          name: Run tests\n          command: yarn ci:test # this command will be added to/found in your package.json scripts\n\n  publish:\n    <<: *defaults\n    steps:\n      - checkout\n      - run: echo \"//registry.npmjs.org/:_authToken=$NPM_TOKEN\" >> ~/.npmrc\n      - restore_cache:\n          name: Restore node modules\n          keys:\n            - v1-dependencies-{{ checksum \"package.json\" }}\n            # fallback to using the latest cache if no exact match is found\n            - v1-dependencies-\n      # Run semantic-release after all the above is set.\n      - run:\n          name: Publish to NPM\n          command: yarn ci:publish # this will be added to your package.json scripts\n\nworkflows:\n  version: 2\n  test_and_release:\n    jobs:\n      - setup\n      - tests:\n          requires:\n            - setup\n      - publish:\n          requires:\n            - tests\n          filters:\n            branches:\n              only: master\n"
  },
  {
    "path": ".gitignore",
    "content": ".DS_Store\nnpm-debug.log\nnpm-debug.log*\ncoverage\n.nyc_output\nlerna-debug.log\nnode_modules\n.vscode/*\n!.vscode/settings.json\n!.vscode/tasks.json\n!.vscode/launch.json\n!.vscode/extensions.json\ntestgrounds\nIntegrationTest\nintegration_test\n.idea\nyarn-error.log\n.vscode\npackage-lock.json\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2016 Infinite Red, Inc.\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": "boilerplate/.babelrc",
    "content": "{\n  \"presets\": [\"module:metro-react-native-babel-preset\"],\n  \"env\": {\n    \"production\": {\n      \"plugins\": [\"ignite-ignore-reactotron\"]\n    }\n  }\n}\n"
  },
  {
    "path": "boilerplate/.editorconfig",
    "content": "# EditorConfig is awesome: http://EditorConfig.org\n\n# top-most EditorConfig file\nroot = true\n\n# Unix-style newlines with a newline ending every file\n[*]\nend_of_line = lf\ninsert_final_newline = true\nindent_style = space\nindent_size = 2\ncharset = utf-8\ntrim_trailing_whitespace = true\n\n\n[*.gradle]\nindent_size = 4"
  },
  {
    "path": "boilerplate/App/Components/AlertMessage.js",
    "content": "import React, { Component } from 'react'\nimport PropTypes from 'prop-types'\nimport { View, Text } from 'react-native'\nimport styles from './Styles/AlertMessageStyles'\n\nexport default class AlertMessage extends Component {\n  static defaultProps = { show: true }\n\n  static propTypes = {\n    title: PropTypes.string,\n    icon: PropTypes.string,\n    style: PropTypes.object,\n    show: PropTypes.bool\n  }\n\n  render () {\n    let messageComponent = null\n    if (this.props.show) {\n      const { title } = this.props\n      return (\n        <View\n          style={[styles.container, this.props.style]}\n        >\n          <View style={styles.contentContainer}>\n            <Text allowFontScaling={false} style={styles.message}>{title && title.toUpperCase()}</Text>\n          </View>\n        </View>\n      )\n    }\n\n    return messageComponent\n  }\n}\n"
  },
  {
    "path": "boilerplate/App/Components/AlertMessage.story.js",
    "content": "import React from 'react'\nimport { storiesOf } from '@storybook/react-native'\n\nimport AlertMessage from './AlertMessage'\n\nstoriesOf('AlertMessage')\n  .add('Default', () => (\n    <AlertMessage\n      title='ALERT ALERT'\n    />\n  ))\n  .add('Hidden', () => (\n    <AlertMessage\n      title='ALERT ALERT'\n      show={false}\n    />\n  ))\n  .add('Custom Style', () => (\n    <AlertMessage\n      title='ALERT ALERT'\n      style={{ backgroundColor: 'red' }}\n    />\n  ))\n"
  },
  {
    "path": "boilerplate/App/Components/DrawerButton.js",
    "content": "import React, { Component } from 'react'\nimport PropTypes from 'prop-types'\nimport { Text, TouchableOpacity } from 'react-native'\nimport styles from './Styles/DrawerButtonStyles'\nimport ExamplesRegistry from '../Services/ExamplesRegistry'\n\n// Note that this file (App/Components/DrawerButton) needs to be\n// imported in your app somewhere, otherwise your component won't be\n// compiled and added to the examples dev screen.\n\n// Ignore in coverage report\n/* istanbul ignore next */\nExamplesRegistry.addComponentExample('Drawer Button', () =>\n  <DrawerButton\n    text='Example left drawer button'\n    onPress={() => window.alert('Your drawers are showing')}\n  />\n)\n\nclass DrawerButton extends Component {\n  static propTypes = {\n    text: PropTypes.string,\n    onPress: PropTypes.func\n  }\n\n  render () {\n    return (\n      <TouchableOpacity onPress={this.props.onPress}>\n        <Text style={styles.text}>{this.props.text}</Text>\n      </TouchableOpacity>\n    )\n  }\n}\n\nexport default DrawerButton\n"
  },
  {
    "path": "boilerplate/App/Components/DrawerButton.story.js",
    "content": "import React from 'react'\nimport { View } from 'react-native'\nimport { storiesOf } from '@storybook/react-native'\n\nimport DrawerButton from './DrawerButton'\n\nstoriesOf('DrawerButton')\n  .add('Default', () => (\n    <View style={{ backgroundColor: 'black' }}>\n      <DrawerButton\n        text='Drawer Button'\n        onPress={() => { }}\n      />\n    </View>\n  ))\n"
  },
  {
    "path": "boilerplate/App/Components/FullButton.js",
    "content": "import React, { Component } from 'react'\nimport PropTypes from 'prop-types'\nimport { TouchableOpacity, Text } from 'react-native'\nimport styles from './Styles/FullButtonStyles'\nimport ExamplesRegistry from '../Services/ExamplesRegistry'\n\n// Note that this file (App/Components/FullButton) needs to be\n// imported in your app somewhere, otherwise your component won't be\n// compiled and added to the examples dev screen.\n\n// Ignore in coverage report\n/* istanbul ignore next */\nExamplesRegistry.addComponentExample('Full Button', () =>\n  <FullButton\n    text='Hey there'\n    onPress={() => window.alert('Full Button Pressed!')}\n  />\n)\n\nexport default class FullButton extends Component {\n  static propTypes = {\n    text: PropTypes.string,\n    onPress: PropTypes.func,\n    styles: PropTypes.object\n  }\n\n  render () {\n    return (\n      <TouchableOpacity style={[styles.button, this.props.styles]} onPress={this.props.onPress}>\n        <Text style={styles.buttonText}>{this.props.text && this.props.text.toUpperCase()}</Text>\n      </TouchableOpacity>\n    )\n  }\n}\n"
  },
  {
    "path": "boilerplate/App/Components/FullButton.story.js",
    "content": "import React from 'react'\nimport { storiesOf } from '@storybook/react-native'\n\nimport FullButton from './FullButton'\n\nstoriesOf('FullButton')\n  .add('Default', () => (\n    <FullButton\n      text='A simple button'\n    />\n  ))\n  .add('Custom Style', () => (\n    <FullButton\n      text='Style Me Up!'\n      styles={{ backgroundColor: 'blue' }}\n    />\n  ))\n"
  },
  {
    "path": "boilerplate/App/Components/README.md",
    "content": "### Components Folder\nAll components are stored and organized here\n"
  },
  {
    "path": "boilerplate/App/Components/RoundedButton.js",
    "content": "import React, { Component } from 'react'\nimport PropTypes from 'prop-types'\nimport { TouchableOpacity, Text } from 'react-native'\nimport styles from './Styles/RoundedButtonStyles'\nimport ExamplesRegistry from '../Services/ExamplesRegistry'\n\n// Note that this file (App/Components/RoundedButton) needs to be\n// imported in your app somewhere, otherwise your component won't be\n// compiled and added to the examples dev screen.\n\n// Ignore in coverage report\n/* istanbul ignore next */\nExamplesRegistry.addComponentExample('Rounded Button', () =>\n  <RoundedButton\n    text='real buttons have curves'\n    onPress={() => window.alert('Rounded Button Pressed!')}\n  />\n)\n\nexport default class RoundedButton extends Component {\n  static propTypes = {\n    onPress: PropTypes.func,\n    text: PropTypes.string,\n    children: PropTypes.string,\n    navigator: PropTypes.object\n  }\n\n  getText () {\n    const buttonText = this.props.text || this.props.children || ''\n    return buttonText.toUpperCase()\n  }\n\n  render () {\n    return (\n      <TouchableOpacity style={styles.button} onPress={this.props.onPress}>\n        <Text style={styles.buttonText}>{this.getText()}</Text>\n      </TouchableOpacity>\n    )\n  }\n}\n"
  },
  {
    "path": "boilerplate/App/Components/RoundedButton.story.js",
    "content": "import React from 'react'\nimport { storiesOf } from '@storybook/react-native'\n\nimport RoundedButton from './RoundedButton'\n\nstoriesOf('RoundedButton')\n  .add('Default', () => (\n    <RoundedButton\n      text='A simple rounded button'\n    />\n  ))\n  .add('Text as children', () => (\n    <RoundedButton>\n        Hello from the children!\n    </RoundedButton>\n  ))\n"
  },
  {
    "path": "boilerplate/App/Components/Stories.js",
    "content": "import './AlertMessage.story'\nimport './DrawerButton.story'\nimport './FullButton.story'\nimport './RoundedButton.story'\n"
  },
  {
    "path": "boilerplate/App/Components/Styles/AlertMessageStyles.js",
    "content": "import { StyleSheet } from 'react-native'\nimport { Colors, Metrics, Fonts } from '../../Themes/'\n\nexport default StyleSheet.create({\n  container: {\n    justifyContent: 'center',\n    marginVertical: Metrics.section\n  },\n  contentContainer: {\n    alignSelf: 'center',\n    alignItems: 'center'\n  },\n  message: {\n    marginTop: Metrics.baseMargin,\n    marginHorizontal: Metrics.baseMargin,\n    textAlign: 'center',\n    fontFamily: Fonts.type.base,\n    fontSize: Fonts.size.regular,\n    fontWeight: 'bold',\n    color: Colors.steel\n  },\n  icon: {\n    color: Colors.steel\n  }\n})\n"
  },
  {
    "path": "boilerplate/App/Components/Styles/DrawerButtonStyles.js",
    "content": "import { Metrics, Colors, Fonts } from '../../Themes'\n\nexport default {\n  text: {\n    ...Fonts.style.h5,\n    color: Colors.snow,\n    marginVertical: Metrics.baseMargin\n  }\n}\n"
  },
  {
    "path": "boilerplate/App/Components/Styles/FullButtonStyles.js",
    "content": "import { StyleSheet } from 'react-native'\nimport { Fonts, Colors } from '../../Themes/'\n\nexport default StyleSheet.create({\n  button: {\n    marginVertical: 5,\n    borderTopColor: Colors.fire,\n    borderBottomColor: Colors.bloodOrange,\n    borderTopWidth: 1,\n    borderBottomWidth: 1,\n    backgroundColor: Colors.ember\n  },\n  buttonText: {\n    margin: 18,\n    textAlign: 'center',\n    color: Colors.snow,\n    fontSize: Fonts.size.medium,\n    fontFamily: Fonts.type.bold\n  }\n})\n"
  },
  {
    "path": "boilerplate/App/Components/Styles/README.md",
    "content": "### Styles Folder\nComponent styles are separated from functionality.\n"
  },
  {
    "path": "boilerplate/App/Components/Styles/RoundedButtonStyles.js",
    "content": "import { StyleSheet } from 'react-native'\nimport { Fonts, Colors, Metrics } from '../../Themes/'\n\nexport default StyleSheet.create({\n  button: {\n    height: 45,\n    borderRadius: 5,\n    marginHorizontal: Metrics.section,\n    marginVertical: Metrics.baseMargin,\n    backgroundColor: Colors.fire,\n    justifyContent: 'center'\n  },\n  buttonText: {\n    color: Colors.snow,\n    textAlign: 'center',\n    fontWeight: 'bold',\n    fontSize: Fonts.size.medium,\n    marginVertical: Metrics.baseMargin\n  }\n})\n"
  },
  {
    "path": "boilerplate/App/Config/AppConfig.js",
    "content": "// Simple React Native specific changes\n\nexport default {\n  // font scaling override - RN default is on\n  allowTextFontScaling: true\n}\n"
  },
  {
    "path": "boilerplate/App/Config/DebugConfig.js",
    "content": "export default {\n  useFixtures: false,\n  ezLogin: false,\n  yellowBox: __DEV__,\n  reduxLogging: __DEV__,\n  includeExamples: __DEV__,\n  useReactotron: __DEV__\n}\n"
  },
  {
    "path": "boilerplate/App/Config/README.md",
    "content": "### Config Folder\nAll application specific configuration falls in this folder.\n\n`AppConfig.js` - production values.\n`DebugConfig.js` - development-wide globals.\n`ReactotronConfig.js` - Reactotron client settings.\n`ReduxPersist.js` - rehydrate Redux state.\n"
  },
  {
    "path": "boilerplate/App/Config/ReactotronConfig.js",
    "content": "import Config from '../Config/DebugConfig'\nimport Immutable from 'seamless-immutable'\nimport Reactotron from 'reactotron-react-native'\nimport { reactotronRedux as reduxPlugin } from 'reactotron-redux'\nimport sagaPlugin from 'reactotron-redux-saga'\n\nconst reactotron = Reactotron\n    .configure({ name: 'Ignite App' })\n    .useReactNative()\n    .use(reduxPlugin({ onRestore: Immutable }))\n    .use(sagaPlugin())\n\nif (Config.useReactotron) {\n  // https://github.com/infinitered/reactotron for more options!\n\n  reactotron.connect()\n\n  // Let's clear Reactotron on every time we load the app\n  reactotron.clear()\n\n  // Totally hacky, but this allows you to not both importing reactotron-react-native\n  // on every file.  This is just DEV mode, so no big deal.\n}\nexport default reactotron\nconsole.tron = reactotron\n"
  },
  {
    "path": "boilerplate/App/Config/index.js",
    "content": "import DebugConfig from './DebugConfig'\nimport AppConfig from './AppConfig' // eslint-disable-line no-unused-vars\n\nif (__DEV__) {\n  // If ReactNative's yellow box warnings are too much, it is possible to turn\n  // it off, but the healthier approach is to fix the warnings.  =)\n  console.disableYellowBox = !DebugConfig.yellowBox\n}\n"
  },
  {
    "path": "boilerplate/App/Containers/App.js",
    "content": "import '../Config'\nimport DebugConfig from '../Config/DebugConfig'\nimport React, { Component } from 'react'\nimport { Provider } from 'react-redux'\nimport RootContainer from './RootContainer'\nimport createStore from '../Redux'\n\n// create our store\nconst store = createStore()\n\n/**\n * Provides an entry point into our application.  Both index.ios.js and index.android.js\n * call this component first.\n *\n * We create our Redux store here, put it into a provider and then bring in our\n * RootContainer.\n *\n * We separate like this to play nice with React Native's hot reloading.\n */\nclass App extends Component {\n  render () {\n    return (\n      <Provider store={store}>\n        <RootContainer />\n      </Provider>\n    )\n  }\n}\n\n// allow reactotron overlay for fast design in dev mode\nexport default DebugConfig.useReactotron\n  ? console.tron.overlay(App)\n  : App\n"
  },
  {
    "path": "boilerplate/App/Containers/LaunchScreen.js",
    "content": "import React, { Component } from 'react'\nimport { ScrollView, Text, Image, View } from 'react-native'\nimport { Images } from '../Themes'\n\n// Styles\nimport styles from './Styles/LaunchScreenStyles'\n\nexport default class LaunchScreen extends Component {\n  render () {\n    return (\n      <View style={styles.mainContainer}>\n        <Image source={Images.background} style={styles.backgroundImage} resizeMode='stretch' />\n        <ScrollView style={styles.container}>\n          <View style={styles.centered}>\n            <Image source={Images.launch} style={styles.logo} />\n          </View>\n\n          <View style={styles.section} >\n            <Image source={Images.ready} />\n            <Text style={styles.sectionText}>\n              This probably isn't what your app is going to look like. Unless your designer handed you this screen and, in that case, congrats! You're ready to ship. For everyone else, this is where you'll see a live preview of your fully functioning app using Ignite.\n            </Text>\n          </View>\n\n        </ScrollView>\n      </View>\n    )\n  }\n}\n"
  },
  {
    "path": "boilerplate/App/Containers/README.md",
    "content": "### Containers Folder\nA container is what they call a \"Smart Component\" in Redux.  It is a component\nwhich knows about Redux.  They are usually used as \"Screens\".\n\nAlso located in here are 2 special containers: `App.js` and `RootContainer.js`.\n\n`App.js` is first component loaded after `index.ios.js` or `index.android.js`.  The purpose of this file is to setup Redux or any other non-visual \"global\" modules.  Having Redux setup here helps with the hot-reloading process in React Native during development as it won't try to reload your sagas and reducers should your colors change (for example).\n\n`RootContainer.js` is the first visual component in the app.  It is the ancestor of all other screens and components.\n\nYou'll probably find you'll have great mileage in Ignite apps without even touching these 2 files.  They, of course, belong to you, so when you're ready to add something non-visual like Firebase or something visual like an overlay, you have spots to place these additions.\n"
  },
  {
    "path": "boilerplate/App/Containers/RootContainer.js",
    "content": "import React, { Component } from 'react'\nimport { View, StatusBar } from 'react-native'\nimport ReduxNavigation from '../Navigation/ReduxNavigation'\nimport { connect } from 'react-redux'\nimport StartupActions from '../Redux/StartupRedux'\n\n// Styles\nimport styles from './Styles/RootContainerStyles'\n\nclass RootContainer extends Component {\n  componentDidMount () {\n    this.props.startup()\n  }\n\n  render () {\n    return (\n      <View style={styles.applicationView}>\n        <StatusBar barStyle='light-content' />\n        <ReduxNavigation />\n      </View>\n    )\n  }\n}\n\n// wraps dispatch to create nicer functions to call within our component\nconst mapDispatchToProps = (dispatch) => ({\n  startup: () => dispatch(StartupActions.startup())\n})\n\nexport default connect(null, mapDispatchToProps)(RootContainer)\n"
  },
  {
    "path": "boilerplate/App/Containers/Styles/LaunchScreenStyles.js",
    "content": "import { StyleSheet } from 'react-native'\nimport { Metrics, ApplicationStyles } from '../../Themes/'\n\nexport default StyleSheet.create({\n  ...ApplicationStyles.screen,\n  container: {\n    paddingBottom: Metrics.baseMargin\n  },\n  logo: {\n    marginTop: Metrics.doubleSection,\n    height: Metrics.images.logo,\n    width: Metrics.images.logo,\n    resizeMode: 'contain'\n  },\n  centered: {\n    alignItems: 'center'\n  }\n})\n"
  },
  {
    "path": "boilerplate/App/Containers/Styles/README.md",
    "content": "### Styles Folder\nContainer styles are separated from functionality.\n"
  },
  {
    "path": "boilerplate/App/Containers/Styles/RootContainerStyles.js",
    "content": "import {StyleSheet} from 'react-native'\nimport {Fonts, Metrics, Colors} from '../../Themes/'\n\nexport default StyleSheet.create({\n  applicationView: {\n    flex: 1\n  },\n  container: {\n    flex: 1,\n    justifyContent: 'center',\n    backgroundColor: Colors.background\n  },\n  welcome: {\n    fontSize: 20,\n    textAlign: 'center',\n    fontFamily: Fonts.type.base,\n    margin: Metrics.baseMargin\n  },\n  myImage: {\n    width: 200,\n    height: 200,\n    alignSelf: 'center'\n  }\n})\n"
  },
  {
    "path": "boilerplate/App/Fixtures/README.md",
    "content": "### Fixtures folder\nAll key API responses are housed here.\n\nThese API responses can be used for several reasons.  _E.G._:\n* To bypass logins when building any screen of the application\n* To quickly test API parsing in unit tests\n* To separate Network from Data concerns while coding\n"
  },
  {
    "path": "boilerplate/App/Fixtures/gantman.json",
    "content": "{\n  \"total_count\": 7,\n  \"incomplete_results\": false,\n  \"items\": [\n    {\n      \"login\": \"GantMan\",\n      \"id\": 997157,\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/997157?v=3\",\n      \"gravatar_id\": \"\",\n      \"url\": \"https://api.github.com/users/GantMan\",\n      \"html_url\": \"https://github.com/GantMan\",\n      \"followers_url\": \"https://api.github.com/users/GantMan/followers\",\n      \"following_url\": \"https://api.github.com/users/GantMan/following{/other_user}\",\n      \"gists_url\": \"https://api.github.com/users/GantMan/gists{/gist_id}\",\n      \"starred_url\": \"https://api.github.com/users/GantMan/starred{/owner}{/repo}\",\n      \"subscriptions_url\": \"https://api.github.com/users/GantMan/subscriptions\",\n      \"organizations_url\": \"https://api.github.com/users/GantMan/orgs\",\n      \"repos_url\": \"https://api.github.com/users/GantMan/repos\",\n      \"events_url\": \"https://api.github.com/users/GantMan/events{/privacy}\",\n      \"received_events_url\": \"https://api.github.com/users/GantMan/received_events\",\n      \"type\": \"User\",\n      \"site_admin\": false,\n      \"score\": 122.12115\n    },\n    {\n      \"login\": \"vlad-G\",\n      \"id\": 13520880,\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/13520880?v=3\",\n      \"gravatar_id\": \"\",\n      \"url\": \"https://api.github.com/users/vlad-G\",\n      \"html_url\": \"https://github.com/vlad-G\",\n      \"followers_url\": \"https://api.github.com/users/vlad-G/followers\",\n      \"following_url\": \"https://api.github.com/users/vlad-G/following{/other_user}\",\n      \"gists_url\": \"https://api.github.com/users/vlad-G/gists{/gist_id}\",\n      \"starred_url\": \"https://api.github.com/users/vlad-G/starred{/owner}{/repo}\",\n      \"subscriptions_url\": \"https://api.github.com/users/vlad-G/subscriptions\",\n      \"organizations_url\": \"https://api.github.com/users/vlad-G/orgs\",\n      \"repos_url\": \"https://api.github.com/users/vlad-G/repos\",\n      \"events_url\": \"https://api.github.com/users/vlad-G/events{/privacy}\",\n      \"received_events_url\": \"https://api.github.com/users/vlad-G/received_events\",\n      \"type\": \"User\",\n      \"site_admin\": false,\n      \"score\": 12.69848\n    },\n    {\n      \"login\": \"gantmani\",\n      \"id\": 3034094,\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/3034094?v=3\",\n      \"gravatar_id\": \"\",\n      \"url\": \"https://api.github.com/users/gantmani\",\n      \"html_url\": \"https://github.com/gantmani\",\n      \"followers_url\": \"https://api.github.com/users/gantmani/followers\",\n      \"following_url\": \"https://api.github.com/users/gantmani/following{/other_user}\",\n      \"gists_url\": \"https://api.github.com/users/gantmani/gists{/gist_id}\",\n      \"starred_url\": \"https://api.github.com/users/gantmani/starred{/owner}{/repo}\",\n      \"subscriptions_url\": \"https://api.github.com/users/gantmani/subscriptions\",\n      \"organizations_url\": \"https://api.github.com/users/gantmani/orgs\",\n      \"repos_url\": \"https://api.github.com/users/gantmani/repos\",\n      \"events_url\": \"https://api.github.com/users/gantmani/events{/privacy}\",\n      \"received_events_url\": \"https://api.github.com/users/gantmani/received_events\",\n      \"type\": \"User\",\n      \"site_admin\": false,\n      \"score\": 11.641713\n    },\n    {\n      \"login\": \"sgantman\",\n      \"id\": 5911526,\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/5911526?v=3\",\n      \"gravatar_id\": \"\",\n      \"url\": \"https://api.github.com/users/sgantman\",\n      \"html_url\": \"https://github.com/sgantman\",\n      \"followers_url\": \"https://api.github.com/users/sgantman/followers\",\n      \"following_url\": \"https://api.github.com/users/sgantman/following{/other_user}\",\n      \"gists_url\": \"https://api.github.com/users/sgantman/gists{/gist_id}\",\n      \"starred_url\": \"https://api.github.com/users/sgantman/starred{/owner}{/repo}\",\n      \"subscriptions_url\": \"https://api.github.com/users/sgantman/subscriptions\",\n      \"organizations_url\": \"https://api.github.com/users/sgantman/orgs\",\n      \"repos_url\": \"https://api.github.com/users/sgantman/repos\",\n      \"events_url\": \"https://api.github.com/users/sgantman/events{/privacy}\",\n      \"received_events_url\": \"https://api.github.com/users/sgantman/received_events\",\n      \"type\": \"User\",\n      \"site_admin\": false,\n      \"score\": 7.926345\n    },\n    {\n      \"login\": \"michaelgantman\",\n      \"id\": 16693070,\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/16693070?v=3\",\n      \"gravatar_id\": \"\",\n      \"url\": \"https://api.github.com/users/michaelgantman\",\n      \"html_url\": \"https://github.com/michaelgantman\",\n      \"followers_url\": \"https://api.github.com/users/michaelgantman/followers\",\n      \"following_url\": \"https://api.github.com/users/michaelgantman/following{/other_user}\",\n      \"gists_url\": \"https://api.github.com/users/michaelgantman/gists{/gist_id}\",\n      \"starred_url\": \"https://api.github.com/users/michaelgantman/starred{/owner}{/repo}\",\n      \"subscriptions_url\": \"https://api.github.com/users/michaelgantman/subscriptions\",\n      \"organizations_url\": \"https://api.github.com/users/michaelgantman/orgs\",\n      \"repos_url\": \"https://api.github.com/users/michaelgantman/repos\",\n      \"events_url\": \"https://api.github.com/users/michaelgantman/events{/privacy}\",\n      \"received_events_url\": \"https://api.github.com/users/michaelgantman/received_events\",\n      \"type\": \"User\",\n      \"site_admin\": false,\n      \"score\": 7.926345\n    },\n    {\n      \"login\": \"gantmanis\",\n      \"id\": 19141249,\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/19141249?v=3\",\n      \"gravatar_id\": \"\",\n      \"url\": \"https://api.github.com/users/gantmanis\",\n      \"html_url\": \"https://github.com/gantmanis\",\n      \"followers_url\": \"https://api.github.com/users/gantmanis/followers\",\n      \"following_url\": \"https://api.github.com/users/gantmanis/following{/other_user}\",\n      \"gists_url\": \"https://api.github.com/users/gantmanis/gists{/gist_id}\",\n      \"starred_url\": \"https://api.github.com/users/gantmanis/starred{/owner}{/repo}\",\n      \"subscriptions_url\": \"https://api.github.com/users/gantmanis/subscriptions\",\n      \"organizations_url\": \"https://api.github.com/users/gantmanis/orgs\",\n      \"repos_url\": \"https://api.github.com/users/gantmanis/repos\",\n      \"events_url\": \"https://api.github.com/users/gantmanis/events{/privacy}\",\n      \"received_events_url\": \"https://api.github.com/users/gantmanis/received_events\",\n      \"type\": \"User\",\n      \"site_admin\": false,\n      \"score\": 7.8813524\n    },\n    {\n      \"login\": \"Gantman2014\",\n      \"id\": 7669410,\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/7669410?v=3\",\n      \"gravatar_id\": \"\",\n      \"url\": \"https://api.github.com/users/Gantman2014\",\n      \"html_url\": \"https://github.com/Gantman2014\",\n      \"followers_url\": \"https://api.github.com/users/Gantman2014/followers\",\n      \"following_url\": \"https://api.github.com/users/Gantman2014/following{/other_user}\",\n      \"gists_url\": \"https://api.github.com/users/Gantman2014/gists{/gist_id}\",\n      \"starred_url\": \"https://api.github.com/users/Gantman2014/starred{/owner}{/repo}\",\n      \"subscriptions_url\": \"https://api.github.com/users/Gantman2014/subscriptions\",\n      \"organizations_url\": \"https://api.github.com/users/Gantman2014/orgs\",\n      \"repos_url\": \"https://api.github.com/users/Gantman2014/repos\",\n      \"events_url\": \"https://api.github.com/users/Gantman2014/events{/privacy}\",\n      \"received_events_url\": \"https://api.github.com/users/Gantman2014/received_events\",\n      \"type\": \"User\",\n      \"site_admin\": false,\n      \"score\": 7.8813524\n    }\n  ]\n}"
  },
  {
    "path": "boilerplate/App/Fixtures/rateLimit.json",
    "content": "{\n  \"resources\": {\n    \"core\": {\n      \"limit\": 60,\n      \"remaining\": 42,\n      \"reset\": 1488126913\n    },\n    \"search\": {\n      \"limit\": 10,\n      \"remaining\": 9,\n      \"reset\": 1488126003\n    }\n  },\n  \"rate\": {\n    \"limit\": 60,\n    \"remaining\": 42,\n    \"reset\": 1488126913\n  }\n}"
  },
  {
    "path": "boilerplate/App/Fixtures/root.json",
    "content": "{\n  \"current_user_url\": \"https://api.github.com/user\",\n  \"current_user_authorizations_html_url\": \"https://github.com/settings/connections/applications{/client_id}\",\n  \"authorizations_url\": \"https://api.github.com/authorizations\",\n  \"code_search_url\": \"https://api.github.com/search/code?q={query}{&page,per_page,sort,order}\",\n  \"commit_search_url\": \"https://api.github.com/search/commits?q={query}{&page,per_page,sort,order}\",\n  \"emails_url\": \"https://api.github.com/user/emails\",\n  \"emojis_url\": \"https://api.github.com/emojis\",\n  \"events_url\": \"https://api.github.com/events\",\n  \"feeds_url\": \"https://api.github.com/feeds\",\n  \"followers_url\": \"https://api.github.com/user/followers\",\n  \"following_url\": \"https://api.github.com/user/following{/target}\",\n  \"gists_url\": \"https://api.github.com/gists{/gist_id}\",\n  \"hub_url\": \"https://api.github.com/hub\",\n  \"issue_search_url\": \"https://api.github.com/search/issues?q={query}{&page,per_page,sort,order}\",\n  \"issues_url\": \"https://api.github.com/issues\",\n  \"keys_url\": \"https://api.github.com/user/keys\",\n  \"notifications_url\": \"https://api.github.com/notifications\",\n  \"organization_repositories_url\": \"https://api.github.com/orgs/{org}/repos{?type,page,per_page,sort}\",\n  \"organization_url\": \"https://api.github.com/orgs/{org}\",\n  \"public_gists_url\": \"https://api.github.com/gists/public\",\n  \"rate_limit_url\": \"https://api.github.com/rate_limit\",\n  \"repository_url\": \"https://api.github.com/repos/{owner}/{repo}\",\n  \"repository_search_url\": \"https://api.github.com/search/repositories?q={query}{&page,per_page,sort,order}\",\n  \"current_user_repositories_url\": \"https://api.github.com/user/repos{?type,page,per_page,sort}\",\n  \"starred_url\": \"https://api.github.com/user/starred{/owner}{/repo}\",\n  \"starred_gists_url\": \"https://api.github.com/gists/starred\",\n  \"team_url\": \"https://api.github.com/teams\",\n  \"user_url\": \"https://api.github.com/users/{user}\",\n  \"user_organizations_url\": \"https://api.github.com/user/orgs\",\n  \"user_repositories_url\": \"https://api.github.com/users/{user}/repos{?type,page,per_page,sort}\",\n  \"user_search_url\": \"https://api.github.com/search/users?q={query}{&page,per_page,sort,order}\"\n}"
  },
  {
    "path": "boilerplate/App/Fixtures/skellock.json",
    "content": "{\n  \"total_count\": 1,\n  \"incomplete_results\": false,\n  \"items\": [\n    {\n      \"login\": \"skellock\",\n      \"id\": 68273,\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/68273?v=3\",\n      \"gravatar_id\": \"\",\n      \"url\": \"https://api.github.com/users/skellock\",\n      \"html_url\": \"https://github.com/skellock\",\n      \"followers_url\": \"https://api.github.com/users/skellock/followers\",\n      \"following_url\": \"https://api.github.com/users/skellock/following{/other_user}\",\n      \"gists_url\": \"https://api.github.com/users/skellock/gists{/gist_id}\",\n      \"starred_url\": \"https://api.github.com/users/skellock/starred{/owner}{/repo}\",\n      \"subscriptions_url\": \"https://api.github.com/users/skellock/subscriptions\",\n      \"organizations_url\": \"https://api.github.com/users/skellock/orgs\",\n      \"repos_url\": \"https://api.github.com/users/skellock/repos\",\n      \"events_url\": \"https://api.github.com/users/skellock/events{/privacy}\",\n      \"received_events_url\": \"https://api.github.com/users/skellock/received_events\",\n      \"type\": \"User\",\n      \"site_admin\": false,\n      \"score\": 107.22611\n    }\n  ]\n}"
  },
  {
    "path": "boilerplate/App/Images/README.md",
    "content": "### Images folder\nHolds all images for the applications."
  },
  {
    "path": "boilerplate/App/Lib/README.md",
    "content": "# Lib\n\nAt first glance, this could appear to be a \"miscellaneous\" folder, but we recommend that you treat this as proving ground for components that could be reusable outside your project.\n\nMaybe you're writing a set of utilities that you could use outside your project, but they're not quite ready or battle tested.  This folder would be a great place to put them.  They ideally be pure functions have no dependencies on other things in your App folder.\n"
  },
  {
    "path": "boilerplate/App/Navigation/AppNavigation.js",
    "content": "import { createAppContainer } from 'react-navigation'\nimport { createStackNavigator } from 'react-navigation-stack';\nimport LaunchScreen from '../Containers/LaunchScreen'\n\nimport styles from './Styles/NavigationStyles'\n\n// Manifest of possible screens\nconst PrimaryNav = createStackNavigator({\n  LaunchScreen: { screen: LaunchScreen }\n}, {\n  // Default config for all screens\n  headerMode: 'none',\n  initialRouteName: 'LaunchScreen',\n  navigationOptions: {\n    headerStyle: styles.header\n  }\n})\n\nexport default createAppContainer(PrimaryNav)\n"
  },
  {
    "path": "boilerplate/App/Navigation/ReduxNavigation.js",
    "content": "import * as React from 'react'\nimport { BackHandler, Platform } from 'react-native'\nimport {\n  createReactNavigationReduxMiddleware,\n  createReduxContainer\n} from 'react-navigation-redux-helpers'\nimport { connect } from 'react-redux'\nimport AppNavigation from './AppNavigation'\n\nexport const appNavigatorMiddleware = createReactNavigationReduxMiddleware(\n  (state) => state.nav,\n  'root'\n)\n\nconst ReduxAppNavigator = createReduxContainer(AppNavigation, 'root')\n\nclass ReduxNavigation extends React.Component {\n  componentDidMount () {\n    if (Platform.OS === 'ios') return\n    BackHandler.addEventListener('hardwareBackPress', () => {\n      const { dispatch, nav } = this.props\n      // change to whatever is your first screen, otherwise unpredictable results may occur\n      if (nav.routes.length === 1 && (nav.routes[0].routeName === 'LaunchScreen')) {\n        return false\n      }\n      // if (shouldCloseApp(nav)) return false\n      dispatch({ type: 'Navigation/BACK' })\n      return true\n    })\n  }\n\n  componentWillUnmount () {\n    if (Platform.OS === 'ios') return\n    BackHandler.removeEventListener('hardwareBackPress', undefined)\n  }\n\n  render () {\n    return <ReduxAppNavigator dispatch={this.props.dispatch} state={this.props.nav} />\n  }\n}\n\nconst mapStateToProps = state => ({\n  nav: state.nav\n})\nexport default connect(mapStateToProps)(ReduxNavigation)\n"
  },
  {
    "path": "boilerplate/App/Navigation/Styles/NavigationStyles.js",
    "content": "import { StyleSheet } from 'react-native'\nimport { Colors } from '../../Themes/'\n\nexport default StyleSheet.create({\n  header: {\n    backgroundColor: Colors.backgroundColor\n  }\n})\n"
  },
  {
    "path": "boilerplate/App/Redux/CreateStore.js",
    "content": "import { createStore, applyMiddleware, compose } from 'redux'\nimport Config from '../Config/DebugConfig'\nimport createSagaMiddleware from 'redux-saga'\nimport ScreenTracking from './ScreenTrackingMiddleware'\nimport { appNavigatorMiddleware } from '../Navigation/ReduxNavigation'\nimport Reactotron from '../Config/ReactotronConfig'\n\n// creates the store\nexport default (rootReducer, rootSaga) => {\n  /* ------------- Redux Configuration ------------- */\n\n  const middleware = []\n  const enhancers = []\n\n  /* ------------- Navigation Middleware ------------ */\n  middleware.push(appNavigatorMiddleware)\n\n  /* ------------- Analytics Middleware ------------- */\n  middleware.push(ScreenTracking)\n\n  /* ------------- Saga Middleware ------------- */\n\n  const sagaMonitor = Config.useReactotron ? console.tron.createSagaMonitor() : null\n  const sagaMiddleware = createSagaMiddleware({ sagaMonitor })\n  middleware.push(sagaMiddleware)\n\n  /* ------------- Assemble Middleware ------------- */\n\n  enhancers.push(applyMiddleware(...middleware))\n\n  // if Reactotron is enabled (default for __DEV__), we'll create the store through Reactotron\n  const createAppropriateStore = createStore\n  if (Config.useReactotron) {\n    enhancers.push(Reactotron.createEnhancer())\n  }\n  const store = createAppropriateStore(rootReducer, compose(...enhancers))\n\n  // kick off root saga\n  let sagasManager = sagaMiddleware.run(rootSaga)\n\n  return {\n    store,\n    sagasManager,\n    sagaMiddleware\n  }\n}\n"
  },
  {
    "path": "boilerplate/App/Redux/GithubRedux.js",
    "content": "import { createReducer, createActions } from 'reduxsauce'\nimport Immutable from 'seamless-immutable'\n\n/* ------------- Types and Action Creators ------------- */\n\nconst { Types, Creators } = createActions({\n  userRequest: ['username'],\n  userSuccess: ['avatar'],\n  userFailure: null\n})\n\nexport const GithubTypes = Types\nexport default Creators\n\n/* ------------- Initial State ------------- */\n\nexport const INITIAL_STATE = Immutable({\n  avatar: null,\n  fetching: null,\n  error: null,\n  username: null\n})\n\n/* ------------- Selectors ------------- */\n\nexport const GithubSelectors = {\n  selectAvatar: state => state.github.avatar\n}\n\n/* ------------- Reducers ------------- */\n\n// request the avatar for a user\nexport const request = (state, { username }) =>\n  state.merge({ fetching: true, username, avatar: null })\n\n// successful avatar lookup\nexport const success = (state, action) => {\n  const { avatar } = action\n  return state.merge({ fetching: false, error: null, avatar })\n}\n\n// failed to get the avatar\nexport const failure = (state) =>\n  state.merge({ fetching: false, error: true, avatar: null })\n\n/* ------------- Hookup Reducers To Types ------------- */\n\nexport const reducer = createReducer(INITIAL_STATE, {\n  [Types.USER_REQUEST]: request,\n  [Types.USER_SUCCESS]: success,\n  [Types.USER_FAILURE]: failure\n})\n"
  },
  {
    "path": "boilerplate/App/Redux/NavigationRedux.js",
    "content": "import AppNavigation from '../Navigation/AppNavigation'\n\nexport const reducer = (state, action) => {\n  const newState = AppNavigation.router.getStateForAction(action, state)\n  return newState || state\n}\n"
  },
  {
    "path": "boilerplate/App/Redux/ScreenTrackingMiddleware.js",
    "content": "import { NavigationActions } from 'react-navigation'\n\n// gets the current screen from navigation state\nconst getCurrentRouteName = (navigationState) => {\n  if (!navigationState) {\n    return null\n  }\n  const route = navigationState.routes[navigationState.index]\n  // dive into nested navigators\n  if (route.routes) {\n    return getCurrentRouteName(route)\n  }\n  return route.routeName\n}\n\nconst screenTracking = ({ getState }) => next => (action) => {\n  if (\n    action.type !== NavigationActions.NAVIGATE &&\n    action.type !== NavigationActions.BACK\n  ) {\n    return next(action)\n  }\n\n  const currentScreen = getCurrentRouteName(getState().nav)\n  const result = next(action)\n  const nextScreen = getCurrentRouteName(getState().nav)\n  if (nextScreen !== currentScreen) {\n    try {\n      __DEV__ && console.tron.log(`NAVIGATING ${currentScreen} to ${nextScreen}`)\n      // Example: Analytics.trackEvent('user_navigation', {currentScreen, nextScreen})\n    } catch (e) {\n      __DEV__ && console.tron.log(e)\n    }\n  }\n  return result\n}\n\nexport default screenTracking\n"
  },
  {
    "path": "boilerplate/App/Redux/SearchRedux.js",
    "content": "import { createReducer, createActions } from 'reduxsauce'\nimport Immutable from 'seamless-immutable'\nimport { filter } from 'ramda'\nimport { startsWith } from 'ramdasauce'\n\nconst LIST_DATA = ['sausage', 'blubber', 'pencil', 'cloud', 'moon', 'water', 'computer', 'school',\n  'network', 'hammer', 'walking', 'violently', 'mediocre', 'literature', 'chair', 'two', 'window',\n  'cords', 'musical', 'zebra', 'xylophone', 'penguin', 'home', 'dog', 'final', 'ink', 'teacher', 'fun',\n  'website', 'banana', 'uncle', 'softly', 'mega', 'ten', 'awesome', 'attatch', 'blue', 'internet', 'bottle',\n  'tight', 'zone', 'tomato', 'prison', 'hydro', 'cleaning', 'telivision', 'send', 'frog', 'cup', 'book',\n  'zooming', 'falling', 'evily', 'gamer', 'lid', 'juice', 'moniter', 'captain', 'bonding', 'loudly', 'thudding',\n  'guitar', 'shaving', 'hair', 'soccer', 'water', 'racket', 'table', 'late', 'media', 'desktop', 'flipper',\n  'club', 'flying', 'smooth', 'monster', 'purple', 'guardian', 'bold', 'hyperlink', 'presentation', 'world', 'national',\n  'comment', 'element', 'magic', 'lion', 'sand', 'crust', 'toast', 'jam', 'hunter', 'forest', 'foraging',\n  'silently', 'tawesomated', 'joshing', 'pong', 'RANDOM', 'WORD'\n]\n\n/* ------------- Types and Action Creators ------------- */\n\nconst { Types, Creators } = createActions({\n  search: ['searchTerm'],\n  cancelSearch: null\n})\n\nexport const TemperatureTypes = Types\nexport default Creators\n\n/* ------------- Initial State ------------- */\n\nexport const INITIAL_STATE = Immutable({\n  searchTerm: '',\n  searching: false,\n  results: LIST_DATA\n})\n\n/* ------------- Reducers ------------- */\n\nexport const performSearch = (state, { searchTerm }) => {\n  const results = filter(startsWith(searchTerm), LIST_DATA)\n  return state.merge({ searching: true, searchTerm, results })\n}\n\nexport const cancelSearch = (state) => INITIAL_STATE\n\n/* ------------- Hookup Reducers To Types ------------- */\n\nexport const reducer = createReducer(INITIAL_STATE, {\n  [Types.SEARCH]: performSearch,\n  [Types.CANCEL_SEARCH]: cancelSearch\n})\n"
  },
  {
    "path": "boilerplate/App/Redux/StartupRedux.js",
    "content": "import { createActions } from 'reduxsauce'\n\n/* ------------- Types and Action Creators ------------- */\n\nconst { Types, Creators } = createActions({\n  startup: null\n})\n\nexport const StartupTypes = Types\nexport default Creators\n"
  },
  {
    "path": "boilerplate/App/Redux/index.js",
    "content": "import { combineReducers } from 'redux'\nimport configureStore from './CreateStore'\nimport rootSaga from '../Sagas/'\n\n/* ------------- Assemble The Reducers ------------- */\nexport const reducers = combineReducers({\n  nav: require('./NavigationRedux').reducer,\n  github: require('./GithubRedux').reducer,\n  search: require('./SearchRedux').reducer\n})\n\nexport default () => {\n  let { store, sagasManager, sagaMiddleware } = configureStore(reducers, rootSaga)\n\n  if (module.hot) {\n    module.hot.accept(() => {\n      const nextRootReducer = require('./').reducers\n      store.replaceReducer(nextRootReducer)\n\n      const newYieldedSagas = require('../Sagas').default\n      sagasManager.cancel()\n      sagasManager.done.then(() => {\n        sagasManager = sagaMiddleware(newYieldedSagas)\n      })\n    })\n  }\n\n  return store\n}\n"
  },
  {
    "path": "boilerplate/App/Sagas/GithubSagas.js",
    "content": "import { call, put } from 'redux-saga/effects'\nimport { path } from 'ramda'\nimport GithubActions from '../Redux/GithubRedux'\n\nexport function * getUserAvatar (api, action) {\n  const { username } = action\n  // make the call to the api\n  const response = yield call(api.getUser, username)\n\n  if (response.ok) {\n    const firstUser = path(['data', 'items'], response)[0]\n    const avatar = firstUser.avatar_url\n    // do data conversion here if needed\n    yield put(GithubActions.userSuccess(avatar))\n  } else {\n    yield put(GithubActions.userFailure())\n  }\n}\n"
  },
  {
    "path": "boilerplate/App/Sagas/StartupSagas.js",
    "content": "import { put, select } from 'redux-saga/effects'\nimport GithubActions, { GithubSelectors } from '../Redux/GithubRedux'\nimport { is } from 'ramda'\n\n// exported to make available for tests\nexport const selectAvatar = GithubSelectors.selectAvatar\n\n// process STARTUP actions\nexport function * startup (action) {\n  if (__DEV__ && console.tron) {\n    // straight-up string logging\n    console.tron.log('Hello, I\\'m an example of how to log via Reactotron.')\n\n    // logging an object for better clarity\n    console.tron.log({\n      message: 'pass objects for better logging',\n      someGeneratorFunction: selectAvatar\n    })\n\n    // fully customized!\n    const subObject = { a: 1, b: [1, 2, 3], c: true }\n    subObject.circularDependency = subObject // osnap!\n    console.tron.display({\n      name: '🔥 IGNITE 🔥',\n      preview: 'You should totally expand this',\n      value: {\n        '💃': 'Welcome to the future!',\n        subObject,\n        someInlineFunction: () => true,\n        someGeneratorFunction: startup,\n        someNormalFunction: selectAvatar\n      }\n    })\n  }\n  const avatar = yield select(selectAvatar)\n  // only get if we don't have it yet\n  if (!is(String, avatar)) {\n    yield put(GithubActions.userRequest('GantMan'))\n  }\n}\n"
  },
  {
    "path": "boilerplate/App/Sagas/index.js",
    "content": "import { takeLatest, all } from 'redux-saga/effects'\nimport API from '../Services/Api'\nimport FixtureAPI from '../Services/FixtureApi'\nimport DebugConfig from '../Config/DebugConfig'\n\n/* ------------- Types ------------- */\n\nimport { StartupTypes } from '../Redux/StartupRedux'\nimport { GithubTypes } from '../Redux/GithubRedux'\n\n/* ------------- Sagas ------------- */\n\nimport { startup } from './StartupSagas'\nimport { getUserAvatar } from './GithubSagas'\n\n/* ------------- API ------------- */\n\n// The API we use is only used from Sagas, so we create it here and pass along\n// to the sagas which need it.\nconst api = DebugConfig.useFixtures ? FixtureAPI : API.create()\n\n/* ------------- Connect Types To Sagas ------------- */\n\nexport default function * root () {\n  yield all([\n    // some sagas only receive an action\n    takeLatest(StartupTypes.STARTUP, startup),\n\n    // some sagas receive extra parameters in addition to an action\n    takeLatest(GithubTypes.USER_REQUEST, getUserAvatar, api)\n  ])\n}\n"
  },
  {
    "path": "boilerplate/App/Services/Api.js",
    "content": "// a library to wrap and simplify api calls\nimport apisauce from 'apisauce'\n\n// our \"constructor\"\nconst create = (baseURL = 'https://api.github.com/') => {\n  // ------\n  // STEP 1\n  // ------\n  //\n  // Create and configure an apisauce-based api object.\n  //\n  const api = apisauce.create({\n    // base URL is read from the \"constructor\"\n    baseURL,\n    // here are some default headers\n    headers: {\n      'Cache-Control': 'no-cache'\n    },\n    // 10 second timeout...\n    timeout: 10000\n  })\n\n  // ------\n  // STEP 2\n  // ------\n  //\n  // Define some functions that call the api.  The goal is to provide\n  // a thin wrapper of the api layer providing nicer feeling functions\n  // rather than \"get\", \"post\" and friends.\n  //\n  // I generally don't like wrapping the output at this level because\n  // sometimes specific actions need to be take on `403` or `401`, etc.\n  //\n  // Since we can't hide from that, we embrace it by getting out of the\n  // way at this level.\n  //\n  const getRoot = () => api.get('')\n  const getRate = () => api.get('rate_limit')\n  const getUser = (username) => api.get('search/users', {q: username})\n\n  // ------\n  // STEP 3\n  // ------\n  //\n  // Return back a collection of functions that we would consider our\n  // interface.  Most of the time it'll be just the list of all the\n  // methods in step 2.\n  //\n  // Notice we're not returning back the `api` created in step 1?  That's\n  // because it is scoped privately.  This is one way to create truly\n  // private scoped goodies in JavaScript.\n  //\n  return {\n    // a list of the API functions from step 2\n    getRoot,\n    getRate,\n    getUser\n  }\n}\n\n// let's return back our create method as the default.\nexport default {\n  create\n}\n"
  },
  {
    "path": "boilerplate/App/Services/ExamplesRegistry.js",
    "content": "import React from 'react'\nimport { Text, View } from 'react-native'\nimport R from 'ramda'\nimport { ApplicationStyles } from '../Themes'\nimport DebugConfig from '../Config/DebugConfig'\nlet globalComponentExamplesRegistry = []\nlet globalPluginExamplesRegistry = []\n\nexport const addComponentExample = (title, usage = () => {}) => { if (DebugConfig.includeExamples) globalComponentExamplesRegistry.push({title, usage}) } // eslint-disable-line\n\nexport const addPluginExample = (title, usage = () => {}) => { if (DebugConfig.includeExamples) globalPluginExamplesRegistry.push({title, usage}) } // eslint-disable-line\n\nconst renderComponentExample = (example) => {\n  return (\n    <View key={example.title}>\n      <View style={ApplicationStyles.darkLabelContainer}>\n        <Text style={ApplicationStyles.darkLabel}>{example.title}</Text>\n      </View>\n      {example.usage.call()}\n    </View>\n  )\n}\n\nconst renderPluginExample = (example) => {\n  return (\n    <View key={example.title}>\n      <View style={ApplicationStyles.darkLabelContainer}>\n        <Text style={ApplicationStyles.darkLabel}>{example.title}</Text>\n      </View>\n      {example.usage.call()}\n    </View>\n  )\n}\n\nexport const renderComponentExamples = () => R.map(renderComponentExample, globalComponentExamplesRegistry)\n\nexport const renderPluginExamples = () => R.map(renderPluginExample, globalPluginExamplesRegistry)\n\n// Default for readability\nexport default {\n  renderComponentExamples,\n  addComponentExample,\n  renderPluginExamples,\n  addPluginExample\n}\n"
  },
  {
    "path": "boilerplate/App/Services/FixtureApi.js",
    "content": "export default {\n  // Functions return fixtures\n  getRoot: () => {\n    return {\n      ok: true,\n      data: require('../Fixtures/root.json')\n    }\n  },\n  getRate: () => {\n    return {\n      ok: true,\n      data: require('../Fixtures/rateLimit.json')\n    }\n  },\n  getUser: (username) => {\n    // This fixture only supports gantman or else returns skellock\n    const gantmanData = require('../Fixtures/gantman.json')\n    const skellockData = require('../Fixtures/skellock.json')\n    return {\n      ok: true,\n      data: username.toLowerCase() === 'gantman' ? gantmanData : skellockData\n    }\n  }\n}\n"
  },
  {
    "path": "boilerplate/App/Themes/ApplicationStyles.js",
    "content": "import Fonts from './Fonts'\nimport Metrics from './Metrics'\nimport Colors from './Colors'\n\n// This file is for a reusable grouping of Theme items.\n// Similar to an XML fragment layout in Android\n\nconst ApplicationStyles = {\n  screen: {\n    mainContainer: {\n      flex: 1,\n      backgroundColor: Colors.transparent\n    },\n    backgroundImage: {\n      position: 'absolute',\n      top: 0,\n      left: 0,\n      bottom: 0,\n      right: 0\n    },\n    container: {\n      flex: 1,\n      paddingTop: Metrics.baseMargin,\n      backgroundColor: Colors.transparent\n    },\n    section: {\n      margin: Metrics.section,\n      padding: Metrics.baseMargin\n    },\n    sectionText: {\n      ...Fonts.style.normal,\n      paddingVertical: Metrics.doubleBaseMargin,\n      color: Colors.snow,\n      marginVertical: Metrics.smallMargin,\n      textAlign: 'center'\n    },\n    subtitle: {\n      color: Colors.snow,\n      padding: Metrics.smallMargin,\n      marginBottom: Metrics.smallMargin,\n      marginHorizontal: Metrics.smallMargin\n    },\n    titleText: {\n      ...Fonts.style.h2,\n      fontSize: 14,\n      color: Colors.text\n    }\n  },\n  darkLabelContainer: {\n    padding: Metrics.smallMargin,\n    paddingBottom: Metrics.doubleBaseMargin,\n    borderBottomColor: Colors.border,\n    borderBottomWidth: 1,\n    marginBottom: Metrics.baseMargin\n  },\n  darkLabel: {\n    fontFamily: Fonts.type.bold,\n    color: Colors.snow\n  },\n  groupContainer: {\n    margin: Metrics.smallMargin,\n    flexDirection: 'row',\n    justifyContent: 'space-around',\n    alignItems: 'center'\n  },\n  sectionTitle: {\n    ...Fonts.style.h4,\n    color: Colors.coal,\n    backgroundColor: Colors.ricePaper,\n    padding: Metrics.smallMargin,\n    marginTop: Metrics.smallMargin,\n    marginHorizontal: Metrics.baseMargin,\n    borderWidth: 1,\n    borderColor: Colors.ember,\n    alignItems: 'center',\n    textAlign: 'center'\n  }\n}\n\nexport default ApplicationStyles\n"
  },
  {
    "path": "boilerplate/App/Themes/Colors.js",
    "content": "const colors = {\n  background: '#1F0808',\n  clear: 'rgba(0,0,0,0)',\n  facebook: '#3b5998',\n  transparent: 'rgba(0,0,0,0)',\n  silver: '#F7F7F7',\n  steel: '#CCCCCC',\n  error: 'rgba(200, 0, 0, 0.8)',\n  ricePaper: 'rgba(255,255,255, 0.75)',\n  frost: '#D8D8D8',\n  cloud: 'rgba(200,200,200, 0.35)',\n  windowTint: 'rgba(0, 0, 0, 0.4)',\n  panther: '#161616',\n  charcoal: '#595959',\n  coal: '#2d2d2d',\n  bloodOrange: '#fb5f26',\n  snow: 'white',\n  ember: 'rgba(164, 0, 48, 0.5)',\n  fire: '#e73536',\n  drawer: 'rgba(30, 30, 29, 0.95)',\n  eggplant: '#251a34',\n  border: '#483F53',\n  banner: '#5F3E63',\n  text: '#E0D7E5'\n}\n\nexport default colors\n"
  },
  {
    "path": "boilerplate/App/Themes/Fonts.js",
    "content": "const type = {\n  base: 'Avenir-Book',\n  bold: 'Avenir-Black',\n  emphasis: 'HelveticaNeue-Italic'\n}\n\nconst size = {\n  h1: 38,\n  h2: 34,\n  h3: 30,\n  h4: 26,\n  h5: 20,\n  h6: 19,\n  input: 18,\n  regular: 17,\n  medium: 14,\n  small: 12,\n  tiny: 8.5\n}\n\nconst style = {\n  h1: {\n    fontFamily: type.base,\n    fontSize: size.h1\n  },\n  h2: {\n    fontWeight: 'bold',\n    fontSize: size.h2\n  },\n  h3: {\n    fontFamily: type.emphasis,\n    fontSize: size.h3\n  },\n  h4: {\n    fontFamily: type.base,\n    fontSize: size.h4\n  },\n  h5: {\n    fontFamily: type.base,\n    fontSize: size.h5\n  },\n  h6: {\n    fontFamily: type.emphasis,\n    fontSize: size.h6\n  },\n  normal: {\n    fontFamily: type.base,\n    fontSize: size.regular\n  },\n  description: {\n    fontFamily: type.base,\n    fontSize: size.medium\n  }\n}\n\nexport default {\n  type,\n  size,\n  style\n}\n"
  },
  {
    "path": "boilerplate/App/Themes/Images.js",
    "content": "// leave off @2x/@3x\nconst images = {\n  logo: require('../Images/ir.png'),\n  clearLogo: require('../Images/top_logo.png'),\n  launch: require('../Images/launch-icon.png'),\n  ready: require('../Images/your-app.png'),\n  ignite: require('../Images/ignite_logo.png'),\n  igniteClear: require('../Images/ignite-logo-transparent.png'),\n  tileBg: require('../Images/tile_bg.png'),\n  background: require('../Images/BG.png'),\n  buttonBackground: require('../Images/button-bg.png'),\n  api: require('../Images/Icons/icon-api-testing.png'),\n  components: require('../Images/Icons/icon-components.png'),\n  deviceInfo: require('../Images/Icons/icon-device-information.png'),\n  faq: require('../Images/Icons/faq-icon.png'),\n  home: require('../Images/Icons/icon-home.png'),\n  theme: require('../Images/Icons/icon-theme.png'),\n  usageExamples: require('../Images/Icons/icon-usage-examples.png'),\n  chevronRight: require('../Images/Icons/chevron-right.png'),\n  hamburger: require('../Images/Icons/hamburger.png'),\n  backButton: require('../Images/Icons/back-button.png'),\n  closeButton: require('../Images/Icons/close-button.png')\n}\n\nexport default images\n"
  },
  {
    "path": "boilerplate/App/Themes/Metrics.js",
    "content": "import {Dimensions, Platform} from 'react-native'\n\nconst { width, height } = Dimensions.get('window')\n\n// Used via Metrics.baseMargin\nconst metrics = {\n  marginHorizontal: 10,\n  marginVertical: 10,\n  section: 25,\n  baseMargin: 10,\n  doubleBaseMargin: 20,\n  smallMargin: 5,\n  doubleSection: 50,\n  horizontalLineHeight: 1,\n  screenWidth: width < height ? width : height,\n  screenHeight: width < height ? height : width,\n  navBarHeight: (Platform.OS === 'ios') ? 64 : 54,\n  buttonRadius: 4,\n  icons: {\n    tiny: 15,\n    small: 20,\n    medium: 30,\n    large: 45,\n    xl: 50\n  },\n  images: {\n    small: 20,\n    medium: 40,\n    large: 60,\n    logo: 200\n  }\n}\n\nexport default metrics\n"
  },
  {
    "path": "boilerplate/App/Themes/README.md",
    "content": "### Themes Folder\nApplication specific themes\n* Base Styles\n* Fonts\n* Metrics\n* Colors\n\netc.\n"
  },
  {
    "path": "boilerplate/App/Themes/index.js",
    "content": "import Colors from './Colors'\nimport Fonts from './Fonts'\nimport Metrics from './Metrics'\nimport Images from './Images'\nimport ApplicationStyles from './ApplicationStyles'\n\nexport { Colors, Fonts, Images, Metrics, ApplicationStyles }\n"
  },
  {
    "path": "boilerplate/App/Transforms/ConvertFromKelvin.js",
    "content": "export default (kelvin: number) => {\n  const celsius = kelvin - 273.15\n  const fahrenheit = (celsius * 1.8000) + 32\n\n  return Math.round(fahrenheit)\n}\n"
  },
  {
    "path": "boilerplate/App/Transforms/README.md",
    "content": "# Transforms\n\nA common pattern when working with APIs is to change data to play nice between your app & the API.  \n\nWe've found this to be the case in every project we've worked on.  So much so that we're recommending that you create a folder dedicated to these transformations.\n\nTransforms are not necessarily a bad thing (although an API might have you transforming more than you'd like).\n\nFor example, you may:\n\n* turn appropriate strings to date objects\n* convert snake case to camel case\n* normalize or denormalize things\n* create lookup tables\n"
  },
  {
    "path": "boilerplate/README.md",
    "content": "#  <%= props.name %>\n[![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat)](http://standardjs.com/)\n\n* Standard compliant React Native App Utilizing [Ignite](https://github.com/infinitered/ignite)\n\n## :arrow_up: How to Setup\n\n**Step 1:** git clone this repo:\n\n**Step 2:** cd to the cloned repo:\n\n**Step 3:** Install the Application with `yarn` or `npm i`\n\n\n## :arrow_forward: How to Run App\n\n1. cd to the repo\n2. Run Build for either OS\n  * for iOS\n    * run `npx react-native run-ios`\n  * for Android\n    * Run Genymotion\n    * run `npx react-native run-android`\n\n## :no_entry_sign: Standard Compliant\n\n[![js-standard-style](https://cdn.rawgit.com/feross/standard/master/badge.svg)](https://github.com/feross/standard)\nThis project adheres to Standard.  Our CI enforces this, so we suggest you enable linting to keep your project compliant during development.\n\n**To Lint on Commit**\n\nThis is implemented using [husky](https://github.com/typicode/husky). There is no additional setup needed.\n\n**Bypass Lint**\n\nIf you have to bypass lint for a special commit that you will come back and clean (pushing something to a branch etc.) then you can bypass git hooks with adding `--no-verify` to your commit command.\n\n**Understanding Linting Errors**\n\nThe linting rules are from JS Standard and React-Standard.  [Regular JS errors can be found with descriptions here](http://eslint.org/docs/rules/), while [React errors and descriptions can be found here](https://github.com/yannickcr/eslint-plugin-react).\n\n## :closed_lock_with_key: Secrets\n\nThis project uses [react-native-config](https://github.com/luggit/react-native-config) to expose config variables to your javascript code in React Native. You can store API keys\nand other sensitive information in a `.env` file:\n\n```\nAPI_URL=https://myapi.com\nGOOGLE_MAPS_API_KEY=abcdefgh\n```\n\nand access them from React Native like so:\n\n```\nimport Secrets from 'react-native-config'\n\nSecrets.API_URL  // 'https://myapi.com'\nSecrets.GOOGLE_MAPS_API_KEY  // 'abcdefgh'\n```\n\nThe `.env` file is ignored by git keeping those secrets out of your repo.\n\n### Get started:\n1. Copy .env.example to .env\n2. Add your config variables\n3. Follow instructions at [https://github.com/luggit/react-native-config#setup](https://github.com/luggit/react-native-config#setup)\n4. Done!\n"
  },
  {
    "path": "boilerplate/Tests/Components/AlertMessageTest.js",
    "content": "import 'react-native'\nimport React from 'react'\nimport AlertMessage from '../../App/Components/AlertMessage'\nimport renderer from 'react-test-renderer'\n\ntest('AlertMessage component renders correctly if show is true', () => {\n  const tree = renderer.create(<AlertMessage title='howdy' />).toJSON()\n  expect(tree).toMatchSnapshot()\n})\n\ntest('AlertMessage component does not render if show is false', () => {\n  const tree = renderer.create(<AlertMessage title='howdy' show={false} />).toJSON()\n  expect(tree).toMatchSnapshot()\n})\n\ntest('AlertMessage component renders correctly if backgroundColor prop is set', () => {\n  const tree = renderer.create(<AlertMessage title='howdy' style={{backgroundColor: 'red'}} />).toJSON()\n  expect(tree).toMatchSnapshot()\n})\n"
  },
  {
    "path": "boilerplate/Tests/Components/DrawerButtonTest.js",
    "content": "import 'react-native'\nimport React from 'react'\nimport DrawerButton from '../../App/Components/DrawerButton'\nimport { shallow } from 'enzyme'\nimport renderer from 'react-test-renderer'\n\ntest('DrawerButton component renders correctly', () => {\n  const tree = renderer.create(<DrawerButton onPress={() => {}} text='hi' />).toJSON()\n  expect(tree).toMatchSnapshot()\n})\n\ntest('onPress', () => {\n  let i = 0\n  const onPress = () => i++\n  const wrapperPress = shallow(<DrawerButton onPress={onPress} text='hi' />)\n\n  expect(wrapperPress.prop('onPress')).toBe(onPress) // uses the right handler\n  expect(i).toBe(0)\n  wrapperPress.simulate('press')\n  expect(i).toBe(1)\n})\n"
  },
  {
    "path": "boilerplate/Tests/Components/FullButtonTest.js",
    "content": "import 'react-native'\nimport React from 'react'\nimport FullButton from '../../App/Components/FullButton'\nimport { shallow } from 'enzyme'\nimport renderer from 'react-test-renderer'\n\ntest('FullButton component renders correctly', () => {\n  const tree = renderer.create(<FullButton onPress={() => {}} text='hi' />).toJSON()\n  expect(tree).toMatchSnapshot()\n})\n\ntest('onPress', () => {\n  let i = 0 // i guess i could have used sinon here too... less is more i guess\n  const onPress = () => i++\n  const wrapperPress = shallow(<FullButton onPress={onPress} text='hi' />)\n\n  expect(wrapperPress.prop('onPress')).toBe(onPress) // uses the right handler\n  expect(i).toBe(0)\n  wrapperPress.simulate('press')\n  expect(i).toBe(1)\n})\n"
  },
  {
    "path": "boilerplate/Tests/Components/RoundedButtonTest.js",
    "content": "import 'react-native'\nimport React from 'react'\nimport RoundedButton from '../../App/Components/RoundedButton'\nimport { shallow } from 'enzyme'\nimport renderer from 'react-test-renderer'\n\ntest('RoundedButton component renders correctly', () => {\n  const tree = renderer.create(<RoundedButton onPress={() => {}} text='howdy' />).toJSON()\n  expect(tree).toMatchSnapshot()\n})\n\ntest('RoundedButton component with children renders correctly', () => {\n  const tree = renderer.create(<RoundedButton onPress={() => {}}>Howdy</RoundedButton>).toJSON()\n  expect(tree).toMatchSnapshot()\n})\n\ntest('onPress', () => {\n  let i = 0 // i guess i could have used sinon here too... less is more i guess\n  const onPress = () => i++\n  const wrapperPress = shallow(<RoundedButton onPress={onPress} text='hi' />)\n\n  expect(wrapperPress.prop('onPress')).toBe(onPress) // uses the right handler\n  expect(i).toBe(0)\n  wrapperPress.simulate('press')\n  expect(i).toBe(1)\n})\n"
  },
  {
    "path": "boilerplate/Tests/Redux/GithubReduxTest.js",
    "content": "import Actions, { reducer, INITIAL_STATE } from '../../App/Redux/GithubRedux'\n\ntest('request', () => {\n  const username = 'taco'\n  const state = reducer(INITIAL_STATE, Actions.userRequest(username))\n\n  expect(state.fetching).toBe(true)\n  expect(state.username).toBe(username)\n  expect(state.avatar).toBeNull()\n})\n\ntest('success', () => {\n  const avatar = 'http://placekitten.com/200/300'\n  const state = reducer(INITIAL_STATE, Actions.userSuccess(avatar))\n\n  expect(state.fetching).toBe(false)\n  expect(state.avatar).toBe(avatar)\n  expect(state.error).toBeNull()\n})\n\ntest('failure', () => {\n  const state = reducer(INITIAL_STATE, Actions.userFailure())\n\n  expect(state.fetching).toBe(false)\n  expect(state.error).toBe(true)\n  expect(state.avatar).toBeNull()\n})\n"
  },
  {
    "path": "boilerplate/Tests/Sagas/GithubSagaTest.js",
    "content": "import FixtureAPI from '../../App/Services/FixtureApi'\nimport { put, call } from 'redux-saga/effects'\nimport { getUserAvatar } from '../../App/Sagas/GithubSagas'\nimport GithubActions from '../../App/Redux/GithubRedux'\nimport { path } from 'ramda'\n\nconst stepper = (fn) => (mock) => fn.next(mock).value\n\ntest('first calls API', () => {\n  const step = stepper(getUserAvatar(FixtureAPI, {username: 'taco'}))\n  // first yield is API\n  expect(step()).toEqual(call(FixtureAPI.getUser, 'taco'))\n})\n\ntest('success path', () => {\n  const response = FixtureAPI.getUser('taco')\n  const step = stepper(getUserAvatar(FixtureAPI, {username: 'taco'}))\n  // first step API\n  step()\n  // Second step successful return\n  const stepResponse = step(response)\n  // Get the avatar Url from the response\n  const firstUser = path(['data', 'items'], response)[0]\n  const avatar = firstUser.avatar_url\n  expect(stepResponse).toEqual(put(GithubActions.userSuccess(avatar)))\n})\n\ntest('failure path', () => {\n  const response = {ok: false}\n  const step = stepper(getUserAvatar(FixtureAPI, {username: 'taco'}))\n  // first step API\n  step()\n  // Second step failed response\n  expect(step(response)).toEqual(put(GithubActions.userFailure()))\n})\n"
  },
  {
    "path": "boilerplate/Tests/Sagas/StartupSagaTest.js",
    "content": "import { select, put } from 'redux-saga/effects'\nimport { selectAvatar, startup } from '../../App/Sagas/StartupSagas'\nimport GithubActions from '../../App/Redux/GithubRedux'\n\nconst stepper = (fn) => (mock) => fn.next(mock).value\n\ntest('watches for the right action', () => {\n  const step = stepper(startup())\n  GithubActions.userRequest('GantMan')\n  expect(step()).toEqual(select(selectAvatar))\n  expect(step()).toEqual(put(GithubActions.userRequest('GantMan')))\n})\n"
  },
  {
    "path": "boilerplate/Tests/Services/FixtureAPITest.js",
    "content": "import API from '../../App/Services/Api'\nimport FixtureAPI from '../../App/Services/FixtureApi'\nimport R from 'ramda'\n\ntest('All fixtures map to actual API', () => {\n  const fixtureKeys = R.keys(FixtureAPI).sort()\n  const apiKeys = R.keys(API.create())\n\n  const intersection = R.intersection(fixtureKeys, apiKeys).sort()\n\n  // There is no difference between the intersection and all fixtures\n  expect(R.equals(fixtureKeys, intersection)).toBe(true)\n})\n\ntest('FixtureAPI getRate returns the right file', () => {\n  const expectedFile = require('../../App/Fixtures/rateLimit.json')\n\n  expect(FixtureAPI.getRate()).toEqual({\n    ok: true,\n    data: expectedFile\n  })\n})\n\ntest('FixtureAPI getUser returns the right file for gantman', () => {\n  const expectedFile = require('../../App/Fixtures/gantman.json')\n\n  expect(FixtureAPI.getUser('GantMan')).toEqual({\n    ok: true,\n    data: expectedFile\n  })\n})\n\ntest('FixtureAPI getUser returns the right file for skellock as default', () => {\n  const expectedFile = require('../../App/Fixtures/skellock.json')\n\n  expect(FixtureAPI.getUser('Whatever')).toEqual({\n    ok: true,\n    data: expectedFile\n  })\n})\n"
  },
  {
    "path": "boilerplate/Tests/Setup.js.ejs",
    "content": "import { configure } from 'enzyme'\nimport Adapter from 'enzyme-adapter-react-16'\n\nconfigure({ adapter: new Adapter() })\n\n// Mock your external modules here if needed\n<%_ if (props.i18n === 'react-native-i18n') { _%>\njest\n.mock('react-native-i18n', () => {\n  const english = require('../App/I18n/languages/english.json')\n  const keys = require('ramda')\n  const replace = require('ramda')\n  const forEach = require('ramda')\n\n  return {\n    t: (key, replacements) => {\n      let value = english[key]\n      if (!value) return key\n      if (!replacements) return value\n\n      forEach((r) => {\n        value = replace(`{{${r}}}`, replacements[r], value)\n      }, keys(replacements))\n      return value\n    }\n  }\n})\n<%_ } else { _%>\n// jest\n// .mock('react-native-device-info', () => {\n//   return { isTablet: jest.fn(() => { return false }) }\n// })\n<%_ } _%>\n"
  },
  {
    "path": "boilerplate/Tests/StoriesTest.js",
    "content": "import initStoryshots from '@storybook/addon-storyshots'\n\ninitStoryshots()\n"
  },
  {
    "path": "boilerplate/ignite.json.ejs",
    "content": "{\n  \"createdWith\": \"<%= props.igniteVersion %>\",\n  \"boilerplate\": \"ignite-andross\",\n  \"examples\": \"classic\",\n  \"navigation\": \"react-navigation\",\n  \"askToOverwrite\": true\n}\n"
  },
  {
    "path": "boilerplate/index.js.ejs",
    "content": "import './App/Config/ReactotronConfig'\nimport { AppRegistry } from 'react-native'\nimport App from './App/Containers/App'\n\nAppRegistry.registerComponent('<%= props.name %>', () => App)\n"
  },
  {
    "path": "boilerplate/package.json.ejs",
    "content": "{\n  \"version\": \"0.0.1\",\n  \"scripts\": {\n    \"clean\": \"rm -rf $TMPDIR/react-* && watchman watch-del-all && npm cache clean --force\",\n    \"clean:android\": \"cd android/ && ./gradlew clean && cd .. && npx react-native run-android\",\n    \"newclear\": \"rm -rf $TMPDIR/react-* && watchman watch-del-all && rm -rf ios/build && rm -rf node_modules/ && npm cache clean --force && npm i\",\n    \"test:watch\": \"jest --watch\",\n    \"updateSnapshot\": \"jest --updateSnapshot\",\n    \"coverage\": \"jest --coverage && open coverage/lcov-report/index.html || xdg-open coverage/lcov-report/index.html\",\n    \"android:build\": \"cd android && ./gradlew assembleRelease\",\n    \"android:install\": \"cd android && ./gradlew assembleRelease && ./gradlew installRelease\",\n    \"android:hockeyapp\": \"cd android && ./gradlew assembleRelease && puck -submit=auto app/build/outputs/apk/app-release.apk\",\n    \"android:devices\": \"$ANDROID_HOME/platform-tools/adb devices\",\n    \"android:logcat\": \"$ANDROID_HOME/platform-tools/adb logcat *:S ReactNative:V ReactNativeJS:V\",\n    \"android:shake\": \"$ANDROID_HOME/platform-tools/adb devices | grep '\\\\t' | awk '{print $1}' | sed 's/\\\\s//g' | xargs -I {} $ANDROID_HOME/platform-tools/adb -s {} shell input keyevent 82\",\n    \"storybook\": \"storybook start -p 7007\"\n  },\n  \"dependencies\": {\n    \"@react-native-community/async-storage\": \"^1.11.0\",\n    \"@react-native-community/masked-view\": \"^0.1.10\",\n    \"apisauce\": \"^1.1.1\",\n    \"enzyme\": \"^3.11.0\",\n    \"enzyme-adapter-react-16\": \"^1.15.2\",\n    \"format-json\": \"^1.0.3\",\n    \"identity-obj-proxy\": \"^3.0.0\",\n    \"lodash\": \"^4.17.17\",\n    \"prop-types\": \"^15.7.2\",\n    \"querystringify\": \"^2.1.1\",\n    \"ramda\": \"^0.27.0\",\n    \"ramdasauce\": \"^2.1.3\",\n    \"react\": \"16.13.1\",\n    \"react-native\": \"0.63.0\",\n    \"react-native-config\": \"^0.12.0\",\n    \"react-native-device-info\": \"^5.3.0\",\n    \"react-native-gesture-handler\": \"1.6.1\",\n    \"react-native-safe-area-context\": \"^3.0.7\",\n    \"react-native-safe-area-view\": \"^1.1.1\",\n    \"react-native-screens\": \"^2.9.0\",\n    \"react-navigation\": \"4.0.0\",\n    \"react-navigation-redux-helpers\": \"^4.0.1\",\n    \"react-navigation-stack\": \"^1.10.3\",\n    \"react-navigation-tabs\": \"^2.5.6\",\n    \"react-redux\": \"^7.1.3\",\n    \"redux\": \"^4.0.4\",\n    \"redux-saga\": \"^1.1.3\",\n    \"reduxsauce\": \"^1.1.1\",\n    \"seamless-immutable\": \"^7.1.4\"\n  },\n  \"devDependencies\": {\n    \"@babel/core\": \"^7.8.4\",\n    \"@babel/runtime\": \"^7.8.4\",\n    \"@react-native-community/eslint-config\": \"^1.1.0\",\n    \"@storybook/addon-actions\": \"5.0.11\",\n    \"@storybook/addon-links\": \"5.0.11\",\n    \"@storybook/addon-storyshots\": \"^4.1.11\",\n    \"@storybook/addons\": \"^4.1.11\",\n    \"@storybook/channels\": \"^4.1.11\",\n    \"@storybook/react-native\": \"^4.1.11\",\n    \"babel-eslint\": \"7.1.1\",\n    \"babel-jest\": \"^25.1.0\",\n    \"babel-plugin-ignite-ignore-reactotron\": \"^0.3.0\",\n    \"eslint\": \"^6.6.0\",\n    \"jest\": \"^25.1.0\",\n    \"metro-react-native-babel-preset\": \"^0.59.0\",\n    \"react-test-renderer\": \"16.13.1\",\n    \"reactotron-react-native\": \"^4.0.2\",\n    \"reactotron-redux\": \"^3.1.2\",\n    \"reactotron-redux-saga\": \"^4.2.2\",\n    \"snazzy\": \"^8.0.0\",\n    \"standard\": \"10.0.2\"\n  },\n  \"jest\": {\n    \"testMatch\": [\n      \"<rootDir>/Tests/**/*.js\",\n      \"**/?(*.)(spec|test).js?(x)\"\n    ],\n    \"testPathIgnorePatterns\":[\n      \"/node_modules/\",\n      \"<rootDir>/Tests/Setup.js\"\n    ],\n    \"moduleNameMapper\": {\n      \"^.+\\\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$\": \"identity-obj-proxy\"\n    },\n    \"transform\": {\n       \"^.+\\\\.(js)$\": \"<rootDir>/node_modules/react-native/jest/preprocessor.js\"\n    },\n    \"setupFiles\": [\n      \"<rootDir>/Tests/Setup\"\n    ],\n    \"preset\": \"react-native\"\n  },\n  \"config\": {}\n}\n"
  },
  {
    "path": "boilerplate/storybook/addons.js",
    "content": "import '@storybook/addon-actions/register'\nimport '@storybook/addon-links/register'\n"
  },
  {
    "path": "boilerplate/storybook/index.js",
    "content": "import StorybookUI from './storybook'\n\nexport default StorybookUI\n"
  },
  {
    "path": "boilerplate/storybook/storybook.ejs",
    "content": "import { AppRegistry } from 'react-native'\nimport { getStorybookUI, configure } from '@storybook/react-native'\n\n// import stories\nconfigure(() => {\n  require('../App/Components/Stories')\n}, module)\n\n// This assumes that storybook is running on the same host as your RN packager,\n// to set manually use, e.g. host: 'localhost' option\nconst StorybookUI = getStorybookUI({ port: 7007, onDeviceUI: true })\nAppRegistry.registerComponent('<%= props.name %>', () => StorybookUI)\nexport default StorybookUI\n"
  },
  {
    "path": "boilerplate.js",
    "content": "const options = require('./options')\nconst { mergeDeepRight, pipe, assoc, omit, __ } = require('ramda')\nconst { getReactNativeVersion } = require('./lib/react-native-version')\n\n/**\n * Is Android installed?\n *\n * $ANDROID_HOME/tools folder has to exist.\n *\n * @param {*} context - The gluegun context.\n * @returns {boolean}\n */\nconst isAndroidInstalled = function(context) {\n  const androidHome = process.env['ANDROID_HOME']\n  const hasAndroidEnv = !context.strings.isBlank(androidHome)\n  const hasAndroid = hasAndroidEnv && context.filesystem.exists(`${androidHome}/tools`) === 'dir'\n\n  return Boolean(hasAndroid)\n}\n\n/**\n * Let's install.\n *\n * @param {any} context - The gluegun context.\n */\nasync function install(context) {\n  const { filesystem, parameters, ignite, reactNative, print, system, prompt, template } = context\n  const { colors } = print\n  const { red, yellow, bold, gray, blue } = colors\n\n  const perfStart = new Date().getTime()\n\n  const name = parameters.first\n  const spinner = print.spin(`using the ${red('Infinite Red')} boilerplate v2 (code name 'Andross')`).succeed()\n\n  // attempt to install React Native or die trying\n  const useNpm = !ignite.useYarn\n  const rnInstall = await reactNative.install({\n    name,\n    version: getReactNativeVersion(context),\n    useNpm,\n  })\n  if (rnInstall.exitCode > 0) process.exit(rnInstall.exitCode)\n\n  // remove the __tests__ directory and App.js that come with React Native\n  filesystem.remove('__tests__')\n  filesystem.remove('App.js')\n\n  // copy our App, Tests & storybook directories\n  spinner.text = '▸ copying files'\n  spinner.start()\n  filesystem.copy(`${__dirname}/boilerplate/App`, `${process.cwd()}/App`, {\n    overwrite: true,\n    matching: '!*.ejs'\n  })\n  filesystem.copy(`${__dirname}/boilerplate/Tests`, `${process.cwd()}/Tests`, {\n    overwrite: true,\n    matching: '!*.ejs'\n  })\n  filesystem.copy(`${__dirname}/boilerplate/storybook`, `${process.cwd()}/storybook`, {\n    overwrite: true,\n    matching: '!*.ejs'\n  })\n  filesystem.dir(`${process.cwd()}/ignite`)\n  spinner.stop()\n\n  // --max, --min, interactive\n  let answers\n  if (parameters.options.max) {\n    answers = options.answers.max\n  } else if (parameters.options.min) {\n    answers = options.answers.min\n  } else {\n    answers = await prompt.ask(options.questions)\n  }\n\n  // generate some templates\n  spinner.text = '▸ generating files'\n  const templates = [\n    { template: 'index.js.ejs', target: 'index.js' },\n    { template: 'README.md', target: 'README.md' },\n    { template: 'ignite.json.ejs', target: 'ignite/ignite.json' },\n    { template: '.editorconfig', target: '.editorconfig' },\n    { template: '.babelrc', target: '.babelrc' },\n    { template: 'Tests/Setup.js.ejs', target: 'Tests/Setup.js' },\n    { template: 'storybook/storybook.ejs', target: 'storybook/storybook.js' },\n    { template: '.env.example', target: '.env.example' }\n  ]\n  const templateProps = {\n    name,\n    igniteVersion: ignite.version,\n    reactNativeVersion: rnInstall.version,\n    vectorIcons: answers['vector-icons'],\n    animatable: answers['animatable'],\n    i18n: answers['i18n']\n  }\n  await ignite.copyBatch(context, templates, templateProps, {\n    quiet: !parameters.options.debug,\n    directory: `${ignite.ignitePluginPath()}/boilerplate`\n  })\n\n  /**\n   * Append to files\n   */\n  // https://github.com/facebook/react-native/issues/12724\n  await filesystem.appendAsync('.gitattributes', '*.bat text eol=crlf')\n  filesystem.append('.gitignore', '\\n# Misc\\n#')\n  filesystem.append('.gitignore', '\\n.env\\n')\n\n  // transform our package.json in case we need to replace variables\n  const rawJson = await template.generate({\n    directory: `${ignite.ignitePluginPath()}/boilerplate`,\n    template: 'package.json.ejs',\n    props: templateProps\n  })\n  const newPackageJson = JSON.parse(rawJson)\n\n  // read in the react-native created package.json\n  const currentPackage = filesystem.read('package.json', 'json')\n\n  // deep merge, lol\n  const newPackage = pipe(\n    assoc('dependencies', mergeDeepRight(currentPackage.dependencies, newPackageJson.dependencies)),\n    assoc('devDependencies', mergeDeepRight(currentPackage.devDependencies, newPackageJson.devDependencies)),\n    assoc('scripts', mergeDeepRight(currentPackage.scripts, newPackageJson.scripts)),\n    mergeDeepRight(__, omit(['dependencies', 'devDependencies', 'scripts'], newPackageJson))\n  )(currentPackage)\n\n  // write this out\n  filesystem.write('package.json', newPackage, { jsonIndent: 2 })\n\n  spinner.stop()\n\n  // react native link -- must use spawn & stdio: ignore or it hangs!! :(\n  // spinner.text = `▸ linking native libraries`\n  // spinner.start()\n  // await system.spawn('npx react-native link', { stdio: 'ignore' })\n  // spinner.stop()\n\n  // pass long the debug flag if we're running in that mode\n  const debugFlag = parameters.options.debug ? '--debug' : ''\n\n  // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n  // NOTE(steve): I'm re-adding this here because boilerplates now hold permanent files\n  // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n  try {\n    // boilerplate adds itself to get plugin.js/generators etc\n    // Could be directory, npm@version, or just npm name.  Default to passed in values\n    const boilerplate = parameters.options.b || parameters.options.boilerplate || 'ignite-andross'\n\n    await system.spawn(`npx ignite-cli add ${boilerplate} ${debugFlag}`, { stdio: 'inherit' })\n\n    // now run install of Ignite Plugins\n    await ignite.addModule('react-navigation', { version: '4.0.0' })\n    await ignite.addModule('react-native-gesture-handler', { version: '1.6.1', link: true })\n\n    ignite.patchInFile(`${process.cwd()}/android/app/src/main/java/com/${name.toLowerCase()}/MainActivity.java`, {\n      after: 'import com.facebook.react.ReactActivity;',\n      insert: `\n      import com.facebook.react.ReactActivityDelegate;\n      import com.facebook.react.ReactRootView;\n      import com.swmansion.gesturehandler.react.RNGestureHandlerEnabledRootView;`\n    })\n\n    ignite.patchInFile(`${process.cwd()}/android/app/src/main/java/com/${name.toLowerCase()}/MainActivity.java`, {\n      after: `public class MainActivity extends ReactActivity {`,\n      insert:\n        '\\n  @Override\\n' +\n        '  protected ReactActivityDelegate createReactActivityDelegate() {\\n' +\n        '    return new ReactActivityDelegate(this, getMainComponentName()) {\\n' +\n        '      @Override\\n' +\n        '      protected ReactRootView createRootView() {\\n' +\n        '       return new RNGestureHandlerEnabledRootView(MainActivity.this);\\n' +\n        '      }\\n' +\n        '    };\\n' +\n        '  }'\n    })\n    if (answers['vector-icons'] === 'react-native-vector-icons') {\n      await system.spawn(`npx ignite-cli add vector-icons@1.1.1 ${debugFlag}`, {\n        stdio: 'inherit'\n      })\n    }\n\n    if (answers['i18n'] === 'react-native-i18n') {\n      await system.spawn(`npx ignite-cli add i18n@1.2.0 ${debugFlag}`, { stdio: 'inherit' })\n    }\n\n    if (answers['animatable'] === 'react-native-animatable') {\n      await system.spawn(`npx ignite-cli add animatable@1.0.2 ${debugFlag}`, {\n        stdio: 'inherit'\n      })\n    }\n\n    // dev-screens be installed after vector-icons and animatable so that it can\n    // conditionally patch its PluginExamplesScreen\n    if (answers['dev-screens'] === 'Yes') {\n      await system.spawn(`npx ignite-cli add dev-screens@\"2.4.5\" ${debugFlag}`, {\n        stdio: 'inherit'\n      })\n    }\n\n    if (answers['redux-persist'] === 'Yes') {\n      await system.spawn(`npx ignite-cli add redux-persist@2.0.0 ${debugFlag}`, {\n        stdio: 'inherit'\n      })\n    }\n\n    if (parameters.options.lint !== false) {\n      await system.spawn(`npx ignite-cli add standard@1.0.0 ${debugFlag}`, {\n        stdio: 'inherit'\n      })\n    }\n  } catch (e) {\n    ignite.log(e)\n    throw e\n  }\n\n  // git configuration\n  const gitExists = await filesystem.exists('./.git')\n  if (!gitExists && !parameters.options['skip-git'] && system.which('git')) {\n    // initial git\n    const spinner = print.spin('configuring git')\n\n    // TODO: Make husky hooks optional\n    const huskyCmd = '' // `&& node node_modules/husky/bin/install .`\n    await system.run(`git init . && git add . && git commit -m \"Initial commit.\" ${huskyCmd}`)\n\n    spinner.succeed(`configured git`)\n  }\n\n  const perfDuration = parseInt((new Date().getTime() - perfStart) / 10) / 100\n  spinner.succeed(`ignited ${yellow(name)} in ${perfDuration}s`)\n\n  const androidInfo = isAndroidInstalled(context)\n    ? ''\n    : `\\n\\nTo run in Android, make sure you've followed the latest react-native setup instructions at https://facebook.github.io/react-native/docs/getting-started.html before using ignite.\\nYou won't be able to run ${bold(\n        'react-native run-android'\n      )} successfully until you have.`\n\n  const successMessage = `\n    ${red('Ignite CLI')} ignited ${yellow(name)} in ${gray(`${perfDuration}s`)}\n\n    To get started:\n\n      cd ${name}\n      npx react-native run-ios\n      npx react-native run-android${androidInfo}\n      npx ignite-cli --help\n\n    ${gray(\n      'Read the walkthrough at https://github.com/infinitered/ignite-andross/blob/master/readme.md#boilerplate-walkthrough'\n    )}\n\n    ${blue('Need additional help? Join our Slack community at http://community.infinite.red.')}\n\n    ${bold('Now get cooking! 🍽')}\n  `\n\n  print.info(successMessage)\n}\n\nmodule.exports = {\n  install\n}\n"
  },
  {
    "path": "commands/generate/component.js",
    "content": "module.exports = {\n  description: 'Generates a component, styles, and an optional test.',\n  run: async function(toolbox) {\n    // grab some features\n    const { parameters, strings, print, ignite } = toolbox\n    const { pascalCase, isBlank } = strings\n    const config = ignite.loadIgniteConfig()\n    const { tests } = config\n\n    const options = parameters.options || {}\n\n    const hasFolder = !isBlank(options.folder)\n\n    // validation\n    if (isBlank(parameters.first) && !hasFolder) {\n      print.info(`${toolbox.runtime.brand} generate component <name>\\n`)\n      print.info('A name is required.')\n      return\n    }\n\n    let componentPath = hasFolder\n      ? `${options.folder}/${parameters.first || 'index'}`\n      : parameters.first\n\n    let pathComponents = componentPath.split('/').map(pascalCase)\n    let name = pathComponents.pop()\n    if (name === 'Index') {\n      name = 'index'\n    }\n    const relativePath = pathComponents.length ? pathComponents.join('/') + '/' : ''\n\n    const props = { name }\n    const jobs = [\n      {\n        template: 'component.ejs',\n        target: `App/Components/${relativePath}${name}.js`\n      },\n      {\n        template: 'component-style.ejs',\n        target: `App/Components/${relativePath}Styles/${name}Style.js`\n      },\n      tests === 'ava' && {\n        template: 'component-test.ejs',\n        target: `Test/Components/${relativePath}${name}Test.js`\n      }\n    ]\n\n    await ignite.copyBatch(toolbox, jobs, props)\n  }\n}\n"
  },
  {
    "path": "commands/generate/container.js",
    "content": "const patterns = require('../../lib/patterns')\n\nmodule.exports = {\n  description: 'Generates a redux smart component.',\n  run: async function(toolbox) {\n    // grab some features\n    const { parameters, strings, print, ignite, filesystem } = toolbox\n    const { pascalCase, isBlank } = strings\n    const config = ignite.loadIgniteConfig()\n\n    // validation\n    if (isBlank(parameters.first)) {\n      print.info(`${toolbox.runtime.brand} generate container <name>\\n`)\n      print.info('A name is required.')\n      return\n    }\n\n    const name = pascalCase(parameters.first)\n    const props = { name }\n\n    const jobs = [\n      {\n        template: 'container.ejs',\n        target: `App/Containers/${name}.js`\n      },\n      {\n        template: 'container-style.ejs',\n        target: `App/Containers/Styles/${name}Style.js`\n      }\n    ]\n\n    await ignite.copyBatch(toolbox, jobs, props)\n\n    // if using `react-navigation` go the extra step\n    // and insert the container into the nav router\n    if (config.navigation === 'react-navigation') {\n      const containerName = name\n      const appNavFilePath = `${process.cwd()}/App/Navigation/AppNavigation.js`\n      const importToAdd = `import ${containerName} from '../Containers/${containerName}'`\n      const routeToAdd = `  ${containerName}: { screen: ${containerName} },`\n\n      if (!filesystem.exists(appNavFilePath)) {\n        const msg = `No '${appNavFilePath}' file found.  Can't insert container.`\n        print.error(msg)\n        process.exit(1)\n      }\n\n      // insert container import\n      ignite.patchInFile(appNavFilePath, {\n        after: patterns[patterns.constants.PATTERN_IMPORTS],\n        insert: importToAdd\n      })\n\n      // insert container route\n      ignite.patchInFile(appNavFilePath, {\n        after: patterns[patterns.constants.PATTERN_ROUTES],\n        insert: routeToAdd\n      })\n    } else {\n      print.info('Container created, manually add it to your navigation')\n    }\n  }\n}\n"
  },
  {
    "path": "commands/generate/generate.js",
    "content": "module.exports = {\n  name: 'generate',\n  alias: ['g'],\n  run: async toolbox => {\n    toolbox.print.printHelp(toolbox)\n  }\n}\n"
  },
  {
    "path": "commands/generate/list.js",
    "content": "module.exports = {\n  alias: ['ls', 'listview'],\n  description: 'Generates a screen with a ListView/Flatlist/SectionList + walkthrough.',\n  run: async function(toolbox) {\n    const patterns = require('../../lib/patterns')\n    // grab some features\n    const { print, parameters, strings, ignite, filesystem } = toolbox\n    const { pascalCase, isBlank } = strings\n    const config = ignite.loadIgniteConfig()\n\n    // validation\n    if (isBlank(parameters.first)) {\n      print.info(`${toolbox.runtime.brand} generate list <name>\\n`)\n      print.info('A name is required.')\n      return\n    }\n\n    const name = pascalCase(parameters.first)\n    const props = { name }\n\n    // which type of list in code\n    const typeCodeMessage = 'What coding style do you want for your list?'\n    const typeCodeChoices = ['Flatlist (new)', 'Listview (classic)']\n\n    // which type of layout?\n    const typeMessage = 'What kind of List would you like to generate?'\n    const typeChoices = ['Row', 'Grid']\n\n    // Sections or no?\n    const typeDataMessage = 'How will your data be presented on this list?'\n    const typeDataChoices = ['Single', 'Sectioned']\n\n    // Check for parameters to bypass questions\n    let typeCode = parameters.options.codeType\n    let type = parameters.options.type\n    let dataType = parameters.options.dataType\n\n    // only prompt if type is not defined\n    if (!typeCode) {\n      // as question 1\n      const codeAnswers = await toolbox.prompt.ask({\n        name: 'type',\n        type: 'list',\n        message: typeCodeMessage,\n        choices: typeCodeChoices\n      })\n      typeCode = codeAnswers.type[0] === typeCodeChoices[0] ? 'flatlist' : 'listview'\n      \n    }\n\n    if (!type) {\n      // ask question 2\n      const answers = await toolbox.prompt.ask({\n        name: 'type',\n        type: 'list',\n        message: typeMessage,\n        choices: typeChoices\n      })\n     \n      type = answers.type[0] === typeDataChoices[0] ? 'row' : 'grid'\n     \n    }\n\n    if (!dataType) {\n      // ask question 3\n      const dataAnswers = await toolbox.prompt.ask({\n        name: 'type',\n        type: 'list',\n        message: typeDataMessage,\n        choices: typeDataChoices\n      })\n      dataType = dataAnswers.type[0] === typeDataChoices[0] ? 'single' : 'sectioned'\n    }\n\n    // Sorry the following is so confusing, but so are React Native lists\n    // There are 3 options and therefore 8 possible combinations\n    let componentTemplate =\n      dataType.toLowerCase() === 'sectioned' ? typeCode + '-sections' : typeCode\n    let styleTemplate = ''\n    // Different logic depending on code types\n    if (typeCode === 'flatlist') {\n      /*\n       * The following mess is because FlatList supports numColumns\n       * where SectionList does not.\n       */\n      if (type.toLowerCase() === 'grid' && dataType.toLowerCase() === 'sectioned') {\n        // grid + section means we need wrap\n        styleTemplate = 'listview-grid-style'\n      } else if (type.toLowerCase() === 'grid') {\n        componentTemplate = componentTemplate + '-grid'\n        // grid + single = no wrap, use columns\n        styleTemplate = 'flatlist-grid-style'\n      } else {\n        // no grids, flatlist basic\n        styleTemplate = 'listview-style'\n      }\n    } else {\n      // listview builder\n      styleTemplate = type.toLowerCase() === 'grid' ? 'listview-grid-style' : 'listview-style'\n    }\n\n    const jobs = [\n      {\n        template: `${componentTemplate}.ejs`,\n        target: `App/Containers/${name}.js`\n      },\n      {\n        template: `${styleTemplate}.ejs`,\n        target: `App/Containers/Styles/${name}Style.js`\n      }\n    ]\n\n    await ignite.copyBatch(toolbox, jobs, props)\n\n    // if using `react-navigation` go the extra step\n    // and insert the screen into the nav router\n    if (config.navigation === 'react-navigation') {\n      const screenName = `${name}`\n      const appNavFilePath = `${process.cwd()}/App/Navigation/AppNavigation.js`\n      const importToAdd = `import ${screenName} from '../Containers/${screenName}'`\n      const routeToAdd = `  ${screenName}: { screen: ${screenName} },`\n\n      if (!filesystem.exists(appNavFilePath)) {\n        const msg = `No '${appNavFilePath}' file found.  Can't insert list screen.`\n        print.error(msg)\n        process.exit(1)\n      }\n\n      // insert list screen import\n      ignite.patchInFile(appNavFilePath, {\n        after: patterns[patterns.constants.PATTERN_IMPORTS],\n        insert: importToAdd\n      })\n\n      // insert list screen route\n      ignite.patchInFile(appNavFilePath, {\n        after: patterns[patterns.constants.PATTERN_ROUTES],\n        insert: routeToAdd\n      })\n    } else {\n      print.info('List screen created, manually add it to your navigation')\n    }\n  }\n}\n"
  },
  {
    "path": "commands/generate/redux.js",
    "content": "module.exports = {\n  description: ' Generates a action/creator/reducer set for Redux.',\n  run: async function(toolbox) {\n    // grab some features\n    const { parameters, ignite, strings, print } = toolbox\n    const { isBlank, pascalCase } = strings\n    const config = ignite.loadIgniteConfig()\n\n    // validation\n    if (isBlank(parameters.first)) {\n      print.info(`${toolbox.runtime.brand} generate redux <name>\\n`)\n      print.info('A name is required.')\n      return\n    }\n\n    const name = pascalCase(parameters.first)\n    const props = { name }\n\n    const jobs = [{ template: `redux.ejs`, target: `App/Redux/${name}Redux.js` }]\n    if (config.tests) {\n      jobs.push({\n        template: `redux-test-${config.tests}.ejs`,\n        target: `Tests/Redux/${name}ReduxTest.js`\n      })\n    }\n\n    await ignite.copyBatch(toolbox, jobs, props)\n  }\n}\n"
  },
  {
    "path": "commands/generate/saga.js",
    "content": "module.exports = {\n  description: 'Generates a saga with an optional test.',\n  run: async function(toolbox) {\n    // grab some features\n    const { parameters, ignite, print, strings } = toolbox\n    const { pascalCase, isBlank } = strings\n    const config = ignite.loadIgniteConfig()\n    const { tests } = config\n\n    // validation\n    if (isBlank(parameters.first)) {\n      print.info(`${toolbox.runtime.brand} generate saga <name>\\n`)\n      print.info('A name is required.')\n      return\n    }\n\n    const name = pascalCase(parameters.first)\n    const props = { name }\n\n    const jobs = [{ template: `saga.ejs`, target: `App/Sagas/${name}Sagas.js` }]\n    if (tests) {\n      jobs.push({\n        template: `saga-test-${tests}.ejs`,\n        target: `Tests/Sagas/${name}SagaTest.js`\n      })\n    }\n\n    // make the templates\n    await ignite.copyBatch(toolbox, jobs, props)\n  }\n}\n"
  },
  {
    "path": "commands/generate/screen.js",
    "content": "const patterns = require('../../lib/patterns')\n\nmodule.exports = {\n  description: 'Generates an opinionated container.',\n  run: async function(toolbox) {\n    // grab some features\n    const { parameters, print, strings, ignite, filesystem } = toolbox\n    const { pascalCase, isBlank } = strings\n    const config = ignite.loadIgniteConfig()\n\n    // validation\n    if (isBlank(parameters.first)) {\n      print.info(`${toolbox.runtime.brand} generate screen <name>\\n`)\n      print.info('A name is required.')\n      return\n    }\n\n    const name = pascalCase(parameters.first)\n    const screenName = name.endsWith('Screen') ? name : `${name}Screen`\n    const props = { name: screenName }\n\n    const jobs = [\n      {\n        template: `screen.ejs`,\n        target: `App/Containers/${screenName}.js`\n      },\n      {\n        template: `screen-style.ejs`,\n        target: `App/Containers/Styles/${screenName}Style.js`\n      }\n    ]\n\n    // make the templates\n    await ignite.copyBatch(toolbox, jobs, props)\n\n    // if using `react-navigation` go the extra step\n    // and insert the screen into the nav router\n    if (config.navigation === 'react-navigation') {\n      const appNavFilePath = `${process.cwd()}/App/Navigation/AppNavigation.js`\n      const importToAdd = `import ${screenName} from '../Containers/${screenName}'`\n      const routeToAdd = `  ${screenName}: { screen: ${screenName} },`\n\n      if (!filesystem.exists(appNavFilePath)) {\n        const msg = `No '${appNavFilePath}' file found.  Can't insert screen.`\n        print.error(msg)\n        process.exit(1)\n      }\n\n      // insert screen import\n      ignite.patchInFile(appNavFilePath, {\n        after: patterns[patterns.constants.PATTERN_IMPORTS],\n        insert: importToAdd\n      })\n\n      // insert screen route\n      ignite.patchInFile(appNavFilePath, {\n        after: patterns[patterns.constants.PATTERN_ROUTES],\n        insert: routeToAdd\n      })\n    } else {\n      print.info(`Screen ${screenName} created, manually add it to your navigation`)\n    }\n  }\n}\n"
  },
  {
    "path": "ignite.json",
    "content": "{\n  \"generators\": [\n    \"component\",\n    \"container\",\n    \"listview\",\n    \"list\",\n    \"redux\",\n    \"saga\",\n    \"screen\"\n  ]\n}\n"
  },
  {
    "path": "lib/patterns.js",
    "content": "const constants = {\n  PATTERN_IMPORTS: 'imports',\n  PATTERN_ROUTES: 'routes'\n}\n//  [constants.PATTERN_IMPORTS]: `import[\\\\s\\\\S]*from\\\\s+'react-navigation';?`,\n\nmodule.exports = {\n  constants,\n\n  [constants.PATTERN_IMPORTS]: `import { createAppContainer } from 'react-navigation'`,\n  [constants.PATTERN_ROUTES]: 'const PrimaryNav'\n}\n"
  },
  {
    "path": "lib/react-native-version.js",
    "content": "const { pathOr, is } = require('ramda')\n\n// the default React Native version for this boilerplate\nconst REACT_NATIVE_VERSION = '0.63.0'\n\n// where the version lives under gluegun\nconst pathToVersion = ['parameters', 'options', 'react-native-version']\n\n// accepts the context and returns back the version\nconst getVersionFromContext = pathOr(REACT_NATIVE_VERSION, pathToVersion)\n\n/**\n * Gets the React Native version to use.\n *\n * Attempts to read it from the command line, and if not there, falls back\n * to the version we want for this boilerplate.  For example:\n *\n *   $ npx ignite-cli new Custom --react-native-version 0.61.1\n *\n * @param {*} context - The gluegun context.\n */\nconst getReactNativeVersion = (context = {}) => {\n  const version = getVersionFromContext(context)\n  return is(String, version) ? version : REACT_NATIVE_VERSION\n}\n\nmodule.exports = {\n  REACT_NATIVE_VERSION,\n  getReactNativeVersion\n}\n"
  },
  {
    "path": "options.js",
    "content": "/**\n * The questions to ask during the install process.\n */\nconst questions = [\n  {\n    name: 'dev-screens',\n    message: 'Would you like Ignite Development Screens?',\n    type: 'list',\n    choices: ['No', 'Yes']\n  },\n  {\n    name: 'vector-icons',\n    message: 'What vector icon library will you use?',\n    type: 'list',\n    choices: ['none', 'react-native-vector-icons']\n  },\n  {\n    name: 'i18n',\n    message: 'What internationalization library will you use?',\n    type: 'list',\n    choices: ['none', 'react-native-i18n']\n  },\n  {\n    name: 'animatable',\n    message: 'What animation library will you use?',\n    type: 'list',\n    choices: ['none', 'react-native-animatable']\n  },\n  {\n    name: 'redux-persist',\n    message: 'Would you like to include redux-persist?',\n    type: 'list',\n    choices: ['No', 'Yes']\n  }\n]\n\n/**\n * The max preset.\n */\nconst max = {\n  'dev-screens': 'Yes',\n  'vector-icons': 'react-native-vector-icons',\n  i18n: 'react-native-i18n',\n  animatable: 'react-native-animatable',\n  'redux-persist': 'Yes'\n}\n\n/**\n * The min preset.\n */\nconst min = {\n  'dev-screens': 'No',\n  'vector-icons': 'none',\n  i18n: 'none',\n  animatable: 'none',\n  'redux-persist': 'No'\n}\n\nmodule.exports = {\n  questions,\n  answers: { min, max }\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"ignite-andross\",\n  \"description\": \"Infinite Red's hot boilerplate for React Native.\",\n  \"license\": \"MIT\",\n  \"repository\": \"infinitered/ignite-andross\",\n  \"homepage\": \"https://github.com/infinitered/ignite-andross\",\n  \"version\": \"4.3.0\",\n  \"files\": [\n    \"boilerplate\",\n    \"commands\",\n    \"lib\",\n    \"templates\",\n    \"boilerplate.js\",\n    \"ignite.json\",\n    \"options.js\",\n    \"plugin.js\",\n    \"readme.md\",\n    \"screenExamples.js\"\n  ],\n  \"author\": {\n    \"name\": \"Infinite Red\",\n    \"email\": \"npm@infinite.red\",\n    \"url\": \"https://github.com/infinitered/ignite-andross\"\n  },\n  \"scripts\": {\n    \"lint\": \"standard\",\n    \"test\": \"jest\",\n    \"watch\": \"jest --runInBand --watch\",\n    \"coverage\": \"jest --runInBand --coverage\",\n    \"ci:test\": \"yarn test\",\n    \"ci:publish\": \"yarn semantic-release\",\n    \"semantic-release\": \"semantic-release\"\n  },\n  \"standard\": {\n    \"parser\": \"babel-eslint\",\n    \"globals\": [\n      \"__DEV__\",\n      \"jasmine\",\n      \"beforeAll\",\n      \"afterAll\",\n      \"test\",\n      \"expect\",\n      \"describe\"\n    ]\n  },\n  \"prettier\": {\n    \"semi\": false,\n    \"singleQuote\": true,\n    \"printWidth\": 120\n  },\n  \"release\": {\n    \"plugins\": [\n      \"@semantic-release/commit-analyzer\",\n      \"@semantic-release/release-notes-generator\",\n      \"@semantic-release/npm\",\n      \"@semantic-release/github\",\n      [\n        \"@semantic-release/git\",\n        {\n          \"assets\": \"package.json\",\n          \"message\": \"chore(release): ${nextRelease.version} [skip ci]\\n\\n${nextRelease.notes}\"\n        }\n      ]\n    ]\n  },\n  \"devDependencies\": {\n    \"@semantic-release/git\": \"^7.0.5\",\n    \"babel-eslint\": \"^7.1.1\",\n    \"fs-jetpack\": \"^1.0.0\",\n    \"jest\": \"^20.0.4\",\n    \"np\": \"^2.15.0\",\n    \"semantic-release\": \"^15.12.2\",\n    \"sinon\": \"^2.3.1\",\n    \"socks\": \"^2.1.6\",\n    \"standard\": \"^10.0.2\",\n    \"tempy\": \"^0.1.0\"\n  },\n  \"dependencies\": {\n    \"ramda\": \"^0.26.1\"\n  }\n}\n"
  },
  {
    "path": "plugin.js",
    "content": "const screenExamples = require('./screenExamples')\n\n/**\n * Add the plugin.\n *\n * @param {any} context - The gluegun context.\n */\nasync function add (context) {\n  await screenExamples.add(context)\n}\n\n/**\n * Remove the plugin.\n *\n * @param {any} context - The gluegun context.\n */\nasync function remove (context) {\n  await screenExamples.remove(context)\n}\n\nmodule.exports = { add, remove }\n"
  },
  {
    "path": "readme.md",
    "content": "<p align=\"center\"><img src=\"http://ir_public.s3.amazonaws.com/projects/ignite/ignite-andross-launch-screen.png\" alt=\"logo\" width=\"414px\"></p>\n\n# Ignite \"Andross\" Boilerplate\n\n## Why is this archived?\n\nWe really appreciate all the community support in the years since we first released ignite-andross. Our focus has shifted to the latest version of [Ignite](https://github.com/infinitered/ignite), which includes the latest version of our boilerplate. Feel free to fork this library and continue on its legacy if you want. \n\nNOTE: This repo has been renamed from ignite-ir-boilerplate-andross to ignite-andross. Although web traffic and git operations for the previous name will be redirected, we recommend you update any links and git urls for this repo.\n\n\n## The original tried and true boilerplate for [Infinite Red](https://infinite.red)'s React Native apps\n\nCurrently includes:\n\n* React Native 0.63\n* React Navigation 4.0.0\n* Redux\n* Redux Sagas\n* And more!\n\n## Quick Start\n\nWhen you've installed the [Ignite CLI](https://github.com/infinitered/ignite), you can get started with this boilerplate like this:\n\n```sh\nnpx ignite-cli new MyLatestCreation\n```\n\nBy default we'll ask you to choose which boilerplate you'd like. If you just want to use this one you can specify it with `--boilerplate` or `-b`:\n\n```sh\nnpx ignite-cli new MyLatestCreation --boilerplate andross\n```\n\nYou can also change the React Native version; just keep in mind, we may not have tested this just yet.\n\n```sh\nnpx ignite-cli new MyLatestCreation --react-native-version 0.99.0-rc.2\n```\n\nBy default we'll ask you some questions during install as to which features you'd like.  If you just want them all, you can skip the questions:\n\n```sh\nnpx ignite-cli new MyLatestCreation --max\n```\n\nIf you want very few of these extras:\n\n```sh\nnpx ignite-cli new MyLatestCreation --min\n```\n\n## Boilerplate walkthrough\n\nYour `App` folder is where most of the goodies are found in an Ignite Next app. Let's walk through them in more detail. Start with `Containers/App.js` (described below) and work your way down the walkthrough in order.\n\n### Containers\n\nContainers are (mostly) full screens, although they can be sections of screens or application containers.\n\n* `App.js` - your main application. We create a Redux store and configure it here\n* `RootContainer.js` - main view of your application. Contains your status bar and navigation component\n* `LaunchScreen.js` - this is the first screen shown in your application. It's loaded into the Navigation component\n* `Styles` - styling for each of the above containers and screens\n\nTo generate a new Container or Screen you can use the following generator commands:\n\n* `npx ignite-cli g container New` - Will create a `New.js` and also a `Styles/NewStyle.js`.\n* `npx ignite-cli g list New` - The same as the `container` command, but it will give you a walkthrough to generate a ListView screen. Allowing you to even pick `FlatList` or not, grid, and some other options.\n* `npx ignite-cli g screen New` - Will create a `NewScreen.js` and also a `Styles/NewScreenStyle.js`. Important to mention that the `screen` generator will add the `Screen` on the file/class name to make easier to identify.\n\nThose commands will also add the new container to the navigations file.\n\n### Navigation\n\nYour primary and other navigation components reside here.\n\n* `AppNavigation.js` - loads in your initial screen and creates your menu(s) in a StackNavigation\n* `Styles` - styling for the navigation\n* `ReduxNavigation.js` - This file contains the core navigation of your application. If you ever change your launch screen, make sure to change it also at `if (nav.routes.length === 1 && (nav.routes[0].routeName === 'LaunchScreen')) {`, otherwise you may encounter navigation problems with the Android back button!\n\n### Components\n\nReact components go here...pretty self-explanatory. We won't go through each in detail -- open each file to read the comments and view the code.\n\nTo generate a new Component you can use the following generator commands:\n\n* `npx ignite-cli g component New` - Will create a `New.js` and also a `Styles/NewStyle.js`.\n* `npx ignite-cli g component path/New` - The same as above, but will use a relative path\n* `npx ignite-cli g component --folder path` - An alternative to `npx ignite-cli g component path/index`\n* `npx ignite-cli g component --folder path new ` - An alternative to `npx ignite-cli g component relativePath/New`\n\n### Storybook\n\n[Storybook](https://storybook.js.org/) has been setup to show off components in the different states. Storybook is a great way to develop and test components outside of use in your app. Simply run `npm run storybook` to get started. All stores are contained in the `*.story.js` files along side the components.\n\n### Themes\n\nStyling themes used throughout your app styles.\n\n* `ApplicationStyles.js` - app-wide styles\n* `Colors.js` - defined colors for your app\n* `Fonts.js` - defined fonts for your app\n* `Images.js` - loads and caches images used in your app\n* `Metrics.js` - useful measurements of things like navBarHeight\n\n### Config\n\nInitialize and configure things here.\n\n* `AppConfig.js` - simple React Native configuration here\n* `DebugConfig.js` - define how you want your debug environment to act\n* `ReactotronConfig.js` - configures [Reactotron](https://github.com/infinitered/reactotron) in your project (Note: this [will be extracted](https://github.com/infinitered/ignite/issues/779) into a plugin in the future)\n* `ReduxPersist.js` - configures Redux Persist (Note: this [will be extracted](https://github.com/infinitered/ignite/issues/780) into a plugin in the future)\n\n### Fixtures\n\nContains json files that mimic API responses for quicker development. These are used by the `Services/FixtureApi.js` object to mock API responses.\n\n### Redux, Sagas\n\nContains a preconfigured Redux and Redux-Sagas setup. Review each file carefully to see how Redux interacts with your application.\n\nHere again we have generators to help you out. You just have to use one of the following:\n\n* `npx ignite-cli g redux Amazing` - Will generate and link the redux for `Amazing`.\n* `npx ignite-cli g saga Amazing` - The same as above, but for the Sagas\n\nYou can read more about Redux and Redux Sagas in these blog posts:\n\n* [Using redux-saga To Simplify Your Growing React Native Codebase](https://shift.infinite.red/using-redux-saga-to-simplify-your-growing-react-native-codebase-2b8036f650de)\n* [A Tour of React Native — Part 2: Redux & Friends](https://shift.infinite.red/a-tour-of-react-native-part-2-redux-friends-4fed022aaa1e)\n\n### Services\n\nContains your API service and other important utilities for your application.\n\n* `Api.js` - main API service, giving you an interface to communicate with your back end\n* `ExamplesRegistry.js` - lets you view component and Ignite plugin examples in your app\n* `FixtureApi.js` - mocks your API service, making it faster to develop early on in your app\n* `ImmutablePersistenceTransform.js` - part of the redux-persist implementation (will be removed)\n* `RehydrationServices.js` - part of the redux-persist implementation (will be removed)\n\n### Lib\n\nWe recommend using this folder for modules that can be extracted into their own NPM packages at some point.\n\n### Images\n\nContains actual images (usually png) used in your application.\n\n### Transforms\n\nHelpers for transforming data between API and your application and vice versa. An example is provided that you can look at to see how it works.\n\n### Tests\n\nThis folder (located as a sibling to `App`) contains sample Jest snapshot and unit tests for your application.\n\nIf you would like to have the `npx ignite-cli generate` command include the generation of tests when available, add\n`\"tests\": \"jest\"` or `\"tests\": \"ava\"` to `./ignite/ignite.json`, depending on the test runner you are using.\n\n**Previous Boilerplates**\n\n* [2016 aka Ignite 1.0](https://github.com/infinitered/ignite-ir-boilerplate-2016)\n\n\n## Premium Support\n\n[Ignite CLI](https://infinite.red/ignite) and [Ignite Andross](https://github.com/infinitered/ignite-andross), as open source projects, are free to use and always will be. [Infinite Red](https://infinite.red/) offers premium Ignite CLI support and general mobile app design/development services. Email us at [hello@infinite.red](mailto:hello@infinite.red) to get in touch with us for more details.\n"
  },
  {
    "path": "screenExamples.js",
    "content": "const screenExamples = [\n  {\n    title: 'Row Example',\n    screen: 'examples/RowExample.js.ejs',\n    ancillary: ['examples/Styles/RowExampleStyle.js.ejs']\n  },\n  {\n    title: 'Grid Example',\n    screen: 'examples/GridExample.js.ejs',\n    ancillary: ['examples/Styles/GridExampleStyle.js.ejs']\n  },\n  {\n    title: 'Sections Example',\n    screen: 'examples/SectionExample.js.ejs',\n    ancillary: ['examples/Styles/SectionExampleStyle.js.ejs']\n  }\n]\n\n/**\n * Adds the screen examples.\n *\n * @param {any} context The gluegun context.\n */\nasync function add (context) {\n  // examples of generated screens\n  await context.ignite.addPluginScreenExamples(screenExamples)\n}\n\n/**\n * Removes the screen examples.\n *\n * @param {any} context The gluegun context.\n */\nasync function remove (context) {\n  // remove screens\n  await context.ignite.removePluginScreenExamples(screenExamples)\n}\n\nmodule.exports = {\n  add, remove\n}\n"
  },
  {
    "path": "templates/component-style.ejs",
    "content": "import { StyleSheet } from 'react-native'\n\nexport default StyleSheet.create({\n  container: {\n    flex: 1\n  }\n})\n"
  },
  {
    "path": "templates/component-test.ejs",
    "content": "import test from 'ava'\nimport React from 'react'\nimport { shallow } from 'enzyme'\nimport <%= props.name %> from '../../App/Components/<%= props.name %>'\n\nconst wrapper = shallow(<<%= props.name %> />)\n\ntest('component exists', t => {\n  t.is(wrapper.length, 1) // exists\n})\n\ntest('component structure', t => {\n  t.is(wrapper.name(), 'View') // the right root component\n  t.is(wrapper.children().length, 1) // has 1 child\n  t.is(wrapper.children().first().name(), 'Text') // that child is Text\n  t.true(wrapper.children().first().containsMatchingElement('<%= props.name %> Component')) // That the Component Text is included\n})\n\n// test('some other things here', t => {\n// const wrapper = shallow(<YourComponentNameHere // SomeProps > )\n   // You can add in props as shown above, or use the constant wrapper declared\n   // at the top of the file.\n// })\n"
  },
  {
    "path": "templates/component.ejs",
    "content": "import React from 'react'\n// import PropTypes from 'prop-types';\nimport { View, Text } from 'react-native'\nimport styles from './Styles/<%= props.name %>Style'\n\nconst <%= props.name %> = () => {\n  return (\n    <View style={styles.container}>\n      <Text><%= props.name %> Component</Text>\n    </View>\n  )\n}\n\n// // Prop type warnings\n// <%= props.name %>.propTypes = {\n//   someProperty: PropTypes.object,\n//   someSetting: PropTypes.bool.isRequired,\n// }\n//\n// // Defaults for props\n// <%= props.name %>.defaultProps = {\n//   someSetting: false\n// }\n\nexport default <%= props.name %>\n"
  },
  {
    "path": "templates/container-style.ejs",
    "content": "import { StyleSheet } from 'react-native'\nimport { Colors, Metrics } from '../../Themes/'\n\nexport default StyleSheet.create({\n  container: {\n    flex: 1,\n    marginTop: Metrics.navBarHeight,\n    backgroundColor: Colors.background\n  }\n})\n"
  },
  {
    "path": "templates/container.ejs",
    "content": "import React from 'react'\nimport { ScrollView, Text } from 'react-native'\nimport { connect } from 'react-redux'\n// Add Actions - replace 'Your' with whatever your reducer is called :)\n// import YourActions from '../Redux/YourRedux'\n\n// Styles\nimport styles from './Styles/<%= props.name %>Style'\n\nconst <%= props.name %> = () => {\n  return (\n    <ScrollView style={styles.container}>\n      <Text><%= props.name %> Container</Text>\n    </ScrollView>\n  )\n}\n\nconst mapStateToProps = (state) => {\n  return {\n  }\n}\n\nconst mapDispatchToProps = (dispatch) => {\n  return {\n  }\n}\n\nexport default connect(mapStateToProps, mapDispatchToProps)(<%= props.name %>)\n"
  },
  {
    "path": "templates/examples/GridExample.js.ejs",
    "content": "import React, { Component } from 'react'\nimport { View, Text, ListView } from 'react-native'\nimport { connect } from 'react-redux'\n\n// For empty lists\n// import AlertMessage from '../Components/AlertMessage'\n\n// Styles\nimport styles from './Styles/GridExampleStyle'\n\nclass GridExample extends Component {\n  constructor (props) {\n    super(props)\n    // If you need scroll to bottom, consider http://bit.ly/2bMQ2BZ\n\n    /* ***********************************************************\n    * STEP 1\n    * This is an array of objects with the properties you desire\n    * Usually this should come from Redux mapStateToProps\n    *************************************************************/\n    const dataObjects = [\n      {title: 'First Title', description: 'First Description'},\n      {title: 'Second Title', description: 'Second Description'},\n      {title: 'Third Title', description: 'Third Description'},\n      {title: 'Fourth Title', description: 'Fourth Description'},\n      {title: 'Fifth Title', description: 'Fifth Description'},\n      {title: 'Sixth Title', description: 'Sixth Description'},\n      {title: 'Seventh Title', description: 'Seventh Description'}\n    ]\n\n    /* ***********************************************************\n    * STEP 2\n    * Teach datasource how to detect if rows are different\n    * Make this function fast!  Perhaps something like:\n    *   (r1, r2) => r1.id !== r2.id}\n    *************************************************************/\n    const rowHasChanged = (r1, r2) => r1 !== r2\n\n    // DataSource configured\n    const ds = new ListView.DataSource({rowHasChanged})\n\n    // Datasource is always in state\n    this.state = {\n      dataSource: ds.cloneWithRows(dataObjects)\n    }\n  }\n\n  /* ***********************************************************\n  * STEP 3\n  * `_renderRow` function -How each cell/row should be rendered\n  * It's our best practice to place a single component here:\n  *\n  * e.g.\n    return <MyCustomCell title={rowData.title} description={rowData.description} />\n  *************************************************************/\n  _renderRow (rowData) {\n    return (\n      <View style={styles.row}>\n        <Text style={styles.boldLabel}>{rowData.title}</Text>\n        <Text style={styles.label}>{rowData.description}</Text>\n      </View>\n    )\n  }\n\n  /* ***********************************************************\n  * STEP 4\n  * If your datasource is driven by Redux, you'll need to\n  * reset it when new data arrives.\n  * DO NOT! place `cloneWithRows` inside of render, since render\n  * is called very often, and should remain fast!  Just replace\n  * state's datasource on newProps.\n  *\n  * e.g.\n    componentWillReceiveProps (newProps) {\n      if (newProps.someData) {\n        this.setState(prevState => ({\n          dataSource: prevState.dataSource.cloneWithRows(newProps.someData)\n        }))\n      }\n    }\n  *************************************************************/\n\n  // Used for friendly AlertMessage\n  // returns true if the dataSource is empty\n  _noRowData () {\n    return this.state.dataSource.getRowCount() === 0\n  }\n\n  // Render a footer.\n  _renderFooter = () => {\n    return (\n      <Text> - Footer - </Text>\n    )\n  }\n\n  render () {\n    return (\n      <View style={styles.container}>\n        <ListView\n          contentContainerStyle={styles.listContent}\n          dataSource={this.state.dataSource}\n          renderRow={this._renderRow}\n          renderFooter={this._renderFooter}\n          enableEmptySections\n          pageSize={15}\n        />\n      </View>\n    )\n  }\n}\n\nconst mapStateToProps = (state) => {\n  return {\n    // ...redux state to props here\n  }\n}\n\nconst mapDispatchToProps = (dispatch) => {\n  return {\n  }\n}\n\nexport default connect(mapStateToProps, mapDispatchToProps)(GridExample)\n"
  },
  {
    "path": "templates/examples/RowExample.js.ejs",
    "content": "import React, { Component } from 'react'\nimport { View, Text, ListView } from 'react-native'\nimport { connect } from 'react-redux'\n\n// Styles\nimport styles from './Styles/RowExampleStyle'\n\nclass RowExample extends Component {\n  constructor (props) {\n    super(props)\n    // If you need scroll to bottom, consider http://bit.ly/2bMQ2BZ\n\n    /* ***********************************************************\n    * STEP 1\n    * This is an array of objects with the properties you desire\n    * Usually this should come from Redux mapStateToProps\n    *************************************************************/\n    const dataObjects = [\n      {title: 'First Title', description: 'First Description'},\n      {title: 'Second Title', description: 'Second Description'},\n      {title: 'Third Title', description: 'Third Description'},\n      {title: 'Fourth Title', description: 'Fourth Description'},\n      {title: 'Fifth Title', description: 'Fifth Description'},\n      {title: 'Sixth Title', description: 'Sixth Description'},\n      {title: 'Seventh Title', description: 'Seventh Description'}\n    ]\n\n    /* ***********************************************************\n    * STEP 2\n    * Teach datasource how to detect if rows are different\n    * Make this function fast!  Perhaps something like:\n    *   (r1, r2) => r1.id !== r2.id}\n    *************************************************************/\n    const rowHasChanged = (r1, r2) => r1 !== r2\n\n    // DataSource configured\n    const ds = new ListView.DataSource({rowHasChanged})\n\n    // Datasource is always in state\n    this.state = {\n      dataSource: ds.cloneWithRows(dataObjects)\n    }\n  }\n\n  /* ***********************************************************\n  * STEP 3\n  * `_renderRow` function -How each cell/row should be rendered\n  * It's our best practice to place a single component here:\n  *\n  * e.g.\n    return <MyCustomCell title={rowData.title} description={rowData.description} />\n  *************************************************************/\n  _renderRow (rowData) {\n    return (\n      <View style={styles.row}>\n        <Text style={styles.boldLabel}>{rowData.title}</Text>\n        <Text style={styles.label}>{rowData.description}</Text>\n      </View>\n    )\n  }\n\n  /* ***********************************************************\n  * STEP 4\n  * If your datasource is driven by Redux, you'll need to\n  * reset it when new data arrives.\n  * DO NOT! place `cloneWithRows` inside of render, since render\n  * is called very often, and should remain fast!  Just replace\n  * state's datasource on newProps.\n  *\n  * e.g.\n    componentWillReceiveProps (newProps) {\n      if (newProps.someData) {\n        this.setState(prevState => ({\n          dataSource: prevState.dataSource.cloneWithRows(newProps.someData)\n        }))\n      }\n    }\n  *************************************************************/\n\n  // Used for friendly AlertMessage\n  // returns true if the dataSource is empty\n  _noRowData () {\n    return this.state.dataSource.getRowCount() === 0\n  }\n\n  // Render a footer.\n  _renderFooter = () => {\n    return (\n      <Text> - Footer - </Text>\n    )\n  }\n\n  render () {\n    return (\n      <View style={styles.container}>\n        <ListView\n          contentContainerStyle={styles.listContent}\n          dataSource={this.state.dataSource}\n          renderRow={this._renderRow}\n          renderFooter={this._renderFooter}\n          enableEmptySections\n          pageSize={15}\n        />\n      </View>\n    )\n  }\n}\n\nconst mapStateToProps = (state) => {\n  return {\n    // ...redux state to props here\n  }\n}\n\nconst mapDispatchToProps = (dispatch) => {\n  return {\n  }\n}\n\nexport default connect(mapStateToProps, mapDispatchToProps)(RowExample)\n"
  },
  {
    "path": "templates/examples/SectionExample.js.ejs",
    "content": "import React, { Component } from 'react'\nimport { View, ListView, Text } from 'react-native'\nimport { connect } from 'react-redux'\n\n// Styles\nimport styles from './Styles/SectionExampleStyle'\n\nclass ListviewSectionsExample extends Component {\n  constructor (props) {\n    super(props)\n\n    /* ***********************************************************\n    * STEP 1\n    * This is an array of objects with the properties you desire\n    * Usually this should come from Redux mapStateToProps\n    *************************************************************/\n    const dataObjects = {\n      first: [\n        {title: 'First Title', description: 'First Description'},\n        {title: 'Second Title', description: 'Second Description'},\n        {title: 'Third Title', description: 'Third Description'},\n        {title: 'Fourth Title', description: 'Fourth Description'},\n        {title: 'Fifth Title', description: 'Fifth Description'},\n        {title: 'Sixth Title', description: 'Sixth Description'},\n        {title: 'Seventh Title', description: 'Seventh Description'},\n        {title: 'Eighth Title', description: 'Eighth Description'},\n        {title: 'Ninth Title', description: 'Ninth Description'},\n        {title: 'Tenth Title', description: 'Tenth Description'}\n      ],\n      second: [\n        {title: 'Eleventh Title', description: 'Eleventh Description'},\n        {title: '12th Title', description: '12th Description'},\n        {title: '13th Title', description: '13th Description'},\n        {title: '14th Title', description: '14th Description'},\n        {title: '15th Title', description: '15th Description'},\n        {title: '16th Title', description: '16th Description'},\n        {title: '17th Title', description: '17th Description'},\n        {title: '18th Title', description: '18th Description'},\n        {title: '19th Title', description: '19th Description'},\n        {title: '20th Title', description: '20th Description'},\n        {title: 'BLACKJACK!', description: 'BLACKJACK! Description'}\n      ]\n    }\n    /* ***********************************************************\n    * STEP 2\n    * Teach datasource how to detect if rows are different\n    * Make this function fast!  Perhaps something like:\n    *   (r1, r2) => r1.id !== r2.id}\n    *   The same goes for sectionHeaderHasChanged\n    *************************************************************/\n    const rowHasChanged = (r1, r2) => r1 !== r2\n    const sectionHeaderHasChanged = (s1, s2) => s1 !== s2\n\n    // DataSource configured\n    const ds = new ListView.DataSource({rowHasChanged, sectionHeaderHasChanged})\n\n    // Datasource is always in state\n    this.state = {\n      dataSource: ds.cloneWithRowsAndSections(dataObjects)\n    }\n  }\n\n  /* ***********************************************************\n  * STEP 3\n  * `_renderRow` function -How each cell/row should be rendered\n  * It's our best practice to place a single component here:\n  *\n  * e.g.\n    return <MyCustomCell title={rowData.title} description={rowData.description} />\n  *************************************************************/\n  _renderRow (rowData, sectionID) {\n    // You can condition on sectionID (key as string), for different cells\n    // in different sections\n    return (\n      <View style={styles.row}>\n        <Text style={styles.boldLabel}>Section {sectionID} - {rowData.title}</Text>\n        <Text style={styles.label}>{rowData.description}</Text>\n      </View>\n    )\n  }\n\n  /* ***********************************************************\n  * STEP 4\n  * If your datasource is driven by Redux, you'll need to\n  * reset it when new data arrives.\n  * DO NOT! place `cloneWithRowsAndSections` inside of render, since render\n  * is called very often, and should remain fast!  Just replace\n  * state's datasource on newProps.\n  *\n  * e.g.\n    componentWillReceiveProps (newProps) {\n      if (newProps.someData) {\n        this.setState(prevState => ({\n          dataSource: prevState.dataSource.cloneWithRowsAndSections(newProps.someData)\n        }))\n      }\n    }\n  *************************************************************/\n\n  // Used for friendly AlertMessage\n  // returns true if the dataSource is empty\n  _noRowData () {\n    return this.state.dataSource.getRowCount() === 0\n  }\n\n  _renderHeader (data, sectionID) {\n    switch (sectionID) {\n      case 'first':\n        return <Text style={styles.boldLabel}>First Section</Text>\n      default:\n        return <Text style={styles.boldLabel}>Second Section</Text>\n    }\n  }\n\n  render () {\n    return (\n      <View style={styles.container}>\n        <ListView\n          renderSectionHeader={this._renderHeader}\n          contentContainerStyle={styles.listContent}\n          dataSource={this.state.dataSource}\n          onLayout={this.onLayout}\n          renderRow={this._renderRow}\n          enableEmptySections\n        />\n      </View>\n    )\n  }\n}\n\nconst mapStateToProps = (state) => {\n  return {\n    // ...redux state to props here\n  }\n}\n\nconst mapDispatchToProps = (dispatch) => {\n  return {\n  }\n}\n\nexport default connect(mapStateToProps, mapDispatchToProps)(ListviewSectionsExample)\n"
  },
  {
    "path": "templates/examples/Styles/GridExampleStyle.js.ejs",
    "content": "import { StyleSheet } from 'react-native'\nimport { ApplicationStyles, Metrics, Colors } from '../../../../../DevScreens/DevTheme/'\n\nexport default StyleSheet.create({\n  ...ApplicationStyles.screen,\n  container: {\n    flex: 1,\n    marginTop: Metrics.navBarHeight,\n    backgroundColor: Colors.background\n  },\n  row: {\n    width: 100,\n    height: 100,\n    justifyContent: 'center',\n    alignItems: 'center',\n    margin: Metrics.baseMargin,\n    backgroundColor: Colors.fire,\n    borderRadius: Metrics.smallMargin\n  },\n  boldLabel: {\n    fontWeight: 'bold',\n    alignSelf: 'center',\n    color: Colors.snow,\n    textAlign: 'center',\n    marginBottom: Metrics.smallMargin\n  },\n  label: {\n    alignSelf: 'center',\n    color: Colors.snow,\n    textAlign: 'center'\n  },\n  listContent: {\n    justifyContent: 'space-around',\n    flexDirection: 'row',\n    flexWrap: 'wrap'\n  }\n})\n"
  },
  {
    "path": "templates/examples/Styles/RowExampleStyle.js.ejs",
    "content": "import { StyleSheet } from 'react-native'\nimport { ApplicationStyles, Metrics, Colors } from '../../../../../DevScreens/DevTheme/'\n\nexport default StyleSheet.create({\n  ...ApplicationStyles.screen,\n  container: {\n    flex: 1,\n    marginTop: Metrics.navBarHeight,\n    backgroundColor: Colors.background\n  },\n  row: {\n    flex: 1,\n    backgroundColor: Colors.fire,\n    marginVertical: Metrics.smallMargin,\n    justifyContent: 'center'\n  },\n  boldLabel: {\n    fontWeight: 'bold',\n    alignSelf: 'center',\n    color: Colors.snow,\n    textAlign: 'center',\n    marginBottom: Metrics.smallMargin\n  },\n  label: {\n    textAlign: 'center',\n    color: Colors.snow\n  },\n  listContent: {\n    marginTop: Metrics.baseMargin\n  }\n})\n"
  },
  {
    "path": "templates/examples/Styles/SectionExampleStyle.js.ejs",
    "content": "import { StyleSheet } from 'react-native'\nimport { ApplicationStyles, Metrics, Colors } from '../../../../../DevScreens/DevTheme/'\n\nexport default StyleSheet.create({\n  ...ApplicationStyles.screen,\n  container: {\n    flex: 1,\n    marginTop: Metrics.navBarHeight,\n    backgroundColor: Colors.background\n  },\n  row: {\n    flex: 1,\n    backgroundColor: Colors.fire,\n    marginVertical: Metrics.smallMargin,\n    justifyContent: 'center'\n  },\n  boldLabel: {\n    fontWeight: 'bold',\n    alignSelf: 'center',\n    color: Colors.snow,\n    textAlign: 'center',\n    marginBottom: Metrics.smallMargin\n  },\n  label: {\n    textAlign: 'center',\n    color: Colors.snow\n  },\n  listContent: {\n    marginTop: Metrics.baseMargin\n  }\n})\n"
  },
  {
    "path": "templates/flatlist-grid-style.ejs",
    "content": "import { StyleSheet } from 'react-native'\nimport { ApplicationStyles, Metrics, Colors } from '../../Themes'\n\nexport default StyleSheet.create({\n  ...ApplicationStyles.screen,\n  container: {\n    flex: 1,\n    backgroundColor: Colors.background\n  },\n  row: {\n    flex: 1,\n    backgroundColor: Colors.fire,\n    marginVertical: Metrics.smallMargin,\n    justifyContent: 'center',\n    margin: 10,\n    padding: 5,\n    paddingVertical: 10,\n    borderRadius: Metrics.smallMargin\n  },\n  boldLabel: {\n    fontWeight: 'bold',\n    alignSelf: 'center',\n    color: Colors.snow,\n    textAlign: 'center',\n    marginBottom: Metrics.smallMargin\n  },\n  label: {\n    textAlign: 'center',\n    color: Colors.snow\n  },\n  listContent: {\n    marginTop: Metrics.baseMargin\n  }\n})\n"
  },
  {
    "path": "templates/flatlist-grid.ejs",
    "content": "import React from 'react'\nimport { View, Text, FlatList } from 'react-native'\nimport { connect } from 'react-redux'\n\n// More info here: https://facebook.github.io/react-native/docs/flatlist.html\n\n// Styles\nimport styles from './Styles/<%= props.name %>Style'\n\nclass <%= props.name %> extends React.PureComponent {\n  /* ***********************************************************\n  * STEP 1\n  * This is an array of objects with the properties you desire\n  * Usually this should come from Redux mapStateToProps\n  *************************************************************/\n  state = {\n    dataObjects: [\n      {title: 'First Title', description: 'First Description'},\n      {title: 'Second Title', description: 'Second Description'},\n      {title: 'Third Title', description: 'Third Description'},\n      {title: 'Fourth Title', description: 'Fourth Description'},\n      {title: 'Fifth Title', description: 'Fifth Description'},\n      {title: 'Sixth Title', description: 'Sixth Description'},\n      {title: 'Seventh Title', description: 'Seventh Description'}\n    ]\n  }\n\n  /* ***********************************************************\n  * STEP 2\n  * `renderRow` function. How each cell/row should be rendered\n  * It's our best practice to place a single component here:\n  *\n  * e.g.\n    return <MyCustomCell title={item.title} description={item.description} />\n  *************************************************************/\n  renderRow ({item}) {\n    return (\n      <View style={styles.row}>\n        <Text style={styles.boldLabel}>{item.title}</Text>\n        <Text style={styles.label}>{item.description}</Text>\n      </View>\n    )\n  }\n\n  /* ***********************************************************\n  * STEP 3\n  * Consider the configurations we've set below.  Customize them\n  * to your liking!  Each with some friendly advice.\n  *************************************************************/\n  // Render a header?\n  renderHeader = () =>\n    <Text style={[styles.label, styles.sectionHeader]}> - Header - </Text>\n\n  // Render a footer?\n  renderFooter = () =>\n    <Text style={[styles.label, styles.sectionHeader]}> - Footer - </Text>\n\n  // Show this when data is empty\n  renderEmpty = () =>\n    <Text style={styles.label}> - Nothing to See Here - </Text>\n\n  renderSeparator = () =>\n    <Text style={styles.label}> - ~~~~~ - </Text>\n\n  // The default function if no Key is provided is index\n  // an identifiable key is important if you plan on\n  // item reordering.  Otherwise index is fine\n  keyExtractor = (item, index) => `${index}`\n\n  // How many items should be kept im memory as we scroll?\n  oneScreensWorth = 20\n\n  // extraData is for anything that is not indicated in data\n  // for instance, if you kept \"favorites\" in `this.state.favs`\n  // pass that in, so changes in favorites will cause a re-render\n  // and your renderItem will have access to change depending on state\n  // e.g. `extraData`={this.state.favs}\n\n  // Optimize your list if the height of each item can be calculated\n  // by supplying a constant height, there is no need to measure each\n  // item after it renders.  This can save significant time for lists\n  // of a size 100+\n  // e.g. itemLayout={(data, index) => (\n  //   {length: ITEM_HEIGHT, offset: ITEM_HEIGHT * index, index}\n  // )}\n\n  render () {\n    return (\n      <View style={styles.container}>\n        <FlatList\n          contentContainerStyle={styles.listContent}\n          data={this.state.dataObjects}\n          renderItem={this.renderRow}\n          numColumns={2}\n          keyExtractor={this.keyExtractor}\n          initialNumToRender={this.oneScreensWorth}\n          ListHeaderComponent={this.renderHeader}\n          ListFooterComponent={this.renderFooter}\n          ListEmptyComponent={this.renderEmpty}\n          ItemSeparatorComponent={this.renderSeparator}\n        />\n      </View>\n    )\n  }\n}\n\nconst mapStateToProps = (state) => {\n  return {\n    // ...redux state to props here\n  }\n}\n\nconst mapDispatchToProps = (dispatch) => {\n  return {\n  }\n}\n\nexport default connect(mapStateToProps, mapDispatchToProps)(<%= props.name %>)\n"
  },
  {
    "path": "templates/flatlist-sections.ejs",
    "content": "import React from 'react'\nimport { View, SectionList, Text } from 'react-native'\nimport { connect } from 'react-redux'\n\n// More info here: https://facebook.github.io/react-native/docs/sectionlist.html\n\n// Styles\nimport styles from './Styles/<%= props.name %>Style'\n\nclass <%= props.name %> extends React.PureComponent {\n  /* ***********************************************************\n  * STEP 1\n  * This is an array of objects with the properties you desire\n  * Usually this should come from Redux mapStateToProps\n  *************************************************************/\n  state = {\n    data: [\n      {\n        key: 'First',\n        data: [\n          {title: 'First Title', description: 'First Description'},\n          {title: 'Second Title', description: 'Second Description'},\n          {title: 'Third Title', description: 'Third Description'},\n          {title: 'Fourth Title', description: 'Fourth Description'},\n          {title: 'Fifth Title', description: 'Fifth Description'},\n          {title: 'Sixth Title', description: 'Sixth Description'},\n          {title: 'Seventh Title', description: 'Seventh Description'},\n          {title: 'Eighth Title', description: 'Eighth Description'},\n          {title: 'Ninth Title', description: 'Ninth Description'},\n          {title: 'Tenth Title', description: 'Tenth Description'}\n        ]\n      }, {\n        key: 'Second',\n        data: [\n          {title: 'Eleventh Title', description: 'Eleventh Description'},\n          {title: '12th Title', description: '12th Description'},\n          {title: '13th Title', description: '13th Description'},\n          {title: '14th Title', description: '14th Description'},\n          {title: '15th Title', description: '15th Description'},\n          {title: '16th Title', description: '16th Description'},\n          {title: '17th Title', description: '17th Description'},\n          {title: '18th Title', description: '18th Description'},\n          {title: '19th Title', description: '19th Description'},\n          {title: '20th Title', description: '20th Description'},\n          {title: 'BLACKJACK!', description: 'BLACKJACK! Description'}\n        ]\n      }\n    ]\n  }\n\n  /* ***********************************************************\n  * STEP 3\n  * `renderItem` function - How each cell should be rendered\n  * It's our best practice to place a single component here:\n  *\n  * e.g.\n  *   return <MyCustomCell title={item.title} description={item.description} />\n  *\n  * For sections with different cells (heterogeneous lists), you can do branch\n  * logic here based on section.key OR at the data level, you can provide\n  * `renderItem` functions in each section.\n  *\n  * Note: You can remove section/separator functions and jam them in here\n  *************************************************************/\n  renderItem ({section, item}) {\n    return (\n      <View style={styles.row}>\n        <Text style={styles.boldLabel}>Section {section.key} - {item.title}</Text>\n        <Text style={styles.label}>{item.description}</Text>\n      </View>\n    )\n  }\n\n  // Conditional branching for section headers, also see step 3\n  renderSectionHeader ({section}) {\n    switch (section.key) {\n      case 'First':\n        return <View style={styles.sectionHeader}><Text style={styles.boldLabel}>First Section</Text></View>\n      default:\n        return <View style={styles.sectionHeader}><Text style={styles.boldLabel}>Second Section</Text></View>\n    }\n  }\n\n  /* ***********************************************************\n  * STEP 2\n  * Consider the configurations we've set below.  Customize them\n  * to your liking!  Each with some friendly advice.\n  *\n  * Removing a function here will make SectionList use default\n  *************************************************************/\n  // Render a header?\n  renderHeader = () =>\n    <Text style={[styles.label, styles.sectionHeader]}> - Full List Header - </Text>\n\n  // Render a footer?\n  renderFooter = () =>\n    <Text style={[styles.label, styles.sectionHeader]}> - Full List Footer - </Text>\n\n  // Does each section need a footer?\n  renderSectionFooter = () =>\n    <Text style={styles.label}> END SECTION!!!! </Text>\n\n  // Show this when data is empty\n  renderEmpty = () =>\n    <Text style={styles.label}> - Nothing to See Here - </Text>\n\n  renderSeparator = () =>\n    <Text style={styles.label}> - ~~~~~ - </Text>\n\n  renderSectionSeparator = () =>\n    <Text style={styles.label}> \\/\\/\\/\\/\\/\\/\\/\\/ </Text>\n\n  // The default function if no Key is provided is index\n  // an identifiable key is important if you plan on\n  // item reordering.  Otherwise index is fine\n  keyExtractor = (item, index) => `${index}`\n\n  // How many items should be kept im memory as we scroll?\n  oneScreensWorth = 20\n\n  // extraData is for anything that is not indicated in data\n  // for instance, if you kept \"favorites\" in `this.state.favs`\n  // pass that in, so changes in favorites will cause a re-render\n  // and your renderItem will have access to change depending on state\n  // e.g. `extraData`={this.state.favs}\n\n  // Optimize your list if the height of each item can be calculated\n  // by supplying a constant height, there is no need to measure each\n  // item after it renders.  This can save significant time for lists\n  // of a size 100+\n  // e.g. itemLayout={(data, index) => (\n  //   {length: ITEM_HEIGHT, offset: ITEM_HEIGHT * index, index}\n  // )}\n\n  render () {\n    return (\n      <View style={styles.container}>\n        <SectionList\n          renderSectionHeader={this.renderSectionHeader}\n          sections={this.state.data}\n          contentContainerStyle={styles.listContent}\n          renderItem={this.renderItem}\n          keyExtractor={this.keyExtractor}\n          initialNumToRender={this.oneScreensWorth}\n          ListHeaderComponent={this.renderHeader}\n          SectionSeparatorComponent={this.renderSectionSeparator}\n          ListFooterComponent={this.renderFooter}\n          ListEmptyComponent={this.renderEmpty}\n          ItemSeparatorComponent={this.renderSeparator}\n          renderSectionFooter={this.renderSectionFooter}\n        />\n      </View>\n    )\n  }\n}\n\nconst mapStateToProps = (state) => {\n  return {\n    // ...redux state to props here\n  }\n}\n\nconst mapDispatchToProps = (dispatch) => {\n  return {\n  }\n}\n\nexport default connect(mapStateToProps, mapDispatchToProps)(<%= props.name %>)\n"
  },
  {
    "path": "templates/flatlist.ejs",
    "content": "import React from 'react'\nimport { View, Text, FlatList } from 'react-native'\nimport { connect } from 'react-redux'\n\n// More info here: https://facebook.github.io/react-native/docs/flatlist.html\n\n// Styles\nimport styles from './Styles/<%= props.name %>Style'\n\nclass <%= props.name %> extends React.PureComponent {\n  /* ***********************************************************\n  * STEP 1\n  * This is an array of objects with the properties you desire\n  * Usually this should come from Redux mapStateToProps\n  *************************************************************/\n  state = {\n    dataObjects: [\n      {title: 'First Title', description: 'First Description'},\n      {title: 'Second Title', description: 'Second Description'},\n      {title: 'Third Title', description: 'Third Description'},\n      {title: 'Fourth Title', description: 'Fourth Description'},\n      {title: 'Fifth Title', description: 'Fifth Description'},\n      {title: 'Sixth Title', description: 'Sixth Description'},\n      {title: 'Seventh Title', description: 'Seventh Description'}\n    ]\n  }\n\n  /* ***********************************************************\n  * STEP 2\n  * `renderRow` function. How each cell/row should be rendered\n  * It's our best practice to place a single component here:\n  *\n  * e.g.\n    return <MyCustomCell title={item.title} description={item.description} />\n  *************************************************************/\n  renderRow ({item}) {\n    return (\n      <View style={styles.row}>\n        <Text style={styles.boldLabel}>{item.title}</Text>\n        <Text style={styles.label}>{item.description}</Text>\n      </View>\n    )\n  }\n\n  /* ***********************************************************\n  * STEP 3\n  * Consider the configurations we've set below.  Customize them\n  * to your liking!  Each with some friendly advice.\n  *************************************************************/\n  // Render a header?\n  renderHeader = () =>\n    <Text style={[styles.label, styles.sectionHeader]}> - Header - </Text>\n\n  // Render a footer?\n  renderFooter = () =>\n    <Text style={[styles.label, styles.sectionHeader]}> - Footer - </Text>\n\n  // Show this when data is empty\n  renderEmpty = () =>\n    <Text style={styles.label}> - Nothing to See Here - </Text>\n\n  renderSeparator = () =>\n    <Text style={styles.label}> - ~~~~~ - </Text>\n\n  // The default function if no Key is provided is index\n  // an identifiable key is important if you plan on\n  // item reordering.  Otherwise index is fine\n  keyExtractor = (item, index) => `${index}`\n\n  // How many items should be kept im memory as we scroll?\n  oneScreensWorth = 20\n\n  // extraData is for anything that is not indicated in data\n  // for instance, if you kept \"favorites\" in `this.state.favs`\n  // pass that in, so changes in favorites will cause a re-render\n  // and your renderItem will have access to change depending on state\n  // e.g. `extraData`={this.state.favs}\n\n  // Optimize your list if the height of each item can be calculated\n  // by supplying a constant height, there is no need to measure each\n  // item after it renders.  This can save significant time for lists\n  // of a size 100+\n  // e.g. itemLayout={(data, index) => (\n  //   {length: ITEM_HEIGHT, offset: ITEM_HEIGHT * index, index}\n  // )}\n\n  render () {\n    return (\n      <View style={styles.container}>\n        <FlatList\n          contentContainerStyle={styles.listContent}\n          data={this.state.dataObjects}\n          renderItem={this.renderRow}\n          keyExtractor={this.keyExtractor}\n          initialNumToRender={this.oneScreensWorth}\n          ListHeaderComponent={this.renderHeader}\n          ListFooterComponent={this.renderFooter}\n          ListEmptyComponent={this.renderEmpty}\n          ItemSeparatorComponent={this.renderSeparator}\n        />\n      </View>\n    )\n  }\n}\n\nconst mapStateToProps = (state) => {\n  return {\n    // ...redux state to props here\n  }\n}\n\nconst mapDispatchToProps = (dispatch) => {\n  return {\n  }\n}\n\nexport default connect(mapStateToProps, mapDispatchToProps)(<%= props.name %>)\n"
  },
  {
    "path": "templates/listview-grid-style.ejs",
    "content": "import { StyleSheet } from 'react-native'\nimport { ApplicationStyles, Metrics, Colors } from '../../Themes'\n\nexport default StyleSheet.create({\n  ...ApplicationStyles.screen,\n  container: {\n    flex: 1,\n    backgroundColor: Colors.background\n  },\n  row: {\n    width: 100,\n    height: 100,\n    justifyContent: 'center',\n    alignItems: 'center',\n    margin: Metrics.baseMargin,\n    backgroundColor: Colors.fire,\n    borderRadius: Metrics.smallMargin\n  },\n  sectionHeader: {\n    paddingTop: Metrics.doubleBaseMargin,\n    width: Metrics.screenWidth,\n    alignSelf: 'center',\n    margin: Metrics.baseMargin,\n    backgroundColor: Colors.background\n  },\n  boldLabel: {\n    fontWeight: 'bold',\n    alignSelf: 'center',\n    color: Colors.snow,\n    textAlign: 'center',\n    marginBottom: Metrics.smallMargin\n  },\n  label: {\n    alignSelf: 'center',\n    color: Colors.snow,\n    textAlign: 'center'\n  },\n  listContent: {\n    justifyContent: 'space-around',\n    flexDirection: 'row',\n    flexWrap: 'wrap'\n  }\n})\n"
  },
  {
    "path": "templates/listview-sections.ejs",
    "content": "import React, { Component } from 'react'\nimport { View, ListView, Text } from 'react-native'\nimport { connect } from 'react-redux'\n\n// For empty lists\n// import AlertMessage from '../Components/AlertMessage'\n\n// Styles\nimport styles from './Styles/<%= props.name %>Style'\n\nclass <%= props.name %> extends Component {\n  constructor (props) {\n    super(props)\n\n    /* ***********************************************************\n    * STEP 1\n    * This is an array of objects with the properties you desire\n    * Usually this should come from Redux mapStateToProps\n    *************************************************************/\n    const dataObjects = {\n      first: [\n        {title: 'First Title', description: 'First Description'},\n        {title: 'Second Title', description: 'Second Description'},\n        {title: 'Third Title', description: 'Third Description'},\n        {title: 'Fourth Title', description: 'Fourth Description'},\n        {title: 'Fifth Title', description: 'Fifth Description'},\n        {title: 'Sixth Title', description: 'Sixth Description'},\n        {title: 'Seventh Title', description: 'Seventh Description'},\n        {title: 'Eighth Title', description: 'Eighth Description'},\n        {title: 'Ninth Title', description: 'Ninth Description'},\n        {title: 'Tenth Title', description: 'Tenth Description'}\n      ],\n      second: [\n        {title: 'Eleventh Title', description: 'Eleventh Description'},\n        {title: '12th Title', description: '12th Description'},\n        {title: '13th Title', description: '13th Description'},\n        {title: '14th Title', description: '14th Description'},\n        {title: '15th Title', description: '15th Description'},\n        {title: '16th Title', description: '16th Description'},\n        {title: '17th Title', description: '17th Description'},\n        {title: '18th Title', description: '18th Description'},\n        {title: '19th Title', description: '19th Description'},\n        {title: '20th Title', description: '20th Description'},\n        {title: 'BLACKJACK!', description: 'BLACKJACK! Description'}\n      ]\n    }\n    /* ***********************************************************\n    * STEP 2\n    * Teach datasource how to detect if rows are different\n    * Make this function fast!  Perhaps something like:\n    *   (r1, r2) => r1.id !== r2.id}\n    *   The same goes for sectionHeaderHasChanged\n    *************************************************************/\n    const rowHasChanged = (r1, r2) => r1 !== r2\n    const sectionHeaderHasChanged = (s1, s2) => s1 !== s2\n\n    // DataSource configured\n    const ds = new ListView.DataSource({rowHasChanged, sectionHeaderHasChanged})\n\n    // Datasource is always in state\n    this.state = {\n      dataSource: ds.cloneWithRowsAndSections(dataObjects)\n    }\n  }\n\n  /* ***********************************************************\n  * STEP 3\n  * `renderRow` function -How each cell/row should be rendered\n  * It's our best practice to place a single component here:\n  *\n  * e.g.\n    return <MyCustomCell title={rowData.title} description={rowData.description} />\n  *************************************************************/\n  renderRow (rowData, sectionID) {\n    // You can condition on sectionID (key as string), for different cells\n    // in different sections\n    return (\n      <View style={styles.row}>\n        <Text style={styles.boldLabel}>Section {sectionID} - {rowData.title}</Text>\n        <Text style={styles.label}>{rowData.description}</Text>\n      </View>\n    )\n  }\n\n  /* ***********************************************************\n  * STEP 4\n  * If your datasource is driven by Redux, you'll need to\n  * reset it when new data arrives.\n  * DO NOT! place `cloneWithRowsAndSections` inside of render, since render\n  * is called very often, and should remain fast!  Just replace\n  * state's datasource on newProps.\n  *\n  * e.g.\n    componentWillReceiveProps (newProps) {\n      if (newProps.someData) {\n        this.setState(prevState => ({\n          dataSource: prevState.dataSource.cloneWithRowsAndSections(newProps.someData)\n        }))\n      }\n    }\n  *************************************************************/\n\n  // Used for friendly AlertMessage\n  // returns true if the dataSource is empty\n  noRowData () {\n    return this.state.dataSource.getRowCount() === 0\n  }\n\n  renderHeader (data, sectionID) {\n    switch (sectionID) {\n      case 'first':\n        return <View style={styles.sectionHeader}><Text style={styles.boldLabel}>First Section</Text></View>\n      default:\n        return <View style={styles.sectionHeader}><Text style={styles.boldLabel}>Second Section</Text></View>\n    }\n  }\n\n  render () {\n    return (\n      <View style={styles.container}>\n        <ListView\n          renderSectionHeader={this.renderHeader}\n          contentContainerStyle={styles.listContent}\n          dataSource={this.state.dataSource}\n          onLayout={this.onLayout}\n          renderRow={this.renderRow}\n          enableEmptySections\n        />\n      </View>\n    )\n  }\n}\n\nconst mapStateToProps = (state) => {\n  return {\n    // ...redux state to props here\n  }\n}\n\nconst mapDispatchToProps = (dispatch) => {\n  return {\n  }\n}\n\nexport default connect(mapStateToProps, mapDispatchToProps)(<%= props.name %>)\n"
  },
  {
    "path": "templates/listview-style.ejs",
    "content": "import { StyleSheet } from 'react-native'\nimport { ApplicationStyles, Metrics, Colors } from '../../Themes'\n\nexport default StyleSheet.create({\n  ...ApplicationStyles.screen,\n  container: {\n    flex: 1,\n    backgroundColor: Colors.background\n  },\n  row: {\n    flex: 1,\n    backgroundColor: Colors.fire,\n    marginVertical: Metrics.smallMargin,\n    justifyContent: 'center'\n  },\n  boldLabel: {\n    fontWeight: 'bold',\n    alignSelf: 'center',\n    color: Colors.snow,\n    textAlign: 'center',\n    marginBottom: Metrics.smallMargin\n  },\n  label: {\n    textAlign: 'center',\n    color: Colors.snow\n  },\n  listContent: {\n    marginTop: Metrics.baseMargin\n  }\n})\n"
  },
  {
    "path": "templates/listview.ejs",
    "content": "import React, { Component } from 'react'\nimport { View, Text, ListView } from 'react-native'\nimport { connect } from 'react-redux'\n\n// For empty lists\n// import AlertMessage from '../Components/AlertMessage'\n\n// Styles\nimport styles from './Styles/<%= props.name %>Style'\n\nclass <%= props.name %> extends Component {\n  state: {\n    dataSource: Object\n  }\n\n  constructor (props) {\n    super(props)\n    /* ***********************************************************\n    * STEP 1\n    * This is an array of objects with the properties you desire\n    * Usually this should come from Redux mapStateToProps\n    *************************************************************/\n    const dataObjects = [\n      {title: 'First Title', description: 'First Description'},\n      {title: 'Second Title', description: 'Second Description'},\n      {title: 'Third Title', description: 'Third Description'},\n      {title: 'Fourth Title', description: 'Fourth Description'},\n      {title: 'Fifth Title', description: 'Fifth Description'},\n      {title: 'Sixth Title', description: 'Sixth Description'},\n      {title: 'Seventh Title', description: 'Seventh Description'}\n    ]\n\n    /* ***********************************************************\n    * STEP 2\n    * Teach datasource how to detect if rows are different\n    * Make this function fast!  Perhaps something like:\n    *   (r1, r2) => r1.id !== r2.id}\n    *************************************************************/\n    const rowHasChanged = (r1, r2) => r1 !== r2\n\n    // DataSource configured\n    const ds = new ListView.DataSource({rowHasChanged})\n\n    // Datasource is always in state\n    this.state = {\n      dataSource: ds.cloneWithRows(dataObjects)\n    }\n  }\n\n  /* ***********************************************************\n  * STEP 3\n  * `renderRow` function -How each cell/row should be rendered\n  * It's our best practice to place a single component here:\n  *\n  * e.g.\n    return <MyCustomCell title={rowData.title} description={rowData.description} />\n  *************************************************************/\n  renderRow (rowData) {\n    return (\n      <View style={styles.row}>\n        <Text style={styles.boldLabel}>{rowData.title}</Text>\n        <Text style={styles.label}>{rowData.description}</Text>\n      </View>\n    )\n  }\n\n  /* ***********************************************************\n  * STEP 4\n  * If your datasource is driven by Redux, you'll need to\n  * reset it when new data arrives.\n  * DO NOT! place `cloneWithRows` inside of render, since render\n  * is called very often, and should remain fast!  Just replace\n  * state's datasource on newProps.\n  *\n  * e.g.\n    componentWillReceiveProps (newProps) {\n      if (newProps.someData) {\n        this.setState(prevState => ({\n          dataSource: prevState.dataSource.cloneWithRows(newProps.someData)\n        }))\n      }\n    }\n  *************************************************************/\n\n  // Used for friendly AlertMessage\n  // returns true if the dataSource is empty\n  noRowData () {\n    return this.state.dataSource.getRowCount() === 0\n  }\n\n  // Render a footer.\n  renderFooter = () => {\n    return (\n      <Text> - Footer - </Text>\n    )\n  }\n\n  render () {\n    return (\n      <View style={styles.container}>\n        <ListView\n          contentContainerStyle={styles.listContent}\n          dataSource={this.state.dataSource}\n          renderRow={this.renderRow}\n          renderFooter={this.renderFooter}\n          enableEmptySections\n          pageSize={15}\n        />\n      </View>\n    )\n  }\n}\n\nconst mapStateToProps = (state) => {\n  return {\n    // ...redux state to props here\n  }\n}\n\nconst mapDispatchToProps = (dispatch) => {\n  return {\n  }\n}\n\nexport default connect(mapStateToProps, mapDispatchToProps)(<%= props.name %>)\n"
  },
  {
    "path": "templates/redux-test-ava.ejs",
    "content": "import test from 'ava'\nimport Actions, { reducer, INITIAL_STATE } from '../../App/Redux/<%= props.name %>Redux'\n\ntest('attempt', t => {\n  const state = reducer(INITIAL_STATE, Actions.<%= camelCase(props.name) %>Request('data'))\n\n  t.true(state.fetching)\n})\n\ntest('success', t => {\n  const state = reducer(INITIAL_STATE, Actions.<%= camelCase(props.name) %>Success('hi'))\n\n  t.is(state.payload, 'hi')\n})\n\ntest('failure', t => {\n  const state = reducer(INITIAL_STATE, Actions.<%= camelCase(props.name) %>Failure(99))\n\n  t.false(state.fetching)\n  t.true(state.error)\n})\n"
  },
  {
    "path": "templates/redux-test-jest.ejs",
    "content": "import Actions, { reducer, INITIAL_STATE } from '../../App/Redux/<%= props.name %>Redux'\n\nit('attempt', () => {\n  const state = reducer(INITIAL_STATE, Actions.<%= camelCase(props.name) %>Request('data'))\n\n  expect(state.fetching).toBe(true)\n})\n\nit('success', () => {\n  const state = reducer(INITIAL_STATE, Actions.<%= camelCase(props.name) %>Success('hi'))\n\n  expect(state.payload).toBe('hi')\n})\n\nit('failure', () => {\n  const state = reducer(INITIAL_STATE, Actions.<%= camelCase(props.name) %>Failure())\n\n  expect(state.fetching).toBe(false)\n  expect(state.error).toBe(true)\n})\n"
  },
  {
    "path": "templates/redux.ejs",
    "content": "import { createReducer, createActions } from 'reduxsauce'\nimport Immutable from 'seamless-immutable'\n\n/* ------------- Types and Action Creators ------------- */\n\nconst { Types, Creators } = createActions({\n  <%= camelCase(props.name) %>Request: ['data'],\n  <%= camelCase(props.name) %>Success: ['payload'],\n  <%= camelCase(props.name) %>Failure: null\n})\n\nexport const <%= props.name %>Types = Types\nexport default Creators\n\n/* ------------- Initial State ------------- */\n\nexport const INITIAL_STATE = Immutable({\n  data: null,\n  fetching: null,\n  payload: null,\n  error: null\n})\n\n/* ------------- Selectors ------------- */\n\nexport const <%= props.name %>Selectors = {\n  getData: state => state.data\n}\n\n/* ------------- Reducers ------------- */\n\n// request the data from an api\nexport const request = (state, { data }) =>\n  state.merge({ fetching: true, data, payload: null })\n\n// successful api lookup\nexport const success = (state, action) => {\n  const { payload } = action\n  return state.merge({ fetching: false, error: null, payload })\n}\n\n// Something went wrong somewhere.\nexport const failure = state =>\n  state.merge({ fetching: false, error: true, payload: null })\n\n/* ------------- Hookup Reducers To Types ------------- */\n\nexport const reducer = createReducer(INITIAL_STATE, {\n  [Types.<%= snakeCase(props.name).toUpperCase() %>_REQUEST]: request,\n  [Types.<%= snakeCase(props.name).toUpperCase() %>_SUCCESS]: success,\n  [Types.<%= snakeCase(props.name).toUpperCase() %>_FAILURE]: failure\n})\n"
  },
  {
    "path": "templates/saga-test-ava.ejs",
    "content": "/* ***********************************************************\n* Wiring Instructions\n* To make this test work, you'll need to:\n*  - Add a Fixture named get<%= props.name %> to the\n*    ./App/Services/FixtureApi file. You can just keep adding\n*    functions to that file.\n*************************************************************/\n\nimport test from 'ava'\nimport FixtureAPI from '../../App/Services/FixtureApi'\nimport { call, put } from 'redux-saga/effects'\nimport { get<%= props.name %> } from '../../App/Sagas/<%= props.name %>Sagas'\nimport <%= props.name %>Actions from '../../App/Redux/<%= props.name %>Redux'\n\nconst stepper = (fn) => (mock) => fn.next(mock).value\n\ntest('first calls API', t => {\n  const step = stepper(get<%= props.name %>(FixtureAPI, {data: 'taco'}))\n  // first yield is the API\n  t.deepEqual(step(), call(FixtureAPI.get<%= props.name %>, 'taco'))\n})\n\ntest('success path', t => {\n  const response = FixtureAPI.get<%= props.name %>('taco')\n  const step = stepper(get<%= props.name %>(FixtureAPI, {data: 'taco'}))\n  // Step 1: hit the api\n  step()\n  // Second step successful return and data!\n  t.deepEqual(step(response), put(<%= pascalCase(props.name) %>Actions.<%= camelCase(props.name) %>Success(21)))\n})\n\ntest('failure path', t => {\n  const response = {ok: false}\n  const step = stepper(get<%= props.name %>(FixtureAPI, {data: 'taco'}))\n  // Step 1: hit the api\n  step()\n  // Second step failed response\n  t.deepEqual(step(response), put(<%= pascalCase(props.name) %>Actions.<%= camelCase(props.name) %>Failure()))\n})\n"
  },
  {
    "path": "templates/saga-test-jest.ejs",
    "content": "/* ***********************************************************\n* Wiring Instructions\n* To make this test work, you'll need to:\n*  - Add a Fixture named get<%= props.name %> to the\n*    ./App/Services/FixtureApi file. You can just keep adding\n*    functions to that file.\n*************************************************************/\n\nimport FixtureAPI from '../../App/Services/FixtureApi'\nimport { call, put } from 'redux-saga/effects'\nimport { get<%= props.name %> } from '../../App/Sagas/<%= props.name %>Sagas'\nimport <%= props.name %>Actions from '../../App/Redux/<%= props.name %>Redux'\n\nconst stepper = (fn) => (mock) => fn.next(mock).value\n\nit('first calls API', () => {\n  const step = stepper(get<%= props.name %>(FixtureAPI, {data: 'taco'}))\n  // first yield is the API\n  expect(step()).toEqual(call(FixtureAPI.get<%= props.name %>, 'taco'))\n})\n\nit('success path', () => {\n  const response = FixtureAPI.get<%= props.name %>('taco')\n  const step = stepper(get<%= props.name %>(FixtureAPI, {data: 'taco'}))\n  // Step 1: Hit the api\n  step()\n  // Step 2: Successful return and data!\n  expect(step(response)).toEqual(put(<%= pascalCase(props.name) %>Actions.<%= camelCase(props.name) %>Success(21)))\n})\n\nit('failure path', () => {\n  const response = {ok: false}\n  const step = stepper(get<%= props.name %>(FixtureAPI, {data: 'taco'}))\n  // Step 1: Hit the api\n  step()\n  // Step 2: Failed response.\n  expect(step(response)).toEqual(put(<%= pascalCase(props.name) %>Actions.<%= camelCase(props.name) %>Failure()))\n})\n"
  },
  {
    "path": "templates/saga.ejs",
    "content": "/* ***********************************************************\n* A short word on how to use this automagically generated file.\n* We're often asked in the Infinite Red Slack channel how to connect\n* to a to a third party api, so we thought we'd demonstrate - but\n* you should know you can use sagas for other flow control too.\n*\n* Other points:\n*  - You'll need to add this saga to sagas/index.js\n*  - This template uses the api declared in sagas/index.js, so\n*    you'll need to define a constant in that file.\n*************************************************************/\n\nimport { call, put } from 'redux-saga/effects'\nimport <%= props.name %>Actions from '../Redux/<%= props.name %>Redux'\n// import { <%= props.name %>Selectors } from '../Redux/<%= props.name %>Redux'\n\nexport function * get<%= props.name %> (api, action) {\n  const { data } = action\n  // get current data from Store\n  // const currentData = yield select(<%= props.name %>Selectors.getData)\n  // make the call to the api\n  const response = yield call(api.get<%= camelCase(props.name) %>, data)\n\n  // success?\n  if (response.ok) {\n    // You might need to change the response here - do this with a 'transform',\n    // located in ../Transforms/. Otherwise, just pass the data back from the api.\n    yield put(<%= props.name %>Actions.<%= camelCase(props.name) %>Success(response.data))\n  } else {\n    yield put(<%= props.name %>Actions.<%= camelCase(props.name) %>Failure())\n  }\n}\n"
  },
  {
    "path": "templates/screen-style.ejs",
    "content": "import { StyleSheet } from 'react-native'\nimport { ApplicationStyles } from '../../Themes/'\n\nexport default StyleSheet.create({\n  ...ApplicationStyles.screen\n})\n"
  },
  {
    "path": "templates/screen.ejs",
    "content": "import React, { Component } from 'react'\nimport { ScrollView, Text, KeyboardAvoidingView } from 'react-native'\nimport { connect } from 'react-redux'\n// Add Actions - replace 'Your' with whatever your reducer is called :)\n// import YourActions from '../Redux/YourRedux'\n\n// Styles\nimport styles from './Styles/<%= props.name %>Style'\n\nclass <%= props.name %> extends Component {\n  render () {\n    return (\n      <ScrollView style={styles.container}>\n        <KeyboardAvoidingView behavior='position'>\n          <Text><%= props.name %></Text>\n        </KeyboardAvoidingView>\n      </ScrollView>\n    )\n  }\n}\n\nconst mapStateToProps = (state) => {\n  return {\n  }\n}\n\nconst mapDispatchToProps = (dispatch) => {\n  return {\n  }\n}\n\nexport default connect(mapStateToProps, mapDispatchToProps)(<%= props.name %>)\n"
  },
  {
    "path": "test/generators-integration.test.js",
    "content": "const execa = require('execa')\nconst jetpack = require('fs-jetpack')\nconst tempy = require('tempy')\n\nconst IGNITE = 'npx ignite-cli'\nconst APP = 'IntegrationTest'\nconst BOILERPLATE = jetpack.path(__dirname, '..')\n\n// calling the ignite cli takes a while\njasmine.DEFAULT_TIMEOUT_INTERVAL = 600000\n\nconst exopts = {\n  preferLocal: false,\n  shell: true\n}\n\ndescribe('generators', () => {\n  beforeAll(async () => {\n    // creates a new temp directory\n    process.chdir(tempy.directory())\n    await execa(IGNITE, ['new', APP, '--min', '--skip-git', '--boilerplate', BOILERPLATE], exopts)\n    process.chdir(APP)\n    await execa('npm', ['run', 'fixcode'], exopts)\n  })\n\n  test('generates a component', async () => {\n    const simpleComponent = 'Simple'\n    await execa(IGNITE, ['g', 'component', simpleComponent], exopts)\n    expect(jetpack.exists(`App/Components/${simpleComponent}.js`)).toBe('file')\n    expect(jetpack.exists(`App/Components/Styles/${simpleComponent}Style.js`)).toBe('file')\n    const lint = await execa('npm', ['-s', 'run', 'lint', '--loglevel=error'], exopts)\n    expect(lint.stderr).toBe('')\n  })\n\n  test('generates a folder component', async () => {\n    const folderComponent = 'Folder'\n    await execa(IGNITE, ['g', 'component', '--folder', folderComponent], exopts)\n    expect(jetpack.exists(`App/Components/${folderComponent}/index.js`)).toBe('file')\n    expect(jetpack.exists(`App/Components/${folderComponent}/Styles/indexStyle.js`)).toBe('file')\n    const lint = await execa('npm', ['-s', 'run', 'lint', '--loglevel=error'], exopts)\n    expect(lint.stderr).toBe('')\n  })\n\n  test('generates a component inside a folder', async () => {\n    const componentName = 'InFolder'\n    const folderName = 'Folder'\n    await execa(IGNITE, ['g', 'component', '--folder', folderName, componentName], exopts)\n    expect(jetpack.exists(`App/Components/${folderName}/${componentName}.js`)).toBe('file')\n    expect(jetpack.exists(`App/Components/${folderName}/Styles/${componentName}Style.js`)).toBe('file')\n    const lint = await execa('npm', ['-s', 'run', 'lint', '--loglevel=error'], exopts)\n    expect(lint.stderr).toBe('')\n  })\n\n  test('generates a component in a relative path', async () => {\n    await execa(IGNITE, ['g', 'component', 'My/SubFolder/Test'], exopts)\n    expect(jetpack.exists('App/Components/My/SubFolder/Test.js')).toBe('file')\n    expect(jetpack.exists('App/Components/My/SubFolder/Styles/TestStyle.js')).toBe('file')\n    const lint = await execa('npm', ['-s', 'run', 'lint', '--loglevel=error'], exopts)\n    expect(lint.stderr).toBe('')\n  })\n\n  test('generate listview of type row works', async () => {\n    await execa(IGNITE, ['g', 'list', 'TestRow', '--type=Row', '--codeType=listview', '--dataType=Single'], exopts)\n    expect(jetpack.exists('App/Containers/TestRow.js')).toBe('file')\n    expect(jetpack.exists('App/Containers/Styles/TestRowStyle.js')).toBe('file')\n    const lint = await execa('npm', ['run', 'lint', '--loglevel=error'], exopts)\n    expect(lint.stderr).toBe('')\n  })\n\n  test('generate flatlist of type row works', async () => {\n    await execa(IGNITE, ['g', 'list', 'TestFlatRow', '--type=Row', '--codeType=flatlist', '--dataType=Single'], exopts)\n    expect(jetpack.exists('App/Containers/TestFlatRow.js')).toBe('file')\n    expect(jetpack.exists('App/Containers/Styles/TestFlatRowStyle.js')).toBe('file')\n    const lint = await execa('npm', ['run', 'lint', '--loglevel=error'], exopts)\n    expect(lint.stderr).toBe('')\n  })\n\n  test('generate listview of sections works', async () => {\n    await execa(\n      IGNITE,\n      ['g', 'list', 'TestSection', '--type=Row', '--codeType=listview', '--dataType=Sectioned'],\n      exopts\n    )\n    expect(jetpack.exists('App/Containers/TestSection.js')).toBe('file')\n    expect(jetpack.exists('App/Containers/Styles/TestSectionStyle.js')).toBe('file')\n    const lint = await execa('npm', ['run', 'lint', '--loglevel=error'], exopts)\n    expect(lint.stderr).toBe('')\n  })\n\n  test('generate flatlist of sections works', async () => {\n    await execa(\n      IGNITE,\n      ['g', 'list', 'TestFlatSection', '--type=Row', '--codeType=flatlist', '--dataType=Sectioned'],\n      exopts\n    )\n    expect(jetpack.exists('App/Containers/TestFlatSection.js')).toBe('file')\n    expect(jetpack.exists('App/Containers/Styles/TestFlatSectionStyle.js')).toBe('file')\n    const lint = await execa('npm', ['run', 'lint', '--loglevel=error'], exopts)\n    expect(lint.stderr).toBe('')\n  })\n\n  test('generate listview of type grid works', async () => {\n    await execa(IGNITE, ['g', 'list', 'TestGrid', '--type=Grid', '--codeType=listview', '--dataType=Single'], exopts)\n    expect(jetpack.exists('App/Containers/TestGrid.js')).toBe('file')\n    expect(jetpack.exists('App/Containers/Styles/TestGridStyle.js')).toBe('file')\n    const lint = await execa('npm', ['run', 'lint', '--loglevel=error'], exopts)\n    expect(lint.stderr).toBe('')\n  })\n\n  test('generate redux works', async () => {\n    await execa(IGNITE, ['g', 'redux', 'Test'], exopts)\n    expect(jetpack.exists('App/Redux/TestRedux.js')).toBe('file')\n    const lint = await execa('npm', ['run', 'lint', '--loglevel=error'], exopts)\n    expect(lint.stderr).toBe('')\n  })\n\n  test('generate container works', async () => {\n    await execa(IGNITE, ['g', 'container', 'Container'], exopts)\n    expect(jetpack.exists('App/Containers/Container.js')).toBe('file')\n    expect(jetpack.exists('App/Containers/Styles/ContainerStyle.js')).toBe('file')\n    const lint = await execa('npm', ['run', 'lint', '--loglevel=error'], exopts)\n    expect(lint.stderr).toBe('')\n  })\n\n  test('generate saga works', async () => {\n    await execa(IGNITE, ['g', 'saga', 'Test'], exopts)\n    expect(jetpack.exists('App/Sagas/TestSagas.js')).toBe('file')\n    const lint = await execa('npm', ['run', 'lint', '--loglevel=error'], exopts)\n    expect(lint.stderr).toBe('')\n  })\n\n  test('generate screen works', async () => {\n    await execa(IGNITE, ['g', 'screen', 'Test'], exopts)\n    expect(jetpack.exists('App/Containers/TestScreen.js')).toBe('file')\n    expect(jetpack.exists('App/Containers/Styles/TestScreenStyle.js')).toBe('file')\n    const lint = await execa('npm', ['run', 'lint', '--loglevel=error'], exopts)\n    expect(lint.stderr).toBe('')\n  })\n})\n"
  },
  {
    "path": "test/interface.test.js",
    "content": "const boilerplate = require('../boilerplate')\nconst plugin = require('../plugin')\n\ntest('boilerplate interface', async () => {\n  expect(typeof boilerplate.install).toBe('function')\n})\n\ntest('plugin interface', async () => {\n  expect(typeof plugin.add).toBe('function')\n  expect(typeof plugin.remove).toBe('function')\n})\n"
  },
  {
    "path": "test/react-native-version.test.js",
    "content": "const boilerplate = require('../lib/react-native-version')\n\n// grab a few things from the boilerplate module\nconst get = boilerplate.getReactNativeVersion\nconst DEFAULT = boilerplate.REACT_NATIVE_VERSION\n\n/**\n * Runs with a valid gluegun context and a staged version number.\n *\n * @param {*} reactNativeVersion The React Native version to use.\n * @return {string} The version number we should be using.\n */\nconst mock = reactNativeVersion => get({\n  parameters: {\n    options: {\n      'react-native-version': reactNativeVersion\n    }\n  }\n})\n\n// this would only happen if we screwed something up in our boilerplate.js\ntest('it handles strange inputs from code', () => {\n  expect(get()).toBe(DEFAULT)\n  expect(get(null)).toBe(DEFAULT)\n  expect(get(true)).toBe(DEFAULT)\n  expect(get(8)).toBe(DEFAULT)\n  expect(get('hello')).toBe(DEFAULT)\n  expect(get([])).toBe(DEFAULT)\n  expect(get({})).toBe(DEFAULT)\n  expect(get(() => true)).toBe(DEFAULT)\n})\n\n// this could happen because it's valid input via minimist from the user\ntest('it handles strange input from the user', () => {\n  expect(mock(true)).toBe(DEFAULT)\n  expect(mock(false)).toBe(DEFAULT)\n  expect(mock([])).toBe(DEFAULT)\n  expect(mock({})).toBe(DEFAULT)\n})\n\n// very edge-casey\ntest('it handles not-quite semver numbers', () => {\n  expect(mock(0)).toBe(DEFAULT)\n  expect(mock(0.25)).toBe(DEFAULT)\n})\n\n// happy path\ntest('it handles valid versions', () => {\n  expect(mock('0.41.0')).toBe('0.41.0')\n  expect(mock('0.41.0-beta.1')).toBe('0.41.0-beta.1')\n  expect(mock(DEFAULT)).toBe(DEFAULT)\n  expect(mock('next')).toBe('next')\n})\n"
  }
]