<commit_before>const React = require("react");

const CompLibrary = require("../../core/CompLibrary.js");
const MarkdownBlock = CompLibrary.MarkdownBlock; /* Used to read markdown */
const Container = CompLibrary.Container;
const GridBlock = CompLibrary.GridBlock;

const translate = require("../../server/translate.js").translate;

const siteConfig = require(process.cwd() + "/siteConfig.js");

class Button extends React.Component {
  render() {
    return (

        <a className={`button ${this.props.className || ""}`} href={this.props.href} target={this.props.target}>
          {this.props.children}

    );
  }
}

Button.defaultProps = {
  target: "_self"
};
const pre = "```";
const code = "`";

// fake, static, responsive refmt, lol. See reason.css homeCodeSnippet logic
const codeExampleSmallScreen =`${pre}reason
let component =
  ReasonReact.statelessComponent("Greeting");

let make = (~name, _children) => {
  ...component,
  render: _self =>
    <button>
      {ReasonReact.string("Hello!")}
    </button>
};
${pre}`;

const codeExampleLargeScreen =`${pre}reason
let component = ReasonReact.statelessComponent("Greeting");

let make = (~name, _children) => {
  ...component,
  render: _self =>
    <button>
      {ReasonReact.string("Hello!")}
    </button>
};
${pre}`;

const quickStart = `${pre}bash
npm install -g bs-platform
bsb -init my-react-app -theme react
cd my-react-app
npm install && npm start
${pre}

Then open another tab and do:

${pre}bash
npm run webpack
${pre}

Your apps are the html files inside ${code}src/${code}`;

class HomeSplash extends React.Component {
  render() {
    let promoSection =
      <div className="section promoSection">
        <div className="promoRow">
          <div className="pluginRowBlock">
            <Button
              className="getStarted"
              href={
                siteConfig.baseUrl +
                "docs/" +
                this.props.language +
                "/installation.html"
              }
            >
              <translate>Get Started</translate>
            </Button>
            <Button
              href="https://jaredforsyth.com/2017/07/05/a-reason-react-tutorial"
            >
              Tutorial
            </Button>
          </div>
        </div>
      </div>;

    return (
      <div className="homeContainer">

        <div id="redirectBanner">
          <div>
            Hello! This particular page hash has moved to <a id="redirectLink"/>.
            Please update the URLs to reflect it. Thanks!
          </div>
        </div>

        <div className="homeWrapperWrapper">

          <img src={siteConfig.baseUrl + siteConfig.headerIcon} className="spinner" />

          <div className="wrapper homeWrapper">
            <div className="projectTitle">{siteConfig.title}</div>

            <div className="homeWrapperInner">
              <div className="homeTagLine">{siteConfig.tagline}</div>
              <div className="homeCodeSnippet">
                <MarkdownBlock>{codeExampleSmallScreen}</MarkdownBlock>
                <MarkdownBlock>{codeExampleLargeScreen}</MarkdownBlock>
              </div>
            </div>

            {promoSection}
          </div>

        </div>
      </div>
    );
  }
}

class Index extends React.Component {
  render() {
    let language = this.props.language || "en";
    const showcase = siteConfig.users
      .filter(user => {
        return user.pinned;
      })
      .map(user => {
        return (
          <a href={user.infoLink} key={user.caption}>
            <img src={`${siteConfig.baseUrl}${user.image}`} title={user.caption} />
          </a>
        );
      });

    return (
      <div>
        <HomeSplash language={language} />
        <div className="mainContainer">
          <Container className="homeThreePoints">
            <GridBlock
              align="center"
              contents={[
                {
                  title: "Safe and Sound",
                  content: "It's Just Reason. We leverage the existing type system to create a library that types just right.",
                },
                {
                  title: "Playground for Future React",
                  content: "Lightweight, first-class support for the ReactJS community idioms you've been using.",
                },
                {
                  title: "Drop In",
                  content: "Easily integrate ReasonReact into your existing app. Convert a file, quickly see benefits.",
                },
              ]}
              layout="threeColumn"
            />
          </Container>

          <Container background="light" className="quickStartAndExamples homeCodeSnippet">
            <div>
              <h2>Quick Start</h2>
              <MarkdownBlock>
                {quickStart}
              </MarkdownBlock>
            </div>
            <div>
              <h2>Examples</h2>
              <GridBlock
                className="examples"
                align="center"
                contents={siteConfig.examples.map(example => ({
                  title: example.name,
                  image: `${siteConfig.baseUrl}${example.image}`,
                  imageLink: example.link,
                  imageAlign: "top",
                  content: "",
                }))}
                layout="twoColumn"
              />
          </div>
          </Container>

          <div className="productShowcaseSection paddingBottom">
            <h2>
              <translate>Projects Using ReasonReact</translate>
            </h2>
            <div className="logos">
              {showcase}
            </div>
            <div className="more-users">
              <a
                className="button"
                href={`${siteConfig.baseUrl}${this.props.language}/built-with-reason-react.html`}
              >
                <translate>See Full List</translate>
              </a>
            </div>
          </div>
        </div>
        <script src={siteConfig.baseUrl + 'js/redirectIndex.js'}></script>
      </div>
    );
  }
}

module.exports = Index;
<commit_msg>[Docs] Temporarily remove tutorial (stale)<commit_after>const React = require("react");

const CompLibrary = require("../../core/CompLibrary.js");
const MarkdownBlock = CompLibrary.MarkdownBlock; /* Used to read markdown */
const Container = CompLibrary.Container;
const GridBlock = CompLibrary.GridBlock;

const translate = require("../../server/translate.js").translate;

const siteConfig = require(process.cwd() + "/siteConfig.js");

class Button extends React.Component {
  render() {
    return (
      <div className="pluginWrapper">
        <a className={`button ${this.props.className || ""}`} href={this.props.href} target={this.props.target}>
          {this.props.children}
        </a>
      </div>
    );
  }
}

Button.defaultProps = {
  target: "_self"
};
const pre = "```";
const code = "`";

// fake, static, responsive refmt, lol. See reason.css homeCodeSnippet logic
const codeExampleSmallScreen =`${pre}reason
let component =
  ReasonReact.statelessComponent("Greeting");

let make = (~name, _children) => {
  ...component,
  render: _self =>
    <button>
      {ReasonReact.string("Hello!")}
    </button>
};
${pre}`;

const codeExampleLargeScreen =`${pre}reason
let component = ReasonReact.statelessComponent("Greeting");

let make = (~name, _children) => {
  ...component,
  render: _self =>
    <button>
      {ReasonReact.string("Hello!")}
    </button>
};
${pre}`;

const quickStart = `${pre}bash
npm install -g bs-platform
bsb -init my-react-app -theme react
cd my-react-app
npm install && npm start
${pre}

Then open another tab and do:

${pre}bash
npm run webpack
${pre}

Your apps are the html files inside ${code}src/${code}`;

class HomeSplash extends React.Component {
  render() {
    let promoSection =

            <Button
              className="getStarted"
              href={
                siteConfig.baseUrl +
                "docs/" +
                this.props.language +
                "/installation.html"
              }
            >
              <translate>Get Started</translate>
            </Button>

;

    return (

            Hello! This particular page hash has moved to .
            Please update the URLs to reflect it. Thanks!

{siteConfig.title}

{siteConfig.tagline}

                <MarkdownBlock>{codeExampleSmallScreen}</MarkdownBlock>
                <MarkdownBlock>{codeExampleLargeScreen}</MarkdownBlock>

            {promoSection}

    );
  }
}

class Index extends React.Component {
  render() {
    let language = this.props.language || "en";
    const showcase = siteConfig.users
      .filter(user => {
        return user.pinned;
      })
      .map(user => {
        return (

            <img src={`${siteConfig.baseUrl}${user.image}`} title={user.caption} />

        );
      });

    return (

        <HomeSplash language={language} />

          <Container className="homeThreePoints">
            <GridBlock
              align="center"
              contents={[
                {
                  title: "Safe and Sound",
                  content: "It's Just Reason. We leverage the existing type system to create a library that types just right.",
                },
                {
                  title: "Playground for Future React",
                  content: "Lightweight, first-class support for the ReactJS community idioms you've been using.",
                },
                {
                  title: "Drop In",
                  content: "Easily integrate ReasonReact into your existing app. Convert a file, quickly see benefits.",
                },
              ]}
              layout="threeColumn"
            />
          </Container>

          <Container background="light" className="quickStartAndExamples homeCodeSnippet">

Quick Start

              <MarkdownBlock>
                {quickStart}
              </MarkdownBlock>

Examples

              <GridBlock
                className="examples"
                align="center"
                contents={siteConfig.examples.map(example => ({
                  title: example.name,
                  image: `${siteConfig.baseUrl}${example.image}`,
                  imageLink: example.link,
                  imageAlign: "top",
                  content: "",
                }))}
                layout="twoColumn"
              />

          </Container>

              <translate>Projects Using ReasonReact</translate>

              {showcase}

              <a
                className="button"
                href={`${siteConfig.baseUrl}${this.props.language}/built-with-reason-react.html`}
              >
                <translate>See Full List</translate>

    );
  }
}

module.exports = Index;
<|endoftext|>


<commit_before>/*ngInject*/
export function setupRoutes($stateProvider, $urlRouterProvider) {
    $stateProvider
        .state('login', {
            url: '/login',
            template: '<mc-login></mc-login>'
        })
        .state('projects', {
            url: '/projects',
            abstract: true,
            template: '

'
        })
        .state('projects.list', {
            url: '/list',
            template: '<mc-projects></mc-projects>'
        })
        .state('projects.share', {
            url: '/share',
            template: '<mc-projects-share></mc-projects-share>'
        })
        .state('user', {
            url: '/user',
            abstract: true,
            template: '

'
        })
        .state('user.apikey', {
            url: '/apikey',
            template: '<mc-user-apikey></mc-user-apikey>'
        })
        .state('user.password', {
            url: '/password',
            template: '<mc-user-password></mc-user-password>'
        })
        .state('project', {
            url: '/project/:project_id',
            abstract: true,
            template: '<ui-view flex="100" layout="column"></ui-view>',
            resolve: {
                // Set the current project in the project service so all components
                // will resolve without having to worry if a promise has resolved.
                // The resolved object is ignored.
                _project: ["$stateParams", "projectsService", "project",
                    // Inject projects so that it resolves before looking up the project.
                    function($stateParams, projectsService, project) {
                        return projectsService.getProject($stateParams.project_id)
                            .then(function(proj) {
                                project.set(proj);
                                return proj;
                            });
                    }],

                _templates: ["processTemplates", "templates", "_project",
                    function(processTemplates, templates, project) {
                        var projectTemplates = processTemplates.templates(project.process_templates, project.id);
                        templates.set(projectTemplates);
                        return projectTemplates;
                    }]
            }
        })
        .state('project.home', {
            url: '/home',
            template: '<mc-project-home></mc-project-home>',
            // hack to update project view
            resolve: {
                // Set the current project in the project service so all components
                // will resolve without having to worry if a promise has resolved.
                // The resolved object is ignored.
                _project: ["$stateParams", "projectsService", "project",
                    // Inject projects so that it resolves before looking up the project.
                    function($stateParams, projectsService, project) {
                        return projectsService.getProject($stateParams.project_id)
                            .then(function(proj) {
                                project.set(proj);
                                return proj;
                            });
                    }]
            }
        })
        .state('project.search', {
            url: '/search/:query',
            template: '<mc-project-search></mc-project-search>'
        })
        .state('project.create', {
            url: '/create',
            abstract: true,
            template: '<ui-view flex layout="column"></ui-view>'
        })
        .state('project.experiment', {
            url: '/experiment/:experiment_id',
            template: `<mc-experiment></mc-experiment>`,
            controllerAs: 'ctrl',
            controller: ['experiment', 'currentExperiment', function(experiment, currentExperiment) {
                currentExperiment.set(experiment);
            }],
            resolve: {
                experiment: ['experimentsService', 'toast', 'toUITask', '$stateParams', 'currentExperiment',
                    function(experimentsService, toast, toUITask, $stateParams, currentExperiment) {
                        return experimentsService.getForProject($stateParams.project_id, $stateParams.experiment_id)
                            .then(
                                (e) => {
                                    e.tasks.forEach((task) => toUITask(task));
                                    currentExperiment.set(e);
                                    return e;
                                },
                                () => toast.error('Failed to retrieve experiment')
                            );
                    }
                ]
            }
        })
        .state('project.experiment.details', {
            url: '/details',
            template: '<mc-experiment-details experiment="ctrl.experiment"></mc-experiment-details>',
            controllerAs: 'ctrl',
            controller: ['experiment', function(experiment) {
                this.experiment = experiment;
            }]
        })
        .state('project.experiment.tasks', {
            url: '/tasks',
            template: '<mc-experiment-tasks></mc-experiment-tasks>'
        })
        .state('project.experiment.forecast', {
            url: '/forecast',
            template: '<mc-experiment-forecast experiment="ctrl.experiment"></mc-experiment-forecast>',
            controllerAs: 'ctrl',
            controller: ['experiment', function(experiment) {
                this.experiment = experiment;
            }]
        })
        .state('project.experiment.flagged', {
            url: '/flagged',
            template: '<mc-experiment-flagged experiment="ctrl.experiment"></mc-experiment-flagged>',
            controllerAs: 'ctrl',
            controller: ['experiment', function(experiment) {
                this.experiment = experiment;
            }]
        })
        .state('project.experiment.samples', {
            url: '/samples',
            template: '<mc-experiment-samples experiment="ctrl.experiment"></mc-experiment-samples>',
            controllerAs: 'ctrl',
            controller: ['experiment', function(experiment) {
                this.experiment = experiment;
            }]
        })
        .state('project.experiment.files', {
            url: '/files',
            template: '<mc-experiment-files experiment="ctrl.experiment"></mc-experiment-files>',
            controllerAs: 'ctrl',
            controller: ['experiment', function(experiment) {
                this.experiment = experiment;
            }]
        })
        .state('project.experiment.notes', {
            url: '/today',
            template: '<mc-experiment-notes experiment="ctrl.experiment"></mc-experiment-notes>',
            controllerAs: 'ctrl',
            controller: ['experiment', function(experiment) {
                this.experiment = experiment;
            }]
        })
        .state('project.create.process', {
            url: '/process/:template_id/:process_id',
            template: '<mc-process-create></mc-process-create>',
            resolve: {
                _template: ['templates', 'template', '$stateParams', 'projectsService',
                    function(templates, template, $stateParams, projectsService) {
                        if ($stateParams.process_id) {
                            return projectsService.getProjectProcess($stateParams.project_id, $stateParams.process_id)
                                .then(function(process) {
                                    var t = templates.loadTemplateFromProcess($stateParams.template_id, process);
                                    template.set(t);
                                    return t;
                                });
                        } else {
                            var t = templates.getTemplate($stateParams.template_id);
                            template.set(t);
                            return t;
                        }
                    }]
            }
        })
        .state('project.experiments', {
            url: '/experiments',
            template: '<mc-project-experiments experiments="ctrl.experiments"></mc-project-experiments>',
            controllerAs: 'ctrl',
            controller: ['$stateParams', 'experimentsService', 'toast', function($stateParams, experimentsService, toast) {
                let ctrl = this;
                ctrl.experiments = [];
                experimentsService.getAllForProject($stateParams.project_id).then(
                    (experiments) => {
                        ctrl.experiments = experiments;
                    },
                    () => toast.error('Unable to retrieve experiments for project')
                );
            }]
        })
        .state('project.processes', {
            url: '/processes',
            template: '<mc-project-processes processes="ctrl.processes"></mc-project-processes>',
            controllerAs: 'ctrl',
            controller: ['projectsService', '$stateParams', 'toastr',
                function(projectsService, $stateParams, toastr) {
                    var ctrl = this;
                    ctrl.processes = [];
                    projectsService.getProjectProcesses($stateParams.project_id).then(
                        (processes) => {
                            ctrl.processes = processes;
                        },
                        () => toastr.error('Unable to retrieve project processes', 'Error', {closeButton: true})
                    )
                }]
        })
        .state('project.processes.process', {
            url: '/process/:process_id',
            template: '<mc-process></mc-process>',
            resolve: {
                _process: ['process', 'projectsService', '$stateParams',
                    function(process, projectsService, $stateParams) {
                        return projectsService.getProjectProcess($stateParams.project_id, $stateParams.process_id)
                            .then(function(p) {
                                process.set(p);
                                return p;
                            });
                    }]
            }
        })
        .state('project.processes.edit', {
            url: '/edit/:process_id',
            template: '<mc-process-edit></mc-process-edit>',
            resolve: {
                _process: ['process', 'projectsService', '$stateParams', 'processEdit', 'templates',
                    function(process, projectsService, $stateParams, processEdit, templates) {
                        return projectsService.getProjectProcess($stateParams.project_id, $stateParams.process_id)
                            .then(function(proc) {
                                var t = templates.getTemplate(proc.process_name);
                                var p = processEdit.fillProcess(t, proc);
                                process.set(p);
                                return p;
                            });
                    }]
            }
        })
        .state('project.samples', {
            url: '/samples',
            template: '<mc-project-samples samples="ctrl.samples"></mc-project-samples>',
            controllerAs: 'ctrl',
            controller: ['samplesService', '$stateParams', 'toastr',
                function(samplesService, $stateParams, toastr) {
                    var ctrl = this;
                    ctrl.samples = [];
                    samplesService.getProjectSamples($stateParams.project_id).then(
                        (samples) => {
                            //console.dir(samples);
                            ctrl.samples = samples;
                        },
                        () => toastr.error('Error retrieving samples for project', 'Error', {closeButton: true})
                    );
                }]
        })
        .state('project.samples.sample', {
            url: '/sample/:sample_id',
            template: '<mc-sample></mc-sample>'
        })
        .state('project.files', {
            url: '/files',
            template: '<mc-file-tree flex layout-fill></mc-file-tree>'
        })
        .state('project.files.uploads', {
            url: '/uploads',
            template: '<mc-file-uploads></mc-file-uploads>'
        })
        .state('project.files.file', {
            url: '/file/:file_id',
            template: '<mc-file></mc-file>'
        })
        .state('project.files.dir', {
            url: '/dir/:dir_id',
            template: '<mc-dir></mc-dir>'
        })
        .state('project.settings', {
            url: '/settings',
            template: '<mc-project-settings></mc-project-settings>'
        });

    $urlRouterProvider.otherwise('/login');
}
<commit_msg>url for project.experiment.notes should be /notes and not /today.<commit_after>/*ngInject*/
export function setupRoutes($stateProvider, $urlRouterProvider) {
    $stateProvider
        .state('login', {
            url: '/login',
            template: '<mc-login></mc-login>'
        })
        .state('projects', {
            url: '/projects',
            abstract: true,
            template: '

'
        })
        .state('projects.list', {
            url: '/list',
            template: '<mc-projects></mc-projects>'
        })
        .state('projects.share', {
            url: '/share',
            template: '<mc-projects-share></mc-projects-share>'
        })
        .state('user', {
            url: '/user',
            abstract: true,
            template: '

'
        })
        .state('user.apikey', {
            url: '/apikey',
            template: '<mc-user-apikey></mc-user-apikey>'
        })
        .state('user.password', {
            url: '/password',
            template: '<mc-user-password></mc-user-password>'
        })
        .state('project', {
            url: '/project/:project_id',
            abstract: true,
            template: '<ui-view flex="100" layout="column"></ui-view>',
            resolve: {
                // Set the current project in the project service so all components
                // will resolve without having to worry if a promise has resolved.
                // The resolved object is ignored.
                _project: ["$stateParams", "projectsService", "project",
                    // Inject projects so that it resolves before looking up the project.
                    function($stateParams, projectsService, project) {
                        return projectsService.getProject($stateParams.project_id)
                            .then(function(proj) {
                                project.set(proj);
                                return proj;
                            });
                    }],

                _templates: ["processTemplates", "templates", "_project",
                    function(processTemplates, templates, project) {
                        var projectTemplates = processTemplates.templates(project.process_templates, project.id);
                        templates.set(projectTemplates);
                        return projectTemplates;
                    }]
            }
        })
        .state('project.home', {
            url: '/home',
            template: '<mc-project-home></mc-project-home>',
            // hack to update project view
            resolve: {
                // Set the current project in the project service so all components
                // will resolve without having to worry if a promise has resolved.
                // The resolved object is ignored.
                _project: ["$stateParams", "projectsService", "project",
                    // Inject projects so that it resolves before looking up the project.
                    function($stateParams, projectsService, project) {
                        return projectsService.getProject($stateParams.project_id)
                            .then(function(proj) {
                                project.set(proj);
                                return proj;
                            });
                    }]
            }
        })
        .state('project.search', {
            url: '/search/:query',
            template: '<mc-project-search></mc-project-search>'
        })
        .state('project.create', {
            url: '/create',
            abstract: true,
            template: '<ui-view flex layout="column"></ui-view>'
        })
        .state('project.experiment', {
            url: '/experiment/:experiment_id',
            template: `<mc-experiment></mc-experiment>`,
            controllerAs: 'ctrl',
            controller: ['experiment', 'currentExperiment', function(experiment, currentExperiment) {
                currentExperiment.set(experiment);
            }],
            resolve: {
                experiment: ['experimentsService', 'toast', 'toUITask', '$stateParams', 'currentExperiment',
                    function(experimentsService, toast, toUITask, $stateParams, currentExperiment) {
                        return experimentsService.getForProject($stateParams.project_id, $stateParams.experiment_id)
                            .then(
                                (e) => {
                                    e.tasks.forEach((task) => toUITask(task));
                                    currentExperiment.set(e);
                                    return e;
                                },
                                () => toast.error('Failed to retrieve experiment')
                            );
                    }
                ]
            }
        })
        .state('project.experiment.details', {
            url: '/details',
            template: '<mc-experiment-details experiment="ctrl.experiment"></mc-experiment-details>',
            controllerAs: 'ctrl',
            controller: ['experiment', function(experiment) {
                this.experiment = experiment;
            }]
        })
        .state('project.experiment.tasks', {
            url: '/tasks',
            template: '<mc-experiment-tasks></mc-experiment-tasks>'
        })
        .state('project.experiment.forecast', {
            url: '/forecast',
            template: '<mc-experiment-forecast experiment="ctrl.experiment"></mc-experiment-forecast>',
            controllerAs: 'ctrl',
            controller: ['experiment', function(experiment) {
                this.experiment = experiment;
            }]
        })
        .state('project.experiment.flagged', {
            url: '/flagged',
            template: '<mc-experiment-flagged experiment="ctrl.experiment"></mc-experiment-flagged>',
            controllerAs: 'ctrl',
            controller: ['experiment', function(experiment) {
                this.experiment = experiment;
            }]
        })
        .state('project.experiment.samples', {
            url: '/samples',
            template: '<mc-experiment-samples experiment="ctrl.experiment"></mc-experiment-samples>',
            controllerAs: 'ctrl',
            controller: ['experiment', function(experiment) {
                this.experiment = experiment;
            }]
        })
        .state('project.experiment.files', {
            url: '/files',
            template: '<mc-experiment-files experiment="ctrl.experiment"></mc-experiment-files>',
            controllerAs: 'ctrl',
            controller: ['experiment', function(experiment) {
                this.experiment = experiment;
            }]
        })
        .state('project.experiment.notes', {
            url: '/notes',
            template: '<mc-experiment-notes experiment="ctrl.experiment"></mc-experiment-notes>',
            controllerAs: 'ctrl',
            controller: ['experiment', function(experiment) {
                this.experiment = experiment;
            }]
        })
        .state('project.create.process', {
            url: '/process/:template_id/:process_id',
            template: '<mc-process-create></mc-process-create>',
            resolve: {
                _template: ['templates', 'template', '$stateParams', 'projectsService',
                    function(templates, template, $stateParams, projectsService) {
                        if ($stateParams.process_id) {
                            return projectsService.getProjectProcess($stateParams.project_id, $stateParams.process_id)
                                .then(function(process) {
                                    var t = templates.loadTemplateFromProcess($stateParams.template_id, process);
                                    template.set(t);
                                    return t;
                                });
                        } else {
                            var t = templates.getTemplate($stateParams.template_id);
                            template.set(t);
                            return t;
                        }
                    }]
            }
        })
        .state('project.experiments', {
            url: '/experiments',
            template: '<mc-project-experiments experiments="ctrl.experiments"></mc-project-experiments>',
            controllerAs: 'ctrl',
            controller: ['$stateParams', 'experimentsService', 'toast', function($stateParams, experimentsService, toast) {
                let ctrl = this;
                ctrl.experiments = [];
                experimentsService.getAllForProject($stateParams.project_id).then(
                    (experiments) => {
                        ctrl.experiments = experiments;
                    },
                    () => toast.error('Unable to retrieve experiments for project')
                );
            }]
        })
        .state('project.processes', {
            url: '/processes',
            template: '<mc-project-processes processes="ctrl.processes"></mc-project-processes>',
            controllerAs: 'ctrl',
            controller: ['projectsService', '$stateParams', 'toastr',
                function(projectsService, $stateParams, toastr) {
                    var ctrl = this;
                    ctrl.processes = [];
                    projectsService.getProjectProcesses($stateParams.project_id).then(
                        (processes) => {
                            ctrl.processes = processes;
                        },
                        () => toastr.error('Unable to retrieve project processes', 'Error', {closeButton: true})
                    )
                }]
        })
        .state('project.processes.process', {
            url: '/process/:process_id',
            template: '<mc-process></mc-process>',
            resolve: {
                _process: ['process', 'projectsService', '$stateParams',
                    function(process, projectsService, $stateParams) {
                        return projectsService.getProjectProcess($stateParams.project_id, $stateParams.process_id)
                            .then(function(p) {
                                process.set(p);
                                return p;
                            });
                    }]
            }
        })
        .state('project.processes.edit', {
            url: '/edit/:process_id',
            template: '<mc-process-edit></mc-process-edit>',
            resolve: {
                _process: ['process', 'projectsService', '$stateParams', 'processEdit', 'templates',
                    function(process, projectsService, $stateParams, processEdit, templates) {
                        return projectsService.getProjectProcess($stateParams.project_id, $stateParams.process_id)
                            .then(function(proc) {
                                var t = templates.getTemplate(proc.process_name);
                                var p = processEdit.fillProcess(t, proc);
                                process.set(p);
                                return p;
                            });
                    }]
            }
        })
        .state('project.samples', {
            url: '/samples',
            template: '<mc-project-samples samples="ctrl.samples"></mc-project-samples>',
            controllerAs: 'ctrl',
            controller: ['samplesService', '$stateParams', 'toastr',
                function(samplesService, $stateParams, toastr) {
                    var ctrl = this;
                    ctrl.samples = [];
                    samplesService.getProjectSamples($stateParams.project_id).then(
                        (samples) => {
                            //console.dir(samples);
                            ctrl.samples = samples;
                        },
                        () => toastr.error('Error retrieving samples for project', 'Error', {closeButton: true})
                    );
                }]
        })
        .state('project.samples.sample', {
            url: '/sample/:sample_id',
            template: '<mc-sample></mc-sample>'
        })
        .state('project.files', {
            url: '/files',
            template: '<mc-file-tree flex layout-fill></mc-file-tree>'
        })
        .state('project.files.uploads', {
            url: '/uploads',
            template: '<mc-file-uploads></mc-file-uploads>'
        })
        .state('project.files.file', {
            url: '/file/:file_id',
            template: '<mc-file></mc-file>'
        })
        .state('project.files.dir', {
            url: '/dir/:dir_id',
            template: '<mc-dir></mc-dir>'
        })
        .state('project.settings', {
            url: '/settings',
            template: '<mc-project-settings></mc-project-settings>'
        });

    $urlRouterProvider.otherwise('/login');
}
<|endoftext|>


<commit_before>var keen = require('keen-js');
var oop = require('js/oop');
var uuid = require('uuid');

var KeenTracker = oop.defclass({
    constructor: function(keenProjectId, keenWriteKey) {
        this.keenClient = new keen({
            projectId: keenProjectId,
            writeKey: keenWriteKey
        });
        this.init();
    },

    createOrUpdateKeenSession: function() {
        var date = new Date();
        var expiresInMinutes = 25;
        var expDate = date.setTime(date.getTime() + (expiresInMinutes*60*1000));
        if(!$.cookie('keenSessionId')){
            $.cookie('keenSessionId', uuid.v1(), {expires: expDate, path: '/'});
        } else {
            var sessionId = $.cookie('keenSessionId');
            $.cookie('keenSessionId', sessionId, {expires: expDate, path: '/'});
        }
    },

    getOrCreateKeenId: function() {
        if(!$.cookie('keenUserId')){
            $.cookie('keenUserId', uuid.v1(), {expires: 365, path: '/'});
        }

        return $.cookie('keenUserId');
    },

    trackPageView: function(){
        this.createOrUpdateKeenSession();
        var ctx = window.contextVars;
        var returning = $.cookie('keenUserId') ? true : false;
        var pageView = {
            'pageUrl': document.URL,
            'keenUserId': this.getOrCreateKeenId(),
            'sessionId': $.cookie('keenSessionId'),
            'pageTitle': document.title,
            'userAgent': '${keen.user_agent}',
            'referrer': {
                'url': document.referrer
            },
            'ipAddress': '${keen.ip}',
            'returning': returning,
            'keen': {
                'addons': [
                    {
                        'name': 'keen:ip_to_geo',
                        'input': {
                            'ip': 'ipAddress'
                        },
                        'output': 'ipGeoInfo'
                    },
                    {
                        'name': 'keen:ua_parser',
                        'input': {
                            'ua_string': 'userAgent'
                        },
                        'output': 'parsedUserAgent'
                    },
                    {
                        'name': 'keen:referrer_parser',
                        'input': {
                            'referrer_url': 'referrer.url',
                            'page_url': 'pageUrl'
                        },
                        'output': 'referrer.info'
                    },
                    {
                        'name' : 'keen:url_parser',
                        'input' : {
                            'url' : 'pageUrl'
                        },
                        'output' : 'parsedPageUrl'
                    }
                ]
            }
            // 'daysSinceFirstVisit':'',
            // 'daysSinceLastVisit': '',
            //'resolution': '' //temp user agent stuff
            //'generation_time': ''
            //'timeSpend': ''
        };
        if(ctx.node){
            pageView.node = {
                'id': ctx.node.id,
                'title': ctx.node.title,
                'type': ctx.node.category,
                'tags': ctx.node.tags
            };
        }
        if(ctx.currentUser){
            pageView.user = ctx.currentUser;
        }

        this.keenClient.addEvent('pageviews', pageView, function(err){
            if(err){
                throw 'Error sending Keen data: ' + err;
            }
        });
    },

    trackCustomEvent: function(eventCollection, eventData){
        this.keenClient.addEvent(eventCollection, eventData);
    },

    init: function(){
        this.trackPageView();
    }
});

module.exports = KeenTracker;
<commit_msg>CR 2 fixes<commit_after>"use strict";

var keen = require('keen-js');
var oop = require('js/oop');
var $ = require('jquery');
var uuid = require('uuid');

var KeenTracker = oop.defclass({
    constructor: function(keenProjectId, keenWriteKey) {
        this.keenClient = new keen({
            projectId: keenProjectId,
            writeKey: keenWriteKey
        });
        this.init();
    },

    createOrUpdateKeenSession: function() {
        var date = new Date();
        var expiresInMinutes = 25;
        var expDate = date.setTime(date.getTime() + (expiresInMinutes*60*1000));
        if(!$.cookie('keenSessionId')){
            $.cookie('keenSessionId', uuid.v1(), {expires: expDate, path: '/'});
        } else {
            var sessionId = $.cookie('keenSessionId');
            $.cookie('keenSessionId', sessionId, {expires: expDate, path: '/'});
        }
    },

    getOrCreateKeenId: function() {
        if(!$.cookie('keenUserId')){
            $.cookie('keenUserId', uuid.v1(), {expires: 365, path: '/'});
        }

        return $.cookie('keenUserId');
    },

    trackPageView: function(){
        this.createOrUpdateKeenSession();
        var ctx = window.contextVars;
        var returning = $.cookie('keenUserId') ? true : false;
        var pageView = {
            'pageUrl': document.URL,
            'keenUserId': this.getOrCreateKeenId(),
            'sessionId': $.cookie('keenSessionId'),
            'pageTitle': document.title,
            'userAgent': '${keen.user_agent}',
            'referrer': {
                'url': document.referrer
            },
            'ipAddress': '${keen.ip}',
            'returning': returning,
            'keen': {
                'addons': [
                    {
                        'name': 'keen:ip_to_geo',
                        'input': {
                            'ip': 'ipAddress'
                        },
                        'output': 'ipGeoInfo'
                    },
                    {
                        'name': 'keen:ua_parser',
                        'input': {
                            'ua_string': 'userAgent'
                        },
                        'output': 'parsedUserAgent'
                    },
                    {
                        'name': 'keen:referrer_parser',
                        'input': {
                            'referrer_url': 'referrer.url',
                            'page_url': 'pageUrl'
                        },
                        'output': 'referrer.info'
                    },
                    {
                        'name' : 'keen:url_parser',
                        'input' : {
                            'url' : 'pageUrl'
                        },
                        'output' : 'parsedPageUrl'
                    }
                ]
            }
            // 'daysSinceFirstVisit':'',
            // 'daysSinceLastVisit': '',
            //'resolution': '' //temp user agent stuff
            //'generation_time': ''
            //'timeSpend': ''
        };
        if(ctx.node){
            pageView.node = {
                'id': ctx.node.id,
                'title': ctx.node.title,
                'type': ctx.node.category,
                'tags': ctx.node.tags
            };
        }
        if(ctx.currentUser){
            pageView.user = ctx.currentUser;
        }

        this.keenClient.addEvent('pageviews', pageView, function(err){
            if(err){
                throw new Error('Error sending Keen data: ' + err);
            }
        });
    },

    init: function(){
        this.trackPageView();
    }
});

module.exports = KeenTracker;
<|endoftext|>


<commit_before>events = [
    {where :'PB', desc : 'Às 9h, no IFPB. Será realizada uma batalha de novas funcionalidades. Qual será a sua favorita?', events:[{title: 'Inscrições', link: 'https://phppb.typeform.com/to/ynrUvl'}]},
    {where :'RJ', desc : 'A Festa de Lançamento do PHP7, na Cidade Maravilhosa', events:[{title: 'Mais detalhes', link: 'https://doity.com.br/phparty7-rj'}]},
    {where :'SC', desc : 'Detalhes em breve.', events:[{title: 'Em Breve', link: '#'}]},
    {where :'SP', desc : 'TestFest, TranslationFest, HandsOn, Palestras e PHParty!', events:[{title: 'Participe', link: 'https://www.meetup.com/php-sp/events/226623832/'}]},
    {where :'DF', desc : 'Um meetup para falar mais sobre o PHP7', events:[{title: 'Inscrições', link: 'https://www.meetup.com/pt/PHP-DF/events/226658599/'}]},
    {where :'MG', desc : 'Um evento para discussão da próxima revolução do PHP.', events:[{title: 'Inscrições', link: 'https://www.meetup.com/PHP-MG/events/226523277/'}]},
    {where :'RS', desc : 'Vamos conversar sobre novas funcionalidades, fazer live coding e palestras!', events:[{title: 'Participe', link: 'https://www.meetup.com/PHP-RS/events/226566799/'}]},
];
<commit_msg>PHPSC Pub<commit_after>events = [
    {where :'PB', desc : 'Às 9h, no IFPB. Será realizada uma batalha de novas funcionalidades. Qual será a sua favorita?', events:[{title: 'Inscrições', link: 'https://phppb.typeform.com/to/ynrUvl'}]},
    {where :'RJ', desc : 'A Festa de Lançamento do PHP7, na Cidade Maravilhosa', events:[{title: 'Mais detalhes', link: 'https://doity.com.br/phparty7-rj'}]},
    {where :'SC', desc : 'Às 19h, no Boteco Zé Mané, faremos o 2nd PHPSC Pub com um Sharkbowl.', events:[{title: 'Participe', link: 'http://www.meetup.com/pt/PHPSC-Floripa/events/226135727/'}]},
    {where :'SP', desc : 'TestFest, TranslationFest, HandsOn, Palestras e PHParty!', events:[{title: 'Participe', link: 'https://www.meetup.com/php-sp/events/226623832/'}]},
    {where :'DF', desc : 'Um meetup para falar mais sobre o PHP7', events:[{title: 'Inscrições', link: 'https://www.meetup.com/pt/PHP-DF/events/226658599/'}]},
    {where :'MG', desc : 'Um evento para discussão da próxima revolução do PHP.', events:[{title: 'Inscrições', link: 'https://www.meetup.com/PHP-MG/events/226523277/'}]},
    {where :'RS', desc : 'Vamos conversar sobre novas funcionalidades, fazer live coding e palestras!', events:[{title: 'Participe', link: 'https://www.meetup.com/PHP-RS/events/226566799/'}]},
];
<|endoftext|>


<commit_before>import antidiary from '../images/antidiary-1.png';
import biteMe from '../images/bite-me-1.png';
import destroyer from '../images/destroyer-1.png';
import diplo from '../images/diplo-1.png';
import fanmail from '../images/fanmail-1.png';
import kswiss from '../images/kswiss-1.png';

export default [
  {
    agency: 'R/GA',
    description: 'I developed a motion-activated mobile audio player app in Angular using the device motion JavaScript API. The app promoted Samsung’s fitness products and would play an exclusive music mix by Diplo only when a certain threshold of device movement was detected to encourage dancing/running/walking/etc. Done while at R/GA.',
    images: [
      {
        src: diplo,
      },
    ],
    link: null,
    title: 'Move With Galaxy',
  },
  {
    agency: 'R/GA',
    description: 'I worked on a team developing an immersive 3D mobile app in Angular for Rihanna in partnership with Samsung to promote her 2016 album release. I was responsible for overall app architecture and routing as well as writing and styling many of the app’s Angular components. Done while at R/GA.',
    images: [
      {
        src: antidiary,
      },
    ],
    link: null,
    title: 'Rihanna Antidiary',
  },
  {
    description: 'I did all front end development for a previous version of K-Swiss’s website.',
    images: [
      {
        src: kswiss,
      },
    ],
    title: 'K-Swiss',
  },
  {
    agency: 'NoFavorite',
    description: 'I did all front end development for the Fanmail e-commerce site. Fully responsive. Done through NoFavorite.',
    images: [
      {
        src: fanmail,
      },
    ],
    title: 'Fanmail',
  },
  {
    description: 'I wrote all grid touch interaction for Destroyer, an iPhone app by The Strange Agency that lets you rearrange and manipulate sound loops.',
    images: [
      {
        src: destroyer,
      },
    ],
    title: 'Destroyer',
  },
  {
    description: 'I did all development for Bite Me, an iPad game available for free in the iTunes app store. Written in Objective-C.',
    images: [
      {
        src: biteMe,
      },
    ],
    title: 'Bite Me',
  },
];
<commit_msg>update projects copy and add year<commit_after>import antidiary from '../images/antidiary-1.png';
import biteMe from '../images/bite-me-1.png';
import destroyer from '../images/destroyer-1.png';
import diplo from '../images/diplo-1.png';
import fanmail from '../images/fanmail-1.png';
import kswiss from '../images/kswiss-1.png';

export default [
  {
    agency: 'R/GA',
    description: 'I developed a motion-activated mobile audio player app in Angular using the device motion JavaScript API. The app promoted Samsung’s fitness products and would play an exclusive music mix by Diplo only when a certain threshold of device movement was detected to encourage dancing, running, walking, and so on.',
    images: [
      {
        src: diplo,
      },
    ],
    link: null,
    title: 'Move With Galaxy',
    year: 2016,
  },
  {
    agency: 'R/GA',
    description: 'I worked on a team developing an immersive 3D mobile app in Angular for Rihanna in partnership with Samsung to promote her 2016 album release. I was responsible for overall app architecture and routing as well as writing and styling many of the app’s Angular components.',
    images: [
      {
        src: antidiary,
      },
    ],
    link: null,
    title: 'Rihanna Antidiary',
    year: 2015,
  },
  {
    agency: 'NoFavorite',
    description: 'I did all front end development for the Fanmail e-commerce site. Fully responsive.',
    images: [
      {
        src: fanmail,
      },
    ],
    title: 'Fanmail',
    year: 2013,
  },
  {
    description: 'I wrote all grid touch interaction for Destroyer, an iPhone app by The Strange Agency that lets you rearrange and manipulate sound loops.',
    images: [
      {
        src: destroyer,
      },
    ],
    title: 'Destroyer',
    year: 2012,
  },
  {
    description: 'I did all front end development for a previous version of K-Swiss’s website.',
    images: [
      {
        src: kswiss,
      },
    ],
    title: 'K-Swiss',
    year: 2011,
  },
  {
    description: 'I did all development for Bite Me, an iPad game available for free in the iTunes app store. Written in Objective-C.',
    images: [
      {
        src: biteMe,
      },
    ],
    title: 'Bite Me',
    year: 2011,
  },
];
<|endoftext|>


<commit_before>// eslint-disable-next-line
'use strict'

const description =
  '
Check out the speaker lineup ' +
  ' here.
'

const southShore = {
  time: '10:00 19:00',
  unified: {
    title: 'Community Trip',
    description:
    '

'+
    '
South Coast Adventure. Waterfalls and black sand beaches on an amazing day.
' +
    '
In a single day you can see the famous waterfalls Seljalandsfoss & Skógafoss, visit Reynisfjara, the dramatic black sand beach near Vík.
' +
    '
Tour duration: 10:00 – 20:00
' +
    '
On this tour you will see:
• Sólheimajökull
• Vík
• Reynisfjara
• Reynisdrangar
• Skógafoss
• Seljalandsfoss
' +
    '
Tickets are sold separately for both attendees and SOs. Attendees will receive a link via email to buy tickets.
',
  },
}

const blueLagoon = {
  time: '09:00 14:00',
  unified: {
    title: 'Blue Lagoon Farewell Brunch',
    description:
    '
Enjoy brunch at the Blue Lagoon as a final gathering after the conference. Then relax in the lagoon as long as you like. Includes transportation from city center, brunch buffet, and access to the lagoon.
' +
    '
The buses leave at 9am, the brunch starts at 10am and access to the lagoon starts at 11am.
' +
    '
Tickets are sold separately for both attendees and SOs. Attendees will receive a link via email to buy tickets.
',
  },
}

const conferenceDays = [
  {
    date: new Date('Wednesday February 28, 2018'),
    slots: [
      {
        time: '20:00 23:59',
        unified: {
          title: 'Welcome Reception at Hard Rock',
          description: '
Come to the welcome reception, meet fellow attendees and pick-up your badge at Hard Rock. The reception is situated on the famous Lækjargata, in the heart of Reykjavik City. Hard Rock Cafe Reykjavik contains three floors, each with its own distinctive vibe.
' +
            '
We look forward to seeing you!
',
        },
      },
    ],
  },
  {
    date: new Date('Thursday March 1, 2018'),
    slots: [
      {
        time: '08:00 09:15',
        unified: {
          grayed: true,
          title: 'Coffee and badge pick-up',
        },
      },
      {
        time: '09:15 09:45',
        unified: {
          grayed: true,
          title: 'Opening JSConf Iceland 2018',
        },
      },
      {
        time: '09:45 10:45',
        unified: {
          title: 'Talks [TBA]',
          description,
        },
      },
      {
        time: '10:45 11:15',
        unified: {
          grayed: true,
          title: 'Break',
        },
      },
      {
        time: '11:15 12:30',
        unified: {
          title: 'Talks [TBA]',
          description,
        },
      },
      {
        time: '12:30 13:30',
        unified: {
          grayed: true,
          title: 'Lunch',
        },
      },
      {
        time: '13:30 15:30',
        unified: {
          title: 'Talks [TBA]',
          description,
        },
      },
      {
        time: '15:30 16:00',
        unified: {
          grayed: true,
          title: 'Break',
        },
      },
      {
        time: '16:00 18:00',
        unified: {
          title: 'Talks [TBA]',
          description,
        },
      },
      {
        time: '19:00 23:00',
        unified: {
          grayed: true,
          title: 'Party, details TBA',
        },
      },
    ],
  },
  {
    date: new Date('Friday March 2, 2018'),
    slots: [
      {
        time: '08:45 09:45',
        unified: {
          grayed: true,
          title: 'Coffee',
        },
      },
      {
        time: '09:45 12:30',
        unified: {
          title: 'Talks [TBA]',
          description,
        },
      },
      {
        time: '12:30 13:30',
        unified: {
          grayed: true,
          title: 'Lunch',
        },
      },
      {
        time: '13:30 15:30',
        unified: {
          title: 'Talks [TBA]',
          description,
        },
      },
      {
        time: '15:30 16:00',
        unified: {
          grayed: true,
          title: 'Break',
        },
      },
      {
        time: '16:00 17:30',
        unified: {
          title: 'Talks [TBA]',
          description,
        },
      },
      {
        time: '17:30 18:00',
        unified: {
          grayed: true,
          title: 'Closing remarks',
        },
      },
      {
        time: '19:00 23:00',
        unified: {
          grayed: true,
          title: 'Party, details TBA',
        },
      },
    ],
  },
  {
    date: new Date('Saturday March 3, 2018'),
    slots: [
      southShore,
    ],
  },
  {
    date: new Date('Sunday March 4, 2018'),
    slots: [
      blueLagoon,
    ],
  },
]

const soDays = [
  {
    date: new Date('Wednesday February 28, 2018'),
    slots: [
      {
        time: '20:00 23:59',
        unified: {
          title: 'Welcome Reception at Hard Rock',
          description: '
Come to the welcome reception, meet conference attendees and other' +
          ' SOs at Hard Rock. The reception is situated on the famous Lækjargata, in the heart' +
          ' of Reykjavik City. Hard Rock Cafe Reykjavik contains three floors, each with its own distinctive vibe.
' +
          '
We look forward to seeing you!
',
        },
      },
    ],
  },
  {
    date: new Date('Thursday March 1, 2018'),
    slots: [
      {
        time: '09:00 09:30',
        unified: {
          grayed: true,
          title: 'Grab your Hop-On, Hop-Off bus tickets at Harpa.',
        },
      },
      {
        time: '09:30 17:00',
        unified: {
          grayed: true,
          title: 'Tour the city.',
        },
      },
      {
        time: '17:00 17:30',
        unified: {
          grayed: true,
          title: 'Arrive back to Harpa.',
        },
      },
      {
        time: '19:00 23:00',
        unified: {
          grayed: true,
          title: 'Party at Ægisgarður',
        },
      },
    ],
  },
  {
    date: new Date('Friday March 2, 2018'),
    noTracks: true,
    slots: [
      {
        time: '09:30 9:45',
        unified: {
          grayed: true,
          title: 'Please arrive early, bus leaves at 9:45.',
        },
      },
      {
        time: '9:45 18:00',
        unified: {
          grayed: true,
          title: 'The Golden Circle day trip. See Geysir, Gullfoss and Þingvellir.',
        },
      },
      {
        time: '17:30 18:00',
        unified: {
          grayed: true,
          title: 'Arrive back to Harpa.',
        },
      },
      {
        time: '19:00 23:00',
        unified: {
          grayed: true,
          title: 'Party, details TBA',
        },
      },
    ],
  },
  {
    date: new Date('Saturday March 3, 2018'),
    slots: [
      southShore,
    ],
  },
  {
    date: new Date('Sunday March 4, 2018'),
    slots: [
      blueLagoon,
    ],
  },
]

/*
function trackFor(slug) {
  return {
    ...speaker,
    name: speaker.name,
    title: speaker.title,
    link: `/speakers/${speaker.slug}/`,
  }
}
*/

function speakerToSlot (slot) {
  const timeSlot = slot
  const keys = Object.keys(slot).filter(
    x => ['unified', 'Hekla', 'Katla'].indexOf(x) !== -1
  )

  timeSlot.tracks = keys.map(type => slot[type])

  return timeSlot
}

function mapDays (days) {
  return days.map(day_ => {
    const day = day_
    day.slots = day.slots.map(speakerToSlot)
    return day
  })
}

export const conference = mapDays(conferenceDays)
export const so = mapDays(soDays)
<commit_msg>Constistency in party titles<commit_after>// eslint-disable-next-line
'use strict'

const description =
  '
Check out the speaker lineup ' +
  ' here.
'

const southShore = {
  time: '10:00 19:00',
  unified: {
    title: 'Community Trip',
    description:
    '

'+
    '
South Coast Adventure. Waterfalls and black sand beaches on an amazing day.
' +
    '
In a single day you can see the famous waterfalls Seljalandsfoss & Skógafoss, visit Reynisfjara, the dramatic black sand beach near Vík.
' +
    '
Tour duration: 10:00 – 20:00
' +
    '
On this tour you will see:
• Sólheimajökull
• Vík
• Reynisfjara
• Reynisdrangar
• Skógafoss
• Seljalandsfoss
' +
    '
Tickets are sold separately for both attendees and SOs. Attendees will receive a link via email to buy tickets.
',
  },
}

const blueLagoon = {
  time: '09:00 14:00',
  unified: {
    title: 'Blue Lagoon Farewell Brunch',
    description:
    '
Enjoy brunch at the Blue Lagoon as a final gathering after the conference. Then relax in the lagoon as long as you like. Includes transportation from city center, brunch buffet, and access to the lagoon.
' +
    '
The buses leave at 9am, the brunch starts at 10am and access to the lagoon starts at 11am.
' +
    '
Tickets are sold separately for both attendees and SOs. Attendees will receive a link via email to buy tickets.
',
  },
}

const conferenceDays = [
  {
    date: new Date('Wednesday February 28, 2018'),
    slots: [
      {
        time: '20:00 23:59',
        unified: {
          title: 'Welcome Reception at Hard Rock',
          description: '
Come to the welcome reception, meet fellow attendees and pick-up your badge at Hard Rock. The reception is situated on the famous Lækjargata, in the heart of Reykjavik City. Hard Rock Cafe Reykjavik contains three floors, each with its own distinctive vibe.
' +
            '
We look forward to seeing you!
',
        },
      },
    ],
  },
  {
    date: new Date('Thursday March 1, 2018'),
    slots: [
      {
        time: '08:00 09:15',
        unified: {
          grayed: true,
          title: 'Coffee and badge pick-up',
        },
      },
      {
        time: '09:15 09:45',
        unified: {
          grayed: true,
          title: 'Opening JSConf Iceland 2018',
        },
      },
      {
        time: '09:45 10:45',
        unified: {
          title: 'Talks [TBA]',
          description,
        },
      },
      {
        time: '10:45 11:15',
        unified: {
          grayed: true,
          title: 'Break',
        },
      },
      {
        time: '11:15 12:30',
        unified: {
          title: 'Talks [TBA]',
          description,
        },
      },
      {
        time: '12:30 13:30',
        unified: {
          grayed: true,
          title: 'Lunch',
        },
      },
      {
        time: '13:30 15:30',
        unified: {
          title: 'Talks [TBA]',
          description,
        },
      },
      {
        time: '15:30 16:00',
        unified: {
          grayed: true,
          title: 'Break',
        },
      },
      {
        time: '16:00 18:00',
        unified: {
          title: 'Talks [TBA]',
          description,
        },
      },
      {
        time: '19:00 23:00',
        unified: {
          grayed: true,
          title: 'Party, details TBA',
        },
      },
    ],
  },
  {
    date: new Date('Friday March 2, 2018'),
    slots: [
      {
        time: '08:45 09:45',
        unified: {
          grayed: true,
          title: 'Coffee',
        },
      },
      {
        time: '09:45 12:30',
        unified: {
          title: 'Talks [TBA]',
          description,
        },
      },
      {
        time: '12:30 13:30',
        unified: {
          grayed: true,
          title: 'Lunch',
        },
      },
      {
        time: '13:30 15:30',
        unified: {
          title: 'Talks [TBA]',
          description,
        },
      },
      {
        time: '15:30 16:00',
        unified: {
          grayed: true,
          title: 'Break',
        },
      },
      {
        time: '16:00 17:30',
        unified: {
          title: 'Talks [TBA]',
          description,
        },
      },
      {
        time: '17:30 18:00',
        unified: {
          grayed: true,
          title: 'Closing remarks',
        },
      },
      {
        time: '19:00 23:00',
        unified: {
          grayed: true,
          title: 'Party, details TBA',
        },
      },
    ],
  },
  {
    date: new Date('Saturday March 3, 2018'),
    slots: [
      southShore,
    ],
  },
  {
    date: new Date('Sunday March 4, 2018'),
    slots: [
      blueLagoon,
    ],
  },
]

const soDays = [
  {
    date: new Date('Wednesday February 28, 2018'),
    slots: [
      {
        time: '20:00 23:59',
        unified: {
          title: 'Welcome Reception at Hard Rock',
          description: '
Come to the welcome reception, meet conference attendees and other' +
          ' SOs at Hard Rock. The reception is situated on the famous Lækjargata, in the heart' +
          ' of Reykjavik City. Hard Rock Cafe Reykjavik contains three floors, each with its own distinctive vibe.
' +
          '
We look forward to seeing you!
',
        },
      },
    ],
  },
  {
    date: new Date('Thursday March 1, 2018'),
    slots: [
      {
        time: '09:00 09:30',
        unified: {
          grayed: true,
          title: 'Grab your Hop-On, Hop-Off bus tickets at Harpa.',
        },
      },
      {
        time: '09:30 17:00',
        unified: {
          grayed: true,
          title: 'Tour the city.',
        },
      },
      {
        time: '17:00 17:30',
        unified: {
          grayed: true,
          title: 'Arrive back to Harpa.',
        },
      },
      {
        time: '19:00 23:00',
        unified: {
          grayed: true,
          title: 'Party, details TBA',
        },
      },
    ],
  },
  {
    date: new Date('Friday March 2, 2018'),
    noTracks: true,
    slots: [
      {
        time: '09:30 9:45',
        unified: {
          grayed: true,
          title: 'Please arrive early, bus leaves at 9:45.',
        },
      },
      {
        time: '9:45 18:00',
        unified: {
          grayed: true,
          title: 'The Golden Circle day trip. See Geysir, Gullfoss and Þingvellir.',
        },
      },
      {
        time: '17:30 18:00',
        unified: {
          grayed: true,
          title: 'Arrive back to Harpa.',
        },
      },
      {
        time: '19:00 23:00',
        unified: {
          grayed: true,
          title: 'Party, details TBA',
        },
      },
    ],
  },
  {
    date: new Date('Saturday March 3, 2018'),
    slots: [
      southShore,
    ],
  },
  {
    date: new Date('Sunday March 4, 2018'),
    slots: [
      blueLagoon,
    ],
  },
]

/*
function trackFor(slug) {
  return {
    ...speaker,
    name: speaker.name,
    title: speaker.title,
    link: `/speakers/${speaker.slug}/`,
  }
}
*/

function speakerToSlot (slot) {
  const timeSlot = slot
  const keys = Object.keys(slot).filter(
    x => ['unified', 'Hekla', 'Katla'].indexOf(x) !== -1
  )

  timeSlot.tracks = keys.map(type => slot[type])

  return timeSlot
}

function mapDays (days) {
  return days.map(day_ => {
    const day = day_
    day.slots = day.slots.map(speakerToSlot)
    return day
  })
}

export const conference = mapDays(conferenceDays)
export const so = mapDays(soDays)
<|endoftext|>


<commit_before>function clampIntRange(num, min, max) {
	num = Math.floor(num);
	if (num < min) num = min;
	if (typeof max !== 'undefined' && num > max) num = max;
	return num;
}
exports.BattleStatuses = {
	brn: {
		effectType: 'Status',
		onStart: function(target) {
			this.add('-status', target.id, 'brn');
		},
		onBasePower: function(basePower, attacker, defender, move) {
			if (move && move.category === 'Physical' && attacker && attacker.ability !== 'guts') {
				return basePower / 2;
			}
		},
		onResidualOrder: 9,
		onResidual: function(pokemon) {
			this.damage(pokemon.maxhp/8);
		}
	},
	par: {
		effectType: 'Status',
		onStart: function(target) {
			this.add('-status', target.id, 'par');
		},
		onModifyStats: function(stats, pokemon) {
			if (pokemon.ability !== 'quickfeet') {
				stats.spe /= 4;
			}
		},
		onBeforeMovePriority: 2,
		onBeforeMove: function(pokemon) {
			if (this.random(4) === 0) {
				this.add('cant', pokemon.id, 'par');
				return false;
			}
		}
	},
	slp: {
		effectType: 'Status',
		onStart: function(target) {
			this.add('-status', target.id, 'slp');
			// 1-3 turns
			this.effectData.startTime = this.random(2,5);
			this.effectData.time = this.effectData.startTime;
			if (target.getAbility().isHalfSleep) {
				this.effectData.time = Math.floor(this.effectData.time / 2);
			}
		},
		onSwitchIn: function(target) {
			this.effectData.time = this.effectData.startTime;
			if (target.getAbility().isHalfSleep) {
				this.effectData.time = Math.floor(this.effectData.time / 2);
			}
		},
		onBeforeMovePriority: 2,
		onBeforeMove: function(pokemon, target, move) {
			pokemon.statusData.time--;
			if (!pokemon.statusData.time) {
				pokemon.cureStatus();
				return;
			}
			this.add('cant', pokemon.id, 'slp');
			if (move.sleepUsable) {
				return;
			}
			return false;
		}
	},
	frz: {
		effectType: 'Status',
		onStart: function(target) {
			this.add('-status', target.id, 'frz');
		},
		onBeforeMovePriority: 2,
		onBeforeMove: function(pokemon, target, move) {
			if (move.thawsUser || this.random(5) === 0) {
				pokemon.cureStatus();
				return;
			}
			this.add('cant', pokemon.id, 'frz');
			return false;
		},
		onHit: function(target, source, move) {
			if (move.type === 'Fire' && move.category !== 'Status') {
				target.cureStatus();
			}
		}
	},
	psn: {
		effectType: 'Status',
		onStart: function(target) {
			this.add('-status', target.id, 'psn');
		},
		onResidualOrder: 9,
		onResidual: function(pokemon) {
			this.damage(pokemon.maxhp/8);
		}
	},
	tox: {
		effectType: 'Status',
		onStart: function(target) {
			this.add('-status', target.id, 'tox');
			this.effectData.stage = 0;
		},
		onSwitchIn: function() {
			this.effectData.stage = 0;
		},
		onResidualOrder: 9,
		onResidual: function(pokemon) {
			if (this.effectData.stage < 15) {
				this.effectData.stage++;
			}
			this.damage(clampIntRange(pokemon.maxhp/16, 1)*this.effectData.stage);
		}
	},
	confusion: {
		// this is a volatile status
		onStart: function(target) {
			this.add('-start', target.id, 'confusion');
			this.effectData.time = this.random(2,6);
		},
		onEnd: function(target) {
			this.add('-end', target.id, 'confusion');
		},
		onBeforeMove: function(pokemon) {
			pokemon.volatiles.confusion.time--;
			if (!pokemon.volatiles.confusion.time) {
				pokemon.removeVolatile('confusion');
				return;
			}
			this.add('-activate', pokemon.id, 'confusion');
			if (this.random(2) === 0) {
				return;
			}
			this.damage(this.getDamage(pokemon,pokemon,40));
			return false;
		}
	},
	flinch: {
		duration: 1,
		onBeforeMovePriority: 1,
		onBeforeMove: function(pokemon) {
			if (!this.runEvent('Flinch', pokemon)) {
				return;
			}
			this.add('cant', pokemon, 'flinch');
			return false;
		}
	},
	trapped: {
		noCopy: true,
		onModifyPokemon: function(pokemon) {
			if (!this.effectData.source || !this.effectData.source.isActive) {
				delete pokemon.volatiles['trapped'];
				return;
			}
			pokemon.trapped = true;
		}
	},
	partiallytrapped: {
		duration: 5,
		durationCallback: function(target, source) {
			if (source.item === 'gripclaw') return 6;
			return this.random(5,7);
		},
		onResidualOrder: 11,
		onResidual: function(pokemon) {
			if (this.effectData.source && (!this.effectData.source.isActive || this.effectData.source.hp <= 0)) {
				pokemon.removeVolatile('partiallytrapped');
				return;
			}
			if (this.effectData.source.item === 'bindingband') {
				this.damage(pokemon.maxhp/8);
			} else {
				this.damage(pokemon.maxhp/16);
			}
		},
		onEnd: function(pokemon) {
			this.add('-end', pokemon, this.effectData.sourceEffect.id, '[partiallytrapped]');
		},
		onModifyPokemon: function(pokemon) {
			pokemon.trapped = true;
		}
	},
	lockedmove: {
		// Outrage, Thrash, Petal Dance...
		durationCallback: function() {
			return this.random(2,4);
		},
		onResidual: function(target) {
			var move = this.getMove(target.lastMove);
			if (!move.self || move.self.volatileStatus !== 'lockedmove') {
				// don't lock, and bypass confusion for calming
				delete target.volatiles['lockedmove'];
			}
		},
		onEnd: function(target) {
			this.add('-end', target, 'rampage');
			target.addVolatile('confusion');
		},
		onLockMove: function(pokemon) {
			return pokemon.lastMove;
		},
		onBeforeTurn: function(pokemon) {
			var move = this.getMove(pokemon.lastMove);
			if (pokemon.lastMove) {
				this.debug('Forcing into '+pokemon.lastMove);
				this.changeDecision(pokemon, {move: pokemon.lastMove});
			}
		}
	},
	choicelock: {
		onStart: function(pokemon) {
			this.effectData.move = this.activeMove.id;
			if (!this.effectData.move) return false;
		},
		onModifyPokemon: function(pokemon) {
			if (!pokemon.hasMove(this.effectData.move)) {
				return;
			}
			if (!pokemon.getItem().isChoice) {
				pokemon.removeVolatile('choicelock');
				return;
			}
			var moves = pokemon.moveset;
			for (var i=0; i<moves.length; i++) {
				if (moves[i].id !== this.effectData.move) {
					moves[i].disabled = true;
				}
			}
		}
	},
	mustrecharge: {
		duration: 2,
		onBeforeMove: function(pokemon) {
			this.add('cant', pokemon, 'recharge');
			return false;
		},
		onLockMove: 'recharge'
	},
	futuremove: {
		// this is a side condition
		onStart: function(side) {
			this.effectData.positions = [];
			for (var i=0; i<side.active.length; i++) {
				this.effectData.positions[i] = null;
			}
		},
		onResidualOrder: 3,
		onResidual: function(side) {
			var finished = true;
			for (var i=0; i<side.active.length; i++) {
				var posData = this.effectData.positions[i];
				if (!posData) continue;

				posData.duration--;

				if (posData.duration > 0) {
					finished = false;
					continue;
				}

				// time's up; time to hit! :D
				var target = side.foe.active[posData.targetPosition];
				var move = this.getMove(posData.move);
				if (target.fainted) {
					this.add('-hint', ''+move.name+' did not hit because the target is fainted.');
					this.effectData.positions[i] = null;
					continue;
				}

				this.add('-message', ''+move.name+' hit! (placeholder)');
				target.removeVolatile('Protect');
				target.removeVolatile('Endure');

				if (typeof posData.moveData.affectedByImmunities === 'undefined') {
					posData.moveData.affectedByImmunities = true;
				}

				this.moveHit(target, posData.source, move, posData.moveData);

				this.effectData.positions[i] = null;
			}
			if (finished) {
				side.removeSideCondition('futuremove');
			}
		}
	},
	stall: {
		// Protect, Detect, Endure counter
		duration: 2,
		onStart: function() {
			this.effectData.counter = 2;
		},
		onRestart: function() {
			this.effectData.counter *= 2;
			this.effectData.duration = 2;
		}
	},

	// weather

	// weather is implemented here since it's so important to the game

	raindance: {
		effectType: 'Weather',
		duration: 5,
		durationCallback: function(source, effect) {
			if (source && source.item === 'damprock') {
				return 8;
			}
			return 5;
		},
		onBasePower: function(basePower, attacker, defender, move) {
			if (move.type === 'Water') {
				this.debug('rain water boost');
				return basePower * 1.5;
			}
			if (move.type === 'Fire') {
				this.debug('rain fire suppress');
				return basePower * .5;
			}
		},
		onStart: function(battle, source, effect) {
			if (effect && effect.effectType === 'Ability') {
				this.effectData.duration = 0;
				this.add('-weather', 'RainDance', '[from] ability: '+effect, '[of] '+source);
			} else {
				this.add('-weather', 'RainDance');
			}
		},
		onResidualOrder: 1,
		onResidual: function() {
			this.add('-weather', 'RainDance', '[upkeep]');
			this.eachEvent('Weather');
		},
		onEnd: function() {
			this.add('-weather', 'none');
		}
	},
	sunnyday: {
		effectType: 'Weather',
		duration: 5,
		durationCallback: function(source, effect) {
			if (source && source.item === 'heatrock') {
				return 8;
			}
			return 5;
		},
		onBasePower: function(basePower, attacker, defender, move) {
			if (move.type === 'Fire') {
				this.debug('Sunny Day fire boost');
				return basePower * 1.5;
			}
			if (move.type === 'Water') {
				this.debug('Sunny Day water suppress');
				return basePower * .5;
			}
		},
		onStart: function(battle, source, effect) {
			if (effect && effect.effectType === 'Ability') {
				this.effectData.duration = 0;
				this.add('-weather', 'SunnyDay', '[from] ability: '+effect, '[of] '+source);
			} else {
				this.add('-weather', 'SunnyDay');
			}
		},
		onImmunity: function(type) {
			if (type === 'frz') return false;
		},
		onResidualOrder: 1,
		onResidual: function() {
			this.add('-weather', 'SunnyDay', '[upkeep]');
			this.eachEvent('Weather');
		},
		onEnd: function() {
			this.add('-weather', 'none');
		}
	},
	sandstorm: {
		effectType: 'Weather',
		duration: 5,
		durationCallback: function(source, effect) {
			if (source && source.item === 'smoothrock') {
				return 8;
			}
			return 5;
		},
		onModifyStats: function(stats, pokemon) {
			if (pokemon.hasType('Rock')) {
				stats.spd *= 3/2;
			}
		},
		onStart: function(battle, source, effect) {
			if (effect && effect.effectType === 'Ability') {
				this.effectData.duration = 0;
				this.add('-weather', 'Sandstorm', '[from] ability: '+effect, '[of] '+source);
			} else {
				this.add('-weather', 'Sandstorm');
			}
		},
		onResidualOrder: 1,
		onResidual: function() {
			this.add('-weather', 'Sandstorm', '[upkeep]');
			this.eachEvent('Weather');
		},
		onWeather: function(target) {
			this.damage(target.maxhp/16);
		},
		onEnd: function() {
			this.add('-weather', 'none');
		}
	},
	hail: {
		effectType: 'Weather',
		duration: 5,
		durationCallback: function(source, effect) {
			if (source && source.item === 'icyrock') {
				return 8;
			}
			return 5;
		},
		onStart: function(battle, source, effect) {
			if (effect && effect.effectType === 'Ability') {
				this.effectData.duration = 0;
				this.add('-weather', 'Hail', '[from] ability: '+effect, '[of] '+source);
			} else {
				this.add('-weather', 'Hail');
			}
		},
		onResidualOrder: 1,
		onResidual: function() {
			this.add('-weather', 'Hail', '[upkeep]');
			this.eachEvent('Weather');
		},
		onWeather: function(target) {
			this.damage(target.maxhp/16);
		},
		onEnd: function() {
			this.add('-weather', 'none');
		}
	}
};
<commit_msg>Remove Outrage lock if the user falls asleep.<commit_after>function clampIntRange(num, min, max) {
	num = Math.floor(num);
	if (num < min) num = min;
	if (typeof max !== 'undefined' && num > max) num = max;
	return num;
}
exports.BattleStatuses = {
	brn: {
		effectType: 'Status',
		onStart: function(target) {
			this.add('-status', target.id, 'brn');
		},
		onBasePower: function(basePower, attacker, defender, move) {
			if (move && move.category === 'Physical' && attacker && attacker.ability !== 'guts') {
				return basePower / 2;
			}
		},
		onResidualOrder: 9,
		onResidual: function(pokemon) {
			this.damage(pokemon.maxhp/8);
		}
	},
	par: {
		effectType: 'Status',
		onStart: function(target) {
			this.add('-status', target.id, 'par');
		},
		onModifyStats: function(stats, pokemon) {
			if (pokemon.ability !== 'quickfeet') {
				stats.spe /= 4;
			}
		},
		onBeforeMovePriority: 2,
		onBeforeMove: function(pokemon) {
			if (this.random(4) === 0) {
				this.add('cant', pokemon.id, 'par');
				return false;
			}
		}
	},
	slp: {
		effectType: 'Status',
		onStart: function(target) {
			this.add('-status', target.id, 'slp');
			// 1-3 turns
			this.effectData.startTime = this.random(2,5);
			this.effectData.time = this.effectData.startTime;
			if (target.getAbility().isHalfSleep) {
				this.effectData.time = Math.floor(this.effectData.time / 2);
			}
		},
		onSwitchIn: function(target) {
			this.effectData.time = this.effectData.startTime;
			if (target.getAbility().isHalfSleep) {
				this.effectData.time = Math.floor(this.effectData.time / 2);
			}
		},
		onBeforeMovePriority: 2,
		onBeforeMove: function(pokemon, target, move) {
			pokemon.statusData.time--;
			if (!pokemon.statusData.time) {
				pokemon.cureStatus();
				return;
			}
			this.add('cant', pokemon.id, 'slp');
			if (move.sleepUsable) {
				return;
			}
			return false;
		}
	},
	frz: {
		effectType: 'Status',
		onStart: function(target) {
			this.add('-status', target.id, 'frz');
		},
		onBeforeMovePriority: 2,
		onBeforeMove: function(pokemon, target, move) {
			if (move.thawsUser || this.random(5) === 0) {
				pokemon.cureStatus();
				return;
			}
			this.add('cant', pokemon.id, 'frz');
			return false;
		},
		onHit: function(target, source, move) {
			if (move.type === 'Fire' && move.category !== 'Status') {
				target.cureStatus();
			}
		}
	},
	psn: {
		effectType: 'Status',
		onStart: function(target) {
			this.add('-status', target.id, 'psn');
		},
		onResidualOrder: 9,
		onResidual: function(pokemon) {
			this.damage(pokemon.maxhp/8);
		}
	},
	tox: {
		effectType: 'Status',
		onStart: function(target) {
			this.add('-status', target.id, 'tox');
			this.effectData.stage = 0;
		},
		onSwitchIn: function() {
			this.effectData.stage = 0;
		},
		onResidualOrder: 9,
		onResidual: function(pokemon) {
			if (this.effectData.stage < 15) {
				this.effectData.stage++;
			}
			this.damage(clampIntRange(pokemon.maxhp/16, 1)*this.effectData.stage);
		}
	},
	confusion: {
		// this is a volatile status
		onStart: function(target) {
			this.add('-start', target.id, 'confusion');
			this.effectData.time = this.random(2,6);
		},
		onEnd: function(target) {
			this.add('-end', target.id, 'confusion');
		},
		onBeforeMove: function(pokemon) {
			pokemon.volatiles.confusion.time--;
			if (!pokemon.volatiles.confusion.time) {
				pokemon.removeVolatile('confusion');
				return;
			}
			this.add('-activate', pokemon.id, 'confusion');
			if (this.random(2) === 0) {
				return;
			}
			this.damage(this.getDamage(pokemon,pokemon,40));
			return false;
		}
	},
	flinch: {
		duration: 1,
		onBeforeMovePriority: 1,
		onBeforeMove: function(pokemon) {
			if (!this.runEvent('Flinch', pokemon)) {
				return;
			}
			this.add('cant', pokemon, 'flinch');
			return false;
		}
	},
	trapped: {
		noCopy: true,
		onModifyPokemon: function(pokemon) {
			if (!this.effectData.source || !this.effectData.source.isActive) {
				delete pokemon.volatiles['trapped'];
				return;
			}
			pokemon.trapped = true;
		}
	},
	partiallytrapped: {
		duration: 5,
		durationCallback: function(target, source) {
			if (source.item === 'gripclaw') return 6;
			return this.random(5,7);
		},
		onResidualOrder: 11,
		onResidual: function(pokemon) {
			if (this.effectData.source && (!this.effectData.source.isActive || this.effectData.source.hp <= 0)) {
				pokemon.removeVolatile('partiallytrapped');
				return;
			}
			if (this.effectData.source.item === 'bindingband') {
				this.damage(pokemon.maxhp/8);
			} else {
				this.damage(pokemon.maxhp/16);
			}
		},
		onEnd: function(pokemon) {
			this.add('-end', pokemon, this.effectData.sourceEffect.id, '[partiallytrapped]');
		},
		onModifyPokemon: function(pokemon) {
			pokemon.trapped = true;
		}
	},
	lockedmove: {
		// Outrage, Thrash, Petal Dance...
		durationCallback: function() {
			return this.random(2,4);
		},
		onResidual: function(target) {
			var move = this.getMove(target.lastMove);
			if (!move.self || move.self.volatileStatus !== 'lockedmove' || target.status === 'slp') {
				// don't lock, and bypass confusion for calming
				delete target.volatiles['lockedmove'];
			}
		},
		onEnd: function(target) {
			this.add('-end', target, 'rampage');
			target.addVolatile('confusion');
		},
		onLockMove: function(pokemon) {
			return pokemon.lastMove;
		},
		onBeforeTurn: function(pokemon) {
			var move = this.getMove(pokemon.lastMove);
			if (pokemon.lastMove) {
				this.debug('Forcing into '+pokemon.lastMove);
				this.changeDecision(pokemon, {move: pokemon.lastMove});
			}
		}
	},
	choicelock: {
		onStart: function(pokemon) {
			this.effectData.move = this.activeMove.id;
			if (!this.effectData.move) return false;
		},
		onModifyPokemon: function(pokemon) {
			if (!pokemon.hasMove(this.effectData.move)) {
				return;
			}
			if (!pokemon.getItem().isChoice) {
				pokemon.removeVolatile('choicelock');
				return;
			}
			var moves = pokemon.moveset;
			for (var i=0; i<moves.length; i++) {
				if (moves[i].id !== this.effectData.move) {
					moves[i].disabled = true;
				}
			}
		}
	},
	mustrecharge: {
		duration: 2,
		onBeforeMove: function(pokemon) {
			this.add('cant', pokemon, 'recharge');
			return false;
		},
		onLockMove: 'recharge'
	},
	futuremove: {
		// this is a side condition
		onStart: function(side) {
			this.effectData.positions = [];
			for (var i=0; i<side.active.length; i++) {
				this.effectData.positions[i] = null;
			}
		},
		onResidualOrder: 3,
		onResidual: function(side) {
			var finished = true;
			for (var i=0; i<side.active.length; i++) {
				var posData = this.effectData.positions[i];
				if (!posData) continue;

				posData.duration--;

				if (posData.duration > 0) {
					finished = false;
					continue;
				}

				// time's up; time to hit! :D
				var target = side.foe.active[posData.targetPosition];
				var move = this.getMove(posData.move);
				if (target.fainted) {
					this.add('-hint', ''+move.name+' did not hit because the target is fainted.');
					this.effectData.positions[i] = null;
					continue;
				}

				this.add('-message', ''+move.name+' hit! (placeholder)');
				target.removeVolatile('Protect');
				target.removeVolatile('Endure');

				if (typeof posData.moveData.affectedByImmunities === 'undefined') {
					posData.moveData.affectedByImmunities = true;
				}

				this.moveHit(target, posData.source, move, posData.moveData);

				this.effectData.positions[i] = null;
			}
			if (finished) {
				side.removeSideCondition('futuremove');
			}
		}
	},
	stall: {
		// Protect, Detect, Endure counter
		duration: 2,
		onStart: function() {
			this.effectData.counter = 2;
		},
		onRestart: function() {
			this.effectData.counter *= 2;
			this.effectData.duration = 2;
		}
	},

	// weather

	// weather is implemented here since it's so important to the game

	raindance: {
		effectType: 'Weather',
		duration: 5,
		durationCallback: function(source, effect) {
			if (source && source.item === 'damprock') {
				return 8;
			}
			return 5;
		},
		onBasePower: function(basePower, attacker, defender, move) {
			if (move.type === 'Water') {
				this.debug('rain water boost');
				return basePower * 1.5;
			}
			if (move.type === 'Fire') {
				this.debug('rain fire suppress');
				return basePower * .5;
			}
		},
		onStart: function(battle, source, effect) {
			if (effect && effect.effectType === 'Ability') {
				this.effectData.duration = 0;
				this.add('-weather', 'RainDance', '[from] ability: '+effect, '[of] '+source);
			} else {
				this.add('-weather', 'RainDance');
			}
		},
		onResidualOrder: 1,
		onResidual: function() {
			this.add('-weather', 'RainDance', '[upkeep]');
			this.eachEvent('Weather');
		},
		onEnd: function() {
			this.add('-weather', 'none');
		}
	},
	sunnyday: {
		effectType: 'Weather',
		duration: 5,
		durationCallback: function(source, effect) {
			if (source && source.item === 'heatrock') {
				return 8;
			}
			return 5;
		},
		onBasePower: function(basePower, attacker, defender, move) {
			if (move.type === 'Fire') {
				this.debug('Sunny Day fire boost');
				return basePower * 1.5;
			}
			if (move.type === 'Water') {
				this.debug('Sunny Day water suppress');
				return basePower * .5;
			}
		},
		onStart: function(battle, source, effect) {
			if (effect && effect.effectType === 'Ability') {
				this.effectData.duration = 0;
				this.add('-weather', 'SunnyDay', '[from] ability: '+effect, '[of] '+source);
			} else {
				this.add('-weather', 'SunnyDay');
			}
		},
		onImmunity: function(type) {
			if (type === 'frz') return false;
		},
		onResidualOrder: 1,
		onResidual: function() {
			this.add('-weather', 'SunnyDay', '[upkeep]');
			this.eachEvent('Weather');
		},
		onEnd: function() {
			this.add('-weather', 'none');
		}
	},
	sandstorm: {
		effectType: 'Weather',
		duration: 5,
		durationCallback: function(source, effect) {
			if (source && source.item === 'smoothrock') {
				return 8;
			}
			return 5;
		},
		onModifyStats: function(stats, pokemon) {
			if (pokemon.hasType('Rock')) {
				stats.spd *= 3/2;
			}
		},
		onStart: function(battle, source, effect) {
			if (effect && effect.effectType === 'Ability') {
				this.effectData.duration = 0;
				this.add('-weather', 'Sandstorm', '[from] ability: '+effect, '[of] '+source);
			} else {
				this.add('-weather', 'Sandstorm');
			}
		},
		onResidualOrder: 1,
		onResidual: function() {
			this.add('-weather', 'Sandstorm', '[upkeep]');
			this.eachEvent('Weather');
		},
		onWeather: function(target) {
			this.damage(target.maxhp/16);
		},
		onEnd: function() {
			this.add('-weather', 'none');
		}
	},
	hail: {
		effectType: 'Weather',
		duration: 5,
		durationCallback: function(source, effect) {
			if (source && source.item === 'icyrock') {
				return 8;
			}
			return 5;
		},
		onStart: function(battle, source, effect) {
			if (effect && effect.effectType === 'Ability') {
				this.effectData.duration = 0;
				this.add('-weather', 'Hail', '[from] ability: '+effect, '[of] '+source);
			} else {
				this.add('-weather', 'Hail');
			}
		},
		onResidualOrder: 1,
		onResidual: function() {
			this.add('-weather', 'Hail', '[upkeep]');
			this.eachEvent('Weather');
		},
		onWeather: function(target) {
			this.damage(target.maxhp/16);
		},
		onEnd: function() {
			this.add('-weather', 'none');
		}
	}
};
<|endoftext|>