<commit_before>import React, { Component } from 'react';
import Dropzone from 'react-dropzone';
import { Card, Button } from 'bm-kit';
import ApplicationTextField from './ApplicationTextField';
import ApplicationToggle from './ApplicationToggle';
import ApplicationSelectField from './ApplicationSelectField';
import ApplicationCompletedCard from './ApplicationCompletedCard';
import ValidationError from './ValidationError';
// import ResumeUploadProgressIndicator from './ResumeUploadProgressIndicator';

import {
  raceOptions,
  genderOptions,
  gradYearOptions,
  isFirstHackathonOptions
} from './ApplicationConsts';

import './_pillar.application.source.scss';

class ApplicationForm extends Component {
  fieldHasError(field) {
    const { validation } = this.props.application;
    return validation.reason_field.indexOf(field) > -1;
  }

  fieldErrorText(field) {
    const { validation } = this.props.application;
    const fieldIndex = validation.reason_field.indexOf(field);
    if (fieldIndex <= -1) return null;

    return validation.reason_label[fieldIndex];
  }

  render() {
    const { applicationForm } = this.props.application;
    const isLoading = this.props.application.loading;
    const isGithubLinked =
      this.props.user.me && this.props.user.me.github_user_id !== null;
    let dropzoneRef;

    const phone = this.props.application.applicationForm.phone;
    return (
      <Dropzone
        ref={node => {
          dropzoneRef = node;
        }}
        disableClick
        multiple={false}
        accept="application/pdf"
        onDrop={this.props.onResumeDrop.bind(this)}
        style={{ border: 'none', height: '100%' }}
      >
        <ApplicationCompletedCard show={applicationForm.completed} />
        <Card className="p-application__form">

Application

Personal

          <ApplicationTextField
            field="first_name"
            label="First Name"
            hasError={this.fieldHasError('first_name')}
            errorText={this.fieldErrorText('first_name')}
          />
          <ApplicationTextField
            field="last_name"
            label="Last Name"
            hasError={this.fieldHasError('last_name')}
            errorText={this.fieldErrorText('last_name')}
          />
          <ApplicationTextField
            field="phone"
            label="Phone Number"
            hasError={phone === null}
            errorText={phone === null ? 'Phone number not set' : null}
          />

            Is this your first hackathon?

          <ApplicationSelectField
            field="isFirstHackathon"
            options={isFirstHackathonOptions}
          />
          <ValidationError
            field="isFirstHackathon"
            validation={this.props.application.validation}
          />

School

School

          <ApplicationSelectField
            field="school_id"
            searchable
            options={this.props.schools}
          />
          <ValidationError
            field="school_id"
            validation={this.props.application.validation}
          />

          <ApplicationTextField
            field="major"
            label="Major"
            hasError={this.fieldHasError('major')}
            errorText={this.fieldErrorText('major')}
          />

            Expected Graduation Year

          <ApplicationSelectField
            field="grad_year"
            searchable
            options={gradYearOptions}
          />
          <ValidationError
            field="grad_year"
            validation={this.props.application.validation}
          />

Social

          <ApplicationTextField
            field="linkedin"
            label="LinkedIn Username"
            disabled={!applicationForm.has_no_linkedin}
            hasError={this.fieldHasError('linkedin')}
            errorText={this.fieldErrorText('linkedin')}
          />
          <ApplicationTextField
            field="github"
            label="GitHub"
            disabled={!applicationForm.has_no_github || isGithubLinked}
            hasError={this.fieldHasError('github')}
            errorText={this.fieldErrorText('github')}
          />
          {isGithubLinked ? (

              You signed up with github, so you can't change the username

          ) : null}

Other Suff

Gender

          <ApplicationSelectField field="gender" options={genderOptions} />
          <ValidationError
            field="gender"
            validation={this.props.application.validation}
          />

Race

          <ApplicationSelectField field="race" options={raceOptions} />
          <ValidationError
            field="race"
            validation={this.props.application.validation}
          />

            <Button
              type="button"
              onClick={() => {
                dropzoneRef.open();
              }}
              full
            >
              Drop or click to upload Resume (PDF only)
            </Button>
            {/* <ResumeUploadProgressIndicator/> */}
            {applicationForm.resume_uploaded ? (

                You've uploaded{' '}

                  {applicationForm.resume_filename}

            ) : null}
            <ValidationError
              field="resume_filename"
              validation={this.props.application.validation}
            />

            <ApplicationToggle field="tandc_1" />

              I will be 18 or older by October 19, 2018.

            <ApplicationToggle field="tandc_2" />

              I agree to the{' '}

                MLH code of conduct

              <ApplicationToggle field="tandc_3" />

              I agree to the terms of both the

                MLH Contest Terms and Conditions

               and the

                MLH Privacy Policy.

              Please note that you may receive pre and post-event informational
              e-mails and occasional messages about hackathons from MLH as per
              the MLH Privacy Policy.

You can edit your application until October 10th.

            <Button
              disabled={isLoading}
              onClick={() => {
                this.props.saveApplication();
              }}
              full
            >
              Save Application
            </Button>

        </Card>
      </Dropzone>
    );
  }
}

//now the redux integration layer
import {
  saveApplication,
  onResumeDrop,
  toggleApplicationFieldValue
} from '../../actions/application';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
function mapStateToProps(state) {
  return {
    user: state.user,
    application: state.application,
    schools: state.application.schools.map(school => ({
      value: school.id,
      label: school.name
    }))
  };
}

const mapDispatchToProps = dispatch => {
  return bindActionCreators(
    {
      saveApplication,
      onResumeDrop,
      toggleApplicationFieldValue
    },
    dispatch
  );
};

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(ApplicationForm);
<commit_msg>Phone number validation (#137)<commit_after>import React, { Component } from 'react';
import Dropzone from 'react-dropzone';
import { Card, Button } from 'bm-kit';
import ApplicationTextField from './ApplicationTextField';
import ApplicationToggle from './ApplicationToggle';
import ApplicationSelectField from './ApplicationSelectField';
import ApplicationCompletedCard from './ApplicationCompletedCard';
import ValidationError from './ValidationError';
// import ResumeUploadProgressIndicator from './ResumeUploadProgressIndicator';

import {
  raceOptions,
  genderOptions,
  gradYearOptions,
  isFirstHackathonOptions
} from './ApplicationConsts';

import './_pillar.application.source.scss';

class ApplicationForm extends Component {
  fieldHasError(field) {
    const { validation } = this.props.application;
    return validation.reason_field.indexOf(field) > -1;
  }

  fieldErrorText(field) {
    const { validation } = this.props.application;
    const fieldIndex = validation.reason_field.indexOf(field);
    if (fieldIndex <= -1) return null;

    return validation.reason_label[fieldIndex];
  }

  render() {
    const { applicationForm } = this.props.application;
    const isLoading = this.props.application.loading;
    const isGithubLinked =
      this.props.user.me && this.props.user.me.github_user_id !== null;
    let dropzoneRef;

    return (
      <Dropzone
        ref={node => {
          dropzoneRef = node;
        }}
        disableClick
        multiple={false}
        accept="application/pdf"
        onDrop={this.props.onResumeDrop.bind(this)}
        style={{ border: 'none', height: '100%' }}
      >
        <ApplicationCompletedCard show={applicationForm.completed} />
        <Card className="p-application__form">

Application

Personal

          <ApplicationTextField
            field="first_name"
            label="First Name"
            hasError={this.fieldHasError('first_name')}
            errorText={this.fieldErrorText('first_name')}
          />
          <ApplicationTextField
            field="last_name"
            label="Last Name"
            hasError={this.fieldHasError('last_name')}
            errorText={this.fieldErrorText('last_name')}
          />
          <ApplicationTextField
            field="phone"
            label="Phone Number"
            hasError={this.fieldHasError('phone')}
            errorText={this.fieldErrorText('phone')}
          />

            Is this your first hackathon?

          <ApplicationSelectField
            field="isFirstHackathon"
            options={isFirstHackathonOptions}
          />
          <ValidationError
            field="isFirstHackathon"
            validation={this.props.application.validation}
          />

School

School

          <ApplicationSelectField
            field="school_id"
            searchable
            options={this.props.schools}
          />
          <ValidationError
            field="school_id"
            validation={this.props.application.validation}
          />

          <ApplicationTextField
            field="major"
            label="Major"
            hasError={this.fieldHasError('major')}
            errorText={this.fieldErrorText('major')}
          />

            Expected Graduation Year

          <ApplicationSelectField
            field="grad_year"
            searchable
            options={gradYearOptions}
          />
          <ValidationError
            field="grad_year"
            validation={this.props.application.validation}
          />

Social

          <ApplicationTextField
            field="linkedin"
            label="LinkedIn Username"
            disabled={!applicationForm.has_no_linkedin}
            hasError={this.fieldHasError('linkedin')}
            errorText={this.fieldErrorText('linkedin')}
          />
          <ApplicationTextField
            field="github"
            label="GitHub"
            disabled={!applicationForm.has_no_github || isGithubLinked}
            hasError={this.fieldHasError('github')}
            errorText={this.fieldErrorText('github')}
          />
          {isGithubLinked ? (

              You signed up with github, so you can't change the username

          ) : null}

Other Suff

Gender

          <ApplicationSelectField field="gender" options={genderOptions} />
          <ValidationError
            field="gender"
            validation={this.props.application.validation}
          />

Race

          <ApplicationSelectField field="race" options={raceOptions} />
          <ValidationError
            field="race"
            validation={this.props.application.validation}
          />

            <Button
              type="button"
              onClick={() => {
                dropzoneRef.open();
              }}
              full
            >
              Drop or click to upload Resume (PDF only)
            </Button>
            {/* <ResumeUploadProgressIndicator/> */}
            {applicationForm.resume_uploaded ? (

                You've uploaded{' '}

                  {applicationForm.resume_filename}

            ) : null}
            <ValidationError
              field="resume_filename"
              validation={this.props.application.validation}
            />

            <ApplicationToggle field="tandc_1" />

              I will be 18 or older by October 19, 2018.

            <ApplicationToggle field="tandc_2" />

              I agree to the{' '}

                MLH code of conduct

              <ApplicationToggle field="tandc_3" />

              I agree to the terms of both the

                MLH Contest Terms and Conditions

               and the

                MLH Privacy Policy.

              Please note that you may receive pre and post-event informational
              e-mails and occasional messages about hackathons from MLH as per
              the MLH Privacy Policy.

You can edit your application until October 10th.

            <Button
              disabled={isLoading}
              onClick={() => {
                this.props.saveApplication();
              }}
              full
            >
              Save Application
            </Button>

        </Card>
      </Dropzone>
    );
  }
}

//now the redux integration layer
import {
  saveApplication,
  onResumeDrop,
  toggleApplicationFieldValue
} from '../../actions/application';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
function mapStateToProps(state) {
  return {
    user: state.user,
    application: state.application,
    schools: state.application.schools.map(school => ({
      value: school.id,
      label: school.name
    }))
  };
}

const mapDispatchToProps = dispatch => {
  return bindActionCreators(
    {
      saveApplication,
      onResumeDrop,
      toggleApplicationFieldValue
    },
    dispatch
  );
};

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(ApplicationForm);
<|endoftext|>


<commit_before>'use strict';

import { REQUEST_TIMEOUT } from '../lib/constants';
import { default as baseRequest } from 'request';
import { default as moment } from 'moment-timezone';
import { acceptableParameters } from '../lib/utils';
import { join } from 'path';
import log from '../lib/logger';
import JSONStream from 'JSONStream';
import { DataStream } from 'scramjet';
import { FetchError, DATA_URL_ERROR } from '../lib/errors';

// Adding in certs to get around unverified connection issue
require('ssl-root-cas/latest')
  .inject()
  .addFile(join(__dirname, '..', '/certs/lets-encrypt-x3-cross-signed.pem.txt'));
const request = baseRequest.defaults({timeout: REQUEST_TIMEOUT});

export const name = 'caaqm';

export async function fetchStream (source) {
  const requestOptions = {
    method: 'POST',
    headers: {
      'accept-language': 'en-US,en',
      'content-type': 'application/x-www-form-urlencoded',
      accept: 'application/json'
    },
    form: false
  };
  const options = Object.assign(requestOptions, {
    url: source.url,
    body: Buffer.from('{"region":"landing_dashboard"}').toString('base64')
  });

  const requestObject = request(options);

  return DataStream
    .pipeline(
      requestObject,
      JSONStream.parse('map.station_list.*')
    )
    .catch(e => {
      requestObject.abort();
      e.stream.end();
      throw e;
    })
    .setOptions({ maxParallel: 20 })
    .into((siteStream, site) => {
      return siteStream.whenWrote({
        station_id: site['station_id'],
        station_name: site['station_name'],
        coords: {
          latitude: Number(site['latitude']),
          longitude: Number(site['longitude'])
        },
        status: site['status']
      });
    }, new DataStream())
    .filter((station) => {
      return station.status === 'Live';
    })
    .into(
      async (measurements, {coords, station_id: stationId}) => {
        const options = Object.assign(requestOptions, {
          url: 'https://app.cpcbccr.com/caaqms/caaqms_viewdata_v2',
          body: Buffer.from(`{"site_id":"${stationId}"}`).toString('base64'),
          resolveWithFullResponse: true,
          timeout: 15000
        });

        try {
          const body = await getInfo(options, stationId);
          const {siteInfo, tableData: {bodyContent}} = JSON.parse(body);

          await (
            DataStream
              .from(bodyContent)
              .each(async p => {
                let parameter = p.parameters.toLowerCase().replace('.', '');
                parameter = (parameter === 'ozone') ? 'o3' : parameter;

                // Make sure we want the pollutant
                if (!acceptableParameters.includes(parameter)) {
                  return;
                }

                let m = {
                  averagingPeriod: {unit: 'hours', value: 0.25},
                  city: siteInfo.city,
                  location: siteInfo.siteName,
                  coordinates: coords,
                  attribution: [{
                    name: 'Central Pollution Control Board',
                    url: 'https://app.cpcbccr.com/ccr/#/caaqm-dashboard-all/caaqm-landing'
                  }],
                  parameter: parameter,
                  unit: p.unit,
                  value: Number(p.concentration)
                };

                // Date
                const date = moment.tz(`${p.date} ${p.time}`, 'DD MMM YYYY HH:mm', 'Asia/Kolkata');
                m.date = {utc: date.toDate(), local: date.format()};

                await measurements.whenWrote(m);
              })
              .run()
          );
        } catch (e) {
          const message = (e.statusCode)
            ? `Status code ${e.statusCode} received on http request for station`
            : `Error while parsing measurements for station`;

          log.debug({message, stationId, code: e.statusCode});

          throw new FetchError(DATA_URL_ERROR, source, e, message);
        }
      },
      new DataStream()
    )
  ;
}

async function getInfo (options, stationId) {
  return new Promise((resolve, reject) => {
    request.post(options, (err, res, body) => {
      log.debug(`stationId: ${stationId}, statusCode: ${res ? res.statusCode : 'unknown'}`);
      if (err) {
        log.error(err ? `${err.message} for stationId: ${stationId}` : 'error');
        reject(err);
      } else {
        resolve(body);
      }
    });
  });
}
<commit_msg>Update error comment for CAAQM adapter<commit_after>'use strict';

import { REQUEST_TIMEOUT } from '../lib/constants';
import { default as baseRequest } from 'request';
import { default as moment } from 'moment-timezone';
import { acceptableParameters } from '../lib/utils';
import { join } from 'path';
import log from '../lib/logger';
import JSONStream from 'JSONStream';
import { DataStream } from 'scramjet';
import { FetchError, DATA_URL_ERROR } from '../lib/errors';

// Adding in certs to get around unverified connection issue
require('ssl-root-cas/latest')
  .inject()
  .addFile(join(__dirname, '..', '/certs/lets-encrypt-x3-cross-signed.pem.txt'));
const request = baseRequest.defaults({timeout: REQUEST_TIMEOUT});

export const name = 'caaqm';

export async function fetchStream (source) {
  const requestOptions = {
    method: 'POST',
    headers: {
      'accept-language': 'en-US,en',
      'content-type': 'application/x-www-form-urlencoded',
      accept: 'application/json'
    },
    form: false
  };
  const options = Object.assign(requestOptions, {
    url: source.url,
    body: Buffer.from('{"region":"landing_dashboard"}').toString('base64')
  });

  const requestObject = request(options);

  return DataStream
    .pipeline(
      requestObject,
      JSONStream.parse('map.station_list.*')
    )
    .catch(e => {
      requestObject.abort();
      e.stream.end();
      throw e;
    })
    .setOptions({ maxParallel: 20 })
    .into((siteStream, site) => {
      return siteStream.whenWrote({
        station_id: site['station_id'],
        station_name: site['station_name'],
        coords: {
          latitude: Number(site['latitude']),
          longitude: Number(site['longitude'])
        },
        status: site['status']
      });
    }, new DataStream())
    .filter((station) => {
      return station.status === 'Live';
    })
    .into(
      async (measurements, {coords, station_id: stationId}) => {
        const options = Object.assign(requestOptions, {
          url: 'https://app.cpcbccr.com/caaqms/caaqms_viewdata_v2',
          body: Buffer.from(`{"site_id":"${stationId}"}`).toString('base64'),
          resolveWithFullResponse: true,
          timeout: 15000
        });

        try {
          const body = await getInfo(options, stationId);
          const {siteInfo, tableData: {bodyContent}} = JSON.parse(body);

          await (
            DataStream
              .from(bodyContent)
              .each(async p => {
                let parameter = p.parameters.toLowerCase().replace('.', '');
                parameter = (parameter === 'ozone') ? 'o3' : parameter;

                // Make sure we want the pollutant
                if (!acceptableParameters.includes(parameter)) {
                  return;
                }

                let m = {
                  averagingPeriod: {unit: 'hours', value: 0.25},
                  city: siteInfo.city,
                  location: siteInfo.siteName,
                  coordinates: coords,
                  attribution: [{
                    name: 'Central Pollution Control Board',
                    url: 'https://app.cpcbccr.com/ccr/#/caaqm-dashboard-all/caaqm-landing'
                  }],
                  parameter: parameter,
                  unit: p.unit,
                  value: Number(p.concentration)
                };

                // Date
                const date = moment.tz(`${p.date} ${p.time}`, 'DD MMM YYYY HH:mm', 'Asia/Kolkata');
                m.date = {utc: date.toDate(), local: date.format()};

                await measurements.whenWrote(m);
              })
              .run()
          );
        } catch (e) {
          const message = (e.statusCode)
            ? `Status code ${e.statusCode} received on http request for station`
            : `Error while parsing measurements for station`;

          log.debug({message, stationId, code: e.statusCode});

          throw new FetchError(DATA_URL_ERROR, source, e, message);
        }
      },
      new DataStream()
    )
  ;
}

async function getInfo (options, stationId) {
  return new Promise((resolve, reject) => {
    request.post(options, (err, res, body) => {
      log.debug(`stationId: ${stationId}, statusCode: ${res ? res.statusCode : 'unknown'}`);
      if (err) {
        log.error(err ? `${err.message} for adapter: ${name} - stationId: ${stationId}` : 'error');
        reject(err);
      } else {
        resolve(body);
      }
    });
  });
}
<|endoftext|>


<commit_before>'use strict';

/* Controllers */

angular.module('myApp.controllers', [])
  .controller('AppCtrl', function($scope, $rootScope, $http, $cookies, $route) {
    $rootScope.topScope = $rootScope;
    $http.defaults.headers.post['X-CSRFToken'] = $cookies.csrftoken;
    $http.defaults.headers.post['Content-Type'] =  'application/x-www-form-urlencoded'
    $http.get('user/').success(function(data) {
        $rootScope.user = data;
    })

    $('.atooltip').tooltip({"placement" : "bottom"});
    $('.input-tooltip').tooltip({"placement" : "bottom", trigger: "focus"});
    $('.dropdown-menu li input').click(function(event){
        // hack to prevent login dropdown from premature closing on mobile platforms
        var dropdown = $(this).parents('li.dropdown')
        setTimeout(function(){
            dropdown.addClass("open");
        },10);
        event.stopPropagation();
    });
    $('a#fdbk_tab').colorbox();

    $rootScope.login = function(){
        $scope.$apply();
        var credentials = {
            'username' : $scope.username,
            'password' : $scope.password
        }
        $http.post('user/login/', credentials).success(function(data) {
            $rootScope.loginResponse = data;
            if (data.success) {
                //$route.reload();
                document.location.reload(true)
            }
        }).error(function(data) {
            $rootScope.loginResponse = {'messgae' : "Přihllášení se nezdařilo"};
        });
    }

    $rootScope.logout = function(){
        $http.get('user/logout/').success(function(data) {
            $rootScope.user = data;
        })
    }

    $rootScope.addPoint = function(){
        $rootScope.user.points++;
    }
  })

  .controller('AppView', function($scope, $routeParams, usersplaces, question) {
    $scope.part = $routeParams.part;
    $scope.user = $routeParams.user || "";
    $scope.placesTypes = [];

    usersplaces($scope.part, $scope.user, function(data) {
        $scope.placesTypes = data;
        $scope.$parent.placesTypes = data;
        var places = {};
        angular.forEach(data[0].places, function(place) {
            places[place.code] = {
                name : place.name,
                skill : place.skill
            }
        });
        var mapConfig = {
            name : $scope.part.toLowerCase(),
            showTooltips : true,
            states : places
        }
        $scope.map = initMap(mapConfig);
    });

    question.availableCount($scope.part, function(count) {
        $scope.practiceCount = count;
    })

  })

  .controller('AppPractice', function($scope, $routeParams, $timeout, $location, places, question) {
    $scope.part = $routeParams.part;

    $scope.setQuestion = function(active) {
        $scope.question = active;
        $scope.map.clearHighlights();
        if (active.type == 1) {
            $scope.map.blink(active.code);
        }
        $scope.canNext = false;
        $scope.select = undefined;
        $("select.select2").select2("val", $scope.select);
    }

    $scope.check = function(selected) {
       var correct = (selected == $scope.question.code);
       $scope.map.highlightState($scope.question.code);
       $scope.map.highlightState(selected, correct ? GOOD : BAD);
       $scope.canNext = true;
       $("select.select2").select2("val", $scope.question.code);
       if (correct) {
           $scope.$parent.addPoint();
       }
       $scope.question.answer = selected;
       $scope.progress = question.answer($scope.question);
    }

    $scope.next = function() {
        if($scope.progress < 100) {
            question.next($scope.part, function(q) {
                $scope.setQuestion(q);
            })
        } else {
            $scope.summary = question.summary();
            $scope.showSummary = true;
            $scope.map.clearHighlights();
            angular.forEach($scope.summary.questions, function(q){
                var correct = q.code == q.answer;
                $scope.map.highlightState(q.code, correct ? GOOD : BAD);
            })
        }
    }

    $scope.openPlacesSelect = function() {
        $timeout(function() {
            $("select.select2").select2("open");
        },100);
    }

    places($scope.part, function(placesTypes) {
        $scope.places = placesTypes[0].places;
        $timeout(function() {
            var format = function(state) {
                if (!state.id) return state.text; // optgroup
                    return ' ' + state.text;
            }
            $("select.select2").select2({
                placeholder: "Vyber stát",
                formatResult: format,
                formatSelection: format,
                escapeMarkup: function(m) { return m; }
            });
            $("select.starters").select2({
                placeholder: "Počáteční písmeno",
                width : '100px'
            });
        },100);

        var mapConfig = {
            name : $scope.part.toLowerCase(),
            click : function  (data) {
                if ($scope.question.type == 0 && !$scope.canNext) {
                    $scope.check(data);
                    $scope.$apply();
                }
            }
        }
        $scope.map = initMap(mapConfig, function() {
            question.first($scope.part, function(q) {
                if(q) $scope.setQuestion(q);
                else {
                    $scope.showSummary = true;
                    $scope.errorMessage = 'Žádný stát není potřeba procvičovat.';
                }
            })
        })
    })

  })

<commit_msg>mobile form  support<commit_after>'use strict';

/* Controllers */

angular.module('myApp.controllers', [])
  .controller('AppCtrl', function($scope, $rootScope, $http, $cookies, $route) {
    $rootScope.topScope = $rootScope;
    $http.defaults.headers.post['X-CSRFToken'] = $cookies.csrftoken;
    $http.defaults.headers.post['Content-Type'] =  'application/x-www-form-urlencoded'
    $http.get('user/').success(function(data) {
        $rootScope.user = data;
    })

    $('.atooltip').tooltip({"placement" : "bottom"});
    $('.input-tooltip').tooltip({"placement" : "bottom", trigger: "focus"});
    $('.dropdown-menu li input').click(function(event){
        // hack to prevent login dropdown from premature closing on mobile platforms
        var dropdown = $(this).parents('li.dropdown')
        setTimeout(function(){
            dropdown.addClass("open");
        },200);
        event.stopPropagation();
    });
    $('a#fdbk_tab').colorbox();

    $rootScope.login = function(){
        $scope.$apply();
        var credentials = {
            'username' : $scope.username,
            'password' : $scope.password
        }
        $http.post('user/login/', credentials).success(function(data) {
            $rootScope.loginResponse = data;
            if (data.success) {
                //$route.reload();
                document.location.reload(true)
            }
        }).error(function(data) {
            $rootScope.loginResponse = {'messgae' : "Přihllášení se nezdařilo"};
        });
    }

    $rootScope.logout = function(){
        $http.get('user/logout/').success(function(data) {
            $rootScope.user = data;
        })
    }

    $rootScope.addPoint = function(){
        $rootScope.user.points++;
    }
  })

  .controller('AppView', function($scope, $routeParams, usersplaces, question) {
    $scope.part = $routeParams.part;
    $scope.user = $routeParams.user || "";
    $scope.placesTypes = [];

    usersplaces($scope.part, $scope.user, function(data) {
        $scope.placesTypes = data;
        $scope.$parent.placesTypes = data;
        var places = {};
        angular.forEach(data[0].places, function(place) {
            places[place.code] = {
                name : place.name,
                skill : place.skill
            }
        });
        var mapConfig = {
            name : $scope.part.toLowerCase(),
            showTooltips : true,
            states : places
        }
        $scope.map = initMap(mapConfig);
    });

    question.availableCount($scope.part, function(count) {
        $scope.practiceCount = count;
    })

  })

  .controller('AppPractice', function($scope, $routeParams, $timeout, $location, places, question) {
    $scope.part = $routeParams.part;

    $scope.setQuestion = function(active) {
        $scope.question = active;
        $scope.map.clearHighlights();
        if (active.type == 1) {
            $scope.map.blink(active.code);
        }
        $scope.canNext = false;
        $scope.select = undefined;
        $("select.select2").select2("val", $scope.select);
    }

    $scope.check = function(selected) {
       var correct = (selected == $scope.question.code);
       $scope.map.highlightState($scope.question.code);
       $scope.map.highlightState(selected, correct ? GOOD : BAD);
       $scope.canNext = true;
       $("select.select2").select2("val", $scope.question.code);
       if (correct) {
           $scope.$parent.addPoint();
       }
       $scope.question.answer = selected;
       $scope.progress = question.answer($scope.question);
    }

    $scope.next = function() {
        if($scope.progress < 100) {
            question.next($scope.part, function(q) {
                $scope.setQuestion(q);
            })
        } else {
            $scope.summary = question.summary();
            $scope.showSummary = true;
            $scope.map.clearHighlights();
            angular.forEach($scope.summary.questions, function(q){
                var correct = q.code == q.answer;
                $scope.map.highlightState(q.code, correct ? GOOD : BAD);
            })
        }
    }

    $scope.openPlacesSelect = function() {
        $timeout(function() {
            $("select.select2").select2("open");
        },100);
    }

    places($scope.part, function(placesTypes) {
        $scope.places = placesTypes[0].places;
        $timeout(function() {
            var format = function(state) {
                if (!state.id) return state.text; // optgroup
                    return ' ' + state.text;
            }
            $("select.select2").select2({
                placeholder: "Vyber stát",
                formatResult: format,
                formatSelection: format,
                escapeMarkup: function(m) { return m; }
            });
            $("select.starters").select2({
                placeholder: "Počáteční písmeno",
                width : '100px'
            });
        },100);

        var mapConfig = {
            name : $scope.part.toLowerCase(),
            click : function  (data) {
                if ($scope.question.type == 0 && !$scope.canNext) {
                    $scope.check(data);
                    $scope.$apply();
                }
            }
        }
        $scope.map = initMap(mapConfig, function() {
            question.first($scope.part, function(q) {
                if(q) $scope.setQuestion(q);
                else {
                    $scope.showSummary = true;
                    $scope.errorMessage = 'Žádný stát není potřeba procvičovat.';
                }
            })
        })
    })

  })

<|endoftext|>


<commit_before>import { createWriteStream } from 'fs'
import { forEach, isFile, exec } from '../../util'

export function generateChangelog ({ commits, file, version, url, bugs, previousFile }) {
  const changelog = typeof file === 'string' ? createFileStream(file) : file
  return new Promise((resolve) => {
    const sections = {
      breaks: [], // special section to highlight breaking changes
      feat: [],
      fix: [],
      perf: []
    }

    const titles = {
      breaks: 'Breaking Changes',
      feat: 'Features',
      fix: 'Bug Fixes',
      perf: 'Performance Improvements'
    }

    changelog.write(`# ${version} (${currentDate()})\n---\n\n`)

    forEach(commits, function (commit) {
      if (isCommitBreakingChange(commit)) {
        sections.breaks.push(commit)
      } else {
        sections[commit.type] = sections[commit.type] || []
        sections[commit.type].push(commit)
      }
    })

    forEach(Object.keys(sections), function (section) {
      const sectionCommits = sections[section]
      const title = titles[section]

      if (!sectionCommits.length) return

      changelog.write(`\n## ${title}\n\n`)

      forEach(sectionCommits, function (commit) {
        changelog.write(`    - ${commit.header} ${linkToCommit(commit.hash, url)}`)
        changelog.write(`\n`)
      })
    })

    changelog.write('\n\n')
    changelog.write(previousFile)

    resolve(changelog)
  })
}

function createFileStream (file) {
  if (!isFile(file)) {
    exec(`touch ${file}`, { silent: true, async: false })
  }
  return createWriteStream(file)
}

function linkToCommit (hash, url) {
  return `[${hash.substr(0, 8)}](${url}/commits/${hash}\)`
}

function currentDate () {
  const now = new Date()
  const pad = function (i) {
    return ('0' + i).substr(-2)
  }
  return `${now.getFullYear()}-` +
         `${pad(now.getMonth() + 1)}-` +
         `${pad(now.getDate())}`
}

function isCommitBreakingChange (commit) {
  return (typeof commit.footer === 'string' &&
    commit.footer.indexOf('BREAKING CHANGE') !== -1)
}
<commit_msg>fix(northbrook): end write stream after generation<commit_after>import { createWriteStream } from 'fs'
import { forEach, isFile, exec } from '../../util'

export function generateChangelog ({ commits, file, version, url, bugs, previousFile }) {
  const changelog = typeof file === 'string' ? createFileStream(file) : file
  return new Promise((resolve) => {
    const sections = {
      breaks: [], // special section to highlight breaking changes
      feat: [],
      fix: [],
      perf: []
    }

    const titles = {
      breaks: 'Breaking Changes',
      feat: 'Features',
      fix: 'Bug Fixes',
      perf: 'Performance Improvements'
    }

    changelog.write(`# ${version} (${currentDate()})\n---\n\n`)

    forEach(commits, function (commit) {
      if (isCommitBreakingChange(commit)) {
        sections.breaks.push(commit)
      } else {
        sections[commit.type] = sections[commit.type] || []
        sections[commit.type].push(commit)
      }
    })

    forEach(Object.keys(sections), function (section) {
      const sectionCommits = sections[section]
      const title = titles[section]

      if (!sectionCommits.length) return

      changelog.write(`\n## ${title}\n\n`)

      forEach(sectionCommits, function (commit) {
        changelog.write(`    - ${commit.header} ${linkToCommit(commit.hash, url)}`)
        changelog.write(`\n`)
      })
    })

    changelog.write('\n\n')
    changelog.write(previousFile)

    changelog.end()
    resolve(changelog)
  })
}

function createFileStream (file) {
  if (!isFile(file)) {
    exec(`touch ${file}`, { silent: true, async: false })
  }
  return createWriteStream(file)
}

function linkToCommit (hash, url) {
  return `[${hash.substr(0, 8)}](${url}/commits/${hash}\)`
}

function currentDate () {
  const now = new Date()
  const pad = function (i) {
    return ('0' + i).substr(-2)
  }
  return `${now.getFullYear()}-` +
         `${pad(now.getMonth() + 1)}-` +
         `${pad(now.getDate())}`
}

function isCommitBreakingChange (commit) {
  return (typeof commit.footer === 'string' &&
    commit.footer.indexOf('BREAKING CHANGE') !== -1)
}
<|endoftext|>


<commit_before>// Copyright 2014 Globo.com Player authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

var UIPlugin = require('../../base/ui_plugin');
var Styler = require('../../base/styler');
var JST = require('../../base/jst');
var _ = require("underscore");

var Visibility = require('visibility');

var HLSVideoPlaybackPlugin = UIPlugin.extend({
  name: 'hls_playback',
  tagName: 'object',
  template: JST.hls_playback,
  attributes: {
    'data-hls-playback': ''
  },
  initialize: function(options) {
    this.src = options.src;
    this.swfPath = options.swfPath || "assets/HLSPlayer.swf";
    this.autoPlay = options.autoPlay;
    this.visibility = new Visibility();
    this.visible = true;
    this.highDefinition = "unavailable"; // this will be changed on checkHighDefinition()
    this.settings = {
      left: ["playstop"],
      default: ["position", "seekbar", "duration"],
      right: ["fullscreen", "volume", "hd"]
    };
    this.checkIfFlashIsReady();
  },
  safe: function(fn) {
    if(this.el.globoGetState && this.el.globoGetDuration && this.el.globoGetPosition &&
       this.el.globoPlayerSmoothSetLevel && this.el.globoPlayerSetflushLiveURLCache && this.el.globoPlayerSetstartFromLowestLevel) {
      return fn.apply(this);
    }
  },
  hiddenCallback: function() {
    this.hiddenId = this.safe(function() {
      return setTimeout(function() { this.el.globoPlayerSmoothSetLevel(0) }.bind(this), 10000);
    });
  },
  visibleCallback: function() {
    this.safe(function() {
      if (this.hiddenId) {
        clearTimeout(this.hiddenId);
      }
      this.el.globoPlayerSmoothSetLevel(-1);
    });
  },
  bootstrap: function() {
    this.el.width = "100%";
    this.el.height = "100%";
    console.log('flash is ready');
    this.trigger('playback:ready', this.name);
    clearInterval(this.bootstrapId);
    this.currentState = "IDLE";
    this.timedCheckState();
    this.el.globoPlayerSetflushLiveURLCache(true);
    this.el.globoPlayerSetstartFromLowestLevel(true); // decreases startup time
    this.autoPlay && this.play();
  },
  checkIfFlashIsReady: function() {
    this.bootstrapId = setInterval(function() {
      if(this.el.globoGetState) {
        this.bootstrap();
      }
    }.bind(this), 50);
  },
  updateTime: function(interval) {
    return this.safe(function() {
      return setInterval(function() {
        this.safe(function() { this.trigger('playback:timeupdate', this.el.globoGetPosition(), this.el.globoGetDuration(), this.name); });
      }.bind(this), interval);
    });
  },
  play: function() {
    this.safe(function() {
      if(this.el.globoGetState() === 'IDLE') {
        clearInterval(this.checkStateId)
        this.checkTimeId = this.updateTime(1000);
      }
      if(this.el.globoGetState() === 'PAUSED') {
        this.el.globoPlayerResume();
      } else {
        this.firstPlay();
      }
      this.trigger('playback:play', this.name);
    });
  },
  getPlaybackType: function() {
    if (this.playbackType)
      return this.playbackType;
    return null;
  },
  getCurrentBitrate: function() {
    return this.safe(function() {
      var currentLevel = this.getLevels()[this.el.globoGetLevel()];
      return currentLevel.bitrate;
    });
  },
  getLastProgramDate: function() {
    var programDate = this.el.globoGetLastProgramDate();
    // normalizing for BRT
    return programDate - 1.08e+7;
  },
  isHighDefinitionAvailable: function(levels) {
    return !!(levels.length > 0 && levels[levels.length-1].bitrate >= 3500000);
  },
  isHighDefinitionInUse: function() {
    return this.highDefinition === "available-in-use";
  },
  checkHighDefinition: function() {
    this.safe(function() {
      // this function is responsible to change media control settings
      // regarding the availability of HD level and if it's being used or not.
      // highDefinition attribute have 3 states: "available", "available-in-use", "unavailable"
      var changed = false;
      this.levels = this.getLevels();
      if (this.isHighDefinitionAvailable(this.levels)) {
        var lastLevel = this.levels.length -1;
        var currentLevel = this.el.globoGetLevel();
        if (currentLevel === lastLevel && this.highDefinition !== "available-in-use") {
          this.highDefinition = "available-in-use";
          changed = true;
        } else if (currentLevel !== lastLevel && this.highDefinition === "available-in-use") {
          this.highDefinition = "available";
          changed = true;
        } else if (this.highDefinition === "unavailable") {
          this.highDefinition = "available";
          changed = true;
        }
      }
      if (changed) {
        this.trigger('playback:highdefinitionupdate');
      }
    });
  },
  getLevels: function() {
    return this.safe(function() {
      if (!this.levels || this.levels.length === 0) {
        this.levels = this.el.globoGetLevels();
      }
      return this.levels;
    });
  },
  timedCheckState: function() {
    this.checkStateId = setInterval(this.checkState.bind(this), 250);
    this.checkHighDefinitionId = setInterval(this.checkHighDefinition.bind(this), 3000);
  },
  checkState: function() {
    this.safe(function() {
      this.updatePlaybackType();
      this.updatePlayerVisibility();
      if (this.el.globoGetState() === "PLAYING_BUFFERING" && this.el.globoGetbufferLength() < 1 && this.currentState !== "PLAYING_BUFFERING") {
        this.trigger('playback:buffering', this.name);
        this.currentState = "PLAYING_BUFFERING";
      } else if (this.currentState === "PLAYING_BUFFERING" && this.el.globoGetState() === "PLAYING") {
        this.trigger('playback:bufferfull', this.name);
        this.currentState = "PLAYING";
      } else if (this.el.globoGetState() === "IDLE") {
        this.trigger('playback:ended', this.name);
        this.trigger('playback:timeupdate', 0, this.el.globoGetDuration(), this.name);
        clearInterval(this.checkStateId);
        this.currentState = "IDLE";
      }
    });
  },
  updatePlayerVisibility: function() {
    if (this.visible && this.visibility.hidden()) {
      this.visible = false;
      this.hiddenCallback();
    } else if (!this.visible && this.visibility.visible()) {
      this.visible = true;
      this.visibleCallback();
    }
  },
  updatePlaybackType: function() {
    this.safe(function() {
      if (!this.playbackType) {
        this.playbackType = this.el.globoGetType();
        if (this.playbackType) {
          this.playbackType = this.playbackType.toLowerCase();
          this.updateSettings();
        }
      }
    });
  },
  firstPlay: function() {
    this.safe(function() {
      this.el.globoPlayerLoad(this.src);
      this.el.globoPlayerPlay();
    });
  },
  volume: function(value) {
    this.safe(function() {
      this.el.globoPlayerVolume(value);
    });
  },
  pause: function() {
    this.safe(function() {
      this.el.globoPlayerPause();
    });
  },
  stop: function() {
    this.safe(function() {
      this.el.globoPlayerStop();
      clearInterval(this.checkStateId);
      this.trigger('playback:timeupdate', 0, this.name);
    })
  },
  isPlaying: function() {
    return this.safe(function() {
      if (this.el.playerGetState)
        return !!(this.el.playerGetState().match(/playing/i));
      return false;
    })
  },
  getDuration: function() {
    return this.safe(function() {
      return this.el.playerGetDuration();
    });
  },
  seek: function(time) {
    this.safe(function() {
      if (time < 0)
        this.el.globoPlayerSeek(time);
      else
        this.el.globoPlayerSeek(this.el.globoGetDuration() * time / 100);
      clearInterval(this.checkStateId);
      this.checkTimeId = this.updateTime(1000);
    });
  },
  timeUpdate: function(time, duration) {
    this.trigger('playback:timeupdate', time, duration, this.name);
  },
  destroy: function() {
    clearInterval(this.checkStateId);
    clearInterval(this.checkTimeId);
    clearInterval(this.checkHighDefinitionId);
    this.stopListening()
    this.$el.remove()
  },
  setupFirefox: function() {
    var $el = this.$('embed');
    $el.attr('data-hls-playback', '');
    this.setElement($el[0]);
  },
  updateSettings: function() {
    this.settings = {
      left: [(this.playbackType === "VOD" ? "playpause" : "playstop")],
      default: ["position", "seekbar", "duration"],
      right: ["fullscreen", "volume", "hd"]
    };
    this.trigger('playback:settingsupdate', this.name);
  },
  render: function() {
    var style = Styler.getStyleFor(this.name);
    this.$el.html(this.template({swfPath: this.swfPath}));
    this.$el.append(style);
    this.el.id = this.cid;
    if(navigator.userAgent.match(/firefox/i)) { //FIXME remove it from here
      this.setupFirefox();
    }
    return this;
  }
});

HLSVideoPlaybackPlugin.canPlay = function(resource) {
  return !!resource.match(/(.*).m3u8/);
}

module.exports = HLSVideoPlaybackPlugin;
<commit_msg>hls playback: setup IE :pray:<commit_after>// Copyright 2014 Globo.com Player authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

var UIPlugin = require('../../base/ui_plugin');
var Styler = require('../../base/styler');
var JST = require('../../base/jst');
var _ = require("underscore");

var Visibility = require('visibility');

var objectIE = '<object id="<%= cid %>" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" data-hls-playback=""><param name="movie" value="<%= swfPath %>"> <param name="quality" value="autohigh"> <param name="swliveconnect" value="true"> <param name="allowScriptAccess" value="always"> <param name="bgcolor" value="#001122"> <param name="allowFullScreen" value="false"> <param name="wmode" value="transparent"> <param name="tabindex" value="1"> </object>';

var HLSVideoPlaybackPlugin = UIPlugin.extend({
  name: 'hls_playback',
  tagName: 'object',
  template: JST.hls_playback,
  attributes: {
    'data-hls-playback': '',
  },
  initialize: function(options) {
    this.src = options.src;
    this.swfPath = options.swfPath || "assets/HLSPlayer.swf";
    this.autoPlay = options.autoPlay;
    this.visibility = new Visibility();
    this.visible = true;
    this.highDefinition = "unavailable"; // this will be changed on checkHighDefinition()
    this.settings = {
      left: ["playstop"],
      default: ["position", "seekbar", "duration"],
      right: ["fullscreen", "volume", "hd"]
    };
    this.checkIfFlashIsReady();
  },
  safe: function(fn) {
    if(this.el.globoGetState && this.el.globoGetDuration && this.el.globoGetPosition &&
       this.el.globoPlayerSmoothSetLevel && this.el.globoPlayerSetflushLiveURLCache && this.el.globoPlayerSetstartFromLowestLevel) {
      return fn.apply(this);
    }
  },
  hiddenCallback: function() {
    this.hiddenId = this.safe(function() {
      return setTimeout(function() { this.el.globoPlayerSmoothSetLevel(0) }.bind(this), 10000);
    });
  },
  visibleCallback: function() {
    this.safe(function() {
      if (this.hiddenId) {
        clearTimeout(this.hiddenId);
      }
      this.el.globoPlayerSmoothSetLevel(-1);
    });
  },
  bootstrap: function() {
    this.el.width = "100%";
    this.el.height = "100%";
    this.trigger('playback:ready', this.name);
    clearInterval(this.bootstrapId);
    this.currentState = "IDLE";
    this.timedCheckState();
    this.el.globoPlayerSetflushLiveURLCache(true);
    this.el.globoPlayerSetstartFromLowestLevel(true); // decreases startup time
    this.autoPlay && this.play();
  },
  checkIfFlashIsReady: function() {
    this.bootstrapId = setInterval(function() {
      if(this.el.globoGetState) {
        this.bootstrap();
      }
    }.bind(this), 50);
  },
  updateTime: function(interval) {
    return this.safe(function() {
      return setInterval(function() {
        this.safe(function() { this.trigger('playback:timeupdate', this.el.globoGetPosition(), this.el.globoGetDuration(), this.name); });
      }.bind(this), interval);
    });
  },
  play: function() {
    this.safe(function() {
      if(this.el.globoGetState() === 'IDLE') {
        clearInterval(this.checkStateId)
        this.checkTimeId = this.updateTime(1000);
      }
      if(this.el.globoGetState() === 'PAUSED') {
        this.el.globoPlayerResume();
      } else {
        this.firstPlay();
      }
      this.trigger('playback:play', this.name);
    });
  },
  getPlaybackType: function() {
    if (this.playbackType)
      return this.playbackType;
    return null;
  },
  getCurrentBitrate: function() {
    return this.safe(function() {
      var currentLevel = this.getLevels()[this.el.globoGetLevel()];
      return currentLevel.bitrate;
    });
  },
  getLastProgramDate: function() {
    var programDate = this.el.globoGetLastProgramDate();
    // normalizing for BRT
    return programDate - 1.08e+7;
  },
  isHighDefinitionAvailable: function(levels) {
    return !!(levels.length > 0 && levels[levels.length-1].bitrate >= 3500000);
  },
  isHighDefinitionInUse: function() {
    return this.highDefinition === "available-in-use";
  },
  checkHighDefinition: function() {
    this.safe(function() {
      // this function is responsible to change media control settings
      // regarding the availability of HD level and if it's being used or not.
      // highDefinition attribute have 3 states: "available", "available-in-use", "unavailable"
      var changed = false;
      this.levels = this.getLevels();
      if (this.isHighDefinitionAvailable(this.levels)) {
        var lastLevel = this.levels.length -1;
        var currentLevel = this.el.globoGetLevel();
        if (currentLevel === lastLevel && this.highDefinition !== "available-in-use") {
          this.highDefinition = "available-in-use";
          changed = true;
        } else if (currentLevel !== lastLevel && this.highDefinition === "available-in-use") {
          this.highDefinition = "available";
          changed = true;
        } else if (this.highDefinition === "unavailable") {
          this.highDefinition = "available";
          changed = true;
        }
      }
      if (changed) {
        this.trigger('playback:highdefinitionupdate');
      }
    });
  },
  getLevels: function() {
    return this.safe(function() {
      if (!this.levels || this.levels.length === 0) {
        this.levels = this.el.globoGetLevels();
      }
      return this.levels;
    });
  },
  timedCheckState: function() {
    this.checkStateId = setInterval(this.checkState.bind(this), 250);
    this.checkHighDefinitionId = setInterval(this.checkHighDefinition.bind(this), 3000);
  },
  checkState: function() {
    this.safe(function() {
      this.updatePlaybackType();
      this.updatePlayerVisibility();
      if (this.el.globoGetState() === "PLAYING_BUFFERING" && this.el.globoGetbufferLength() < 1 && this.currentState !== "PLAYING_BUFFERING") {
        this.trigger('playback:buffering', this.name);
        this.currentState = "PLAYING_BUFFERING";
      } else if (this.currentState === "PLAYING_BUFFERING" && this.el.globoGetState() === "PLAYING") {
        this.trigger('playback:bufferfull', this.name);
        this.currentState = "PLAYING";
      } else if (this.el.globoGetState() === "IDLE") {
        this.trigger('playback:ended', this.name);
        this.trigger('playback:timeupdate', 0, this.el.globoGetDuration(), this.name);
        clearInterval(this.checkStateId);
        this.currentState = "IDLE";
      }
    });
  },
  updatePlayerVisibility: function() {
    if (this.visible && this.visibility.hidden()) {
      this.visible = false;
      this.hiddenCallback();
    } else if (!this.visible && this.visibility.visible()) {
      this.visible = true;
      this.visibleCallback();
    }
  },
  updatePlaybackType: function() {
    this.safe(function() {
      if (!this.playbackType) {
        this.playbackType = this.el.globoGetType();
        if (this.playbackType) {
          this.playbackType = this.playbackType.toLowerCase();
          this.updateSettings();
        }
      }
    });
  },
  firstPlay: function() {
    this.safe(function() {
      this.el.globoPlayerLoad(this.src);
      this.el.globoPlayerPlay();
    });
  },
  volume: function(value) {
    this.safe(function() {
      this.el.globoPlayerVolume(value);
    });
  },
  pause: function() {
    this.safe(function() {
      this.el.globoPlayerPause();
    });
  },
  stop: function() {
    this.safe(function() {
      this.el.globoPlayerStop();
      clearInterval(this.checkStateId);
      this.trigger('playback:timeupdate', 0, this.name);
    })
  },
  isPlaying: function() {
    return this.safe(function() {
      if (this.el.playerGetState)
        return !!(this.el.playerGetState().match(/playing/i));
      return false;
    })
  },
  getDuration: function() {
    return this.safe(function() {
      return this.el.playerGetDuration();
    });
  },
  seek: function(time) {
    this.safe(function() {
      if (time < 0)
        this.el.globoPlayerSeek(time);
      else
        this.el.globoPlayerSeek(this.el.globoGetDuration() * time / 100);
      clearInterval(this.checkStateId);
      this.checkTimeId = this.updateTime(1000);
    });
  },
  timeUpdate: function(time, duration) {
    this.trigger('playback:timeupdate', time, duration, this.name);
  },
  destroy: function() {
    clearInterval(this.checkStateId);
    clearInterval(this.checkTimeId);
    clearInterval(this.checkHighDefinitionId);
    this.stopListening()
    this.$el.remove()
  },
  setupFirefox: function() {
    var $el = this.$('embed');
    $el.attr('data-hls-playback', '');
    this.setElement($el[0]);
  },
  setupIE: function() {
    this.setElement($(_.template(objectIE)({cid: this.cid, swfPath: this.swfPath})));
  },
  updateSettings: function() {
    this.settings = {
      left: [(this.playbackType === "VOD" ? "playpause" : "playstop")],
      default: ["position", "seekbar", "duration"],
      right: ["fullscreen", "volume", "hd"]
    };
    this.trigger('playback:settingsupdate', this.name);
  },
  render: function() {
    var style = Styler.getStyleFor(this.name);
    this.$el.html(this.template({swfPath: this.swfPath}));
    this.$el.append(style);
    this.el.id = this.cid;
    if(navigator.userAgent.match(/firefox/i)) { //FIXME remove it from here
      this.setupFirefox();
    } else if(window.ActiveXObject) {
      this.setupIE();
    }
    return this;
  }
});

HLSVideoPlaybackPlugin.canPlay = function(resource) {
  return !!resource.match(/(.*).m3u8/);
}

module.exports = HLSVideoPlaybackPlugin;
<|endoftext|>


<commit_before>angular.module("omniControllers")
  .controller("ExchangeBuyController",["$scope", "$http", "Transaction", "ADDRESS_EXPLORER_URL",
    function ExchangeBuyController($scope, $http, Transaction, ADDRESS_EXPLORER_URL) {
        $scope.editTransactionCost = function(){
          $scope.modalManager.openTransactionCostModal($scope, $scope.confirm);
        }
      $scope.selectedAddress= $scope.hasBitcoins ? $scope.wallet.getAsset(0).tradableAddresses[0] : undefined;
      $scope.setAddress = function(address){
            $scope.selectedAddress = address;
      }
      var transaction = $scope.global['buyOffer'];
      $scope.buySaleID = transaction.tx_hash;
      $http.get('/v1/transaction/tx/' + transaction.tx_hash + '.json').success(function(data) {
        var tx = data[0];
        $scope.selectedCoin=tx.currency_str;
        $scope.bitcoinAddresses = $scope.hasBitcoins ? $scope.wallet.getAsset(0).tradableAddresses : [];
        if(parseInt(tx.currencyId) <3) {
          $scope.divisible = true;
          $scope.sendPlaceholderValue = '1.00000000';
          $scope.sendPlaceholderStep = $scope.sendPlaceholderMin = '0.00000001';
          $scope.displayedAbbreviation = tx.currency_str;
        } else {
          $http.get("/v1/property/"+tx.currencyId.replace(new RegExp("^0+"), "") +".json", function(data) {
            var property = data[0];
            if(property.propertyType == "0001"){
              $scope.divisible =false;
              $scope.sendPlaceholderValue = $scope.sendPlaceholderStep = $scope.sendPlaceholderMin = '1';
            } else  {
              $scope.divisible = true;
              $scope.sendPlaceholderValue = '1.00000000';
              $scope.sendPlaceholderStep = $scope.sendPlaceholderMin = '0.00000001';
            }

            $scope.displayedAbbreviation = property.propertyName + " #" + property.currencyId;
          });
        }
      });
      // [ Buy Form Helpers ]

      $scope.confirm = function(){
        //TODO: VALIDATIONS
        var fee = new Big($scope.minersFee);
        var exchangeAccept = new Transaction(22,$scope.selectedAddress,fee,{
            amount: +new Big($scope.buyAmount).times(SATOSHI_UNIT).valueOf(),
            tx_hash: $scope.buySaleID,
            donate: $scope.account.getSetting("donate")
          });

        $scope.modalManager.openConfirmationModal({
          dataTemplate: '/views/modals/partials/accept.html',
          scope:{
            title:"EXCHANGE.BUY.MODALTITLE",
            displayedAbbreviation: $scope.displayedAbbreviation,
            buyAmount: $scope.buyAmount,
            minerFees: $scope.minersFee,
            selectedCoin: $scope.selectedCoin,
            insufficientBitcoin : $scope.insufficientBitcoin,
            fees : $scope.minersFee,
            totalCost : exchangeAccept.totalCost.valueOf(),
            selectedAddress : $scope.selectedAddress,
            sellerAddress: transaction.from_address,
            offerHash:transaction.tx_hash,
            salePricePerCoin:transaction.formatted_price_per_coin,
            saleBlocks:transaction.formatted_block_time_limit,
            confirmText:"EXCHANGE.BUY.CONFIRM",
            explorerUrl:ADDRESS_EXPLORER_URL,
            successRedirect:"/exchange/trade"
          },
          transaction:exchangeAccept
        })
      }

      // $scope.validateBuyForm = function() {
      //   var dustValue = 5757;
      //   var minerMinimum = 10000;
      //   var nonZeroValue = 1;
      //   var divisible = $scope.divisible;

      //   var convertToSatoshi = [
      //       $scope.minerFees,
      //       $scope.buyAmount,
      //       $scope.balanceData[0],
      //       $scope.balanceData[1]
      //     ];

      //   if (!divisible) {
      //     delete convertToSatoshi[ convertToSatoshi.indexOf( $scope.buyAmount ) ];
      //     delete convertToSatoshi[ convertToSatoshi.indexOf( $scope.balanceData[0] ) ];
      //   }

      //   var convertedValues = $scope.convertDisplayedValue( convertToSatoshi );

      //   var minerFees = +convertedValues[0];
      //   var buyAmount = divisible ? +convertedValues[1] : +$scope.buyAmount;

      //   var balance = divisible ? +convertedValues[2] : +$scope.balanceData[0];
      //   var btcbalance = +convertedValues[3];

      //   var coin = $scope.selectedCoin;
      //   var address = $scope.selectedAddress;
      //   var saleHash = $scope.buySaleID;

      //   var totalBtcCost = parseFloat($scope.convertDisplayedValue(transaction.formatted_price_per_coin * $scope.convertSatoshiToDisplayedValue(buyAmount)));
      //   var totalFeeCost = parseFloat($scope.convertDisplayedValue($scope.totalCost));
      //   var insufficientBitcoin = false;

      //   var required = [coin, address, buyAmount, minerFees, balance, btcbalance, $scope.buyForm.$valid];
      //   console.log(required);
      //   var error = 'Please ';
      //   if ($scope.buyForm.$valid == false) {
      //     error += 'make sure all fields are completely filled, ';
      //   }
      //   //should be valid hash
      //   //if( walletTransactionService.validAddress(sendTo) == false) {
      //   //   error += 'make sure you are sending to a valid MSC/BTC address, '
      //   //}
      //   if (coin == 'Bitcoin') {
      //     error += 'make sure your sale is for MSC or TMSC, ';
      //   }
      //   if( ((coin == 'Mastercoin') || (coin == 'Test Mastercoin')) ) {
      //     if (buyAmount < nonZeroValue)
      //       error += 'make sure your send amount is non-zero, ';
      //     if (minerFees < minerMinimum)
      //       error += 'make sure your fee entry is at least 0.0001 BTC, ';
      //     if ((totalFeeCost <= btcbalance) == false)
      //       error += 'make sure you have enough Bitcoin to cover your fees, ';
      //     if ((totalBtcCost+totalFeeCost <= btcbalance) == false) {
      //       insufficientBitcoin = true;
      //     }
      //   }
      //   if (error.length < 8) {
      //     $scope.$parent.showErrors = false;

      //     // open modal
      //     var modalInstance = $modal.open({
      //       templateUrl: '/partials/wallet_buy_modal.html',
      //       controller: function($scope, $modalInstance, $rootScope, data, prepareBuyTransaction, getUnsignedBuyTransaction, convertSatoshiToDisplayedValue) {
      //         $scope.sendSuccess = false, $scope.sendError = false, $scope.waiting = false, $scope.privKeyPass = {};
      //         $scope.convertSatoshiToDisplayedValue=convertSatoshiToDisplayedValue,
      //         $scope.displayedAbbreviation=data.displayedAbbreviation,
      //         $scope.buyAmount=data.amt,
      //         $scope.minerFees= data.fee,
      //         $scope.selectedCoin= data.selectedCoin;
      //         $scope.insufficientBitcoin = data.insufficientBitcoin

      //         $scope.ok = function() {
      //           $scope.clicked = true;
      //           $scope.waiting = true;
      //           prepareBuyTransaction(data.buyer, data.amt, data.hash, data.fee, $scope.privKeyPass, $scope);
      //         };
      //         $scope.cancel = function () {
      //           $modalInstance.dismiss('cancel');
      //         };
      //       },
      //       resolve: {
      //         data: function() {
      //           return {
      //             buyer: address,
      //             amt: buyAmount,
      //             hash: saleHash,
      //             fee: minerFees,
      //             selectedCoin: $scope.selectedCoin,
      //             displayedAbbreviation: $scope.displayedAbbreviation,
      //             insufficientBitcoin: insufficientBitcoin
      //           };
      //         },
      //         prepareBuyTransaction: function() {
      //           return prepareBuyTransaction;
      //         },
      //         getUnsignedBuyTransaction: function() {
      //           return getUnsignedBuyTransaction;
      //         },
      //         pushSignedTransaction: function() {
      //           return walletTransactionService.pushSignedTransaction;
      //         },
      //         convertSatoshiToDisplayedValue: function() {
      //           return $scope.convertSatoshiToDisplayedValue;
      //         }
      //       }
      //     });
      //   } else {
      //     error += 'and try again.';
      //     $scope.error = error;
      //     $scope.$parent.showErrors = true;
      //   }
      // };

    }])<commit_msg>Add missing injection dependency<commit_after>angular.module("omniControllers")
  .controller("ExchangeBuyController",["$scope", "$http", "Transaction", "ADDRESS_EXPLORER_URL", "SATOSHI_UNIT",
    function ExchangeBuyController($scope, $http, Transaction, ADDRESS_EXPLORER_URL, SATOSHI_UNIT) {
        $scope.editTransactionCost = function(){
          $scope.modalManager.openTransactionCostModal($scope, $scope.confirm);
        }
      $scope.selectedAddress= $scope.hasBitcoins ? $scope.wallet.getAsset(0).tradableAddresses[0] : undefined;
      $scope.setAddress = function(address){
            $scope.selectedAddress = address;
      }
      var transaction = $scope.global['buyOffer'];
      $scope.buySaleID = transaction.tx_hash;
      $http.get('/v1/transaction/tx/' + transaction.tx_hash + '.json').success(function(data) {
        var tx = data[0];
        $scope.selectedCoin=tx.currency_str;
        $scope.bitcoinAddresses = $scope.hasBitcoins ? $scope.wallet.getAsset(0).tradableAddresses : [];
        if(parseInt(tx.currencyId) <3) {
          $scope.divisible = true;
          $scope.sendPlaceholderValue = '1.00000000';
          $scope.sendPlaceholderStep = $scope.sendPlaceholderMin = '0.00000001';
          $scope.displayedAbbreviation = tx.currency_str;
        } else {
          $http.get("/v1/property/"+tx.currencyId.replace(new RegExp("^0+"), "") +".json", function(data) {
            var property = data[0];
            if(property.propertyType == "0001"){
              $scope.divisible =false;
              $scope.sendPlaceholderValue = $scope.sendPlaceholderStep = $scope.sendPlaceholderMin = '1';
            } else  {
              $scope.divisible = true;
              $scope.sendPlaceholderValue = '1.00000000';
              $scope.sendPlaceholderStep = $scope.sendPlaceholderMin = '0.00000001';
            }

            $scope.displayedAbbreviation = property.propertyName + " #" + property.currencyId;
          });
        }
      });
      // [ Buy Form Helpers ]

      $scope.confirm = function(){
        //TODO: VALIDATIONS
        var fee = new Big($scope.minersFee);
        var exchangeAccept = new Transaction(22,$scope.selectedAddress,fee,{
            amount: +new Big($scope.buyAmount).times(SATOSHI_UNIT).valueOf(),
            tx_hash: $scope.buySaleID,
            donate: $scope.account.getSetting("donate")
          });

        $scope.modalManager.openConfirmationModal({
          dataTemplate: '/views/modals/partials/accept.html',
          scope:{
            title:"EXCHANGE.BUY.MODALTITLE",
            displayedAbbreviation: $scope.displayedAbbreviation,
            buyAmount: $scope.buyAmount,
            minerFees: $scope.minersFee,
            selectedCoin: $scope.selectedCoin,
            insufficientBitcoin : $scope.insufficientBitcoin,
            fees : $scope.minersFee,
            totalCost : exchangeAccept.totalCost.valueOf(),
            selectedAddress : $scope.selectedAddress,
            sellerAddress: transaction.from_address,
            offerHash:transaction.tx_hash,
            salePricePerCoin:transaction.formatted_price_per_coin,
            saleBlocks:transaction.formatted_block_time_limit,
            confirmText:"EXCHANGE.BUY.CONFIRM",
            explorerUrl:ADDRESS_EXPLORER_URL,
            successRedirect:"/exchange/trade"
          },
          transaction:exchangeAccept
        })
      }

      // $scope.validateBuyForm = function() {
      //   var dustValue = 5757;
      //   var minerMinimum = 10000;
      //   var nonZeroValue = 1;
      //   var divisible = $scope.divisible;

      //   var convertToSatoshi = [
      //       $scope.minerFees,
      //       $scope.buyAmount,
      //       $scope.balanceData[0],
      //       $scope.balanceData[1]
      //     ];

      //   if (!divisible) {
      //     delete convertToSatoshi[ convertToSatoshi.indexOf( $scope.buyAmount ) ];
      //     delete convertToSatoshi[ convertToSatoshi.indexOf( $scope.balanceData[0] ) ];
      //   }

      //   var convertedValues = $scope.convertDisplayedValue( convertToSatoshi );

      //   var minerFees = +convertedValues[0];
      //   var buyAmount = divisible ? +convertedValues[1] : +$scope.buyAmount;

      //   var balance = divisible ? +convertedValues[2] : +$scope.balanceData[0];
      //   var btcbalance = +convertedValues[3];

      //   var coin = $scope.selectedCoin;
      //   var address = $scope.selectedAddress;
      //   var saleHash = $scope.buySaleID;

      //   var totalBtcCost = parseFloat($scope.convertDisplayedValue(transaction.formatted_price_per_coin * $scope.convertSatoshiToDisplayedValue(buyAmount)));
      //   var totalFeeCost = parseFloat($scope.convertDisplayedValue($scope.totalCost));
      //   var insufficientBitcoin = false;

      //   var required = [coin, address, buyAmount, minerFees, balance, btcbalance, $scope.buyForm.$valid];
      //   console.log(required);
      //   var error = 'Please ';
      //   if ($scope.buyForm.$valid == false) {
      //     error += 'make sure all fields are completely filled, ';
      //   }
      //   //should be valid hash
      //   //if( walletTransactionService.validAddress(sendTo) == false) {
      //   //   error += 'make sure you are sending to a valid MSC/BTC address, '
      //   //}
      //   if (coin == 'Bitcoin') {
      //     error += 'make sure your sale is for MSC or TMSC, ';
      //   }
      //   if( ((coin == 'Mastercoin') || (coin == 'Test Mastercoin')) ) {
      //     if (buyAmount < nonZeroValue)
      //       error += 'make sure your send amount is non-zero, ';
      //     if (minerFees < minerMinimum)
      //       error += 'make sure your fee entry is at least 0.0001 BTC, ';
      //     if ((totalFeeCost <= btcbalance) == false)
      //       error += 'make sure you have enough Bitcoin to cover your fees, ';
      //     if ((totalBtcCost+totalFeeCost <= btcbalance) == false) {
      //       insufficientBitcoin = true;
      //     }
      //   }
      //   if (error.length < 8) {
      //     $scope.$parent.showErrors = false;

      //     // open modal
      //     var modalInstance = $modal.open({
      //       templateUrl: '/partials/wallet_buy_modal.html',
      //       controller: function($scope, $modalInstance, $rootScope, data, prepareBuyTransaction, getUnsignedBuyTransaction, convertSatoshiToDisplayedValue) {
      //         $scope.sendSuccess = false, $scope.sendError = false, $scope.waiting = false, $scope.privKeyPass = {};
      //         $scope.convertSatoshiToDisplayedValue=convertSatoshiToDisplayedValue,
      //         $scope.displayedAbbreviation=data.displayedAbbreviation,
      //         $scope.buyAmount=data.amt,
      //         $scope.minerFees= data.fee,
      //         $scope.selectedCoin= data.selectedCoin;
      //         $scope.insufficientBitcoin = data.insufficientBitcoin

      //         $scope.ok = function() {
      //           $scope.clicked = true;
      //           $scope.waiting = true;
      //           prepareBuyTransaction(data.buyer, data.amt, data.hash, data.fee, $scope.privKeyPass, $scope);
      //         };
      //         $scope.cancel = function () {
      //           $modalInstance.dismiss('cancel');
      //         };
      //       },
      //       resolve: {
      //         data: function() {
      //           return {
      //             buyer: address,
      //             amt: buyAmount,
      //             hash: saleHash,
      //             fee: minerFees,
      //             selectedCoin: $scope.selectedCoin,
      //             displayedAbbreviation: $scope.displayedAbbreviation,
      //             insufficientBitcoin: insufficientBitcoin
      //           };
      //         },
      //         prepareBuyTransaction: function() {
      //           return prepareBuyTransaction;
      //         },
      //         getUnsignedBuyTransaction: function() {
      //           return getUnsignedBuyTransaction;
      //         },
      //         pushSignedTransaction: function() {
      //           return walletTransactionService.pushSignedTransaction;
      //         },
      //         convertSatoshiToDisplayedValue: function() {
      //           return $scope.convertSatoshiToDisplayedValue;
      //         }
      //       }
      //     });
      //   } else {
      //     error += 'and try again.';
      //     $scope.error = error;
      //     $scope.$parent.showErrors = true;
      //   }
      // };

    }])<|endoftext|>


<commit_before>angular.module('mrlapp.service.cligui', [])
        .controller('CLIGuiCtrl', ['$scope', '$log', 'mrl', function ($scope, $log, mrl) {
                var _self = this;
                $log.info('CLIGuiCtrl');

                this.init = function () {
                    // get fresh copy
                    var service = mrl.getService($scope.data.service.name);

                    this.onMsg = function (msg) {
                        switch (msg.method) {
                            case 'onStdout':
                                $scope.data.cli = $scope.data.cli + '\n' + msg.data[0];
                                $scope.$apply();
                                break;
                            case 'onClockStarted':
                                $scope.data.label = "Stop";
                                $scope.$apply();
                                break;
                            case 'onClockStopped':
                                $scope.data.label = "Start";
                                $scope.$apply();
                                break;
                            default:
                                $log.error("ERROR - unhandled method " + msg.method);
                                break;
                        }
                    }
                    ;

                    //$scope.myStyle = ".boxsizingBorder {-webkit-box-sizing: border-box;-moz-box-sizing: border-box;box-sizing: border-box;}";
                    // $scope.myStyle = "{'background-color':'black';}";

                    var buffer = "";

                    $scope.data.keyPress = function (event) {
                        var keyCode = event.keyCode;
                        var c = String.fromCharCode((96 <= keyCode && keyCode <= 105) ? keyCode - 48 : keyCode);
                        $log.info('keyPress ', keyCode);
                        if (keyCode == 13) {
                            this.send('process', buffer);
                            buffer = '';
                            return;
                        }
                        buffer = buffer + String.fromCharCode(keyCode);
                    };

                    this.subscribe('stdout');
                };

                $scope.cb.notifycontrollerisready(this);
            }
        ]);
<commit_msg>WebUI - optimization for cligui<commit_after>angular.module('mrlapp.service.cligui', [])
        .controller('CLIGuiCtrl', ['$scope', '$log', 'mrl', function ($scope, $log, mrl) {
                var _self = this;
                $log.info('CLIGuiCtrl');

                this.init = function () {
                    // get fresh copy
                    var service = this.getService();

                    this.onMsg = function (msg) {
                        switch (msg.method) {
                            case 'onStdout':
                                $scope.data.cli = $scope.data.cli + '\n' + msg.data[0];
                                $scope.$apply();
                                break;
                            case 'onClockStarted':
                                $scope.data.label = "Stop";
                                $scope.$apply();
                                break;
                            case 'onClockStopped':
                                $scope.data.label = "Start";
                                $scope.$apply();
                                break;
                            default:
                                $log.error("ERROR - unhandled method " + msg.method);
                                break;
                        }
                    }
                    ;

                    //$scope.myStyle = ".boxsizingBorder {-webkit-box-sizing: border-box;-moz-box-sizing: border-box;box-sizing: border-box;}";
                    // $scope.myStyle = "{'background-color':'black';}";

                    var buffer = "";

                    $scope.data.keyPress = function (event) {
                        var keyCode = event.keyCode;
                        var c = String.fromCharCode((96 <= keyCode && keyCode <= 105) ? keyCode - 48 : keyCode);
                        $log.info('keyPress ', keyCode);
                        if (keyCode == 13) {
                            this.send('process', buffer);
                            buffer = '';
                            return;
                        }
                        buffer = buffer + String.fromCharCode(keyCode);
                    };

                    this.subscribe('stdout');
                };

                $scope.cb.notifycontrollerisready(this);
            }
        ]);
<|endoftext|>


<commit_before>import React from 'react'

import RandomText from '../../../components/RandomText'
import View from '../../../components/ViewWrapper'
import classes from '../AboutView.scss'

const p = React.PropTypes

const titleAnimationDuration = 2000
const paragraphs = [
  `I'm just a giant nerd who's constantly in awe of technology. I love the
  tangibility and craftsmanship of working on the web, so I'm looking for my
  first apprenticeship or junior position in web tech.`,

  `My programming skills center around JavaScript, and I'm comfortable with
  everything from fundamentals to tools like Node and MongoDB. And of course,
  CSS and HTML come with that. Most of my work is in the MERN stack, though I've
  also dabbled in Python and Java in academic contexts, and I'm planning to pick
  up Ruby next. I'm always happy to adopt a new tool because at least half the
  reason I do web dev is because I get an inordinate amount of joy out of having
  a shiny new technology to play with.`,

  `When I'm not sitting in front of a screen I sink most of my time into
  generalist nerdery, becoming a less awful pianist/baritone/cellist, tutoring
  STEM topics, or getting very - often tragically - ambitious with an oven.`
]

export default class AboutView extends React.Component {

  static propTypes = {
    curBreakpoint: p.oneOfType([p.number, p.object]).isRequired
  }

  constructor () {
    super()
    this.state = {
      // Make an array w/ length paragraphs filled w/ false
      showParagraphs: paragraphs.map(() => false)
    }

    this.timeouts = []
    this.sizesByBreakpoint = {
      0: {
        width: 250,
        fontHeight: 40
      },
      1: {
        width: 300,
        fontHeight: 50
      },
      2: {
        width: 400,
        fontHeight: 60
      },
      3: {
        width: 400,
        fontHeight: 60
      },
      4: {
        width: 400,
        fontHeight: 60
      },
      5: {
        width: 430,
        fontHeight: 65
      }
    }
  }

  componentDidMount () {
    // Cascade showParagraphs to true in 500ms delays after title animation
    this.state.showParagraphs.forEach((paragraph, i) => {
      this.timeouts.push(setTimeout(() => {
        const showParagraphs = this.state.showParagraphs
        showParagraphs[i] = true
        this.setState({showParagraphs})
      }, titleAnimationDuration + 500 + i * 500))
    })
  }

  componentWillUnmount () {
    this.timeouts.forEach(timeoutId => clearTimeout(timeoutId))
  }

  render () {
    const titleSizes = this.sizesByBreakpoint[this.props.curBreakpoint]
    return (
      <View className={classes.container}>

          <RandomText
            text='About Me'
            className={classes.title}
            width={titleSizes.width}
            fontHeight={titleSizes.fontHeight}
            animationSpeed={1200}
            animationRandomness={.3}
            animationDuration={titleAnimationDuration}
            animate='in' />

          {paragraphs.map((text, i) => (

              {paragraphs[i]}

          ))}

      </View>
    )
  }
}
<commit_msg>Update about<commit_after>import React from 'react'

import RandomText from '../../../components/RandomText'
import View from '../../../components/ViewWrapper'
import classes from '../AboutView.scss'

const p = React.PropTypes

const titleAnimationDuration = 2000
const paragraphs = [
  `I'm a giant nerd currently working in software dev for Gaslight and ComputerEase in Cincinnati.',

  `My programming skills center around JavaScript, and I'm comfortable with
  everything from fundamentals to tools like Node and MongoDB. And of course,
  CSS and HTML come with that. Most of my work is in the MERN stack, though I've
  also dabbled in Python and Java in academic contexts, and I'm planning to pick
  up Ruby next. I'm always happy to adopt a new tool because at least half the
  reason I do web dev is because I get an inordinate amount of joy out of having
  a shiny new technology to play with.`,

  `When I'm not sitting in front of a screen I sink most of my time into
  general nerdery around computers and philosophy, practicing cello/piano/singing, tutoring
  STEM topics, or getting overly ambitious in the kitchen.`
]

export default class AboutView extends React.Component {

  static propTypes = {
    curBreakpoint: p.oneOfType([p.number, p.object]).isRequired
  }

  constructor () {
    super()
    this.state = {
      // Make an array w/ length paragraphs filled w/ false
      showParagraphs: paragraphs.map(() => false)
    }

    this.timeouts = []
    this.sizesByBreakpoint = {
      0: {
        width: 250,
        fontHeight: 40
      },
      1: {
        width: 300,
        fontHeight: 50
      },
      2: {
        width: 400,
        fontHeight: 60
      },
      3: {
        width: 400,
        fontHeight: 60
      },
      4: {
        width: 400,
        fontHeight: 60
      },
      5: {
        width: 430,
        fontHeight: 65
      }
    }
  }

  componentDidMount () {
    // Cascade showParagraphs to true in 500ms delays after title animation
    this.state.showParagraphs.forEach((paragraph, i) => {
      this.timeouts.push(setTimeout(() => {
        const showParagraphs = this.state.showParagraphs
        showParagraphs[i] = true
        this.setState({showParagraphs})
      }, titleAnimationDuration + 500 + i * 500))
    })
  }

  componentWillUnmount () {
    this.timeouts.forEach(timeoutId => clearTimeout(timeoutId))
  }

  render () {
    const titleSizes = this.sizesByBreakpoint[this.props.curBreakpoint]
    return (
      <View className={classes.container}>

          <RandomText
            text='About Me'
            className={classes.title}
            width={titleSizes.width}
            fontHeight={titleSizes.fontHeight}
            animationSpeed={1200}
            animationRandomness={.3}
            animationDuration={titleAnimationDuration}
            animate='in' />

          {paragraphs.map((text, i) => (

              {paragraphs[i]}

          ))}

      </View>
    )
  }
}
<|endoftext|>