<commit_before>/**
 * ISARI HCERES Export Routine
 * ============================
 */
const async = require('async'),
      moment = require('moment'),
      mongoose = require('mongoose'),
      _ = require('lodash');

const debug = require('debug')('isari:export');

const ObjectId = mongoose.Types.ObjectId;

const {
  getSimpleEnumValues,
  getNestedEnumValues} = require('../lib/enums');

const NATIONALITIES = getSimpleEnumValues('nationalities')

const hceres2017enums = {};
getSimpleEnumValues('hceres2017').forEach(e => {
  hceres2017enums[e.value] = e.label.fr;
});

const {
  createWorkbook,
  createSheet,
  addSheetToWorkbook,
  parseDate,
  fillIncompleteDate,
  overlap
} = require('./helpers.js');

//const GRADES_INDEX = require('../../specs/export/grades.json');
const GRADES_INDEX = require('../../specs/export/grades2gradesHCERES.json');

const GENDER_MAP = {
  m: 'H',
  f: 'F',
  o: ''
};

/**
 * Constants.
 */
const FILENAME = 'faculté_permanente.xlsx';

/**
 * Helpers.
 */
function findRelevantItem(collection) {
  const relevants = collection.filter(item => {
    return (
      (!item.startDate && !item.endDate) ||
      (!item.endDate && parseDate(item.startDate).isSameOrBefore(HCERES_DATE)) ||
      (
        parseDate(item.endDate).isSameOrAfter(HCERES_DATE) &&
        parseDate(item.startDate).isSameOrBefore(HCERES_DATE)
      )
    );
  });
  return _(relevants)
  .sortBy(['endDate', 'startDate'])
  .value()
  .reverse()[0];
}

function formatDate(date) {
  if (date) {
    const [year, month, day] = date.split('-');
    if (day)
      return moment(date).format('DD/MM/YYYY');
    else if (month)
      return `${year}/${month}`;
    else
      return year;
  }
  else
    return '';
}

/**
 * Sheets definitions.
 */
const SHEETS = [
  {
    id: 'staff',
    name: 'faculté permanente',
    headers: [

      {key: 'name', label: 'Nom'},
      {key: 'firstName', label: 'Prénom'},
      {key: 'birthDate', label: 'Date de naissance'},
      {key: 'gender', label: 'Genre'},
      {key: 'nationalities', label: 'Nationalité.s'},
      {key: 'emails', label: 'Email.s'},
      {key: 'lab1', label: 'Laboratoire de rattachement actuel 1'},
      {key: 'lab2', label: 'Laboratoire de rattachement actuel 2'},
      {key: 'dept1', label: 'Département de rattachement actuel 1'},
      {key: 'dept2', label: 'Département de rattachement actuel 2'},
      {key: 'status', label: 'Statut actuel'},
      {key: 'grade', label: 'Grade actuel'},
      {key: 'tutelle', label: 'Tutelle'},
      {key: 'startDate', label: 'Date de début'},
      {key: 'endDate', label: 'Date de fin'},
    ],
    populate(models, centerId, range, callback) {
      const People = models.People;
      let facultyMember = []

      let [start, end] = ['0000','9999'];

      if (range.length === 1){
        start = range[0];
        end = range[0];
      }
      if (range.length === 2){
        start = range[0];
        end = range[1];
      }

      start = fillIncompleteDate(start, true);
      end = fillIncompleteDate(end, false);

      async.waterfall([
        next => {
          // org filter
          let orgFilter = false;
          if (centerId){
            orgFilter = {organization: ObjectId(centerId)};
            next(null,orgFilter)
          }
          else{
            const Organization = models.Organization;
            Organization.aggregate([
              {$match:{isariMonitored:true}},
              {$project:{_id:1}}
            ]).then( orgs =>{
                orgFilter = {organization:{$in:orgs.map(o => o._id)}};
                next(null,orgFilter);
            }
            )
          }
        },
        (orgFilter,next) => {
          People.find({
            $and:[
              {academicMemberships: {
                $elemMatch:{
                  $and:[
                    orgFilter,
                    {$or: [
                        {endDate:{$gte: start}},
                        {endDate:{$exists: false }}
                    ]},
                    {$or: [
                        {startDate:{$lte: end}},
                        {startDate:{$exists: false }}
                    ]}
                  ]
                }
              }},
              {grades: {
                $elemMatch: {
                  $and:[
                    {gradeStatus: { $not:{$in: ['appuiadministratif','appuitechnique']} }},
                    {$or: [
                          {endDate:{$gte: start}},
                          {endDate:{$exists: false }}
                      ]},
                      {$or: [
                          {startDate:{$lte: end}},
                          {startDate:{$exists: false }}
                      ]}
                  ]
                }
              }}
            ]
          })
          .populate({
            path: 'positions.organization',
          })
          .populate({
            path: 'academicMemberships.organization',
          })
          .then(people => {
            //-- 2) Retrieving necessary data
            facultyMember = _(people).map(person => {

              const info = {
                name: person.name,
                firstName: person.firstName,
                gender: GENDER_MAP[person.gender],
              };

              if (person.birthDate) {
                info.birthDate = formatDate(person.birthDate);
              }

              if (person.nationalities && person.nationalities.length > 0) {
                info.nationalities = person.nationalities.map(n =>
                 NATIONALITIES.find(en => en.value === n).label.fr
                ).join(', ');
              }

              if (person.grades){
                  grade = _.sortBy(
                            person.grades.filter(p =>
                             overlap(p,[start,end])
                             && !['appuiadministratif','appuitechnique'].includes(p.gradeStatus)
                            ),
                            [p => p.endDate || p.startDate])
                            .reverse()[0]
                  if (grade){
                    if(grade.gradeStatus)
                      info.status = getSimpleEnumValues('gradeStatus').find(g => g.value === grade.gradeStatus).label.fr
                    if(grade.grade && grade.gradeStatus)
                      info.grade = getNestedEnumValues('grade')[grade.gradeStatus].find(g => g.value === grade.grade).label.fr

                  }
              }

              if (person.ORCID)
                info.orcid = person.ORCID;

              // if (person.positions) {
              //   if (person.positions.map(p => p.organization).find(t => t.acronym === 'CNRS')) {
              //     info.organization = 'CNRS';
              //     info.uai = '0753639Y';
              //   }
              //   else {
              //     info.organization = 'IEP Paris';
              //     info.uai = '0753431X';
              //   }
              // }

              // // date d'arrivé
              // info.startDate = formatDate(findRelevantItem(person.academicMemberships).startDate);

              // const grade = findRelevantItem(person.grades);

              // if (grade) {
              //   if (GRADES_INDEX[grade.gradeStatus] && GRADES_INDEX[grade.gradeStatus][grade.grade]) {
              //     info.jobType = GRADES_INDEX[grade.gradeStatus][grade.grade].type_emploiHCERES;
              //     info.grade = GRADES_INDEX[grade.gradeStatus][grade.grade].gradeHCERES;
              //   }
              //   else {
              //     // no grade DRH ?
              //     info.jobType = '?? ' + grade.gradeStatus;
              //     info.grade = '?? ' + grade.grade;
              //   }
              // }
              // else
              //   debug(`No grade found for ${person.name} ${person.firstName}`);

              // if (person.distinctions && person.distinctions.some(d => d.title === 'HDR'))
              //   info.hdr = 'OUI';

              return info;
            })
            // removing empty cases
            .compact()
            .value();
            // order by name
            facultyMember = _.sortBy(facultyMember, p => `${p.name} - ${p.firstName}`);

            next(null, facultyMember);
          });
      }], (err,p) =>{
        if (err) throw err;
        callback(null, p);
      } );

    }
  }
];

/**
 * Process.
 */
module.exports = function(models, centerId, range, callback) {
  const workbook = createWorkbook(FILENAME);

  // TODO: check existence of center before!
  async.eachSeries(SHEETS, (sheet, next) => {

    // Custom sheet
    if (sheet.custom)
      return sheet.custom(models, centerId, range, (err, sheetData) => {
        if (err)
          return next(err);

        for (const k in sheetData) {
          if (k !== '!ref')
            sheetData[k] = {
              v: sheetData[k],
              t: typeof sheetData[k] === 'number' ? 'n' : 's'
            };
        }

        addSheetToWorkbook(
          workbook,
          sheetData,
          sheet.name
        );

        return next();
      });

    // Classical sheet with headers
    return sheet.populate(models, centerId, range, (err, collection) => {
      if (err)
        return next(err);

      addSheetToWorkbook(
        workbook,
        createSheet(sheet.headers, collection),
        sheet.name
      );

      return next();
    });
  }, err => {
    if (err)
      return callback(err);

    return callback(null, workbook);
  });
};
<commit_msg>almost finished faculty export relates #359<commit_after>/**
 * ISARI HCERES Export Routine
 * ============================
 */
const async = require('async'),
      moment = require('moment'),
      mongoose = require('mongoose'),
      _ = require('lodash');

const debug = require('debug')('isari:export');

const ObjectId = mongoose.Types.ObjectId;

const {
  getSimpleEnumValues,
  getNestedEnumValues} = require('../lib/enums');

const NATIONALITIES = getSimpleEnumValues('nationalities')

const simpleEnumValue = (enumName, value) =>{
  const e = getSimpleEnumValues(enumName).find(e => e.value === value)
  return e ? e.label.fr : value
};

const {
  createWorkbook,
  createSheet,
  addSheetToWorkbook,
  parseDate,
  fillIncompleteDate,
  overlap
} = require('./helpers.js');

//const GRADES_INDEX = require('../../specs/export/grades.json');
const GRADES_INDEX = require('../../specs/export/grades2gradesHCERES.json');

const GENDER_MAP = {
  m: 'H',
  f: 'F',
  o: ''
};

/**
 * Constants.
 */
const FILENAME = 'faculté_permanente.xlsx';

/**
 * Helpers.
 */
function findAndSortRelevantItems(collection) {
  return _.sortBy(collection
             .filter(e => overlap(e,reportPeriod)),
           [e => e.endDate ? e.endDate : Infinity]
           ).reverse();
}

function formatDate(date) {
  if (date) {
    const [year, month, day] = date.split('-');
    if (day)
      return moment(date).format('DD/MM/YYYY');
    else if (month)
      return `${year}/${month}`;
    else
      return year;
  }
  else
    return '';
}

/**
 * Sheets definitions.
 */
const SHEETS = [
  {
    id: 'staff',
    name: 'faculté permanente',
    headers: [

      {key: 'name', label: 'Nom'},
      {key: 'firstName', label: 'Prénom'},
      {key: 'birthDate', label: 'Date de naissance'},
      {key: 'gender', label: 'Genre'},
      {key: 'nationalities', label: 'Nationalité.s'},
      {key: 'emails', label: 'Email.s'},
      {key: 'lab1', label: 'Laboratoire de rattachement 1 dernier connu sur la période'},
      {key: 'lab2', label: 'Laboratoire de rattachement 2 avant-dernier connu sur la période'},
      {key: 'dept1', label: 'Département de rattachement actuel 1'},
      {key: 'dept2', label: 'Département de rattachement actuel 2'},
      {key: 'status', label: 'Statut dernier connu sur la période'},
      {key: 'grade', label: 'Grade  dernier connu sur la période'},
      {key: 'tutelle', label: 'Tutelle dernière connue'},
      {key: 'startTutelle', label: 'Date de début dernière tutelle'},
      {key: 'endTutelle', label: 'Date de fin derière tutelle'},
      {key: 'startDate', label: 'Date d\'entrée'},
      {key: 'bonuses', label: 'Primes sur la période'},
      {key: 'facultyMonitoring', label: 'Suivi faculté permanente'},
      {key: 'facultyMonitoringDate', label: 'Suivi faculté permanente Date'},
      {key: 'facultyMonitoringComment', label: 'Suivi faculté permanente Commentaire'}
    ],
    populate(models, centerId, range, callback) {
      const People = models.People;
      let facultyMember = []

      let [start, end] = ['0000','9999'];

      if (range.length === 1){
        start = range[0];
        end = range[0];
      }
      if (range.length === 2){
        start = range[0];
        end = range[1];
      }

      start = fillIncompleteDate(start, true);
      end = fillIncompleteDate(end, false);
      const reportPeriod = {startDate:start, endDate:end}
      const findAndSortRelevantItems = (collection) => {
        return _.sortBy(collection
                   .filter(e => overlap(e,reportPeriod)),
                 [e => e.endDate ? e.endDate : Infinity]
                 ).reverse();
      };

      async.waterfall([
        next => {
          // org filter
          let orgFilter = false;
          if (centerId){
            orgFilter = {organization: ObjectId(centerId)};
            next(null,orgFilter)
          }
          else{
            const Organization = models.Organization;
            Organization.aggregate([
              {$match:{isariMonitored:true}},
              {$project:{_id:1}}
            ]).then( orgs =>{
                orgFilter = {organization:{$in:orgs.map(o => o._id)}};
                next(null,orgFilter);
            }
            )
          }
        },
        (orgFilter,next) => {
          People.find({
            $and:[
              {academicMemberships: {
                $elemMatch:{
                  $and:[
                    orgFilter,
                    {membershipType:{$in:['membre', 'rattaché']}},
                    {$or: [
                        {endDate:{$gte: start}},
                        {endDate:{$exists: false }}
                    ]},
                    {$or: [
                        {startDate:{$lte: end}},
                        {startDate:{$exists: false }}
                    ]}
                  ]
                }
              }},
              {grades: {
                $elemMatch: {
                  $and:[
                    {gradeStatus: { $not:{$in: ['appuiadministratif','appuitechnique']} }},
                    {$or: [
                          {endDate:{$gte: start}},
                          {endDate:{$exists: false }}
                      ]},
                      {$or: [
                          {startDate:{$lte: end}},
                          {startDate:{$exists: false }}
                      ]}
                  ]
                }
              }}
            ]
          })
          .populate({
            path: 'positions.organization',
          })
          .populate({
            path: 'academicMemberships.organization',
          })
          .then(people => {
            //-- 2) Retrieving necessary data
            facultyMember = _(people).map(person => {

              const info = {
                name: person.name,
                firstName: person.firstName,
                gender: GENDER_MAP[person.gender],
              };

              if (person.birthDate) {
                info.birthDate = formatDate(person.birthDate);
              }

              if (person.nationalities && person.nationalities.length > 0) {
                info.nationalities = person.nationalities.map(n =>
                 simpleEnumValue('nationalities',n)
                ).join(', ');
              }

              if (person.contacts && person.contacts.length>0)
              {
                info.emails = person.contacts.map(c => c.email).filter(e => e).join(', ');
              }

              const labos = findAndSortRelevantItems(person.academicMemberships);
              info.lab1 = labos.length > 0 ? labos[0].organization.acronym || labos[0].organization.name : '';
              info.lab2 = labos.length > 1 ? labos[1].organization.acronym || labos[1].organization.name : '';

              if (person.deptMemberships && person.deptMemberships.length>0){
                const departements = findAndSortRelevantItems(person.deptMemberships);
                info.dept1 = departements.length > 0 ? simpleEnumValue('teachingDepartements',departements[0].departement) : '';
                info.dept2 = departements.length > 1 ? simpleEnumValue('teachingDepartements',departements[1].departement)  : '';
              }

              if (person.positions && person.positions.length > 0){
                const positions = findAndSortRelevantItems(person.positions);
                if (positions && positions.length > 0 && positions[0].organization){
                  info.tutelle =  positions[0].organization.acronym || positions[0].organization.name;
                  info.startTutelle = positions[0].startDate;
                  info.endTutelle = positions[0].endDate;
                }
              }

              const startDates = person.academicMemberships
                  .filter(am => am.organization.isariMonitored)
                  .map(am => am.startDate)
                  .concat(person.positions
                    .filter(p => p.organization.acronym &&
                                 ['FNSP', 'CNRS', 'MESR'].includes(p.organization.acronym))
                    .map(p => p.startDate)
                  ).sort()
              if (startDates && startDates.length > 0)
                info.startDate = startDates[0]

              if (person.grades){
                  grade = findAndSortRelevantItems(person.grades).filter(p =>
                              !['appuiadministratif','appuitechnique'].includes(p.gradeStatus)
                            )[0]
                  if (grade){
                    if(grade.gradeStatus)
                      info.status = simpleEnumValue('gradeStatus', grade.gradeStatus)
                    if(grade.grade && grade.gradeStatus)
                      info.grade = getNestedEnumValues('grade')[grade.gradeStatus].find(g => g.value === grade.grade).label.fr

                  }
              }

              if (person.bonuses && person.bonuses.length > 0){
                info.bonuses = findAndSortRelevantItems(person.bonuses)
                  .map(b => {
                    const type = simpleEnumValue('bonusTypes',b.bonusType);
                    const startYear = b.startDate ? b.startDate.slice(0,4):'';
                    const endYear = b.endDate ? '-'+b.endDate.slice(0,4):'';
                    return `${type} ${startYear}${endYear}`
                  }).join(", ")
              }

              if (person.facultyMonitoring && person.facultyMonitoring.length > 0){
                const fms = findAndSortRelevantItems(person.facultyMonitoring);
                if (fms && fms.length > 0){
                  const fm = fms[0];
                  info.facultyMonitoring = simpleEnumValue('facultyMonitoringTypes', fm.facultyMonitoringType)
                  info.facultyMonitoringDate = fm.date ? fm.date : '';
                  info.facultyMonitoringComment = fm.comments ? fm.comments : '';
                }
              }

              if (person.ORCID)
                info.orcid = person.ORCID;

              // if (person.positions) {
              //   if (person.positions.map(p => p.organization).find(t => t.acronym === 'CNRS')) {
              //     info.organization = 'CNRS';
              //     info.uai = '0753639Y';
              //   }
              //   else {
              //     info.organization = 'IEP Paris';
              //     info.uai = '0753431X';
              //   }
              // }

              // // date d'arrivé
              // info.startDate = formatDate(findRelevantItem(person.academicMemberships).startDate);

              // const grade = findRelevantItem(person.grades);

              // if (grade) {
              //   if (GRADES_INDEX[grade.gradeStatus] && GRADES_INDEX[grade.gradeStatus][grade.grade]) {
              //     info.jobType = GRADES_INDEX[grade.gradeStatus][grade.grade].type_emploiHCERES;
              //     info.grade = GRADES_INDEX[grade.gradeStatus][grade.grade].gradeHCERES;
              //   }
              //   else {
              //     // no grade DRH ?
              //     info.jobType = '?? ' + grade.gradeStatus;
              //     info.grade = '?? ' + grade.grade;
              //   }
              // }
              // else
              //   debug(`No grade found for ${person.name} ${person.firstName}`);

              // if (person.distinctions && person.distinctions.some(d => d.title === 'HDR'))
              //   info.hdr = 'OUI';

              return info;
            })
            // removing empty cases
            .compact()
            .value();
            // order by name
            facultyMember = _.sortBy(facultyMember, p => `${p.name} - ${p.firstName}`);

            next(null, facultyMember);
          });
      }], (err,p) =>{
        if (err) throw err;
        callback(null, p);
      } );

    }
  }
];

/**
 * Process.
 */
module.exports = function(models, centerId, range, callback) {
  const workbook = createWorkbook(FILENAME);

  // TODO: check existence of center before!
  async.eachSeries(SHEETS, (sheet, next) => {

    // Custom sheet
    if (sheet.custom)
      return sheet.custom(models, centerId, range, (err, sheetData) => {
        if (err)
          return next(err);

        for (const k in sheetData) {
          if (k !== '!ref')
            sheetData[k] = {
              v: sheetData[k],
              t: typeof sheetData[k] === 'number' ? 'n' : 's'
            };
        }

        addSheetToWorkbook(
          workbook,
          sheetData,
          sheet.name
        );

        return next();
      });

    // Classical sheet with headers
    return sheet.populate(models, centerId, range, (err, collection) => {
      if (err)
        return next(err);

      addSheetToWorkbook(
        workbook,
        createSheet(sheet.headers, collection),
        sheet.name
      );

      return next();
    });
  }, err => {
    if (err)
      return callback(err);

    return callback(null, workbook);
  });
};
<|endoftext|>


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

/**
 * External dependencies
 */
import PropTypes from 'prop-types';
import { CircularProgress } from '@material-ui/core';

/**
 * WordPress dependencies
 */
import { __ } from '@wordpress/i18n';
import { useCallback, Fragment } from '@wordpress/element';

/**
 * Internal dependencies
 */
import Data from 'googlesitekit-data';
import Button from '../../../../../components/Button';
import {
	MODULES_IDEA_HUB,
	IDEA_HUB_BUTTON_CREATE,
	IDEA_HUB_BUTTON_PIN,
	IDEA_HUB_BUTTON_UNPIN,
	IDEA_HUB_BUTTON_DELETE,
	IDEA_HUB_BUTTON_VIEW,
	IDEA_HUB_ACTIVITY_CREATING_DRAFT,
	IDEA_HUB_ACTIVITY_DRAFT_CREATED,
	IDEA_HUB_ACTIVITY_IS_PROCESSING,
	IDEA_HUB_GA_CATEGORY_WIDGET,
} from '../../../datastore/constants';
import DeleteIcon from '../../../../../../svg/idea-hub-delete.svg';
import CreateIcon from '../../../../../../svg/idea-hub-create.svg';
import PinIcon from '../../../../../../svg/idea-hub-pin.svg';
import UnpinIcon from '../../../../../../svg/idea-hub-unpin.svg';
import { trackEvent } from '../../../../../util';

const DRAFT_CREATED_TIMER = 2000;

const { useDispatch, useSelect } = Data;

export default function Idea( props ) {
	const { postEditURL, name, text, topics, buttons } = props;

	const {
		createIdeaDraftPost,
		saveIdea,
		unsaveIdea,
		dismissIdea,
		setActivity,
		removeActivity,
		removeIdeaFromNewAndSavedIdeas,
	} = useDispatch( MODULES_IDEA_HUB );

	const activity = useSelect( ( select ) =>
		select( MODULES_IDEA_HUB ).getActivity( name )
	);

	const handleDelete = useCallback( async () => {
		setActivity( name, IDEA_HUB_ACTIVITY_IS_PROCESSING );
		await dismissIdea( name );
		removeActivity( name );

		trackEvent( IDEA_HUB_GA_CATEGORY_WIDGET, 'dismiss_idea' );
	}, [ name, dismissIdea, setActivity, removeActivity ] );

	const handlePin = useCallback( async () => {
		setActivity( name, IDEA_HUB_ACTIVITY_IS_PROCESSING );
		await saveIdea( name );
		removeActivity( name );

		trackEvent( IDEA_HUB_GA_CATEGORY_WIDGET, 'save_idea' );
	}, [ name, saveIdea, setActivity, removeActivity ] );

	const handleUnpin = useCallback( async () => {
		setActivity( name, IDEA_HUB_ACTIVITY_IS_PROCESSING );
		await unsaveIdea( name );
		removeActivity( name );

		trackEvent( IDEA_HUB_GA_CATEGORY_WIDGET, 'unsave_idea' );
	}, [ name, unsaveIdea, setActivity, removeActivity ] );

	const handleCreate = useCallback( async () => {
		setActivity( name, IDEA_HUB_ACTIVITY_CREATING_DRAFT );
		await createIdeaDraftPost( { name, text, topics } );
		setActivity( name, IDEA_HUB_ACTIVITY_DRAFT_CREATED );

		trackEvent( IDEA_HUB_GA_CATEGORY_WIDGET, 'start_draft' );

		setTimeout( () => {
			removeActivity( name );
			removeIdeaFromNewAndSavedIdeas( name );
		}, DRAFT_CREATED_TIMER );
	}, [
		removeActivity,
		removeIdeaFromNewAndSavedIdeas,
		createIdeaDraftPost,
		name,
		text,
		topics,
		setActivity,
	] );

	const handleView = useCallback( async () => {
		await trackEvent( IDEA_HUB_GA_CATEGORY_WIDGET, 'view_draft' );
	}, [] );

	return (

					{ topics.map( ( topic, key ) => (

							{ topic.displayName }

					) ) }

{ text }

				{ activity === IDEA_HUB_ACTIVITY_CREATING_DRAFT && (

{ __( 'Creating draft', 'google-site-kit' ) }

							<CircularProgress size={ 10 } />

				) }
				{ activity === IDEA_HUB_ACTIVITY_DRAFT_CREATED && (

{ __( 'Draft created', 'google-site-kit' ) }

				) }
				{ ! [
					IDEA_HUB_ACTIVITY_CREATING_DRAFT,
					IDEA_HUB_ACTIVITY_DRAFT_CREATED,
				].includes( activity ) && (
					<Fragment>
						{ buttons.includes( IDEA_HUB_BUTTON_DELETE ) && (
							<Button
								className="googlesitekit-idea-hub__actions--delete"
								onClick={ handleDelete }
								disabled={
									activity === IDEA_HUB_ACTIVITY_IS_PROCESSING
								}
								icon={ <DeleteIcon /> }
							/>
						) }

						{ buttons.includes( IDEA_HUB_BUTTON_PIN ) && (
							<Button
								className="googlesitekit-idea-hub__actions--pin"
								onClick={ handlePin }
								disabled={
									activity === IDEA_HUB_ACTIVITY_IS_PROCESSING
								}
								icon={ <PinIcon /> }
							/>
						) }

						{ buttons.includes( IDEA_HUB_BUTTON_UNPIN ) && (
							<Button
								className="googlesitekit-idea-hub__actions--unpin"
								onClick={ handleUnpin }
								disabled={
									activity === IDEA_HUB_ACTIVITY_IS_PROCESSING
								}
								icon={ <UnpinIcon /> }
							/>
						) }

						{ buttons.includes( IDEA_HUB_BUTTON_CREATE ) && (
							<Button
								className="googlesitekit-idea-hub__actions--create"
								onClick={ handleCreate }
								disabled={
									activity === IDEA_HUB_ACTIVITY_IS_PROCESSING
								}
								icon={ <CreateIcon /> }
							/>
						) }

						{ buttons.includes( IDEA_HUB_BUTTON_VIEW ) &&
							postEditURL && (
								<Button
									className="googlesitekit-idea-hub__actions--view"
									href={ postEditURL }
									onClick={ handleView }
									disabled={
										activity ===
										IDEA_HUB_ACTIVITY_IS_PROCESSING
									}
								>
									{ __( 'View draft', 'google-site-kit' ) }
								</Button>
							) }
					</Fragment>
				) }

	);
}

Idea.propTypes = {
	postID: PropTypes.number,
	postEditURL: PropTypes.string,
	postURL: PropTypes.string,
	name: PropTypes.string.isRequired,
	text: PropTypes.string.isRequired,
	topics: PropTypes.arrayOf(
		PropTypes.shape( {
			displayName: PropTypes.string,
			mid: PropTypes.string,
		} )
	),
	buttons: PropTypes.arrayOf( PropTypes.string ).isRequired,
};

Idea.defaultProps = {
	topics: [],
};
<commit_msg>Show tooltips for Idea Hub icon buttons.<commit_after>/**
 * Idea component
 *
 * Site Kit by Google, Copyright 2021 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * External dependencies
 */
import PropTypes from 'prop-types';
import { CircularProgress } from '@material-ui/core';

/**
 * WordPress dependencies
 */
import { __ } from '@wordpress/i18n';
import { useCallback, Fragment } from '@wordpress/element';

/**
 * Internal dependencies
 */
import Data from 'googlesitekit-data';
import Button from '../../../../../components/Button';
import {
	MODULES_IDEA_HUB,
	IDEA_HUB_BUTTON_CREATE,
	IDEA_HUB_BUTTON_PIN,
	IDEA_HUB_BUTTON_UNPIN,
	IDEA_HUB_BUTTON_DELETE,
	IDEA_HUB_BUTTON_VIEW,
	IDEA_HUB_ACTIVITY_CREATING_DRAFT,
	IDEA_HUB_ACTIVITY_DRAFT_CREATED,
	IDEA_HUB_ACTIVITY_IS_PROCESSING,
	IDEA_HUB_GA_CATEGORY_WIDGET,
} from '../../../datastore/constants';
import DeleteIcon from '../../../../../../svg/idea-hub-delete.svg';
import CreateIcon from '../../../../../../svg/idea-hub-create.svg';
import PinIcon from '../../../../../../svg/idea-hub-pin.svg';
import UnpinIcon from '../../../../../../svg/idea-hub-unpin.svg';
import { trackEvent } from '../../../../../util';

const DRAFT_CREATED_TIMER = 2000;

const { useDispatch, useSelect } = Data;

export default function Idea( props ) {
	const { postEditURL, name, text, topics, buttons } = props;

	const {
		createIdeaDraftPost,
		saveIdea,
		unsaveIdea,
		dismissIdea,
		setActivity,
		removeActivity,
		removeIdeaFromNewAndSavedIdeas,
	} = useDispatch( MODULES_IDEA_HUB );

	const activity = useSelect( ( select ) =>
		select( MODULES_IDEA_HUB ).getActivity( name )
	);

	const handleDelete = useCallback( async () => {
		setActivity( name, IDEA_HUB_ACTIVITY_IS_PROCESSING );
		await dismissIdea( name );
		removeActivity( name );

		trackEvent( IDEA_HUB_GA_CATEGORY_WIDGET, 'dismiss_idea' );
	}, [ name, dismissIdea, setActivity, removeActivity ] );

	const handlePin = useCallback( async () => {
		setActivity( name, IDEA_HUB_ACTIVITY_IS_PROCESSING );
		await saveIdea( name );
		removeActivity( name );

		trackEvent( IDEA_HUB_GA_CATEGORY_WIDGET, 'save_idea' );
	}, [ name, saveIdea, setActivity, removeActivity ] );

	const handleUnpin = useCallback( async () => {
		setActivity( name, IDEA_HUB_ACTIVITY_IS_PROCESSING );
		await unsaveIdea( name );
		removeActivity( name );

		trackEvent( IDEA_HUB_GA_CATEGORY_WIDGET, 'unsave_idea' );
	}, [ name, unsaveIdea, setActivity, removeActivity ] );

	const handleCreate = useCallback( async () => {
		setActivity( name, IDEA_HUB_ACTIVITY_CREATING_DRAFT );
		await createIdeaDraftPost( { name, text, topics } );
		setActivity( name, IDEA_HUB_ACTIVITY_DRAFT_CREATED );

		trackEvent( IDEA_HUB_GA_CATEGORY_WIDGET, 'start_draft' );

		setTimeout( () => {
			removeActivity( name );
			removeIdeaFromNewAndSavedIdeas( name );
		}, DRAFT_CREATED_TIMER );
	}, [
		removeActivity,
		removeIdeaFromNewAndSavedIdeas,
		createIdeaDraftPost,
		name,
		text,
		topics,
		setActivity,
	] );

	const handleView = useCallback( async () => {
		await trackEvent( IDEA_HUB_GA_CATEGORY_WIDGET, 'view_draft' );
	}, [] );

	return (

					{ topics.map( ( topic, key ) => (

							{ topic.displayName }

					) ) }

{ text }

				{ activity === IDEA_HUB_ACTIVITY_CREATING_DRAFT && (

{ __( 'Creating draft', 'google-site-kit' ) }

							<CircularProgress size={ 10 } />

				) }
				{ activity === IDEA_HUB_ACTIVITY_DRAFT_CREATED && (

{ __( 'Draft created', 'google-site-kit' ) }

				) }
				{ ! [
					IDEA_HUB_ACTIVITY_CREATING_DRAFT,
					IDEA_HUB_ACTIVITY_DRAFT_CREATED,
				].includes( activity ) && (
					<Fragment>
						{ buttons.includes( IDEA_HUB_BUTTON_DELETE ) && (
							<Button
								className="googlesitekit-idea-hub__actions--delete"
								onClick={ handleDelete }
								disabled={
									activity === IDEA_HUB_ACTIVITY_IS_PROCESSING
								}
								icon={ <DeleteIcon /> }
								title={ __( 'Dismiss', 'google-site-kit' ) }
							/>
						) }

						{ buttons.includes( IDEA_HUB_BUTTON_PIN ) && (
							<Button
								className="googlesitekit-idea-hub__actions--pin"
								onClick={ handlePin }
								disabled={
									activity === IDEA_HUB_ACTIVITY_IS_PROCESSING
								}
								icon={ <PinIcon /> }
								title={ __(
									'Save for later',
									'google-site-kit'
								) }
							/>
						) }

						{ buttons.includes( IDEA_HUB_BUTTON_UNPIN ) && (
							<Button
								className="googlesitekit-idea-hub__actions--unpin"
								onClick={ handleUnpin }
								disabled={
									activity === IDEA_HUB_ACTIVITY_IS_PROCESSING
								}
								icon={ <UnpinIcon /> }
								title={ __(
									'Remove from saved"',
									'google-site-kit'
								) }
							/>
						) }

						{ buttons.includes( IDEA_HUB_BUTTON_CREATE ) && (
							<Button
								className="googlesitekit-idea-hub__actions--create"
								onClick={ handleCreate }
								disabled={
									activity === IDEA_HUB_ACTIVITY_IS_PROCESSING
								}
								icon={ <CreateIcon /> }
								title={ __(
									'Start a draft post',
									'google-site-kit'
								) }
							/>
						) }

						{ buttons.includes( IDEA_HUB_BUTTON_VIEW ) &&
							postEditURL && (
								<Button
									className="googlesitekit-idea-hub__actions--view"
									href={ postEditURL }
									onClick={ handleView }
									disabled={
										activity ===
										IDEA_HUB_ACTIVITY_IS_PROCESSING
									}
								>
									{ __( 'View draft', 'google-site-kit' ) }
								</Button>
							) }
					</Fragment>
				) }

	);
}

Idea.propTypes = {
	postID: PropTypes.number,
	postEditURL: PropTypes.string,
	postURL: PropTypes.string,
	name: PropTypes.string.isRequired,
	text: PropTypes.string.isRequired,
	topics: PropTypes.arrayOf(
		PropTypes.shape( {
			displayName: PropTypes.string,
			mid: PropTypes.string,
		} )
	),
	buttons: PropTypes.arrayOf( PropTypes.string ).isRequired,
};

Idea.defaultProps = {
	topics: [],
};
<|endoftext|>


<commit_before>/* eslint-disable */
/**
 * Created by max on 2017/1/19.
 */

var getAsText = function (fileToRead) {
  var reader = new window.FileReader()
  // Read file into memory as UTF-8
  reader.readAsText(fileToRead)
  // Handle errors load
  reader.onload = this.loadHandler
  reader.onerror = this.errorHandler
}

var loadHandler = function (event) {
  var csv = event.target.result
  processData(csv)
}

var processData = function (csv) {
  var lines = []
  var allTextLines = csv.split(/\r\n|\n/)
  for (var i = 0; i < allTextLines.length; i++) {
    var data = allTextLines[i].split(',')
    var tarr = []
    for (var j = 0; j < data.length; j++) {
      tarr.push(data[j].replace(/"/g, ''));
    }
    lines.push(tarr)
  }
  checkHeadFormat(lines)
}

var checkHeadFormat = function (lines) {
  var count = []
  var daysCount = []
  for (var i = 0; i < lines[0].length; i++) {
    var index = lines[0][i].split('.')
    var num = parseInt(index[0])
    if (num === 0) {
      count.push(num)
    } else if (num > 0) {
      count.push(num)
      daysCount[num] = i
    }
  }
  count.sort(function (a, b) {
    return a - b
  })
  if (count.length - 1 !== count[count.length - 1]) {
    window.alert('顯示名稱或天數格式錯誤，顯示名稱請在標題前加上\'0.\'，天數請從\'1.\'開始，不得跳號！')
  } else {
    checkShiftFormat(daysCount, lines)
  }
}

var checkShiftFormat = function (daysCount, lines) {
  for (var i = 1; i < lines.length; i++) {
    for (var j = 1; j < daysCount.length; j++) {
      var shifts = lines[i][daysCount[j]].split(';')
      for (var k = 0; k < shifts.length; k++) {
        if (!shifts[k].includes('.')) {
          window.alert('班數設定錯誤，未包含\'.\'。')
          return
        }
        var index = shifts[k].split('.')
        var num = parseInt(index[0])
        if (num === 0) {
          window.alert('班數設定錯誤，不可使用\'0\'，請從\'1\'開始。')
        } else if (!(num > 0)) {  //
          window.alert('班數設定錯誤，不可使用除數字以外其他字符！')
        }
      }
    }
  }
}

var errorHandler = function (evt) {
  if (evt.target.error.name === 'NotReadableError') {
    window.alert('Canno\'t read file !')
  }
}

var fileReader = {
  getAsText: getAsText,
  loadHandler: loadHandler,
  processData: processData,
  checkHeadFormat: checkHeadFormat,
  checkShiftFormat: checkShiftFormat,
  errorHandler: errorHandler
}

export default fileReader
<commit_msg>Fix file reader<commit_after>/* eslint-disable */
/**
 * Created by max on 2017/1/19.
 */

var getAsText = function (fileToRead) {
  var reader = new window.FileReader()
  // Read file into memory as UTF-8
  reader.readAsText(fileToRead)
  // Handle errors load
  reader.onload = this.loadHandler
  reader.onerror = this.errorHandler
}

var loadHandler = function (event) {
  var csv = event.target.result
  processData(csv)
}

var processData = function (csv) {
  var lines = []
  var allTextLines = csv.split(/\r\n|\n/)
  for (var i = 0; i < allTextLines.length; i++) {
    var data = allTextLines[i].split(',')
    var tarr = []
    for (var j = 0; j < data.length; j++) {
      tarr.push(data[j].replace(/"/g, ''));
    }
    lines.push(tarr)
  }
  checkHeadFormat(lines)
}

var checkHeadFormat = function (lines) {
  var count = []
  var daysCount = []
  for (var i = 0; i < lines[0].length; i++) {
    var index = lines[0][i].split('.')
    var num = parseInt(index[0])
    if (num === 0) {
      count.push(num)
    } else if (num > 0) {
      count.push(num)
      daysCount[num] = i
    }
  }
  count.sort(function (a, b) {
    return a - b
  })
  if (count.length - 1 !== count[count.length - 1]) {
    window.alert('顯示名稱或天數格式錯誤，顯示名稱請在標題前加上\'0.\'，天數請從\'1.\'開始，不得跳號！')
  } else {
    checkShiftFormat(daysCount, lines)
  }
}

var checkShiftFormat = function (daysCount, lines) {
  for (var i = 1; i < lines.length; i++) {
    for (var j = 1; j < daysCount.length; j++) {
      var shifts = lines[i][daysCount[j]].split(';')
      for (var k = 0; k < shifts.length; k++) {
        if(shifts[0]!='') {
          if (!shifts[k].includes('.')) {
            window.alert('班數設定錯誤，未包含\'.\'。')
            return
          }
          var index = shifts[k].split('.')
          var num = parseInt(index[0])
          if (num === 0) {
            window.alert('班數設定錯誤，不可使用\'0\'，請從\'1\'開始。')
          } else if (!(num > 0)) {  //
            window.alert('班數設定錯誤，不可使用除數字以外其他字符！')
          }
        }
      }
    }
  }
}

var errorHandler = function (evt) {
  if (evt.target.error.name === 'NotReadableError') {
    window.alert('Canno\'t read file !')
  }
}

var fileReader = {
  getAsText: getAsText,
  loadHandler: loadHandler,
  processData: processData,
  checkHeadFormat: checkHeadFormat,
  checkShiftFormat: checkShiftFormat,
  errorHandler: errorHandler
}

export default fileReader
<|endoftext|>


<commit_before>const i18next = require('i18next');
const { join } = require('path');
const { readdirSync, lstatSync } = require('fs');
const fsBackend = require('i18next-fs-backend');

const i18nPath = join(__dirname, '../i18n');
const SUPPORTED_NAMESPACES = [
  'emails', // default
];

module.exports = (function initI18n() {
  i18next
    .use(fsBackend)
    .init({
      initImmediate: false,
      fallbackLng: 'en',
      nsSeparator: ':|',
      ns: SUPPORTED_NAMESPACES,
      defaultNS: 'emails',
      preload: readdirSync(i18nPath).filter((fileName) => lstatSync(join(i18nPath, fileName)).isDirectory()),
      backend: {
        loadPath: join(__dirname, '../i18n/{{lng}}/{{ns}}.json'),
      },
    });

  return i18next;
}());
<commit_msg>fix(i18n): fix i18next instance instantiation<commit_after>const i18next = require('i18next');
const { join } = require('path');
const { readdirSync, lstatSync } = require('fs');
const fsBackend = require('i18next-fs-backend');

const i18nPath = join(__dirname, '../i18n');
const SUPPORTED_NAMESPACES = [
  'emails', // default
];

module.exports = (function initI18n() {
  const i18n = i18next.createInstance();

  i18n
    .use(fsBackend)
    .init({
      initImmediate: false,
      fallbackLng: 'en',
      nsSeparator: ':|',
      ns: SUPPORTED_NAMESPACES,
      defaultNS: 'emails',
      preload: readdirSync(i18nPath).filter((fileName) => lstatSync(join(i18nPath, fileName)).isDirectory()),
      backend: {
        loadPath: join(__dirname, '../i18n/{{lng}}/{{ns}}.json'),
      },
    });

  return i18n;
}());
<|endoftext|>


<commit_before>let { MeshPhongMaterial } = require('three/src/materials/MeshPhongMaterial')
let { MeshBasicMaterial } = require('three/src/materials/MeshBasicMaterial')
let { PerspectiveCamera } = require('three/src/cameras/PerspectiveCamera')
let { DirectionalLight } = require('three/src/lights/DirectionalLight')
let { SphereGeometry } = require('three/src/geometries/SphereGeometry')
let { SpriteMaterial } = require('three/src/materials/SpriteMaterial')
let { WebGLRenderer } = require('three/src/renderers/WebGLRenderer')
let { TextureLoader } = require('three/src/loaders/TextureLoader')
let { AmbientLight } = require('three/src/lights/AmbientLight')
let { Spherical } = require('three/src/math/Spherical')
let { Vector3 } = require('three/src/math/Vector3')
let { Vector2 } = require('three/src/math/Vector2')
let { Sprite } = require('three/src/objects/Sprite')
let { Scene } = require('three/src/scenes/Scene')
let { Color } = require('three/src/math/Color')
let { Mesh } = require('three/src/objects/Mesh')

let visited = require('../../cities/dots.js')

const RADIUS = 0.765 * 0.88

// DOM

let loading = document.querySelector('.globe_loading')
let div = document.querySelector('.globe_earth')

let mapUrl, hereUrl
for (let i of document.querySelectorAll('[as=image]')) {
  if (i.href.indexOf('/map.') !== -1) {
    mapUrl = i.href
  } else if (i.href.indexOf('/here.') !== -1) {
    hereUrl = i.href
  }
}

// Base

let renderer = new WebGLRenderer()
let scene = new Scene()
let camera = new PerspectiveCamera(45, 1, 0.01, 1000)

renderer.setPixelRatio(window.devicePixelRatio)

let loader = new TextureLoader()

// Light

scene.add(new AmbientLight(0xafafaf))

let light = new DirectionalLight(0x606060, 1)
light.position.set(1, 0, 1)
scene.add(light)

// Methods

function resize () {
  renderer.setSize(div.clientWidth, div.clientHeight)
  renderer.render(scene, camera)
}

function render () {
  renderer.render(scene, camera)
}

function setPosition (position, radius, latitude, longitude) {
  let phi = (90 - latitude) * (Math.PI / 180)
  let theta = (longitude + 180) * (Math.PI / 180)

  position.x = -radius * Math.sin(phi) * Math.cos(theta)
  position.z = radius * Math.sin(phi) * Math.sin(theta)
  position.y = radius * Math.cos(phi)
}

function moveSun () {
  let now = new Date()
  let solstice = new Date(now.getFullYear() + '-06-21 00:00:00')
  let days = (now - solstice) / (1000 * 60 * 60 * 24)
  let sunLat = 23.44 * Math.cos(2 * Math.PI * days / 365.26)
  let sunLong = 180 - 15 * (now.getUTCHours() + now.getMinutes() / 60)
  setPosition(light.position, 2, sunLat, sunLong)
}

// Scene

scene.background = new Color(0xffffff)

let sphere = new Mesh(
  new SphereGeometry(RADIUS, 64, 64),
  new MeshPhongMaterial({
    map: loader.load(mapUrl, load)
  })
)
scene.add(sphere)

let here = new Sprite(
  new SpriteMaterial({
    map: loader.load(hereUrl, load)
  })
)
here.material.depthTest = false
here.scale.set(0.1, 0.1, 1)
here.center.set(0.5, 0)
scene.add(here)

visited.forEach(i => {
  let dot = new Mesh(
    new SphereGeometry(0.004, 8),
    new MeshBasicMaterial({
      color: new Color(0xffffff)
    })
  )
  setPosition(dot.position, RADIUS, i[0], i[1])
  scene.add(dot)
})

// Control

let rotateStart = new Vector2()
let rotateEnd = new Vector2()
let rotateDelta = new Vector2()
let delta = new Spherical()

const PI2 = 2 * Math.PI

let distanceToEdge

function move () {
  delta.setFromVector3(camera.position)

  rotateDelta.subVectors(rotateEnd, rotateStart)
  delta.theta -= PI2 * rotateDelta.x / renderer.domElement.clientHeight
  delta.phi -= PI2 * rotateDelta.y / renderer.domElement.clientHeight
  rotateStart.copy(rotateEnd)

  delta.makeSafe()
  camera.position.setFromSpherical(delta)
  camera.lookAt(0, 0, 0)

  let distanceToHere = camera.position.distanceTo(here.position)
  here.material.depthTest = distanceToHere > distanceToEdge

  requestAnimationFrame(render)
}

function mouseMove (e) {
  rotateEnd.set(e.clientX, e.clientY)
  move()
}

function mouseUp () {
  document.removeEventListener('mousemove', mouseMove, false)
  document.removeEventListener('mouseup', mouseUp, false)
}

renderer.domElement.addEventListener('mousedown', e => {
  if (e.button === 0) { // left
    rotateStart.set(e.clientX, e.clientY)
    e.preventDefault()
    document.addEventListener('mousemove', mouseMove, false)
    document.addEventListener('mouseup', mouseUp, false)
  }
})

if (window.innerWidth > 980) {
  renderer.domElement.addEventListener('touchstart', e => {
    rotateStart.set(e.touches[0].pageX, e.touches[0].pageY)
  }, { passive: true })
  renderer.domElement.addEventListener('touchmove', e => {
    rotateEnd.set(e.touches[0].pageX, e.touches[0].pageY)
    move()
  }, { passive: true })
} else {
  renderer.domElement.addEventListener('touchstart', e => {
    e.preventDefault()
    rotateStart.set(e.touches[0].pageX, e.touches[0].pageY)
  })
  renderer.domElement.addEventListener('touchmove', e => {
    e.preventDefault()
    rotateEnd.set(e.touches[0].pageX, e.touches[0].pageY)
    move()
  })
}

// Init

window.addEventListener('resize', resize)
resize()

moveSun()
setTimeout(moveSun, 30 * 60 * 1000)

window.sL = l => {
  setPosition(here.position, RADIUS, l.latitude, l.longitude)
  setPosition(camera.position, 2, l.latitude > 0 ? 20 : -20, l.longitude)
  camera.lookAt(0, 0, 0)
  distanceToEdge = camera.position.distanceTo(new Vector3(0, RADIUS, 0))
  load()
}

let loaded = 0

function load () {
  loaded += 1
  if (loaded === 3) {
    div.appendChild(renderer.domElement)
    loading.remove()
    render()
  }
}
<commit_msg>Reduce light to make visited cities more visible<commit_after>let { MeshPhongMaterial } = require('three/src/materials/MeshPhongMaterial')
let { MeshBasicMaterial } = require('three/src/materials/MeshBasicMaterial')
let { PerspectiveCamera } = require('three/src/cameras/PerspectiveCamera')
let { DirectionalLight } = require('three/src/lights/DirectionalLight')
let { SphereGeometry } = require('three/src/geometries/SphereGeometry')
let { SpriteMaterial } = require('three/src/materials/SpriteMaterial')
let { WebGLRenderer } = require('three/src/renderers/WebGLRenderer')
let { TextureLoader } = require('three/src/loaders/TextureLoader')
let { AmbientLight } = require('three/src/lights/AmbientLight')
let { Spherical } = require('three/src/math/Spherical')
let { Vector3 } = require('three/src/math/Vector3')
let { Vector2 } = require('three/src/math/Vector2')
let { Sprite } = require('three/src/objects/Sprite')
let { Scene } = require('three/src/scenes/Scene')
let { Color } = require('three/src/math/Color')
let { Mesh } = require('three/src/objects/Mesh')

let visited = require('../../cities/dots.js')

const RADIUS = 0.765 * 0.88

// DOM

let loading = document.querySelector('.globe_loading')
let div = document.querySelector('.globe_earth')

let mapUrl, hereUrl
for (let i of document.querySelectorAll('[as=image]')) {
  if (i.href.indexOf('/map.') !== -1) {
    mapUrl = i.href
  } else if (i.href.indexOf('/here.') !== -1) {
    hereUrl = i.href
  }
}

// Base

let renderer = new WebGLRenderer()
let scene = new Scene()
let camera = new PerspectiveCamera(45, 1, 0.01, 1000)

renderer.setPixelRatio(window.devicePixelRatio)

let loader = new TextureLoader()

// Light

scene.add(new AmbientLight(0x606060))

let light = new DirectionalLight(0x7f7f7f, 1)
light.position.set(1, 0, 1)
scene.add(light)

// Methods

function resize () {
  renderer.setSize(div.clientWidth, div.clientHeight)
  renderer.render(scene, camera)
}

function render () {
  renderer.render(scene, camera)
}

function setPosition (position, radius, latitude, longitude) {
  let phi = (90 - latitude) * (Math.PI / 180)
  let theta = (longitude + 180) * (Math.PI / 180)

  position.x = -radius * Math.sin(phi) * Math.cos(theta)
  position.z = radius * Math.sin(phi) * Math.sin(theta)
  position.y = radius * Math.cos(phi)
}

function moveSun () {
  let now = new Date()
  let solstice = new Date(now.getFullYear() + '-06-21 00:00:00')
  let days = (now - solstice) / (1000 * 60 * 60 * 24)
  let sunLat = 23.44 * Math.cos(2 * Math.PI * days / 365.26)
  let sunLong = 180 - 15 * (now.getUTCHours() + now.getMinutes() / 60)
  setPosition(light.position, 2, sunLat, sunLong)
}

let loaded = 0

function load () {
  loaded += 1
  if (loaded === 3) {
    div.appendChild(renderer.domElement)
    loading.remove()
    render()
  }
}

// Scene

scene.background = new Color(0xffffff)

let sphere = new Mesh(
  new SphereGeometry(RADIUS, 64, 64),
  new MeshPhongMaterial({
    map: loader.load(mapUrl, load)
  })
)
scene.add(sphere)

let here = new Sprite(
  new SpriteMaterial({
    map: loader.load(hereUrl, load)
  })
)
here.material.depthTest = false
here.scale.set(0.1, 0.1, 1)
here.center.set(0.5, 0)
scene.add(here)

visited.forEach(i => {
  let dot = new Mesh(
    new SphereGeometry(0.004, 8),
    new MeshBasicMaterial({
      color: new Color(0xffffff)
    })
  )
  setPosition(dot.position, RADIUS, i[0], i[1])
  scene.add(dot)
})

// Control

let rotateStart = new Vector2()
let rotateEnd = new Vector2()
let rotateDelta = new Vector2()
let delta = new Spherical()

const PI2 = 2 * Math.PI

let distanceToEdge

function move () {
  delta.setFromVector3(camera.position)

  rotateDelta.subVectors(rotateEnd, rotateStart)
  delta.theta -= PI2 * rotateDelta.x / renderer.domElement.clientHeight
  delta.phi -= PI2 * rotateDelta.y / renderer.domElement.clientHeight
  rotateStart.copy(rotateEnd)

  delta.makeSafe()
  camera.position.setFromSpherical(delta)
  camera.lookAt(0, 0, 0)

  let distanceToHere = camera.position.distanceTo(here.position)
  here.material.depthTest = distanceToHere > distanceToEdge

  requestAnimationFrame(render)
}

function mouseMove (e) {
  rotateEnd.set(e.clientX, e.clientY)
  move()
}

function mouseUp () {
  document.removeEventListener('mousemove', mouseMove, false)
  document.removeEventListener('mouseup', mouseUp, false)
}

renderer.domElement.addEventListener('mousedown', e => {
  if (e.button === 0) { // left
    rotateStart.set(e.clientX, e.clientY)
    e.preventDefault()
    document.addEventListener('mousemove', mouseMove, false)
    document.addEventListener('mouseup', mouseUp, false)
  }
})

if (window.innerWidth > 980) {
  renderer.domElement.addEventListener('touchstart', e => {
    rotateStart.set(e.touches[0].pageX, e.touches[0].pageY)
  }, { passive: true })
  renderer.domElement.addEventListener('touchmove', e => {
    rotateEnd.set(e.touches[0].pageX, e.touches[0].pageY)
    move()
  }, { passive: true })
} else {
  renderer.domElement.addEventListener('touchstart', e => {
    e.preventDefault()
    rotateStart.set(e.touches[0].pageX, e.touches[0].pageY)
  })
  renderer.domElement.addEventListener('touchmove', e => {
    e.preventDefault()
    rotateEnd.set(e.touches[0].pageX, e.touches[0].pageY)
    move()
  })
}

// Init

window.addEventListener('resize', resize)
resize()

moveSun()
setTimeout(moveSun, 30 * 60 * 1000)

window.sL = l => {
  setPosition(here.position, RADIUS, l.latitude, l.longitude)
  setPosition(camera.position, 2, l.latitude > 0 ? 20 : -20, l.longitude)
  camera.lookAt(0, 0, 0)
  distanceToEdge = camera.position.distanceTo(new Vector3(0, RADIUS, 0))
  load()
}
<|endoftext|>


<commit_before>/********************************
* EZ-TC Plugin by jd            *
* Makes adding trainer cards EZ *
********************************/

var fs = require('fs');
var serialize = require('node-serialize');
var trainerCards = {};

function loadTrainerCards() {
	try {
		trainerCards = serialize.unserialize(fs.readFileSync('config/trainercards.json', 'utf8'));
		Object.merge(CommandParser.commands, trainerCards);
	} catch (e) {};
}
setTimeout(function(){loadTrainerCards();},1000);

function saveTrainerCards() {
	fs.writeFileSync('config/trainercards.json', serialize.serialize(trainerCards));
	Object.merge(CommandParser.commands, trainerCards);
}

exports.commands = {
	eztc: 'trainercard',
	trainercards: 'trainercard',
	tc: 'trainercard',
	trainercard: function (target, room, user) {
		if (!target) target = 'help';
		var parts = target.split(',');
		for (var u in parts) parts[u] = parts[u].trim();

		switch (parts[0]) {
			case 'add':
				if (!this.can('pban')) return false;
				if (!parts[2]) return this.sendReply("Usage: /trainercard add, [command name], [html]");
				var commandName = toId(parts[1]);
				if (CommandParser.commands[commandName]) return this.sendReply("/trainercards - The command \"" + commandName + "\" already exists.");
				var html = parts.splice(2, parts.length).join(',');
				trainerCards[commandName] = new Function('target', 'room', 'user', "if (!room.disableTrainerCards) if (!this.canBroadcast()) return; this.sendReplyBox('" + html.replace(/'/g, "\\'") + "');");
				saveTrainerCards();
				this.sendReply("The trainer card \"" + commandName + "\" has been added.");
				this.logModCommand(user.name + " added the trainer card " + commandName);
				try {
					Rooms.rooms.staff.add(user.name + " added the trainer card " + commandName);
				} catch (e) {};
				break;

			case 'rem':
			case 'del':
			case 'delete':
			case 'remove':
				if (!this.can('pban')) return false;
				if (!parts[1]) return this.sendReply("Usage: /trainercard remove, [command name]");
				var commandName = toId(parts[1]);
				if (!trainerCards[commandName]) return this.sendReply("/trainercards - The command \"" + commandName + "\" does not exist, or was added manually.");
				delete CommandParser.commands[commandName];
				delete trainerCards[commandName];
				saveTrainerCards();
				this.sendReply("The trainer card \"" + commandName + "\" has been removed.");
				this.logModCommand(user.name + " removed the trainer card " + commandName);
				try {
					Rooms.rooms.staff.add(user.name + " removed the trainer card " + commandName);
				} catch (e) {};
				break;

			case 'list':
				if (!this.can('trainercard')) return false;
				var output = "There's a total of " + Object.size(trainerCards) + " trainer cards added with this command:
";
				for (var tc in trainerCards) {
					output += tc + "
";
				}
				this.sendReplyBox(output);
				break;

			case 'off':
				if (!this.can('roommod', null, room)) return false;
				if (room.disableTrainerCards) return this.sendReply("Broadcasting trainer cards is already disabled in this room.");
				room.disableTrainerCards = true;
				room.chatRoomData.disableTrainerCards = true;
				Rooms.global.writeChatRoomData();
				this.privateModCommand("(" + user.name + " has disabled broadcasting trainer cards in this room.)");
				break;

			case 'on':
				if (!this.can('roommod', null, room)) return false;
				if (!room.disableTrainerCards) return this.sendReply("Broadcasing trainer cards is already enabled in this room.");
				delete room.disableTrainerCards;
				delete room.chatRoomData.disableTrainerCards;
				Rooms.global.writeChatRoomData();
				this.privateModCommand("(" + user.name + " has enabled broadcasting trainer cards in this room.)");
				break;

			case 'reload':
				if (!this.can('pban')) return false;
				return this.sendReply("Trainer cards have been reloaded.");
				loadTrainerCards();
				break;

			case 'info':
			case 'help':
			default:
				if (!this.canBroadcast()) return;
				this.sendReplyBox(
					"EZ-TC Commands:
" +
					"/trainercard add, [command name], [html] - Adds a trainer card.
" +
					"/trainercard remove, [command name] - Removes a trainer card.
" +
					"/trainercard list - Shows a list of all trainer cards added with this command.
" +
					"/trainercard off - Disables broadcasting trainer cards in the current room.
" +
					"/trainercard on - Enables broadcasting trainer cards in the current room.
" +
					"/trainercard reload - Reloads trainer cards if they break (shouldn't happen).
" +
					"/trainercard help - Shows this help command.
" +
					"EZ-TC Plugin by jd"
				);
		}
	}
};<commit_msg>Add a /tc source command<commit_after>/********************************
* EZ-TC Plugin by jd            *
* Makes adding trainer cards EZ *
********************************/

var fs = require('fs');
var serialize = require('node-serialize');
var trainerCards = {};

function loadTrainerCards() {
	try {
		trainerCards = serialize.unserialize(fs.readFileSync('config/trainercards.json', 'utf8'));
		Object.merge(CommandParser.commands, trainerCards);
	} catch (e) {};
}
setTimeout(function(){loadTrainerCards();},1000);

function saveTrainerCards() {
	fs.writeFileSync('config/trainercards.json', serialize.serialize(trainerCards));
	Object.merge(CommandParser.commands, trainerCards);
}

exports.commands = {
	eztc: 'trainercard',
	trainercards: 'trainercard',
	tc: 'trainercard',
	trainercard: function (target, room, user) {
		if (!target) target = 'help';
		var parts = target.split(',');
		for (var u in parts) parts[u] = parts[u].trim();

		switch (parts[0]) {
			case 'add':
				if (!this.can('pban')) return false;
				if (!parts[2]) return this.sendReply("Usage: /trainercard add, [command name], [html]");
				var commandName = toId(parts[1]);
				if (CommandParser.commands[commandName]) return this.sendReply("/trainercards - The command \"" + commandName + "\" already exists.");
				var html = parts.splice(2, parts.length).join(',');
				trainerCards[commandName] = new Function('target', 'room', 'user', "if (!room.disableTrainerCards) if (!this.canBroadcast()) return; this.sendReplyBox('" + html.replace(/'/g, "\\'") + "');");
				saveTrainerCards();
				this.sendReply("The trainer card \"" + commandName + "\" has been added.");
				this.logModCommand(user.name + " added the trainer card " + commandName);
				try {
					Rooms.rooms.staff.add(user.name + " added the trainer card " + commandName);
				} catch (e) {};
				break;

			case 'rem':
			case 'del':
			case 'delete':
			case 'remove':
				if (!this.can('pban')) return false;
				if (!parts[1]) return this.sendReply("Usage: /trainercard remove, [command name]");
				var commandName = toId(parts[1]);
				if (!trainerCards[commandName]) return this.sendReply("/trainercards - The command \"" + commandName + "\" does not exist, or was added manually.");
				delete CommandParser.commands[commandName];
				delete trainerCards[commandName];
				saveTrainerCards();
				this.sendReply("The trainer card \"" + commandName + "\" has been removed.");
				this.logModCommand(user.name + " removed the trainer card " + commandName);
				try {
					Rooms.rooms.staff.add(user.name + " removed the trainer card " + commandName);
				} catch (e) {};
				break;

			case 'list':
				if (!this.can('trainercard')) return false;
				var output = "There's a total of " + Object.size(trainerCards) + " trainer cards added with this command:
";
				for (var tc in trainerCards) {
					output += tc + "
";
				}
				this.sendReplyBox(output);
				break;

			case 'off':
				if (!this.can('roommod', null, room)) return false;
				if (room.disableTrainerCards) return this.sendReply("Broadcasting trainer cards is already disabled in this room.");
				room.disableTrainerCards = true;
				room.chatRoomData.disableTrainerCards = true;
				Rooms.global.writeChatRoomData();
				this.privateModCommand("(" + user.name + " has disabled broadcasting trainer cards in this room.)");
				break;

			case 'on':
				if (!this.can('roommod', null, room)) return false;
				if (!room.disableTrainerCards) return this.sendReply("Broadcasing trainer cards is already enabled in this room.");
				delete room.disableTrainerCards;
				delete room.chatRoomData.disableTrainerCards;
				Rooms.global.writeChatRoomData();
				this.privateModCommand("(" + user.name + " has enabled broadcasting trainer cards in this room.)");
				break;

			case 'reload':
				if (!this.can('pban')) return false;
				return this.sendReply("Trainer cards have been reloaded.");
				loadTrainerCards();
				break;

			case 'source':
				if (!this.can('pban')) return false;
				if (!parts[1]) return this.errorReply("Usage: /tc source, [commands] - displays the source code of a trainer card.");
				if (!CommandParser.commands[parts[1]]) return this.errorReply("Command not found.  Check spelling?");
				return this.sendReply(CommandParser.commands[parts[1]]);
				break;

			case 'info':
			case 'help':
			default:
				if (!this.canBroadcast()) return;
				this.sendReplyBox(
					"EZ-TC Commands:
" +
					"/trainercard add, [command name], [html] - Adds a trainer card.
" +
					"/trainercard remove, [command name] - Removes a trainer card.
" +
					"/trainercard list - Shows a list of all trainer cards added with this command.
" +
					"/trainercard off - Disables broadcasting trainer cards in the current room.
" +
					"/trainercard on - Enables broadcasting trainer cards in the current room.
" +
					"/trainercard reload - Reloads trainer cards if they break (shouldn't happen).
" +
					"/trainercard help - Shows this help command.
" +
					"EZ-TC Plugin by jd"
				);
		}
	}
};<|endoftext|>


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

'use strict';

// MODULES //

var bench = require( '@stdlib/bench' );
var randu = require( '@stdlib/random/base/randu' );
var isnan = require( '@stdlib/math/base/assert/is-nan' );
var EPS = require( '@stdlib/constants/math/float64-eps' );
var pkg = require( './../package.json' ).name;
var iterator = require( './../lib' );

// MAIN //

bench( pkg, function benchmark( assert ) {
	var lambda;
	var iter;
	var i;

	assert.tic();
	for ( i = 0; i < assert.iterations; i++ ) {
		lambda = ( randu() * 10.0 ) + EPS;
		iter = iterator( lambda );
		if ( typeof iter !== 'object' ) {
			assert.fail( 'should return an object' );
		}
	}
	assert.toc();
	if ( typeof iter !== 'object' || typeof iter.next !== 'function' ) {
		assert.fail( 'should return an iterator protocol-compliant object' );
	}
	assert.pass( 'benchmark finished' );
	assert.end();
});

bench( pkg+'::iteration', function benchmark( assert ) {
	var lambda;
	var rand;
	var z;
	var i;

	lambda = 1.5;
	rand = iterator( lambda );

	assert.tic();
	for ( i = 0; i < assert.iterations; i++ ) {
		z = rand.next().value;
		if ( isnan( z ) ) {
			assert.fail( 'should not return NaN' );
		}
	}
	assert.toc();
	if ( isnan( z ) ) {
		assert.fail( 'should not return NaN' );
	}
	assert.pass( 'benchmark finished' );
	assert.end();
});
<commit_msg>Remove spaces<commit_after>/**
* @license Apache-2.0
*
* Copyright (c) 2018 The Stdlib Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*    http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

'use strict';

// MODULES //

var bench = require( '@stdlib/bench' );
var randu = require( '@stdlib/random/base/randu' );
var isnan = require( '@stdlib/math/base/assert/is-nan' );
var EPS = require( '@stdlib/constants/math/float64-eps' );
var pkg = require( './../package.json' ).name;
var iterator = require( './../lib' );

// MAIN //

bench( pkg, function benchmark( assert ) {
	var lambda;
	var iter;
	var i;

	assert.tic();
	for ( i = 0; i < assert.iterations; i++ ) {
		lambda = ( randu()*10.0 ) + EPS;
		iter = iterator( lambda );
		if ( typeof iter !== 'object' ) {
			assert.fail( 'should return an object' );
		}
	}
	assert.toc();
	if ( typeof iter !== 'object' || typeof iter.next !== 'function' ) {
		assert.fail( 'should return an iterator protocol-compliant object' );
	}
	assert.pass( 'benchmark finished' );
	assert.end();
});

bench( pkg+'::iteration', function benchmark( assert ) {
	var lambda;
	var rand;
	var z;
	var i;

	lambda = 1.5;
	rand = iterator( lambda );

	assert.tic();
	for ( i = 0; i < assert.iterations; i++ ) {
		z = rand.next().value;
		if ( isnan( z ) ) {
			assert.fail( 'should not return NaN' );
		}
	}
	assert.toc();
	if ( isnan( z ) ) {
		assert.fail( 'should not return NaN' );
	}
	assert.pass( 'benchmark finished' );
	assert.end();
});
<|endoftext|>


<commit_before>// Copyright (c) 2018, Compiler Explorer Authors
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

"use strict";

var _ = require('underscore');
var $ = require('jquery');
var FontScale = require('../fontscale');
var AnsiToHtml = require('../ansi-to-html');
var Toggles = require('../toggles');
var ga = require('../analytics');
var monaco = require('../monaco');

function makeAnsiToHtml(color) {
    return new AnsiToHtml({
        fg: color ? color : '#333',
        bg: '#f5f5f5',
        stream: true,
        escapeXML: true
    });
}

function Tool(hub, container, state) {
    this.container = container;
    this.compilerId = state.compiler;
    this.editorId = state.editor;
    this.toolId = state.toolId;
    this.toolName = "Tool";
    this.compilerService = hub.compilerService;
    this.eventHub = hub.createEventHub();
    this.domRoot = container.getElement();
    this.domRoot.html($('#tool-output').html());
    this.editorContentRoot = this.domRoot.find('.monaco-placeholder');
    this.plainContentRoot = this.domRoot.find('pre.content');
    this.optionsToolbar = this.domRoot.find('.options-toolbar');
    this.compilerName = "";
    this.normalAnsiToHtml = makeAnsiToHtml();
    this.errorAnsiToHtml = makeAnsiToHtml('red');

    this.optionsField = this.domRoot.find('input.options');
    this.stdinField = this.domRoot.find('textarea.tool-stdin');

    this.outputEditor = monaco.editor.create(this.editorContentRoot[0], {
        scrollBeyondLastLine: false,
        readOnly: true,
        language: 'text',
        fontFamily: "courier new",
        glyphMargin: true,
        fixedOverflowWidgets: true,
        minimap: {
            maxColumn: 80
        },
        lineNumbersMinChars: 5,
        renderIndentGuides: false
    });

    this.fontScale = new FontScale(this.domRoot, state, ".content,.monaco-editor");
    this.fontScale.on('change', _.bind(function () {
        this.saveState();
    }, this));

    this.initButtons(state);
    this.options = new Toggles(this.domRoot.find('.options'), state);
    this.options.on('change', _.bind(this.onOptionsChange, this));

    this.initArgs(state);

    this.container.on('resize', this.resize, this);
    this.container.on('shown', this.resize, this);
    this.container.on('destroy', this.close, this);

    this.eventHub.on('compileResult', this.onCompileResult, this);
    this.eventHub.on('compilerClose', this.onCompilerClose, this);

    this.onOptionsChange();
    this.updateCompilerName();

    ga.proxy('send', {
        hitType: 'event',
        eventCategory: 'OpenViewPane',
        eventAction: 'Tool'
    });

    this.eventHub.emit('toolOpened', this.compilerId, this.currentState());

    this.initCallbacks();
}

Tool.prototype.initCallbacks = function () {
    this.toggleArgs.on('click', _.bind(function () {
        this.togglePanel(this.toggleArgs, this.panelArgs);
    }, this));

    this.toggleStdin.on('click', _.bind(function () {
        this.togglePanel(this.toggleStdin, this.panelStdin);
    }, this));
};

Tool.prototype.initArgs = function (state) {
    var optionsChange = _.debounce(_.bind(function (e) {
        this.onOptionsChange($(e.target).val());

        this.eventHub.emit('toolSettingsChange', this.compilerId);
    }, this), 800);

    if (this.optionsField) {
        this.optionsField
            .on('change', optionsChange)
            .on('keyup', optionsChange);

        if (state.args) {
            this.optionsField.val(state.args);
        }
    }

    if (this.stdinField) {
        this.stdinField
            .on('change', optionsChange)
            .on('keyup', optionsChange);

        if (state.stdin) {
            this.stdinField.val(state.stdin);
        }
    }
};

Tool.prototype.getInputArgs = function () {
    if (this.optionsField) {
        return this.optionsField.val();
    } else {
        return "";
    }
};

Tool.prototype.getInputStdin = function () {
    if (this.stdinField) {
        return this.stdinField.val();
    } else {
        return "";
    }
};

Tool.prototype.getEffectiveOptions = function () {
    return this.options.get();
};

Tool.prototype.resize = function () {
    var barsHeight = this.optionsToolbar.outerHeight() + 2;
    if (!this.panelArgs.hasClass("d-none")) {
        barsHeight += this.panelArgs.outerHeight();
    }
    if (!this.panelStdin.hasClass("d-none")) {
        barsHeight += this.panelStdin.outerHeight();
    }

    this.outputEditor.layout({
        width: this.domRoot.width(),
        height: this.domRoot.height() - barsHeight
    });

    this.plainContentRoot.height(this.domRoot.height() - barsHeight);
};

Tool.prototype.onOptionsChange = function () {
    var options = this.getEffectiveOptions();
    this.plainContentRoot.toggleClass('wrap', options.wrap);
    this.wrapButton.prop('title', '[' + (options.wrap ? 'ON' : 'OFF') + '] ' + this.wrapTitle);

    this.saveState();
};

Tool.prototype.initButtons = function (state) {
    this.wrapButton = this.domRoot.find('.wrap-lines');
    this.wrapTitle = this.wrapButton.prop('title');

    this.panelArgs = this.domRoot.find('.panel-args');
    this.panelStdin = this.domRoot.find('.panel-stdin');

    this.initToggleButtons(state);
};

Tool.prototype.initToggleButtons = function (state) {
    this.toggleArgs = this.domRoot.find('.toggle-args');
    this.toggleStdin = this.domRoot.find('.toggle-stdin');

    if (state.argsPanelShown === true) {
        this.showPanel(this.toggleArgs, this.panelArgs);
    }

    if (state.stdinPanelShown === true) {
        this.showPanel(this.toggleStdin, this.panelStdin);
    }
};

Tool.prototype.showPanel = function (button, panel) {
    panel.removeClass('d-none');
    button.addClass('active');
    this.resize();
};

Tool.prototype.hidePanel = function (button, panel) {
    panel.addClass('d-none');
    button.removeClass('active');
    this.resize();
};

Tool.prototype.togglePanel = function (button, panel) {
    if (panel.hasClass('d-none')) {
        this.showPanel(button, panel);
    } else {
        this.hidePanel(button, panel);
    }
    this.saveState();
};

Tool.prototype.currentState = function () {
    var options = this.getEffectiveOptions();
    var state = {
        compiler: this.compilerId,
        editor: this.editorId,
        wrap: options.wrap,
        toolId: this.toolId,
        args: this.getInputArgs(),
        stdin: this.getInputStdin()
    };
    this.fontScale.addState(state);
    return state;
};

Tool.prototype.saveState = function () {
    this.container.setState(this.currentState());
};

Tool.prototype.setLanguage = function (languageId) {
    if (languageId) {
        this.options.enableToggle("wrap", false);
        monaco.editor.setModelLanguage(this.outputEditor.getModel(), languageId);
        this.outputEditor.setValue("");
        $(this.plainContentRoot).hide();
        $(this.editorContentRoot).show();
    } else {
        this.options.enableToggle("wrap", true);
        this.plainContentRoot.empty();
        $(this.editorContentRoot).hide();
        $(this.plainContentRoot).show();
    }
};

Tool.prototype.onCompileResult = function (id, compiler, result) {
    try{
        if (id !== this.compilerId) return;
        if (compiler) this.compilerName = compiler.name;

        var toolResult = null;
        if (result && result.tools) {
            toolResult = _.find(result.tools, function (tool) {
                return (tool.id === this.toolId);
            }, this);
        }

        var toolInfo = null;
        if (compiler && compiler.tools) {
            toolInfo = _.find(compiler.tools, function (tool) {
                return (tool.tool.id === this.toolId);
            }, this);
        }

        if (toolInfo) {
            if (toolInfo.tool.stdinHint) {
                this.stdinField.prop("placeholder", toolInfo.tool.stdinHint);
            } else {
                this.stdinField.prop("placeholder", "Tool stdin...");
            }
        }

        if (toolResult) {
            if (toolResult.languageId && (toolResult.languageId === "stderr")) {
                toolResult.languageId = false;
            }

            this.setLanguage(toolResult.languageId);

            if (toolResult.languageId) {
                this.setEditorContent(_.pluck(toolResult.stdout, 'text').join('\n'));
            } else {
                _.each((toolResult.stdout || []).concat(toolResult.stderr || []), function (obj) {
                    this.add(this.normalAnsiToHtml.toHtml(obj.text), obj.tag ? obj.tag.line : obj.line);
                }, this);

                this.toolName = toolResult.name;
                //this.add(this.toolName + " returned: " + toolResult.code);

                this.updateCompilerName();
            }

            if (toolResult.sourcechanged) {
                this.eventHub.emit('newSource', this.editorId, toolResult.newsource);
            }
        } else {
            this.setEditorContent("No tool result");
        }
    } catch(e) {
        this.setLanguage(false);
        this.add("javascript error: " + e.message);
    }
};

Tool.prototype.add = function (msg, lineNum) {
    var elem = $('

').appendTo(this.plainContentRoot);
    if (lineNum) {
        elem.html(
            $('')
                .prop('href', 'javascript:;')
                .html(msg)
                .click(_.bind(function (e) {
                    this.eventHub.emit('editorSetDecoration', this.editorId, lineNum, true);
                    e.preventDefault();
                    return false;
                }, this))
                .on('mouseover', _.bind(function () {
                    this.eventHub.emit('editorSetDecoration', this.editorId, lineNum, false);
                }, this))
        );
    } else {
        elem.html(msg);
    }
};

Tool.prototype.setEditorContent = function (content) {
    if (!this.outputEditor || !this.outputEditor.getModel()) return;
    var editorModel = this.outputEditor.getModel();
    var visibleRanges = this.outputEditor.getVisibleRanges();
    var currentTopLine = visibleRanges.length > 0 ? visibleRanges[0].startLineNumber : 1;
    editorModel.setValue(content);
    this.outputEditor.revealLine(currentTopLine);
    this.setNormalContent();
};

Tool.prototype.setNormalContent = function () {
    this.outputEditor.updateOptions({
        lineNumbers: true,
        codeLens: false
    });
    if (this.codeLensProvider) {
        this.codeLensProvider.dispose();
    }
};

Tool.prototype.updateCompilerName = function () {
    var name = this.toolName + " #" + this.compilerId;
    if (this.compilerName) name += " with " + this.compilerName;
    this.container.setTitle(name);
};

Tool.prototype.onCompilerClose = function (id) {
    if (id === this.compilerId) {
        this.close();
        _.defer(function (self) {
            self.container.close();
        }, this);
    }
};

Tool.prototype.close = function () {
    this.eventHub.emit('toolClosed', this.compilerId, this.currentState());
    this.eventHub.unsubscribe();
    this.outputEditor.dispose();
};

module.exports = {
    Tool: Tool
};
<commit_msg>update tool name also when using monaco output<commit_after>// Copyright (c) 2018, Compiler Explorer Authors
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

"use strict";

var _ = require('underscore');
var $ = require('jquery');
var FontScale = require('../fontscale');
var AnsiToHtml = require('../ansi-to-html');
var Toggles = require('../toggles');
var ga = require('../analytics');
var monaco = require('../monaco');

function makeAnsiToHtml(color) {
    return new AnsiToHtml({
        fg: color ? color : '#333',
        bg: '#f5f5f5',
        stream: true,
        escapeXML: true
    });
}

function Tool(hub, container, state) {
    this.container = container;
    this.compilerId = state.compiler;
    this.editorId = state.editor;
    this.toolId = state.toolId;
    this.toolName = "Tool";
    this.compilerService = hub.compilerService;
    this.eventHub = hub.createEventHub();
    this.domRoot = container.getElement();
    this.domRoot.html($('#tool-output').html());
    this.editorContentRoot = this.domRoot.find('.monaco-placeholder');
    this.plainContentRoot = this.domRoot.find('pre.content');
    this.optionsToolbar = this.domRoot.find('.options-toolbar');
    this.compilerName = "";
    this.normalAnsiToHtml = makeAnsiToHtml();
    this.errorAnsiToHtml = makeAnsiToHtml('red');

    this.optionsField = this.domRoot.find('input.options');
    this.stdinField = this.domRoot.find('textarea.tool-stdin');

    this.outputEditor = monaco.editor.create(this.editorContentRoot[0], {
        scrollBeyondLastLine: false,
        readOnly: true,
        language: 'text',
        fontFamily: "courier new",
        glyphMargin: true,
        fixedOverflowWidgets: true,
        minimap: {
            maxColumn: 80
        },
        lineNumbersMinChars: 5,
        renderIndentGuides: false
    });

    this.fontScale = new FontScale(this.domRoot, state, ".content,.monaco-editor");
    this.fontScale.on('change', _.bind(function () {
        this.saveState();
    }, this));

    this.initButtons(state);
    this.options = new Toggles(this.domRoot.find('.options'), state);
    this.options.on('change', _.bind(this.onOptionsChange, this));

    this.initArgs(state);

    this.container.on('resize', this.resize, this);
    this.container.on('shown', this.resize, this);
    this.container.on('destroy', this.close, this);

    this.eventHub.on('compileResult', this.onCompileResult, this);
    this.eventHub.on('compilerClose', this.onCompilerClose, this);

    this.onOptionsChange();
    this.updateCompilerName();

    ga.proxy('send', {
        hitType: 'event',
        eventCategory: 'OpenViewPane',
        eventAction: 'Tool'
    });

    this.eventHub.emit('toolOpened', this.compilerId, this.currentState());

    this.initCallbacks();
}

Tool.prototype.initCallbacks = function () {
    this.toggleArgs.on('click', _.bind(function () {
        this.togglePanel(this.toggleArgs, this.panelArgs);
    }, this));

    this.toggleStdin.on('click', _.bind(function () {
        this.togglePanel(this.toggleStdin, this.panelStdin);
    }, this));
};

Tool.prototype.initArgs = function (state) {
    var optionsChange = _.debounce(_.bind(function (e) {
        this.onOptionsChange($(e.target).val());

        this.eventHub.emit('toolSettingsChange', this.compilerId);
    }, this), 800);

    if (this.optionsField) {
        this.optionsField
            .on('change', optionsChange)
            .on('keyup', optionsChange);

        if (state.args) {
            this.optionsField.val(state.args);
        }
    }

    if (this.stdinField) {
        this.stdinField
            .on('change', optionsChange)
            .on('keyup', optionsChange);

        if (state.stdin) {
            this.stdinField.val(state.stdin);
        }
    }
};

Tool.prototype.getInputArgs = function () {
    if (this.optionsField) {
        return this.optionsField.val();
    } else {
        return "";
    }
};

Tool.prototype.getInputStdin = function () {
    if (this.stdinField) {
        return this.stdinField.val();
    } else {
        return "";
    }
};

Tool.prototype.getEffectiveOptions = function () {
    return this.options.get();
};

Tool.prototype.resize = function () {
    var barsHeight = this.optionsToolbar.outerHeight() + 2;
    if (!this.panelArgs.hasClass("d-none")) {
        barsHeight += this.panelArgs.outerHeight();
    }
    if (!this.panelStdin.hasClass("d-none")) {
        barsHeight += this.panelStdin.outerHeight();
    }

    this.outputEditor.layout({
        width: this.domRoot.width(),
        height: this.domRoot.height() - barsHeight
    });

    this.plainContentRoot.height(this.domRoot.height() - barsHeight);
};

Tool.prototype.onOptionsChange = function () {
    var options = this.getEffectiveOptions();
    this.plainContentRoot.toggleClass('wrap', options.wrap);
    this.wrapButton.prop('title', '[' + (options.wrap ? 'ON' : 'OFF') + '] ' + this.wrapTitle);

    this.saveState();
};

Tool.prototype.initButtons = function (state) {
    this.wrapButton = this.domRoot.find('.wrap-lines');
    this.wrapTitle = this.wrapButton.prop('title');

    this.panelArgs = this.domRoot.find('.panel-args');
    this.panelStdin = this.domRoot.find('.panel-stdin');

    this.initToggleButtons(state);
};

Tool.prototype.initToggleButtons = function (state) {
    this.toggleArgs = this.domRoot.find('.toggle-args');
    this.toggleStdin = this.domRoot.find('.toggle-stdin');

    if (state.argsPanelShown === true) {
        this.showPanel(this.toggleArgs, this.panelArgs);
    }

    if (state.stdinPanelShown === true) {
        this.showPanel(this.toggleStdin, this.panelStdin);
    }
};

Tool.prototype.showPanel = function (button, panel) {
    panel.removeClass('d-none');
    button.addClass('active');
    this.resize();
};

Tool.prototype.hidePanel = function (button, panel) {
    panel.addClass('d-none');
    button.removeClass('active');
    this.resize();
};

Tool.prototype.togglePanel = function (button, panel) {
    if (panel.hasClass('d-none')) {
        this.showPanel(button, panel);
    } else {
        this.hidePanel(button, panel);
    }
    this.saveState();
};

Tool.prototype.currentState = function () {
    var options = this.getEffectiveOptions();
    var state = {
        compiler: this.compilerId,
        editor: this.editorId,
        wrap: options.wrap,
        toolId: this.toolId,
        args: this.getInputArgs(),
        stdin: this.getInputStdin()
    };
    this.fontScale.addState(state);
    return state;
};

Tool.prototype.saveState = function () {
    this.container.setState(this.currentState());
};

Tool.prototype.setLanguage = function (languageId) {
    if (languageId) {
        this.options.enableToggle("wrap", false);
        monaco.editor.setModelLanguage(this.outputEditor.getModel(), languageId);
        this.outputEditor.setValue("");
        $(this.plainContentRoot).hide();
        $(this.editorContentRoot).show();
    } else {
        this.options.enableToggle("wrap", true);
        this.plainContentRoot.empty();
        $(this.editorContentRoot).hide();
        $(this.plainContentRoot).show();
    }
};

Tool.prototype.onCompileResult = function (id, compiler, result) {
    try{
        if (id !== this.compilerId) return;
        if (compiler) this.compilerName = compiler.name;

        var toolResult = null;
        if (result && result.tools) {
            toolResult = _.find(result.tools, function (tool) {
                return (tool.id === this.toolId);
            }, this);
        }

        var toolInfo = null;
        if (compiler && compiler.tools) {
            toolInfo = _.find(compiler.tools, function (tool) {
                return (tool.tool.id === this.toolId);
            }, this);
        }

        if (toolInfo) {
            if (toolInfo.tool.stdinHint) {
                this.stdinField.prop("placeholder", toolInfo.tool.stdinHint);
            } else {
                this.stdinField.prop("placeholder", "Tool stdin...");
            }
        }

        if (toolResult) {
            if (toolResult.languageId && (toolResult.languageId === "stderr")) {
                toolResult.languageId = false;
            }

            this.setLanguage(toolResult.languageId);

            if (toolResult.languageId) {
                this.setEditorContent(_.pluck(toolResult.stdout, 'text').join('\n'));
            } else {
                _.each((toolResult.stdout || []).concat(toolResult.stderr || []), function (obj) {
                    this.add(this.normalAnsiToHtml.toHtml(obj.text), obj.tag ? obj.tag.line : obj.line);
                }, this);
            }

            this.toolName = toolResult.name;
            this.updateCompilerName();

            if (toolResult.sourcechanged) {
                this.eventHub.emit('newSource', this.editorId, toolResult.newsource);
            }
        } else {
            this.setEditorContent("No tool result");
        }
    } catch(e) {
        this.setLanguage(false);
        this.add("javascript error: " + e.message);
    }
};

Tool.prototype.add = function (msg, lineNum) {
    var elem = $('

').appendTo(this.plainContentRoot);
    if (lineNum) {
        elem.html(
            $('')
                .prop('href', 'javascript:;')
                .html(msg)
                .click(_.bind(function (e) {
                    this.eventHub.emit('editorSetDecoration', this.editorId, lineNum, true);
                    e.preventDefault();
                    return false;
                }, this))
                .on('mouseover', _.bind(function () {
                    this.eventHub.emit('editorSetDecoration', this.editorId, lineNum, false);
                }, this))
        );
    } else {
        elem.html(msg);
    }
};

Tool.prototype.setEditorContent = function (content) {
    if (!this.outputEditor || !this.outputEditor.getModel()) return;
    var editorModel = this.outputEditor.getModel();
    var visibleRanges = this.outputEditor.getVisibleRanges();
    var currentTopLine = visibleRanges.length > 0 ? visibleRanges[0].startLineNumber : 1;
    editorModel.setValue(content);
    this.outputEditor.revealLine(currentTopLine);
    this.setNormalContent();
};

Tool.prototype.setNormalContent = function () {
    this.outputEditor.updateOptions({
        lineNumbers: true,
        codeLens: false
    });
    if (this.codeLensProvider) {
        this.codeLensProvider.dispose();
    }
};

Tool.prototype.updateCompilerName = function () {
    var name = this.toolName + " #" + this.compilerId;
    if (this.compilerName) name += " with " + this.compilerName;
    this.container.setTitle(name);
};

Tool.prototype.onCompilerClose = function (id) {
    if (id === this.compilerId) {
        this.close();
        _.defer(function (self) {
            self.container.close();
        }, this);
    }
};

Tool.prototype.close = function () {
    this.eventHub.emit('toolClosed', this.compilerId, this.currentState());
    this.eventHub.unsubscribe();
    this.outputEditor.dispose();
};

module.exports = {
    Tool: Tool
};
<|endoftext|>


<commit_before>//Import events
var events = require('evenets');

//Create EventHandler function
var EventHandler = function() {
  //Call the EventEmitter constructor on this object
  events.EventEmitter.call(this);
  //Create the registered event
  this.registered = function() {
    this.emit('registered');
  }
  //Request event
  //callback is the callback used once work is received
  this.request = function(callback) {
    this.emit('request', callback);
  }

  //Submit event
  //callback is the callback once submitted work is confirmed
  this.submit = function(callback) {
    this.emit('submit', callback);
  }
}

EventHandler.prototype.__proto__ = events.EventEmitter.prototype;

module.exports = EventHandler;
<commit_msg>Module name typo<commit_after>//Import events
var events = require('events');

//Create EventHandler function
var EventHandler = function() {
  //Call the EventEmitter constructor on this object
  events.EventEmitter.call(this);
  //Create the registered event
  this.registered = function() {
    this.emit('registered');
  }
  //Request event
  //callback is the callback used once work is received
  this.request = function(callback) {
    this.emit('request', callback);
  }

  //Submit event
  //callback is the callback once submitted work is confirmed
  this.submit = function(callback) {
    this.emit('submit', callback);
  }
}

EventHandler.prototype.__proto__ = events.EventEmitter.prototype;

module.exports = EventHandler;
<|endoftext|>