<commit_before>import ClientProject from "../client-project";
import OSProject from "../os-project";
import Contributor from "../contributor";

import set from "can-set";
import DefineMap from "can-define/map/";
import DefineList from "can-define/list/";
import superModel from '../../lib/super-model';
import feathersClient from '../feathers-client';

import moment from "moment";
import MonthlyOSProject from "./monthly-os-project";
import MonthlyClientProject from "./monthly-client-project";
import MonthlyContributions from "./monthly-contributions";

import algebra from '../algebras';
import idMerge from "can-connect/helpers/id-merge";

// Issue #152: every change causes browser to repaint.
// Reason: `can-define/map/map`'s `setProps`:
//     .attr is called on deep replace
//     .replace is called w/o letting it go through the setter.
//     As a result the list gets completely replaced, when its needed to be merged with the updated items.
// Could be removed or moved to the setter depending on a fix for https://github.com/canjs/can-define/issues/96.
[ MonthlyOSProject, MonthlyClientProject ].forEach( MapObj => {
  var attrOrig = MapObj.List.prototype.attr;
  MapObj.List.prototype.attr = function( items, replace ) {
    if ( replace === false && typeof items === "object" ) {
      idMerge( this, items, function( obj ){ return obj._id }, function( x ){
        if ( x instanceof MapObj ) {
          return x;
        }
        return new MapObj( x );
      });
      return this;
    } else {
      return attrOrig.apply( this, arguments );
    }
  };
} );

var ContributionMonth = DefineMap.extend("ContributionMonth",{
  _id: "string",
  __v:"number",
  date: "date",
  monthlyOSProjects: {
    Type: MonthlyOSProject.List,
    set: function(monthlyOSProjects){
      monthlyOSProjects.contributionMonth = this;
      return monthlyOSProjects;
    }
  },
  monthlyClientProjects: MonthlyClientProject.List,
  monthlyContributions: MonthlyContributions.List,
  calculations: {
    get: function() {
      var calculations = {
          clientProjects: {},
          totalDollarForAllClientProjects: 0,
          osProjects: {}
      };

      var clientProjectsUsingOSProject = {};
      var monthlyOSProjectMap = {};
      var totalCommissionedSignificance = 0;
      this.monthlyOSProjects.forEach( osProject => {
        monthlyOSProjectMap[osProject.osProjectRef._id] = osProject;
        if(osProject.commissioned) {
          totalCommissionedSignificance += osProject.significance;
        }
      });
      // for each client project, calculate out:
      // - rate (based on how many commissioned projects it uses) = 4 - 2 * (usedCommissionedSignificance / totalCommissionedSignificance)
      // - total = (rate * hours)
      // - totalSignificance - the total significance for this project
      // - osProjectsUsed - a map of the OS projects used
      this.monthlyClientProjects.forEach((monthlyClientProject) => {

        let totalSignificance = 0;
        let usedCommissionedSignificance = 0;
        let commissionedMonthlyOSProjects = [];
        let uncommissionedMonthlyOSProjects = [];

        monthlyClientProject.monthlyClientProjectsOSProjects.forEach( usedOSProjectRef => {
          var monthlyOSProject = monthlyOSProjectMap[usedOSProjectRef._id];
          if(monthlyOSProject) {
            // calculate needed significances
            if(monthlyOSProject.commissioned) {
              usedCommissionedSignificance += monthlyOSProject.significance;
              commissionedMonthlyOSProjects.push(monthlyOSProject);
            } else {
              uncommissionedMonthlyOSProjects.push(monthlyOSProject);
            }
            totalSignificance += monthlyOSProject.significance;

            // for an OS project, make it possible to get the clients using it
            if(!clientProjectsUsingOSProject[usedOSProjectRef._id]) {
              clientProjectsUsingOSProject[usedOSProjectRef._id] = [];
            }
            clientProjectsUsingOSProject[usedOSProjectRef._id].push(monthlyClientProject);
          }
        });

        // Don't divide by 0 if there are no commissioned projects
        if (totalCommissionedSignificance === 0) {
          totalCommissionedSignificance = 1;
        }

        let rate = 4 - 2 * (usedCommissionedSignificance / totalCommissionedSignificance);
        rate = isNaN(rate) ? 0 : rate; //handle the situation where there is not significance
        let totalAmount = parseFloat(Math.round((rate * monthlyClientProject.hours) * 100) / 100);

        calculations.totalDollarForAllClientProjects += totalAmount;

        calculations.clientProjects[monthlyClientProject.clientProjectRef._id] = {
          rate: parseFloat(Math.round(rate * 100) / 100),
          totalAmount,
          totalSignificance,
          commissionedMonthlyOSProjects,
          uncommissionedMonthlyOSProjects
        };

      });

      // once the rates are calculated, calculates for each OS project:
      // - total - for each clientProject using this project, take it's share
      this.monthlyOSProjects.forEach(function(osProject) {

        var clientProjects = clientProjectsUsingOSProject[osProject.osProjectRef._id];
        if(clientProjects) {
          calculations.osProjects[osProject.osProjectRef._id] = clientProjects.reduce(function(prev, monthlyClientProject){
            var clientProjectCalc = calculations.clientProjects[monthlyClientProject.clientProjectRef._id];
            return prev + (clientProjectCalc.totalAmount * osProject.significance / clientProjectCalc.totalSignificance);
          },0);
        } else {
          calculations.osProjects[osProject.osProjectRef._id] = 0;
        }
      });

      return calculations;
    }
  },

  // Can add using an osProject or monthlyOSProject
  addNewMonthlyOSProject( project ) {
    let monthlyOSProject;
    if (project instanceof MonthlyOSProject) {
      monthlyOSProject = project;
    }
    else {
      monthlyOSProject = new MonthlyOSProject({
        significance: 0,
        commissioned: false,
        osProjectRef: project,
        osProjectID: project._id
      });
    }
    this.monthlyOSProjects.push(monthlyOSProject);
    this.save().catch(err => {
      console.error("Failed saving the contributionMonth obj: ", err);
    });
    return monthlyOSProject;
  },
  removeMonthlyOSProject( monthlyOSProject ) {
    this.monthlyOSProjects.splice(this.monthlyOSProjects.indexOf(monthlyOSProject), 1);
    this.monthlyClientProjects.forEach( clientProject => {
      clientProject.monthlyClientProjectsOSProjects.splice(clientProject.monthlyClientProjectsOSProjects.indexOf(monthlyOSProject.osProjectRef), 1);
    });
    this.save().catch(err => {
      console.error("Failed saving the contributionMonth obj: ", err);
    });
  },

  commissionedMonthlyOSProjectsCountFor: function(monthlyClientProject) {
    if(this.calculations.clientProjects.hasOwnProperty(monthlyClientProject.clientProjectRef._id)) {
      return this.calculations.clientProjects[monthlyClientProject.clientProjectRef._id].commissionedMonthlyOSProjects.length;
    }
    return 0;
  },
  uncommissionedMonthlyOSProjectsCountFor: function(monthlyClientProject) {
    if(this.calculations.clientProjects.hasOwnProperty(monthlyClientProject.clientProjectRef._id)) {
      return this.calculations.clientProjects[monthlyClientProject.clientProjectRef._id].uncommissionedMonthlyOSProjects.length;
    }
    return 0;
  },
  removeClientProject: function(clientProject) {
    this.monthlyClientProjects.splice(this.monthlyClientProjects.indexOf(clientProject), 1);
  },
  getRate: function(monthlyClientProject) {

    if(this.calculations.clientProjects[monthlyClientProject.clientProjectRef._id]) {
        return this.calculations.clientProjects[monthlyClientProject.clientProjectRef._id].rate;
    }
    return 0;

  },
  getTotal: function(monthlyClientProject) {
    if(this.calculations.clientProjects[monthlyClientProject.clientProjectRef._id]) {
        return this.calculations.clientProjects[monthlyClientProject.clientProjectRef._id].totalAmount;
    }
    return 0;

  },

  addContribution(newContribution) {
    this.monthlyContributions.push(newContribution);
    this.save().then(function() {}, function() {
      console.error("Failed saving the contributionMonth obj: ", arguments);
    });
  },

  removeContribution(contribution) {
    const index = this.monthlyContributions.indexOf(contribution);
    this.monthlyContributions.splice(index, 1);
    this.save().then(function() {}, function() {
      console.error("Failed saving the contributionMonth obj: ", arguments);
    });
  }
});

ContributionMonth.List = DefineList.extend({
  "#": ContributionMonth,
  OSProjectContributionsMap: function(currentContributionMonth) {

    var OSProjectContributionsMap = {};
    this.forEach(contributionMonth => {
      if(moment(contributionMonth.date).isBefore(moment(currentContributionMonth.date).add(1, 'day'))) {
        var monthlyContributions = contributionMonth.monthlyContributions;
        monthlyContributions && monthlyContributions.length && monthlyContributions.forEach( monthlyContribution => {
          if( ! OSProjectContributionsMap[monthlyContribution.osProjectRef._id] ) {
            OSProjectContributionsMap[monthlyContribution.osProjectRef._id] = {
              contributors: {},
              totalPoints: 0
            };
          }

          if(! OSProjectContributionsMap[monthlyContribution.osProjectRef._id].contributors[monthlyContribution.contributorRef._id] ) {
            OSProjectContributionsMap[monthlyContribution.osProjectRef._id].contributors[monthlyContribution.contributorRef._id] = {
              points: monthlyContribution.points
            };
          }
          else {
            OSProjectContributionsMap[monthlyContribution.osProjectRef._id].contributors[monthlyContribution.contributorRef._id].points = OSProjectContributionsMap[monthlyContribution.osProjectRef._id].contributors[monthlyContribution.contributorRef._id].points + monthlyContribution.points;
          }

          OSProjectContributionsMap[monthlyContribution.osProjectRef._id].totalPoints = OSProjectContributionsMap[monthlyContribution.osProjectRef._id].totalPoints + monthlyContribution.points;

        });
      }
    });

    return OSProjectContributionsMap;
  }
});

var dataMassage = function(oType) {
  return function(item) {
    if (typeof item[oType + 'Id'] === 'object') {
      item[oType] = item[oType + 'Id'];
      item[oType + 'Id'] = item[oType]._id;
    }
  };
};

ContributionMonth.connection = superModel({
  parseInstanceProp: "data",
  Map: ContributionMonth,
  List: ContributionMonth.List,
  feathersService: feathersClient.service("/api/contribution_months"),
  name: "contributionMonth",
  algebra
});

ContributionMonth.algebra = algebra;

export default ContributionMonth;
<commit_msg>Fix issue with merging contributions during update<commit_after>import ClientProject from "../client-project";
import OSProject from "../os-project";
import Contributor from "../contributor";

import set from "can-set";
import DefineMap from "can-define/map/";
import DefineList from "can-define/list/";
import superModel from '../../lib/super-model';
import feathersClient from '../feathers-client';

import moment from "moment";
import MonthlyOSProject from "./monthly-os-project";
import MonthlyClientProject from "./monthly-client-project";
import MonthlyContributions from "./monthly-contributions";

import algebra from '../algebras';
import idMerge from "can-connect/helpers/id-merge";

// Issue #152: every change causes browser to repaint.
// Reason: `can-define/map/map`'s `setProps`:
//     .attr is called on deep replace
//     .replace is called w/o letting it go through the setter.
//     As a result the list gets completely replaced, when its needed to be merged with the updated items.
// Could be removed or moved to the setter depending on a fix for https://github.com/canjs/can-define/issues/96.
[ MonthlyOSProject, MonthlyClientProject, MonthlyContributions ].forEach( MapObj => {
  var attrOrig = MapObj.List.prototype.attr;
  MapObj.List.prototype.attr = function( items, replace ) {
    if ( replace === false && typeof items === "object" ) {
      idMerge( this, items, function( obj ){ return obj._id }, function( x ){
        if ( x instanceof MapObj ) {
          return x;
        }
        return new MapObj( x );
      });
      return this;
    } else {
      return attrOrig.apply( this, arguments );
    }
  };
} );

var ContributionMonth = DefineMap.extend("ContributionMonth",{
  _id: "string",
  __v:"number",
  date: "date",
  monthlyOSProjects: {
    Type: MonthlyOSProject.List,
    set: function(monthlyOSProjects){
      monthlyOSProjects.contributionMonth = this;
      return monthlyOSProjects;
    }
  },
  monthlyClientProjects: MonthlyClientProject.List,
  monthlyContributions: MonthlyContributions.List,
  calculations: {
    get: function() {
      var calculations = {
          clientProjects: {},
          totalDollarForAllClientProjects: 0,
          osProjects: {}
      };

      var clientProjectsUsingOSProject = {};
      var monthlyOSProjectMap = {};
      var totalCommissionedSignificance = 0;
      this.monthlyOSProjects.forEach( osProject => {
        monthlyOSProjectMap[osProject.osProjectRef._id] = osProject;
        if(osProject.commissioned) {
          totalCommissionedSignificance += osProject.significance;
        }
      });
      // for each client project, calculate out:
      // - rate (based on how many commissioned projects it uses) = 4 - 2 * (usedCommissionedSignificance / totalCommissionedSignificance)
      // - total = (rate * hours)
      // - totalSignificance - the total significance for this project
      // - osProjectsUsed - a map of the OS projects used
      this.monthlyClientProjects.forEach((monthlyClientProject) => {

        let totalSignificance = 0;
        let usedCommissionedSignificance = 0;
        let commissionedMonthlyOSProjects = [];
        let uncommissionedMonthlyOSProjects = [];

        monthlyClientProject.monthlyClientProjectsOSProjects.forEach( usedOSProjectRef => {
          var monthlyOSProject = monthlyOSProjectMap[usedOSProjectRef._id];
          if(monthlyOSProject) {
            // calculate needed significances
            if(monthlyOSProject.commissioned) {
              usedCommissionedSignificance += monthlyOSProject.significance;
              commissionedMonthlyOSProjects.push(monthlyOSProject);
            } else {
              uncommissionedMonthlyOSProjects.push(monthlyOSProject);
            }
            totalSignificance += monthlyOSProject.significance;

            // for an OS project, make it possible to get the clients using it
            if(!clientProjectsUsingOSProject[usedOSProjectRef._id]) {
              clientProjectsUsingOSProject[usedOSProjectRef._id] = [];
            }
            clientProjectsUsingOSProject[usedOSProjectRef._id].push(monthlyClientProject);
          }
        });

        // Don't divide by 0 if there are no commissioned projects
        if (totalCommissionedSignificance === 0) {
          totalCommissionedSignificance = 1;
        }

        let rate = 4 - 2 * (usedCommissionedSignificance / totalCommissionedSignificance);
        rate = isNaN(rate) ? 0 : rate; //handle the situation where there is not significance
        let totalAmount = parseFloat(Math.round((rate * monthlyClientProject.hours) * 100) / 100);

        calculations.totalDollarForAllClientProjects += totalAmount;

        calculations.clientProjects[monthlyClientProject.clientProjectRef._id] = {
          rate: parseFloat(Math.round(rate * 100) / 100),
          totalAmount,
          totalSignificance,
          commissionedMonthlyOSProjects,
          uncommissionedMonthlyOSProjects
        };

      });

      // once the rates are calculated, calculates for each OS project:
      // - total - for each clientProject using this project, take it's share
      this.monthlyOSProjects.forEach(function(osProject) {

        var clientProjects = clientProjectsUsingOSProject[osProject.osProjectRef._id];
        if(clientProjects) {
          calculations.osProjects[osProject.osProjectRef._id] = clientProjects.reduce(function(prev, monthlyClientProject){
            var clientProjectCalc = calculations.clientProjects[monthlyClientProject.clientProjectRef._id];
            return prev + (clientProjectCalc.totalAmount * osProject.significance / clientProjectCalc.totalSignificance);
          },0);
        } else {
          calculations.osProjects[osProject.osProjectRef._id] = 0;
        }
      });

      return calculations;
    }
  },

  // Can add using an osProject or monthlyOSProject
  addNewMonthlyOSProject( project ) {
    let monthlyOSProject;
    if (project instanceof MonthlyOSProject) {
      monthlyOSProject = project;
    }
    else {
      monthlyOSProject = new MonthlyOSProject({
        significance: 0,
        commissioned: false,
        osProjectRef: project,
        osProjectID: project._id
      });
    }
    this.monthlyOSProjects.push(monthlyOSProject);
    this.save().catch(err => {
      console.error("Failed saving the contributionMonth obj: ", err);
    });
    return monthlyOSProject;
  },
  removeMonthlyOSProject( monthlyOSProject ) {
    this.monthlyOSProjects.splice(this.monthlyOSProjects.indexOf(monthlyOSProject), 1);
    this.monthlyClientProjects.forEach( clientProject => {
      clientProject.monthlyClientProjectsOSProjects.splice(clientProject.monthlyClientProjectsOSProjects.indexOf(monthlyOSProject.osProjectRef), 1);
    });
    this.save().catch(err => {
      console.error("Failed saving the contributionMonth obj: ", err);
    });
  },

  commissionedMonthlyOSProjectsCountFor: function(monthlyClientProject) {
    if(this.calculations.clientProjects.hasOwnProperty(monthlyClientProject.clientProjectRef._id)) {
      return this.calculations.clientProjects[monthlyClientProject.clientProjectRef._id].commissionedMonthlyOSProjects.length;
    }
    return 0;
  },
  uncommissionedMonthlyOSProjectsCountFor: function(monthlyClientProject) {
    if(this.calculations.clientProjects.hasOwnProperty(monthlyClientProject.clientProjectRef._id)) {
      return this.calculations.clientProjects[monthlyClientProject.clientProjectRef._id].uncommissionedMonthlyOSProjects.length;
    }
    return 0;
  },
  removeClientProject: function(clientProject) {
    this.monthlyClientProjects.splice(this.monthlyClientProjects.indexOf(clientProject), 1);
  },
  getRate: function(monthlyClientProject) {

    if(this.calculations.clientProjects[monthlyClientProject.clientProjectRef._id]) {
        return this.calculations.clientProjects[monthlyClientProject.clientProjectRef._id].rate;
    }
    return 0;

  },
  getTotal: function(monthlyClientProject) {
    if(this.calculations.clientProjects[monthlyClientProject.clientProjectRef._id]) {
        return this.calculations.clientProjects[monthlyClientProject.clientProjectRef._id].totalAmount;
    }
    return 0;

  },

  addContribution(newContribution) {
    this.monthlyContributions.push(newContribution);
    this.save().then(function() {}, function() {
      console.error("Failed saving the contributionMonth obj: ", arguments);
    });
  },

  removeContribution(contribution) {
    const index = this.monthlyContributions.indexOf(contribution);
    this.monthlyContributions.splice(index, 1);
    this.save().then(function() {}, function() {
      console.error("Failed saving the contributionMonth obj: ", arguments);
    });
  }
});

ContributionMonth.List = DefineList.extend({
  "#": ContributionMonth,
  OSProjectContributionsMap: function(currentContributionMonth) {

    var OSProjectContributionsMap = {};
    this.forEach(contributionMonth => {
      if(moment(contributionMonth.date).isBefore(moment(currentContributionMonth.date).add(1, 'day'))) {
        var monthlyContributions = contributionMonth.monthlyContributions;
        monthlyContributions && monthlyContributions.length && monthlyContributions.forEach( monthlyContribution => {
          if( ! OSProjectContributionsMap[monthlyContribution.osProjectRef._id] ) {
            OSProjectContributionsMap[monthlyContribution.osProjectRef._id] = {
              contributors: {},
              totalPoints: 0
            };
          }

          if(! OSProjectContributionsMap[monthlyContribution.osProjectRef._id].contributors[monthlyContribution.contributorRef._id] ) {
            OSProjectContributionsMap[monthlyContribution.osProjectRef._id].contributors[monthlyContribution.contributorRef._id] = {
              points: monthlyContribution.points
            };
          }
          else {
            OSProjectContributionsMap[monthlyContribution.osProjectRef._id].contributors[monthlyContribution.contributorRef._id].points = OSProjectContributionsMap[monthlyContribution.osProjectRef._id].contributors[monthlyContribution.contributorRef._id].points + monthlyContribution.points;
          }

          OSProjectContributionsMap[monthlyContribution.osProjectRef._id].totalPoints = OSProjectContributionsMap[monthlyContribution.osProjectRef._id].totalPoints + monthlyContribution.points;

        });
      }
    });

    return OSProjectContributionsMap;
  }
});

var dataMassage = function(oType) {
  return function(item) {
    if (typeof item[oType + 'Id'] === 'object') {
      item[oType] = item[oType + 'Id'];
      item[oType + 'Id'] = item[oType]._id;
    }
  };
};

ContributionMonth.connection = superModel({
  parseInstanceProp: "data",
  Map: ContributionMonth,
  List: ContributionMonth.List,
  feathersService: feathersClient.service("/api/contribution_months"),
  name: "contributionMonth",
  algebra
});

ContributionMonth.algebra = algebra;

export default ContributionMonth;
<|endoftext|>


<commit_before>// Copyright 2018-2021, University of Colorado Boulder

/**
 * A Scenery Node that portrays a thermometer and a triangular indicator of the precise position where the temperature
 * is being sensed. The triangular indicator can be filled with a color to make it more clear what exactly is being
 * measured.
 *
 * @author John Blanco
 */

import Bounds2 from '../../../../dot/js/Bounds2.js';
import Range from '../../../../dot/js/Range.js';
import merge from '../../../../phet-core/js/merge.js';
import ModelViewTransform2 from '../../../../phetcommon/js/view/ModelViewTransform2.js';
import MovableDragHandler from '../../../../scenery-phet/js/input/MovableDragHandler.js';
import TemperatureAndColorSensorNode from '../../../../scenery-phet/js/TemperatureAndColorSensorNode.js';
import { Node } from '../../../../scenery/js/imports.js';
import Tandem from '../../../../tandem/js/Tandem.js';
import energyFormsAndChanges from '../../energyFormsAndChanges.js';
import EFACConstants from '../EFACConstants.js';

class EFACTemperatureAndColorSensorNode extends Node {

  /**
   * @param {TemperatureAndColorSensor} temperatureAndColorSensor - model element that measures temperature and color
   * at a position in model space
   * @param {Object} [options]
   */
  constructor( temperatureAndColorSensor, options ) {
    options = merge( {
      modelViewTransform: ModelViewTransform2.createIdentity(),
      draggable: false,
      dragBounds: Bounds2.EVERYTHING,
      cursor: 'pointer',
      phetioInputEnabledPropertyInstrumented: true,

      // phet-io
      tandem: Tandem.REQUIRED
    }, options );

    super( options );

    // @public (read-only) {TemperatureAndColorSensorNode} - public so getBounds functions can be called
    this.temperatureAndColorSensorNode = new TemperatureAndColorSensorNode(
      new Range(
        EFACConstants.WATER_FREEZING_POINT_TEMPERATURE,
        EFACConstants.OLIVE_OIL_BOILING_POINT_TEMPERATURE
      ),
      temperatureAndColorSensor.sensedTemperatureProperty,
      temperatureAndColorSensor.sensedElementColorProperty
    );
    this.addChild( this.temperatureAndColorSensorNode );

    // move this node when the model element moves
    temperatureAndColorSensor.positionProperty.link( position => {
      this.translation = options.modelViewTransform.modelToViewPosition( position );
    } );

    // add a drag handler if needed
    if ( options.draggable ) {
      this.addInputListener( new MovableDragHandler( temperatureAndColorSensor.positionProperty, {
        modelViewTransform: options.modelViewTransform,
        dragBounds: options.dragBounds.withMaxX(
          options.dragBounds.right - options.modelViewTransform.viewToModelDeltaX( this.width )
        ),
        attach: true,
        startDrag: () => {
          temperatureAndColorSensor.userControlledProperty.set( true );
        },
        endDrag: () => {
          temperatureAndColorSensor.userControlledProperty.set( false );
        },
        tandem: options.tandem.createTandem( 'inputListener' )
      } ) );
    }
  }
}

energyFormsAndChanges.register( 'EFACTemperatureAndColorSensorNode', EFACTemperatureAndColorSensorNode );
export default EFACTemperatureAndColorSensorNode;
<commit_msg>change constructor signature for TemperatureAndColorSensorNode, https://github.com/phetsims/sun/issues/769<commit_after>// Copyright 2018-2021, University of Colorado Boulder

/**
 * A Scenery Node that portrays a thermometer and a triangular indicator of the precise position where the temperature
 * is being sensed. The triangular indicator can be filled with a color to make it more clear what exactly is being
 * measured.
 *
 * @author John Blanco
 */

import Bounds2 from '../../../../dot/js/Bounds2.js';
import Range from '../../../../dot/js/Range.js';
import merge from '../../../../phet-core/js/merge.js';
import ModelViewTransform2 from '../../../../phetcommon/js/view/ModelViewTransform2.js';
import MovableDragHandler from '../../../../scenery-phet/js/input/MovableDragHandler.js';
import TemperatureAndColorSensorNode from '../../../../scenery-phet/js/TemperatureAndColorSensorNode.js';
import { Node } from '../../../../scenery/js/imports.js';
import Tandem from '../../../../tandem/js/Tandem.js';
import energyFormsAndChanges from '../../energyFormsAndChanges.js';
import EFACConstants from '../EFACConstants.js';

class EFACTemperatureAndColorSensorNode extends Node {

  /**
   * @param {TemperatureAndColorSensor} temperatureAndColorSensor - model element that measures temperature and color
   * at a position in model space
   * @param {Object} [options]
   */
  constructor( temperatureAndColorSensor, options ) {
    options = merge( {
      modelViewTransform: ModelViewTransform2.createIdentity(),
      draggable: false,
      dragBounds: Bounds2.EVERYTHING,
      cursor: 'pointer',
      phetioInputEnabledPropertyInstrumented: true,

      // phet-io
      tandem: Tandem.REQUIRED
    }, options );

    super( options );

    // @public (read-only) {TemperatureAndColorSensorNode} - public so getBounds functions can be called
    this.temperatureAndColorSensorNode = new TemperatureAndColorSensorNode(
      temperatureAndColorSensor.sensedTemperatureProperty,
      new Range( EFACConstants.WATER_FREEZING_POINT_TEMPERATURE, EFACConstants.OLIVE_OIL_BOILING_POINT_TEMPERATURE ),
      temperatureAndColorSensor.sensedElementColorProperty );
    this.addChild( this.temperatureAndColorSensorNode );

    // move this node when the model element moves
    temperatureAndColorSensor.positionProperty.link( position => {
      this.translation = options.modelViewTransform.modelToViewPosition( position );
    } );

    // add a drag handler if needed
    if ( options.draggable ) {
      this.addInputListener( new MovableDragHandler( temperatureAndColorSensor.positionProperty, {
        modelViewTransform: options.modelViewTransform,
        dragBounds: options.dragBounds.withMaxX(
          options.dragBounds.right - options.modelViewTransform.viewToModelDeltaX( this.width )
        ),
        attach: true,
        startDrag: () => {
          temperatureAndColorSensor.userControlledProperty.set( true );
        },
        endDrag: () => {
          temperatureAndColorSensor.userControlledProperty.set( false );
        },
        tandem: options.tandem.createTandem( 'inputListener' )
      } ) );
    }
  }
}

energyFormsAndChanges.register( 'EFACTemperatureAndColorSensorNode', EFACTemperatureAndColorSensorNode );
export default EFACTemperatureAndColorSensorNode;
<|endoftext|>


<commit_before>var _ = require("lodash");
var async = require("async");
var mongoose = require("mongoose");
require("ukiyoe-models")(mongoose);

var ExtractedImage = mongoose.model("ExtractedImage");

mongoose.connect('mongodb://localhost/extract');

mongoose.connection.on('error', function(err) {
    console.error('Connection Error:', err)
});

mongoose.connection.once('open', function() {
    var query = {"image": {$eq: null}};

    ExtractedImage.batchQuery(query, 1000, function(err, data) {
        if (data.done) {
            console.log("DONE");
            process.exit(0);
            return;
        }

        process.stdout.write("Processing " + data.from + " to " +
            data.to + "\r");
        async.eachLimit(data.images, 10, function(extracted, callback) {
            extracted.upgrade(callback);
        });
    });
});<commit_msg>Minor tweaks to upgrade script.<commit_after>var async = require("async");
var mongoose = require("mongoose");
require("ukiyoe-models")(mongoose);

var ExtractedImage = mongoose.model("ExtractedImage");

mongoose.connect('mongodb://localhost/extract');

mongoose.connection.on('error', function(err) {
    console.error('Connection Error:', err)
});

mongoose.connection.once('open', function() {
    ExtractedImage.batchQuery({"image": null}, 1000, function(err, data) {
        if (data.done) {
            console.log("DONE");
            process.exit(0);
            return;
        }

        process.stdout.write("Processing " + data.from + " to " +
            data.to + "\r");
        async.eachLimit(data.images, 10, function(extracted, callback) {
            extracted.upgrade(callback);
        });
    });
});<|endoftext|>


<commit_before>import { action, observable } from "mobx";
import uuidv4 from "uuid/v4";
import Command from "./Command";

export default class TestCase {
  id = null;
  @observable name = null;
  @observable commands = [];

  constructor(id = uuidv4(), name = "Untitled Test") {
    this.id = id;
    this.name = name;
  }

  @action.bound setName(name) {
    this.name = name;
  }

  @action.bound createCommand(index) {
    if (index !== undefined && index.constructor.name !== "Number") {
      throw new Error(`Expected to receive Number instead received ${index !== undefined ? index.constructor.name : index}`);
    } else {
      const command = new Command();
      index !== undefined ? this.commands.splice(index, 0, command) : this.commands.push(command);
      return command;
    }
  }

  @action.bound insertCommandAt(command, index) {
    if (!command || command.constructor.name !== "Command") {
      throw new Error(`Expected to receive Command instead received ${command ? command.constructor.name : command}`);
    } else if (index === undefined || index.constructor.name !== "Number") {
      throw new Error(`Expected to receive Number instead received ${index !== undefined ? index.constructor.name : index}`);
    } else {
      this.commands.splice(index, 0, command);
    }
  }

  @action.bound swapCommands(from, to) {
    const command = this.commands.splice(from, 1)[0];
    this.insertCommandAt(command, to);
  }

  @action.bound removeCommand(command) {
    this.commands.remove(command);
  }

  @action.bound clearAllCommands() {
    this.commands.clear();
  }
}
<commit_msg>from js basic implementation<commit_after>import { action, observable } from "mobx";
import uuidv4 from "uuid/v4";
import Command from "./Command";

export default class TestCase {
  id = null;
  @observable name = null;
  @observable commands = [];

  constructor(id = uuidv4(), name = "Untitled Test") {
    this.id = id;
    this.name = name;
  }

  @action.bound setName(name) {
    this.name = name;
  }

  @action.bound createCommand(index) {
    if (index !== undefined && index.constructor.name !== "Number") {
      throw new Error(`Expected to receive Number instead received ${index !== undefined ? index.constructor.name : index}`);
    } else {
      const command = new Command();
      index !== undefined ? this.commands.splice(index, 0, command) : this.commands.push(command);
      return command;
    }
  }

  @action.bound insertCommandAt(command, index) {
    if (!command || command.constructor.name !== "Command") {
      throw new Error(`Expected to receive Command instead received ${command ? command.constructor.name : command}`);
    } else if (index === undefined || index.constructor.name !== "Number") {
      throw new Error(`Expected to receive Number instead received ${index !== undefined ? index.constructor.name : index}`);
    } else {
      this.commands.splice(index, 0, command);
    }
  }

  @action.bound swapCommands(from, to) {
    const command = this.commands.splice(from, 1)[0];
    this.insertCommandAt(command, to);
  }

  @action.bound removeCommand(command) {
    this.commands.remove(command);
  }

  @action.bound clearAllCommands() {
    this.commands.clear();
  }

  static fromJS = function(jsRep) {
    const test = new TestCase(jsRep.id);
    test.setName(jsRep.name);

    return test;
  };
}
<|endoftext|>


<commit_before>
google.load('visualization', '1', {packages: ['corechart', 'bar']});
google.setOnLoadCallback(drawMultSeries);

function piirra(kuvadata,otsakkeet,otsikko,kohde,tyyppi) {

	  if (tyyppi=="P") { prosenttia='percent'; }
	  if (tyyppi=="N") { prosenttia=false; }
	  if (tyyppi=="100") {
		for (x=1;x<kuvadata.length;x++) {		vuosi_nolla=kuvadata[x][0];		for (i=0;i<kuvadata[0].length;i++)
		{ 		kuvadata[x][i]=(kuvadata[x][i]/vuosi_nolla)*100;		} 		}
		prosenttia=false;
	  }
	   if (tyyppi=="0") {
		for (x=1;x<kuvadata.length;x++) {
			vuosi_nolla=kuvadata[x][0];
			for (i=0;i<kuvadata[0].length;i++) 	{ kuvadata[x][i]=(vuosi_nolla-kuvadata[x][i]);	}
		}
		prosenttia=false;
	  }

	  if (tyyppi=="NP") { prosenttia=true; }
		var rivit = new Array();
		rivit.push(otsakkeet);

		if (kuvadata.length==4) {
		for (i=0;i<kuvadata[0].length;i++) { vuosi=kuvadata[0][i].toString();
		luku=parseInt(kuvadata[1][i]); luku2=parseInt(kuvadata[2][i]);	luku3=parseInt(kuvadata[3][i]);
        rivit.push([vuosi,luku,luku2,luku3]); 		}
	    }
		if (kuvadata.length==3) {
		for (i=0;i<kuvadata[0].length;i++) { vuosi=kuvadata[0][i].toString();
		luku=parseInt(kuvadata[1][i]); luku2=parseInt(kuvadata[2][i]);
        rivit.push([vuosi,luku,luku2]); 		}
	    }
		if (kuvadata.length==2) {
		for (i=0;i<kuvadata[0].length;i++) { vuosi=kuvadata[0][i].toString();
		luku=parseInt(kuvadata[1][i]);
        rivit.push([vuosi,luku]); 		}
	    }

		var data = google.visualization.arrayToDataTable(rivit);

      var options = {
        title: otsikko,
        chartArea: {width: '75%',height:'80%'},
        hAxis: {     title: 'Vuosi',   minValue: 0     },
        //vAxis: {     title: 'Ikäluokka'    },
		bar: { groupWidth: '25%' },
		height: 500,
		//width:'100%',
		isStacked:prosenttia
      };
	  if (tyyppi=="0") {  var chart =  new google.visualization.LineChart(document.getElementById(kohde)); 	 }
	  else {    var chart = new google.visualization.ColumnChart(document.getElementById(kohde)); }
      chart.draw(data, options);

}
<commit_msg>Update grafiikka.js<commit_after>
google.load('visualization', '1', {packages: ['corechart', 'bar']});
google.setOnLoadCallback(drawMultSeries);

function piirra(kuvadata,otsakkeet,otsikko,kohde,tyyppi) {

	  if (tyyppi=="P") { prosenttia='percent'; }
	  if (tyyppi=="N") { prosenttia=false; }
	  if (tyyppi=="100") {
		for (x=1;x<kuvadata.length;x++) {
			vuosi_nolla=kuvadata[x][0];
			for (i=0;i<kuvadata[0].length;i++) 	{ kuvadata[x][i]=(kuvadata[x][i]/vuosi_nolla)*100;	} 		}
		prosenttia=false;
	  }
	   if (tyyppi=="0") {
		for (x=1;x<kuvadata.length;x++) {
			vuosi_nolla=kuvadata[x][0];
			for (i=0;i<kuvadata[0].length;i++) 	{ kuvadata[x][i]=(vuosi_nolla-kuvadata[x][i]);	}
		}
		prosenttia=false;
	  }

	  if (tyyppi=="NP") { prosenttia=true; }
		var rivit = new Array();
		rivit.push(otsakkeet);

		if (kuvadata.length==4) {
		for (i=0;i<kuvadata[0].length;i++) { vuosi=kuvadata[0][i].toString();
		luku=parseInt(kuvadata[1][i]); luku2=parseInt(kuvadata[2][i]);	luku3=parseInt(kuvadata[3][i]);
        rivit.push([vuosi,luku,luku2,luku3]); 		}
	    }
		if (kuvadata.length==3) {
		for (i=0;i<kuvadata[0].length;i++) { vuosi=kuvadata[0][i].toString();
		luku=parseInt(kuvadata[1][i]); luku2=parseInt(kuvadata[2][i]);
        rivit.push([vuosi,luku,luku2]); 		}
	    }
		if (kuvadata.length==2) {
		for (i=0;i<kuvadata[0].length;i++) { vuosi=kuvadata[0][i].toString();
		luku=parseInt(kuvadata[1][i]);
        rivit.push([vuosi,luku]); 		}
	    }

		var data = google.visualization.arrayToDataTable(rivit);

      var options = {
        title: otsikko,
        chartArea: {width: '75%',height:'80%'},
        hAxis: {     title: 'Vuosi',   minValue: 0     },
        //vAxis: {     title: 'Ikäluokka'    },
		bar: { groupWidth: '25%' },
		height: 500,
		//width:'100%',
		isStacked:prosenttia
      };
	  if (tyyppi=="0") {  var chart =  new google.visualization.LineChart(document.getElementById(kohde)); 	 }
	  else {    var chart = new google.visualization.ColumnChart(document.getElementById(kohde)); }
      chart.draw(data, options);

}
<|endoftext|>


<commit_before>

// let time = 0
// const autoConfirm = () => {
//     if (!state.auto_confirm_pending() || pendingNum === 0) return
//     if (lock !== false && (new Date - lock) < 10000) return
//     log("try auto confirm")
//     location.href = "/#quest/assist/unclaimed"
//     waitForElementToExist(".btn-multi-raid.lis-raid", (targets) => {
//         pendingNum = document.querySelectorAll(".btn-multi-raid.lis-raid").length
//         setTimeout(() => {
//             log("press confirm raid.. time = ", ++time)
//             pressBySelector(".btn-multi-raid.lis-raid")
//             pendingNum --
//         }, 1341)
//     }, true)
// }
// setInterval(autoConfirm, 5000)
const autoConfirmPending = async () => {
    await waitState(state => state.auto_confirm_pending)()
    await waitPendingBattle()
    await waitLock()
    const token = lock(1000000)

    log("try confirm pending battle")
    const resp = await waitConfirmPendingBattle()
    log("confirm resp = ", resp)
    updateState({pending_battle: 0})

    unlock(token)
    return autoConfirmPending()
}
autoConfirmPending()

const autoBattleAutoPrpr = async (raid_id) => {
    const resp = await autoBattlePrpr(raid_id)
    log("AUTO PRPR RESP", resp)
    if (!resp) {
        const token = lock((Math.random() * 3000 + 1000) * 1000)
        return false
    }
    return true
}
const autoBattlePrpr = async (raid_id) => {
    await waitLock()
    const token = lock(35000)
    const time = new Date()

    log("prpr try join raid", raid_id)
    if (!await waitJoinRaid(raid_id)) {
        log("join raid faild")
        return false
    }
    await waitSelectSupporter(["カグヤ", "ホワイトラビット"])
    await waitSelectDeck(3, 1)

    updateState({pending_battle: state.pending_battle + 1})

    log("prpr attack", 1)
    await waitPressAttack()
    log("prpr attack", 2)
    await waitPressAttack()
    log("prpr skill!!")
    await waitPressSkill(4, 3)
    log("prpr attack!!")
    await waitPressAttack()
    await waitPressAuto()

    unlock(token)
    return true
}

const autoBattlePolarLight = async () => {
    await waitState(state => state.auto_battle)()
    await waitLock()
    const token = lock(600000)

    await waitRedirect("/#quest/supporter/599851/5")
    await waitSelectSupporter(["シヴァ", "アテナ"])
    await waitSelectDeck(2, 1)

    await auto_battle_polar_light_battle_script()

    log("wait redirect", "/#quest")
    await waitRedirect("/#quest")

    await waitTime(3000)
    unlock(token)
    return autoBattlePolarLight()
}

const auto_battle_polar_light_battle_script = async () => {
    log("wait switch charge off")
    await waitSwitchChargeOff()
    log("wait press attack")
    await waitPressAttack()
    log("wait press auto")
    await waitPressAuto()

    log("wait time", 1000, "ms")
    await waitTime(1000)

    log("wait battle count = 3")
    await waitBattleCount(3)
    log("wait press auto")
    await waitPressAuto()

    log("wait press skill")
    await waitPressSkill(1, 2)
    await waitPressSkill(1, 3)
    await waitPressSkill(1, 4)
    await waitPressSkill(1, 1)
    await waitPressSkill(2, 4)
    await waitPressSkill(2, 2)
    await waitPressSkill(3, 1)
    await waitPressSkill(4, 3)
    await waitPressSkill(4, 1)

    log("wait press attack")
    await waitPressAttack()
    log("wait press auto")
    await waitPressAuto()

    log("press charge")
    await waitSwitchChargeOn()

    log("wait boss die")
    await waitBossDie()
}<commit_msg>Revert "bug fixx"<commit_after>

// let time = 0
// const autoConfirm = () => {
//     if (!state.auto_confirm_pending() || pendingNum === 0) return
//     if (lock !== false && (new Date - lock) < 10000) return
//     log("try auto confirm")
//     location.href = "/#quest/assist/unclaimed"
//     waitForElementToExist(".btn-multi-raid.lis-raid", (targets) => {
//         pendingNum = document.querySelectorAll(".btn-multi-raid.lis-raid").length
//         setTimeout(() => {
//             log("press confirm raid.. time = ", ++time)
//             pressBySelector(".btn-multi-raid.lis-raid")
//             pendingNum --
//         }, 1341)
//     }, true)
// }
// setInterval(autoConfirm, 5000)
const autoConfirmPending = async () => {
    await waitState(state => state.auto_confirm_pending)()
    await waitPendingBattle()
    await waitLock()
    const token = lock(1000000)

    log("try confirm pending battle")
    const resp = await waitConfirmPendingBattle()
    log("confirm resp = ", resp)
    updateState({pending_battle: 0})

    unlock(token)
    return autoConfirmPending()
}
autoConfirmPending()

const autoBattleAutoPrpr = async (raid_id) => {
    const resp = await autoBattlePrpr(raid_id)
    log("AUTO PRPR RESP", resp)
    if (!resp) {
        const token = lock((Math.random() * 3000 + 1000) * 1000)
        return false
    }
    return true
}
const autoBattlePrpr = async (raid_id) => {
    await waitLock()
    const token = lock(35000)
    const time = new Date()

    log("prpr try join raid", raid_id)
    if (!await waitJoinRaid(raid_id)) {
        log("join raid faild")
        return false
    }
    await waitSelectSupporter(["カグヤ", "ホワイトラビット"])
    await waitSelectDeck(3, 1)

    updateState({pending_battle: state.pending_battle + 1})

    log("prpr attack", 1)
    await waitPressAttack()
    log("prpr attack", 2)
    await waitPressAttack()
    log("prpr skill!!")
    await waitPressSkill(2, 3)
    log("prpr attack!!")
    await waitPressAttack()
    await waitPressAuto()

    unlock(token)
    return true
}

const autoBattlePolarLight = async () => {
    await waitState(state => state.auto_battle)()
    await waitLock()
    const token = lock(600000)

    await waitRedirect("/#quest/supporter/599851/5")
    await waitSelectSupporter(["シヴァ", "アテナ"])
    await waitSelectDeck(2, 1)

    await auto_battle_polar_light_battle_script()

    log("wait redirect", "/#quest")
    await waitRedirect("/#quest")

    await waitTime(3000)
    unlock(token)
    return autoBattlePolarLight()
}

const auto_battle_polar_light_battle_script = async () => {
    log("wait switch charge off")
    await waitSwitchChargeOff()
    log("wait press attack")
    await waitPressAttack()
    log("wait press auto")
    await waitPressAuto()

    log("wait time", 1000, "ms")
    await waitTime(1000)

    log("wait battle count = 3")
    await waitBattleCount(3)
    log("wait press auto")
    await waitPressAuto()

    log("wait press skill")
    await waitPressSkill(1, 2)
    await waitPressSkill(1, 3)
    await waitPressSkill(1, 4)
    await waitPressSkill(1, 1)
    await waitPressSkill(2, 4)
    await waitPressSkill(2, 2)
    await waitPressSkill(3, 1)
    await waitPressSkill(4, 3)
    await waitPressSkill(4, 1)

    log("wait press attack")
    await waitPressAttack()
    log("wait press auto")
    await waitPressAuto()

    log("press charge")
    await waitSwitchChargeOn()

    log("wait boss die")
    await waitBossDie()
}<|endoftext|>


<commit_before>var Server = require('./server');
var Friend = require('./friend');
var Movie = require('./movie');
var ko = require('knockout');
var $ = require('jquery');

function AppViewModel() {
   // PRIVATE
   //-------------
   var API_URL = 'localhost';
   var LEFT = 37;
   var RIGHT = 39;

   var ACCESS_TOKEN = $('#access-token').text();
   var self = this;
   //var server = new Server(API_URL);

   var disableSwipe = false;

   var movies = [];

   var onShowDetail = function() {
     self.showDetails(true);
   };

   var maybeGetMoreMovies = function() {
       if (movies.length < 6) {
//           server.getNextTrailers(function(movie) {
//               // Update current movie and shift in the new movie
//               self.onNewMovies(movie);
//               // Update current movie and shift in the new movie
//               self.onNewMovie(movie);
//           });
       }
   };

   var nextMovie = function() {
     self.firstMovie(!self.firstMovie());
     movies.shift();
     maybeGetMoreMovies();
     if (self.firstMovie()) {
       self.currentMovie(movies[0]);
       self.nextMovie(movies[1]);
     } else {
       self.currentMovie(movies[1]);
       self.nextMovie(movies[0]);
     }
   };

   var nextCard = function() {
     disableSwipe = true;
     console.log('next card');
     $('.film-roll').animate({'top' : '0'}, 1000, function() {
       console.log('New card down: done');

       nextMovie();

       $('.film-roll').css({'top' : '-100%'});
       $('.frame').last().prepend('.film-roll');
       disableSwipe = false;
     });
   };

   var flipCard = function() {
     self.showDetails(!self.showDetails());
   };

   // PUBLIC
   //-------------
   self.currentMovie = ko.observable(null);
   self.nextMovie = ko.observable(null);
   self.firstMovie = ko.observable(true);
   self.showDetails = ko.observable(false);
   self.makeEventName = ko.observable("");

   self.onNewMovies = function(movie) {
     // Push in the new movie and update the current pointer
     movies = movies.concat(movie);

     // Fill in friend fields for each movie
     for(var i = 0; i < movie.length; i++) {
//         server.getFriendsWhoLiked(movie[i], function(friends) {
//            movie[i].setFriends(friends);
//         });
     }
   };

   self.onRight = function() {
     if (!disableSwipe) {
       // First "Yes" flip
       if (!self.showDetails()) {
         flipCard();
       } else { // Next card
         self.onLeft();
       }
     }
   };

   self.onLeft = function() {
     console.log('LEFT');
     if (!disableSwipe) {
       nextCard();
     }
   };

   // INIT
   //-------------

   $(document).keydown(function (e) {
     if(e.which == LEFT) {
       self.onLeft();
     } else if(e.which == RIGHT) {
       self.onRight();
     }
     return true;
   });

//   server.getNextTrailers(function(movies) {
//     // Load the movie into the queue
//     self.onNewMovies(movies);
//   });
}

module.exports = AppViewModel;<commit_msg>fixed<commit_after>var Server = require('./server');
var Friend = require('./friend');
var Movie = require('./movie');
var ko = require('knockout');
var $ = require('jquery');

function AppViewModel() {
   // PRIVATE
   //-------------
   var API_URL = 'localhost';
   var LEFT = 37;
   var RIGHT = 39;

   var ACCESS_TOKEN = $('#access-token').text();
   var self = this;
   //var server = new Server(API_URL);

   var disableSwipe = false;

   var movies = [];

   var onShowDetail = function() {
     self.showDetails(true);
   };

   var maybeGetMoreMovies = function() {
       if (movies.length < 6) {
           server.getNextTrailers(function(movie) {
               // Update current movie and shift in the new movie
               self.onNewMovies(movie);
               // Update current movie and shift in the new movie
               self.onNewMovie(movie);
           });
       }
   };

   var nextMovie = function() {
     self.firstMovie(!self.firstMovie());
     movies.shift();
     maybeGetMoreMovies();
     if (self.firstMovie()) {
       self.currentMovie(movies[0]);
       self.nextMovie(movies[1]);
     } else {
       self.currentMovie(movies[1]);
       self.nextMovie(movies[0]);
     }
   };

   var nextCard = function() {
     disableSwipe = true;
     console.log('next card');
     $('.film-roll').animate({'top' : '0'}, 1000, function() {
       console.log('New card down: done');

       nextMovie();

       $('.film-roll').css({'top' : '-100%'});
       $('.frame').last().prepend('.film-roll');
       disableSwipe = false;
     });
   };

   var flipCard = function() {
     self.showDetails(!self.showDetails());
   };

   // PUBLIC
   //-------------
   self.currentMovie = ko.observable(null);
   self.nextMovie = ko.observable(null);
   self.firstMovie = ko.observable(true);
   self.showDetails = ko.observable(false);
   self.makeEventName = ko.observable("");

   self.onNewMovies = function(movie) {
     // Push in the new movie and update the current pointer
     movies = movies.concat(movie);

     // Fill in friend fields for each movie
     for(var i = 0; i < movie.length; i++) {
//         server.getFriendsWhoLiked(movie[i], function(friends) {
//            movie[i].setFriends(friends);
//         });
     }
   };

   self.onRight = function() {
     if (!disableSwipe) {
       // First "Yes" flip
       if (!self.showDetails()) {
         flipCard();
       } else { // Next card
         self.onLeft();
       }
     }
   };

   self.onLeft = function() {
     console.log('LEFT');
     if (!disableSwipe) {
       nextCard();
     }
   };

   // INIT
   //-------------

   $(document).keydown(function (e) {
     if(e.which == LEFT) {
       self.onLeft();
     } else if(e.which == RIGHT) {
       self.onRight();
     }
     return true;
   });

   server.getNextTrailers(function(movies) {
     // Load the movie into the queue
     self.onNewMovies(movies);
   });
}

module.exports = AppViewModel;<|endoftext|>


<commit_before>"use strict";

// Ionic Starter App

// angular.module is a global place for creating, registering and retrieving Angular modules
// 'starter' is the name of this angular module example (also set in a <body> attribute in index.html)
// the 2nd parameter is an array of 'requires'
// 'starter.services' is found in services.js
// 'starter.controllers' is found in controllers.js
var isNotMobile = false;

var db;

var idCount = {
      team: 2,
      staff: 6,
      patient: 2
};

angular.module('app', ['ionic', 'ngCordova', 'app.controllers', 'app.routes', 'app.services', 'app.directives'])
.run(function($ionicPlatform, $cordovaSQLite) {
  $ionicPlatform.ready(function() {
    if (window.cordova && window.cordova.plugins && window.cordova.plugins.Keyboard) {
      cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
      cordova.plugins.Keyboard.disableScroll(true);
    }
    if (window.StatusBar) {
      // org.apache.cordova.statusbar required
      StatusBar.styleDefault();
    }

    // Important!!
    //
    // Instantiate database file/connection after ionic platform is ready.
    //
    // try {
    //     db = $cordovaSQLite.openDB("my.db");
    // } catch (error) {
    //     console.log(error);
    // }

    try {

      // window.sqlitePlugin.deleteDatabase({name: 'my.db', location: 'default'}, function() {console.log("delete success");}, function(err) {console.log("delete error" + JSON.stringify(err));});

      db = window.sqlitePlugin.openDatabase({ name: 'my.db', location: 'default' }, function () {

        db.sqlBatch([
          'CREATE TABLE IF NOT EXISTS teams (id integer, name text,location text)'
          // ,[ 'INSERT INTO teams VALUES (?,?,?)', [0,'test team xxx','UCL test ward'] ],
        ],
        function() {
          // mobileCount++;
          console.log('Find the idCount for team ****************');
          db.executeSql('SELECT MAX(id) AS idmax FROM teams;', [], function (resultSet) {
            console.log('----Sample column value: ' + resultSet.rows.item(0).idmax);
            idCount.team = resultSet.rows.item(0).idmax ? 1 +resultSet.rows.item(0).idmax : 0;
            console.log("Next id is: " + idCount.team);
          });
        }, function(error) {
          console.log('Populate table ezzy error: ' + error.message);
        });

      }, function (error) {
          console.log('Open database ezzy ERROR: ' + JSON.stringify(error));
      });

    } catch (error) {
        isNotMobile = true;
        console.log("catch error for ezzy" + error);
    }

    // Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
    // for form inputs)

  });
});

<commit_msg>add create table if not exist for patients and staffmems<commit_after>"use strict";

// Ionic Starter App

// angular.module is a global place for creating, registering and retrieving Angular modules
// 'starter' is the name of this angular module example (also set in a <body> attribute in index.html)
// the 2nd parameter is an array of 'requires'
// 'starter.services' is found in services.js
// 'starter.controllers' is found in controllers.js
var isNotMobile = false;

var db;

var idCount = {
      team: 2,
      staff: 6,
      patient: 2
};

angular.module('app', ['ionic', 'ngCordova', 'app.controllers', 'app.routes', 'app.services', 'app.directives'])
.run(function($ionicPlatform, $cordovaSQLite) {
  $ionicPlatform.ready(function() {
    if (window.cordova && window.cordova.plugins && window.cordova.plugins.Keyboard) {
      cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
      cordova.plugins.Keyboard.disableScroll(true);
    }
    if (window.StatusBar) {
      // org.apache.cordova.statusbar required
      StatusBar.styleDefault();
    }

    // Important!!
    //
    // Instantiate database file/connection after ionic platform is ready.
    //
    // try {
    //     db = $cordovaSQLite.openDB("my.db");
    // } catch (error) {
    //     console.log(error);
    // }

    try {

      // window.sqlitePlugin.deleteDatabase({name: 'my.db', location: 'default'}, function() {console.log("delete success");}, function(err) {console.log("delete error" + JSON.stringify(err));});

      db = window.sqlitePlugin.openDatabase({ name: 'my.db', location: 'default' }, function () {

        db.sqlBatch([
          'CREATE TABLE IF NOT EXISTS teams (id integer, name text,location text)',
          'CREATE TABLE IF NOT EXISTS staffmems (id integer, name text, role integer, contact text, team integer, picture text)',
          'CREATE TABLE IF NOT EXISTS patients (id integer, patientName text, patientDOB integer, HospitalNumber text, NHSNumber text, patientHeight integer, BetaBlockers integer, Antibiotic integer, BloodTransfusion integer, Antihypertensive integer )'
          // ,[ 'INSERT INTO teams VALUES (?,?,?)', [0,'test team xxx','UCL test ward'] ],
        ],
        function() {
          // mobileCount++;
          console.log('Find the idCount for team ****************');
          db.executeSql('SELECT MAX(id) AS idmax FROM teams;', [], function (resultSet) {
            console.log('----Sample column value: ' + resultSet.rows.item(0).idmax);
            idCount.team = resultSet.rows.item(0).idmax ? 1 +resultSet.rows.item(0).idmax : 0;
            console.log("Next id is: " + idCount.team);
          });
        }, function(error) {
          console.log('Populate table ezzy error: ' + error.message);
        });

      }, function (error) {
          console.log('Open database ezzy ERROR: ' + JSON.stringify(error));
      });

    } catch (error) {
        isNotMobile = true;
        console.log("catch error for ezzy" + error);
    }

    // Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
    // for form inputs)

  });
});

<|endoftext|>


<commit_before>// Game.Loader is a simple utility to track modules as they load (for the purpose of a load screen or some such).
// The loader can be initialized with an arbitrary list of module names. Additional modules
// can be `register`ed to the loader instance, as well as sub-modules.
Game.Loader = function(modules) {
	this.modules = {};
	for (var i = 0; i < modules.length; i++) {
		this.modules[modules[i]] = {
			submodules: {},
			progress: 0
		};
	}
	this.totalProgress = 0;
	this.currentlyLoading = [];
};
Game.Loader.prototype.getProgress = function() {
	return this.totalProgress;
};
Game.Loader.prototype.registerModule = function(module, submodule) {
	if(module in this.modules === false) {
		this.modules[module] = {
			submodules: {},
			progress: 0
		};
	} else if(submodule in this.modules[module].submodules === false) {
		this.modules[module].submodules[submodule] = {
			progress: 0
		};
	}
};
Game.Loader.prototype.startModule = function(module) {
	if(this.currentlyLoading.indexOf(module) === -1)
		this.currentlyLoading.push(module);
};
Game.Loader.prototype.startSubmodule = function(module, submodule) {
	if(this.currentlyLoading.indexOf(module) === -1)
		throw new Error("'" + module + "' is not currently loading.");
	if(this.currentlyLoading.indexOf(submodule) === -1)
		this.currentlyLoading.push(submodule);
};
Game.Loader.prototype.finishModule = function(module) {
	if(module in this.modules === false)
		throw new Error("'" + module + "' is not a registered module");

	// Make progress 100
	this.modules[module].progress = 100;

	// Remove item from currently loading list
	var index = this.currentlyLoading.indexOf(module);
	this.currentlyLoading.splice(index, 1);

	this._updateProgress();
};
Game.Loader.prototype.finishSubmodule = function(module, submodule) {
	if(this.currentlyLoading.indexOf(module) === -1)
		throw new Error("'" + module + "' is not currently loading.");
	else if(this.currentlyLoading.indexOf(submodule) === -1)
		throw new Error("'" + submodule + "' is not currently loading");
	else if(module in this.modules === false)
		throw new Error("'" + module + "' is not a registered module");
	else if(submodule in this.modules[module].submodules === false)
		throw new Error("'" + submodule + "' is not a registered submodule of '" + module + "'");

	this.modules[module].submodules[submodule].progress = 100;
	var index = this.currentlyLoading.indexOf(submodule);
	this.currentlyLoading.splice(index, 1);

	this._updateProgress();
};
Game.Loader.prototype.updateModule = function(module, amount) {
	if(module in this.modules === false)
		throw new Error("'" + module + "' is not a registered module");

	this.modules[module].progress = amount;

	this._updateProgress();
};
Game.Loader.prototype.updateSubmodule = function(module, submodule, amount) {
	if(module in this.modules === false)
		throw new Error("'" + module + "' is not a registered module");
	else if(submodule in this.modules[module].submodules === false)
		throw new Error("'" + submodule + "' is not a submodule of '" + module + "'");

	this.modules[module].submodules[submodule].progress = amount;

	// Update module progress as a function of the submodule's progress
	var numSubmodules = Object.keys(this.modules[module].submodules).length,
		maxProgress = numSubmodules * 100,
		currentProgress = 0;

	for(var sm in this.modules[module].submodules)
		currentProgress += this.modules[module].submodules[sm].progress;

	this.modules[module].progress = (currentProgress / maxProgress) * 100;

	this._updateProgress();
};
Game.Loader.prototype._updateProgress = function() {
	var numModules = Object.keys(this.modules).length,
		maxProgress = numModules * 100,
		currentProgress = 0,
        submodules, moduleMaxProgress, moduleProgress;

    for(var module in this.modules) {
        submodules = Object.keys(this.modules[module].submodules);
        moduleMaxProgress = submodules.length * 100;
        moduleProgress = 0;
        if(submodules.length) {
            for(var submodule in this.modules[module].submodules) {
                moduleProgress +=  this.modules[module].submodules[submodule].progress
            }

            this.modules[module].progress = (moduleProgress / moduleMaxProgress) * 100;
        }

        currentProgress += this.modules[module].progress;
    }

	for(var module in this.modules)
		currentProgress += this.modules[module].progress;

	this.totalProgress = (currentProgress / maxProgress) * 100;
};
<commit_msg>tabs -> spaces<commit_after>// Game.Loader is a simple utility to track modules as they load (for the purpose of a load screen or some such).
// The loader can be initialized with an arbitrary list of module names. Additional modules
// can be `register`ed to the loader instance, as well as sub-modules.
Game.Loader = function(modules) {
    this.modules = {};
    for (var i = 0; i < modules.length; i++) {
        this.modules[modules[i]] = {
            submodules: {},
            progress: 0
        };
    }
    this.totalProgress = 0;
    this.currentlyLoading = [];
};
Game.Loader.prototype.getProgress = function() {
    return this.totalProgress;
};
Game.Loader.prototype.registerModule = function(module, submodule) {
    if(module in this.modules === false) {
        this.modules[module] = {
            submodules: {},
            progress: 0
        };
    } else if(submodule in this.modules[module].submodules === false) {
        this.modules[module].submodules[submodule] = {
            progress: 0
        };
    }
};
Game.Loader.prototype.startModule = function(module) {
    if(this.currentlyLoading.indexOf(module) === -1)
        this.currentlyLoading.push(module);
};
Game.Loader.prototype.startSubmodule = function(module, submodule) {
    if(this.currentlyLoading.indexOf(module) === -1)
        throw new Error("'" + module + "' is not currently loading.");
    if(this.currentlyLoading.indexOf(submodule) === -1)
        this.currentlyLoading.push(submodule);
};
Game.Loader.prototype.finishModule = function(module) {
    if(module in this.modules === false)
        throw new Error("'" + module + "' is not a registered module");

    // Make progress 100
    this.modules[module].progress = 100;

    // Remove item from currently loading list
    var index = this.currentlyLoading.indexOf(module);
    this.currentlyLoading.splice(index, 1);

    this._updateProgress();
};
Game.Loader.prototype.finishSubmodule = function(module, submodule) {
    if(this.currentlyLoading.indexOf(module) === -1)
        throw new Error("'" + module + "' is not currently loading.");
    else if(this.currentlyLoading.indexOf(submodule) === -1)
        throw new Error("'" + submodule + "' is not currently loading");
    else if(module in this.modules === false)
        throw new Error("'" + module + "' is not a registered module");
    else if(submodule in this.modules[module].submodules === false)
        throw new Error("'" + submodule + "' is not a registered submodule of '" + module + "'");

    this.modules[module].submodules[submodule].progress = 100;
    var index = this.currentlyLoading.indexOf(submodule);
    this.currentlyLoading.splice(index, 1);

    this._updateProgress();
};
Game.Loader.prototype.updateModule = function(module, amount) {
    if(module in this.modules === false)
        throw new Error("'" + module + "' is not a registered module");

    this.modules[module].progress = amount;

    this._updateProgress();
};
Game.Loader.prototype.updateSubmodule = function(module, submodule, amount) {
    if(module in this.modules === false)
        throw new Error("'" + module + "' is not a registered module");
    else if(submodule in this.modules[module].submodules === false)
        throw new Error("'" + submodule + "' is not a submodule of '" + module + "'");

    this.modules[module].submodules[submodule].progress = amount;

    // Update module progress as a function of the submodule's progress
    var numSubmodules = Object.keys(this.modules[module].submodules).length,
        maxProgress = numSubmodules * 100,
        currentProgress = 0;

    for(var sm in this.modules[module].submodules)
        currentProgress += this.modules[module].submodules[sm].progress;

    this.modules[module].progress = (currentProgress / maxProgress) * 100;

    this._updateProgress();
};
Game.Loader.prototype._updateProgress = function() {
    var numModules = Object.keys(this.modules).length,
        maxProgress = numModules * 100,
        currentProgress = 0,
        submodules, moduleMaxProgress, moduleProgress;

    for(var module in this.modules) {
        submodules = Object.keys(this.modules[module].submodules);
        moduleMaxProgress = submodules.length * 100;
        moduleProgress = 0;
        if(submodules.length) {
            for(var submodule in this.modules[module].submodules) {
                moduleProgress +=  this.modules[module].submodules[submodule].progress
            }

            this.modules[module].progress = (moduleProgress / moduleMaxProgress) * 100;
        }

        currentProgress += this.modules[module].progress;
    }

    for(var module in this.modules)
        currentProgress += this.modules[module].progress;

    this.totalProgress = (currentProgress / maxProgress) * 100;
};
<|endoftext|>


<commit_before>/**
 * Classy - classy classes for JavaScript
 *
 * :copyright: (c) 2010 by Armin Ronacher.
 * :license: BSD.
 */

;(function(undefined) {
  var
    CLASSY_VERSION = '1.3',
    root = this,
    old_class = root.Class,
    disable_constructor = false;

  /* we check if $super is in use by a class if we can.  But first we have to
     check if the JavaScript interpreter supports that.  This also matches
     to false positives later, but that does not do any harm besides slightly
     slowing calls down. */
  var probe_super = (function(){$super();}).toString().indexOf('$super') > 0;
  function usesSuper(obj) {
    return !probe_super || /\B\$super\b/.test(obj.toString());
  }

  /* helper function to set the attribute of something to a value or
     removes it if the value is undefined. */
  function setOrUnset(obj, key, value) {
    if (value === undefined)
      delete obj[key];
    else
      obj[key] = value;
  }

  /* gets the own property of an object */
  function getOwnProperty(obj, name) {
    return Object.prototype.hasOwnProperty.call(obj, name)
      ? obj[name] : undefined;
  }

  /* instanciate a class without calling the constructor */
  function cheapNew(cls) {
    disable_constructor = true;
    var rv = new cls;
    disable_constructor = false;
    return rv;
  }

  /* the base class we export */
  var Class = function() {};

  /* restore the global Class name and pass it to a function.  This allows
     different versions of the classy library to be used side by side and
     in combination with other libraries. */
  Class.$noConflict = function() {
    try {
      setOrUnset(root, 'Class', old_class);
    }
    catch (e) {
      // fix for IE that does not support delete on window
      root.Class = old_class;
    }
    return Class;
  };

  /* what version of classy are we using? */
  Class.$classyVersion = CLASSY_VERSION;

  /* extend functionality */
  Class.$extend = function(properties) {
    var super_prototype = this.prototype;

    /* disable constructors and instanciate prototype.  Because the
       prototype can't raise an exception when created, we are safe
       without a try/finally here. */
    var prototype = cheapNew(this);

    /* copy all properties of the includes over if there are any */
    if (properties.__include__)
      for (var i = 0, n = properties.__include__.length; i != n; ++i) {
        var mixin = properties.__include__[i];
        for (var name in mixin) {
          var value = getOwnProperty(mixin, name);
          if (value !== undefined)
            prototype[name] = mixin[name];
        }
      }

    /* copy class vars from the superclass */
    properties.__classvars__ = properties.__classvars__ || {};
    if (prototype.__classvars__)
      for (var key in prototype.__classvars__)
        if (!properties.__classvars__[key]) {
          var value = getOwnProperty(prototype.__classvars__, key);
          properties.__classvars__[key] = value;
        }

    /* copy all properties over to the new prototype */
    for (var name in properties) {
      var value = getOwnProperty(properties, name);
      if (name === '__include__' ||
          value === undefined)
        continue;

      prototype[name] = typeof value === 'function' && usesSuper(value) ?
        (function(meth, name) {
          return function() {
            var old_super = getOwnProperty(this, '$super');
            this.$super = super_prototype[name];
            try {
              return meth.apply(this, arguments);
            }
            finally {
              setOrUnset(this, '$super', old_super);
            }
          };
        })(value, name) : value
    }

    /* dummy constructor */
    var rv = function() {
      if (disable_constructor)
        return;
      var proper_this = root === this ? cheapNew(arguments.callee) : this;
      if (proper_this.__init__)
        proper_this.__init__.apply(proper_this, arguments);
      proper_this.$class = rv;
      return proper_this;
    }

    /* copy all class vars over of any */
    for (var key in properties.__classvars__) {
      var value = getOwnProperty(properties.__classvars__, key);
      if (value !== undefined)
        rv[key] = value;
    }

    /* copy prototype and constructor over, reattach $extend and
       return the class */
    rv.prototype = prototype;
    rv.constructor = rv;
    rv.$extend = Class.$extend;
    rv.$withData = Class.$withData;
    return rv;
  };

  /* instanciate with data functionality */
  Class.$withData = function(data) {
    var rv = cheapNew(this);
    for (var key in data) {
      var value = getOwnProperty(data, key);
      if (value !== undefined)
        rv[key] = value;
    }
    return rv;
  };

  /* export the class */
  root.Class = Class;
})();
<commit_msg>Version bump :)<commit_after>/**
 * Classy - classy classes for JavaScript
 *
 * :copyright: (c) 2011 by Armin Ronacher.
 * :license: BSD.
 */

;(function(undefined) {
  var
    CLASSY_VERSION = '1.4',
    root = this,
    old_class = root.Class,
    disable_constructor = false;

  /* we check if $super is in use by a class if we can.  But first we have to
     check if the JavaScript interpreter supports that.  This also matches
     to false positives later, but that does not do any harm besides slightly
     slowing calls down. */
  var probe_super = (function(){$super();}).toString().indexOf('$super') > 0;
  function usesSuper(obj) {
    return !probe_super || /\B\$super\b/.test(obj.toString());
  }

  /* helper function to set the attribute of something to a value or
     removes it if the value is undefined. */
  function setOrUnset(obj, key, value) {
    if (value === undefined)
      delete obj[key];
    else
      obj[key] = value;
  }

  /* gets the own property of an object */
  function getOwnProperty(obj, name) {
    return Object.prototype.hasOwnProperty.call(obj, name)
      ? obj[name] : undefined;
  }

  /* instanciate a class without calling the constructor */
  function cheapNew(cls) {
    disable_constructor = true;
    var rv = new cls;
    disable_constructor = false;
    return rv;
  }

  /* the base class we export */
  var Class = function() {};

  /* restore the global Class name and pass it to a function.  This allows
     different versions of the classy library to be used side by side and
     in combination with other libraries. */
  Class.$noConflict = function() {
    try {
      setOrUnset(root, 'Class', old_class);
    }
    catch (e) {
      // fix for IE that does not support delete on window
      root.Class = old_class;
    }
    return Class;
  };

  /* what version of classy are we using? */
  Class.$classyVersion = CLASSY_VERSION;

  /* extend functionality */
  Class.$extend = function(properties) {
    var super_prototype = this.prototype;

    /* disable constructors and instanciate prototype.  Because the
       prototype can't raise an exception when created, we are safe
       without a try/finally here. */
    var prototype = cheapNew(this);

    /* copy all properties of the includes over if there are any */
    if (properties.__include__)
      for (var i = 0, n = properties.__include__.length; i != n; ++i) {
        var mixin = properties.__include__[i];
        for (var name in mixin) {
          var value = getOwnProperty(mixin, name);
          if (value !== undefined)
            prototype[name] = mixin[name];
        }
      }

    /* copy class vars from the superclass */
    properties.__classvars__ = properties.__classvars__ || {};
    if (prototype.__classvars__)
      for (var key in prototype.__classvars__)
        if (!properties.__classvars__[key]) {
          var value = getOwnProperty(prototype.__classvars__, key);
          properties.__classvars__[key] = value;
        }

    /* copy all properties over to the new prototype */
    for (var name in properties) {
      var value = getOwnProperty(properties, name);
      if (name === '__include__' ||
          value === undefined)
        continue;

      prototype[name] = typeof value === 'function' && usesSuper(value) ?
        (function(meth, name) {
          return function() {
            var old_super = getOwnProperty(this, '$super');
            this.$super = super_prototype[name];
            try {
              return meth.apply(this, arguments);
            }
            finally {
              setOrUnset(this, '$super', old_super);
            }
          };
        })(value, name) : value
    }

    /* dummy constructor */
    var rv = function() {
      if (disable_constructor)
        return;
      var proper_this = root === this ? cheapNew(arguments.callee) : this;
      if (proper_this.__init__)
        proper_this.__init__.apply(proper_this, arguments);
      proper_this.$class = rv;
      return proper_this;
    }

    /* copy all class vars over of any */
    for (var key in properties.__classvars__) {
      var value = getOwnProperty(properties.__classvars__, key);
      if (value !== undefined)
        rv[key] = value;
    }

    /* copy prototype and constructor over, reattach $extend and
       return the class */
    rv.prototype = prototype;
    rv.constructor = rv;
    rv.$extend = Class.$extend;
    rv.$withData = Class.$withData;
    return rv;
  };

  /* instanciate with data functionality */
  Class.$withData = function(data) {
    var rv = cheapNew(this);
    for (var key in data) {
      var value = getOwnProperty(data, key);
      if (value !== undefined)
        rv[key] = value;
    }
    return rv;
  };

  /* export the class */
  root.Class = Class;
})();
<|endoftext|>


<commit_before>//META {"name": "BetterReplyer", "source": "https://github.com/Zerthox/BetterDiscord-Plugins/blob/master/v1/BetterReplyer.plugin.js"} *//

/**
 * @author Zerthox
 * @version 4.0.5
 * @return {class} BetterReplyer Plugin class
 */
const BetterReplyer = (() => {

	// Api constants
	const {React, ReactDOM} = BdApi;

	/** Module storage */
	const Module = {
		Constants: BdApi.findModuleByProps("Permissions"),
		Permissions: BdApi.findModuleByProps("getChannelPermissions"),
		Drafts: BdApi.findModuleByProps("getDraft"),
		DraftActions: BdApi.findModuleByProps("saveDraft"),
		Users: BdApi.findModuleByProps("getUser", "getCurrentUser")
	};

	/** Component storage */
	const Component = {
		Message: BdApi.findModuleByProps("Message", "MessageAvatar").Message,
		ChannelTextArea: BDV2.WebpackModules.findByDisplayName("ChannelTextArea")
	};

	/** Selector storage */
	const Selector = {
		Messages: BdApi.findModuleByProps("message", "container", "headerCozy"),
		TextArea: BdApi.findModuleByProps("channelTextArea")
	};

	/** Storage for Patches */
	const Patches = {};

	// return plugin class
	return class BetterReplyer {

		/**
		 * @return {string} Plugin name
		 */
		getName() {
			return "BetterReplyer";
		}

		/**
		 * @return {string} Plugin version
		 */
		getVersion() {
			return "4.0.5";
		}

		/**
		 * @return {ReactElement} Plugin author
		 */
		getAuthor() {
			return this.createAnchor({text: "Zerthox", url: "https://github.com/Zerthox"});
		}

		/**
		 * @return {ReactElement} Plugin description
		 */
		getDescription() {
			return React.createElement("span", {style: {"white-space": "pre-line"}},
				"Reply to people using their ID with a button.\n Inspired by ",
				this.createAnchor({text: "Replyer", url: "https://github.com/cosmicsalad/Discord-Themes-and-Plugins/blob/master/plugins/replyer.plugin.js"}),
				" by ",
				this.createAnchor({text: "@Hammmock#3110", url: "https://github.com/cosmicsalad"}),
				", ",
				this.createAnchor({text: "@Natsulus#0001", url: "https://github.com/Delivator"}),
				" & ",
				this.createAnchor({text: "@Zerebos#7790", url: "https://github.com/rauenzi"}),
				"."
			);
		}

		/**
		 * Log a message in Console
		 * @param {string} msg message
		 */
		log(msg) {
			console.log(`%c[${this.getName()}] %c(v${this.getVersion()})%c ${msg}`, "color: #3a71c1; font-weight: 700;", "color: #666; font-size: .8em;", "");
		}

		/**
		 * Create a new Anchor element based on Discord's Anchor Component
		 * @param {object} props Component props
		 * @param {string} props.text Anchor text
		 * @param {string} props.url Anchor url
		 * @return {ReactElement} New Anchor element
		 */
		createAnchor(props) {
			return React.createElement(BDV2.WebpackModules.findByDisplayName("Anchor"), {href: props.url, target: "_blank", title: props.url}, props.text);
		}

		/**
		 * Plugin constructor
		 */
		constructor() {
			this.focused = null;
			this.selection = [0, 0];
			this.mode = false;
		}

		/**
		 * Plugin start function
		 */
		start() {

			// inject styles
			BdApi.injectCSS(this.getName(),
				`/* BetterReplyer CSS */
				.replyer {
					position: relative;
					top: -1px;
					margin-left: 5px;
					padding: 3px 5px;
					background: rgba(0, 0, 0, 0.4);
					border-radius: 3px;
					color: #fff !important;
					font-size: 10px;
					text-transform: uppercase;
					cursor: pointer;
				}
				.${Selector.Messages.container.split(" ")[0]}:not(:hover) .replyer {
					visibility: hidden;
				}`
			);

			// patch "Message" component render function
			Patches.message = BdApi.monkeyPatch(Component.Message.prototype, "render", {silent: true, after: (d) => {

				// get this & old return value
				const t = d.thisObject,
					r = d.returnValue;

				// get message author id
				const id = t.props.message.author.id;

				// return unmodified if disabled, compact, no header or author is current user
				if (t.props.isDisabled || t.props.isCompact || !t.props.isHeader || id === Module.Users.getCurrentUser().id) {
					return r;
				}

				// get current channel permissions
				const p = Module.Permissions.getChannelPermissions(t.props.channel.id);

				// return unmodified if no permissions to send messages
				if (typeof p === "number" && !(p & Module.Constants.Permissions.SEND_MESSAGES)) {
					return r;
				}

				// find message header
				const h = [r.props.children].flat().find((e) => e.props && e.props.className === Selector.Messages.headerCozy);

				// find message header meta
				const m = h && [h.props.children].flat().find((e) => e.props && e.props.className === Selector.Messages.headerCozyMeta);

				// check if message header meta found
				if (m) {

					// get children
					const c = [m.props.children].flat();

					// push reply button
					c.push(React.createElement("span", {
						className: "replyer",
						onClick: () => {

							// get saved text area
							const f = this.focused;

							// check if text area saved
							if (f) {

								// focus textarea
								f.focus();

								// check mode
								if (this.mode) {

									// select saved selection
									f.setSelectionRange(this.selection[0], this.selection[1]);

									// insert mention
									document.execCommand("insertText", false, `<@!${id}>`);

									// update saved text area
									setTimeout(() => {
										this.focused = f;
									}, 100);
								}
								else {

									// get mention
									const m = `<@!${id}> `;

									// go to start of textarea
									f.setSelectionRange(0, 0);

									// insert mention
									document.execCommand("insertText", false, m);

									// select saved selection
									f.setSelectionRange(this.selection[0] + m.length, this.selection[1] + m.length);
								}
							}
							else {

								// default to current channel
								Module.DraftActions.saveDraft(t.props.channel.id, `<@!${id}> ${Module.Drafts.getDraft(t.props.channel.id)}`);
							}
						}
					}, "Reply"));

					// override children
					m.props.children = c;
				}

				// return modified return value
				return r;
			}});
			this.log("Patched render of Message");

			// patch "ChannelTextArea" component render function
			Patches.textarea = BdApi.monkeyPatch(Component.ChannelTextArea.prototype, "render", {silent: true, instead: (d) => {

				// get this
				const t = d.thisObject;

				// declare blur handler
				const f = () => {

					// get dom node
					const e = ReactDOM.findDOMNode(d.thisObject).querySelector("textarea");

					// save focused textarea
					this.focused = e;

					// save selection
					this.selection = [e.selectionStart, e.selectionEnd];

					// set mode
					this.mode = true;

					// reset mode after 100ms
					setTimeout(() => {
						if (this.focused === e) {
							this.mode = false;
						}
					}, 100);
				};

				// check if text area has a blur handler
				if (t.props.onBlur) {

					// patch blur handler
					BdApi.monkeyPatch(t.props, "onBlur", {silent: true, before: f});
				}
				else {

					// assign blur handler
					t.props.onBlur = f;
				}

				// return render with modified this
				return d.originalMethod.apply(t);
			}});
			this.log("Patched onBlur of ChannelTextArea");

			// force update
			this.forceUpdateAll();

			// console output
			this.log("Enabled");
		}

		/**
		 * Plugin stop function
		 */
		stop() {

			// reset saved text area, selection & mode
			this.focused = null;
			this.selection = [0, 0];
			this.mode = false;

			// clear styles
			BdApi.clearCSS(this.getName());

			// revert all patches
			for (const k in Patches) {
				Patches[k]();
				delete Patches[k];
			}
			this.log("Unpatched all");

			// force update
			this.forceUpdateAll();

			// console output
			this.log("Disabled");
		}

		/**
		 * Force update the "Message" & "ChannelTextArea" component state nodes
		 */
		forceUpdateAll() {

			// force update messages
			for (const e of document.getElementsByClassName(Selector.Messages.message)) {
				const i = BdApi.getInternalInstance(e);
				i && i.return.stateNode.forceUpdate && i.return.stateNode.forceUpdate();
			}

			// force update channel text areas
			for (const e of document.getElementsByClassName(Selector.TextArea.channelTextArea)) {
				const i = BdApi.getInternalInstance(e);
				i && i.return.stateNode.forceUpdate && i.return.stateNode.forceUpdate();
			}
		}

	};
})();<commit_msg>Prepare BetterReplyer for BBD update<commit_after>//META {"name": "BetterReplyer", "source": "https://github.com/Zerthox/BetterDiscord-Plugins/blob/master/v1/BetterReplyer.plugin.js"} *//

/**
 * @author Zerthox
 * @version 4.0.6
 * @return {class} BetterReplyer Plugin class
 */
const BetterReplyer = (() => {

	// Api constants
	const {React, ReactDOM} = BdApi;

	/** Module storage */
	const Module = {
		Constants: BdApi.findModuleByProps("Permissions"),
		Permissions: BdApi.findModuleByProps("getChannelPermissions"),
		Drafts: BdApi.findModuleByProps("getDraft"),
		DraftActions: BdApi.findModuleByProps("saveDraft"),
		Users: BdApi.findModuleByProps("getUser", "getCurrentUser")
	};

	/** Component storage */
	const Component = {
		Message: BdApi.findModuleByProps("Message", "MessageAvatar").Message,
		ChannelTextArea: BdApi.findModule((m) => m.displayName === "ChannelTextArea")
	};

	/** Selector storage */
	const Selector = {
		Messages: BdApi.findModuleByProps("message", "container", "headerCozy"),
		TextArea: BdApi.findModuleByProps("channelTextArea")
	};

	/** Storage for Patches */
	const Patches = {};

	// return plugin class
	return class BetterReplyer {

		/**
		 * @return {string} Plugin name
		 */
		getName() {
			return "BetterReplyer";
		}

		/**
		 * @return {string} Plugin version
		 */
		getVersion() {
			return "4.0.6";
		}

		/**
		 * @return {string} Plugin author
		 */
		getAuthor() {
			return "Zerthox";
		}

		/**
		 * @return {ReactElement} Plugin description
		 */
		getDescription() {
			return "Reply to people using their ID with a button.\n Inspired by Replyer by @Hammmock#3110, @Natsulus#0001 & @Zerebos#7790.";
		}

		/**
		 * Log a message in Console
		 * @param {string} msg message
		 */
		log(msg) {
			console.log(`%c[${this.getName()}] %c(v${this.getVersion()})%c ${msg}`, "color: #3a71c1; font-weight: 700;", "color: #666; font-size: .8em;", "");
		}

		/**
		 * Plugin constructor
		 */
		constructor() {
			this.focused = null;
			this.selection = [0, 0];
			this.mode = false;
		}

		/**
		 * Plugin start function
		 */
		start() {

			// inject styles
			BdApi.injectCSS(this.getName(),
				`/* BetterReplyer CSS */
				.replyer {
					position: relative;
					top: -1px;
					margin-left: 5px;
					padding: 3px 5px;
					background: rgba(0, 0, 0, 0.4);
					border-radius: 3px;
					color: #fff !important;
					font-size: 10px;
					text-transform: uppercase;
					cursor: pointer;
				}
				.${Selector.Messages.container.split(" ")[0]}:not(:hover) .replyer {
					visibility: hidden;
				}`
			);

			// patch "Message" component render function
			Patches.message = BdApi.monkeyPatch(Component.Message.prototype, "render", {silent: true, after: (d) => {

				// get this & old return value
				const t = d.thisObject,
					r = d.returnValue;

				// get message author id
				const id = t.props.message.author.id;

				// return unmodified if disabled, compact, no header or author is current user
				if (t.props.isDisabled || t.props.isCompact || !t.props.isHeader || id === Module.Users.getCurrentUser().id) {
					return r;
				}

				// get current channel permissions
				const p = Module.Permissions.getChannelPermissions(t.props.channel.id);

				// return unmodified if no permissions to send messages
				if (typeof p === "number" && !(p & Module.Constants.Permissions.SEND_MESSAGES)) {
					return r;
				}

				// find message header
				const h = [r.props.children].flat().find((e) => e.props && e.props.className === Selector.Messages.headerCozy);

				// find message header meta
				const m = h && [h.props.children].flat().find((e) => e.props && e.props.className === Selector.Messages.headerCozyMeta);

				// check if message header meta found
				if (m) {

					// get children
					const c = [m.props.children].flat();

					// push reply button
					c.push(React.createElement("span", {
						className: "replyer",
						onClick: () => {

							// get saved text area
							const f = this.focused;

							// check if text area saved
							if (f) {

								// focus textarea
								f.focus();

								// check mode
								if (this.mode) {

									// select saved selection
									f.setSelectionRange(this.selection[0], this.selection[1]);

									// insert mention
									document.execCommand("insertText", false, `<@!${id}>`);

									// update saved text area
									setTimeout(() => {
										this.focused = f;
									}, 100);
								}
								else {

									// get mention
									const m = `<@!${id}> `;

									// go to start of textarea
									f.setSelectionRange(0, 0);

									// insert mention
									document.execCommand("insertText", false, m);

									// select saved selection
									f.setSelectionRange(this.selection[0] + m.length, this.selection[1] + m.length);
								}
							}
							else {

								// default to current channel
								Module.DraftActions.saveDraft(t.props.channel.id, `<@!${id}> ${Module.Drafts.getDraft(t.props.channel.id)}`);
							}
						}
					}, "Reply"));

					// override children
					m.props.children = c;
				}

				// return modified return value
				return r;
			}});
			this.log("Patched render of Message component");

			// patch "ChannelTextArea" component render function
			Patches.textarea = BdApi.monkeyPatch(Component.ChannelTextArea.prototype, "render", {silent: true, instead: (d) => {

				// get this
				const t = d.thisObject;

				// declare blur handler
				const f = () => {

					// get dom node
					const e = ReactDOM.findDOMNode(d.thisObject).querySelector("textarea");

					// save focused textarea
					this.focused = e;

					// save selection
					this.selection = [e.selectionStart, e.selectionEnd];

					// set mode
					this.mode = true;

					// reset mode after 100ms
					setTimeout(() => {
						if (this.focused === e) {
							this.mode = false;
						}
					}, 100);
				};

				// check if text area has a blur handler
				if (t.props.onBlur) {

					// patch blur handler
					BdApi.monkeyPatch(t.props, "onBlur", {silent: true, before: f});
				}
				else {

					// assign blur handler
					t.props.onBlur = f;
				}

				// return render with modified this
				return d.originalMethod.apply(t);
			}});
			this.log("Patched onBlur of ChannelTextArea component");

			// force update
			this.forceUpdateAll();

			// console output
			this.log("Enabled");
		}

		/**
		 * Plugin stop function
		 */
		stop() {

			// reset saved text area, selection & mode
			this.focused = null;
			this.selection = [0, 0];
			this.mode = false;

			// clear styles
			BdApi.clearCSS(this.getName());

			// revert all patches
			for (const k in Patches) {
				Patches[k]();
				delete Patches[k];
			}
			this.log("Unpatched all");

			// force update
			this.forceUpdateAll();

			// console output
			this.log("Disabled");
		}

		/**
		 * Force update the "Message" & "ChannelTextArea" component state nodes
		 */
		forceUpdateAll() {

			// force update messages
			for (const e of document.getElementsByClassName(Selector.Messages.message)) {
				const i = BdApi.getInternalInstance(e);
				i && i.return.stateNode.forceUpdate && i.return.stateNode.forceUpdate();
			}

			// force update channel text areas
			for (const e of document.getElementsByClassName(Selector.TextArea.channelTextArea)) {
				const i = BdApi.getInternalInstance(e);
				i && i.return.stateNode.forceUpdate && i.return.stateNode.forceUpdate();
			}
		}

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