<commit_before>describe('iframe launcher', function() {
  var launcher;

  beforeEach(function() {
    launcher = document.createElement('versal-iframe-launcher');
    launcher.setAttribute('data-environment', '{"test": "initial-environment"}');
    launcher.setAttribute('data-config', '{"test": "initial-config"}');
    launcher.setAttribute('data-userstate', '{"test": "initial-userstate"}');
    launcher.setAttribute('src', '/base/iframe-launcher/test/test_gadget.html');
    launcher.setAttribute('editable', 'true');
    document.body.appendChild(launcher);
  });

  afterEach(function() {
    document.body.removeChild(launcher);
  });

  it("doesn't send events before starting to listen", function(done) {
    window.gadgetLoaded = function() {
      launcher.setAttribute('data-config', '{"test": "something"}');
      window.recordPlayerEvent = function(eventMessage) {
        done("No events should be fired");
      };
      setTimeout(done, 100);
    };
  });

  describe('player events', function() {
    before(function() {
      window.gadgetLoaded = function() {
        launcher.children[0].contentWindow.sendGadgetEvent({event: 'startListening'});
      };
    });

    it('sends a bunch of initial events', function(done) {
      var recordedEvents = [];

      window.recordPlayerEvent = function(eventMessage) {
        recordedEvents.push(eventMessage);

        if (eventMessage.event == 'editableChanged') {
          chai.expect(recordedEvents).to.deep.equal([
            {event: 'environmentChanged', data: {test: 'initial-environment'}},
            {event: 'attributesChanged', data: {test: 'initial-config'}},
            {event: 'learnerStateChanged', data: {test: 'initial-userstate'}},
            {event: 'editableChanged', data: {editable: true}},
          ]);
          delete window.recordPlayerEvent;
          done();
        }
      };
    });

    it('sends attributesChanged when data-config changes', function(done) {
      window.recordPlayerEvent = function(eventMessage) {
        if (eventMessage.event == 'editableChanged') {
          launcher.setAttribute('data-config', '{"test": "new-config"}');
        }
        if (eventMessage.event == 'attributesChanged' &&
              eventMessage.data.test == 'new-config') {
          done();
        }
      };
    });

    it('doesnt send attributesChanged when data-config doesnt really change', function(done) {
      window.recordPlayerEvent = function(eventMessage) {
        if (eventMessage.event == 'editableChanged') {
          window.recordPlayerEvent = function(eventMessage) {
            if (eventMessage.event == 'attributesChanged') done("attributesChanged should not be called");
          };
          launcher.setAttribute('data-config', '{"test"   :    "initial-config"}');
        }
      };
      setTimeout(done, 100);
    });

    it('sends learnerStateChanged when data-userstate changes', function(done) {
      window.recordPlayerEvent = function(eventMessage) {
        if (eventMessage.event == 'editableChanged') {
          launcher.setAttribute('data-userstate', '{"test": "new-userstate"}');
        }
        if (eventMessage.event == 'learnerStateChanged' &&
              eventMessage.data.test == 'new-userstate') {
          done();
        }
      };
    });

    it('doesnt send learnerStateChanged when data-userstate doesnt really change', function(done) {
      window.recordPlayerEvent = function(eventMessage) {
        if (eventMessage.event == 'editableChanged') {
          window.recordPlayerEvent = function(eventMessage) {
            if (eventMessage.event == 'learnerStateChanged') done("learnerStateChanged should not be called");
          };
          launcher.setAttribute('data-userstate', '{"test"   :    "initial-userstate"}');
        }
      };
      setTimeout(done, 100);
    });

    it('sends editableChanged when editable changes', function(done) {
      window.recordPlayerEvent = function(eventMessage) {
        if (eventMessage.event == 'editableChanged') {
          launcher.setAttribute('editable', true);
        }
        if (eventMessage.event == 'editableChanged' &&
              eventMessage.data.editable === true) {
          done();
        }
      };
    });
  });

  describe('detaching and attaching again', function(){

    it('should send initial events again', function(done){
      window.gadgetLoaded = function() {
        launcher.children[0].contentWindow.sendGadgetEvent({event: 'startListening'});
      };

      var eventCount = 0;

      window.recordPlayerEvent = function(eventMessage){
        eventCount++;
        // After first 4 events, detach launcher and attach it again.
        if(eventCount == 4) {
          document.body.removeChild(launcher);
          setTimeout(function(){ document.body.appendChild(launcher); }, 1);
        };
        if(eventCount == 8) { done(); }
      };
    });
  });

  describe('gadget events', function() {

    beforeEach(function(done){
      window.gadgetLoaded = function() {
        launcher.children[0].contentWindow.sendGadgetEvent({event: 'startListening'});
      };
      window.recordPlayerEvent = function(eventMessage) {
        if (eventMessage.event == 'editableChanged') {
          done();
        }
      };
    });

    it('patches config when receiving setAttributes', function(done) {
      var observer = new MutationObserver(function() {
        chai.expect(launcher.config).to.deep.eq(
          {test: 'initial-config', test2: 'new-config'});
        observer.disconnect();
        done();
      });
      observer.observe(launcher, {attributes: true});

      launcher.children[0].contentWindow.sendGadgetEvent(
        {event: 'setAttributes', data: {test2: 'new-config'}});
    });

    it('sends attributesChanged after receiving setAttributes', function(done) {
      window.recordPlayerEvent = function(eventMessage) {
        if (eventMessage.event == 'attributesChanged' &&
              eventMessage.data.test2 == 'new-config') {
          done();
        }
      };

      launcher.children[0].contentWindow.sendGadgetEvent(
        {event: 'setAttributes', data: {test2: 'new-config'}});
    });

    it('doesNOT sends attributesChanged after receiving setAttributes ' +
       'in the learner mode', function(done) {
      launcher.removeAttribute('editable');

      window.recordPlayerEvent = function(eventMessage) {
        if (eventMessage.event == 'attributesChanged' &&
              eventMessage.data.test == 'new-config-test') {
          try{
            //error out when this code is executed
            expect(true, 'attributesChanged fired for learner').to.be.false;
            done();
          }catch(e){
            done(e);
          }
        }
      };

      //done() if recordPlayerEvent() is not invoked in 1 seconds
      setTimeout(function(){
        done();
      }, 1000);

      launcher.children[0].contentWindow.sendGadgetEvent(
        {event: 'setAttributes', data: {test: 'new-config-test'}});
    });

    it('only sends one attributesChanged after to immediately subsequent setAttributes events', function(done) {
      window.recordPlayerEvent = function(eventMessage) {
        if (eventMessage.event == 'attributesChanged' &&
              eventMessage.data.value == 2) {
          done();
        } else {
          done('attributesChanged should only fire with {value: 2}, not: ' + JSON.stringify(eventMessage));
        }
      };

      launcher.children[0].contentWindow.sendGadgetEvent(
        {event: 'setAttributes', data: {value: 1}});
      launcher.children[0].contentWindow.sendGadgetEvent(
        {event: 'setAttributes', data: {value: 2}});
    });

    it('unsets attributes that are set to null', function(done) {
      var observer = new MutationObserver(function() {
        chai.expect(launcher.config).to.deep.eq({});
        observer.disconnect();
        done();
      });

      observer.observe(launcher, {attributes: true});

      launcher.children[0].contentWindow.sendGadgetEvent(
        {event: 'setAttributes', data: {test: null}});
    });

    it('patches userstate when receiving setLearnerState', function(done) {
      var observer = new MutationObserver(function() {
        chai.expect(launcher.userstate).to.deep.eq(
          {test: 'initial-userstate', test2: 'new-userstate'});
        observer.disconnect();
        done();
      });
      observer.observe(launcher, {attributes: true});

      launcher.children[0].contentWindow.sendGadgetEvent(
        {event: 'setLearnerState', data: {test2: 'new-userstate'}});
    });

    it('unsets learnerState that are set to null', function(done) {
      var observer = new MutationObserver(function() {
        chai.expect(launcher.userstate).to.deep.eq({});
        observer.disconnect();
        done();
      });

      observer.observe(launcher, {attributes: true});

      launcher.children[0].contentWindow.sendGadgetEvent(
        {event: 'setLearnerState', data: {test: null}});
    });

    it('sends learnerStateChanged after receiving setLearnerState', function(done) {
      window.recordPlayerEvent = function(eventMessage) {
        if (eventMessage.event == 'learnerStateChanged' &&
              eventMessage.data.test2 == 'new-userstate') {
          done();
        }
      };

      launcher.children[0].contentWindow.sendGadgetEvent(
        {event: 'setLearnerState', data: {test2: 'new-userstate'}});
    });

    it('updates height when receiving setHeight', function(done) {
      var observer = new MutationObserver(function() {
        chai.expect(launcher.clientHeight).to.eq(137);
        observer.disconnect();
        done();
      });
      observer.observe(launcher, {attributes: true, subtree: true});

      launcher.children[0].contentWindow.sendGadgetEvent(
        {event: 'setHeight', data: {pixels: 137}});
    });

    it('does NOT cap height', function(done) {
      var observer = new MutationObserver(function() {
        chai.expect(launcher.clientHeight).to.eq(10000);
        observer.disconnect();
        done();
      });
      observer.observe(launcher, {attributes: true, subtree: true});

      launcher.children[0].contentWindow.sendGadgetEvent(
        {event: 'setHeight', data: {pixels: 10000}});
    });

    it('fires "rendered" the first time it receives setHeight', function(done) {
      var eventCount = 0;
      launcher.addEventListener('rendered', function() {
        eventCount++;
      });

      launcher.addEventListener('track', function() {
        chai.expect(eventCount).to.equal(1);
        done();
      });

      launcher.children[0].contentWindow.sendGadgetEvent(
        {event: 'setHeight', data: {pixels: 1337}});
      launcher.children[0].contentWindow.sendGadgetEvent(
        {event: 'setHeight', data: {pixels: 0}});
      launcher.children[0].contentWindow.sendGadgetEvent(
        {event: 'setHeight', data: {pixels: 1337}});
      launcher.children[0].contentWindow.sendGadgetEvent(
        {event: 'track'});
    });

    it('passes on some events that are handled by the player', function(done) {
      eventList = ['setPropertySheetAttributes', 'setEmpty', 'track', 'changeBlocking', 'requestAsset'];
      eventsFired = 0;
      eventList.forEach(function(eventName) {
        // count every event being fired, until we've had them all
        launcher.addEventListener(eventName, function() {
          if (++eventsFired == eventList.length) done();
        });
      });

      // send all events
      eventList.forEach(function(eventName) {
        launcher.children[0].contentWindow.sendGadgetEvent({event: eventName});
      });
    });

    it('passes on error events', function(done) {
      previousOnError = window.onerror;
      window.onerror = function() {
        window.onerror = previousOnError;
        done();
      };
      launcher.children[0].contentWindow.sendGadgetEvent({event: 'error'});
    });

    it('allows the fullscreen API', function() {
      // Unfortunately we cannot check the fullscreen API itself, because this test file
      // is run in an iframe itself, which does not have allowfullscreen set... :-(
      chai.expect(launcher.children[0].getAttribute('allowfullscreen')).to.eq('allowfullscreen');
    });
  });
});
<commit_msg>grammar<commit_after>describe('iframe launcher', function() {
  var launcher;

  beforeEach(function() {
    launcher = document.createElement('versal-iframe-launcher');
    launcher.setAttribute('data-environment', '{"test": "initial-environment"}');
    launcher.setAttribute('data-config', '{"test": "initial-config"}');
    launcher.setAttribute('data-userstate', '{"test": "initial-userstate"}');
    launcher.setAttribute('src', '/base/iframe-launcher/test/test_gadget.html');
    launcher.setAttribute('editable', 'true');
    document.body.appendChild(launcher);
  });

  afterEach(function() {
    document.body.removeChild(launcher);
  });

  it("doesn't send events before starting to listen", function(done) {
    window.gadgetLoaded = function() {
      launcher.setAttribute('data-config', '{"test": "something"}');
      window.recordPlayerEvent = function(eventMessage) {
        done("No events should be fired");
      };
      setTimeout(done, 100);
    };
  });

  describe('player events', function() {
    before(function() {
      window.gadgetLoaded = function() {
        launcher.children[0].contentWindow.sendGadgetEvent({event: 'startListening'});
      };
    });

    it('sends a bunch of initial events', function(done) {
      var recordedEvents = [];

      window.recordPlayerEvent = function(eventMessage) {
        recordedEvents.push(eventMessage);

        if (eventMessage.event == 'editableChanged') {
          chai.expect(recordedEvents).to.deep.equal([
            {event: 'environmentChanged', data: {test: 'initial-environment'}},
            {event: 'attributesChanged', data: {test: 'initial-config'}},
            {event: 'learnerStateChanged', data: {test: 'initial-userstate'}},
            {event: 'editableChanged', data: {editable: true}},
          ]);
          delete window.recordPlayerEvent;
          done();
        }
      };
    });

    it('sends attributesChanged when data-config changes', function(done) {
      window.recordPlayerEvent = function(eventMessage) {
        if (eventMessage.event == 'editableChanged') {
          launcher.setAttribute('data-config', '{"test": "new-config"}');
        }
        if (eventMessage.event == 'attributesChanged' &&
              eventMessage.data.test == 'new-config') {
          done();
        }
      };
    });

    it('doesnt send attributesChanged when data-config doesnt really change', function(done) {
      window.recordPlayerEvent = function(eventMessage) {
        if (eventMessage.event == 'editableChanged') {
          window.recordPlayerEvent = function(eventMessage) {
            if (eventMessage.event == 'attributesChanged') done("attributesChanged should not be called");
          };
          launcher.setAttribute('data-config', '{"test"   :    "initial-config"}');
        }
      };
      setTimeout(done, 100);
    });

    it('sends learnerStateChanged when data-userstate changes', function(done) {
      window.recordPlayerEvent = function(eventMessage) {
        if (eventMessage.event == 'editableChanged') {
          launcher.setAttribute('data-userstate', '{"test": "new-userstate"}');
        }
        if (eventMessage.event == 'learnerStateChanged' &&
              eventMessage.data.test == 'new-userstate') {
          done();
        }
      };
    });

    it('doesnt send learnerStateChanged when data-userstate doesnt really change', function(done) {
      window.recordPlayerEvent = function(eventMessage) {
        if (eventMessage.event == 'editableChanged') {
          window.recordPlayerEvent = function(eventMessage) {
            if (eventMessage.event == 'learnerStateChanged') done("learnerStateChanged should not be called");
          };
          launcher.setAttribute('data-userstate', '{"test"   :    "initial-userstate"}');
        }
      };
      setTimeout(done, 100);
    });

    it('sends editableChanged when editable changes', function(done) {
      window.recordPlayerEvent = function(eventMessage) {
        if (eventMessage.event == 'editableChanged') {
          launcher.setAttribute('editable', true);
        }
        if (eventMessage.event == 'editableChanged' &&
              eventMessage.data.editable === true) {
          done();
        }
      };
    });
  });

  describe('detaching and attaching again', function(){

    it('should send initial events again', function(done){
      window.gadgetLoaded = function() {
        launcher.children[0].contentWindow.sendGadgetEvent({event: 'startListening'});
      };

      var eventCount = 0;

      window.recordPlayerEvent = function(eventMessage){
        eventCount++;
        // After first 4 events, detach launcher and attach it again.
        if(eventCount == 4) {
          document.body.removeChild(launcher);
          setTimeout(function(){ document.body.appendChild(launcher); }, 1);
        };
        if(eventCount == 8) { done(); }
      };
    });
  });

  describe('gadget events', function() {

    beforeEach(function(done){
      window.gadgetLoaded = function() {
        launcher.children[0].contentWindow.sendGadgetEvent({event: 'startListening'});
      };
      window.recordPlayerEvent = function(eventMessage) {
        if (eventMessage.event == 'editableChanged') {
          done();
        }
      };
    });

    it('patches config when receiving setAttributes', function(done) {
      var observer = new MutationObserver(function() {
        chai.expect(launcher.config).to.deep.eq(
          {test: 'initial-config', test2: 'new-config'});
        observer.disconnect();
        done();
      });
      observer.observe(launcher, {attributes: true});

      launcher.children[0].contentWindow.sendGadgetEvent(
        {event: 'setAttributes', data: {test2: 'new-config'}});
    });

    it('sends attributesChanged after receiving setAttributes', function(done) {
      window.recordPlayerEvent = function(eventMessage) {
        if (eventMessage.event == 'attributesChanged' &&
              eventMessage.data.test2 == 'new-config') {
          done();
        }
      };

      launcher.children[0].contentWindow.sendGadgetEvent(
        {event: 'setAttributes', data: {test2: 'new-config'}});
    });

    it('doesnt send attributesChanged after receiving setAttributes ' +
       'in learner mode', function(done) {
      launcher.removeAttribute('editable');

      window.recordPlayerEvent = function(eventMessage) {
        if (eventMessage.event == 'attributesChanged' &&
              eventMessage.data.test == 'new-config-test') {
          try{
            //error out when this code is executed
            expect(true, 'attributesChanged fired for learner').to.be.false;
            done();
          }catch(e){
            done(e);
          }
        }
      };

      //done() if recordPlayerEvent() is not invoked in 1 seconds
      setTimeout(function(){
        done();
      }, 1000);

      launcher.children[0].contentWindow.sendGadgetEvent(
        {event: 'setAttributes', data: {test: 'new-config-test'}});
    });

    it('only sends one attributesChanged after to immediately subsequent setAttributes events', function(done) {
      window.recordPlayerEvent = function(eventMessage) {
        if (eventMessage.event == 'attributesChanged' &&
              eventMessage.data.value == 2) {
          done();
        } else {
          done('attributesChanged should only fire with {value: 2}, not: ' + JSON.stringify(eventMessage));
        }
      };

      launcher.children[0].contentWindow.sendGadgetEvent(
        {event: 'setAttributes', data: {value: 1}});
      launcher.children[0].contentWindow.sendGadgetEvent(
        {event: 'setAttributes', data: {value: 2}});
    });

    it('unsets attributes that are set to null', function(done) {
      var observer = new MutationObserver(function() {
        chai.expect(launcher.config).to.deep.eq({});
        observer.disconnect();
        done();
      });

      observer.observe(launcher, {attributes: true});

      launcher.children[0].contentWindow.sendGadgetEvent(
        {event: 'setAttributes', data: {test: null}});
    });

    it('patches userstate when receiving setLearnerState', function(done) {
      var observer = new MutationObserver(function() {
        chai.expect(launcher.userstate).to.deep.eq(
          {test: 'initial-userstate', test2: 'new-userstate'});
        observer.disconnect();
        done();
      });
      observer.observe(launcher, {attributes: true});

      launcher.children[0].contentWindow.sendGadgetEvent(
        {event: 'setLearnerState', data: {test2: 'new-userstate'}});
    });

    it('unsets learnerState that are set to null', function(done) {
      var observer = new MutationObserver(function() {
        chai.expect(launcher.userstate).to.deep.eq({});
        observer.disconnect();
        done();
      });

      observer.observe(launcher, {attributes: true});

      launcher.children[0].contentWindow.sendGadgetEvent(
        {event: 'setLearnerState', data: {test: null}});
    });

    it('sends learnerStateChanged after receiving setLearnerState', function(done) {
      window.recordPlayerEvent = function(eventMessage) {
        if (eventMessage.event == 'learnerStateChanged' &&
              eventMessage.data.test2 == 'new-userstate') {
          done();
        }
      };

      launcher.children[0].contentWindow.sendGadgetEvent(
        {event: 'setLearnerState', data: {test2: 'new-userstate'}});
    });

    it('updates height when receiving setHeight', function(done) {
      var observer = new MutationObserver(function() {
        chai.expect(launcher.clientHeight).to.eq(137);
        observer.disconnect();
        done();
      });
      observer.observe(launcher, {attributes: true, subtree: true});

      launcher.children[0].contentWindow.sendGadgetEvent(
        {event: 'setHeight', data: {pixels: 137}});
    });

    it('does NOT cap height', function(done) {
      var observer = new MutationObserver(function() {
        chai.expect(launcher.clientHeight).to.eq(10000);
        observer.disconnect();
        done();
      });
      observer.observe(launcher, {attributes: true, subtree: true});

      launcher.children[0].contentWindow.sendGadgetEvent(
        {event: 'setHeight', data: {pixels: 10000}});
    });

    it('fires "rendered" the first time it receives setHeight', function(done) {
      var eventCount = 0;
      launcher.addEventListener('rendered', function() {
        eventCount++;
      });

      launcher.addEventListener('track', function() {
        chai.expect(eventCount).to.equal(1);
        done();
      });

      launcher.children[0].contentWindow.sendGadgetEvent(
        {event: 'setHeight', data: {pixels: 1337}});
      launcher.children[0].contentWindow.sendGadgetEvent(
        {event: 'setHeight', data: {pixels: 0}});
      launcher.children[0].contentWindow.sendGadgetEvent(
        {event: 'setHeight', data: {pixels: 1337}});
      launcher.children[0].contentWindow.sendGadgetEvent(
        {event: 'track'});
    });

    it('passes on some events that are handled by the player', function(done) {
      eventList = ['setPropertySheetAttributes', 'setEmpty', 'track', 'changeBlocking', 'requestAsset'];
      eventsFired = 0;
      eventList.forEach(function(eventName) {
        // count every event being fired, until we've had them all
        launcher.addEventListener(eventName, function() {
          if (++eventsFired == eventList.length) done();
        });
      });

      // send all events
      eventList.forEach(function(eventName) {
        launcher.children[0].contentWindow.sendGadgetEvent({event: eventName});
      });
    });

    it('passes on error events', function(done) {
      previousOnError = window.onerror;
      window.onerror = function() {
        window.onerror = previousOnError;
        done();
      };
      launcher.children[0].contentWindow.sendGadgetEvent({event: 'error'});
    });

    it('allows the fullscreen API', function() {
      // Unfortunately we cannot check the fullscreen API itself, because this test file
      // is run in an iframe itself, which does not have allowfullscreen set... :-(
      chai.expect(launcher.children[0].getAttribute('allowfullscreen')).to.eq('allowfullscreen');
    });
  });
});
<|endoftext|>


<commit_before><commit_msg>Enable to move component on top of others<commit_after><|endoftext|>


<commit_before>import React, { Component, Fragment } from 'react'
import { Head } from 'react-static'
import { api } from '../../data'
import {
  ThemeProvider,
  Card,
  Container,
  Box,
  Flex,
  Text,
  Heading,
  Button,
  LargeButton,
  Link as DSLink,
  cx
} from '@hackclub/design-system'
import LoadingAnimation from '../components/LoadingAnimation'
import Login from '../components/Login'
import ApplyNav from '../components/ApplyNav'
import fetch from 'unfetch'
import { Link } from 'react-static'

LargeButton.link = LargeButton.withComponent(Link)

const A = DSLink.extend`
  :hover {
    text-decoration: underline;
  }
`

const CustomHeading = props => (
  <Heading.h2
    m={0}
    align={['center', 'left']}
    f={3}
    color="primary"
    caps
    {...props}
  />
)

const timeSince = time => {
  const seconds = Math.floor((new Date() - new Date(time)) / 1000)
  const intervals = [
    [Math.floor(seconds / (60 * 60 * 24 * 7)), 'weeks'],
    [Math.floor(seconds / (60 * 60 * 24)), 'days'],
    [Math.floor(seconds / (60 * 60)), 'hours'],
    [Math.floor(seconds / 60), 'minutes']
  ]
  for (var i = 0; i < intervals.length; i++) {
    let interval = intervals[i]
    if (interval[0] > 1) {
      return interval.join(' ')
    }
  }
  return 'less than a minute'
}

const Neg = () => <Text.span color="error" bold children="NOT" />

const CustomCard = props => (
  <Card boxShadowSize="md" p={[3, 4]} color="black" bg="snow" {...props} />
)

const ApplicationCard = props => {
  const {
    id,
    applicant_profiles,
    updated_at,
    created_at,
    submitted_at
  } = props.app

  const leaderProfile = applicant_profiles.find(
    profile => profile.applicant.id == props.applicantId
  )
  const coLeaderProfiles = applicant_profiles.filter(
    profile => profile.applicant.id != props.applicantId
  )

  return (
    <Container maxWidth={36} mt={3} p={3}>
      <CustomCard>
        <Text>Here's what you need to apply:</Text>

            A group of friends in{' '}

              your team
            {' '}
            ready to help you start your club

        <Text>After you submit your application:</Text>

We'll get back to you with our decision within 3 days

            If you're accepted we'll schedule a call to train you to lead your
            club

            We'll give you access to our curriculum, a template for your
            meetings, and access to our online community of club leaders

            Once you start having club meetings we'll check in with you each
            week to make sure everything is going well

          Contact us at team@hackclub.com{' '}
          if you have any questions while applying.

        <Text color="slate" f={1}>

            * We also accept applications from clubs that have already held
            meetings.

        </Text>
      </CustomCard>
      <Flex
        align="center"
        justify="center"
        flexDirection={['column', 'row']}
        my={3}
        mx={[null, -2]}
      >
        <LargeButton.link
          w={1}
          m={2}
          to={`/apply/club?id=${id}`}
          children="Edit Application"
        />
        <LargeButton.link
          w={1}
          m={2}
          to={`/apply/leader?id=${leaderProfile.id}`}
          children="Edit Leader Profile"
        />
      </Flex>
      <CustomCard>
        <CustomHeading>Application</CustomHeading>

            This application was{' '}
            {updated_at === created_at ? 'created' : 'updated'}{' '}
            {timeSince(updated_at)} ago

          {submitted_at ? (

              You submitted this application{' '}
              {timeSince(submitted_at)} ago

          ) : (

              You have <Neg /> submitted your application

          )}

        <CustomHeading>Leader Profiles</CustomHeading>

            You have {leaderProfile.completed_at ? null : <Neg />} finished your
            leader profile

          {coLeaderProfiles.map((profile, index) => (

              {profile.applicant.email}
              {profile.completed_at ? null : (

                  has <Neg />{' '}

              )}
              finished their leader profile

          ))}

      </CustomCard>
    </Container>
  )
}

class ApplicationIndex extends Component {
  constructor(props) {
    super(props)

    this.state = {
      status: 'loading',
      app: undefined,
      authToken: undefined,
      applicantId: undefined
    }
  }

  componentDidMount() {
    const authToken = window.localStorage.getItem('authToken')
    const applicantId = window.localStorage.getItem('applicantId')
    this.setState({ authToken, applicantId })
    const needsToAuth = authToken === null || applicantId === null

    if (needsToAuth) {
      this.setState({ status: 'needsToAuth' })
    } else {
      // Populate the list of applications
      fetch(`${api}/v1/applicants/${applicantId}/new_club_applications`, {
        headers: { Authorization: `Bearer ${authToken}` }
      })
        .then(res => {
          if (res.ok) {
            return res.json()
          } else {
            throw res
          }
        })
        .then(json => {
          if (json.length === 0) {
            return fetch(
              `${api}/v1/applicants/${applicantId}/new_club_applications`,
              {
                method: 'POST',
                headers: { Authorization: `Bearer ${authToken}` }
              }
            ).then(res => {
              if (res.ok) {
                return res.json()
              } else {
                throw res
              }
            })
          }
          return json.sort((a, b) => {
            return new Date(b.created_at) - new Date(a.created_at)
          })[0]
        })
        .then(app => {
          this.setState({
            status: 'finished',
            app: app
          })
        })
        .catch(e => {
          console.error(e)
          if (e.status === 401) {
            this.setState({ status: 'needsToAuth' })
          }
        })
    }
  }

  content() {
    const { app, status, authToken, applicantId } = this.state

    switch (status) {
      case 'needsToAuth':
        return <Login />
      case 'loading':
        return <LoadingAnimation />
      case 'finished':
        return (
          <Fragment>
            <ApplyNav breadcrumb={0} />
            <Heading.h1
              bg="primary"
              color="white"
              f={[5, 6]}
              mt={-1}
              py={4}
              px={3}
              align="center"
            >
              Apply to Hack Club
            </Heading.h1>
            <ApplicationCard app={app} applicantId={applicantId} />
          </Fragment>
        )
      default:
        return <Text>Something terrible has happened.</Text>
    }
  }

  render() {
    return (
      <ThemeProvider>

          <title>Apply – Hack Club</title>

        {this.content()}
      </ThemeProvider>
    )
  }
}

export default ApplicationIndex
<commit_msg>Shorten application summary<commit_after>import React, { Component, Fragment } from 'react'
import { Head } from 'react-static'
import { api } from '../../data'
import {
  ThemeProvider,
  Card,
  Container,
  Box,
  Flex,
  Text,
  Heading,
  Button,
  LargeButton,
  Link as DSLink,
  cx
} from '@hackclub/design-system'
import LoadingAnimation from '../components/LoadingAnimation'
import Login from '../components/Login'
import ApplyNav from '../components/ApplyNav'
import fetch from 'unfetch'
import { Link } from 'react-static'

LargeButton.link = LargeButton.withComponent(Link)

const A = DSLink.extend`
  :hover {
    text-decoration: underline;
  }
`

const CustomHeading = props => (
  <Heading.h2
    m={0}
    align={['center', 'left']}
    f={3}
    color="primary"
    caps
    {...props}
  />
)

const timeSince = time => {
  const seconds = Math.floor((new Date() - new Date(time)) / 1000)
  const intervals = [
    [Math.floor(seconds / (60 * 60 * 24 * 7)), 'weeks'],
    [Math.floor(seconds / (60 * 60 * 24)), 'days'],
    [Math.floor(seconds / (60 * 60)), 'hours'],
    [Math.floor(seconds / 60), 'minutes']
  ]
  for (var i = 0; i < intervals.length; i++) {
    let interval = intervals[i]
    if (interval[0] > 1) {
      return interval.join(' ')
    }
  }
  return 'less than a minute'
}

const Neg = () => <Text.span color="error" bold children="NOT" />

const CustomCard = props => (
  <Card boxShadowSize="md" p={[3, 4]} color="black" bg="snow" {...props} />
)

const ApplicationCard = props => {
  const {
    id,
    applicant_profiles,
    updated_at,
    created_at,
    submitted_at
  } = props.app

  const leaderProfile = applicant_profiles.find(
    profile => profile.applicant.id == props.applicantId
  )
  const coLeaderProfiles = applicant_profiles.filter(
    profile => profile.applicant.id != props.applicantId
  )

  return (
    <Container maxWidth={36} mt={3} p={3}>
      <CustomCard>
        <Text>
          All you need to apply is{' '}

            a team
          . After you submit your application:
        </Text>

We’ll get back to you with our decision within 3 days

            If you’re accepted we’ll schedule a call to train you to lead your
            club

            We’ll give you access to our curriculum, a template for your
            meetings, and access to our online community of club leaders

            Once you start having club meetings we’ll check in with you each
            week to make sure everything is going well

          Contact us at team@hackclub.com{' '}
          if you have any questions while applying.

        <Text color="slate" f={1}>

            * We also accept applications from clubs that have already held
            meetings.

        </Text>
      </CustomCard>
      <Flex
        align="center"
        justify="center"
        flexDirection={['column', 'row']}
        my={3}
        mx={[null, -2]}
      >
        <LargeButton.link
          w={1}
          m={2}
          to={`/apply/club?id=${id}`}
          children="Edit Application"
        />
        <LargeButton.link
          w={1}
          m={2}
          to={`/apply/leader?id=${leaderProfile.id}`}
          children="Edit Leader Profile"
        />
      </Flex>
      <CustomCard>
        <CustomHeading>Application</CustomHeading>

            This application was{' '}
            {updated_at === created_at ? 'created' : 'updated'}{' '}
            {timeSince(updated_at)} ago

          {submitted_at ? (

              You submitted this application{' '}
              {timeSince(submitted_at)} ago

          ) : (

              You have <Neg /> submitted your application

          )}

        <CustomHeading>Leader Profiles</CustomHeading>

            You have {leaderProfile.completed_at ? null : <Neg />} finished your
            leader profile

          {coLeaderProfiles.map((profile, index) => (

              {profile.applicant.email}
              {profile.completed_at ? null : (

                  has <Neg />{' '}

              )}
              finished their leader profile

          ))}

      </CustomCard>
    </Container>
  )
}

class ApplicationIndex extends Component {
  constructor(props) {
    super(props)

    this.state = {
      status: 'loading',
      app: undefined,
      authToken: undefined,
      applicantId: undefined
    }
  }

  componentDidMount() {
    const authToken = window.localStorage.getItem('authToken')
    const applicantId = window.localStorage.getItem('applicantId')
    this.setState({ authToken, applicantId })
    const needsToAuth = authToken === null || applicantId === null

    if (needsToAuth) {
      this.setState({ status: 'needsToAuth' })
    } else {
      // Populate the list of applications
      fetch(`${api}/v1/applicants/${applicantId}/new_club_applications`, {
        headers: { Authorization: `Bearer ${authToken}` }
      })
        .then(res => {
          if (res.ok) {
            return res.json()
          } else {
            throw res
          }
        })
        .then(json => {
          if (json.length === 0) {
            return fetch(
              `${api}/v1/applicants/${applicantId}/new_club_applications`,
              {
                method: 'POST',
                headers: { Authorization: `Bearer ${authToken}` }
              }
            ).then(res => {
              if (res.ok) {
                return res.json()
              } else {
                throw res
              }
            })
          }
          return json.sort((a, b) => {
            return new Date(b.created_at) - new Date(a.created_at)
          })[0]
        })
        .then(app => {
          this.setState({
            status: 'finished',
            app: app
          })
        })
        .catch(e => {
          console.error(e)
          if (e.status === 401) {
            this.setState({ status: 'needsToAuth' })
          }
        })
    }
  }

  content() {
    const { app, status, authToken, applicantId } = this.state

    switch (status) {
      case 'needsToAuth':
        return <Login />
      case 'loading':
        return <LoadingAnimation />
      case 'finished':
        return (
          <Fragment>
            <ApplyNav breadcrumb={0} />
            <Heading.h1
              bg="primary"
              color="white"
              f={[5, 6]}
              mt={-1}
              py={4}
              px={3}
              align="center"
            >
              Apply to Hack Club
            </Heading.h1>
            <ApplicationCard app={app} applicantId={applicantId} />
          </Fragment>
        )
      default:
        return <Text>Something terrible has happened.</Text>
    }
  }

  render() {
    return (
      <ThemeProvider>

          <title>Apply – Hack Club</title>

        {this.content()}
      </ThemeProvider>
    )
  }
}

export default ApplicationIndex
<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import _ from 'lodash';

import RunHistoryChart from "../components/RunHistoryChart";
import NewRunModal from "../components/Modal/NewRunModal";
import CollapsiblePanel from '../components/CollapsiblePanel';
import RunList from '../components/RunList';

import contextProps from '../prop-types/context';
import recordSetProps from '../prop-types/record_set';
import recordMatchingSystemProps from '../prop-types/record_matching_system';
import patientProps from '../prop-types/patient';
import { runProps } from '../prop-types/run';

import ItemBeingTested from '../util/ItemBeingTested';

import { createRun } from '../actions/matchRun';

export class BenchmarkContext extends Component {
  constructor(props) {
    super(props);

    let itemBeingTested = ItemBeingTested(this.props.context,
                                          this.props.matchRuns,
                                          this.props.recordSets,
                                          this.props.recordMatchingSystems);

    this.state = {
      itemBeingTested: itemBeingTested
    };
  }

  completedRuns() {
    return this.props.matchRuns.filter((mr) => mr.status === 'responded');
  }

  unfinishedRuns() {
    return this.props.matchRuns.filter((mr) => mr.status === 'no-response');
  }

  displayAlert() {
    if (this.unfinishedRuns().length > 0) {
      let runningJob = _.last(this.unfinishedRuns());

      return (

          {' '}Running a job against {this.props.recordSets.find((rs) => rs.id === runningJob.masterRecordSetId).name}

      );
    }
  }

  lineChartData() {
    return {
      labels: _.map(this.completedRuns(), (mr) => {
        const recordSet = this.props.recordSets.find((rs) => rs.id === mr.masterRecordSetId);
        return recordSet ? recordSet.name : 'Unknown';
      }),
      datasets: [{ label: 'Duplicates', data: this.completedRuns().map((mr) => mr.metrics.matchCount) }]
    };
  }

  displayChart() {
    if (this.props.matchRuns.length > 0) {
      return (

          <RunHistoryChart chartData={this.lineChartData()} />

      );
    } else {
      return (

            Loading...

      );
    }
  }

  displayRuns() {
    if (this.props.matchRuns.length > 0) {
      return (
        <RunList runs={this.props.matchRuns}
                 recordMatchingSystem={this.state.itemBeingTested}
                 patients={this.props.patients} />
      );
    } else {
      return (

          Loading...

      );
    }
  }

  render() {
    return (
      <CollapsiblePanel panelTitle={this.props.context.name}
                        panelIcon="line-chart"
                        subtitle={this.state.itemBeingTested}
                        subtitleIcon="sitemap"
                        buttonText="New Run"
                        modalTarget="#newRunModal">

          {this.displayAlert()}
          {this.displayChart()}
          {this.displayRuns()}

          <NewRunModal title="New Benchmark Run"
                       context={this.props.context}
                       recordSets={this.props.recordSets}
                       recordMatchingSystems={this.props.recordMatchingSystems}
                       runCreator={(recordMatchSystemInterfaceId, masterRecordSetId, recordMatchContextId, note) => {
                                    this.props.createRun(recordMatchSystemInterfaceId, masterRecordSetId, recordMatchContextId, note);}}
                       matchRuns={this.props.matchRuns} />

      </CollapsiblePanel>
    );
  }
}

BenchmarkContext.displayName = 'BenchmarkContext';

BenchmarkContext.propTypes = {
  context: contextProps.isRequired,
  patients: PropTypes.objectOf(patientProps),
  recordSets: PropTypes.arrayOf(recordSetProps),
  recordMatchingSystems: PropTypes.arrayOf(recordMatchingSystemProps),
  matchRuns: PropTypes.arrayOf(runProps).isRequired,
  fetchMatchRunsByContext: PropTypes.func,
  createRun: PropTypes.func,
  selectRecordSet: PropTypes.func,
  contextCreator: PropTypes.func.isRequired
};

export function mapStateToProps(state, ownProps) {
  const contextId = ownProps.context.id;
  const matchRuns = _.sortBy(
    _.values(state.matchRuns).filter((mr) => mr.recordMatchContextId === contextId),
    (mr) => new Date(mr.meta.createdOn));
  // All runs should have the same matching system, so we can grab the id for the
  // first one
  let recordMatchingSystems = _.values(state.recordMatchingSystems);
  const recordSets = _.values(state.recordSets);
  const patients = state.patients;

  return {matchRuns, recordMatchingSystems, recordSets, patients};
}

export default connect(mapStateToProps, { createRun })(BenchmarkContext);
<commit_msg>Fix for empty BenchmarkContext<commit_after>import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import _ from 'lodash';

import RunHistoryChart from "../components/RunHistoryChart";
import NewRunModal from "../components/Modal/NewRunModal";
import CollapsiblePanel from '../components/CollapsiblePanel';
import RunList from '../components/RunList';

import contextProps from '../prop-types/context';
import recordSetProps from '../prop-types/record_set';
import recordMatchingSystemProps from '../prop-types/record_matching_system';
import patientProps from '../prop-types/patient';
import { runProps } from '../prop-types/run';

import ItemBeingTested from '../util/ItemBeingTested';

import { createRun } from '../actions/matchRun';

export class BenchmarkContext extends Component {
  constructor(props) {
    super(props);

    let itemBeingTested = ItemBeingTested(this.props.context,
                                          this.props.matchRuns,
                                          this.props.recordSets,
                                          this.props.recordMatchingSystems);

    this.state = {
      itemBeingTested: itemBeingTested
    };
  }

  completedRuns() {
    return this.props.matchRuns.filter((mr) => mr.status === 'responded');
  }

  unfinishedRuns() {
    return this.props.matchRuns.filter((mr) => mr.status === 'no-response');
  }

  displayAlert() {
    if (this.unfinishedRuns().length > 0) {
      let runningJob = _.last(this.unfinishedRuns());

      return (

          {' '}Running a job against {this.props.recordSets.find((rs) => rs.id === runningJob.masterRecordSetId).name}

      );
    }
  }

  lineChartData() {
    return {
      labels: _.map(this.completedRuns(), (mr) => {
        const recordSet = this.props.recordSets.find((rs) => rs.id === mr.masterRecordSetId);
        return recordSet ? recordSet.name : 'Unknown';
      }),
      datasets: [{ label: 'Duplicates', data: this.completedRuns().map((mr) => mr.metrics.matchCount) }]
    };
  }

  displayChart() {
    if (this.props.matchRuns.length > 0) {
      return (

          <RunHistoryChart chartData={this.lineChartData()} />

      );
    } else {
      return (

No runs have been created for this context

      );
    }
  }

  displayRuns() {
    if (this.props.matchRuns.length > 0) {
      return (
        <RunList runs={this.props.matchRuns}
                 recordMatchingSystem={this.state.itemBeingTested}
                 patients={this.props.patients} />
      );
    }
  }

  render() {
    return (
      <CollapsiblePanel panelTitle={this.props.context.name}
                        panelIcon="line-chart"
                        subtitle={this.state.itemBeingTested}
                        subtitleIcon="sitemap"
                        buttonText="New Run"
                        modalTarget="#newRunModal">

          {this.displayAlert()}
          {this.displayChart()}
          {this.displayRuns()}

          <NewRunModal title="New Benchmark Run"
                       context={this.props.context}
                       recordSets={this.props.recordSets}
                       recordMatchingSystems={this.props.recordMatchingSystems}
                       runCreator={(recordMatchSystemInterfaceId, masterRecordSetId, recordMatchContextId, note) => {
                                    this.props.createRun(recordMatchSystemInterfaceId, masterRecordSetId, recordMatchContextId, note);}}
                       matchRuns={this.props.allMatchRuns} />

      </CollapsiblePanel>
    );
  }
}

BenchmarkContext.displayName = 'BenchmarkContext';

BenchmarkContext.propTypes = {
  context: contextProps.isRequired,
  patients: PropTypes.objectOf(patientProps),
  recordSets: PropTypes.arrayOf(recordSetProps),
  recordMatchingSystems: PropTypes.arrayOf(recordMatchingSystemProps),
  matchRuns: PropTypes.arrayOf(runProps).isRequired,
  allMatchRuns: PropTypes.objectOf(runProps).isRequired,
  createRun: PropTypes.func,
  selectRecordSet: PropTypes.func,
  contextCreator: PropTypes.func.isRequired
};

export function mapStateToProps(state, ownProps) {
  const contextId = ownProps.context.id;
  const allMatchRuns = state.matchRuns;
  const matchRuns = _.sortBy(
    _.values(state.matchRuns).filter((mr) => mr.recordMatchContextId === contextId),
    (mr) => new Date(mr.meta.createdOn));
  // All runs should have the same matching system, so we can grab the id for the
  // first one
  let recordMatchingSystems = _.values(state.recordMatchingSystems);
  const recordSets = _.values(state.recordSets);
  const patients = state.patients;

  return {matchRuns, recordMatchingSystems, recordSets, patients, allMatchRuns};
}

export default connect(mapStateToProps, { createRun })(BenchmarkContext);
<|endoftext|>


<commit_before>
import { and, or, not, createAndOrNot } from './';

var def = ["OR", {x: 2}, {y: 3}, ["AND", {foo: true}, {bar: false}]];

const opperators = {
  AND: and,
  OR: or,
  NOT: not
};

function dataToPredicate(def) {
  console.log(def);
  return function checkFunction(model) {
    for (let key in def) {
      if (def.hasOwnProperty(key)) {
        return def[key] === model[key];
      }
    }
  }
}

function compilePredicate(def, interpreter) {
  return (value) => {
    return opperators[def[0]](...def.slice(1).map(term => {
      if (Array.isArray(term)) {
        return compilePredicate(term);
      } else {
        return interpreter(term);
      }
    }))(value);
  }
}

const predicate = compilePredicate(def, dataToPredicate);

console.log(predicate({x: 1, y: 3}));

// .forEach(fn => {
//   console.log(fn({x: 1, y: 3});
// }));
<commit_msg>compiler idea working<commit_after>
import { and, or, not, createAndOrNot } from './';

const opperators = {
  AND: and,
  OR: or,
  NOT: not
};

function dataToPredicate(term) {
  return function predicate(model) {
    for (let key in term) {
      if (term.hasOwnProperty(key)) {
        return term[key] === model[key];
      }
    }
  }
}

function compilePredicate(config, interpreter) {
  return function predicate(value) {
    return opperators[config[0]](...config.slice(1).map(term => {
      if (Array.isArray(term)) {
        return compilePredicate(term, interpreter);
      } else {
        return interpreter(term);
      }
    }))(value);
  }
}

var config = [ "AND", { x: 2 },
                      { y: 3 },
                      [ "OR", { foo: true },
                              { bar: true }]];

const predicate = compilePredicate(config, dataToPredicate);

console.log(predicate({x: 2, y: 3, bar: true})); // true

<|endoftext|>


<commit_before>'use strict';
/**
 * The controller for the board API
 *
 *
 * @module boardController
 * @license MIT
 * @author yamikuronue
 */

/*Express typedefs*/

/**
  @typedef Request
  @type {object}
  @property {object} params - The parameters for the request
 /

/**
  @typedef Response
  @type {object}
  @function send - The function to send data to the client
  @function status - Set the status code for the response
*/

const Board = require('../model/Board');
const Game = require('../model/Game');
const debug = require('debug')('SockRPG:controller:Board');

/**
 * Get all games in the esystem
 * @param {Request} _ Express' request object. Expects an ID under the params key
 * @param {Response} res Express response object
 * @returns {Promise} A promise that will resolve when the response has been sent.
 */
function getAllGames(_, res) {
	//For this sprint, all users can see all games
	return Game.getAllGames().then((data) => {
		res.send(data);
	}).catch((err) => {
		debug(`Error Getting Games: ${err.toString()}`);
		//TODO: Add Proper Logging
		res.status(500).send({error: err.toString()});
	});
}

/**
 * Get a single game.
 * @param {Request} req Express' request object. Expects an ID under the params key
 * @param {Response} res Express' response object.
 * @returns {Promise} A promise that will resolve when the response has been sent.
 */
function getGame(req, res) {
	if (!req.params.id) {
		res.status(501).send({error: 'Missing ID'});
		return Promise.resolve();
	}

	return Game.getGame(req.params.id).then((data) => {
		if (Array.isArray(data)) {
			data = data[0]; //Only the first game
		}

		if (!data) {
			res.status(404).end();
			return undefined;
		}

		const output = data.serialize();

		return data.getThreads().then((threadIDs) => {
			output.threadList = threadIDs;
			res.status(200).send(output);
		});
	}).catch((err) => {
		debug(`Error Getting Game: ${err.toString()}`);
		//TODO: Add Proper Logging
		res.status(500).send({error: err.toString()});
	});
}

/**
 * Add a game to the collection.
 * @param {Request} req Express' request object. Expects a body with a name parameter
 * @param {Response} res Express' response object.
 * @returns {Promise} A promise that will resolve when the response has been sent.
 */
function addGame(req, res) {
	return Game.addGame(req.body).then((index) => {
		res.status(200).send({id: index[0]}).end();
	}).catch((err) => {
		debug(`Error Adding Game: ${err.toString()}`);
		//TODO: Add Proper Logging
		res.status(500).send({error: err.toString()});
	});
}

/**
 * Update a game
 * @param {Request} req Express' request object. Expects a body with data and an ID under the params key
 * @param {Response} res Express' response object.
 * @returns {Promise} A promise that will resolve when the response has been sent.
 */
function updateGame(req, res) {
	return Game.getGame(req.params.id).then((board) => {
		board.Name = req.body.Name || board.Name;
		board.Owner = req.body.Owner || board.Owner;
		board.description = req.body.Game.gameDescription || board.description;

		if ('Adult' in req.body) {
			board.Adult = req.body.Adult;
		}
		return board.save();
	}).then(() => {
		res.status(200).end();
	}).catch((err) => {
		debug(`Error Updating Game: ${err.toString()}`);
		//TODO: Add Proper Logging

		//TODO: we shouldn't be switching behavior based on text matches. let's find a better way at some point.
		if (err.toString().indexOf('No such') > -1) {
			res.status(404).send({error: err.toString()});
		} else {
			res.status(500).send({error: err.toString()});
		}
	});
}

/**
 * Get all boards in the system
 * @param {Request} _ Express' request object. Expects an ID under the params key
 * @param {Response} res Express' response object.
 * @returns {Promise} A promise that will resolve when the response has been sent.
 */
function getAllBoards(_, res) {
	//For this sprint, all users can see all games
	return Board.getAllBoards().then((data) => {
		res.send(data);
	}).catch((err) => {
		debug(`Error Getting Boards: ${err.toString()}`);
		//TODO: Add Proper Logging
		res.status(500).send({error: err.toString()});
	});
}

/**
 * Get a single board.
 * @param {Request} req Express' request object. Expects an ID under the params key
 * @param {Response} res Express' response object.
 * @returns {Promise} A promise that will resolve when the response has been sent.
 */
function getBoard(req, res) {
	if (!req.params.id) {
		res.status(501).send({error: 'Missing ID'});
		return Promise.resolve();
	}

	return Board.getBoard(req.params.id).then((data) => {
		if (Array.isArray(data)) {
			data = data[0]; //Only the first board
		}
		if (!data) {
			res.status(404).end();
			return undefined;
		}

		const output = data.serialize();

		return data.getThreads().then((threadIDs) => {
			output.threadList = threadIDs;
			res.status(200).send(output);
		});
	}).catch((err) => {
		debug(`Error Getting Board: ${err.toString()}`);
		//TODO: Add Proper Logging
		res.status(500).send({error: err.toString()});
	});
}

/**
 * Update a board
 * @param {Request} req Express' request object. Expects a body with a name parameter
 * @param {Response} res Express' response object.
 * @returns {Promise} A promise that will resolve when the response has been sent.
 */
function addBoard(req, res) {
	return Board.addBoard(req.body).then((index) => {
		res.status(200).send({
			id: index[0]
		}).end();
	}).catch((err) => {
		debug(`Error Adding Board: ${err.toString()}`);
		//TODO: Add Proper Logging
		res.status(500).send({error: err.toString()});
	});
}

/**
 * Add a board to the collection.
 * @param {Request} req Express' request object. Expects a body with data and an ID under the params key
 * @param {Response} res Express' response object.
 * @returns {Promise} A promise that will resolve when the response has been sent.
 */
function updateBoard(req, res) {

	return Board.getBoard(req.params.id).then((board) => {
		board.Name = req.body.Name || board.Name;
		board.Owner = req.body.Owner || board.Owner;
		if ('Adult' in req.body) {
			board.Adult = req.body.Adult;
		}
		return board.save();
	}).then(() => {
		res.status(200).end();
	}).catch((err) => {
		debug(`Error Updating Board: ${err.toString()}`);
		//TODO: Add Proper Logging

		//TODO: Let's not switch on text when we don't need to.
		if (err.toString().indexOf('No such') > -1) {
			res.status(404).send({error: err.toString()});
		} else {
			res.status(500).send({error: err.toString()});
		}
	});
}

const controller = {
	getAllGames: getAllGames,

	getGame: getGame,

	addGame: addGame,

	updateGame: updateGame,

	getAllBoards: getAllBoards,

	getBoard: getBoard,

	addBoard: addBoard,

	updateBoard: updateBoard

};

module.exports = controller;
<commit_msg>chore(refactor): remove redundant CYA code<commit_after>'use strict';
/**
 * The controller for the board API
 *
 *
 * @module boardController
 * @license MIT
 * @author yamikuronue
 */

/*Express typedefs*/

/**
  @typedef Request
  @type {object}
  @property {object} params - The parameters for the request
 /

/**
  @typedef Response
  @type {object}
  @function send - The function to send data to the client
  @function status - Set the status code for the response
*/

const Board = require('../model/Board');
const Game = require('../model/Game');
const debug = require('debug')('SockRPG:controller:Board');

/**
 * Get all games in the esystem
 * @param {Request} _ Express' request object. Expects an ID under the params key
 * @param {Response} res Express response object
 * @returns {Promise} A promise that will resolve when the response has been sent.
 */
function getAllGames(_, res) {
	//For this sprint, all users can see all games
	return Game.getAllGames().then((data) => {
		res.send(data);
	}).catch((err) => {
		debug(`Error Getting Games: ${err.toString()}`);
		//TODO: Add Proper Logging
		res.status(500).send({error: err.toString()});
	});
}

/**
 * Get a single game.
 * @param {Request} req Express' request object. Expects an ID under the params key
 * @param {Response} res Express' response object.
 * @returns {Promise} A promise that will resolve when the response has been sent.
 */
function getGame(req, res) {
	if (!req.params.id) {
		res.status(501).send({error: 'Missing ID'});
		return Promise.resolve();
	}

	return Game.getGame(req.params.id).then((data) => {
		if (Array.isArray(data)) {
			data = data[0]; //Only the first game
		}

		if (!data) {
			res.status(404).end();
			return undefined;
		}

		const output = data.serialize();

		return data.getThreads().then((threadIDs) => {
			output.threadList = threadIDs;
			res.status(200).send(output);
		});
	}).catch((err) => {
		debug(`Error Getting Game: ${err.toString()}`);
		//TODO: Add Proper Logging
		res.status(500).send({error: err.toString()});
	});
}

/**
 * Add a game to the collection.
 * @param {Request} req Express' request object. Expects a body with a name parameter
 * @param {Response} res Express' response object.
 * @returns {Promise} A promise that will resolve when the response has been sent.
 */
function addGame(req, res) {
	return Game.addGame(req.body).then((index) => {
		res.status(200).send({id: index[0]}).end();
	}).catch((err) => {
		debug(`Error Adding Game: ${err.toString()}`);
		//TODO: Add Proper Logging
		res.status(500).send({error: err.toString()});
	});
}

/**
 * Update a game
 * @param {Request} req Express' request object. Expects a body with data and an ID under the params key
 * @param {Response} res Express' response object.
 * @returns {Promise} A promise that will resolve when the response has been sent.
 */
function updateGame(req, res) {
	return Game.getGame(req.params.id).then((board) => {
		board.Name = req.body.Name || board.Name;
		board.Owner = req.body.Owner || board.Owner;
		board.description = req.body.Game.gameDescription || board.description;

		if ('Adult' in req.body) {
			board.Adult = req.body.Adult;
		}
		return board.save();
	}).then(() => {
		res.status(200).end();
	}).catch((err) => {
		debug(`Error Updating Game: ${err.toString()}`);
		//TODO: Add Proper Logging

		//TODO: we shouldn't be switching behavior based on text matches. let's find a better way at some point.
		if (err.toString().indexOf('No such') > -1) {
			res.status(404).send({error: err.toString()});
		} else {
			res.status(500).send({error: err.toString()});
		}
	});
}

/**
 * Get all boards in the system
 * @param {Request} _ Express' request object. Expects an ID under the params key
 * @param {Response} res Express' response object.
 * @returns {Promise} A promise that will resolve when the response has been sent.
 */
function getAllBoards(_, res) {
	//For this sprint, all users can see all games
	return Board.getAllBoards().then((data) => {
		res.send(data);
	}).catch((err) => {
		debug(`Error Getting Boards: ${err.toString()}`);
		//TODO: Add Proper Logging
		res.status(500).send({error: err.toString()});
	});
}

/**
 * Get a single board.
 * @param {Request} req Express' request object. Expects an ID under the params key
 * @param {Response} res Express' response object.
 * @returns {Promise} A promise that will resolve when the response has been sent.
 */
function getBoard(req, res) {
	if (!req.params.id) {
		res.status(501).send({error: 'Missing ID'});
		return Promise.resolve();
	}

	return Board.getBoard(req.params.id).then((data) => {
		if (!data) {
			res.status(404).end();
			return undefined;
		}

		const output = data.serialize();

		return data.getThreads().then((threadIDs) => {
			output.threadList = threadIDs;
			res.status(200).send(output);
		});
	}).catch((err) => {
		debug(`Error Getting Board: ${err.toString()}`);
		//TODO: Add Proper Logging
		res.status(500).send({error: err.toString()});
	});
}

/**
 * Update a board
 * @param {Request} req Express' request object. Expects a body with a name parameter
 * @param {Response} res Express' response object.
 * @returns {Promise} A promise that will resolve when the response has been sent.
 */
function addBoard(req, res) {
	return Board.addBoard(req.body).then((index) => {
		res.status(200).send({
			id: index[0]
		}).end();
	}).catch((err) => {
		debug(`Error Adding Board: ${err.toString()}`);
		//TODO: Add Proper Logging
		res.status(500).send({error: err.toString()});
	});
}

/**
 * Add a board to the collection.
 * @param {Request} req Express' request object. Expects a body with data and an ID under the params key
 * @param {Response} res Express' response object.
 * @returns {Promise} A promise that will resolve when the response has been sent.
 */
function updateBoard(req, res) {

	return Board.getBoard(req.params.id).then((board) => {
		board.Name = req.body.Name || board.Name;
		board.Owner = req.body.Owner || board.Owner;
		if ('Adult' in req.body) {
			board.Adult = req.body.Adult;
		}
		return board.save();
	}).then(() => {
		res.status(200).end();
	}).catch((err) => {
		debug(`Error Updating Board: ${err.toString()}`);
		//TODO: Add Proper Logging

		//TODO: Let's not switch on text when we don't need to.
		if (err.toString().indexOf('No such') > -1) {
			res.status(404).send({error: err.toString()});
		} else {
			res.status(500).send({error: err.toString()});
		}
	});
}

const controller = {
	getAllGames: getAllGames,

	getGame: getGame,

	addGame: addGame,

	updateGame: updateGame,

	getAllBoards: getAllBoards,

	getBoard: getBoard,

	addBoard: addBoard,

	updateBoard: updateBoard

};

module.exports = controller;
<|endoftext|>


<commit_before>'use strict';
const app = require('../business/app.business');
const scraper = require('../business/scraper.busuness');

module.exports = {
    home: (req, res, next) => {
        res.render('index');
    },

    getRandomImage: (req, res, next) => {
        app.getRandomImage(req.params.group).then((content) => {
            if (content === null) {
                res.redirect('/');
            } else {
                res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0');
                res.setHeader('Cache-Control', 'post-check=0, pre-check=0');
                res.setHeader('Pragma', 'no-cache');

                res.render('vemardu', { content: content });
            }
        }).catch((err) => {
            res.redirect('/');
        });
    },
    scrape: (req, res, next) => {
        scraper(req.params.group).then((content) => {
            if (content === null) {
                res.sendStatus(400);
            } else {
                res.sendStatus(200);
            }
        }).catch((err) => {
            console.log(err);
            res.sendStatus(500);
        });
    },
}<commit_msg>if one then<commit_after>'use strict';
const app = require('../business/app.business');
const group = require('../business/group.business');
const scraper = require('../business/scraper.busuness');

module.exports = {
    home: (req, res, next) => {
        group.list().then(x => {
            if (x.length == 1) {
                getRandomImage(req, res, next);
            }
            if (x.length == 0) {
                return res.render('index');
            }
            if (x.length > 1) {
                return res.render('index');
            }
        }).catch(x => console.log(x))
    },

    getRandomImage: (req, res, next) => {
        app.getRandomImage(req.params.group).then((content) => {
            if (content === null) {
                res.redirect('/');
            } else {
                res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0');
                res.setHeader('Cache-Control', 'post-check=0, pre-check=0');
                res.setHeader('Pragma', 'no-cache');

                res.render('vemardu', { content: content });
            }
        }).catch((err) => {
            res.redirect('/');
        });
    },
    scrape: (req, res, next) => {
        scraper(req.params.group).then((content) => {
            if (content === null) {
                res.sendStatus(400);
            } else {
                res.sendStatus(200);
            }
        }).catch((err) => {
            console.log(err);
            res.sendStatus(500);
        });
    },
}<|endoftext|>


<commit_before>var BaseTexture = require('./BaseTexture'),
    Texture = require('./Texture'),
    RenderTarget = require('../renderers/webgl/utils/RenderTarget'),
    FilterManager = require('../renderers/webgl/managers/FilterManager'),
    CanvasBuffer = require('../renderers/canvas/utils/CanvasBuffer'),
    math = require('../math'),
    CONST = require('../const'),
    tempMatrix = new math.Matrix();

/**
 * A RenderTexture is a special texture that allows any Pixi display object to be rendered to it.
 *
 * __Hint__: All DisplayObjects (i.e. Sprites) that render to a RenderTexture should be preloaded
 * otherwise black rectangles will be drawn instead.
 *
 * A RenderTexture takes a snapshot of any Display Object given to its render method. The position
 * and rotation of the given Display Objects is ignored. For example:
 *
 * ```js
 * var renderTexture = new PIXI.RenderTexture(800, 600);
 * var sprite = PIXI.Sprite.fromImage("spinObj_01.png");
 *
 * sprite.position.x = 800/2;
 * sprite.position.y = 600/2;
 * sprite.anchor.x = 0.5;
 * sprite.anchor.y = 0.5;
 *
 * renderTexture.render(sprite);
 * ```
 *
 * The Sprite in this case will be rendered to a position of 0,0. To render this sprite at its actual
 * position a Container should be used:
 *
 * ```js
 * var doc = new Container();
 *
 * doc.addChild(sprite);
 *
 * renderTexture.render(doc);  // Renders to center of renderTexture
 * ```
 *
 * @class
 * @extends Texture
 * @memberof PIXI
 * @param renderer {CanvasRenderer|WebGLRenderer} The renderer used for this RenderTexture
 * @param [width=100] {number} The width of the render texture
 * @param [height=100] {number} The height of the render texture
 * @param [scaleMode] {number} See {@link SCALE_MODES} for possible values
 * @param [resolution=1] {number} The resolution of the texture being generated
 */
function RenderTexture(renderer, width, height, scaleMode, resolution)
{
    if (!renderer)
    {
        throw new Error('Unable to create RenderTexture, you must pass a renderer into the constructor.');
    }

    width = width || 100;
    height = height || 100;
    resolution = resolution || CONST.RESOLUTION;

    /**
     * The base texture object that this texture uses
     *
     * @member {BaseTexture}
     */
    var baseTexture = new BaseTexture();
    baseTexture.width = width;
    baseTexture.height = height;
    baseTexture.resolution = resolution;
    baseTexture.scaleMode = scaleMode || CONST.SCALE_MODES.DEFAULT;
    baseTexture.hasLoaded = true;

    Texture.call(this,
        baseTexture,
        new math.Rectangle(0, 0, width, height)
    );

    /**
     * The with of the render texture
     *
     * @member {number}
     */
    this.width = width;

    /**
     * The height of the render texture
     *
     * @member {number}
     */
    this.height = height;

    /**
     * The Resolution of the texture.
     *
     * @member {number}
     */
    this.resolution = resolution;

    /**
     * The framing rectangle of the render texture
     *
     * @member {Rectangle}
     */
    //this._frame = new math.Rectangle(0, 0, this.width * this.resolution, this.height * this.resolution);

    /**
     * This is the area of the BaseTexture image to actually copy to the Canvas / WebGL when rendering,
     * irrespective of the actual frame size or placement (which can be influenced by trimmed texture atlases)
     *
     * @member {Rectangle}
     */
    //this.crop = new math.Rectangle(0, 0, this.width * this.resolution, this.height * this.resolution);

    /**
     * Draw/render the given DisplayObject onto the texture.
     *
     * The displayObject and descendents are transformed during this operation.
     * If `updateTransform` is true then the transformations will be restored before the
     * method returns. Otherwise it is up to the calling code to correctly use or reset
     * the transformed display objects.
     *
     * The display object is always rendered with a worldAlpha value of 1.
     *
     * @method
     * @param displayObject {DisplayObject} The display object to render this texture on
     * @param [matrix] {Matrix} Optional matrix to apply to the display object before rendering.
     * @param [clear=false] {boolean} If true the texture will be cleared before the displayObject is drawn
     * @param [updateTransform=true] {boolean} If true the displayObject's worldTransform/worldAlpha and all children
     *  transformations will be restored. Not restoring this information will be a little faster.
     */
    this.render = null;

    /**
     * The renderer this RenderTexture uses. A RenderTexture can only belong to one renderer at the moment if its webGL.
     *
     * @member {CanvasRenderer|WebGLRenderer}
     */
    this.renderer = renderer;

    if (this.renderer.type === CONST.RENDERER_TYPE.WEBGL)
    {
        var gl = this.renderer.gl;

        this.textureBuffer = new RenderTarget(gl, this.width, this.height, null, this.resolution);//, this.baseTexture.scaleMode);
        this.baseTexture._glTextures[gl.id] =  this.textureBuffer.texture;

        //TODO refactor filter manager.. as really its no longer a manager if we use it here..
        this.filterManager = new FilterManager(this.renderer);
        this.filterManager.onContextChange();
        this.filterManager.resize(width, height);
        this.render = this.renderWebGL;

        // the creation of a filter manager unbinds the buffers..
        this.renderer.currentRenderer.start();
    }
    else
    {

        this.render = this.renderCanvas;
        this.textureBuffer = new CanvasBuffer(this.width* this.resolution, this.height* this.resolution);
        this.baseTexture.source = this.textureBuffer.canvas;
    }

    /**
     * @member {boolean}
     */
    this.valid = true;

    this._updateUvs();
}

RenderTexture.prototype = Object.create(Texture.prototype);
RenderTexture.prototype.constructor = RenderTexture;
module.exports = RenderTexture;

/**
 * Resizes the RenderTexture.
 *
 * @param width {number} The width to resize to.
 * @param height {number} The height to resize to.
 * @param updateBase {boolean} Should the baseTexture.width and height values be resized as well?
 */
RenderTexture.prototype.resize = function (width, height, updateBase)
{
    if (width === this.width && height === this.height)
    {
        return;
    }

    this.valid = (width > 0 && height > 0);

    this.width = this._frame.width = this.crop.width = width;
    this.height =  this._frame.height = this.crop.height = height;

    if (updateBase)
    {
        this.baseTexture.width = this.width;
        this.baseTexture.height = this.height;
    }

    if (this.renderer.type === CONST.RENDERER_TYPE.WEBGL)
    {
        this.projection.x = this.width / 2;
        this.projection.y = -this.height / 2;
    }

    if (!this.valid)
    {
        return;
    }

    this.textureBuffer.resize(this.width * this.resolution, this.height * this.resolution);

    if(this.filterManager)
    {
        this.filterManager.resize(this.width, this.height);
    }
};

/**
 * Clears the RenderTexture.
 *
 */
RenderTexture.prototype.clear = function ()
{
    if (!this.valid)
    {
        return;
    }

    if (this.renderer.type === CONST.RENDERER_TYPE.WEBGL)
    {
        this.renderer.gl.bindFramebuffer(this.renderer.gl.FRAMEBUFFER, this.textureBuffer.frameBuffer);
    }

    this.textureBuffer.clear();
};

/**
 * Internal method assigned to the `render` property if using a CanvasRenderer.
 *
 * @private
 * @param displayObject {DisplayObject} The display object to render this texture on
 * @param [matrix] {Matrix} Optional matrix to apply to the display object before rendering.
 * @param [clear=false] {boolean} If true the texture will be cleared before the displayObject is drawn
 * @param [updateTransform=true] {boolean} If true the displayObject's worldTransform/worldAlpha and all children
 *  transformations will be restored. Not restoring this information will be a little faster.
 */
RenderTexture.prototype.renderWebGL = function (displayObject, matrix, clear, updateTransform)
{
    if (!this.valid)
    {
        return;
    }

    updateTransform = (updateTransform !== undefined) updateTransform ? true;//!updateTransform;

    this.textureBuffer.transform = matrix;

    // setWorld Alpha to ensure that the object is renderer at full opacity
    displayObject.worldAlpha = displayObject.alpha;

    if (updateTransform)
    {

        // reset the matrix of the displatyObject..
        displayObject.worldTransform.identity();

        displayObject.currentBounds = null;

        // Time to update all the children of the displayObject with the new matrix..
        var children = displayObject.children;
        var i, j;

        for (i = 0, j = children.length; i < j; ++i)
        {
            children[i].updateTransform();
        }
    }

   if (clear)
    {
        this.textureBuffer.clear();
    }

    //TODO rename textureBuffer to renderTarget..
    var temp =  this.renderer.filterManager;

    this.renderer.filterManager = this.filterManager;
    this.renderer.renderDisplayObject(displayObject, this.textureBuffer);

    this.renderer.filterManager = temp;

};

/**
 * Internal method assigned to the `render` property if using a CanvasRenderer.
 *
 * @private
 * @param displayObject {DisplayObject} The display object to render this texture on
 * @param [matrix] {Matrix} Optional matrix to apply to the display object before rendering.
 * @param [clear] {boolean} If true the texture will be cleared before the displayObject is drawn
 */
RenderTexture.prototype.renderCanvas = function (displayObject, matrix, clear, updateTransform)
{
    if (!this.valid)
    {
        return;
    }

    updateTransform = !!updateTransform;
    var cachedWt = displayObject.worldTransform;

    var wt = tempMatrix;

    wt.identity();

    if (matrix)
    {
        wt.append(matrix);
    }

    displayObject.worldTransform = wt;

    // setWorld Alpha to ensure that the object is renderer at full opacity
    displayObject.worldAlpha = 1;

    // Time to update all the children of the displayObject with the new matrix..
    var children = displayObject.children;
    var i, j;

    for (i = 0, j = children.length; i < j; ++i)
    {
        children[i].updateTransform();
    }

    if (clear)
    {
        this.textureBuffer.clear();
    }

    displayObject.worldTransform = cachedWt;

//    this.textureBuffer.
    var context = this.textureBuffer.context;

    var realResolution = this.renderer.resolution;

    this.renderer.resolution = this.resolution;

    this.renderer.renderDisplayObject(displayObject, context);

    this.renderer.resolution = realResolution;
 //   context.setTransform(1, 0, 0, 1, 0, 0);
   // context.fillStyle ="#FF0000"
//    context.fillRect(0, 0, 800, 600);

};

/**
 * Destroys this texture
 *
 * @param destroyBase {boolean} Whether to destroy the base texture as well
 */
RenderTexture.prototype.destroy = function ()
{
    Texture.prototype.destroy.call(this, true);

    this.textureBuffer.destroy();

    // destroy the filtermanager..
    if(this.filterManager)
    {
        this.filterManager.destroy();
    }

    this.renderer = null;
};

/**
 * Will return a HTML Image of the texture
 *
 * @return {Image}
 */
RenderTexture.prototype.getImage = function ()
{
    var image = new Image();
    image.src = this.getBase64();
    return image;
};

/**
 * Will return a a base64 encoded string of this texture. It works by calling RenderTexture.getCanvas and then running toDataURL on that.
 *
 * @return {string} A base64 encoded string of the texture.
 */
RenderTexture.prototype.getBase64 = function ()
{
    return this.getCanvas().toDataURL();
};

/**
 * Creates a Canvas element, renders this RenderTexture to it and then returns it.
 *
 * @return {HTMLCanvasElement} A Canvas element with the texture rendered on.
 */
RenderTexture.prototype.getCanvas = function ()
{
    if (this.renderer.type === CONST.RENDERER_TYPE.WEBGL)
    {
        var gl =  this.renderer.gl;
        var width = this.textureBuffer.width;
        var height = this.textureBuffer.height;

        var webGLPixels = new Uint8Array(4 * width * height);

        gl.bindFramebuffer(gl.FRAMEBUFFER, this.textureBuffer.frameBuffer);
        gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, webGLPixels);
        gl.bindFramebuffer(gl.FRAMEBUFFER, null);

        var tempCanvas = new CanvasBuffer(width, height);
        var canvasData = tempCanvas.context.getImageData(0, 0, width, height);
        canvasData.data.set(webGLPixels);

        tempCanvas.context.putImageData(canvasData, 0, 0);

        return tempCanvas.canvas;
    }
    else
    {
        return this.textureBuffer.canvas;
    }
};
<commit_msg>fixed type :/<commit_after>var BaseTexture = require('./BaseTexture'),
    Texture = require('./Texture'),
    RenderTarget = require('../renderers/webgl/utils/RenderTarget'),
    FilterManager = require('../renderers/webgl/managers/FilterManager'),
    CanvasBuffer = require('../renderers/canvas/utils/CanvasBuffer'),
    math = require('../math'),
    CONST = require('../const'),
    tempMatrix = new math.Matrix();

/**
 * A RenderTexture is a special texture that allows any Pixi display object to be rendered to it.
 *
 * __Hint__: All DisplayObjects (i.e. Sprites) that render to a RenderTexture should be preloaded
 * otherwise black rectangles will be drawn instead.
 *
 * A RenderTexture takes a snapshot of any Display Object given to its render method. The position
 * and rotation of the given Display Objects is ignored. For example:
 *
 * ```js
 * var renderTexture = new PIXI.RenderTexture(800, 600);
 * var sprite = PIXI.Sprite.fromImage("spinObj_01.png");
 *
 * sprite.position.x = 800/2;
 * sprite.position.y = 600/2;
 * sprite.anchor.x = 0.5;
 * sprite.anchor.y = 0.5;
 *
 * renderTexture.render(sprite);
 * ```
 *
 * The Sprite in this case will be rendered to a position of 0,0. To render this sprite at its actual
 * position a Container should be used:
 *
 * ```js
 * var doc = new Container();
 *
 * doc.addChild(sprite);
 *
 * renderTexture.render(doc);  // Renders to center of renderTexture
 * ```
 *
 * @class
 * @extends Texture
 * @memberof PIXI
 * @param renderer {CanvasRenderer|WebGLRenderer} The renderer used for this RenderTexture
 * @param [width=100] {number} The width of the render texture
 * @param [height=100] {number} The height of the render texture
 * @param [scaleMode] {number} See {@link SCALE_MODES} for possible values
 * @param [resolution=1] {number} The resolution of the texture being generated
 */
function RenderTexture(renderer, width, height, scaleMode, resolution)
{
    if (!renderer)
    {
        throw new Error('Unable to create RenderTexture, you must pass a renderer into the constructor.');
    }

    width = width || 100;
    height = height || 100;
    resolution = resolution || CONST.RESOLUTION;

    /**
     * The base texture object that this texture uses
     *
     * @member {BaseTexture}
     */
    var baseTexture = new BaseTexture();
    baseTexture.width = width;
    baseTexture.height = height;
    baseTexture.resolution = resolution;
    baseTexture.scaleMode = scaleMode || CONST.SCALE_MODES.DEFAULT;
    baseTexture.hasLoaded = true;

    Texture.call(this,
        baseTexture,
        new math.Rectangle(0, 0, width, height)
    );

    /**
     * The with of the render texture
     *
     * @member {number}
     */
    this.width = width;

    /**
     * The height of the render texture
     *
     * @member {number}
     */
    this.height = height;

    /**
     * The Resolution of the texture.
     *
     * @member {number}
     */
    this.resolution = resolution;

    /**
     * The framing rectangle of the render texture
     *
     * @member {Rectangle}
     */
    //this._frame = new math.Rectangle(0, 0, this.width * this.resolution, this.height * this.resolution);

    /**
     * This is the area of the BaseTexture image to actually copy to the Canvas / WebGL when rendering,
     * irrespective of the actual frame size or placement (which can be influenced by trimmed texture atlases)
     *
     * @member {Rectangle}
     */
    //this.crop = new math.Rectangle(0, 0, this.width * this.resolution, this.height * this.resolution);

    /**
     * Draw/render the given DisplayObject onto the texture.
     *
     * The displayObject and descendents are transformed during this operation.
     * If `updateTransform` is true then the transformations will be restored before the
     * method returns. Otherwise it is up to the calling code to correctly use or reset
     * the transformed display objects.
     *
     * The display object is always rendered with a worldAlpha value of 1.
     *
     * @method
     * @param displayObject {DisplayObject} The display object to render this texture on
     * @param [matrix] {Matrix} Optional matrix to apply to the display object before rendering.
     * @param [clear=false] {boolean} If true the texture will be cleared before the displayObject is drawn
     * @param [updateTransform=true] {boolean} If true the displayObject's worldTransform/worldAlpha and all children
     *  transformations will be restored. Not restoring this information will be a little faster.
     */
    this.render = null;

    /**
     * The renderer this RenderTexture uses. A RenderTexture can only belong to one renderer at the moment if its webGL.
     *
     * @member {CanvasRenderer|WebGLRenderer}
     */
    this.renderer = renderer;

    if (this.renderer.type === CONST.RENDERER_TYPE.WEBGL)
    {
        var gl = this.renderer.gl;

        this.textureBuffer = new RenderTarget(gl, this.width, this.height, null, this.resolution);//, this.baseTexture.scaleMode);
        this.baseTexture._glTextures[gl.id] =  this.textureBuffer.texture;

        //TODO refactor filter manager.. as really its no longer a manager if we use it here..
        this.filterManager = new FilterManager(this.renderer);
        this.filterManager.onContextChange();
        this.filterManager.resize(width, height);
        this.render = this.renderWebGL;

        // the creation of a filter manager unbinds the buffers..
        this.renderer.currentRenderer.start();
    }
    else
    {

        this.render = this.renderCanvas;
        this.textureBuffer = new CanvasBuffer(this.width* this.resolution, this.height* this.resolution);
        this.baseTexture.source = this.textureBuffer.canvas;
    }

    /**
     * @member {boolean}
     */
    this.valid = true;

    this._updateUvs();
}

RenderTexture.prototype = Object.create(Texture.prototype);
RenderTexture.prototype.constructor = RenderTexture;
module.exports = RenderTexture;

/**
 * Resizes the RenderTexture.
 *
 * @param width {number} The width to resize to.
 * @param height {number} The height to resize to.
 * @param updateBase {boolean} Should the baseTexture.width and height values be resized as well?
 */
RenderTexture.prototype.resize = function (width, height, updateBase)
{
    if (width === this.width && height === this.height)
    {
        return;
    }

    this.valid = (width > 0 && height > 0);

    this.width = this._frame.width = this.crop.width = width;
    this.height =  this._frame.height = this.crop.height = height;

    if (updateBase)
    {
        this.baseTexture.width = this.width;
        this.baseTexture.height = this.height;
    }

    if (this.renderer.type === CONST.RENDERER_TYPE.WEBGL)
    {
        this.projection.x = this.width / 2;
        this.projection.y = -this.height / 2;
    }

    if (!this.valid)
    {
        return;
    }

    this.textureBuffer.resize(this.width * this.resolution, this.height * this.resolution);

    if(this.filterManager)
    {
        this.filterManager.resize(this.width, this.height);
    }
};

/**
 * Clears the RenderTexture.
 *
 */
RenderTexture.prototype.clear = function ()
{
    if (!this.valid)
    {
        return;
    }

    if (this.renderer.type === CONST.RENDERER_TYPE.WEBGL)
    {
        this.renderer.gl.bindFramebuffer(this.renderer.gl.FRAMEBUFFER, this.textureBuffer.frameBuffer);
    }

    this.textureBuffer.clear();
};

/**
 * Internal method assigned to the `render` property if using a CanvasRenderer.
 *
 * @private
 * @param displayObject {DisplayObject} The display object to render this texture on
 * @param [matrix] {Matrix} Optional matrix to apply to the display object before rendering.
 * @param [clear=false] {boolean} If true the texture will be cleared before the displayObject is drawn
 * @param [updateTransform=true] {boolean} If true the displayObject's worldTransform/worldAlpha and all children
 *  transformations will be restored. Not restoring this information will be a little faster.
 */
RenderTexture.prototype.renderWebGL = function (displayObject, matrix, clear, updateTransform)
{
    if (!this.valid)
    {
        return;
    }

    updateTransform = (updateTransform !== undefined) ? updateTransform : true;//!updateTransform;

    this.textureBuffer.transform = matrix;

    // setWorld Alpha to ensure that the object is renderer at full opacity
    displayObject.worldAlpha = displayObject.alpha;

    if (updateTransform)
    {

        // reset the matrix of the displatyObject..
        displayObject.worldTransform.identity();

        displayObject.currentBounds = null;

        // Time to update all the children of the displayObject with the new matrix..
        var children = displayObject.children;
        var i, j;

        for (i = 0, j = children.length; i < j; ++i)
        {
            children[i].updateTransform();
        }
    }

   if (clear)
    {
        this.textureBuffer.clear();
    }

    //TODO rename textureBuffer to renderTarget..
    var temp =  this.renderer.filterManager;

    this.renderer.filterManager = this.filterManager;
    this.renderer.renderDisplayObject(displayObject, this.textureBuffer);

    this.renderer.filterManager = temp;

};

/**
 * Internal method assigned to the `render` property if using a CanvasRenderer.
 *
 * @private
 * @param displayObject {DisplayObject} The display object to render this texture on
 * @param [matrix] {Matrix} Optional matrix to apply to the display object before rendering.
 * @param [clear] {boolean} If true the texture will be cleared before the displayObject is drawn
 */
RenderTexture.prototype.renderCanvas = function (displayObject, matrix, clear, updateTransform)
{
    if (!this.valid)
    {
        return;
    }

    updateTransform = !!updateTransform;
    var cachedWt = displayObject.worldTransform;

    var wt = tempMatrix;

    wt.identity();

    if (matrix)
    {
        wt.append(matrix);
    }

    displayObject.worldTransform = wt;

    // setWorld Alpha to ensure that the object is renderer at full opacity
    displayObject.worldAlpha = 1;

    // Time to update all the children of the displayObject with the new matrix..
    var children = displayObject.children;
    var i, j;

    for (i = 0, j = children.length; i < j; ++i)
    {
        children[i].updateTransform();
    }

    if (clear)
    {
        this.textureBuffer.clear();
    }

    displayObject.worldTransform = cachedWt;

//    this.textureBuffer.
    var context = this.textureBuffer.context;

    var realResolution = this.renderer.resolution;

    this.renderer.resolution = this.resolution;

    this.renderer.renderDisplayObject(displayObject, context);

    this.renderer.resolution = realResolution;
 //   context.setTransform(1, 0, 0, 1, 0, 0);
   // context.fillStyle ="#FF0000"
//    context.fillRect(0, 0, 800, 600);

};

/**
 * Destroys this texture
 *
 * @param destroyBase {boolean} Whether to destroy the base texture as well
 */
RenderTexture.prototype.destroy = function ()
{
    Texture.prototype.destroy.call(this, true);

    this.textureBuffer.destroy();

    // destroy the filtermanager..
    if(this.filterManager)
    {
        this.filterManager.destroy();
    }

    this.renderer = null;
};

/**
 * Will return a HTML Image of the texture
 *
 * @return {Image}
 */
RenderTexture.prototype.getImage = function ()
{
    var image = new Image();
    image.src = this.getBase64();
    return image;
};

/**
 * Will return a a base64 encoded string of this texture. It works by calling RenderTexture.getCanvas and then running toDataURL on that.
 *
 * @return {string} A base64 encoded string of the texture.
 */
RenderTexture.prototype.getBase64 = function ()
{
    return this.getCanvas().toDataURL();
};

/**
 * Creates a Canvas element, renders this RenderTexture to it and then returns it.
 *
 * @return {HTMLCanvasElement} A Canvas element with the texture rendered on.
 */
RenderTexture.prototype.getCanvas = function ()
{
    if (this.renderer.type === CONST.RENDERER_TYPE.WEBGL)
    {
        var gl =  this.renderer.gl;
        var width = this.textureBuffer.width;
        var height = this.textureBuffer.height;

        var webGLPixels = new Uint8Array(4 * width * height);

        gl.bindFramebuffer(gl.FRAMEBUFFER, this.textureBuffer.frameBuffer);
        gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, webGLPixels);
        gl.bindFramebuffer(gl.FRAMEBUFFER, null);

        var tempCanvas = new CanvasBuffer(width, height);
        var canvasData = tempCanvas.context.getImageData(0, 0, width, height);
        canvasData.data.set(webGLPixels);

        tempCanvas.context.putImageData(canvasData, 0, 0);

        return tempCanvas.canvas;
    }
    else
    {
        return this.textureBuffer.canvas;
    }
};
<|endoftext|>