<commit_before>/**
 * Copyright (c) 2018 Andrew Howden. All rights reserved.
 *
 * This copyright does not apply where other licenses override it.
 */

import { html } from '@polymer/lit-element';
import { PageViewElement } from './page-view-element.js';

// These are the shared styles needed by this element.
import { SharedStyles } from './shared-styles.js';

// These are the elements needed by this element
import '@polymer/iron-flex-layout/iron-flex-layout.js';
import '@polymer/iron-icon/iron-icon.js';
import '@polymer/iron-icons/iron-icons.js';
import '@polymer/paper-card/paper-card.js';
import '@polymer/paper-button/paper-button.js';

import { repeat} from 'lit-html/lib/repeat.js';

class AhcPortfolio extends PageViewElement {
    _render(props) {
       return html`${SharedStyles}
       <custom-style>

       </custom-style>

         ${repeat(AhcPortfolio.properties.portfolio.value(), (i) => html`
             <paper-card heading="${i.title}">

${i.content}

               <iron-icon src="/images/icons/skills.png"></iron-icon>${i.skills.join(', ')}

               <iron-icon icon="icons:home"></iron-icon>${i.company}

             </paper-card>
         `)}

       `
    }

    static get properties() {
        return {
            active: Boolean,
            portfolio: {
                value() {
                    return [
                        {
                            id: 'a2d603bc-9f29-11e8-8e33-931c0083bdde',
                            title: "Port the MageAudit Magento analysis tool from Laravel 2 to Magento 1.x",
                            content: 'Most of the analysis existed, however the initial design had some inefficient designs, and the opportunity was taken to restructure the design to make additional analysis far easier to implement in future. MageAudit is still operating to this day.',
                            skills: [
                                'PHP', 'Magento'
                            ],
                            company: 'Fontis'
                        },
                        {
                            id: 'ad0c02c8-9f29-11e8-94a5-bb7f01112aaf',
                            title: "Drafted the incident response framework, structuring crisis management response",
                            content: "This involved creating the processes for declaring an 'incident', managing staff reallocation for the crisis and creating effective post-mortems to prevent issue recurrence. This framework has been used successfully for over a year to manage a wide variety of unexpected but critical system failures with minimal stress, clear communication with stakeholders and a systematic reduction of risk across otherwise risky systems.",
                            skills: [
                                'Communication', 'Crisis Management'
                            ],
                            company: 'Sitewards'
                        },
                        {
                            id: '1b04d05a-a2b5-11e8-9fbc-4fb2b8fda64f',
                            title: "Collaboratively detect, analyse and remediate a compromised machine",
                            content: "This started as a routine investigation into unscheduled unavailability for > 5 minutes, triggering an alert. The unavailability was traced to a reboot, which was in turn triggered by a malicious actor to gain persistent root privileges. Detection involved scanning through the system log until we detected hardware USB insert events, at which point the data center was called for further information. Having no physical access recorded to the device, we discovered the IMPI interface and promptly disabled it. Remediation involved reflashing the machine with a new copy of the operating system, and using an Ansible definition to restore the machine to a known good state. The unauthorised access was detected and removed within approximately 3 hours, thanks to previously implemented time series data monitoring. Follow up work implemented the system monitoring tooling 'Falco', the remote analysis tool 'OSQuery' as well as log aggregation and other system utilities.",
                            skills: [
                                'Linux', 'Ansible', 'Security'
                            ],
                            company: 'Sitewards'
                        },
                        {
                            id: 'b3acb762-9f29-11e8-bd6e-6b6aee3a319c',
                            title: "Writing an Ansible specification for deploying Kubernetes onto a CoreOS Cluster on Google Cloud",
                            content: "Still ongoing, but the goal is to have a Kubernetes stack that can be run on anything from bare metal to a cloud provider. This involved creating and understanding Systemd service units and how to drain CoreOS nodes of their Kubernetes workloads prior to the automated reboot scheduled by system upgrades.",
                            skills: [
                                'Ansible', 'CoreOS', 'Kubernetes', 'Linux'
                            ],
                            company: 'Fontis'
                        },
                        {
                            id: 'b8639f5a-9f29-11e8-9a4b-333f4fa17870',
                            title: "Redesign of the Bing Lee checkout",
                            content: "A complete reimplementation of a one step checkout, requiring as little information from the user as is required by the other information specified during the checkout. This required considerable restructuring of Magentos core validation logic, additional validation and reasonably complex implementation of various JavaScript driven features.",
                            skills: [
                                'JavaScript', 'PHP', 'Magento'
                            ],
                            company: 'Fontis'
                        },
                        {
                            id: 'bc83b02a-9f29-11e8-94a9-dba2c3dad045',
                            title: "Rebuilding the GAZ MAN website as a mobile first website",
                            content: "The design for the desktop site was kept as similar as possible to the current design, but the design was ported to bootstrap 3.x and made responsive.",
                            skills: [
                                'CSS', 'JavaScript', 'PHP', 'Bootstrap'
                            ],
                            company: 'Fontis'
                        },
                        {
                            id: '0dcbc9a4-9f2a-11e8-ad70-975c4f96174c',
                            title: "Implemented time series data collection and alerting across production infrastructure.",
                            content: "This involved deploying the time series data collection tool 'Prometheus' and accompanying Grafana, Blackbox exporter and Pushgateway onto a Kubernetes cluster, writing Ansible playbooks to install the Prometheus 'exporter' or exposition binaries and configuring Prometheus and the appropriate reverse proxies to serve this data behind HTTPS and basic authentication. It additionally involved outreach in the dev team teaching how to read and understand time series data, particularly with regards to the Prometheus tooling.",
                            skills: [
                                'Prometheus', 'Kubernetes', 'Ansible', 'Communication'
                            ],
                            company: 'Sitewards'
                        },
                        {
                            id: 'c0983938-9f29-11e8-9c36-7330ad0c79b4',
                            title: "Deploy a backup strategy for Kubernetes based on LVM snapshots",
                            content: "This involved finding and working with a package maintainer to implement a tool that made disk snapshots on a schedule defined on disk metadata.",
                            skills: [
                                'Kubernetes', 'Helm', 'Python'
                            ],
                            company: 'Sitewards'
                        },
                        {
                            id: 'd330bd54-9f29-11e8-94c4-2fdbc8df2dee',
                            title: "Create continuous delivery pipelines based on Kubernetes, Ansible",
                            content: "This involved creating a multi-step pipeline based on the BitBucket pipelines product. Specific issues that required solving were ensuring idempotency and reproducability with the build, allowing deployment to multiple environments, allowing tearing down of created environments, delivering to production safely and reliably and allowing automated restoration of production systems in the case of build failure.",
                            skills: [
                                "Ansible", "Kubernetes", "Pipelines", "Bash", "Python"
                            ],
                            company: 'Sitewards'
                        },
                        {
                            id: '762ec4ce-4178-4664-9e68-e96b0e4a9c93',
                            title: 'Implement image optimisation based on browser window size',
                            content: 'During a periodic analysis of a web service with the tool "Lighthouse", it was determined that the images are improperly sized given the bounds they\'re displayed in. To resolve this, the image proxy "Thumbor" was implemented, generating images that were stripped and degraded to reduce their size. Additionally and where possible, images were sized based on the Client Hints device width specification to further reduce the page weight.',
                            skills: [
                                'Web', 'Python', 'Ansible', 'Thumbor', 'JavaScript', 'Lighthouse'
                            ],
                            company: 'Sitewards'
                        },
                        {
                            id: 'b8a7dd8c-a2c6-11e8-acb0-e7514a582152',
                            title: 'Completed the "Certified Kubernetes Administrator" exam',
                            content: 'As part of an effort to further increase adoption of the Kubernetes software orchestration tooling and to demonstrate capability to executive stakeholders I completed the "Certified Kubernetes Administrator" exam. Additionally, I am helping others to prepare and take the exam within the next 12 months.',
                            skills: [
                                'Kubernetes', 'Linux'
                            ],
                            company: 'Sitewards'
                        },
                        {
                            id: '28c05860-a2c7-11e8-996b-d7568421bdfc',
                            title: 'Diagnosed silent network failures that allowed MySQL replication to lag out of sync',
                            content: 'One of the replicated databases operated as part of the infrastructure periodically failed to replicate until it drifted so far out of sync it needed to be manually reconciled. This involved doing a TCPDump of the connection, spotting the TCP RST and seeing that MySQL did not detect the connection, still waiting on "Waiting for master to send event". Further investigation determined this happened after a long period without any other traffic, and that the issue is fairly common with the AWS stateful firewall pruning connections. The solution was to reduce the heartbeat for the SQL connection to ~60 seconds.',
                            skills: [
                                'MySQL', 'Amazon Web Services', 'Networking'
                            ],
                            company: 'Sitewards'
                        },
                        {
                            id: 'b3e28e5c-a2c9-11e8-b1a6-fb2ee9838b59',
                            title: 'Started writing content on a Medium blog',
                            content: 'As part of ongoing efforts to impart knowledge to other colleagues and to increase the perception of both personal and corporate technical competence I started writing articles of a fairly technical nature on Medium. These have proven extremely useful in internal discussions as well as have a monthly readership of > 1000 people.',
                            skills: [
                                'English', 'Writing', 'Communication'
                            ],
                            company: 'Sitewards'
                        },
                        {
                            id: 'b3e28e5c-a2c9-11e8-b1a6-fb2ee9838b59',
                            title: 'Assisted in general preparation for the General Data Protection Regulation',
                            content: 'With the GDPR being enforceable from May 1st, 2018 a general audit was conducted of company software, systems and processes to determine whether there were any safety and privacy violations. Though the audit showed nothing serious, various improvements were made to data anonymisation and various software systems that employees had picked up without clear privacy policies were migrated to other software systems. A list of all software was written and is maintained, and data protection agreements signed with all software suppliers. Lastly, stricter guidelines were written for the use of work computers, limiting their personal use to prevent the inadvertent leakage of customer data to third party services.',
                            skills: [
                                'Security', 'Communication', 'Legal'
                            ],
                            company: 'Sitewards'
                        },
                        {
                            id: 'd0d60d6c-a2ca-11e8-8e46-3362eeff117d',
                            title: 'Transitioned between teams',
                            content: 'As part of ongoing professional development I\'ve been able to develop a reasonable expertise in systems administration. This expertise was a better fit for another, larger project and I was thus transferred. This involved handing over the project to other colleagues and ensuring they understood and could debug all systems associated. This was largely smooth due to the habit of ongoing documentation for all changes in git, and a limited amount of documentation during the transition betwen projects.',
                            skills: [
                                'Communication'
                            ],
                            company: 'Sitewards'
                        }
                    ]
                }
            }
        }
    }
}

window.customElements.define('ahc-portfolio', AhcPortfolio);
<commit_msg>AD-HOC feat (Portfolio): Add external links to various reference for portfolio<commit_after>/**
 * Copyright (c) 2018 Andrew Howden. All rights reserved.
 *
 * This copyright does not apply where other licenses override it.
 */

import { html } from '@polymer/lit-element';
import { PageViewElement } from './page-view-element.js';

// These are the shared styles needed by this element.
import { SharedStyles } from './shared-styles.js';

// These are the elements needed by this element
import '@polymer/iron-flex-layout/iron-flex-layout.js';
import '@polymer/iron-icon/iron-icon.js';
import '@polymer/iron-icons/iron-icons.js';
import '@polymer/paper-card/paper-card.js';
import '@polymer/paper-button/paper-button.js';

import { repeat} from 'lit-html/lib/repeat.js';

class AhcPortfolio extends PageViewElement {
    _render(props) {
       return html`${SharedStyles}
       <custom-style>

       </custom-style>

         ${repeat(AhcPortfolio.properties.portfolio.value(), (i) => html`
             <paper-card heading="${i.title}">

${i.content}

${i.links ? 'Further details available at:': ''}

${i.links ? repeat(i.links, (j) => html`<li><a href="${j.href}" target="_blank" rel="noopener">${j.caption}</a>`) : ''}

               <iron-icon src="/images/icons/skills.png"></iron-icon>${i.skills.join(', ')}

               <iron-icon icon="icons:home"></iron-icon>${i.company}

             </paper-card>
         `)}

       `
    }

    static get properties() {
        return {
            active: Boolean,
            portfolio: {
                value() {
                    return [
                        {
                            id: 'a2d603bc-9f29-11e8-8e33-931c0083bdde',
                            title: "Port the MageAudit Magento analysis tool from Laravel 2 to Magento 1.x",
                            content: 'Most of the analysis existed, however the initial design had some inefficient designs, and the opportunity was taken to restructure the design to make additional analysis far easier to implement in future. MageAudit is still operating to this day.',
                            skills: [
                                'PHP', 'Magento'
                            ],
                            links: [
                                {
                                    caption: 'The MageAudit tool',
                                    href: 'https://www.fontis.com.au/mageaudit'
                                },
                                {
                                    caption: 'The MageAudit release blog',
                                    href: 'https://www.fontis.com.au/blog/mageaudit-updated-report-history'
                                }
                            ],
                            company: 'Fontis'
                        },
                        {
                            id: 'ad0c02c8-9f29-11e8-94a5-bb7f01112aaf',
                            title: "Drafted the incident response framework, structuring crisis management response",
                            content: "This involved creating the processes for declaring an 'incident', managing staff reallocation for the crisis and creating effective post-mortems to prevent issue recurrence. This framework has been used successfully for over a year to manage a wide variety of unexpected but critical system failures with minimal stress, clear communication with stakeholders and a systematic reduction of risk across otherwise risky systems.",
                            skills: [
                                'Communication', 'Crisis Management'
                            ],
                            links: [
                                {
                                    caption: 'An explanation of the incident response process',
                                    href: 'https://medium.com/sitewards/i-hereby-declare-this-an-incident-4219ba2573a6'
                                },
                                {
                                    caption: 'A gentle introduction to post mortems to be systematic about finding issues',
                                    href: 'https://medium.com/@andrewhowdencom/trust-me-i-know-what-im-doing-8d36de464dc4'
                                }
                            ],
                            company: 'Sitewards'
                        },
                        {
                            id: '1b04d05a-a2b5-11e8-9fbc-4fb2b8fda64f',
                            title: "Collaboratively detect, analyse and remediate a compromised machine",
                            content: "This started as a routine investigation into unscheduled unavailability for > 5 minutes, triggering an alert. The unavailability was traced to a reboot, which was in turn triggered by a malicious actor to gain persistent root privileges. Detection involved scanning through the system log until we detected hardware USB insert events, at which point the data center was called for further information. Having no physical access recorded to the device, we discovered the IMPI interface and promptly disabled it. Remediation involved reflashing the machine with a new copy of the operating system, and using an Ansible definition to restore the machine to a known good state. The unauthorised access was detected and removed within approximately 3 hours, thanks to previously implemented time series data monitoring. Follow up work implemented the system monitoring tooling 'Falco', the remote analysis tool 'OSQuery' as well as log aggregation and other system utilities.",
                            skills: [
                                'Linux', 'Ansible', 'Security'
                            ],
                            links: [
                                {
                                    caption: 'A gentle introduction to evaluating security',
                                    href: 'https://medium.com/sitewards/am-i-secure-b080aff2fe17'
                                },
                                {
                                    caption: 'A description of our obligation to keep data safe with reference to the GDPR',
                                    href: 'https://medium.com/sitewards/on-the-obligation-under-gpdr-to-handle-data-safely-eac9831c0e83'
                                }
                            ],
                            company: 'Sitewards'
                        },
                        {
                            id: 'b3acb762-9f29-11e8-bd6e-6b6aee3a319c',
                            title: "Writing an Ansible specification for deploying Kubernetes onto a CoreOS Cluster on Google Cloud",
                            content: "Still ongoing, but the goal is to have a Kubernetes stack that can be run on anything from bare metal to a cloud provider. This involved creating and understanding Systemd service units and how to drain CoreOS nodes of their Kubernetes workloads prior to the automated reboot scheduled by system upgrades.",
                            skills: [
                                'Ansible', 'CoreOS', 'Kubernetes', 'Linux'
                            ],
                            company: 'Fontis'
                        },
                        {
                            id: 'b8639f5a-9f29-11e8-9a4b-333f4fa17870',
                            title: "Redesign of the Bing Lee checkout",
                            content: "A complete reimplementation of a one step checkout, requiring as little information from the user as is required by the other information specified during the checkout. This required considerable restructuring of Magentos core validation logic, additional validation and reasonably complex implementation of various JavaScript driven features.",
                            skills: [
                                'JavaScript', 'PHP', 'Magento'
                            ],
                            links: [
                                {
                                    caption: 'The Bing Lee eCommerce store',
                                    href: 'https://www.binglee.com.au/'
                                }
                            ],
                            company: 'Fontis'
                        },
                        {
                            id: 'bc83b02a-9f29-11e8-94a9-dba2c3dad045',
                            title: "Rebuilding the GAZ MAN website as a mobile first website",
                            content: "The design for the desktop site was kept as similar as possible to the current design, but the design was ported to bootstrap 3.x and made responsive.",
                            skills: [
                                'CSS', 'JavaScript', 'PHP', 'Bootstrap'
                            ],
                            links: [
                                {
                                    caption: 'The GAZ MAN eCommerce store',
                                    href: 'https://www.gazman.com.au/'
                                }
                            ],
                            company: 'Fontis'
                        },
                        {
                            id: '0dcbc9a4-9f2a-11e8-ad70-975c4f96174c',
                            title: "Implemented time series data collection and alerting across production infrastructure.",
                            content: "This involved deploying the time series data collection tool 'Prometheus' and accompanying Grafana, Blackbox exporter and Pushgateway onto a Kubernetes cluster, writing Ansible playbooks to install the Prometheus 'exporter' or exposition binaries and configuring Prometheus and the appropriate reverse proxies to serve this data behind HTTPS and basic authentication. It additionally involved outreach in the dev team teaching how to read and understand time series data, particularly with regards to the Prometheus tooling.",
                            skills: [
                                'Prometheus', 'Kubernetes', 'Ansible', 'Communication'
                            ],
                            links: [
                                {
                                    caption: 'A guide to implementing Prometheus across disparate systems',
                                    href: 'https://medium.com/sitewards/one-approach-to-implementing-prometheus-across-disparate-systems-b87f2009b8be'
                                }
                            ],
                            company: 'Sitewards'
                        },
                        {
                            id: 'c0983938-9f29-11e8-9c36-7330ad0c79b4',
                            title: "Deploy a backup strategy for Kubernetes based on LVM snapshots",
                            content: "This involved finding and working with a package maintainer to implement a tool that made disk snapshots on a schedule defined on disk metadata.",
                            skills: [
                                'Kubernetes', 'Helm', 'Python'
                            ],
                            company: 'Sitewards'
                        },
                        {
                            id: 'd330bd54-9f29-11e8-94c4-2fdbc8df2dee',
                            title: "Create continuous delivery pipelines based on Kubernetes, Ansible",
                            content: "This involved creating a multi-step pipeline based on the BitBucket pipelines product. Specific issues that required solving were ensuring idempotency and reproducability with the build, allowing deployment to multiple environments, allowing tearing down of created environments, delivering to production safely and reliably and allowing automated restoration of production systems in the case of build failure.",
                            skills: [
                                "Ansible", "Kubernetes", "Pipelines", "Bash", "Python"
                            ],
                            links: [
                                {
                                    caption: 'A description of the release pipeline, including CI/CD',
                                    href: 'https://medium.com/sitewards/one-take-on-release-management-20dc202e8762'
                                }
                            ],
                            company: 'Sitewards'
                        },
                        {
                            id: '762ec4ce-4178-4664-9e68-e96b0e4a9c93',
                            title: 'Implement image optimisation based on browser window size',
                            content: 'During a periodic analysis of a web service with the tool "Lighthouse", it was determined that the images are improperly sized given the bounds they\'re displayed in. To resolve this, the image proxy "Thumbor" was implemented, generating images that were stripped and degraded to reduce their size. Additionally and where possible, images were sized based on the Client Hints device width specification to further reduce the page weight.',
                            skills: [
                                'Web', 'Python', 'Ansible', 'Thumbor', 'JavaScript', 'Lighthouse'
                            ],
                            company: 'Sitewards'
                        },
                        {
                            id: 'b8a7dd8c-a2c6-11e8-acb0-e7514a582152',
                            title: 'Completed the "Certified Kubernetes Administrator" exam',
                            content: 'As part of an effort to further increase adoption of the Kubernetes software orchestration tooling and to demonstrate capability to executive stakeholders I completed the "Certified Kubernetes Administrator" exam. Additionally, I am helping others to prepare and take the exam within the next 12 months.',
                            skills: [
                                'Kubernetes', 'Linux'
                            ],
                            links: [
                                {
                                    caption: 'Some notes about making production simpler with containers',
                                    href: 'https://medium.com/sitewards/simpler-production-with-containers-f9b355087b12'
                                }
                            ],
                            company: 'Sitewards'
                        },
                        {
                            id: '28c05860-a2c7-11e8-996b-d7568421bdfc',
                            title: 'Diagnosed silent network failures that allowed MySQL replication to lag out of sync',
                            content: 'One of the replicated databases operated as part of the infrastructure periodically failed to replicate until it drifted so far out of sync it needed to be manually reconciled. This involved doing a TCPDump of the connection, spotting the TCP RST and seeing that MySQL did not detect the connection, still waiting on "Waiting for master to send event". Further investigation determined this happened after a long period without any other traffic, and that the issue is fairly common with the AWS stateful firewall pruning connections. The solution was to reduce the heartbeat for the SQL connection to ~60 seconds.',
                            skills: [
                                'MySQL', 'Amazon Web Services', 'Networking'
                            ],
                            company: 'Sitewards'
                        },
                        {
                            id: 'b3e28e5c-a2c9-11e8-b1a6-fb2ee9838b59',
                            title: 'Started writing content on a Medium blog',
                            content: 'As part of ongoing efforts to impart knowledge to other colleagues and to increase the perception of both personal and corporate technical competence I started writing articles of a fairly technical nature on Medium. These have proven extremely useful in internal discussions as well as have a monthly readership of > 1000 people.',
                            skills: [
                                'English', 'Writing', 'Communication'
                            ],
                            links: [
                                {
                                    caption: 'The personal Medium blog',
                                    href: 'http://medium.com/@andrewhowdencom'
                                },
                                {
                                    caption: 'The Sitewards Medium blog',
                                    href: 'https://medium.com/sitewards'
                                }
                            ],
                            company: 'Sitewards'
                        },
                        {
                            id: 'b3e28e5c-a2c9-11e8-b1a6-fb2ee9838b59',
                            title: 'Assisted in general preparation for the General Data Protection Regulation',
                            content: 'With the GDPR being enforceable from May 1st, 2018 a general audit was conducted of company software, systems and processes to determine whether there were any safety and privacy violations. Though the audit showed nothing serious, various improvements were made to data anonymisation and various software systems that employees had picked up without clear privacy policies were migrated to other software systems. A list of all software was written and is maintained, and data protection agreements signed with all software suppliers. Lastly, stricter guidelines were written for the use of work computers, limiting their personal use to prevent the inadvertent leakage of customer data to third party services.',
                            skills: [
                                'Security', 'Communication', 'Legal'
                            ],
                            links: [
                                {
                                    caption: 'A discussion about our responsibilities as development teams',
                                    href: 'https://medium.com/sitewards/your-services-our-computers-83a964992930'
                                }
                            ],
                            company: 'Sitewards'
                        },
                        {
                            id: 'd0d60d6c-a2ca-11e8-8e46-3362eeff117d',
                            title: 'Transitioned between teams',
                            content: 'As part of ongoing professional development I\'ve been able to develop a reasonable expertise in systems administration. This expertise was a better fit for another, larger project and I was thus transferred. This involved handing over the project to other colleagues and ensuring they understood and could debug all systems associated. This was largely smooth due to the habit of ongoing documentation for all changes in git, and a limited amount of documentation during the transition betwen projects.',
                            skills: [
                                'Communication'
                            ],
                            links: [
                                {
                                    caption: 'Arguments for storing documentation canonically in version control',
                                    href: 'https://medium.com/sitewards/docs-in-jira-eh-github-mm-git-histories-fuck-yeah-1576cc5a6c39'
                                },
                                {
                                    caption: 'A guide to templating commit messages',
                                    href: 'https://medium.com/sitewards/git-tips-template-your-commit-messages-187d8a2051b8'
                                },
                                {
                                    caption: 'Some notes about the value of git commit messages',
                                    href: 'https://medium.com/sitewards/git-tips-the-memoir-of-commit-messages-7d15ed2205ac'
                                },
                                {
                                    caption: 'Some opinions on what makes a "good" commit message',
                                    href: 'https://medium.com/@andrewhowdencom/anatomy-of-a-good-commit-message-acd9c4490437'
                                }
                            ],
                            company: 'Sitewards'
                        }
                    ]
                }
            }
        }
    }
}

window.customElements.define('ahc-portfolio', AhcPortfolio);
<|endoftext|>


<commit_before>import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import AvatarImage from './AvatarImage';
import AvatarInitials from './AvatarInitials';
import AvatarOverlay from './AvatarOverlay';
import Box, { pickBoxProps } from '../box';
import cx from 'classnames';
import theme from './theme.css';
import { COLORS } from '../../constants';

const hashCode = str => {
  let hash = 0;
  if (!str || str.length === 0) {
    return hash;
  }
  for (let i = 0; i < str.length; i++) {
    const char = str.charCodeAt(i);
    hash = (hash << 5) - hash + char;
    hash &= hash; // Convert to 32bit integer
  }
  return hash;
};

const getColor = id => (id ? COLORS[Math.abs(hashCode(id)) % COLORS.length] : COLORS[0]);

class Avatar extends PureComponent {
  render() {
    const { className, editable, imageUrl, fullName, id, onImageChange, size, shape, ...others } = this.props;
    const avatarClassNames = cx(theme['avatar'], theme[`is-${size}`], theme[`is-${shape}`], className);
    const boxProps = pickBoxProps(others);

    return (
      <Box className={avatarClassNames} {...boxProps}>
        {imageUrl ? (
          <AvatarImage image={imageUrl} imageAlt={fullName} {...others} />
        ) : (
          <AvatarInitials color={getColor(id)} name={fullName} {...others} />
        )}
        {editable && (size === 'large' || size === 'hero') && <AvatarOverlay onClick={onImageChange} />}
      </Box>
    );
  }
}

Avatar.propTypes = {
  /** If true, an overlay will be shown with edit icon. */
  editable: PropTypes.bool,
  /** The image url to show as an avatar. */
  imageUrl: PropTypes.string,
  /** When no image available, avatar initials will be based on this string. */
  fullName: PropTypes.string,
  /** Expects a uuid to determine the avatar initials background color. */
  id: PropTypes.string,
  /** Callback function that is fired when user clicks the edit icon. */
  onImageChange: PropTypes.func,
  /** The shape of the avatar. */
  shape: PropTypes.oneOf(['circle', 'rounded']),
  /** The size of the avatar. */
  size: PropTypes.oneOf(['tiny', 'small', 'medium', 'large', 'hero']),
};

Avatar.defaultProps = {
  shape: 'circle',
  size: 'medium',
};

export default Avatar;
<commit_msg>Change default color from aqua to neutral<commit_after>import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import AvatarImage from './AvatarImage';
import AvatarInitials from './AvatarInitials';
import AvatarOverlay from './AvatarOverlay';
import Box, { pickBoxProps } from '../box';
import cx from 'classnames';
import theme from './theme.css';
import { COLORS } from '../../constants';

const hashCode = str => {
  let hash = 0;
  if (!str || str.length === 0) {
    return hash;
  }
  for (let i = 0; i < str.length; i++) {
    const char = str.charCodeAt(i);
    hash = (hash << 5) - hash + char;
    hash &= hash; // Convert to 32bit integer
  }
  return hash;
};

const getColor = id => (id ? COLORS[Math.abs(hashCode(id)) % COLORS.length] : COLORS[2]);

class Avatar extends PureComponent {
  render() {
    const { className, editable, imageUrl, fullName, id, onImageChange, size, shape, ...others } = this.props;
    const avatarClassNames = cx(theme['avatar'], theme[`is-${size}`], theme[`is-${shape}`], className);
    const boxProps = pickBoxProps(others);

    return (
      <Box className={avatarClassNames} {...boxProps}>
        {imageUrl ? (
          <AvatarImage image={imageUrl} imageAlt={fullName} {...others} />
        ) : (
          <AvatarInitials color={getColor(id)} name={fullName} {...others} />
        )}
        {editable && (size === 'large' || size === 'hero') && <AvatarOverlay onClick={onImageChange} />}
      </Box>
    );
  }
}

Avatar.propTypes = {
  /** If true, an overlay will be shown with edit icon. */
  editable: PropTypes.bool,
  /** The image url to show as an avatar. */
  imageUrl: PropTypes.string,
  /** When no image available, avatar initials will be based on this string. */
  fullName: PropTypes.string,
  /** Expects a uuid to determine the avatar initials background color. */
  id: PropTypes.string,
  /** Callback function that is fired when user clicks the edit icon. */
  onImageChange: PropTypes.func,
  /** The shape of the avatar. */
  shape: PropTypes.oneOf(['circle', 'rounded']),
  /** The size of the avatar. */
  size: PropTypes.oneOf(['tiny', 'small', 'medium', 'large', 'hero']),
};

Avatar.defaultProps = {
  shape: 'circle',
  size: 'medium',
};

export default Avatar;
<|endoftext|>


<commit_before>export default {
  direction: 'horizontal',
  touchEventsTarget: 'container',
  initialSlide: 0,
  speed: 300,
  // autoplay
  autoplay: false,
  autoplayDisableOnInteraction: true,
  autoplayStopOnLast: false,
  // To support iOS's swipe-to-go-back gesture (when being used in-app, with UIWebView).
  iOSEdgeSwipeDetection: false,
  iOSEdgeSwipeThreshold: 20,
  // Free mode
  freeMode: false,
  freeModeMomentum: true,
  freeModeMomentumRatio: 1,
  freeModeMomentumBounce: true,
  freeModeMomentumBounceRatio: 1,
  freeModeMomentumVelocityRatio: 1,
  freeModeSticky: false,
  freeModeMinimumVelocity: 0.02,
  // Autoheight
  autoHeight: false,
  // Set wrapper width
  setWrapperSize: false,
  // Virtual Translate
  virtualTranslate: false,
  // Effects
  effect: 'slide', // 'slide' or 'fade' or 'cube' or 'coverflow' or 'flip'
  coverflow: {
    rotate: 50,
    stretch: 0,
    depth: 100,
    modifier: 1,
    slideShadows: true,
  },
  flip: {
    slideShadows: true,
    limitRotation: true,
  },
  cube: {
    slideShadows: true,
    shadow: true,
    shadowOffset: 20,
    shadowScale: 0.94,
  },
  fade: {
    crossFade: false,
  },
  // Parallax
  parallax: false,
  // Zoom
  zoom: false,
  zoomMax: 3,
  zoomMin: 1,
  zoomToggle: true,
  // Scrollbar
  scrollbar: null,
  scrollbarHide: true,
  scrollbarDraggable: false,
  scrollbarSnapOnRelease: false,
  // Keyboard Mousewheel
  // keyboardControl: false,
  // mousewheelControl: false,
  // mousewheelReleaseOnEdges: false,
  // mousewheelInvert: false,
  // mousewheelForceToAxis: false,
  // mousewheelSensitivity: 1,
  // mousewheelEventsTarged: 'container',
  // Hash Navigation
  hashnav: false,
  hashnavWatchState: false,
  // History
  history: false,
  // Commong Nav State
  replaceState: false,
  // Breakpoints
  breakpoints: undefined,
  // Slides grid
  spaceBetween: 0,
  slidesPerView: 1,
  slidesPerColumn: 1,
  slidesPerColumnFill: 'column',
  slidesPerGroup: 1,
  centeredSlides: false,
  slidesOffsetBefore: 0, // in px
  slidesOffsetAfter: 0, // in px
  // Round length
  roundLengths: false,
  // Touches
  touchRatio: 1,
  touchAngle: 45,
  simulateTouch: true,
  shortSwipes: true,
  longSwipes: true,
  longSwipesRatio: 0.5,
  longSwipesMs: 300,
  followFinger: true,
  onlyExternal: false,
  threshold: 0,
  touchMoveStopPropagation: true,
  touchReleaseOnEdges: false,
  // Unique Navigation Elements
  uniqueNavElements: true,
  // Pagination
  // pagination: null,
  // paginationElement: 'span',
  // paginationClickable: false,
  // paginationHide: false,
  // paginationBulletRender: null,
  // paginationProgressRender: null,
  // paginationFractionRender: null,
  // paginationCustomRender: null,
  // paginationType: 'bullets', // 'bullets' or 'progress' or 'fraction' or 'custom'
  fitSlideGroupWithBlank: false,
  blankClass: 'swiper-invisible-blank-slide',
  // Resistance
  resistance: true,
  resistanceRatio: 0.85,
  // Next/prev buttons
  // nextButton: null,
  // prevButton: null,
  // Progress
  watchSlidesProgress: false,
  watchSlidesVisibility: false,
  // Cursor
  grabCursor: false,
  // Clicks
  preventClicks: true,
  preventClicksPropagation: true,
  slideToClickedSlide: false,
  // Lazy Loading
  lazyLoading: false,
  lazyLoadingInPrevNext: false,
  lazyLoadingInPrevNextAmount: 1,
  lazyLoadingOnTransitionStart: false,
  // Images
  preloadImages: true,
  updateOnImagesReady: true,
  // loop
  loop: false,
  loopAdditionalSlides: 0,
  loopedSlides: null,
  // Control
  control: undefined,
  controlInverse: false,
  controlBy: 'slide', // or 'container'
  normalizeSlideIndex: true,
  // Swiping/no swiping
  allowSwipeToPrev: true,
  allowSwipeToNext: true,
  swipeHandler: null, // '.swipe-handler',
  noSwiping: true,
  noSwipingClass: 'swiper-no-swiping',
  // Passive Listeners
  passiveListeners: true,
  // NS
  containerModifierClass: 'swiper-container-', // NEW
  slideClass: 'swiper-slide',
  slideActiveClass: 'swiper-slide-active',
  slideDuplicateActiveClass: 'swiper-slide-duplicate-active',
  slideVisibleClass: 'swiper-slide-visible',
  slideDuplicateClass: 'swiper-slide-duplicate',
  slideNextClass: 'swiper-slide-next',
  slideDuplicateNextClass: 'swiper-slide-duplicate-next',
  slidePrevClass: 'swiper-slide-prev',
  slideDuplicatePrevClass: 'swiper-slide-duplicate-prev',
  wrapperClass: 'swiper-wrapper',
  // bulletClass: 'swiper-pagination-bullet',
  // bulletActiveClass: 'swiper-pagination-bullet-active',
  // buttonDisabledClass: 'swiper-button-disabled',
  // paginationCurrentClass: 'swiper-pagination-current',
  // paginationTotalClass: 'swiper-pagination-total',
  // paginationHiddenClass: 'swiper-pagination-hidden',
  // paginationProgressbarClass: 'swiper-pagination-progressbar',
  // paginationClickableClass: 'swiper-pagination-clickable', // NEW
  // paginationModifierClass: 'swiper-pagination-', // NEW
  lazyLoadingClass: 'swiper-lazy',
  lazyStatusLoadingClass: 'swiper-lazy-loading',
  lazyStatusLoadedClass: 'swiper-lazy-loaded',
  lazyPreloaderClass: 'swiper-lazy-preloader',
  notificationClass: 'swiper-notification',
  preloaderClass: 'preloader',
  zoomContainerClass: 'swiper-zoom-container',

  // Observer
  observer: false,
  observeParents: false,
  // Accessibility
  a11y: false,
  prevSlideMessage: 'Previous slide',
  nextSlideMessage: 'Next slide',
  firstSlideMessage: 'This is the first slide',
  lastSlideMessage: 'This is the last slide',
  paginationBulletMessage: 'Go to slide {{index}}',
  // Callbacks
  runCallbacksOnInit: true,
  /*
  Callbacks:
  onInit: function (swiper)
  onDestroy: function (swiper)
  onBeforeResize: function (swiper)
  onAfterResize: function (swiper)
  onClick: function (swiper, e)
  onTap: function (swiper, e)
  onDoubleTap: function (swiper, e)
  onSliderMove: function (swiper, e)
  onSlideChangeStart: function (swiper)
  onSlideChangeEnd: function (swiper)
  onTransitionStart: function (swiper)
  onTransitionEnd: function (swiper)
  onImagesReady: function (swiper)
  onProgress: function (swiper, progress)
  onTouchStart: function (swiper, e)
  onTouchMove: function (swiper, e)
  onTouchMoveOpposite: function (swiper, e)
  onTouchEnd: function (swiper, e)
  onReachBeginning: function (swiper)
  onReachEnd: function (swiper)
  onSetTransition: function (swiper, duration)
  onSetTranslate: function (swiper, translate)
  onAutoplayStart: function (swiper)
  onAutoplayStop: function (swiper),
  onLazyImageLoad: function (swiper, slide, image)
  onLazyImageReady: function (swiper, slide, image)
  onKeyPress: function (swiper, keyCode)
  */
};
<commit_msg>Rename allows + add init:true parameter<commit_after>export default {
  init: true,
  direction: 'horizontal',
  touchEventsTarget: 'container',
  initialSlide: 0,
  speed: 300,
  // autoplay
  autoplay: false,
  autoplayDisableOnInteraction: true,
  autoplayStopOnLast: false,
  // To support iOS's swipe-to-go-back gesture (when being used in-app, with UIWebView).
  iOSEdgeSwipeDetection: false,
  iOSEdgeSwipeThreshold: 20,
  // Free mode
  freeMode: false,
  freeModeMomentum: true,
  freeModeMomentumRatio: 1,
  freeModeMomentumBounce: true,
  freeModeMomentumBounceRatio: 1,
  freeModeMomentumVelocityRatio: 1,
  freeModeSticky: false,
  freeModeMinimumVelocity: 0.02,
  // Autoheight
  autoHeight: false,
  // Set wrapper width
  setWrapperSize: false,
  // Virtual Translate
  virtualTranslate: false,
  // Effects
  effect: 'slide', // 'slide' or 'fade' or 'cube' or 'coverflow' or 'flip'
  coverflow: {
    rotate: 50,
    stretch: 0,
    depth: 100,
    modifier: 1,
    slideShadows: true,
  },
  flip: {
    slideShadows: true,
    limitRotation: true,
  },
  cube: {
    slideShadows: true,
    shadow: true,
    shadowOffset: 20,
    shadowScale: 0.94,
  },
  fade: {
    crossFade: false,
  },
  // Parallax
  parallax: false,
  // Zoom
  zoom: false,
  zoomMax: 3,
  zoomMin: 1,
  zoomToggle: true,
  // Scrollbar
  scrollbar: null,
  scrollbarHide: true,
  scrollbarDraggable: false,
  scrollbarSnapOnRelease: false,
  // Keyboard Mousewheel
  // keyboardControl: false,
  // mousewheelControl: false,
  // mousewheelReleaseOnEdges: false,
  // mousewheelInvert: false,
  // mousewheelForceToAxis: false,
  // mousewheelSensitivity: 1,
  // mousewheelEventsTarged: 'container',
  // Hash Navigation
  hashnav: false,
  hashnavWatchState: false,
  // History
  history: false,
  // Commong Nav State
  replaceState: false,
  // Breakpoints
  breakpoints: undefined,
  // Slides grid
  spaceBetween: 0,
  slidesPerView: 1,
  slidesPerColumn: 1,
  slidesPerColumnFill: 'column',
  slidesPerGroup: 1,
  centeredSlides: false,
  slidesOffsetBefore: 0, // in px
  slidesOffsetAfter: 0, // in px
  // Round length
  roundLengths: false,
  // Touches
  touchRatio: 1,
  touchAngle: 45,
  simulateTouch: true,
  shortSwipes: true,
  longSwipes: true,
  longSwipesRatio: 0.5,
  longSwipesMs: 300,
  followFinger: true,
  onlyExternal: false,
  threshold: 0,
  touchMoveStopPropagation: true,
  touchReleaseOnEdges: false,
  // Unique Navigation Elements
  uniqueNavElements: true,
  // Pagination
  // pagination: null,
  // paginationElement: 'span',
  // paginationClickable: false,
  // paginationHide: false,
  // paginationBulletRender: null,
  // paginationProgressRender: null,
  // paginationFractionRender: null,
  // paginationCustomRender: null,
  // paginationType: 'bullets', // 'bullets' or 'progress' or 'fraction' or 'custom'
  fitSlideGroupWithBlank: false,
  blankClass: 'swiper-invisible-blank-slide',
  // Resistance
  resistance: true,
  resistanceRatio: 0.85,
  // Next/prev buttons
  // nextButton: null,
  // prevButton: null,
  // Progress
  watchSlidesProgress: false,
  watchSlidesVisibility: false,
  // Cursor
  grabCursor: false,
  // Clicks
  preventClicks: true,
  preventClicksPropagation: true,
  slideToClickedSlide: false,
  // Lazy Loading
  lazyLoading: false,
  lazyLoadingInPrevNext: false,
  lazyLoadingInPrevNextAmount: 1,
  lazyLoadingOnTransitionStart: false,
  // Images
  preloadImages: true,
  updateOnImagesReady: true,
  // loop
  loop: false,
  loopAdditionalSlides: 0,
  loopedSlides: null,
  // Control
  control: undefined,
  controlInverse: false,
  controlBy: 'slide', // or 'container'
  normalizeSlideIndex: true,
  // Swiping/no swiping
  allowSlidePrev: true,
  allowSlideNext: true,
  swipeHandler: null, // '.swipe-handler',
  noSwiping: true,
  noSwipingClass: 'swiper-no-swiping',
  // Passive Listeners
  passiveListeners: true,
  // NS
  containerModifierClass: 'swiper-container-', // NEW
  slideClass: 'swiper-slide',
  slideActiveClass: 'swiper-slide-active',
  slideDuplicateActiveClass: 'swiper-slide-duplicate-active',
  slideVisibleClass: 'swiper-slide-visible',
  slideDuplicateClass: 'swiper-slide-duplicate',
  slideNextClass: 'swiper-slide-next',
  slideDuplicateNextClass: 'swiper-slide-duplicate-next',
  slidePrevClass: 'swiper-slide-prev',
  slideDuplicatePrevClass: 'swiper-slide-duplicate-prev',
  wrapperClass: 'swiper-wrapper',
  // bulletClass: 'swiper-pagination-bullet',
  // bulletActiveClass: 'swiper-pagination-bullet-active',
  // buttonDisabledClass: 'swiper-button-disabled',
  // paginationCurrentClass: 'swiper-pagination-current',
  // paginationTotalClass: 'swiper-pagination-total',
  // paginationHiddenClass: 'swiper-pagination-hidden',
  // paginationProgressbarClass: 'swiper-pagination-progressbar',
  // paginationClickableClass: 'swiper-pagination-clickable', // NEW
  // paginationModifierClass: 'swiper-pagination-', // NEW
  lazyLoadingClass: 'swiper-lazy',
  lazyStatusLoadingClass: 'swiper-lazy-loading',
  lazyStatusLoadedClass: 'swiper-lazy-loaded',
  lazyPreloaderClass: 'swiper-lazy-preloader',
  notificationClass: 'swiper-notification',
  preloaderClass: 'preloader',
  zoomContainerClass: 'swiper-zoom-container',

  // Observer
  observer: false,
  observeParents: false,
  // Accessibility
  a11y: false,
  prevSlideMessage: 'Previous slide',
  nextSlideMessage: 'Next slide',
  firstSlideMessage: 'This is the first slide',
  lastSlideMessage: 'This is the last slide',
  paginationBulletMessage: 'Go to slide {{index}}',
  // Callbacks
  runCallbacksOnInit: true,
  /*
  Callbacks:
  onInit: function (swiper)
  onDestroy: function (swiper)
  onBeforeResize: function (swiper)
  onAfterResize: function (swiper)
  onClick: function (swiper, e)
  onTap: function (swiper, e)
  onDoubleTap: function (swiper, e)
  onSliderMove: function (swiper, e)
  onSlideChangeStart: function (swiper)
  onSlideChangeEnd: function (swiper)
  onTransitionStart: function (swiper)
  onTransitionEnd: function (swiper)
  onImagesReady: function (swiper)
  onProgress: function (swiper, progress)
  onTouchStart: function (swiper, e)
  onTouchMove: function (swiper, e)
  onTouchMoveOpposite: function (swiper, e)
  onTouchEnd: function (swiper, e)
  onReachBeginning: function (swiper)
  onReachEnd: function (swiper)
  onSetTransition: function (swiper, duration)
  onSetTranslate: function (swiper, translate)
  onAutoplayStart: function (swiper)
  onAutoplayStop: function (swiper),
  onLazyImageLoad: function (swiper, slide, image)
  onLazyImageReady: function (swiper, slide, image)
  onKeyPress: function (swiper, keyCode)
  */
};
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import Dialog from 'material-ui/Dialog';
import RaisedButton from 'material-ui/RaisedButton';
import FlatButton from 'material-ui/FlatButton';
import IconButton from 'material-ui/IconButton';
import SvgIcon from 'material-ui/SvgIcon';
import LinearProgress from 'material-ui/LinearProgress';
import CircularProgress from 'material-ui/CircularProgress';
import ICONS from '../styles/icons';
import FoodItemTable from './foodItemTable';
import ResolveItemTable from './resolveItemTable';
import {
	green500,
	green100,
	red500,
	red100,
} from 'material-ui/styles/colors';
import classNames from 'classnames';
import { connect } from 'react-redux';
import * as actions from '../actions';

const styles = {
	foodItemInput: {
		height: '60px',
		width: '60px',
		borderRadius: 30,
		backgroundColor: '#FFFFFF',
	},
	dialogTitle: {
		width: '100%',
	},
	speechButton: {
		width: '100%',
	},
	actionButtonCancel: {
		width: '50%',
		backgroundColor: red100,
	},
	actionButtonSubmit: {
		width: '50%',
		backgroundColor: green100,
	},
	progressBar: {
		paddingLeft: '5%',
		paddingRight: '5%',
		backgroundColor: '#FFFFFF',
		width: '100%',
	},
	CircularProgress: {
		alignSelf: 'center',
	},
};

class FoodItemInput extends Component {
	constructor(props) {
		super(props);
		this.state = {
			open: false,
			recognitionStarted: false,
			newItemsAdded: false,
			itemsPosted: false,
			newItems: [],
			confirmedItems: {},
			clarifyingItems: [],
			editedItems: [],
		};
		this.discardItems = this.discardItems.bind(this);
		this.handleOpen = this.handleOpen.bind(this);
		this.handleSubmit = this.handleSubmit.bind(this);
		this.handleFinalSubmit = this.handleFinalSubmit.bind(this);
		this.handleCancel = this.handleCancel.bind(this);
		this.handleClose = this.handleClose.bind(this);
		this.handleCancel = this.handleCancel.bind(this);
		this.speechRecognitionInit = this.speechRecognitionInit.bind(this);
		this.startSpeechRecognition = this.startSpeechRecognition.bind(this);
		this.endSpeechRecognition = this.endSpeechRecognition.bind(this);
		this.renderTable = this.renderTable.bind(this);
		this.handleEditing = this.handleEditing.bind(this);
	}

	discardItems(item) {
		console.log('item passed into discardItems is : ', item);
		const bool = this.state.confirmedItems[item];
		console.log('bool is : ', bool);
		this.setState({
			confirmedItems: {
				...this.state.confirmedItems,
				[item]: !bool,
			},
		}, () => {
			console.log('result of this.setState in discardItems is : ', this.state);
		});
		// confirmedItems[item] = !confirmedItems[item];
		// console.log('Discarded Items', confirmedItems);
		console.log('Discarded items are : ', this.state.confirmedItems);
	}

	startSpeechRecognition() {
		this.setState({
			recognitionStarted: true,
		}, this.recognition.start());
	}

	endSpeechRecognition() {
		this.setState({
			recognitionStarted: false,
		}, this.recognition.stop());
	}

	speechRecognitionInit() {
		/* eslint-disable */
		const SpeechRecognition = webkitSpeechRecognition;
		this.recognition = new SpeechRecognition();
		this.Kate = window.speechSynthesis;
		/* eslint-enable */

		// const SpeechGrammarList = webkitSpeechGrammarList;
		// const SpeechRecognitionEvent = SpeechRecognitionEvent;
		// const recognition = new SpeechGrammarList();
		// const speechRecognitionList = new SpeechGrammarList();
		// speechRecognitionList.addFromString(grammar, 1);
		this.recognition.interimResults = false;

		// let speechFlag = false;
		// const speechResults = [];

		this.recognition.onresult = (event) => {
			for (let i = event.resultIndex; i < event.results.length; ++i) {
				const identificated = event.results[i][0].transcript;
				if (event.results[i].isFinal) {
					console.log('Final sentence is : ', identificated);
					const tempRes = identificated.split('next');
					// function handling edge cases goes here
					const cleanList = this.listErrorHandling(tempRes);
					const itemsObject = {};
					cleanList.forEach(item => {
						// confirmedItems[item] = true;
						itemsObject[item] = true;
					});
					this.setState({
						confirmedItems: { ...this.state.confirmedItems, ...itemsObject },
					}, () => {
						console.log('result of this.setState in recognition on result is : ', this.state.confirmedItems);
					});
					const itemsToAdd = [...this.state.newItems, ...cleanList];
					this.setState({ newItems: itemsToAdd, newItemsAdded: true });
					console.log('this is state.newItems: ', this.state.newItems);
				} else {
					console.log('I understood : ', identificated);
				}
			}
		};

		this.recognition.onstart = () => {
			console.log('this.recognition.onstart fired');
		};
		this.recognition.onend = () => {
			console.log('this.recognition.onend fired');
			this.recognition.stop();
			const voices = window.speechSynthesis.getVoices();
			const areYouFinished = new SpeechSynthesisUtterance('Are you finished?');
			areYouFinished.voice = voices[20];
			areYouFinished.rate = 0.9;
			areYouFinished.pitch = 0.8;

			const finishedRecognition = new SpeechRecognition();
			setTimeout(() => {
				this.Kate.speak(areYouFinished);
				setTimeout(() => {
					finishedRecognition.start();
					setTimeout(() => {
						finishedRecognition.onresult = (evt) => {
							console.log('event is : ', evt);
							console.log('event on finishedRecognition onend is : ', evt.results[0][0].transcript);
							const result = evt.results[0][0].transcript.toLowerCase();
							if (result === 'yes' || result === 'yeah' || result === 'yup') {
								finishedRecognition.stop();
								this.endSpeechRecognition();
							} else {
								finishedRecognition.stop();
								this.startSpeechRecognition();
							}
						};
					}, 0);
				}, 650);
			}, 500);
		};
	}

	// make an array out of the Speech user input
	// map that array to the component state
	listErrorHandling(list) {
		const list1 = list.map(item => {
			if (item !== '' && item !== undefined) {
				// takes out all white space on front and end of string
				const tempItem = item.split(' ');
				if (item[0] === ' ') {
					tempItem.shift();
				}
				if (item[item.length - 1] === ' ') {
					tempItem.pop();
				}
				// capitalizes first char in each word of item
				for (let i = 0; i < tempItem.length; i++) {
					const arr = tempItem[i].split('');
					if (arr[0] !== undefined) {
						arr[0] = arr[0].toUpperCase();
						tempItem[i] = arr.join('');
					}
				}
				return tempItem.join(' ');
			}
			return '';
		});
		// splices out all empty strings
		for (let i = 0; i < list1.length; i++) {
			const curr = list1[i];
			if (curr === '') {
				list1.splice(i, 1);
				i--;
			}
		}
		return list1;
	}

	handleOpen() {
		this.speechRecognitionInit();
		this.setState({ open: true });
	}

	handleClose() {
		this.setState({ open: false });
	}

	handleCancel() {
		this.setState({ open: false, newItems: [], newItemsAdded: false });
	}

	handleSubmit() {
		const submitObject = { ...this.state.confirmedItems, length: this.state.newItems.length };
		// confirmedItems.length = this.state.newItems.length;
		this.props.submitFoods(submitObject);

		// handleSubmit should not close modal immediately, as user needs to verify results
		this.setState({ newItems: [], newItemsAdded: false, itemsPosted: true, confirmedItems: {} });
		// this.setState({ open: false, newItems: [], newItemsAdded: false, confirmedItems: {} });
	}

	handleEditing(editedItems) {
		this.setState({
			editedItems,
		});
	}

	handleFinalSubmit() {
		console.log('handleFinalSubmit called in foodItemInput');
		let flag = true;
		const foodItems = this.state.editedItems;
		for (let i = 0; i < foodItems.length; i++) {
			if (!foodItems[i].expiration || !foodItems[i].foodGroup) {
				flag = false;
			}
		}
		if (flag) {
			console.log('no errors in handleFinalSubmit');
			this.props.resolveIceboxItems({ foodItems });
			setTimeout(() => {
				this.setState({
					newItems: [],
					newItemsAdded: false,
					clarifyingItems: [],
					editedItems: [],
					open: false,
				});
			}, 1000);
		}
	}

	renderDialogBody() {
		if (!this.state.recognitionStarted && !this.state.newItemsAdded
				&& this.props.noExpirationItems.length === 0 && this.props.noFoodGroupItems.length === 0) {
			return (

 Read the names of your foods out loud, as you load them into the refrigerator.

 After each food say "next" and when you are done say "end" like this:

"Tomatoes..next..Milk..next..Chicken...end"

			);
		} else if (this.state.recognitionStarted) {
			return <LinearProgress mode="indeterminate" style={styles.progressBar} />;
		} else if (this.props.noExpirationItems.length > 0 || this.props.noFoodGroupItems.length > 0) {
			return (

 We were unable to find some of the items you tried to add,

 could you give us a hand and fill out the missing fields below?

 Once you're finished, please hit the green submit button!

			);
		}
		return

;
	}

	renderActions() {
		if (this.props.noExpirationItems.length === 0 && this.props.noFoodGroupItems.length === 0) {
			return (!this.state.recognitionStarted) ? (
				<RaisedButton
					label="Start Input"
					className={classNames('animated pulse start-speech-input')}
					onTouchTap={this.startSpeechRecognition}
					backgroundColor={green500}
					style={styles.speechButton}
					icon={
						<SvgIcon className="icebox-toolbar-svgicon-speech">
							<path d={ICONS.Speech.d} />
						</SvgIcon>
					}
				/>
			) : (
				<RaisedButton
					label="End Input"
					className={classNames('animated pulse end-speech-input')}
					onTouchTap={this.endSpeechRecognition}
					backgroundColor={red500}
					style={styles.speechButton}
					icon={
						<SvgIcon className="icebox-toolbar-svgicon-speech">
							<path d={ICONS.Speech.d} />
						</SvgIcon>
					}
				/>
			);
		}
		return
;
	}

	renderTable() {
		let clarifyingItems = [...this.props.noExpirationItems, ...this.props.noFoodGroupItems];
		clarifyingItems = clarifyingItems.map(item => ({ ...item, toggled: true }));

		if (this.state.newItems.length > 0) {
			return <FoodItemTable items={this.state.newItems} discarded={this.discardItems} />;
		} else if (this.props.noExpirationItems.length > 0 || this.props.noFoodGroupItems.length > 0) {
			// this.setState({
			// 	clarifyingItems,
			// });
			return (
				<ResolveItemTable
					items={clarifyingItems}
					discarded={this.discardItems}
					handleEditing={this.handleEditing}
				/>
			);
		}
		return
;
	}

	renderModalBody() {
		console.log('renderModalBody, this.props.isLoading is : ', this.props.isLoading);
		return (!this.props.isLoading) ? (

					{this.renderActions()}

				{this.renderDialogBody()}

				{this.renderTable()}

		) : (
			<CircularProgress style={styles.CircularProgress} size={4} />
		);
	}

	render() {
		const preSubmit = [
			<FlatButton
				label="Cancel"
				style={styles.actionButtonCancel}
				onTouchTap={this.handleCancel}
			/>,
			<FlatButton
				label="Submit"
				style={styles.actionButtonSubmit}
				disabled={!this.state.newItemsAdded}
				onTouchTap={this.handleSubmit}
			/>,
		];

		const postSubmit = [
			<FlatButton
				label="Cancel"
				style={styles.actionButtonCancel}
				onTouchTap={this.handleCancel}
			/>,
			<FlatButton
				label="Submit"
				style={styles.actionButtonSubmit}
				onTouchTap={this.handleFinalSubmit}
			/>,
		];

		const renderDialogActions = () => (
			(!this.state.itemsPosted
				&& this.props.noExpirationItems.length === 0
				&& this.props.noFoodGroupItems.length === 0) ? preSubmit : postSubmit
		);

		return (

				<IconButton
					tooltip="Speech"
					tooltipPosition="bottom-center"
					className="icebox-toolbar-speech"
					iconStyle={{ width: '48px', height: '48px' }}
					style={{ width: '60px', height: '60px', padding: 0 }}
					label="Dialog"
					onTouchTap={this.handleOpen}
				>
					<SvgIcon className="icebox-toolbar-svgicon-speech">
						<path d={ICONS.Speech.d} />
					</SvgIcon>
				</IconButton>
				<Dialog
					actions={renderDialogActions()}
					modal={false}
					open={this.state.open}
					onRequestClose={this.handleClose}
					autoScrollBodyContent
				>
					{this.renderModalBody()}
				</Dialog>

		);
	}
}
/*

	{this.renderActions()}

{this.renderDialogBody()}

<FoodItemTable items={this.state.newItems} discarded={this.discardItems} />
*/

FoodItemInput.propTypes = {
	submitFoods: React.PropTypes.func,
	isLoading: React.PropTypes.bool,
	noExpirationItems: React.PropTypes.array,
	noFoodGroupItems: React.PropTypes.array,
	resolveIceboxItems: React.PropTypes.func,
};

const mapStateToProps = (state) => ({
	isLoading: state.loading,
	noExpirationItems: state.icebox.noExpirationItems,
	noFoodGroupItems: state.icebox.noFoodGroupItems,
});

export default connect(mapStateToProps, actions)(FoodItemInput);

<commit_msg>[fix] adds itemsPosted conditional to renderActions method in foodItemInput component<commit_after>import React, { Component } from 'react';
import Dialog from 'material-ui/Dialog';
import RaisedButton from 'material-ui/RaisedButton';
import FlatButton from 'material-ui/FlatButton';
import IconButton from 'material-ui/IconButton';
import SvgIcon from 'material-ui/SvgIcon';
import LinearProgress from 'material-ui/LinearProgress';
import CircularProgress from 'material-ui/CircularProgress';
import ICONS from '../styles/icons';
import FoodItemTable from './foodItemTable';
import ResolveItemTable from './resolveItemTable';
import {
	green500,
	green100,
	red500,
	red100,
} from 'material-ui/styles/colors';
import classNames from 'classnames';
import { connect } from 'react-redux';
import * as actions from '../actions';

const styles = {
	foodItemInput: {
		height: '60px',
		width: '60px',
		borderRadius: 30,
		backgroundColor: '#FFFFFF',
	},
	dialogTitle: {
		width: '100%',
	},
	speechButton: {
		width: '100%',
	},
	actionButtonCancel: {
		width: '50%',
		backgroundColor: red100,
	},
	actionButtonSubmit: {
		width: '50%',
		backgroundColor: green100,
	},
	progressBar: {
		paddingLeft: '5%',
		paddingRight: '5%',
		backgroundColor: '#FFFFFF',
		width: '100%',
	},
	CircularProgress: {
		alignSelf: 'center',
	},
};

class FoodItemInput extends Component {
	constructor(props) {
		super(props);
		this.state = {
			open: false,
			recognitionStarted: false,
			newItemsAdded: false,
			itemsPosted: false,
			newItems: [],
			confirmedItems: {},
			clarifyingItems: [],
			editedItems: [],
		};
		this.discardItems = this.discardItems.bind(this);
		this.handleOpen = this.handleOpen.bind(this);
		this.handleSubmit = this.handleSubmit.bind(this);
		this.handleFinalSubmit = this.handleFinalSubmit.bind(this);
		this.handleCancel = this.handleCancel.bind(this);
		this.handleClose = this.handleClose.bind(this);
		this.handleCancel = this.handleCancel.bind(this);
		this.speechRecognitionInit = this.speechRecognitionInit.bind(this);
		this.startSpeechRecognition = this.startSpeechRecognition.bind(this);
		this.endSpeechRecognition = this.endSpeechRecognition.bind(this);
		this.renderTable = this.renderTable.bind(this);
		this.handleEditing = this.handleEditing.bind(this);
	}

	discardItems(item) {
		console.log('item passed into discardItems is : ', item);
		const bool = this.state.confirmedItems[item];
		console.log('bool is : ', bool);
		this.setState({
			confirmedItems: {
				...this.state.confirmedItems,
				[item]: !bool,
			},
		}, () => {
			console.log('result of this.setState in discardItems is : ', this.state);
		});
		// confirmedItems[item] = !confirmedItems[item];
		// console.log('Discarded Items', confirmedItems);
		console.log('Discarded items are : ', this.state.confirmedItems);
	}

	startSpeechRecognition() {
		this.setState({
			recognitionStarted: true,
		}, this.recognition.start());
	}

	endSpeechRecognition() {
		this.setState({
			recognitionStarted: false,
		}, this.recognition.stop());
	}

	speechRecognitionInit() {
		/* eslint-disable */
		const SpeechRecognition = webkitSpeechRecognition;
		this.recognition = new SpeechRecognition();
		this.Kate = window.speechSynthesis;
		/* eslint-enable */

		// const SpeechGrammarList = webkitSpeechGrammarList;
		// const SpeechRecognitionEvent = SpeechRecognitionEvent;
		// const recognition = new SpeechGrammarList();
		// const speechRecognitionList = new SpeechGrammarList();
		// speechRecognitionList.addFromString(grammar, 1);
		this.recognition.interimResults = false;

		// let speechFlag = false;
		// const speechResults = [];

		this.recognition.onresult = (event) => {
			for (let i = event.resultIndex; i < event.results.length; ++i) {
				const identificated = event.results[i][0].transcript;
				if (event.results[i].isFinal) {
					console.log('Final sentence is : ', identificated);
					const tempRes = identificated.split('next');
					// function handling edge cases goes here
					const cleanList = this.listErrorHandling(tempRes);
					const itemsObject = {};
					cleanList.forEach(item => {
						// confirmedItems[item] = true;
						itemsObject[item] = true;
					});
					this.setState({
						confirmedItems: { ...this.state.confirmedItems, ...itemsObject },
					}, () => {
						console.log('result of this.setState in recognition on result is : ', this.state.confirmedItems);
					});
					const itemsToAdd = [...this.state.newItems, ...cleanList];
					this.setState({ newItems: itemsToAdd, newItemsAdded: true });
					console.log('this is state.newItems: ', this.state.newItems);
				} else {
					console.log('I understood : ', identificated);
				}
			}
		};

		this.recognition.onstart = () => {
			console.log('this.recognition.onstart fired');
		};
		this.recognition.onend = () => {
			console.log('this.recognition.onend fired');
			this.recognition.stop();
			const voices = window.speechSynthesis.getVoices();
			const areYouFinished = new SpeechSynthesisUtterance('Are you finished?');
			areYouFinished.voice = voices[20];
			areYouFinished.rate = 0.9;
			areYouFinished.pitch = 0.8;

			const finishedRecognition = new SpeechRecognition();
			setTimeout(() => {
				this.Kate.speak(areYouFinished);
				setTimeout(() => {
					finishedRecognition.start();
					setTimeout(() => {
						finishedRecognition.onresult = (evt) => {
							console.log('event is : ', evt);
							console.log('event on finishedRecognition onend is : ', evt.results[0][0].transcript);
							const result = evt.results[0][0].transcript.toLowerCase();
							if (result === 'yes' || result === 'yeah' || result === 'yup') {
								finishedRecognition.stop();
								this.endSpeechRecognition();
							} else {
								finishedRecognition.stop();
								this.startSpeechRecognition();
							}
						};
					}, 0);
				}, 650);
			}, 500);
		};
	}

	// make an array out of the Speech user input
	// map that array to the component state
	listErrorHandling(list) {
		const list1 = list.map(item => {
			if (item !== '' && item !== undefined) {
				// takes out all white space on front and end of string
				const tempItem = item.split(' ');
				if (item[0] === ' ') {
					tempItem.shift();
				}
				if (item[item.length - 1] === ' ') {
					tempItem.pop();
				}
				// capitalizes first char in each word of item
				for (let i = 0; i < tempItem.length; i++) {
					const arr = tempItem[i].split('');
					if (arr[0] !== undefined) {
						arr[0] = arr[0].toUpperCase();
						tempItem[i] = arr.join('');
					}
				}
				return tempItem.join(' ');
			}
			return '';
		});
		// splices out all empty strings
		for (let i = 0; i < list1.length; i++) {
			const curr = list1[i];
			if (curr === '') {
				list1.splice(i, 1);
				i--;
			}
		}
		return list1;
	}

	handleOpen() {
		this.speechRecognitionInit();
		this.setState({ open: true });
	}

	handleClose() {
		this.setState({ open: false });
	}

	handleCancel() {
		this.setState({ open: false, newItems: [], newItemsAdded: false });
	}

	handleSubmit() {
		const submitObject = { ...this.state.confirmedItems, length: this.state.newItems.length };
		// confirmedItems.length = this.state.newItems.length;
		this.props.submitFoods(submitObject);

		// handleSubmit should not close modal immediately, as user needs to verify results
		this.setState({ newItems: [], newItemsAdded: false, itemsPosted: true, confirmedItems: {} });
		// this.setState({ open: false, newItems: [], newItemsAdded: false, confirmedItems: {} });
	}

	handleEditing(editedItems) {
		this.setState({
			editedItems,
		});
	}

	handleFinalSubmit() {
		console.log('handleFinalSubmit called in foodItemInput');
		let flag = true;
		const foodItems = this.state.editedItems;
		for (let i = 0; i < foodItems.length; i++) {
			if (!foodItems[i].expiration || !foodItems[i].foodGroup) {
				flag = false;
			}
		}
		if (flag) {
			console.log('no errors in handleFinalSubmit');
			this.props.resolveIceboxItems({ foodItems });
			setTimeout(() => {
				this.setState({
					newItems: [],
					newItemsAdded: false,
					itemsPosted: false,
					clarifyingItems: [],
					editedItems: [],
					open: false,
				});
			}, 1000);
		}
	}

	renderDialogBody() {
		if (!this.state.recognitionStarted && !this.state.newItemsAdded
				&& this.props.noExpirationItems.length === 0 && this.props.noFoodGroupItems.length === 0) {
			return (

 Read the names of your foods out loud, as you load them into the refrigerator.

 After each food say "next" and when you are done say "end" like this:

"Tomatoes..next..Milk..next..Chicken...end"

			);
		} else if (this.state.recognitionStarted) {
			return <LinearProgress mode="indeterminate" style={styles.progressBar} />;
		} else if (this.props.noExpirationItems.length > 0 || this.props.noFoodGroupItems.length > 0) {
			return (

 We were unable to find some of the items you tried to add,

 could you give us a hand and fill out the missing fields below?

 Once you're finished, please hit the green submit button!

			);
		}
		return

;
	}

	renderActions() {
		if (this.props.noExpirationItems.length === 0 && this.props.noFoodGroupItems.length === 0) {
			return (!this.state.recognitionStarted) ? (
				<RaisedButton
					label="Start Input"
					className={classNames('animated pulse start-speech-input')}
					onTouchTap={this.startSpeechRecognition}
					backgroundColor={green500}
					style={styles.speechButton}
					icon={
						<SvgIcon className="icebox-toolbar-svgicon-speech">
							<path d={ICONS.Speech.d} />
						</SvgIcon>
					}
				/>
			) : (
				<RaisedButton
					label="End Input"
					className={classNames('animated pulse end-speech-input')}
					onTouchTap={this.endSpeechRecognition}
					backgroundColor={red500}
					style={styles.speechButton}
					icon={
						<SvgIcon className="icebox-toolbar-svgicon-speech">
							<path d={ICONS.Speech.d} />
						</SvgIcon>
					}
				/>
			);
		}
		return
;
	}

	renderTable() {
		let clarifyingItems = [...this.props.noExpirationItems, ...this.props.noFoodGroupItems];
		clarifyingItems = clarifyingItems.map(item => ({ ...item, toggled: true }));

		if (this.state.newItems.length > 0) {
			return <FoodItemTable items={this.state.newItems} discarded={this.discardItems} />;
		} else if (this.props.noExpirationItems.length > 0 || this.props.noFoodGroupItems.length > 0) {
			// this.setState({
			// 	clarifyingItems,
			// });
			return (
				<ResolveItemTable
					items={clarifyingItems}
					discarded={this.discardItems}
					handleEditing={this.handleEditing}
				/>
			);
		}
		return
;
	}

	renderModalBody() {
		console.log('renderModalBody, this.props.isLoading is : ', this.props.isLoading);
		return (!this.props.isLoading) ? (

					{this.renderActions()}

				{this.renderDialogBody()}

				{this.renderTable()}

		) : (
			<CircularProgress style={styles.CircularProgress} size={4} />
		);
	}

	render() {
		const preSubmit = [
			<FlatButton
				label="Cancel"
				style={styles.actionButtonCancel}
				onTouchTap={this.handleCancel}
			/>,
			<FlatButton
				label="Submit"
				style={styles.actionButtonSubmit}
				disabled={!this.state.newItemsAdded}
				onTouchTap={this.handleSubmit}
			/>,
		];

		const postSubmit = [
			<FlatButton
				label="Cancel"
				style={styles.actionButtonCancel}
				onTouchTap={this.handleCancel}
			/>,
			<FlatButton
				label="Submit"
				style={styles.actionButtonSubmit}
				onTouchTap={this.handleFinalSubmit}
			/>,
		];

		const renderDialogActions = () => (
			(!this.state.itemsPosted
				&& this.props.noExpirationItems.length === 0
				&& this.props.noFoodGroupItems.length === 0) ? preSubmit : postSubmit
		);

		return (

				<IconButton
					tooltip="Speech"
					tooltipPosition="bottom-center"
					className="icebox-toolbar-speech"
					iconStyle={{ width: '48px', height: '48px' }}
					style={{ width: '60px', height: '60px', padding: 0 }}
					label="Dialog"
					onTouchTap={this.handleOpen}
				>
					<SvgIcon className="icebox-toolbar-svgicon-speech">
						<path d={ICONS.Speech.d} />
					</SvgIcon>
				</IconButton>
				<Dialog
					actions={renderDialogActions()}
					modal={false}
					open={this.state.open}
					onRequestClose={this.handleClose}
					autoScrollBodyContent
				>
					{this.renderModalBody()}
				</Dialog>

		);
	}
}
/*

	{this.renderActions()}

{this.renderDialogBody()}

<FoodItemTable items={this.state.newItems} discarded={this.discardItems} />
*/

FoodItemInput.propTypes = {
	submitFoods: React.PropTypes.func,
	isLoading: React.PropTypes.bool,
	noExpirationItems: React.PropTypes.array,
	noFoodGroupItems: React.PropTypes.array,
	resolveIceboxItems: React.PropTypes.func,
};

const mapStateToProps = (state) => ({
	isLoading: state.loading,
	noExpirationItems: state.icebox.noExpirationItems,
	noFoodGroupItems: state.icebox.noFoodGroupItems,
});

export default connect(mapStateToProps, actions)(FoodItemInput);

<|endoftext|>


<commit_before>'use strict'

import React from 'react'
import ReactDOM from 'react-dom'

import Header from './header'

module.exports = class HomePageBtn extends React.Component {
  constructor(props){
    super(props)
  }

  render (){
    return (
      <div>
        <Header />
      </div>
    )
  }
}

<commit_msg>delete<commit_after><|endoftext|>


<commit_before>import React from 'react'
import '../../assets/stylesheets/application.css';
import { checkWeb3 } from '../../utils/blockchainHelpers'
import { Link } from 'react-router-dom';
import { setFlatFileContentToState, toast } from '../../utils/utils';
import { StepNavigation } from '../Common/StepNavigation';
import { NAVIGATION_STEPS, CONTRACT_TYPES, TOAST } from '../../utils/constants';
import { inject, observer } from 'mobx-react';
const { CROWDSALE_CONTRACT } = NAVIGATION_STEPS;

const DOWNLOAD_STATUS = {
  PENDING: 'pending',
  SUCCESS: 'success',
  FAILURE: 'failure'
}

const ContinueButton = ({downloadStatus}) => {
  const success = downloadStatus === DOWNLOAD_STATUS.SUCCESS

  if (success) {
    return (
      <Link to="/2">
        Continue
      </Link>
    );
  } else {
    return (
      <Link to="/2" onClick={e => e.preventDefault()}>
        Continue
      </Link>
    );
  }
};

@inject('contractStore', 'web3Store') @observer
export class stepOne extends React.Component {

  constructor() {
    super()

    this.state = {
      contractsDownloaded: DOWNLOAD_STATUS.PENDING
    }
  }

  getStandardCrowdsaleAssets() {
    return Promise.all([
      this.getCrowdsaleAsset("CrowdsaleStandard", "crowdsale"),
      this.getCrowdsaleAsset("CrowdsaleStandardToken", "token")
    ])
  }

  getWhiteListWithCapCrowdsaleAssets () {
    return Promise.all([
      this.getCrowdsaleAsset("SafeMathLibExt", "safeMathLib"),
      this.getCrowdsaleAsset("CrowdsaleWhiteListWithCap", "crowdsale"),
      this.getCrowdsaleAsset("CrowdsaleWhiteListWithCapToken", "token"),
      this.getCrowdsaleAsset("CrowdsaleWhiteListWithCapPricingStrategy", "pricingStrategy"),
      this.getCrowdsaleAsset("CrowdsaleWhiteListWithCapPricingStrategy", "pricingStrategy"),
      this.getCrowdsaleAsset("FinalizeAgent", "finalizeAgent"),
      this.getCrowdsaleAsset("NullFinalizeAgent", "nullFinalizeAgent"),
      this.getCrowdsaleAsset("Registry", "registry")
    ])
  }

  getCrowdsaleAsset(contractName, stateProp) {
    const src = setFlatFileContentToState(`./contracts/${contractName}_flat.sol`)
    const bin = setFlatFileContentToState(`./contracts/${contractName}_flat.bin`)
    const abi = setFlatFileContentToState(`./contracts/${contractName}_flat.abi`)

    return Promise.all([src, bin, abi])
      .then(result => this.addContractsToState(...result, stateProp))
  }

  addContractsToState(src, bin, abi, contract) {
    this.props.contractStore.setContract(contract, {
      src,
      bin,
      abi: JSON.parse(abi),
      addr: (contract==="crowdsale" || contract==="pricingStrategy" || contract==="finalizeAgent") ? [] : "",
      abiConstructor: (contract==="crowdsale" || contract==="pricingStrategy" || contract==="finalizeAgent") ? [] : ""
    });
  }

  contractTypeSelected(e) {
    this.props.contractStore.setContractType(e.currentTarget.id);
    this.getWhiteListWithCapCrowdsaleAssets();
  }

  componentDidMount() {
    checkWeb3(this.props.web3Store.web3);

    let downloadContracts = null

    switch (this.props.contractStore.contractType) {
      case CONTRACT_TYPES.standard:
        downloadContracts = this.getStandardCrowdsaleAssets();
        break;
      case CONTRACT_TYPES.whitelistwithcap:
        downloadContracts = this.getWhiteListWithCapCrowdsaleAssets();
        break
      default:
        break
    }

    downloadContracts
      .then(
        () => {
          this.setState({
            contractsDownloaded: DOWNLOAD_STATUS.SUCCESS
          })
        },
        (e) => {
          console.error('Error downloading contracts', e)
          toast.showToaster({
            type: TOAST.TYPE.ERROR,
            message: 'The contracts could not be downloaded'
          })
          this.setState({
            contractsDownloaded: DOWNLOAD_STATUS.FAILURE
          })
        }
      )
  }

  render() {
    return (

       <StepNavigation activeStep={CROWDSALE_CONTRACT}/>

Crowdsale Contract

              Select a strategy for your crowdsale contract.

              <input
                type="radio"
                checked={this.props.contractStore.contractType === CONTRACT_TYPES.whitelistwithcap}
                name="contract-type"
                id={CONTRACT_TYPES.whitelistwithcap}
                onChange={(e) => this.contractTypeSelected(e)}
              />
              Whitelist with Cap

                Modern crowdsale strategy with multiple tiers, whitelists, and limits. Recommended for every crowdsale.

          <ContinueButton downloadStatus={this.state.contractsDownloaded} />

    )
  }
}
<commit_msg>Update message when contract download fails<commit_after>import React from 'react'
import '../../assets/stylesheets/application.css';
import { checkWeb3 } from '../../utils/blockchainHelpers'
import { Link } from 'react-router-dom';
import { setFlatFileContentToState, toast } from '../../utils/utils';
import { StepNavigation } from '../Common/StepNavigation';
import { NAVIGATION_STEPS, CONTRACT_TYPES, TOAST } from '../../utils/constants';
import { inject, observer } from 'mobx-react';
const { CROWDSALE_CONTRACT } = NAVIGATION_STEPS;

const DOWNLOAD_STATUS = {
  PENDING: 'pending',
  SUCCESS: 'success',
  FAILURE: 'failure'
}

const ContinueButton = ({downloadStatus}) => {
  const success = downloadStatus === DOWNLOAD_STATUS.SUCCESS

  if (success) {
    return (
      <Link to="/2">
        Continue
      </Link>
    );
  } else {
    return (
      <Link to="/2" onClick={e => e.preventDefault()}>
        Continue
      </Link>
    );
  }
};

@inject('contractStore', 'web3Store') @observer
export class stepOne extends React.Component {

  constructor() {
    super()

    this.state = {
      contractsDownloaded: DOWNLOAD_STATUS.PENDING
    }
  }

  getStandardCrowdsaleAssets() {
    return Promise.all([
      this.getCrowdsaleAsset("CrowdsaleStandard", "crowdsale"),
      this.getCrowdsaleAsset("CrowdsaleStandardToken", "token")
    ])
  }

  getWhiteListWithCapCrowdsaleAssets () {
    return Promise.all([
      this.getCrowdsaleAsset("SafeMathLibExt", "safeMathLib"),
      this.getCrowdsaleAsset("CrowdsaleWhiteListWithCap", "crowdsale"),
      this.getCrowdsaleAsset("CrowdsaleWhiteListWithCapToken", "token"),
      this.getCrowdsaleAsset("CrowdsaleWhiteListWithCapPricingStrategy", "pricingStrategy"),
      this.getCrowdsaleAsset("CrowdsaleWhiteListWithCapPricingStrategy", "pricingStrategy"),
      this.getCrowdsaleAsset("FinalizeAgent", "finalizeAgent"),
      this.getCrowdsaleAsset("NullFinalizeAgent", "nullFinalizeAgent"),
      this.getCrowdsaleAsset("Registry", "registry")
    ])
  }

  getCrowdsaleAsset(contractName, stateProp) {
    const src = setFlatFileContentToState(`./contracts/${contractName}_flat.sol`)
    const bin = setFlatFileContentToState(`./contracts/${contractName}_flat.bin`)
    const abi = setFlatFileContentToState(`./contracts/${contractName}_flat.abi`)

    return Promise.all([src, bin, abi])
      .then(result => this.addContractsToState(...result, stateProp))
  }

  addContractsToState(src, bin, abi, contract) {
    this.props.contractStore.setContract(contract, {
      src,
      bin,
      abi: JSON.parse(abi),
      addr: (contract==="crowdsale" || contract==="pricingStrategy" || contract==="finalizeAgent") ? [] : "",
      abiConstructor: (contract==="crowdsale" || contract==="pricingStrategy" || contract==="finalizeAgent") ? [] : ""
    });
  }

  contractTypeSelected(e) {
    this.props.contractStore.setContractType(e.currentTarget.id);
    this.getWhiteListWithCapCrowdsaleAssets();
  }

  componentDidMount() {
    checkWeb3(this.props.web3Store.web3);

    let downloadContracts = null

    switch (this.props.contractStore.contractType) {
      case CONTRACT_TYPES.standard:
        downloadContracts = this.getStandardCrowdsaleAssets();
        break;
      case CONTRACT_TYPES.whitelistwithcap:
        downloadContracts = this.getWhiteListWithCapCrowdsaleAssets();
        break
      default:
        break
    }

    downloadContracts
      .then(
        () => {
          this.setState({
            contractsDownloaded: DOWNLOAD_STATUS.SUCCESS
          })
        },
        (e) => {
          console.error('Error downloading contracts', e)
          toast.showToaster({
            type: TOAST.TYPE.ERROR,
            message: 'The contracts could not be downloaded.Please try to refresh the page. If the problem persists, try again later.'
          })
          this.setState({
            contractsDownloaded: DOWNLOAD_STATUS.FAILURE
          })
        }
      )
  }

  render() {
    return (

       <StepNavigation activeStep={CROWDSALE_CONTRACT}/>

Crowdsale Contract

              Select a strategy for your crowdsale contract.

              <input
                type="radio"
                checked={this.props.contractStore.contractType === CONTRACT_TYPES.whitelistwithcap}
                name="contract-type"
                id={CONTRACT_TYPES.whitelistwithcap}
                onChange={(e) => this.contractTypeSelected(e)}
              />
              Whitelist with Cap

                Modern crowdsale strategy with multiple tiers, whitelists, and limits. Recommended for every crowdsale.

          <ContinueButton downloadStatus={this.state.contractsDownloaded} />

    )
  }
}
<|endoftext|>


<commit_before>import React, { Component } from 'react'
import '../../assets/stylesheets/application.css';
import { Link } from 'react-router-dom'
import { checkWeb3 } from '../../utils/blockchainHelpers'
import { StepNavigation } from '../Common/StepNavigation'
import { InputField } from '../Common/InputField'
import { NumericInput } from '../Common/NumericInput'
import { ReservedTokensInputBlock } from '../Common/ReservedTokensInputBlock'
import { NAVIGATION_STEPS, VALIDATION_MESSAGES, TEXT_FIELDS, DESCRIPTION } from '../../utils/constants'
import { inject, observer } from 'mobx-react';

const { TOKEN_SETUP } = NAVIGATION_STEPS
const { NAME, TICKER, DECIMALS } = TEXT_FIELDS

@inject('tokenStore', 'web3Store', 'tierCrowdsaleListStore', 'reservedTokenStore') @observer
export class stepTwo extends Component {
  componentDidMount() {
    checkWeb3(this.props.web3Store.web3);
  }

  showErrorMessages = (parent) => {
    this.props.tokenStore.invalidateToken();
  }

  updateTokenStore = (event, property) => {
    const value = event.target.value;
    this.props.tokenStore.setProperty(property, value);
    this.props.tokenStore.validateTokens(property);
  }

  updateDecimalsStore = value => {
    this.updateTokenStore({ target: { value } }, 'decimals')
  }

  renderLink () {
    return <Link className="button button_fill" to='/3'>Continue</Link>
  }

  renderLinkComponent = () => {
    if(this.props.tokenStore.isTokenValid) {
      return this.renderLink();
    }
    return
 Continue

  }

  removeReservedToken = index => {
    this.props.reservedTokenStore.removeToken(index)
  }

  addReservedTokensItem = newToken => {
    this.props.reservedTokenStore.addToken(newToken)
  }

  render () {
    return (

        <StepNavigation activeStep={TOKEN_SETUP}/>

Token setup

              Configure properties of your token. Created token contract will be ERC-20 compatible.

            <InputField side='left' type='text'
              errorMessage={VALIDATION_MESSAGES.NAME}
              valid={this.props.tokenStore.validToken['name']}
              title={NAME}
              value={this.props.tokenStore.name}
              onChange={(e) => this.updateTokenStore(e, 'name')}
              description={`The name of your token. Will be used by Etherscan and other token browsers. Be afraid of trademarks.`}
            />
            <InputField
              side='right' type='text'
              errorMessage={VALIDATION_MESSAGES.TICKER}
              valid={this.props.tokenStore.validToken['ticker']}
              title={TICKER}
              value={this.props.tokenStore.ticker}
              onChange={(e) => this.updateTokenStore(e, 'ticker')}
              description={`${DESCRIPTION.TOKEN_TICKER} There are 11,881,376 combinations for 26 english letters. Be hurry. `}
            />
            <NumericInput
              side="left"
              title={DECIMALS}
              description="Refers to how divisible a token can be, from 0 (not at all divisible) to 18 (pretty much continuous)."
              min="0"
              max="18"
              errorMessage={VALIDATION_MESSAGES.DECIMALS}
              onValueUpdate={this.updateDecimalsStore}
            />

Reserved tokens

          <ReservedTokensInputBlock
            tokens={this.props.reservedTokenStore.tokens}
            addReservedTokensItem={this.addReservedTokensItem}
            removeReservedToken={this.removeReservedToken}
          />

          {this.renderLinkComponent()}

    )}
}
<commit_msg>Change props from string to expressions<commit_after>import React, { Component } from 'react'
import '../../assets/stylesheets/application.css';
import { Link } from 'react-router-dom'
import { checkWeb3 } from '../../utils/blockchainHelpers'
import { StepNavigation } from '../Common/StepNavigation'
import { InputField } from '../Common/InputField'
import { NumericInput } from '../Common/NumericInput'
import { ReservedTokensInputBlock } from '../Common/ReservedTokensInputBlock'
import { NAVIGATION_STEPS, VALIDATION_MESSAGES, TEXT_FIELDS, DESCRIPTION } from '../../utils/constants'
import { inject, observer } from 'mobx-react';

const { TOKEN_SETUP } = NAVIGATION_STEPS
const { NAME, TICKER, DECIMALS } = TEXT_FIELDS

@inject('tokenStore', 'web3Store', 'tierCrowdsaleListStore', 'reservedTokenStore') @observer
export class stepTwo extends Component {
  componentDidMount() {
    checkWeb3(this.props.web3Store.web3);
  }

  showErrorMessages = (parent) => {
    this.props.tokenStore.invalidateToken();
  }

  updateTokenStore = (event, property) => {
    const value = event.target.value;
    this.props.tokenStore.setProperty(property, value);
    this.props.tokenStore.validateTokens(property);
  }

  updateDecimalsStore = value => {
    this.updateTokenStore({ target: { value } }, 'decimals')
  }

  renderLink () {
    return <Link className="button button_fill" to='/3'>Continue</Link>
  }

  renderLinkComponent = () => {
    if(this.props.tokenStore.isTokenValid) {
      return this.renderLink();
    }
    return
 Continue

  }

  removeReservedToken = index => {
    this.props.reservedTokenStore.removeToken(index)
  }

  addReservedTokensItem = newToken => {
    this.props.reservedTokenStore.addToken(newToken)
  }

  render () {
    return (

        <StepNavigation activeStep={TOKEN_SETUP}/>

Token setup

              Configure properties of your token. Created token contract will be ERC-20 compatible.

            <InputField side='left' type='text'
              errorMessage={VALIDATION_MESSAGES.NAME}
              valid={this.props.tokenStore.validToken['name']}
              title={NAME}
              value={this.props.tokenStore.name}
              onChange={(e) => this.updateTokenStore(e, 'name')}
              description={`The name of your token. Will be used by Etherscan and other token browsers. Be afraid of trademarks.`}
            />
            <InputField
              side='right' type='text'
              errorMessage={VALIDATION_MESSAGES.TICKER}
              valid={this.props.tokenStore.validToken['ticker']}
              title={TICKER}
              value={this.props.tokenStore.ticker}
              onChange={(e) => this.updateTokenStore(e, 'ticker')}
              description={`${DESCRIPTION.TOKEN_TICKER} There are 11,881,376 combinations for 26 english letters. Be hurry. `}
            />
            <NumericInput
              side="left"
              title={DECIMALS}
              description="Refers to how divisible a token can be, from 0 (not at all divisible) to 18 (pretty much continuous)."
              min={0}
              max={18}
              errorMessage={VALIDATION_MESSAGES.DECIMALS}
              onValueUpdate={this.updateDecimalsStore}
            />

Reserved tokens

          <ReservedTokensInputBlock
            tokens={this.props.reservedTokenStore.tokens}
            addReservedTokensItem={this.addReservedTokensItem}
            removeReservedToken={this.removeReservedToken}
          />

          {this.renderLinkComponent()}

    )}
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 Uber Technologies, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under the License
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
// or implied. See the License for the specific language governing permissions and limitations under
// the License.

module.exports = {
  initTracer: require('./dist/src/configuration.js').default.initTracer,

  SpanContext: require('./dist/src/span_context.js').default,
  Span: require('./dist/src/span.js').default,
  Tracer: require('./dist/src/tracer.js').default,

  ConstSampler: require('./dist/src/samplers/const_sampler.js').default,
  ProbabilisticSampler: require('./dist/src/samplers/probabilistic_sampler.js').default,
  RateLimitingSampler: require('./dist/src/samplers/ratelimiting_sampler.js').default,
  RemoteSampler: require('./dist/src/samplers/remote_sampler.js').default,

  CompositeReporter: require('./dist/src/reporters/composite_reporter.js').default,
  InMemoryReporter: require('./dist/src/reporters/in_memory_reporter.js').default,
  LoggingReporter: require('./dist/src/reporters/logging_reporter.js').default,
  NoopReporter: require('./dist/src/reporters/noop_reporter.js').default,
  RemoteReporter: require('./dist/src/reporters/remote_reporter.js').default,

  TextMapCodec: require('./dist/src/propagators/text_map_codec.js').default,
  ZipkinB3TextMapCodec: require('./dist/src/propagators/zipkin_b3_text_map_codec.js').default,

  TestUtils: require('./dist/src/test_util.js').default,
  TChannelBridge: require('./dist/src/tchannel_bridge.js').default,
  opentracing: require('opentracing'),
};
<commit_msg>Export Configuration (#221)<commit_after>// Copyright (c) 2016 Uber Technologies, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under the License
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
// or implied. See the License for the specific language governing permissions and limitations under
// the License.

module.exports = {
  initTracer: require('./dist/src/configuration.js').default.initTracer,
  Configuration: require('./dist/src/configuration.js').default,

  SpanContext: require('./dist/src/span_context.js').default,
  Span: require('./dist/src/span.js').default,
  Tracer: require('./dist/src/tracer.js').default,

  ConstSampler: require('./dist/src/samplers/const_sampler.js').default,
  ProbabilisticSampler: require('./dist/src/samplers/probabilistic_sampler.js').default,
  RateLimitingSampler: require('./dist/src/samplers/ratelimiting_sampler.js').default,
  RemoteSampler: require('./dist/src/samplers/remote_sampler.js').default,

  CompositeReporter: require('./dist/src/reporters/composite_reporter.js').default,
  InMemoryReporter: require('./dist/src/reporters/in_memory_reporter.js').default,
  LoggingReporter: require('./dist/src/reporters/logging_reporter.js').default,
  NoopReporter: require('./dist/src/reporters/noop_reporter.js').default,
  RemoteReporter: require('./dist/src/reporters/remote_reporter.js').default,

  TextMapCodec: require('./dist/src/propagators/text_map_codec.js').default,
  ZipkinB3TextMapCodec: require('./dist/src/propagators/zipkin_b3_text_map_codec.js').default,

  TestUtils: require('./dist/src/test_util.js').default,
  TChannelBridge: require('./dist/src/tchannel_bridge.js').default,
  opentracing: require('opentracing'),
};
<|endoftext|>